diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java index d93139979a..6abde886c2 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java @@ -364,15 +364,20 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http prefaceSent = true; - if (!connection().isServer()) { + final boolean isClient = !connection().isServer(); + if (isClient) { // Clients must send the preface string as the first bytes on the connection. ctx.write(connectionPrefaceBuf()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); - ctx.fireUserEventTriggered(Http2ConnectionPrefaceWrittenEvent.INSTANCE); } // Both client and server must send their initial settings. encoder.writeSettings(ctx, initialSettings, ctx.newPromise()).addListener( ChannelFutureListener.CLOSE_ON_FAILURE); + + if (isClient) { + ctx.fireUserEventTriggered( + Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE); + } } } diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceWrittenEvent.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.java similarity index 60% rename from codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceWrittenEvent.java rename to codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.java index 37a7c6b82f..f339e0cc40 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceWrittenEvent.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.java @@ -17,14 +17,15 @@ package io.netty.handler.codec.http2; import io.netty.util.internal.UnstableApi; /** - * Signifies that the connection preface has been sent. - * The client sends the preface, and the server receives the preface. The client shouldn't write any data until this - * event has been processed. + * Signifies that the connection preface and + * the initial SETTINGS frame have been sent. The client sends the preface, and the server receives the preface. + * The client shouldn't write any data until this event has been processed. */ @UnstableApi -public final class Http2ConnectionPrefaceWrittenEvent { - static final Http2ConnectionPrefaceWrittenEvent INSTANCE = new Http2ConnectionPrefaceWrittenEvent(); +public final class Http2ConnectionPrefaceAndSettingsFrameWrittenEvent { + static final Http2ConnectionPrefaceAndSettingsFrameWrittenEvent INSTANCE = + new Http2ConnectionPrefaceAndSettingsFrameWrittenEvent(); - private Http2ConnectionPrefaceWrittenEvent() { + private Http2ConnectionPrefaceAndSettingsFrameWrittenEvent() { } } diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodec.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodec.java index a068589963..82107f9f69 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodec.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodec.java @@ -231,7 +231,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler { */ @Override public final void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof Http2ConnectionPrefaceWrittenEvent) { + if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) { // The user event implies that we are on the client. tryExpandConnectionFlowControlWindow(connection()); } else if (evt instanceof UpgradeEvent) { diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DataCompressionHttp2Test.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DataCompressionHttp2Test.java index 0d6b008d7a..1d815a330c 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DataCompressionHttp2Test.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DataCompressionHttp2Test.java @@ -347,7 +347,7 @@ public class DataCompressionHttp2Test { p.addLast(clientHandler); p.addLast(new ChannelInboundHandlerAdapter() { public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof Http2ConnectionPrefaceWrittenEvent) { + if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) { prefaceWrittenLatch.countDown(); ctx.pipeline().remove(this); } diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java index bc0da645d5..483e39e69d 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java @@ -44,6 +44,7 @@ import org.mockito.stubbing.Answer; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import static io.netty.buffer.Unpooled.copiedBuffer; import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf; @@ -240,6 +241,34 @@ public class Http2ConnectionHandlerTest { } } + @Test + public void clientShouldveSentPrefaceAndSettingsFrameWhenUserEventIsTriggered() throws Exception { + when(connection.isServer()).thenReturn(false); + when(channel.isActive()).thenReturn(false); + handler = newHandler(); + when(channel.isActive()).thenReturn(true); + + final Http2ConnectionPrefaceAndSettingsFrameWrittenEvent evt = + Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE; + + final AtomicBoolean verified = new AtomicBoolean(false); + final Answer verifier = new Answer() { + @Override + public Object answer(final InvocationOnMock in) throws Throwable { + assertTrue(in.getArgument(0).equals(evt)); // sanity check... + verify(ctx).write(eq(connectionPrefaceBuf())); + verify(encoder).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class)); + verified.set(true); + return null; + } + }; + + doAnswer(verifier).when(ctx).fireUserEventTriggered(evt); + + handler.channelActive(ctx); + assertTrue(verified.get()); + } + @Test public void clientShouldSendClientPrefaceStringWhenActive() throws Exception { when(connection.isServer()).thenReturn(false); diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionRoundtripTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionRoundtripTest.java index 8fb1f8a26d..09d610641a 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionRoundtripTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionRoundtripTest.java @@ -933,7 +933,7 @@ public class Http2ConnectionRoundtripTest { p.addLast(new ChannelInboundHandlerAdapter() { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof Http2ConnectionPrefaceWrittenEvent) { + if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) { prefaceWrittenLatch.countDown(); ctx.pipeline().remove(this); } diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java index d2226a428c..0e4f3e9520 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/HttpToHttp2ConnectionHandlerTest.java @@ -61,7 +61,6 @@ import static io.netty.handler.codec.http.HttpMethod.POST; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import static io.netty.handler.codec.http2.Http2TestUtil.of; import static io.netty.util.CharsetUtil.UTF_8; -import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -541,7 +540,7 @@ public class HttpToHttp2ConnectionHandlerTest { p.addLast(new ChannelInboundHandlerAdapter() { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof Http2ConnectionPrefaceWrittenEvent) { + if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) { prefaceWrittenLatch.countDown(); ctx.pipeline().remove(this); } diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java index 07fa916cbc..b29c0966d7 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/InboundHttp2ToHttpAdapterTest.java @@ -60,7 +60,6 @@ import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Except import static io.netty.handler.codec.http2.Http2Exception.isStreamError; import static io.netty.handler.codec.http2.Http2TestUtil.of; import static io.netty.handler.codec.http2.Http2TestUtil.runInChannel; -import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -725,7 +724,7 @@ public class InboundHttp2ToHttpAdapterTest { }); p.addLast(new ChannelInboundHandlerAdapter() { public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof Http2ConnectionPrefaceWrittenEvent) { + if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) { prefaceWrittenLatch.countDown(); ctx.pipeline().remove(this); }