Author: schultz
Date: Fri Jan 21 17:46:03 2011
New Revision: 1061929

URL: http://svn.apache.org/viewvc?rev=1061929&view=rev
Log:
Fixed bug #49711: HttpServletRequest#getParts() does not work in a Filter
- Added <Connector> attribute allowCasualMultipartParsing (default false)
- Requests that contain multipart/form-data will be parsed in the absence of 
@MultipartConfig when the above attribute is set to "true"


Modified:
    tomcat/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java
    tomcat/trunk/java/org/apache/catalina/connector/Connector.java
    tomcat/trunk/java/org/apache/catalina/connector/Request.java
    tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
    tomcat/trunk/test/org/apache/catalina/connector/TestRequest.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/ajp.xml
    tomcat/trunk/webapps/docs/config/http.xml

Modified: tomcat/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java Fri Jan 
21 17:46:03 2011
@@ -170,6 +170,7 @@ public abstract class AbstractCatalinaTa
         URLConnection conn = null;
         InputStreamReader reader = null;
         try {
+            openRedirector();
 
             // Create a connection for this command
             conn = (new URL(url + command)).openConnection();

Modified: tomcat/trunk/java/org/apache/catalina/connector/Connector.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Connector.java?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/Connector.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/Connector.java Fri Jan 21 
17:46:03 2011
@@ -246,6 +246,13 @@ public class Connector extends Lifecycle
       */
      protected boolean useBodyEncodingForURI = false;
 
+
+    /**
+     * Allow multipart/form-data requests to be parsed even when the
+     * target servlet doesn't specify @MultipartConfig or have a
+     * &lt;multipart-config&gt; element.
+     */
+    protected boolean allowCasualMultipartParsing = false;
      
      protected static HashMap<String,String> replacements =
          new HashMap<String,String>();
@@ -767,6 +774,32 @@ public class Connector extends Lifecycle
 
      }
 
