Repository: netty/netty
Issue: Http2StreamChannel doesn't inherit config of the parent channel
Labels: defect

# Problem

As you probably aware, Finagle is a bit special when it comes to Netty 4 usage. For example, we neither use pooling nor prefer direct buffers at the moment. We're getting close to the pooled/direct utopia, but we're not there yet.

That said, Finagle's HTTP/2 pipelines are unpooled and yet we've discovered that inbound messages on the server-side are pooled in some cases. Turns out, `Http2StreamChannel` doesn't inherit the channel config from the parent channel (in our case, a channel with unpooled allocator) and just [defaults to a standard setup effectively enabling pooling](https://github.com/netty/netty/blob/4.1/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2StreamChannel.java#L58).

A possible workaround is to override the default allocator (`-Dio.netty.allocator.type`).

Is there any reason to not pass parent's channel config to the `Http2StreamChannel` constructor to make sure it re-uses its settings? I'm happy to make a PR if that sounds like a reasonable solution.

I'm not excluding the possibility that this is done intentionally for HTTP/2 and there is a good reason to not reuse parent's channel config. I apologize if that's the case and I'm eager to hear your thoughts about this.

# Env Details

* Netty version: 4.1.9-Final
* JVM version: 1.8.0_111-b14
* OS: Darwin 15.6.0


Issue comments:
@vkostyukov this is a bug... Please open a PR FTW :)
Thanks @normanmaurer! I'm on it!
Fixed by https://github.com/netty/netty/pull/6552

Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
index e03abd2165d..83d9eb5ce7c 100644
--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodec.java
@@ -305,6 +305,12 @@ ChannelFuture createStreamChannel(Channel parentChannel, EventLoopGroup group, C
         }
         channel.pipeline().addLast(handler);
 
+        // We need to copy parent's channel options into a child's options to make
+        // sure they share same allocator, same receive buffer allocator, etc.
+        //
+        // See https://github.com/netty/netty/issues/6551
+        channel.config().setOptions(parentChannel.config().getOptions());
+
         initOpts(channel, options);
         initAttrs(channel, attrs);
 


Test patch:
diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java
index 95e57a5e24a..c17c1970da0 100644
--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java
+++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java
@@ -39,6 +39,7 @@
 import org.junit.Test;
 
 import static io.netty.util.ReferenceCountUtil.release;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -343,6 +344,28 @@ public void settingChannelOptsAndAttrsOnBootstrap() {
         assertEquals("bar", channel.attr(key).get());
     }
 
+    @Test
+    public void childChannelShouldShareParentsChannelOptions() {
+        EmbeddedChannel parent = new EmbeddedChannel();
+        parent.config().setAutoRead(false);
+        parent.config().setWriteSpinCount(42);
+
+        Http2StreamChannelBootstrap b = new Http2StreamChannelBootstrap();
+        parent.pipeline().addLast(new Http2MultiplexCodec(true, b));
+
+        Channel child = b
+            .parentChannel(parent)
+            .handler(new TestChannelInitializer())
+            .connect()
+            .channel();
+
+        assertFalse(child.config().isAutoRead());
+        assertEquals(child.config().getWriteSpinCount(), 42);
+
+        child.close();
+        assertTrue(!parent.finish());
+    }
+
     @Test
     public void outboundStreamShouldWriteGoAwayWithoutReset() {
         childChannelInitializer.handler = new ChannelInboundHandlerAdapter() {