Author: markt
Date: Wed Jan 11 20:54:41 2017
New Revision: 1778348

URL: http://svn.apache.org/viewvc?rev=1778348&view=rev
Log:
Improve handling of case when an HTTP/2 client sends more data that is subject 
to flow control than the current window size allows.

Added:
    tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java   (with 
props)
Modified:
    tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java?rev=1778348&r1=1778347&r2=1778348&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java Wed Jan 11 
20:54:41 2017
@@ -178,6 +178,11 @@ class Http2Parser {
             }
         } else {
             synchronized (dest) {
+                if (dest.remaining() < dataLength) {
+                    swallow(streamId, dataLength, false);
+                    // Client has sent more data than permitted by Window size
+                    throw new StreamException("Client sent more data than 
stream window allowed", Http2Error.FLOW_CONTROL_ERROR, streamId);
+                }
                 input.fill(true, dest, dataLength);
                 // Process padding before sending any notifications in case
                 // padding is invalid.

Added: tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java?rev=1778348&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java (added)
+++ tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java Wed Jan 11 
20:54:41 2017
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.coyote.http2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.startup.Tomcat;
+
+public class TestAbortedUpload extends Http2TestBase {
+
+    @Test
+    public void testAbortedRequest() throws Exception {
+        http2Connect();
+
+        Http2Protocol http2Protocol =
+                (Http2Protocol) 
getTomcatInstance().getConnector().findUpgradeProtocols()[0];
+        http2Protocol.setAllowedTrailerHeaders(TRAILER_HEADER_NAME);
+
+        int bodySize = 8192;
+        int bodyCount = 10;
+
+        byte[] headersFrameHeader = new byte[9];
+        ByteBuffer headersPayload = ByteBuffer.allocate(128);
+        byte[] dataFrameHeader = new byte[9];
+        ByteBuffer dataPayload = ByteBuffer.allocate(bodySize);
+        byte[] trailerFrameHeader = new byte[9];
+        ByteBuffer trailerPayload = ByteBuffer.allocate(256);
+
+        buildPostRequest(headersFrameHeader, headersPayload, false, 
dataFrameHeader, dataPayload,
+                null, trailerFrameHeader, trailerPayload, 3);
+
+        // Write the headers
+        writeFrame(headersFrameHeader, headersPayload);
+        // Body
+        for (int i = 0; i < bodyCount; i++) {
+            writeFrame(dataFrameHeader, dataPayload);
+        }
+
+        // Trailers
+        writeFrame(trailerFrameHeader, trailerPayload);
+
+
+        parser.readFrame(true);
+        parser.readFrame(true);
+        parser.readFrame(true);
+        parser.readFrame(true);
+
+        // Tomcat's default Window size is 8*8k (StreamInputBuffer.inBuffer)
+        // This test sends 10*8k
+        // 9th and 10th data frames trigger a RST for a flow control error
+        // Test reads input stream which copies up to 8k into
+        // StreamInputBuffer.outBuffer
+        // That leaves 8k free in inBuffer buffer which triggers a Window 
Update
+        Assert.assertEquals(
+                "3-RST-[3]\n" +
+                "3-RST-[3]\n" +
+                "0-WindowSize-[8192]\n" +
+                "3-WindowSize-[8192]\n",
+                output.getTrace());
+    }
+
+
+    @Override
+    protected void configureAndStartWebApplication() throws LifecycleException 
{
+        Tomcat tomcat = getTomcatInstance();
+
+        // Retain '/simple' url-pattern since it enables code re-use
+        Context ctxt = tomcat.addContext("", null);
+        Tomcat.addServlet(ctxt, "abort", new AbortServlet());
+        ctxt.addServletMappingDecoded("/simple", "abort");
+
+        tomcat.start();
+    }
+
+
+    private static class AbortServlet extends SimpleServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse 
resp) throws ServletException, IOException {
+            // Read upto 128 bytes and then return a 403 response
+
+            InputStream is = req.getInputStream();
+            byte[] buf = new byte[128];
+            int toRead = 128;
+
+            int read = is.read(buf);
+            while (read != -1 && toRead > 0) {
+                toRead -= read;
+                read = is.read(buf);
+            }
+
+            if (toRead == 0) {
+                resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            } else {
+                resp.setStatus(HttpServletResponse.SC_OK);
+            }
+        }
+    }
+}

Propchange: tomcat/trunk/test/org/apache/coyote/http2/TestAbortedUpload.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1778348&r1=1778347&r2=1778348&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Jan 11 20:54:41 2017
@@ -45,6 +45,14 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 9.0.0.M18 (markt)" rtext="in development">
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Improve handling of case when an HTTP/2 client sends more data that is
+        subject to flow control than the current window size allows. (markt)
+      </fix>
+    </changelog>
+  </subsection>
   <subsection name="Other">
     <changelog>
       <fix>



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

Reply via email to