+    /**
+     * Set to <code>true</code> to allow requests mapped to servlets that
+     * do not explicitly declare @MultipartConfig or have
+     * &lt;multipart-config&gt; specified in web.xml to parse
+     * multipart/form-data requests.
+     *
+     * @param allowCasualMultipartParsing <code>true</code> to allow such
+     *        casual parsing, <code>false</code> otherwise.
+     */
+    public void setAllowCasualMultipartParsing(boolean 
allowCasualMultipartParsing)
+    {
+        this.allowCasualMultipartParsing = allowCasualMultipartParsing;
+    }
+
+    /**
+     * Returns <code>true</code> if requests mapped to servlets without
+     * "multipart config" to parse multipart/form-data requests anyway.
+     *
+     * @return <code>true</code> if requests mapped to servlets without
+     *    "multipart config" to parse multipart/form-data requests,
+     *    <code>false</code> otherwise.
+     */
+    protected boolean getAllowCasualMultipartParsing()
+    {
+        return this.allowCasualMultipartParsing;
+    }
 
     /**
      * Indicates whether the generation of an X-Powered-By response header for

Modified: tomcat/trunk/java/org/apache/catalina/connector/Request.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Request.java?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/Request.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/Request.java Fri Jan 21 
17:46:03 2011
@@ -2537,7 +2537,7 @@ public class Request
         
         return parts;
     }
-    
+
     private void parseParts() {
 
         // Return immediately if the parts have already been parsed
@@ -2545,13 +2545,22 @@ public class Request
             return;
 
         MultipartConfigElement mce = getWrapper().getMultipartConfigElement();
+
         if (mce == null) {
-            parts = Collections.emptyList();
-            return;
+            Connector connector = getConnector();
+            if(connector.getAllowCasualMultipartParsing()) {
+                mce = new MultipartConfigElement(null,
+                                                 connector.getMaxPostSize(),
+                                                 connector.getMaxPostSize(),
+                                                 connector.getMaxPostSize());
+            } else {
+                parts = Collections.emptyList();
+                return;
+            }
         }
         
         Parameters parameters = coyoteRequest.getParameters();
-        
+
         File location;
         String locationStr = mce.getLocation();
         if (locationStr == null || locationStr.length() == 0) {
@@ -2582,7 +2591,7 @@ public class Request
         upload.setFileItemFactory(factory);
         upload.setFileSizeMax(mce.getMaxFileSize());
         upload.setSizeMax(mce.getMaxRequestSize());
-        
+
         parts = new ArrayList<Part>();
         try {
             List<FileItem> items = upload.parseRequest(this);
@@ -2604,11 +2613,12 @@ public class Request
                                             Parameters.DEFAULT_ENCODING)});
                         } catch (UnsupportedEncodingException e) {
                             // Should not be possible
+                            e.printStackTrace();
                         }
                     }
                 }
             }
-            
+
         } catch (InvalidContentTypeException e) {
             partsParseException = new ServletException(e);
         } catch (FileUploadBase.SizeException e) {

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Fri Jan 21 
17:46:03 2011
@@ -242,6 +242,9 @@ public class AprEndpoint extends Abstrac
     public String getSSLCipherSuite() { return SSLCipherSuite; }
     public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite 
= SSLCipherSuite; }
 
+    protected boolean SSLFIPSMode = false;
+    public boolean getSSLFIPSMode() { return SSLFIPSMode; }
+    public void setSSLFIPSMode(boolean SSLFIPSMode) { this.SSLFIPSMode = 
SSLFIPSMode; }
 
     /**
      * SSL certificate file.

Modified: tomcat/trunk/test/org/apache/catalina/connector/TestRequest.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/connector/TestRequest.java?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/connector/TestRequest.java (original)
+++ tomcat/trunk/test/org/apache/catalina/connector/TestRequest.java Fri Jan 21 
17:46:03 2011
@@ -25,12 +25,15 @@ import java.net.URL;
 import java.util.Enumeration;
 import java.util.TreeMap;
 
+import javax.servlet.MultipartConfigElement;
 import javax.servlet.ServletException;
+import javax.servlet.annotation.MultipartConfig;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
 import org.apache.catalina.authenticator.BasicAuthenticator;
 import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.startup.SimpleHttpClient;
@@ -524,6 +527,167 @@ public class TestRequest extends TomcatB
         }
     }
 
+    /**
+     * Test case for bug 49711: HttpServletRequest.getParts does not work
+     * in a filter.
+     */
+    public void testBug49711() {
+        Bug49711Client client = new Bug49711Client();
+        client.setPort(getPort());
+
+        // Make sure non-multipart works properly
+        client.doRequest("/regular", false, false);
+
+        assertEquals("Incorrect response for GET request",
+                     "parts=0",
+                     client.getResponseBody());
+
+        client.reset();
+
+        // Make sure regular multipart works properly
+        client.doRequest("/multipart", false, true); // send multipart request
+
+        assertEquals("Regular multipart doesn't work",
+                     "parts=1",
+                     client.getResponseBody());
+
+        client.reset();
+
+        // Make casual multipart request to "regular" servlet w/o config
+        // We expect that no parts will be available
+        client.doRequest("/regular", false, true); // send multipart request
+
+        assertEquals("Incorrect response for non-configured casual multipart 
request",
+                     "parts=0", // multipart request should be ignored
+                     client.getResponseBody());
+
+        client.reset();
+
+        // Make casual multipart request to "regular" servlet w/config
+        // We expect that the server /will/ parse the parts, even though
+        // there is no @MultipartConfig
+        client.doRequest("/regular", true, true); // send multipart request
+
+        assertEquals("Incorrect response for configured casual multipart 
request",
+                     "parts=1",
+                     client.getResponseBody());
+
+        client.reset();
+    }
+
+    private static class Bug49711Servlet extends HttpServlet {
+        @Override
+        protected void service(HttpServletRequest req, HttpServletResponse 
resp)
+            throws ServletException, IOException {
+            // Just echo the parameters and values back as plain text
+            resp.setContentType("text/plain");
+            resp.setCharacterEncoding("UTF-8");
+
+            PrintWriter out = resp.getWriter();
+            
+            out.println("parts=" + (null == req.getParts()
+                                    ? "null"
+                                    : req.getParts().size()));
+        }
+    }
+
+    @MultipartConfig
+    private static class Bug49711Servlet_multipart extends Bug49711Servlet {
+    }
+
+    /**
+     * Bug 49711 test client: test for casual getParts calls.
+     */
+    private class Bug49711Client extends SimpleHttpClient {
+
+        private boolean init;
+        
+        private synchronized void init() throws Exception {
+            if (init) return;
+            
+            Tomcat tomcat = getTomcatInstance();
+            Context root = tomcat.addContext("", TEMP_DIR);
+            Tomcat.addServlet(root, "regular", new Bug49711Servlet());
+            Wrapper w = Tomcat.addServlet(root, "multipart", new 
Bug49711Servlet_multipart());
+
+            // Tomcat.addServlet does not respect annotations, so we have
+            // to set our own MultipartConfigElement.
+            w.setMultipartConfigElement(new MultipartConfigElement(""));
+
+            root.addServletMapping("/regular", "regular");
+            root.addServletMapping("/multipart", "multipart");
+            tomcat.start();
+            
+            init = true;
+        }
+        
+        private Exception doRequest(String uri,
+                                    boolean allowCasualMultipart,
+                                    boolean makeMultipartRequest) {
+            Tomcat tomcat = getTomcatInstance();
+
+            
tomcat.getConnector().setAllowCasualMultipartParsing(allowCasualMultipart);
+
+            try {
+                init();
+
+                // Open connection
+                connect();
+
+                // Send specified request body using method
+                String[] request;
+
+                if(makeMultipartRequest) {
+                    String boundary = "--simpleboundary";
+
+                    String content = "--" + boundary + CRLF
+                        + "Content-Disposition: form-data; name=\"name\"" + 
CRLF + CRLF
+                        + "value" + CRLF
+                        + "--" + boundary + "--" + CRLF
+                        ;
+
+                    // Re-encode the content so that bytes = characters
+                    if(null != content)
+                        content = new String(content.getBytes("UTF-8"), 
"ASCII");
+
+                    request = new String[] {
+                        "POST http://localhost:"; + getPort() + uri + " 
HTTP/1.1" + CRLF
+                        + "Host: localhost" + CRLF
+                        + "Connection: close" + CRLF
+                        + "Content-Type: multipart/form-data; boundary=" + 
boundary + CRLF
+                        + "Content-Length: " + content.length() + CRLF
+                        + CRLF
+                        + content
+                        + CRLF
+                    };
+                }
+                else
+                {
+                    request = new String[] {
+                        "GET http://localhost:"; + getPort() + uri + " 
HTTP/1.1" + CRLF
+                        + "Host: localhost" + CRLF
+                        + "Connection: close" + CRLF
+                        + CRLF
+                    };
+                }
+
+                setRequest(request);
+                processRequest(); // blocks until response has been read
+                
+                // Close the connection
+                disconnect();
+            } catch (Exception e) {
+                return e;
+            }
+            return null;
+        }
+
+        @Override
+        public boolean isResponseBodyOK() {
+            return false; // Don't care
+        }
+    }
+
     private HttpURLConnection getConnection() throws IOException {
         final String query = "http://localhost:"; + getPort() + "/";
         URL postURL;

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Jan 21 17:46:03 2011
@@ -66,6 +66,12 @@
         Fix NPE in RemoteAddrFilter, RemoteHostFilter. (kkolinko)
       </fix>
       <fix>
+        <bug>49711</bug>: HttpServletRequest#getParts will work in a filter
+        or servlet without an @MultipartConfig annotation or
+        MultipartConfigElement if the new "allowCasualMultipartParsing"
+        connector attribute is set to "true". (schultz)
+      </fix>
+      <fix>
         <bug>50582</bug>: Refactor access logging so chunked encoding is not
         forced for all requests if bytes sent is logged. (markt)
       </fix>

Modified: tomcat/trunk/webapps/docs/config/ajp.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/ajp.xml?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/ajp.xml (original)
+++ tomcat/trunk/webapps/docs/config/ajp.xml Fri Jan 21 17:46:03 2011
@@ -74,6 +74,17 @@
 
   <attributes>
 
+    <attribute name="allowCasualMultipartParsing" required="false">
+      <p>Set to true if Tomcat should automatically parse
+      multipart/form-data request bodies when HttpServletRequest.getPart*
+      or HttpServletRequest.getParameter* is called, even when the
+      target servlet isn't marked with the @MultipartConfig annotation
+      (See Servlet Specification 3.0, Section 3.2 for details).
+      Note that any setting other than <code>true</code> causes Tomcat
+      to behave in a way that is not technically spec-compliant.
+      The default is <code>false</code></p>
+    </attribute>
+
     <attribute name="allowTrace" required="false">
       <p>A boolean value which can be used to enable or disable the TRACE
       HTTP method. If not specified, this attribute is set to false.</p>
@@ -121,7 +132,7 @@
       to POST. This is useful in RESTful applications that want to
       support POST-style semantics for PUT requests.
       Note that any setting other than <code>POST</code> causes Tomcat
-      to behave in a way that does against the intent of the servlet
+      to behave in a way that goes against the intent of the servlet
       specification.
       The HTTP method TRACE is specifically forbidden here in accordance
       with the HTTP specification.

Modified: tomcat/trunk/webapps/docs/config/http.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1061929&r1=1061928&r2=1061929&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/trunk/webapps/docs/config/http.xml Fri Jan 21 17:46:03 2011
@@ -74,6 +74,17 @@
 
   <attributes>
  
+    <attribute name="allowCasualMultipartParsing" required="false">
+      <p>Set to true if Tomcat should automatically parse
+      multipart/form-data request bodies when HttpServletRequest.getPart*
+      or HttpServletRequest.getParameter* is called, even when the
+      target servlet isn't marked with the @MultipartConfig annotation
+      (See Servlet Specification 3.0, Section 3.2 for details).
+      Note that any setting other than <code>true</code> causes Tomcat
+      to behave in a way that is not technically spec-compliant.
+      The default is <code>false</code></p>
+    </attribute>
+
     <attribute name="allowTrace" required="false">
       <p>A boolean value which can be used to enable or disable the TRACE
       HTTP method. If not specified, this attribute is set to false.</p>
@@ -121,7 +132,7 @@
       to POST. This is useful in RESTful applications that want to
       support POST-style semantics for PUT requests.
       Note that any setting other than <code>POST</code> causes Tomcat
-      to behave in a way that does against the intent of the servlet
+      to behave in a way that goes against the intent of the servlet
       specification.
       The HTTP method TRACE is specifically forbidden here in accordance
       with the HTTP specification.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to