This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit ab34aa9a338c3de113dfe4dda1ebbd49defb7d04
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Jan 25 16:28:34 2023 +0000

    Fix BZ 66442 - h2 responses without bodies should not use DATA frames
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=66442
---
 java/org/apache/coyote/http2/Stream.java           |  7 ++++
 java/org/apache/coyote/http2/StreamProcessor.java  |  4 ++
 test/org/apache/coyote/http2/Http2TestBase.java    | 12 ++++++
 .../apache/coyote/http2/TestStreamProcessor.java   | 49 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  5 +++
 5 files changed, 77 insertions(+)

diff --git a/java/org/apache/coyote/http2/Stream.java 
b/java/org/apache/coyote/http2/Stream.java
index 51f9f72f76..2c05ff688f 100644
--- a/java/org/apache/coyote/http2/Stream.java
+++ b/java/org/apache/coyote/http2/Stream.java
@@ -34,6 +34,7 @@ import org.apache.coyote.Response;
 import org.apache.coyote.http11.HttpOutputBuffer;
 import org.apache.coyote.http11.OutputFilter;
 import org.apache.coyote.http11.filters.SavedRequestInputFilter;
+import org.apache.coyote.http11.filters.VoidOutputFilter;
 import org.apache.coyote.http2.HpackDecoder.HeaderEmitter;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -425,6 +426,12 @@ class Stream extends AbstractNonZeroStream implements 
HeaderEmitter {
     }
 
 
+    void configureVoidOutputFilter() {
+        addOutputFilter(new VoidOutputFilter());
+        // Prevent further writes by the application
+        streamOutputBuffer.closed = true;
+    }
+
     private void parseAuthority(String value, boolean host) throws 
HpackException {
         int i;
         try {
diff --git a/java/org/apache/coyote/http2/StreamProcessor.java 
b/java/org/apache/coyote/http2/StreamProcessor.java
index d6e48624b3..d51ad971e1 100644
--- a/java/org/apache/coyote/http2/StreamProcessor.java
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
@@ -182,6 +182,10 @@ class StreamProcessor extends AbstractProcessor {
                 headers.addValue("content-length").setLong(contentLength);
             }
         } else {
+            // Disable response body
+            if (stream != null) {
+                stream.configureVoidOutputFilter();
+            }
             if (statusCode == 205) {
                 // RFC 7231 requires the server to explicitly signal an empty
                 // response in this case
diff --git a/test/org/apache/coyote/http2/Http2TestBase.java 
b/test/org/apache/coyote/http2/Http2TestBase.java
index e6f60a2f3a..5d4b2d9dae 100644
--- a/test/org/apache/coyote/http2/Http2TestBase.java
+++ b/test/org/apache/coyote/http2/Http2TestBase.java
@@ -1269,6 +1269,18 @@ public abstract class Http2TestBase extends 
TomcatBaseTest {
     }
 
 
+    public static class NoContentServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
+        }
+    }
+
+
     protected static class SimpleServlet extends HttpServlet {
 
         private static final long serialVersionUID = 1L;
diff --git a/test/org/apache/coyote/http2/TestStreamProcessor.java 
b/test/org/apache/coyote/http2/TestStreamProcessor.java
index 21ec994ba7..ff3f7d07cf 100644
--- a/test/org/apache/coyote/http2/TestStreamProcessor.java
+++ b/test/org/apache/coyote/http2/TestStreamProcessor.java
@@ -165,6 +165,55 @@ public class TestStreamProcessor extends Http2TestBase {
         }
         expected.append("3-Header-[date]-[Wed, 11 Nov 2015 19:18:42 GMT]\n");
         expected.append("3-HeadersEnd\n");
+        expected.append("3-EndOfStream\n");
+
+        Assert.assertEquals(expected.toString(), output.getTrace());
+    }
+
+
+    @Test
+    public void testPrepareHeadersNoContent() throws Exception {
+        enableHttp2();
+
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp");
+        Context ctxt = tomcat.addWebapp(null, "", appDir.getAbsolutePath());
+
+        Tomcat.addServlet(ctxt, "simple", new SimpleServlet());
+        ctxt.addServletMappingDecoded("/simple", "simple");
+        Tomcat.addServlet(ctxt, "noContent", new NoContentServlet());
+        ctxt.addServletMappingDecoded("/noContent", "noContent");
+
+
+        tomcat.start();
+
+        openClientConnection();
+        doHttpUpgrade();
+        sendClientPreface();
+        validateHttp2InitialResponse();
+
+        byte[] frameHeader = new byte[9];
+        ByteBuffer headersPayload = ByteBuffer.allocate(128);
+
+        List<Header> headers = new ArrayList<>(3);
+        headers.add(new Header(":method", "GET"));
+        headers.add(new Header(":scheme", "http"));
+        headers.add(new Header(":path", "/noContent"));
+        headers.add(new Header(":authority", "localhost:" + getPort()));
+
+        buildGetRequest(frameHeader, headersPayload, null, headers, 3);
+
+        writeFrame(frameHeader, headersPayload);
+
+        parser.readFrame();
+
+        StringBuilder expected = new StringBuilder();
+        expected.append("3-HeadersStart\n");
+        expected.append("3-Header-[:status]-[204]\n");
+        expected.append("3-Header-[date]-[Wed, 11 Nov 2015 19:18:42 GMT]\n");
+        expected.append("3-HeadersEnd\n");
+        expected.append("3-EndOfStream\n");
 
         Assert.assertEquals(expected.toString(), output.getTrace());
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 5bcc002b2a..9a0cee9c51 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -119,6 +119,11 @@
         Log basic information for each configured TLS certificate when Tomcat
         starts. (markt)
       </add>
+      <fix>
+        <bug>66442</bug>: When an HTTP/2 response must not include a body,
+        ensure that the end of stream flag is set on the headers frame and that
+        no data frame is sent. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to