diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java index 11499d0300b..3c762fcb920 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java @@ -31,6 +31,7 @@ import io.micronaut.http.ssl.ServerSslConfiguration; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOutboundHandler; @@ -498,26 +499,48 @@ void configureForH2cSupport() { // todo: move to Http2ServerHandler (upgrade request is a bit difficult) - final Http2FrameCodec connectionHandler = createHttp2FrameCodec(); + final Http2FrameCodec frameCodec; + final Http2ConnectionHandler connectionHandler; + if (server.getServerConfiguration().isLegacyMultiplexHandlers()) { + frameCodec = createHttp2FrameCodec(); + connectionHandler = frameCodec; + } else { + connectionHandler = createHttp2ServerHandler(false); + frameCodec = null; + } final String fallbackHandlerName = "http1-fallback-handler"; HttpServerUpgradeHandler.UpgradeCodecFactory upgradeCodecFactory = protocol -> { if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) { + class Http2ServerUpgradeCodecImpl extends Http2ServerUpgradeCodec { + public Http2ServerUpgradeCodecImpl(Http2ConnectionHandler connectionHandler) { + super(connectionHandler); + } - return new Http2ServerUpgradeCodec(connectionHandler, new Http2MultiplexHandler(new ChannelInitializer() { - @Override - protected void initChannel(@NonNull Http2StreamChannel ch) { - StreamPipeline streamPipeline = new StreamPipeline(ch, sslHandler, connectionCustomizer.specializeForChannel(ch, NettyServerCustomizer.ChannelRole.REQUEST_STREAM)); - streamPipeline.insertHttp2FrameHandlers(); - streamPipeline.streamCustomizer.onStreamPipelineBuilt(); + public Http2ServerUpgradeCodecImpl(Http2FrameCodec http2Codec, ChannelHandler... handlers) { + super(http2Codec, handlers); } - })) { + @Override public void upgradeTo(ChannelHandlerContext ctx, FullHttpRequest upgradeRequest) { super.upgradeTo(ctx, upgradeRequest); pipeline.remove(fallbackHandlerName); + new StreamPipeline(channel, sslHandler, connectionCustomizer).afterHttp2ServerHandlerSetUp(); onRequestPipelineBuilt(); } - }; + } + + if (frameCodec == null) { + return new Http2ServerUpgradeCodecImpl(connectionHandler); + } else { + return new Http2ServerUpgradeCodecImpl(frameCodec, new Http2MultiplexHandler(new ChannelInitializer() { + @Override + protected void initChannel(@NonNull Http2StreamChannel ch) { + StreamPipeline streamPipeline = new StreamPipeline(ch, sslHandler, connectionCustomizer.specializeForChannel(ch, NettyServerCustomizer.ChannelRole.REQUEST_STREAM)); + streamPipeline.insertHttp2FrameHandlers(); + streamPipeline.streamCustomizer.onStreamPipelineBuilt(); + } + })); + } } else { return null; } diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java index 39188e3de9e..2abd652833d 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java @@ -158,6 +158,7 @@ public class NettyHttpRequest extends AbstractNettyHttpRequest implements * ONLY for NettyBodyAnnotationBinder use. */ @Internal + @SuppressWarnings("VisibilityModifier") public ArgumentBinder.BindingResult> convertibleBody; private final NettyHttpHeaders headers; diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/handler/Http2ServerHandler.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/handler/Http2ServerHandler.java index 19c3ada0a95..e9105cd0086 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/handler/Http2ServerHandler.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/handler/Http2ServerHandler.java @@ -20,7 +20,9 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpServerUpgradeHandler; import io.netty.handler.codec.http2.AbstractHttp2ConnectionHandlerBuilder; import io.netty.handler.codec.http2.DefaultHttp2Connection; import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener; @@ -228,6 +230,22 @@ protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { return true; }); } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof HttpServerUpgradeHandler.UpgradeEvent upgrade) { + FullHttpRequest fhr = upgrade.upgradeRequest(); + io.netty.handler.codec.http2.Http2Stream cs = connection().stream(1); + Http2ServerHandler.Http2Stream stream = handler.new Http2Stream(cs); + cs.setProperty(handler.streamKey, stream); + boolean empty = !fhr.content().isReadable(); + stream.onHeadersRead(fhr, empty); + if (!empty) { + stream.onDataRead(fhr.content(), true); + } + } + super.userEventTriggered(ctx, evt); + } } /** @@ -287,6 +305,10 @@ private final class Http2Stream extends MultiplexedStream { @Override void notifyDataConsumed(int n) { + if (stream.id() == 1) { + // ignore for upgrade stream + return; + } try { connectionHandler.connection().local().flowController().consumeBytes(stream, n); } catch (Http2Exception e) {