/** * Eagerly reads {@code byteCount} bytes from the source before launching a background task to * process the data. This avoids corrupting the stream. */ private void pushDataLater( final int streamId, final BufferedSource source, final int byteCount, final boolean inFinished) throws IOException { final Buffer buffer = new Buffer(); source.require(byteCount); // Eagerly read the frame before firing client thread. source.read(buffer, byteCount); if (buffer.size() != byteCount) throw new IOException(buffer.size() + " != " + byteCount); pushExecutor.execute( new NamedRunnable("OkHttp %s Push Data[%s]", hostname, streamId) { @Override public void execute() { try { boolean cancel = pushObserver.onData(streamId, buffer, byteCount, inFinished); if (cancel) frameWriter.rstStream(streamId, ErrorCode.CANCEL); if (cancel || inFinished) { synchronized (FramedConnection.this) { currentPushRequests.remove(streamId); } } } catch (IOException ignored) { } } }); }
@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; }