Skip to content

Commit 12e1169

Browse files
authored
Use the correct error when reset a stream (#13309)
Motivation: At the moment we always used "CANCEL" when reseting a stream because of an error. This is not correct, we should use the error that caused the stream error. Modifications: - Use correct error when reset a stream. - Add unit test Result: Correctly propagate stream errors via reset
1 parent ccc5e01 commit 12e1169

4 files changed

Lines changed: 34 additions & 3 deletions

File tree

codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2StreamChannel.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,11 @@ void fireChildReadComplete() {
576576
unsafe.notifyReadComplete(unsafe.recvBufAllocHandle(), false);
577577
}
578578

579+
final void closeWithError(Http2Error error) {
580+
assert eventLoop().inEventLoop();
581+
unsafe.close(unsafe.voidPromise(), error);
582+
}
583+
579584
private final class Http2ChannelUnsafe implements Unsafe {
580585
private final VoidChannelPromise unsafeVoidPromise =
581586
new VoidChannelPromise(AbstractHttp2StreamChannel.this, false);
@@ -648,6 +653,10 @@ public void disconnect(ChannelPromise promise) {
648653

649654
@Override
650655
public void close(final ChannelPromise promise) {
656+
close(promise, Http2Error.CANCEL);
657+
}
658+
659+
void close(final ChannelPromise promise, Http2Error error) {
651660
if (!promise.setUncancellable()) {
652661
return;
653662
}
@@ -678,7 +687,7 @@ public void operationComplete(ChannelFuture future) {
678687
// Only ever send a reset frame if the connection is still alive and if the stream was created before
679688
// as otherwise we may send a RST on a stream in an invalid state and cause a connection error.
680689
if (parent().isActive() && !readEOS && isStreamIdValid(stream.id())) {
681-
Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(Http2Error.CANCEL).stream(stream());
690+
Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(error).stream(stream());
682691
write(resetFrame, unsafe().voidPromise());
683692
flush();
684693
}

codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ final void onHttp2FrameStreamException(ChannelHandlerContext ctx, Http2FrameStre
208208
try {
209209
channel.pipeline().fireExceptionCaught(cause.getCause());
210210
} finally {
211-
channel.unsafe().closeForcibly();
211+
// Close with the correct error that causes this stream exception.
212+
// See https://github.com/netty/netty/issues/13235#issuecomment-1441994672
213+
channel.closeWithError(cause.error());
212214
}
213215
}
214216

codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ public void exceptionCaught(ChannelHandlerContext ctx, final Throwable cause) th
274274
try {
275275
childChannel.pipeline().fireExceptionCaught(cause.getCause());
276276
} finally {
277-
childChannel.unsafe().closeForcibly();
277+
// Close with the correct error that causes this stream exception.
278+
// See https://github.com/netty/netty/issues/13235#issuecomment-1441994672
279+
childChannel.closeWithError(exception.error());
278280
}
279281
return;
280282
}

codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,24 @@ public void execute() throws Throwable {
356356
assertFalse(channel.isActive());
357357
}
358358

359+
@Test
360+
public void contentLengthNotMatchRstStreamWithProtocolError() {
361+
final LastInboundHandler inboundHandler = new LastInboundHandler();
362+
request.addLong(HttpHeaderNames.CONTENT_LENGTH, 10);
363+
Http2StreamChannel channel = newInboundStream(3, false, inboundHandler);
364+
frameInboundWriter.writeInboundData(3, bb(8), 0, true);
365+
assertThrows(StreamException.class, new Executable() {
366+
@Override
367+
public void execute() throws Throwable {
368+
inboundHandler.checkException();
369+
}
370+
});
371+
assertNotNull(inboundHandler.readInbound());
372+
assertFalse(channel.isActive());
373+
verify(frameWriter).writeRstStream(eqCodecCtx(), eq(3),
374+
eq(Http2Error.PROTOCOL_ERROR.code()), anyChannelPromise());
375+
}
376+
359377
@Test
360378
public void framesShouldBeMultiplexed() {
361379
LastInboundHandler handler1 = new LastInboundHandler();

0 commit comments

Comments
 (0)