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:
parent
02b7507a62
commit
650406c0a3
@ -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
|
* 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
|
* 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
|
* 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}.
|
* <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.
|
// Need to be volatile as accessed from within the DefaultHttp2StreamChannel in a multi-threaded fashion.
|
||||||
volatile ChannelHandlerContext ctx;
|
volatile ChannelHandlerContext ctx;
|
||||||
|
|
||||||
Http2MultiplexCodec(Http2ConnectionEncoder encoder, Http2ConnectionDecoder decoder, Http2Settings initialSettings,
|
Http2MultiplexCodec(Http2ConnectionEncoder encoder,
|
||||||
ChannelHandler inboundStreamHandler) {
|
Http2ConnectionDecoder decoder,
|
||||||
|
Http2Settings initialSettings,
|
||||||
|
ChannelHandler inboundStreamHandler) {
|
||||||
super(encoder, decoder, initialSettings);
|
super(encoder, decoder, initialSettings);
|
||||||
this.inboundStreamHandler = inboundStreamHandler;
|
this.inboundStreamHandler = inboundStreamHandler;
|
||||||
}
|
}
|
||||||
@ -218,11 +221,15 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
|||||||
onHttp2StreamFrame(((Http2MultiplexCodecStream) streamFrame.stream()).channel, streamFrame);
|
onHttp2StreamFrame(((Http2MultiplexCodecStream) streamFrame.stream()).channel, streamFrame);
|
||||||
} else if (frame instanceof Http2GoAwayFrame) {
|
} else if (frame instanceof Http2GoAwayFrame) {
|
||||||
onHttp2GoAwayFrame(ctx, (Http2GoAwayFrame) frame);
|
onHttp2GoAwayFrame(ctx, (Http2GoAwayFrame) frame);
|
||||||
|
// Allow other handlers to act on GOAWAY frame
|
||||||
|
ctx.fireChannelRead(frame);
|
||||||
} else if (frame instanceof Http2SettingsFrame) {
|
} else if (frame instanceof Http2SettingsFrame) {
|
||||||
Http2Settings settings = ((Http2SettingsFrame) frame).settings();
|
Http2Settings settings = ((Http2SettingsFrame) frame).settings();
|
||||||
if (settings.initialWindowSize() != null) {
|
if (settings.initialWindowSize() != null) {
|
||||||
initialOutboundStreamWindow = settings.initialWindowSize();
|
initialOutboundStreamWindow = settings.initialWindowSize();
|
||||||
}
|
}
|
||||||
|
// Allow other handlers to act on SETTINGS frame
|
||||||
|
ctx.fireChannelRead(frame);
|
||||||
} else {
|
} else {
|
||||||
// Send any other frames down the pipeline
|
// Send any other frames down the pipeline
|
||||||
ctx.fireChannelRead(frame);
|
ctx.fireChannelRead(frame);
|
||||||
|
@ -231,7 +231,7 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
|
|||||||
|
|
||||||
ByteBuf settingsFrame = settingsFrameBuf();
|
ByteBuf settingsFrame = settingsFrameBuf();
|
||||||
|
|
||||||
assertFalse(channel.writeInbound(settingsFrame));
|
assertTrue(channel.writeInbound(settingsFrame));
|
||||||
|
|
||||||
assertEquals(1, userEvents.size());
|
assertEquals(1, userEvents.size());
|
||||||
assertTrue(userEvents.get(0) instanceof PriorKnowledgeUpgradeEvent);
|
assertTrue(userEvents.get(0) instanceof PriorKnowledgeUpgradeEvent);
|
||||||
|
@ -41,11 +41,13 @@ import org.junit.Ignore;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static io.netty.util.ReferenceCountUtil.release;
|
import static io.netty.util.ReferenceCountUtil.release;
|
||||||
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,11 +177,15 @@ public class Http2MultiplexCodecTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void unhandledHttp2FramesShouldBePropagated() {
|
public void unhandledHttp2FramesShouldBePropagated() {
|
||||||
Http2PingFrame decodedFrame = new DefaultHttp2PingFrame(0);
|
assertThat(parentChannel.readInbound(), instanceOf(Http2SettingsFrame.class));
|
||||||
|
|
||||||
codec.onHttp2Frame(decodedFrame);
|
Http2PingFrame pingFrame = new DefaultHttp2PingFrame(0);
|
||||||
Http2PingFrame receivedPing = parentChannel.readInbound();
|
codec.onHttp2Frame(pingFrame);
|
||||||
assertSame(receivedPing, decodedFrame);
|
assertSame(parentChannel.readInbound(), pingFrame);
|
||||||
|
|
||||||
|
DefaultHttp2GoAwayFrame goAwayFrame = new DefaultHttp2GoAwayFrame(1);
|
||||||
|
codec.onHttp2Frame(goAwayFrame);
|
||||||
|
assertSame(parentChannel.readInbound(), goAwayFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -619,8 +625,10 @@ public class Http2MultiplexCodecTest {
|
|||||||
*/
|
*/
|
||||||
private final class TestableHttp2MultiplexCodec extends Http2MultiplexCodec {
|
private final class TestableHttp2MultiplexCodec extends Http2MultiplexCodec {
|
||||||
|
|
||||||
public TestableHttp2MultiplexCodec(Http2ConnectionEncoder encoder, Http2ConnectionDecoder decoder,
|
public TestableHttp2MultiplexCodec(Http2ConnectionEncoder encoder,
|
||||||
Http2Settings initialSettings, ChannelHandler inboundStreamHandler) {
|
Http2ConnectionDecoder decoder,
|
||||||
|
Http2Settings initialSettings,
|
||||||
|
ChannelHandler inboundStreamHandler) {
|
||||||
super(encoder, decoder, initialSettings, inboundStreamHandler);
|
super(encoder, decoder, initialSettings, inboundStreamHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +690,7 @@ public class Http2MultiplexCodecTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class TestableHttp2MultiplexCodecBuilder extends Http2MultiplexCodecBuilder {
|
private final class TestableHttp2MultiplexCodecBuilder extends Http2MultiplexCodecBuilder {
|
||||||
|
|
||||||
TestableHttp2MultiplexCodecBuilder(boolean server, ChannelHandler childHandler) {
|
TestableHttp2MultiplexCodecBuilder(boolean server, ChannelHandler childHandler) {
|
||||||
super(server, childHandler);
|
super(server, childHandler);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user