HTTP/2 RST_STREAM in IDLE

Motivation:
The spec requires that a RST_STREAM received on an IDLE stream results in a connection error. This is not happening.

Modifications:
Check for this condition when a RST_STREAM is received in DefaultHttp2ConnectionDecoder.

Result:
More spec compliant.  Fixes https://github.com/netty/netty/issues/3573.
This commit is contained in:
Scott Mitchell 2015-04-03 09:53:57 -07:00
parent e5d01c4caf
commit 9517edd498
2 changed files with 16 additions and 3 deletions

View File

@ -356,9 +356,13 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
@Override @Override
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception { public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
Http2Stream stream = connection.requireStream(streamId); Http2Stream stream = connection.requireStream(streamId);
if (stream.state() == CLOSED) { switch(stream.state()) {
// RstStream frames must be ignored for closed streams. case IDLE:
return; throw connectionError(PROTOCOL_ERROR, "RST_STREAM received for IDLE stream %d", streamId);
case CLOSED:
return; // RST_STREAM frames must be ignored for closed streams.
default:
break;
} }
listener.onRstStreamRead(ctx, streamId, errorCode); listener.onRstStreamRead(ctx, streamId, errorCode);

View File

@ -20,6 +20,7 @@ import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGH
import static io.netty.handler.codec.http2.Http2CodecUtil.emptyPingBuf; import static io.netty.handler.codec.http2.Http2CodecUtil.emptyPingBuf;
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR; import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError; import static io.netty.handler.codec.http2.Http2Exception.connectionError;
import static io.netty.handler.codec.http2.Http2Stream.State.IDLE;
import static io.netty.handler.codec.http2.Http2Stream.State.OPEN; import static io.netty.handler.codec.http2.Http2Stream.State.OPEN;
import static io.netty.handler.codec.http2.Http2Stream.State.RESERVED_REMOTE; import static io.netty.handler.codec.http2.Http2Stream.State.RESERVED_REMOTE;
import static io.netty.util.CharsetUtil.UTF_8; import static io.netty.util.CharsetUtil.UTF_8;
@ -501,6 +502,14 @@ public class DefaultHttp2ConnectionDecoderTest {
verify(listener).onRstStreamRead(eq(ctx), eq(STREAM_ID), eq(PROTOCOL_ERROR.code())); verify(listener).onRstStreamRead(eq(ctx), eq(STREAM_ID), eq(PROTOCOL_ERROR.code()));
} }
@Test(expected = Http2Exception.class)
public void rstStreamOnIdleStreamShouldThrow() throws Exception {
when(stream.state()).thenReturn(IDLE);
decode().onRstStreamRead(ctx, STREAM_ID, PROTOCOL_ERROR.code());
verify(lifecycleManager).closeStream(eq(stream), eq(future));
verify(listener, never()).onRstStreamRead(any(ChannelHandlerContext.class), anyInt(), anyLong());
}
@Test @Test
public void pingReadWithAckShouldNotifylistener() throws Exception { public void pingReadWithAckShouldNotifylistener() throws Exception {
decode().onPingAckRead(ctx, emptyPingBuf()); decode().onPingAckRead(ctx, emptyPingBuf());