Author: markt
Date: Fri Feb  1 10:28:14 2019
New Revision: 1852700

URL: http://svn.apache.org/viewvc?rev=1852700&view=rev
Log:
Implement read timeout for direct read of request body

Modified:
    tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
    tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Timeouts.java

Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties?rev=1852700&r1=1852699&r2=1852700&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties [UTF-8] 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties [UTF-8] 
Fri Feb  1 10:28:14 2019
@@ -91,6 +91,7 @@ stream.header.unknownPseudoHeader=Connec
 stream.inputBuffer.copy=Copying [{0}] bytes from inBuffer to outBuffer
 stream.inputBuffer.dispatch=Data added to inBuffer when read interest is 
registered. Triggering a read dispatch
 stream.inputBuffer.empty=The Stream input buffer is empty. Waiting for more 
data
+stream.inputBuffer.readTimeout=Timeout waiting to read data from client
 stream.inputBuffer.reset=Stream reset
 stream.inputBuffer.signal=Data added to inBuffer when read thread is waiting. 
Signalling that thread to continue
 stream.notWritable=Connection [{0}], Stream [{1}], This stream is not writable

Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1852700&r1=1852699&r2=1852700&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Fri Feb  1 10:28:14 
2019
@@ -977,10 +977,22 @@ class Stream extends AbstractStream impl
                         if (log.isDebugEnabled()) {
                             
log.debug(sm.getString("stream.inputBuffer.empty"));
                         }
-                        inBuffer.wait();
+
+                        
inBuffer.wait(handler.getProtocol().getStreamReadTimeout());
+
                         if (resetReceived) {
                             throw new 
IOException(sm.getString("stream.inputBuffer.reset"));
                         }
+
+                        if (inBuffer.position() == 0) {
+                            String msg = 
sm.getString("stream.inputBuffer.readTimeout");
+                            StreamException se = new StreamException(
+                                    msg, Http2Error.ENHANCE_YOUR_CALM, 
getIdAsInt());
+                            // Trigger a reset once control returns to Tomcat
+                            coyoteResponse.setError();
+                            streamOutputBuffer.reset = se;
+                            throw new CloseNowException(msg, se);
+                        }
                     } catch (InterruptedException e) {
                         // Possible shutdown / rst or similar. Use an
                         // IOException to signal to the client that further I/O

Modified: tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java?rev=1852700&r1=1852699&r2=1852700&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java Fri Feb  1 
10:28:14 2019
@@ -28,6 +28,7 @@ import java.nio.charset.StandardCharsets
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Random;
 
 import javax.net.SocketFactory;
@@ -302,6 +303,24 @@ public abstract class Http2TestBase exte
     }
 
 
+    protected void sendParameterPostRequest(int streamId, byte[] padding, 
String body,
+            long contentLength, boolean useExpectation) throws IOException {
+        byte[] headersFrameHeader = new byte[9];
+        ByteBuffer headersPayload = ByteBuffer.allocate(128);
+        byte[] dataFrameHeader = new byte[9];
+        ByteBuffer dataPayload = ByteBuffer.allocate(128);
+
+        buildPostRequest(headersFrameHeader, headersPayload, useExpectation,
+                "application/x-www-form-urlencoded", contentLength, 
"/parameter", dataFrameHeader,
+                dataPayload, padding, null, null, streamId);
+        writeFrame(headersFrameHeader, headersPayload);
+        if (body != null) {
+            dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1));
+            writeFrame(dataFrameHeader, dataPayload);
+        }
+    }
+
+
     protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer 
headersPayload,
             boolean useExpectation, byte[] dataFrameHeader, ByteBuffer 
dataPayload, byte[] padding,
             int streamId) {
@@ -312,14 +331,29 @@ public abstract class Http2TestBase exte
     protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer 
headersPayload,
             boolean useExpectation, byte[] dataFrameHeader, ByteBuffer 
dataPayload, byte[] padding,
             byte[] trailersFrameHeader, ByteBuffer trailersPayload, int 
streamId) {
+        buildPostRequest(headersFrameHeader, headersPayload, useExpectation, 
null, -1, "/simple",
+                dataFrameHeader, dataPayload, padding, trailersFrameHeader, 
trailersPayload, streamId);
+    }
+
+    protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer 
headersPayload,
+            boolean useExpectation, String contentType, long contentLength, 
String path,
+            byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding,
+            byte[] trailersFrameHeader, ByteBuffer trailersPayload, int 
streamId) {
+
         MimeHeaders headers = new MimeHeaders();
         headers.addValue(":method").setString("POST");
         headers.addValue(":scheme").setString("http");
-        headers.addValue(":path").setString("/simple");
+        headers.addValue(":path").setString(path);
         headers.addValue(":authority").setString("localhost:" + getPort());
         if (useExpectation) {
             headers.addValue("expect").setString("100-continue");
         }
+        if (contentType != null) {
+            headers.addValue("content-type").setString(contentType);
+        }
+        if (contentLength > -1) {
+            headers.addValue("content-length").setLong(contentLength);
+        }
         hpackEncoder.encode(headers, headersPayload);
 
         headersPayload.flip();
@@ -514,6 +548,8 @@ public abstract class Http2TestBase exte
         ctxt.addServletMappingDecoded("/large", "large");
         Tomcat.addServlet(ctxt, "cookie", new CookieServlet());
         ctxt.addServletMappingDecoded("/cookie", "cookie");
+        Tomcat.addServlet(ctxt, "parameter", new ParameterServlet());
+        ctxt.addServletMappingDecoded("/parameter", "parameter");
 
         tomcat.start();
     }
@@ -1222,6 +1258,24 @@ public abstract class Http2TestBase exte
         }
     }
 
+
+    static class ParameterServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            Map<String,String[]> params = req.getParameterMap();
+
+            resp.setContentType("text/plain");
+            resp.setCharacterEncoding("UTF-8");
+
+            resp.getWriter().print(params.size());
+        }
+    }
+
 
     static class SettingValue {
         private final int setting;

Modified: tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Timeouts.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Timeouts.java?rev=1852700&r1=1852699&r2=1852700&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Timeouts.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Timeouts.java Fri Feb  1 
10:28:14 2019
@@ -26,7 +26,6 @@ public class TestHttp2Timeouts extends H
     @Before
     public void http2Connect() throws Exception {
         super.http2Connect();
-        sendSettings(0, false, new 
SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
     }
 
 
@@ -36,6 +35,7 @@ public class TestHttp2Timeouts extends H
      */
     @Test
     public void testClientWithEmptyWindow() throws Exception {
+        sendSettings(0, false, new 
SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
         sendSimpleGetRequest(3);
 
         // Settings
@@ -57,6 +57,7 @@ public class TestHttp2Timeouts extends H
      */
     @Test
     public void testClientWithEmptyWindowLargeResponse() throws Exception {
+        sendSettings(0, false, new 
SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
         sendLargeGetRequest(3);
 
         // Settings
@@ -70,4 +71,37 @@ public class TestHttp2Timeouts extends H
         Assert.assertEquals("3-RST-[11]\n", output.getTrace());
     }
 
+
+    /*
+     * Timeout with app reading request body directly.
+     */
+    @Test
+    public void testClientPostsNoBody() throws Exception {
+        sendSimplePostRequest(3,  null,  false);
+
+        // Headers
+        parser.readFrame(false);
+        output.clearTrace();
+
+        parser.readFrame(false);
+
+        Assert.assertEquals("3-RST-[11]\n", output.getTrace());
+    }
+
+
+    /*
+     * Timeout with app processing parameters.
+     */
+    @Test
+    public void testClientPostsNoParameters() throws Exception {
+        sendParameterPostRequest(3, null, null, 10, false);
+
+        // Headers
+        parser.readFrame(false);
+        output.clearTrace();
+
+        parser.readFrame(false);
+
+        Assert.assertEquals("3-RST-[11]\n", output.getTrace());
+    }
 }



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

Reply via email to