Correctly handle http2 upgrades when Http2FrameCodec is used together… (#9318)

Motivation:

In the latest release we introduced Http2MultiplexHandler as a replacement of Http2MultiplexCodec. This did split the frame parsing from the multiplexing to allow a more flexible way to handle frames and to make the code cleaner. Unfortunally we did miss to special handle this in Http2ServerUpgradeCodec and so did not correctly add Http2MultiplexHandler to the pipeline before calling Http2FrameCodec.onHttpServerUpgrade(...). This did lead to the situation that we did not correctly receive the event on the Http2MultiplexHandler and so did not correctly created the Http2StreamChannel for the upgrade stream. Because of this we ended up with an NPE if a frame was dispatched to the upgrade stream later on.

Modifications:

- Correctly add Http2MultiplexHandler to the pipeline before calling Http2FrameCodec.onHttpServerUpgrade(...)
- Add unit test

Result:

Fixes https://github.com/netty/netty/issues/9314.
This commit is contained in:
Norman Maurer 2019-07-04 08:32:41 +02:00 committed by GitHub
parent 1b82474286
commit 16b98d370f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 9 deletions

View File

@ -146,19 +146,19 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
try {
// Add the HTTP/2 connection handler to the pipeline immediately following the current handler.
ctx.pipeline().addAfter(ctx.name(), handlerName, connectionHandler);
connectionHandler.onHttpServerUpgrade(settings);
// Add also all extra handlers as these may handle events / messages produced by the connectionHandler.
// See https://github.com/netty/netty/issues/9314
if (handlers != null) {
final String name = ctx.pipeline().context(connectionHandler).name();
for (int i = handlers.length - 1; i >= 0; i--) {
ctx.pipeline().addAfter(name, null, handlers[i]);
}
}
connectionHandler.onHttpServerUpgrade(settings);
} catch (Http2Exception e) {
ctx.fireExceptionCaught(e);
ctx.close();
return;
}
if (handlers != null) {
final String name = ctx.pipeline().context(connectionHandler).name();
for (int i = handlers.length - 1; i >= 0; i--) {
ctx.pipeline().addAfter(name, null, handlers[i]);
}
}
}

View File

@ -76,6 +76,11 @@ public class Http2ServerUpgradeCodecTest {
// Flush the channel to ensure we write out all buffered data
channel.flush();
channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf());
Http2FrameInboundWriter writer = new Http2FrameInboundWriter(channel);
writer.writeInboundSettings(new Http2Settings());
writer.writeInboundRstStream(Http2CodecUtil.HTTP_UPGRADE_STREAM_ID, Http2Error.CANCEL.code());
assertSame(handler, channel.pipeline().remove(handler.getClass()));
assertNull(channel.pipeline().get(handler.getClass()));
assertTrue(channel.finish());
@ -85,6 +90,10 @@ public class Http2ServerUpgradeCodecTest {
assertNotNull(settingsBuffer);
settingsBuffer.release();
ByteBuf buf = channel.readOutbound();
assertNotNull(buf);
buf.release();
assertNull(channel.readOutbound());
}