Author: markt
Date: Tue Nov  3 12:33:42 2015
New Revision: 1712277

URL: http://svn.apache.org/viewvc?rev=1712277&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=58031
Make the (first) reason parameter parsing failed available as a request 
attribute and then use it to provide a better status code via the 
FailedRequstFilter (if configured).

Modified:
    tomcat/tc6.0.x/trunk/STATUS.txt
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/Globals.java
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java
    
tomcat/tc6.0.x/trunk/java/org/apache/catalina/filters/FailedRequestFilter.java
    tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Parameters.java
    tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml

Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Tue Nov  3 12:33:42 2015
@@ -28,14 +28,6 @@ None
 PATCHES PROPOSED TO BACKPORT:
   [ New proposals should be added at the end of the list ]
 
-* Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=58031
-  Provide a mechanism to enable a 413 response if maxPostSize is exceeded while
-  processing parameters
-  http://svn.apache.org/r1694433
-  http://svn.apache.org/r1694437
-  +1: markt, remm
-  -1:
-
 * Ensure LogFactoryImpl is excluded from extras/tomcat-juli-adapters jar.
   Reported by Benjamin Gandon on the dev list
   Mail thread: http://tomcat.markmail.org/thread/7iygcau3vja4cbui

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/Globals.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/Globals.java?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/Globals.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/Globals.java Tue Nov  3 
12:33:42 2015
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,9 +30,9 @@ public final class Globals {
 
     /**
      * The servlet context attribute under which we store the alternate
-     * deployment descriptor for this web application 
+     * deployment descriptor for this web application
      */
-    public static final String ALT_DD_ATTR = 
+    public static final String ALT_DD_ATTR =
         "org.apache.catalina.deploy.alt_dd";
 
     /**
@@ -62,13 +62,13 @@ public final class Globals {
     /**
      * Request dispatcher state.
      */
-    public static final String DISPATCHER_TYPE_ATTR = 
+    public static final String DISPATCHER_TYPE_ATTR =
         "org.apache.catalina.core.DISPATCHER_TYPE";
 
     /**
      * Request dispatcher path.
      */
-    public static final String DISPATCHER_REQUEST_PATH_ATTR = 
+    public static final String DISPATCHER_REQUEST_PATH_ATTR =
         "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
 
     /**
@@ -223,8 +223,8 @@ public final class Globals {
      */
     public static final String FORWARD_REQUEST_URI_ATTR =
         "javax.servlet.forward.request_uri";
-    
-    
+
+
     /**
      * The request attribute under which the original context path is stored
      * on an forwarded dispatcher request.
@@ -264,7 +264,7 @@ public final class Globals {
     public static final String SERVLET_NAME_ATTR =
         "javax.servlet.error.servlet_name";
 
-    
+
     /**
      * The name of the cookie used to pass the session identifier back
      * and forth with the client.
@@ -308,7 +308,7 @@ public final class Globals {
     public static final String SUBJECT_ATTR =
         "javax.security.auth.subject";
 
-    
+
     /**
      * The servlet context attribute under which we record the set of
      * welcome files (as an object of type String[]) for this application.
@@ -338,7 +338,14 @@ public final class Globals {
 
 
     /**
-     * The master flag which controls strict servlet specification 
+     * The reason that the parameter parsing failed.
+     */
+    public static final String PARAMETER_PARSE_FAILED_REASON_ATTR =
+            "org.apache.catalina.parameter_parse_failed_reason";
+
+
+    /**
+     * The master flag which controls strict servlet specification
      * compliance.
      */
     public static final boolean STRICT_SERVLET_COMPLIANCE =

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java Tue 
Nov  3 12:33:42 2015
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -53,6 +53,7 @@ import org.apache.tomcat.util.buf.String
 import org.apache.tomcat.util.http.Cookies;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.http.Parameters.FailReason;
 import org.apache.tomcat.util.http.ServerCookie;
 import org.apache.tomcat.util.http.mapper.MappingData;
 
@@ -90,18 +91,18 @@ public class Request
     private final static boolean ALLOW_EMPTY_QUERY_STRING;
 
     private static final Log log = LogFactory.getLog(Request.class);
-    
+
     static {
         // Ensure that classes are loaded for SM
         new StringCache.ByteEntry();
         new StringCache.CharEntry();
-        
+
         ALLOW_EMPTY_QUERY_STRING = Boolean.parseBoolean(System.getProperty(
                 
"org.apache.catalina.connector.Request.ALLOW_EMPTY_QUERY_STRING",
                 Boolean.toString(Globals.STRICT_SERVLET_COMPLIANCE)));
     }
 
-    
+
     // ----------------------------------------------------------- Constructors
     public Request() {
 
@@ -122,7 +123,7 @@ public class Request
 
     /**
      * Set the Coyote request.
-     * 
+     *
      * @param coyoteRequest The Coyote request
      */
     public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) {
@@ -213,19 +214,19 @@ public class Request
      */
     protected String authType = null;
 
-    
+
     /**
      * Associated event.
      */
     protected CometEventImpl event = null;
-    
+
 
     /**
      * Comet state
      */
     protected boolean comet = false;
-    
-    
+
+
     /**
      * The current dispatcher type.
      */
@@ -241,7 +242,7 @@ public class Request
     /**
      * ServletInputStream.
      */
-    protected CoyoteInputStream inputStream = 
+    protected CoyoteInputStream inputStream =
         new CoyoteInputStream(inputBuffer);
 
 
@@ -292,7 +293,7 @@ public class Request
      */
     protected boolean secure = false;
 
-    
+
     /**
      * The Subject associated with the current AccessControllerContext
      */
@@ -370,18 +371,18 @@ public class Request
      */
     protected String remoteHost = null;
 
-    
+
     /**
      * Remote port
      */
     protected int remotePort = -1;
-    
+
     /**
      * Local address
      */
     protected String localAddr = null;
 
-    
+
     /**
      * Local address
      */
@@ -422,7 +423,7 @@ public class Request
             event.clear();
             event = null;
         }
-        
+
         authType = null;
         inputBuffer.recycle();
         usingInputStream = false;
@@ -494,7 +495,7 @@ public class Request
     public void clearEncoders() {
         inputBuffer.clearEncoders();
     }
-    
+
 
     /**
      * Clear cached encoders (to save memory for Comet requests).
@@ -503,7 +504,7 @@ public class Request
         throws IOException {
         return (inputBuffer.realReadBytes(null, 0, 0) > 0);
     }
-    
+
 
     // -------------------------------------------------------- Request Methods
 
@@ -570,7 +571,7 @@ public class Request
 
     /**
      * Set filter chain associated with the request.
-     * 
+     *
      * @param filterChain new filter chain
      */
     public void setFilterChain(FilterChain filterChain) {
@@ -642,7 +643,7 @@ public class Request
     public HttpServletRequest getRequest() {
         if (facade == null) {
             facade = new RequestFacade(this);
-        } 
+        }
         return (facade);
     }
 
@@ -702,7 +703,7 @@ public class Request
 
     /**
      * Set the URI converter.
-     * 
+     *
      * @param URIConverter the new URI connverter
      */
     protected void setURIConverter(B2CConverter URIConverter) {
@@ -743,7 +744,7 @@ public class Request
      *
      * @exception IOException if an input/output error occurs
      */
-    public ServletInputStream createInputStream() 
+    public ServletInputStream createInputStream()
         throws IOException {
         if (inputStream == null) {
             inputStream = new CoyoteInputStream(inputBuffer);
@@ -913,11 +914,11 @@ public class Request
     public Object getAttribute(String name) {
 
         if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
-            return (dispatcherType == null) 
+            return (dispatcherType == null)
                 ? ApplicationFilterFactory.REQUEST_INTEGER
                 : dispatcherType;
         } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
-            return (requestDispatcherPath == null) 
+            return (requestDispatcherPath == null)
                 ? getRequestPathMB().toString()
                 : requestDispatcherPath.toString();
         } else if (name.equals(Globals.PARAMETER_PARSE_FAILED_ATTR)) {
@@ -936,7 +937,7 @@ public class Request
         if(attr != null)
             return attr;
         if( isSSLAttribute(name) ) {
-            coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, 
+            coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
                                  coyoteRequest);
             attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR);
             if( attr != null) {
@@ -1259,14 +1260,14 @@ public class Request
     /**
      * Returns the Internet Protocol (IP) source port of the client
      * or last proxy that sent the request.
-     */    
+     */
     public int getRemotePort(){
         if (remotePort == -1) {
             coyoteRequest.action
                 (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest);
             remotePort = coyoteRequest.getRemotePort();
         }
-        return remotePort;    
+        return remotePort;
     }
 
     /**
@@ -1285,14 +1286,14 @@ public class Request
     /**
      * Returns the Internet Protocol (IP) address of the interface on
      * which the request  was received.
-     */       
+     */
     public String getLocalAddr(){
         if (localAddr == null) {
             coyoteRequest.action
                 (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest);
             localAddr = coyoteRequest.localAddr().toString();
         }
-        return localAddr;    
+        return localAddr;
     }
 
 
@@ -1308,7 +1309,7 @@ public class Request
         }
         return localPort;
     }
-    
+
     /**
      * Return a RequestDispatcher that wraps the resource at the specified
      * path, which may be interpreted as relative to the current request path.
@@ -1414,7 +1415,7 @@ public class Request
         } else {
             return;
         }
-        
+
         // Notify interested application event listeners
         Object listeners[] = context.getApplicationEventListeners();
         if ((listeners == null) || (listeners.length == 0))
@@ -1445,7 +1446,7 @@ public class Request
      * @param value The associated value
      */
     public void setAttribute(String name, Object value) {
-       
+
         // Name cannot be null
         if (name == null)
             throw new IllegalArgumentException
@@ -1504,7 +1505,7 @@ public class Request
         if (name.startsWith("org.apache.tomcat.")) {
             coyoteRequest.setAttribute(name, value);
         }
-        
+
         // Notify interested application event listeners
         Object listeners[] = context.getApplicationEventListeners();
         if ((listeners == null) || (listeners.length == 0))
@@ -1779,7 +1780,7 @@ public class Request
 
     /**
      * Set the decoded request URI.
-     * 
+     *
      * @param uri The decoded request URI
      */
     public void setDecodedRequestURI(String uri) {
@@ -1789,7 +1790,7 @@ public class Request
 
     /**
      * Get the decoded request URI.
-     * 
+     *
      * @return the URL decoded request URI
      */
     public String getDecodedRequestURI() {
@@ -1799,7 +1800,7 @@ public class Request
 
     /**
      * Get the decoded request URI.
-     * 
+     *
      * @return the URL decoded request URI
      */
     public MessageBytes getDecodedRequestURIMB() {
@@ -1831,18 +1832,18 @@ public class Request
 
         if (Globals.IS_SECURITY_ENABLED){
             HttpSession session = getSession(false);
-            if ( (subject != null) && 
+            if ( (subject != null) &&
                  (!subject.getPrincipals().contains(principal)) ){
-                subject.getPrincipals().add(principal);         
+                subject.getPrincipals().add(principal);
             } else if (session != null &&
                         session.getAttribute(Globals.SUBJECT_ATTR) == null) {
                 subject = new Subject();
-                subject.getPrincipals().add(principal);         
+                subject.getPrincipals().add(principal);
             }
             if (session != null){
                 session.setAttribute(Globals.SUBJECT_ATTR, subject);
             }
-        } 
+        }
 
         this.userPrincipal = principal;
     }
@@ -1870,7 +1871,7 @@ public class Request
 
     /**
      * Get the context path.
-     * 
+     *
      * @return the context path
      */
     public MessageBytes getContextPathMB() {
@@ -1995,7 +1996,7 @@ public class Request
 
     /**
      * Get the path info.
-     * 
+     *
      * @return the path info
      */
     public MessageBytes getPathInfoMB() {
@@ -2029,7 +2030,7 @@ public class Request
         if (!ALLOW_EMPTY_QUERY_STRING && "".equals(queryString)) {
             return null;
         }
-        
+
         return queryString;
     }
 
@@ -2051,7 +2052,7 @@ public class Request
 
     /**
      * Get the request path.
-     * 
+     *
      * @return the request path
      */
     public MessageBytes getRequestPathMB() {
@@ -2125,7 +2126,7 @@ public class Request
 
     /**
      * Get the servlet path.
-     * 
+     *
      * @return the servlet path
      */
     public MessageBytes getServletPathMB() {
@@ -2297,7 +2298,7 @@ public class Request
      * are several things that may trigger an ID change. These include moving
      * between nodes in a cluster and session fixation prevention during the
      * authentication process.
-     * 
+     *
      * @param newSessionId   The new session ID to use
      */
     public void changeSessionId(String newSessionId) {
@@ -2306,10 +2307,10 @@ public class Request
         if (requestedSessionId != null && requestedSessionId.length() > 0) {
             requestedSessionId = newSessionId;
         }
-        
+
         if (context != null && !context.getCookies())
             return;
-        
+
         if (response != null) {
             String scName = null;
             if (context != null) {
@@ -2318,7 +2319,7 @@ public class Request
             if (scName == null) {
                 scName = Globals.SESSION_COOKIE_NAME;
             }
-            
+
             Cookie newCookie = new Cookie(scName, newSessionId);
 
             configureSessionCookie(newCookie);
@@ -2332,7 +2333,7 @@ public class Request
         }
     }
 
-    
+
     /**
      * Return the session associated with this Request, creating one
      * if necessary and requested.
@@ -2354,8 +2355,8 @@ public class Request
         }
         return event;
     }
-    
-    
+
+
     /**
      * Return true if the current request is handling Comet traffic.
      */
@@ -2363,7 +2364,7 @@ public class Request
         return comet;
     }
 
-    
+
     /**
      * Set comet state.
      */
@@ -2376,8 +2377,8 @@ public class Request
      */
     public boolean isParametersParsed() {
         return parametersParsed;
-    }    
-    
+    }
+
     /**
      * Return true if bytes are available.
      */
@@ -2388,11 +2389,11 @@ public class Request
     public void cometClose() {
         coyoteRequest.action(ActionCode.ACTION_COMET_CLOSE,getEvent());
     }
-    
+
     public void setCometTimeout(long timeout) {
         coyoteRequest.action(ActionCode.ACTION_COMET_SETTIMEOUT,new 
Long(timeout));
     }
-    
+
     // ------------------------------------------------------ Protected Methods
 
 
@@ -2441,7 +2442,7 @@ public class Request
         // Attempt to reuse session id if one was submitted in a cookie
         // Do not reuse the session id if it is from a URL, to prevent possible
         // phishing attacks
-        if (connector.getEmptySessionPath() 
+        if (connector.getEmptySessionPath()
                 && isRequestedSessionIdFromCookie()) {
             session = manager.createSession(getRequestedSessionId());
         } else {
@@ -2476,9 +2477,9 @@ public class Request
      */
     protected void configureSessionCookie(Cookie cookie) {
         cookie.setMaxAge(-1);
-        
+
         Context ctxt = getContext();
-        
+
         String contextPath = null;
         if (ctxt != null && !getConnector().getEmptySessionPath()) {
             if (ctxt.getSessionCookiePath() != null) {
@@ -2492,7 +2493,7 @@ public class Request
         } else {
             cookie.setPath("/");
         }
-        
+
         if (ctxt != null && ctxt.getSessionCookieDomain() != null) {
             cookie.setDomain(ctxt.getSessionCookieDomain());
         }
@@ -2501,7 +2502,7 @@ public class Request
             cookie.setSecure(true);
         }
     }
-    
+
     protected String unescape(String s) {
         if (s==null) return null;
         if (s.indexOf('\\') == -1) return s;
@@ -2622,6 +2623,7 @@ public class Request
                         context.getLogger().debug(
                                 sm.getString("coyoteRequest.postTooLarge"));
                     }
+                    parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                     return;
                 }
                 byte[] formData = null;
@@ -2634,6 +2636,7 @@ public class Request
                 }
                 try {
                     if (readPostBody(formData, len) != len) {
+                        
parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
                         return;
                     }
                 } catch (IOException e) {
@@ -2642,6 +2645,7 @@ public class Request
                         context.getLogger().debug(
                                 sm.getString("coyoteRequest.parseParameters"), 
e);
                     }
+                    
parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);
                     return;
                 }
                 parameters.processParameters(formData, 0, len);
@@ -2652,6 +2656,7 @@ public class Request
                     formData = readChunkedPostBody();
                 } catch (IllegalStateException ise) {
                     // chunkedPostTooLarge error
+                    parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                     Context context = getContext();
                     if (context != null && 
context.getLogger().isDebugEnabled()) {
                         context.getLogger().debug(
@@ -2661,6 +2666,7 @@ public class Request
                     return;
                 } catch (IOException e) {
                     // Client disconnect
+                    
parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);
                     if (context.getLogger().isDebugEnabled()) {
                         context.getLogger().debug(
                                 sm.getString("coyoteRequest.parseParameters"), 
e);
@@ -2674,7 +2680,7 @@ public class Request
             success = true;
         } finally {
             if (!success) {
-                parameters.setParseFailed(true);
+                parameters.setParseFailedReason(FailReason.UNKNOWN);
             }
         }
 
@@ -2705,9 +2711,9 @@ public class Request
      */
     protected byte[] readChunkedPostBody() throws IOException {
         ByteChunk body = new ByteChunk();
-        
+
         byte[] buffer = new byte[CACHED_POST_LEN];
-        
+
         int len = 0;
         while (len > -1) {
             len = getStream().read(buffer, 0, CACHED_POST_LEN);
@@ -2733,8 +2739,8 @@ public class Request
             return body.getBuffer();
         }
     }
-    
-    
+
+
     /**
      * Parse request locales.
      */
@@ -2866,7 +2872,7 @@ public class Request
 
     }
 
-    
+
     protected static final boolean isAlpha(String value) {
         for (int i = 0; i < value.length(); i++) {
             char c = value.charAt(i);
@@ -2876,5 +2882,5 @@ public class Request
         }
         return true;
     }
-    
+
 }

Modified: 
tomcat/tc6.0.x/trunk/java/org/apache/catalina/filters/FailedRequestFilter.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/filters/FailedRequestFilter.java?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- 
tomcat/tc6.0.x/trunk/java/org/apache/catalina/filters/FailedRequestFilter.java 
(original)
+++ 
tomcat/tc6.0.x/trunk/java/org/apache/catalina/filters/FailedRequestFilter.java 
Tue Nov  3 12:33:42 2015
@@ -30,6 +30,7 @@ import org.apache.catalina.CometFilter;
 import org.apache.catalina.CometFilterChain;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.Parameters.FailReason;
 
 /**
  * Filter that will reject requests if there was a failure during parameter
@@ -55,8 +56,41 @@ public class FailedRequestFilter extends
     public void doFilter(ServletRequest request, ServletResponse response,
             FilterChain chain) throws IOException, ServletException {
         if (!isGoodRequest(request)) {
-            ((HttpServletResponse) response)
-                    .sendError(HttpServletResponse.SC_BAD_REQUEST);
+            FailReason reason = (FailReason) request.getAttribute(
+                    Globals.PARAMETER_PARSE_FAILED_REASON_ATTR);
+
+            int status;
+
+            switch (reason) {
+                case IO_ERROR:
+                    // Not the client's fault
+                    status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+                    break;
+                case POST_TOO_LARGE:
+                    status = HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE;
+                    break;
+                case TOO_MANY_PARAMETERS:
+                    // 413/414 aren't really correct here since the request 
body
+                    // and/or URI could be well below any limits set. Use the
+                    // default.
+                case UNKNOWN: // Assume the client is at fault
+                // Various things that the client can get wrong that don't have
+                // a specific status code so use the default.
+                case INVALID_CONTENT_TYPE:
+                case MULTIPART_CONFIG_INVALID:
+                case NO_NAME:
+                case REQUEST_BODY_INCOMPLETE:
+                case URL_DECODING:
+                case CLIENT_DISCONNECT:
+                    // Client is never going to see this so this is really just
+                    // for the access logs. The default is fine.
+                default:
+                    // 400
+                    status = HttpServletResponse.SC_BAD_REQUEST;
+                    break;
+            }
+
+            ((HttpServletResponse) response).sendError(status);
             return;
         }
         chain.doFilter(request, response);

Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Parameters.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Parameters.java?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Parameters.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Parameters.java Tue 
Nov  3 12:33:42 2015
@@ -34,7 +34,7 @@ import org.apache.tomcat.util.log.UserDa
 import org.apache.tomcat.util.res.StringManager;
 
 /**
- * 
+ *
  * @author Costin Manolache
  */
 public final class Parameters {
@@ -53,7 +53,7 @@ public final class Parameters {
         new HashMap<String,ArrayList<String>>();
 
     private boolean didQueryParameters=false;
-    
+
     MessageBytes queryMB;
 
     UDecoder urlDec;
@@ -61,15 +61,15 @@ public final class Parameters {
 
     String encoding=null;
     String queryStringEncoding=null;
-    
+
     private int limit = -1;
     private int parameterCount = 0;
 
     /**
-     * Is set to <code>true</code> if there were failures during parameter
-     * parsing.
+     * Set to the reason for the failure (the first failure if there is more
+     * than one) if there were failures during parameter parsing.
      */
-    private boolean parseFailed = false;
+    private FailReason parseFailedReason = null;
 
     public Parameters() {
         // NO-OP
@@ -102,11 +102,17 @@ public final class Parameters {
     }
 
     public boolean isParseFailed() {
-        return parseFailed;
+        return parseFailedReason != null;
     }
 
-    public void setParseFailed(boolean parseFailed) {
-        this.parseFailed = parseFailed;
+    public FailReason getParseFailedReason() {
+        return parseFailedReason;
+    }
+
+    public void setParseFailedReason(FailReason failReason) {
+        if (this.parseFailedReason == null) {
+            this.parseFailedReason = failReason;
+        }
     }
 
     public void recycle() {
@@ -115,13 +121,13 @@ public final class Parameters {
         didQueryParameters=false;
         encoding=null;
         decodedQuery.recycle();
-        parseFailed = false;
+        parseFailedReason = null;
     }
 
     // -------------------- Data access --------------------
     // Access to the current name/values, no side effect ( processing ).
     // You must explicitly call handleQueryParameters and the post methods.
-    
+
     public void addParameterValues(String key, String[] newValues) {
         if (key == null) {
             return;
@@ -147,7 +153,7 @@ public final class Parameters {
         }
         return values.toArray(new String[values.size()]);
     }
- 
+
     public Enumeration<String> getParameterNames() {
         handleQueryParameters();
         return Collections.enumeration(paramHashValues.keySet());
@@ -176,7 +182,7 @@ public final class Parameters {
 
         if( queryMB==null || queryMB.isNull() )
             return;
-        
+
         if(log.isDebugEnabled()) {
             log.debug("Decoding query " + decodedQuery + " " +
                     queryStringEncoding);
@@ -216,15 +222,15 @@ public final class Parameters {
     private static final String DEFAULT_ENCODING = "ISO-8859-1";
     private static final Charset DEFAULT_CHARSET =
         Charset.forName(DEFAULT_ENCODING);
-    
-    
+
+
     public void processParameters( byte bytes[], int start, int len ) {
         processParameters(bytes, start, len, getCharset(encoding));
     }
 
     private void processParameters(byte bytes[], int start, int len,
                                   Charset charset) {
-        
+
         if(log.isDebugEnabled()) {
             try {
                 log.debug(sm.getString("parameters.bytes",
@@ -235,7 +241,7 @@ public final class Parameters {
         }
 
         int decodeFailCount = 0;
-            
+
         int pos = start;
         int end = start + len;
 
@@ -243,7 +249,7 @@ public final class Parameters {
             parameterCount ++;
 
             if (limit > -1 && parameterCount > limit) {
-                parseFailed = true;
+                setParseFailedReason(FailReason.TOO_MANY_PARAMETERS);
                 UserDataHelper.Mode logMode = maxParamCountLog.getNextMode();
                 if (logMode != null) {
                     String message = sm.getString("parameters.maxCountFail",
@@ -319,7 +325,7 @@ public final class Parameters {
                     valueEnd = pos;
                 }
             }
-            
+
             if (log.isDebugEnabled() && valueStart == -1) {
                 try {
                     log.debug(sm.getString("parameters.noequal",
@@ -331,7 +337,7 @@ public final class Parameters {
                     // Not possible. All JVMs must support ISO-8859-1
                 }
             }
-            
+
             if (nameEnd <= nameStart ) {
                 if (valueStart == -1) {
                     // &&
@@ -370,11 +376,11 @@ public final class Parameters {
                             log.debug(message);
                     }
                 }
-                parseFailed = true;
+                setParseFailedReason(FailReason.NO_NAME);
                 continue;
                 // invalid chunk - it's better to ignore
             }
-            
+
             tmpName.setBytes(bytes, nameStart, nameEnd - nameStart);
             if (valueStart >= 0) {
                 tmpValue.setBytes(bytes, valueStart, valueEnd - valueStart);
@@ -398,7 +404,7 @@ public final class Parameters {
                     log.error(sm.getString("parameters.copyFail"), ioe);
                 }
             }
-            
+
             try {
                 String name;
                 String value;
@@ -421,7 +427,7 @@ public final class Parameters {
 
                 addParam(name, value);
             } catch (IOException e) {
-                parseFailed = true;
+                setParseFailedReason(FailReason.URL_DECODING);
                 decodeFailCount++;
                 if (decodeFailCount == 1 || log.isDebugEnabled()) {
                     if (log.isDebugEnabled()) {
@@ -480,7 +486,7 @@ public final class Parameters {
     private void urlDecode(ByteChunk bc)
         throws IOException {
         if( urlDec==null ) {
-            urlDec=new UDecoder();   
+            urlDec=new UDecoder();
         }
         urlDec.convert(bc);
     }
@@ -507,7 +513,7 @@ public final class Parameters {
         }
     }
 
-    /** 
+    /**
      * Debug purpose
      */
     public String paramsAsString() {
@@ -523,4 +529,17 @@ public final class Parameters {
         return sb.toString();
     }
 
+
+    public enum FailReason {
+        CLIENT_DISCONNECT,
+        MULTIPART_CONFIG_INVALID,
+        INVALID_CONTENT_TYPE,
+        IO_ERROR,
+        NO_NAME,
+        POST_TOO_LARGE,
+        REQUEST_BODY_INCOMPLETE,
+        TOO_MANY_PARAMETERS,
+        UNKNOWN,
+        URL_DECODING
+    }
 }

Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1712277&r1=1712276&r2=1712277&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Tue Nov  3 12:33:42 2015
@@ -60,6 +60,11 @@
         system property. (kkolinko)
       </fix>
       <fix>
+        <bug>58031</bug>: Make the (first) reason parameter parsing failed
+        available as a request attribute and then use it to provide a better
+        status code via the FailedRequstFilter (if configured). (markt)
+      </fix>
+      <fix>
         <bug>58313</bug>: Fix concurrent access of encoders map when clearing
         encoders during Comet processing. (markt)
       </fix>



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

Reply via email to