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