From c0708fc464695abe62c1cf2f79ad76c0d9b05e7e Mon Sep 17 00:00:00 2001 From: Violeta Georgieva Date: Thu, 29 Apr 2021 13:12:43 +0300 Subject: [PATCH] Verify SslHandler#unwrap send fireChannelRead event after a notification for a handshake success (#11203) Motivation: #11210 fixed a regression caused by #11156. This change adds a unit test for it. Modifications: - Add test Result: Verify fix in #11210 Co-authored-by: Norman Maurer --- .../http2/Http2MultiplexTransportTest.java | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTransportTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTransportTest.java index 77045683e9..f43cf6fe33 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTransportTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTransportTest.java @@ -31,7 +31,9 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ApplicationProtocolNames; +import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandshakeCompletionEvent; @@ -443,4 +445,132 @@ public class Http2MultiplexTransportTest { } } } + + @Test(timeout = 5000L) + public void testFireChannelReadAfterHandshakeSuccess_JDK() throws Exception { + assumeTrue(SslProvider.isAlpnSupported(SslProvider.JDK)); + testFireChannelReadAfterHandshakeSuccess(SslProvider.JDK); + } + + @Test(timeout = 5000L) + public void testFireChannelReadAfterHandshakeSuccess_OPENSSL() throws Exception { + assumeTrue(OpenSsl.isAvailable()); + assumeTrue(SslProvider.isAlpnSupported(SslProvider.OPENSSL)); + testFireChannelReadAfterHandshakeSuccess(SslProvider.OPENSSL); + } + + private void testFireChannelReadAfterHandshakeSuccess(SslProvider provider) throws Exception { + SelfSignedCertificate ssc = null; + try { + ssc = new SelfSignedCertificate(); + final SslContext serverCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) + .sslProvider(provider) + .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2, + ApplicationProtocolNames.HTTP_1_1)) + .build(); + + ServerBootstrap sb = new ServerBootstrap(); + sb.group(eventLoopGroup); + sb.channel(NioServerSocketChannel.class); + sb.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(serverCtx.newHandler(ch.alloc())); + ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_1_1) { + @Override + protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { + ctx.pipeline().addLast(new Http2FrameCodecBuilder(true).build()); + ctx.pipeline().addLast(new Http2MultiplexHandler(new ChannelInboundHandlerAdapter() { + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) { + if (msg instanceof Http2HeadersFrame && ((Http2HeadersFrame) msg).isEndStream()) { + ctx.writeAndFlush(new DefaultHttp2HeadersFrame( + new DefaultHttp2Headers(), false)) + .addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) { + ctx.writeAndFlush(new DefaultHttp2DataFrame( + Unpooled.copiedBuffer("Hello World", CharsetUtil.US_ASCII), + true)); + } + }); + } + ReferenceCountUtil.release(msg); + } + })); + } + }); + } + }); + serverChannel = sb.bind(new InetSocketAddress(NetUtil.LOCALHOST, 0)).sync().channel(); + + final SslContext clientCtx = SslContextBuilder.forClient() + .sslProvider(provider) + .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2, + ApplicationProtocolNames.HTTP_1_1)) + .build(); + + final CountDownLatch latch = new CountDownLatch(1); + Bootstrap bs = new Bootstrap(); + bs.group(eventLoopGroup); + bs.channel(NioSocketChannel.class); + bs.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + ch.pipeline().addLast(clientCtx.newHandler(ch.alloc())); + ch.pipeline().addLast(new Http2FrameCodecBuilder(false).build()); + ch.pipeline().addLast(new Http2MultiplexHandler(DISCARD_HANDLER)); + ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + if (evt instanceof SslHandshakeCompletionEvent) { + SslHandshakeCompletionEvent handshakeCompletionEvent = + (SslHandshakeCompletionEvent) evt; + if (handshakeCompletionEvent.isSuccess()) { + Http2StreamChannelBootstrap h2Bootstrap = + new Http2StreamChannelBootstrap(clientChannel); + h2Bootstrap.handler(new ChannelInboundHandlerAdapter() { + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof Http2DataFrame && ((Http2DataFrame) msg).isEndStream()) { + latch.countDown(); + } + ReferenceCountUtil.release(msg); + } + }); + h2Bootstrap.open().addListener(new FutureListener() { + @Override + public void operationComplete(Future future) { + if (future.isSuccess()) { + future.getNow().writeAndFlush(new DefaultHttp2HeadersFrame( + new DefaultHttp2Headers(), true)); + } + } + }); + } + } + } + }); + } + }); + clientChannel = bs.connect(serverChannel.localAddress()).sync().channel(); + + latch.await(); + } finally { + if (ssc != null) { + ssc.delete(); + } + } + } }