Author: markt
Date: Thu Jun 19 09:06:39 2014
New Revision: 1603770
URL: http://svn.apache.org/r1603770
Log:
Add a new limit, defaulting to 2MB, for the amount of data Tomcat will swallow
for an aborted upload.
Modified:
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
tomcat/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties
tomcat/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/http.xml
Modified:
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Thu
Jun 19 09:06:39 2014
@@ -647,14 +647,15 @@ public abstract class AbstractHttp11Proc
/**
* Initialize standard input and output filters.
*/
- protected void initializeFilters(int maxTrailerSize, int maxExtensionSize)
{
+ protected void initializeFilters(int maxTrailerSize, int maxExtensionSize,
+ int maxSwallowSize) {
// Create and add the identity filters.
- getInputBuffer().addFilter(new IdentityInputFilter());
+ getInputBuffer().addFilter(new IdentityInputFilter(maxSwallowSize));
getOutputBuffer().addFilter(new IdentityOutputFilter());
// Create and add the chunked filters.
getInputBuffer().addFilter(
- new ChunkedInputFilter(maxTrailerSize, maxExtensionSize));
+ new ChunkedInputFilter(maxTrailerSize, maxExtensionSize,
maxSwallowSize));
getOutputBuffer().addFilter(new ChunkedOutputFilter());
// Create and add the void filters.
Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java Thu
Jun 19 09:06:39 2014
@@ -155,6 +155,16 @@ public abstract class AbstractHttp11Prot
/**
+ * Maximum amount of request body to swallow.
+ */
+ private int maxSwallowSize = 2 * 1024 * 1024;
+ public int getMaxSwallowSize() { return maxSwallowSize; }
+ public void setMaxSwallowSize(int maxSwallowSize) {
+ this.maxSwallowSize = maxSwallowSize;
+ }
+
+
+ /**
* This field indicates if the protocol is treated as if it is secure. This
* normally means https is being used but can be used to fake https e.g
* behind a reverse proxy.
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Jun
19 09:06:39 2014
@@ -59,7 +59,7 @@ public class Http11AprProcessor extends
public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint,
- int maxTrailerSize, int maxExtensionSize) {
+ int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
@@ -69,7 +69,7 @@ public class Http11AprProcessor extends
outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize);
response.setOutputBuffer(outputBuffer);
- initializeFilters(maxTrailerSize, maxExtensionSize);
+ initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize);
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Thu Jun
19 09:06:39 2014
@@ -319,7 +319,8 @@ public class Http11AprProtocol extends A
protected Http11AprProcessor createProcessor() {
Http11AprProcessor processor = new Http11AprProcessor(
proto.getMaxHttpHeaderSize(), (AprEndpoint)proto.endpoint,
- proto.getMaxTrailerSize(), proto.getMaxExtensionSize());
+ proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
+ proto.getMaxSwallowSize());
processor.setAdapter(proto.getAdapter());
processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java Thu Jun
19 09:06:39 2014
@@ -60,7 +60,7 @@ public class Http11Nio2Processor extends
public Http11Nio2Processor(int maxHttpHeaderSize, Nio2Endpoint endpoint,
- int maxTrailerSize, int maxExtensionSize) {
+ int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
@@ -70,7 +70,7 @@ public class Http11Nio2Processor extends
outputBuffer = new InternalNio2OutputBuffer(response,
maxHttpHeaderSize);
response.setOutputBuffer(outputBuffer);
- initializeFilters(maxTrailerSize, maxExtensionSize);
+ initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize);
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Protocol.java Thu Jun
19 09:06:39 2014
@@ -248,7 +248,8 @@ public class Http11Nio2Protocol extends
public Http11Nio2Processor createProcessor() {
Http11Nio2Processor processor = new Http11Nio2Processor(
proto.getMaxHttpHeaderSize(), (Nio2Endpoint)
proto.endpoint,
- proto.getMaxTrailerSize(), proto.getMaxExtensionSize());
+ proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
+ proto.getMaxSwallowSize());
processor.setAdapter(proto.getAdapter());
processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Jun
19 09:06:39 2014
@@ -63,7 +63,7 @@ public class Http11NioProcessor extends
public Http11NioProcessor(int maxHttpHeaderSize, NioEndpoint endpoint,
- int maxTrailerSize, int maxExtensionSize) {
+ int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
@@ -73,7 +73,7 @@ public class Http11NioProcessor extends
outputBuffer = new InternalNioOutputBuffer(response,
maxHttpHeaderSize);
response.setOutputBuffer(outputBuffer);
- initializeFilters(maxTrailerSize, maxExtensionSize);
+ initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize);
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java Thu Jun
19 09:06:39 2014
@@ -280,7 +280,8 @@ public class Http11NioProtocol extends A
public Http11NioProcessor createProcessor() {
Http11NioProcessor processor = new Http11NioProcessor(
proto.getMaxHttpHeaderSize(), (NioEndpoint)proto.endpoint,
- proto.getMaxTrailerSize(), proto.getMaxExtensionSize());
+ proto.getMaxTrailerSize(), proto.getMaxExtensionSize(),
+ proto.getMaxSwallowSize());
processor.setAdapter(proto.getAdapter());
processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java Thu Jun 19
09:06:39 2014
@@ -49,7 +49,7 @@ public class Http11Processor extends Abs
public Http11Processor(int headerBufferSize, JIoEndpoint endpoint,
- int maxTrailerSize, int maxExtensionSize) {
+ int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
@@ -59,7 +59,7 @@ public class Http11Processor extends Abs
outputBuffer = new InternalOutputBuffer(response, headerBufferSize);
response.setOutputBuffer(outputBuffer);
- initializeFilters(maxTrailerSize, maxExtensionSize);
+ initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize);
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java Thu Jun 19
09:06:39 2014
@@ -186,7 +186,8 @@ public class Http11Protocol extends Abst
protected Http11Processor createProcessor() {
Http11Processor processor = new Http11Processor(
proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint,
- proto.getMaxTrailerSize(),proto.getMaxExtensionSize());
+ proto.getMaxTrailerSize(),proto.getMaxExtensionSize(),
+ proto.getMaxSwallowSize());
processor.setAdapter(proto.getAdapter());
processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
Thu Jun 19 09:06:39 2014
@@ -137,6 +137,9 @@ public class ChunkedInputFilter implemen
private long extensionSize;
+ private final int maxSwallowSize;
+
+
/**
* Flag that indicates if an error has occurred.
*/
@@ -145,10 +148,11 @@ public class ChunkedInputFilter implemen
// ----------------------------------------------------------- Constructors
- public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize) {
+ public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize, int
maxSwallowSize) {
this.trailingHeaders.setLimit(maxTrailerSize);
this.maxExtensionSize = maxExtensionSize;
this.maxTrailerSize = maxTrailerSize;
+ this.maxSwallowSize = maxSwallowSize;
}
@@ -234,9 +238,14 @@ public class ChunkedInputFilter implemen
*/
@Override
public long end() throws IOException {
+ long swallowed = 0;
+ int read = 0;
// Consume extra bytes : parse the stream until the end chunk is found
- while (doRead(readChunk, null) >= 0) {
- // NOOP: Just consume the input
+ while ((read = doRead(readChunk, null)) >= 0) {
+ swallowed += read;
+ if (maxSwallowSize > -1 && swallowed > maxSwallowSize) {
+ throwIOException(sm.getString("inputFilter.maxSwallow"));
+ }
}
// Return the number of extra bytes which were consumed
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
Thu Jun 19 09:06:39 2014
@@ -24,6 +24,7 @@ import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.res.StringManager;
/**
* Identity input filter.
@@ -32,6 +33,9 @@ import org.apache.tomcat.util.buf.ByteCh
*/
public class IdentityInputFilter implements InputFilter {
+ private static final StringManager sm = StringManager.getManager(
+ IdentityInputFilter.class.getPackage().getName());
+
// -------------------------------------------------------------- Constants
@@ -76,6 +80,14 @@ public class IdentityInputFilter impleme
protected final ByteChunk endChunk = new ByteChunk();
+ private final int maxSwallowSize;
+
+
+ public IdentityInputFilter(int maxSwallowSize) {
+ this.maxSwallowSize = maxSwallowSize;
+ }
+
+
// ---------------------------------------------------- InputBuffer Methods
/**
@@ -137,8 +149,11 @@ public class IdentityInputFilter impleme
* End the current request.
*/
@Override
- public long end()
- throws IOException {
+ public long end() throws IOException {
+
+ if (maxSwallowSize > -1 && remaining > maxSwallowSize) {
+ throw new IOException(sm.getString("inputFilter.maxSwallow"));
+ }
// Consume extra bytes.
while (remaining > 0) {
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties
Thu Jun 19 09:06:39 2014
@@ -22,4 +22,6 @@ chunkedInputFilter.invalidCrlfNoCR=Inval
chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data
available to read)
chunkedInputFilter.invalidHeader=Invalid chunk header
chunkedInputFilter.maxExtension=maxExtensionSize exceeded
-chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
\ No newline at end of file
+chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
+
+inputFilter.maxSwallow=maxSwallowSize exceeded
\ No newline at end of file
Modified:
tomcat/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java
Thu Jun 19 09:06:39 2014
@@ -16,8 +16,14 @@
*/
package org.apache.catalina.core;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.io.Writer;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
@@ -32,6 +38,7 @@ import javax.servlet.http.Part;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.Context;
@@ -113,7 +120,7 @@ public class TestSwallowAbortedUploads e
Exception ex = doAbortedUploadTest(client, true, true);
assertNull("Limited upload with swallow enabled generates client
exception",
ex);
- assertTrue("Limited upload with swallow enabled returns error status
code",
+ assertTrue("Limited upload with swallow enabled returns non-500 status
code",
client.isResponse500());
client.reset();
}
@@ -400,4 +407,72 @@ public class TestSwallowAbortedUploads e
}
}
+
+ @Test
+ public void testChunkedPUTLimit() throws Exception {
+ doTestChunkedPUT(true);
+ }
+
+
+ @Test
+ public void testChunkedPUTNoLimit() throws Exception {
+ doTestChunkedPUT(false);
+ }
+
+
+ public void doTestChunkedPUT(boolean limit) throws Exception {
+
+ Tomcat tomcat = getTomcatInstance();
+ tomcat.addContext("", TEMP_DIR);
+ // No need for target to exist.
+
+ if (!limit) {
+ tomcat.getConnector().setAttribute("maxSwallowSize", "-1");
+ }
+
+ tomcat.start();
+
+ Exception writeEx = null;
+ Exception readEx = null;
+ String responseLine = null;
+
+ try (Socket conn = new Socket("localhost", getPort())) {
+ Writer writer = new OutputStreamWriter(
+ conn.getOutputStream(), StandardCharsets.US_ASCII);
+ writer.write("PUT /does-not-exist HTTP/1.1\r\n");
+ writer.write("Host: any\r\n");
+ writer.write("Transfer-encoding: chunked\r\n");
+ writer.write("\r\n");
+
+ // Smarter than the typical client. Attempts to read the response
+ // even if the request is not fully written.
+ try {
+ // Write (or try to write) 16MB
+ for (int i = 0; i < 1024 * 1024; i++) {
+ writer.write("10\r\n");
+ writer.write("0123456789ABCDEF\r\n");
+ }
+ } catch (Exception e) {
+ writeEx = e;
+ }
+
+ try {
+ BufferedReader reader = new BufferedReader(new
InputStreamReader(
+ conn.getInputStream(), StandardCharsets.US_ASCII));
+
+ responseLine = reader.readLine();
+ } catch (IOException e) {
+ readEx = e;
+ }
+ }
+
+ if (limit) {
+ Assert.assertNotNull(writeEx);
+ } else {
+ Assert.assertNull(writeEx);
+ }
+ Assert.assertNull(readEx);
+ Assert.assertNotNull(responseLine);
+ Assert.assertTrue(responseLine.contains("404"));
+ }
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jun 19 09:06:39 2014
@@ -205,6 +205,10 @@
<fix>
Improve configuration of cache sizes in the endpoint. (markt)
</fix>
+ <add>
+ Add a new limit, defaulting to 2MB, for the amount of data Tomcat will
+ swallow for an aborted upload. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
Modified: tomcat/trunk/webapps/docs/config/http.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1603770&r1=1603769&r2=1603770&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/trunk/webapps/docs/config/http.xml Thu Jun 19 09:06:39 2014
@@ -436,6 +436,16 @@
If not specified, this attribute is set to 100.</p>
</attribute>
+ <attribute name="maxSwallowSize" required="false">
+ <p>The maximum number of request body bytes (excluding transfer encoding
+ overhead) that will be swallowed by Tomcat for an aborted upload. An
+ aborted upload is when Tomcat knows that the request body is going to be
+ ignored but the client still sends it. If Tomcat does not swallow the
body
+ the client is unlikely to see the response. If not specified the default
+ of 2097152 (2 megabytes) will be used. A value of less than zero
indicates
+ that no limit should be enforced.</p>
+ </attribute>
+
<attribute name="maxThreads" required="false">
<p>The maximum number of request processing threads to be created
by this <strong>Connector</strong>, which therefore determines the
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]