Http2MultiplexCodec now propagates SETTINGS and GOAWAY frames in pipeline.

Motivation:

Allow the observation of SETTINGS frame by other handlers in the pipeline. For my particular use case this allows me to observe the value of MAX_CONCURRENT_STREAMS for a ChannelPool abstraction that supports HTTP/2 multiplexing. Beside this also forward GOAWAY frames.

Modification:

Always forward SETTINGS and GOAWAY frames

Result:

Settings / Goaway can now be observed in the parent channel. Previously it was not possible (to my knowledge) to capture the settings when using Http2MultiplexCodec.
This commit is contained in:
shorea 2018-02-12 17:42:59 -08:00 committed by Norman Maurer
parent 02b7507a62
commit 650406c0a3
3 changed files with 26 additions and 10 deletions

View File

@ -66,7 +66,8 @@ import static java.lang.Math.min;
* communication, closing of the channel is delayed until any inbound queue is drained with {@link
* Channel#read()}, which follows the default behavior of channels in Netty. Applications are
* free to close the channel in response to such events if they don't have use for any queued
* messages.
* messages. Any connection level events like {@link Http2SettingsFrame} and {@link Http2GoAwayFrame}
* will be processed internally and also propagated down the pipeline for other handlers to act on.
*
* <p>Outbound streams are supported via the {@link Http2StreamChannelBootstrap}.
*
@ -164,8 +165,10 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
// Need to be volatile as accessed from within the DefaultHttp2StreamChannel in a multi-threaded fashion.
volatile ChannelHandlerContext ctx;
Http2MultiplexCodec(Http2ConnectionEncoder encoder, Http2ConnectionDecoder decoder, Http2Settings initialSettings,
ChannelHandler inboundStreamHandler) {
Http2MultiplexCodec(Http2ConnectionEncoder encoder,
Http2ConnectionDecoder decoder,
Http2Settings initialSettings,
ChannelHandler inboundStreamHandler) {
super(encoder, decoder, initialSettings);
this.inboundStreamHandler = inboundStreamHandler;
}
@ -218,11 +221,15 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
onHttp2StreamFrame(((Http2MultiplexCodecStream) streamFrame.stream()).channel, streamFrame);
} else if (frame instanceof Http2GoAwayFrame) {
onHttp2GoAwayFrame(ctx, (Http2GoAwayFrame) frame);
// Allow other handlers to act on GOAWAY frame
ctx.fireChannelRead(frame);
} else if (frame instanceof Http2SettingsFrame) {
Http2Settings settings = ((Http2SettingsFrame) frame).settings();
if (settings.initialWindowSize() != null) {
initialOutboundStreamWindow = settings.initialWindowSize();
}
// Allow other handlers to act on SETTINGS frame
ctx.fireChannelRead(frame);
} else {
// Send any other frames down the pipeline
ctx.fireChannelRead(frame);

View File

@ -231,7 +231,7 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
ByteBuf settingsFrame = settingsFrameBuf();
assertFalse(channel.writeInbound(settingsFrame));
assertTrue(channel.writeInbound(settingsFrame));
assertEquals(1, userEvents.size());
assertTrue(userEvents.get(0) instanceof PriorKnowledgeUpgradeEvent);

View File

@ -41,11 +41,13 @@ import org.junit.Ignore;
import org.junit.Test;
import static io.netty.util.ReferenceCountUtil.release;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
@ -175,11 +177,15 @@ public class Http2MultiplexCodecTest {
@Test
public void unhandledHttp2FramesShouldBePropagated() {
Http2PingFrame decodedFrame = new DefaultHttp2PingFrame(0);
assertThat(parentChannel.readInbound(), instanceOf(Http2SettingsFrame.class));
codec.onHttp2Frame(decodedFrame);
Http2PingFrame receivedPing = parentChannel.readInbound();
assertSame(receivedPing, decodedFrame);
Http2PingFrame pingFrame = new DefaultHttp2PingFrame(0);
codec.onHttp2Frame(pingFrame);
assertSame(parentChannel.readInbound(), pingFrame);
DefaultHttp2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(1);
codec.onHttp2Frame(goAwayFrame);
assertSame(parentChannel.readInbound(), goAwayFrame);
}
@Test
@ -619,8 +625,10 @@ public class Http2MultiplexCodecTest {
*/
private final class TestableHttp2MultiplexCodec extends Http2MultiplexCodec {
public TestableHttp2MultiplexCodec(Http2ConnectionEncoder encoder, Http2ConnectionDecoder decoder,
Http2Settings initialSettings, ChannelHandler inboundStreamHandler) {
public TestableHttp2MultiplexCodec(Http2ConnectionEncoder encoder,
Http2ConnectionDecoder decoder,
Http2Settings initialSettings,
ChannelHandler inboundStreamHandler) {
super(encoder, decoder, initialSettings, inboundStreamHandler);
}
@ -682,6 +690,7 @@ public class Http2MultiplexCodecTest {
}
private final class TestableHttp2MultiplexCodecBuilder extends Http2MultiplexCodecBuilder {
TestableHttp2MultiplexCodecBuilder(boolean server, ChannelHandler childHandler) {
super(server, childHandler);
}