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


The following commit(s) were added to refs/heads/8.5.x by this push:
     new 63c1d4e  Send WINDOW_UPDATE frames correctly when a DATA frame 
includes padding
63c1d4e is described below

commit 63c1d4e607e6aaa7ca12cd9c8a09b16765adcd25
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Aug 28 13:04:43 2020 +0100

    Send WINDOW_UPDATE frames correctly when a DATA frame includes padding
    
    When a Stream was closed the window update frame was not sent for the
    connection. When zero length padding was used, an update frame was not
    sent. In both cases the result would be a smaller flow control window
    than intended.
    
    Bugs detected by Travis CI
---
 java/org/apache/coyote/http2/Http2Parser.java      |  2 +-
 .../apache/coyote/http2/Http2UpgradeHandler.java   | 27 ++++++++--------
 test/org/apache/coyote/http2/Http2TestBase.java    | 28 +++++++++++++----
 .../apache/coyote/http2/TestHttp2Section_6_1.java  | 36 +++++++++++++++++-----
 webapps/docs/changelog.xml                         | 10 ++++++
 5 files changed, 76 insertions(+), 27 deletions(-)

diff --git a/java/org/apache/coyote/http2/Http2Parser.java 
b/java/org/apache/coyote/http2/Http2Parser.java
index 68dd528..a20ee33 100644
--- a/java/org/apache/coyote/http2/Http2Parser.java
+++ b/java/org/apache/coyote/http2/Http2Parser.java
@@ -195,7 +195,7 @@ class Http2Parser {
                 output.endRequestBodyFrame(streamId);
             }
         }
-        if (padLength > 0) {
+        if (Flags.hasPadding(flags)) {
             output.swallowedPadding(streamId, padLength);
         }
     }
diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java 
b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
index 62e1423..2d1957a 100644
--- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
@@ -792,9 +792,6 @@ public class Http2UpgradeHandler extends AbstractStream 
implements InternalHttpU
      */
     void writeWindowUpdate(Stream stream, int increment, boolean 
applicationInitiated)
             throws IOException {
-        if (!stream.canWrite()) {
-            return;
-        }
         synchronized (socketWrapper) {
             // Build window update frame for stream 0
             byte[] frame = new byte[13];
@@ -802,17 +799,21 @@ public class Http2UpgradeHandler extends AbstractStream 
implements InternalHttpU
             frame[3] = FrameType.WINDOW_UPDATE.getIdByte();
             ByteUtil.set31Bits(frame, 9, increment);
             socketWrapper.write(true, frame, 0, frame.length);
-            // Change stream Id and re-use
-            ByteUtil.set31Bits(frame, 5, stream.getIdAsInt());
-            try {
-                socketWrapper.write(true, frame, 0, frame.length);
-                socketWrapper.flush(true);
-            } catch (IOException ioe) {
-                if (applicationInitiated) {
-                    handleAppInitiatedIOException(ioe);
-                } else {
-                    throw ioe;
+            if  (stream.canWrite()) {
+                // Change stream Id and re-use
+                ByteUtil.set31Bits(frame, 5, stream.getIdAsInt());
+                try {
+                    socketWrapper.write(true, frame, 0, frame.length);
+                    socketWrapper.flush(true);
+                } catch (IOException ioe) {
+                    if (applicationInitiated) {
+                        handleAppInitiatedIOException(ioe);
+                    } else {
+                        throw ioe;
+                    }
                 }
+            } else {
+                socketWrapper.flush(true);
             }
         }
     }
diff --git a/test/org/apache/coyote/http2/Http2TestBase.java 
b/test/org/apache/coyote/http2/Http2TestBase.java
index ff70953..ce61d4b 100644
--- a/test/org/apache/coyote/http2/Http2TestBase.java
+++ b/test/org/apache/coyote/http2/Http2TestBase.java
@@ -459,19 +459,35 @@ public abstract class Http2TestBase extends 
TomcatBaseTest {
 
 
     protected void readSimplePostResponse(boolean padding) throws 
Http2Exception, IOException {
-        if (padding) {
-            // Window updates for padding
-            parser.readFrame(true);
-            parser.readFrame(true);
-        }
+        /*
+         * If there is padding there will always be a window update for the
+         * connection and, depending on timing, there may be an update for the
+         * stream. The Window updates for padding (if present) may appear at 
any
+         * time. The comments in the code below are only indicative of what the
+         * frames are likely to contain. Actual frame order with padding may be
+         * different.
+         */
+
         // Connection window update after reading request body
         parser.readFrame(true);
         // Stream window update after reading request body
         parser.readFrame(true);
         // Headers
         parser.readFrame(true);
-        // Body
+        // Body (includes end of stream)
         parser.readFrame(true);
+
+        if (padding) {
+            // Connection window update for padding
+            parser.readFrame(true);
+
+            // If EndOfStream has not been received then the stream window
+            // update must have been received so a further frame needs to be
+            // read for EndOfStream.
+            if (!output.getTrace().contains("EndOfStream")) {
+                parser.readFrame(true);
+            }
+        }
     }
 
 
diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_1.java 
b/test/org/apache/coyote/http2/TestHttp2Section_6_1.java
index 20405d4..8e3d948 100644
--- a/test/org/apache/coyote/http2/TestHttp2Section_6_1.java
+++ b/test/org/apache/coyote/http2/TestHttp2Section_6_1.java
@@ -62,14 +62,21 @@ public class TestHttp2Section_6_1 extends Http2TestBase {
             sendSimplePostRequest(3, padding);
             readSimplePostResponse(true);
 
-            // The window update for the padding could occur anywhere since it
-            // happens on a different thead to the response.
+            // The window updates for padding could occur anywhere since they
+            // happen on a different thread to the response.
+            // The connection window update is always present if there is
+            // padding.
             String trace = output.getTrace();
-            String paddingWindowUpdate = 
"0-WindowSize-[9]\n3-WindowSize-[9]\n";
-
+            String paddingWindowUpdate = "0-WindowSize-[9]\n";
             Assert.assertTrue(trace, trace.contains(paddingWindowUpdate));
             trace = trace.replace(paddingWindowUpdate, "");
 
+            // The stream window update may or may not be present depending on
+            //  timing. Remove it if present.
+            if (trace.contains("3-WindowSize-[9]\n")) {
+                trace = trace.replace("3-WindowSize-[9]\n", "");
+            }
+
             Assert.assertEquals("0-WindowSize-[119]\n" +
                     "3-WindowSize-[119]\n" +
                     "3-HeadersStart\n" +
@@ -155,8 +162,23 @@ public class TestHttp2Section_6_1 extends Http2TestBase {
         byte[] padding = new byte[0];
 
         sendSimplePostRequest(3, padding);
-        // Since padding is zero length, response looks like there is none.
-        readSimplePostResponse(false);
+        readSimplePostResponse(true);
+
+        // The window updates for padding could occur anywhere since they
+        // happen on a different thread to the response.
+        // The connection window update is always present if there is
+        // padding.
+        String trace = output.getTrace();
+        String paddingWindowUpdate = "0-WindowSize-[1]\n";
+        Assert.assertTrue(trace, trace.contains(paddingWindowUpdate));
+        trace = trace.replace(paddingWindowUpdate, "");
+
+        // The stream window update may or may not be present depending on
+        //  timing. Remove it if present.
+        paddingWindowUpdate = "3-WindowSize-[1]\n";
+        if (trace.contains(paddingWindowUpdate)) {
+            trace = trace.replace(paddingWindowUpdate, "");
+        }
 
         Assert.assertEquals("0-WindowSize-[127]\n" +
                 "3-WindowSize-[127]\n" +
@@ -166,6 +188,6 @@ public class TestHttp2Section_6_1 extends Http2TestBase {
                 "3-Header-[date]-[Wed, 11 Nov 2015 19:18:42 GMT]\n" +
                 "3-HeadersEnd\n" +
                 "3-Body-127\n" +
-                "3-EndOfStream\n", output.getTrace());
+                "3-EndOfStream\n", trace);
     }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index bba5959..67108b5 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -120,6 +120,16 @@
         the stream immediately if it is waiting for an allocation when the flow
         control error occurs. (markt)
       </fix>
+      <fix>
+        Ensure that window update frames are sent for HTTP/2 connections to
+        account for DATA frames containing padding including when the 
associated
+        stream has been closed. (markt)
+      </fix>
+      <fix>
+        Ensure that window update frames are sent for HTTP/2 connections and
+        streams to account for DATA frames containing zero-length padding.
+        (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="WebSocket">


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

Reply via email to