Configures HTTP2 pipeline with more proper way

Motivation:

When we use pipeline.replace and we still had ongoing inbound, then
there will be some problem that inbound message would go to wrong
handlers. So we add handler first, and remove self after add, so that
the next handler will be the correct one.

Modifications:

Uses remove after addAfter instead of replace.

Result:

Fixed #6881
This commit is contained in:
chhsiao90 2017-07-07 20:51:16 +08:00 committed by Norman Maurer
parent 6ab9c177ac
commit 8320a45c15
2 changed files with 55 additions and 5 deletions

View File

@ -89,8 +89,11 @@ public final class CleartextHttp2ServerUpgradeHandler extends ChannelHandlerAdap
// following network traffic // following network traffic
ctx.pipeline() ctx.pipeline()
.remove(httpServerCodec) .remove(httpServerCodec)
.remove(httpServerUpgradeHandler) .remove(httpServerUpgradeHandler);
.replace(this, null, http2ServerHandler);
ctx.pipeline().addAfter(ctx.name(), null, http2ServerHandler);
ctx.pipeline().remove(this);
ctx.fireUserEventTriggered(PriorKnowledgeUpgradeEvent.INSTANCE); ctx.fireUserEventTriggered(PriorKnowledgeUpgradeEvent.INSTANCE);
} }
} }

View File

@ -17,8 +17,10 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
@ -35,7 +37,6 @@ import io.netty.handler.codec.http2.Http2Stream.State;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import org.junit.After; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
@ -56,8 +57,7 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
private List<Object> userEvents; private List<Object> userEvents;
@Before private void setUpServerChannel() {
public void setUp() {
frameListener = mock(Http2FrameListener.class); frameListener = mock(Http2FrameListener.class);
http2ConnectionHandler = new Http2ConnectionHandlerBuilder().frameListener(frameListener).build(); http2ConnectionHandler = new Http2ConnectionHandlerBuilder().frameListener(frameListener).build();
@ -91,6 +91,8 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
@Test @Test
public void priorKnowledge() throws Exception { public void priorKnowledge() throws Exception {
setUpServerChannel();
channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf()); channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf());
ByteBuf settingsFrame = settingsFrameBuf(); ByteBuf settingsFrame = settingsFrameBuf();
@ -109,6 +111,8 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
@Test @Test
public void upgrade() throws Exception { public void upgrade() throws Exception {
setUpServerChannel();
String upgradeString = "GET / HTTP/1.1\r\n" + String upgradeString = "GET / HTTP/1.1\r\n" +
"Host: example.com\r\n" + "Host: example.com\r\n" +
"Connection: Upgrade, HTTP2-Settings\r\n" + "Connection: Upgrade, HTTP2-Settings\r\n" +
@ -138,6 +142,8 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
@Test @Test
public void priorKnowledgeInFragments() throws Exception { public void priorKnowledgeInFragments() throws Exception {
setUpServerChannel();
ByteBuf connectionPreface = Http2CodecUtil.connectionPrefaceBuf(); ByteBuf connectionPreface = Http2CodecUtil.connectionPrefaceBuf();
assertFalse(channel.writeInbound(connectionPreface.readBytes(5), connectionPreface)); assertFalse(channel.writeInbound(connectionPreface.readBytes(5), connectionPreface));
@ -156,6 +162,8 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
@Test @Test
public void downgrade() throws Exception { public void downgrade() throws Exception {
setUpServerChannel();
String requestString = "GET / HTTP/1.1\r\n" + String requestString = "GET / HTTP/1.1\r\n" +
"Host: example.com\r\n\r\n"; "Host: example.com\r\n\r\n";
ByteBuf inbound = Unpooled.buffer().writeBytes(requestString.getBytes(CharsetUtil.US_ASCII)); ByteBuf inbound = Unpooled.buffer().writeBytes(requestString.getBytes(CharsetUtil.US_ASCII));
@ -175,6 +183,45 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
assertNull(channel.readInbound()); assertNull(channel.readInbound());
} }
@Test
public void usedHttp2Codec() throws Exception {
final Http2Codec http2Codec = new Http2CodecBuilder(true, new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
}
}).build();
UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() {
@Override
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
return new Http2ServerUpgradeCodec(http2Codec);
}
};
http2ConnectionHandler = http2Codec.frameCodec().connectionHandler();
userEvents = new ArrayList<Object>();
HttpServerCodec httpServerCodec = new HttpServerCodec();
HttpServerUpgradeHandler upgradeHandler = new HttpServerUpgradeHandler(httpServerCodec, upgradeCodecFactory);
CleartextHttp2ServerUpgradeHandler handler = new CleartextHttp2ServerUpgradeHandler(
httpServerCodec, upgradeHandler, http2Codec);
channel = new EmbeddedChannel(handler, new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
userEvents.add(evt);
}
});
assertFalse(channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf()));
ByteBuf settingsFrame = settingsFrameBuf();
assertFalse(channel.writeInbound(settingsFrame));
assertEquals(1, userEvents.size());
assertTrue(userEvents.get(0) instanceof PriorKnowledgeUpgradeEvent);
}
private static ByteBuf settingsFrameBuf() { private static ByteBuf settingsFrameBuf() {
ByteBuf settingsFrame = Unpooled.buffer(); ByteBuf settingsFrame = Unpooled.buffer();
settingsFrame.writeMedium(12); // Payload length settingsFrame.writeMedium(12); // Payload length