@Override public boolean onData(int streamId, BufferedSource source, int byteCount, boolean last) throws IOException { source.skip(byteCount); return true; }
@Override public long read(Buffer sink, long byteCount) throws IOException { while (left == 0) { source.skip(padding); padding = 0; if ((flags & FLAG_END_HEADERS) != 0) return -1; readContinuationHeader(); // TODO: test case for empty continuation header? } long read = source.read(sink, Math.min(byteCount, left)); if (read == -1) return -1; left -= read; return read; }
/** * Consumes the field name of the specified length and the optional colon and its optional * trailing space. Returns the number of bytes skipped. */ private long skipNameAndDivider(long length) throws IOException { source.skip(length); if (source.getBuffer().getByte(0) == ':') { source.skip(1L); length++; if (source.getBuffer().getByte(0) == ' ') { source.skip(1); length++; } } return length; } }
/** Consumes {@code \r}, {@code \r\n}, or {@code \n} from {@link #source}. */ private void skipCrAndOrLf() throws IOException { if ((source.readByte() & 0xff) == '\r' && source.request(1) && source.getBuffer().getByte(0) == '\n') { source.skip(1); } }
private void readData(Handler handler, int length, byte flags, int streamId) throws IOException { if (streamId == 0) throw ioException("PROTOCOL_ERROR: TYPE_DATA streamId == 0"); // TODO: checkState open or half-closed (local) or raise STREAM_CLOSED boolean inFinished = (flags & FLAG_END_STREAM) != 0; boolean gzipped = (flags & FLAG_COMPRESSED) != 0; if (gzipped) { throw ioException("PROTOCOL_ERROR: FLAG_COMPRESSED without SETTINGS_COMPRESS_DATA"); } short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0; length = lengthWithoutPadding(length, flags, padding); handler.data(inFinished, streamId, source, length); source.skip(padding); }
@Override public T convert(ResponseBody value) throws IOException { BufferedSource source = value.source(); try { // Moshi has no document-level API so the responsibility of BOM skipping falls to whatever // is delegating to it. Since it's a UTF-8-only library as well we only honor the UTF-8 BOM. if (source.rangeEquals(0, UTF8_BOM)) { source.skip(UTF8_BOM.size()); } JsonReader reader = JsonReader.of(source); T result = adapter.fromJson(reader); if (reader.peek() != JsonReader.Token.END_DOCUMENT) { throw new JsonDataException("JSON document was not fully consumed."); } return result; } finally { value.close(); } } }
@Test public void resetTooLow() throws Exception { SourceMarker marker = new SourceMarker(new Buffer().writeUtf8("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); BufferedSource source = marker.source(); source.skip(3); marker.mark(3); source.skip(2); try { marker.reset(2); fail(); } catch (IOException expected) { assertThat(expected).hasMessage("cannot reset to 2: out of range"); } }
@Override public void data(boolean inFinished, int streamId, BufferedSource source, int length) throws IOException { if (pushedStream(streamId)) { pushDataLater(streamId, source, length, inFinished); return; } Http2Stream dataStream = getStream(streamId); if (dataStream == null) { writeSynResetLater(streamId, ErrorCode.PROTOCOL_ERROR); updateConnectionFlowControl(length); source.skip(length); return; } dataStream.receiveData(source, length); if (inFinished) { dataStream.receiveHeaders(Util.EMPTY_HEADERS, true); } }
@Test public void resetTooHigh() throws Exception { SourceMarker marker = new SourceMarker(new Buffer().writeUtf8("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); BufferedSource source = marker.source(); marker.mark(3); source.skip(6); try { marker.reset(4); fail(); } catch (IOException expected) { assertThat(expected).hasMessage("cannot reset to 4: out of range"); } }
@Test public void skip() throws Exception { sink.writeUtf8("a"); sink.writeUtf8(repeat('b', SEGMENT_SIZE)); sink.writeUtf8("c"); sink.emit(); source.skip(1); assertEquals('b', source.readByte() & 0xff); source.skip(SEGMENT_SIZE - 2); assertEquals('b', source.readByte() & 0xff); source.skip(1); assertTrue(source.exhausted()); }
@Test public void skipInsufficientData() throws Exception { sink.writeUtf8("a"); sink.emit(); try { source.skip(2); fail(); } catch (EOFException ignored) { } }
@Test public void skipTracksBufferFirst() throws Exception { Buffer source = new Buffer(); source.writeUtf8("bb"); BufferedSource bufferedSource = Okio.buffer((Source) source); bufferedSource.getBuffer().writeUtf8("aa"); bufferedSource.skip(2); assertEquals(0, bufferedSource.getBuffer().size()); assertEquals(2, source.size()); }
@Test public void skipReadsOneSegmentAtATime() throws Exception { Buffer source = new Buffer(); source.writeUtf8(repeat('a', SEGMENT_SIZE)); source.writeUtf8(repeat('b', SEGMENT_SIZE)); BufferedSource bufferedSource = Okio.buffer((Source) source); bufferedSource.skip(2); assertEquals(SEGMENT_SIZE, source.size()); assertEquals(SEGMENT_SIZE - 2, bufferedSource.getBuffer().size()); }
@Test public void readUtf8SpansSegments() throws Exception { sink.writeUtf8(repeat('a', SEGMENT_SIZE * 2)); sink.emit(); source.skip(SEGMENT_SIZE - 1); assertEquals("aa", source.readUtf8(2)); }
@Test public void longHexStringAcrossSegment() throws IOException { sink.writeUtf8(repeat('a', SEGMENT_SIZE - 8)).writeUtf8("FFFFFFFFFFFFFFFF"); sink.emit(); source.skip(SEGMENT_SIZE - 8); assertEquals(-1, source.readHexadecimalUnsignedLong()); }
@Test public void readIntSplitAcrossMultipleSegments() throws Exception { sink.writeUtf8(repeat('a', SEGMENT_SIZE - 3)); sink.write(new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01 }); sink.emit(); source.skip(SEGMENT_SIZE - 3); assertEquals(0xabcdef01, source.readInt()); assertTrue(source.exhausted()); }
@Test public void readLongSplitAcrossMultipleSegments() throws Exception { sink.writeUtf8(repeat('a', SEGMENT_SIZE - 7)); sink.write(new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21, }); sink.emit(); source.skip(SEGMENT_SIZE - 7); assertEquals(0xabcdef0187654321L, source.readLong()); assertTrue(source.exhausted()); }
@Test public void readShortSplitAcrossMultipleSegments() throws Exception { sink.writeUtf8(repeat('a', SEGMENT_SIZE - 1)); sink.write(new byte[] { (byte) 0xab, (byte) 0xcd }); sink.emit(); source.skip(SEGMENT_SIZE - 1); assertEquals((short) 0xabcd, source.readShort()); assertTrue(source.exhausted()); }
@Test public void longDecimalStringAcrossSegment() throws IOException { sink.writeUtf8(repeat('a', SEGMENT_SIZE - 8)).writeUtf8("1234567890123456"); sink.writeUtf8("zzz"); sink.emit(); source.skip(SEGMENT_SIZE - 8); assertEquals(1234567890123456L, source.readDecimalLong()); assertEquals("zzz", source.readUtf8()); }