You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2014/06/19 11:31:43 UTC

svn commit: r1603781 - in /tomcat/tc7.0.x/trunk: ./ java/org/apache/coyote/http11/ java/org/apache/coyote/http11/filters/ test/org/apache/catalina/core/ webapps/docs/ webapps/docs/config/

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org