Repository: netty/netty
Issue: HTTP/2 headers with END_STREAM writes a RST_STREAM
Labels: defect

If a headers frame is written with the END_STREAM flag sent we send a RST_STREAM frame.  The remote flow controller should not generate a RST_STREAM in this case.


Issue comments:
@nmittler @buchgr - I have a pending PR for this.

Fixed by https://github.com/netty/netty/pull/3733


Pull request review comments:

Patch that resolved the issue:
diff --git a/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp1Handler.java b/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp1Handler.java
index 009e8fa2131..aa8f1d29494 100644
--- a/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp1Handler.java
+++ b/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp1Handler.java
@@ -15,7 +15,9 @@
  */
 package io.netty.example.http2.server;
 
+import static io.netty.util.internal.ObjectUtil.checkNotNull;
 import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
@@ -24,7 +26,6 @@
 import io.netty.handler.codec.http.HttpHeaderUtil;
 import io.netty.handler.codec.http.HttpHeaderValues;
 import io.netty.handler.codec.http.HttpRequest;
-
 import static io.netty.handler.codec.http.HttpHeaderNames.*;
 import static io.netty.handler.codec.http.HttpResponseStatus.*;
 import static io.netty.handler.codec.http.HttpVersion.*;
@@ -33,6 +34,11 @@
  * HTTP handler that responds with a "Hello World"
  */
 public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequest> {
+    private final String establishApproach;
+
+    public HelloWorldHttp1Handler(String establishApproach) {
+        this.establishApproach = checkNotNull(establishApproach, "establishApproach");
+    }
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
@@ -43,6 +49,7 @@ public void messageReceived(ChannelHandlerContext ctx, HttpRequest req) throws E
 
         ByteBuf content = ctx.alloc().buffer();
         content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES.duplicate());
+        ByteBufUtil.writeAscii(content, " - via " + req.protocolVersion() + " (" + establishApproach + ")");
 
         FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
         response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
diff --git a/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp2Handler.java b/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp2Handler.java
index 61fff9e4b91..f0ae73fd6e1 100644
--- a/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp2Handler.java
+++ b/example/src/main/java/io/netty/example/http2/server/HelloWorldHttp2Handler.java
@@ -21,6 +21,7 @@
 import static io.netty.handler.codec.http.HttpResponseStatus.OK;
 import static io.netty.handler.logging.LogLevel.INFO;
 import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.http.HttpServerUpgradeHandler;
 import io.netty.handler.codec.http2.DefaultHttp2Connection;
@@ -112,7 +113,10 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId,
                 Http2Headers headers, int streamDependency, short weight,
                 boolean exclusive, int padding, boolean endStream) throws Http2Exception {
             if (endStream) {
-                sendResponse(ctx, streamId, RESPONSE_BYTES.duplicate());
+                ByteBuf content = ctx.alloc().buffer();
+                content.writeBytes(HelloWorldHttp2Handler.RESPONSE_BYTES.duplicate());
+                ByteBufUtil.writeAscii(content, " - via HTTP/2");
+                sendResponse(ctx, streamId, content);
             }
         }
 
diff --git a/example/src/main/java/io/netty/example/http2/server/Http2OrHttpHandler.java b/example/src/main/java/io/netty/example/http2/server/Http2OrHttpHandler.java
index bb8cae84f86..e07dec24868 100644
--- a/example/src/main/java/io/netty/example/http2/server/Http2OrHttpHandler.java
+++ b/example/src/main/java/io/netty/example/http2/server/Http2OrHttpHandler.java
@@ -48,7 +48,7 @@ protected SelectedProtocol getProtocol(SSLEngine engine) {
 
     @Override
     protected ChannelHandler createHttp1RequestHandler() {
-        return new HelloWorldHttp1Handler();
+        return new HelloWorldHttp1Handler("ALPN Negotiation");
     }
 
     @Override
diff --git a/example/src/main/java/io/netty/example/http2/server/Http2ServerInitializer.java b/example/src/main/java/io/netty/example/http2/server/Http2ServerInitializer.java
index ac36a9819b4..cc5a7f31ada 100644
--- a/example/src/main/java/io/netty/example/http2/server/Http2ServerInitializer.java
+++ b/example/src/main/java/io/netty/example/http2/server/Http2ServerInitializer.java
@@ -19,7 +19,9 @@
 import io.netty.channel.ChannelHandlerAdapter;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
+import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpMessage;
 import io.netty.handler.codec.http.HttpServerCodec;
 import io.netty.handler.codec.http.HttpServerUpgradeHandler;
 import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
@@ -66,6 +68,16 @@ private static void configureClearText(SocketChannel ch) {
 
         ch.pipeline().addLast(sourceCodec);
         ch.pipeline().addLast(upgradeHandler);
+        ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpMessage>() {
+            @Override
+            protected void messageReceived(ChannelHandlerContext ctx, HttpMessage msg) throws Exception {
+                // If this handler is hit then no upgrade has been attempted and the client is just talking HTTP.
+                System.err.println("Directly talking: " + msg.protocolVersion() + " (no upgrade was attempted)");
+                ctx.pipeline().replace(this, "http-hello-world",
+                        new HelloWorldHttp1Handler("Direct. No Upgrade Attempted."));
+                ctx.fireChannelRead(msg);
+            }
+        });
         ch.pipeline().addLast(new UserEventLogger());
     }
 


Test patch: