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: [email protected]
For additional commands, e-mail: [email protected]