Author: markt Date: Thu Jun 19 09:31:43 2014 New Revision: 1603781 URL: http://svn.apache.org/r1603781 Log: Add a new limit, defaulting to 2MB, for the amount of data Tomcat will swallow for an aborted upload.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1603770,1603775,1603779 Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Thu Jun 19 09:31:43 2014 @@ -683,14 +683,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/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java Thu Jun 19 09:31:43 2014 @@ -163,6 +163,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/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Jun 19 09:31:43 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/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Thu Jun 19 09:31:43 2014 @@ -300,7 +300,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.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Jun 19 09:31:43 2014 @@ -64,7 +64,7 @@ public class Http11NioProcessor extends public Http11NioProcessor(int maxHttpHeaderSize, NioEndpoint endpoint, - int maxTrailerSize, int maxExtensionSize) { + int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) { super(endpoint); @@ -74,7 +74,7 @@ public class Http11NioProcessor extends outputBuffer = new InternalNioOutputBuffer(response, maxHttpHeaderSize); response.setOutputBuffer(outputBuffer); - initializeFilters(maxTrailerSize, maxExtensionSize); + initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize); } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java Thu Jun 19 09:31:43 2014 @@ -259,7 +259,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.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java Thu Jun 19 09:31:43 2014 @@ -50,7 +50,7 @@ public class Http11Processor extends Abs public Http11Processor(int headerBufferSize, JIoEndpoint endpoint, - int maxTrailerSize, int maxExtensionSize) { + int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) { super(endpoint); @@ -60,7 +60,7 @@ public class Http11Processor extends Abs outputBuffer = new InternalOutputBuffer(response, headerBufferSize); response.setOutputBuffer(outputBuffer); - initializeFilters(maxTrailerSize, maxExtensionSize); + initializeFilters(maxTrailerSize, maxExtensionSize, maxSwallowSize); } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Protocol.java Thu Jun 19 09:31:43 2014 @@ -164,7 +164,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.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java Thu Jun 19 09:31:43 2014 @@ -138,6 +138,9 @@ public class ChunkedInputFilter implemen private long extensionSize; + private final int maxSwallowSize; + + /** * Flag that indicates if an error has occurred. */ @@ -146,10 +149,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; } @@ -235,9 +239,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/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java Thu Jun 19 09:31:43 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,8 +80,10 @@ public class IdentityInputFilter impleme protected ByteChunk endChunk = new ByteChunk(); - // ------------------------------------------------------------- Properties + private final int maxSwallowSize; + + // ------------------------------------------------------------- Properties /** * Get content length. @@ -101,6 +107,13 @@ public class IdentityInputFilter impleme } + // ------------------------------------------------------------ Constructor + + public IdentityInputFilter(int maxSwallowSize) { + this.maxSwallowSize = maxSwallowSize; + } + + // ---------------------------------------------------- InputBuffer Methods @@ -163,8 +176,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/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/filters/LocalStrings.properties Thu Jun 19 09:31:43 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/tc7.0.x/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestSwallowAbortedUploads.java Thu Jun 19 09:31:43 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(); } @@ -410,4 +417,78 @@ 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; + Socket conn = null; + + try { + 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; + } + } finally { + if (conn != null) { + conn.close(); + } + } + + if (limit) { + Assert.assertNotNull(writeEx); + } else { + Assert.assertNull(writeEx); + Assert.assertNull(readEx); + Assert.assertNotNull(responseLine); + Assert.assertTrue(responseLine.contains("404")); + } + } } Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Thu Jun 19 09:31:43 2014 @@ -147,6 +147,10 @@ HTTP connector and ensure that access log entries generated by error conditions use the correct request start time. (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/tc7.0.x/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml?rev=1603781&r1=1603780&r2=1603781&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml Thu Jun 19 09:31:43 2014 @@ -431,6 +431,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: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org