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();
}
}
}