public void readDataFrame()

in src/main/java/com/twitter/whiskey/net/SpdySession.java [190:293]


    public void readDataFrame(int streamId, boolean last, ByteBuffer data) {
    /*
     * SPDY Data frame processing requirements:
     *
     * If an endpoint receives a data frame for a Stream-ID which is not open
     * and the endpoint has not sent a GOAWAY frame, it must issue a stream error
     * with the error code INVALID_STREAM for the Stream-ID.
     *
     * If an endpoint which created the stream receives a data frame before receiving
     * a SYN_REPLY on that stream, it is a protocol error, and the recipient must
     * issue a stream error with the status code PROTOCOL_ERROR for the Stream-ID.
     *
     * If an endpoint receives multiple data frames for invalid Stream-IDs,
     * it may close the session.
     *
     * If an endpoint refuses a stream it must ignore any data frames for that stream.
     *
     * If an endpoint receives a data frame after the stream is half-closed from the
     * sender, it must send a RST_STREAM frame with the status STREAM_ALREADY_CLOSED.
     *
     * If an endpoint receives a data frame after the stream is closed, it must send
     * a RST_STREAM frame with the status PROTOCOL_ERROR.
     */

        Platform.LOGGER.debug(
            "read DATA\n--> Stream-ID = " + streamId + "\n--> Size = " + data.remaining() +
                "\n--> Last: " + last
        );
        SpdyStream stream = activeStreams.get(streamId);

        // Check if session flow control is violated
        if (sessionReceiveWindow < data.remaining()) {
            closeWithError(new SpdySessionException("session flow control violatian"));
            return;
        }

        // Check if we received a data frame for a valid Stream-ID
        if (stream == null) {
            if (streamId < lastGoodStreamId) {
                sendRstStream(streamId, SPDY_STREAM_PROTOCOL_ERROR);
            } else if (!sentGoAwayFrame) {
                sendRstStream(streamId, SPDY_STREAM_INVALID_STREAM);
            }
            return;
        }

        // Check if we received a data frame for a stream which is half-closed
        if (stream.isClosedRemotely()) {
            sendRstStream(streamId, SPDY_STREAM_STREAM_ALREADY_CLOSED);
            return;
        }

        // Check if we received a data frame before receiving a SYN_REPLY
        if (stream.isLocal() && !stream.hasReceivedReply()) {
            sendRstStream(streamId, SPDY_STREAM_PROTOCOL_ERROR);
            return;
        }

    /*
     * SPDY Data frame flow control processing requirements:
     *
     * Recipient should not send a WINDOW_UPDATE frame as it consumes the last data frame.
     */

        // Check if stream flow control is violated
        if (stream.getReceiveWindow() < data.remaining()) {
            sendRstStream(streamId, SPDY_STREAM_FLOW_CONTROL_ERROR);
            return;
        }

        // Update session receive window size
        sessionReceiveWindow -= data.remaining();

        // Send a WINDOW_UPDATE frame if less than half the sesion window size remains
        if (sessionReceiveWindow <= initialReceiveWindow / 2) {
            int deltaWindowSize = initialReceiveWindow - sessionReceiveWindow;
            sendWindowUpdate(SPDY_SESSION_STREAM_ID, deltaWindowSize);
        }

        // Update stream receive window size
        stream.reduceReceiveWindow(data.remaining());

        if (stream.getReceiveWindow() <= initialReceiveWindow / 2) {
            int deltaWindowSize = initialReceiveWindow - stream.getReceiveWindow();
            stream.increaseReceiveWindow(deltaWindowSize);
            sendWindowUpdate(streamId, deltaWindowSize);
        }

        try {
            stream.onData(data);
        } catch (DataFormatException e) {
            sendRstStream(streamId, SPDY_STREAM_INTERNAL_ERROR);
            activeStreams.remove(stream);
            stream.close(e);
        }

        if (last) {
            stream.closeRemotely();
            if (stream.isClosed()) {
                activeStreams.remove(stream);
                stream.complete();
            }
        }
    }