private void readData(Handler handler, int length, byte flags, int streamId) throws IOException { // 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 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; }
@Override public void data(boolean inFinished, int streamId, BufferedSource source, int length) throws IOException { if (pushedStream(streamId)) { pushDataLater(streamId, source, length, inFinished); return; } FramedStream dataStream = getStream(streamId); if (dataStream == null) { writeSynResetLater(streamId, ErrorCode.INVALID_STREAM); source.skip(length); return; } dataStream.receiveData(source, length); if (inFinished) { dataStream.receiveFin(); } }
@Override public boolean onData(int streamId, BufferedSource source, int byteCount, boolean last) throws IOException { source.skip(byteCount); return false; }
@Override public boolean nextFrame(Handler handler) throws IOException { try { source.require(9); // Frame header size } catch (IOException e) { return false; // This might be a normal socket close. } /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length (24) | * +---------------+---------------+---------------+ * | Type (8) | Flags (8) | * +-+-+-----------+---------------+-------------------------------+ * |R| Stream Identifier (31) | * +=+=============================================================+ * | Frame Payload (0...) ... * +---------------------------------------------------------------+ */ int length = readMedium(source); if (length < 0 || length > INITIAL_MAX_FRAME_SIZE) { throw ioException("FRAME_SIZE_ERROR: %s", length); } byte type = (byte) (source.readByte() & 0xff); byte flags = (byte) (source.readByte() & 0xff); int streamId = (source.readInt() & 0x7fffffff); // Ignore reserved bit. if (logger.isLoggable(FINE)) logger.fine(formatHeader(true, streamId, length, type, flags)); switch (type) { case TYPE_DATA: readData(handler, length, flags, streamId); break; case TYPE_HEADERS: readHeaders(handler, length, flags, streamId); break; case TYPE_PRIORITY: readPriority(handler, length, flags, streamId); break; case TYPE_RST_STREAM: readRstStream(handler, length, flags, streamId); break; case TYPE_SETTINGS: readSettings(handler, length, flags, streamId); break; case TYPE_PUSH_PROMISE: readPushPromise(handler, length, flags, streamId); break; case TYPE_PING: readPing(handler, length, flags, streamId); break; case TYPE_GOAWAY: readGoAway(handler, length, flags, streamId); break; case TYPE_WINDOW_UPDATE: readWindowUpdate(handler, length, flags, streamId); break; default: // Implementations MUST discard frames that have unknown or unsupported types. source.skip(length); } return true; }