This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push: new 2b0ab14fb5 Provide finder grained control of multi-part requests 2b0ab14fb5 is described below commit 2b0ab14fb55d4edc896e5f1817f2ab76f714ae5e Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Jun 3 16:05:53 2025 +0100 Provide finder grained control of multi-part requests This exposes two new configuration attributes on the Connector: - maxPartCount - maxPartHeaderSize --- java/org/apache/catalina/connector/Connector.java | 24 +++++++++++++++++++ java/org/apache/catalina/connector/Request.java | 28 ++++++++++++++++++----- webapps/docs/changelog.xml | 7 ++++++ webapps/docs/config/ajp.xml | 15 ++++++++++++ webapps/docs/config/http.xml | 15 ++++++++++++ webapps/docs/config/http2.xml | 2 ++ 6 files changed, 85 insertions(+), 6 deletions(-) diff --git a/java/org/apache/catalina/connector/Connector.java b/java/org/apache/catalina/connector/Connector.java index f9b223f8c2..9ff15c5e9a 100644 --- a/java/org/apache/catalina/connector/Connector.java +++ b/java/org/apache/catalina/connector/Connector.java @@ -210,6 +210,10 @@ public class Connector extends LifecycleMBeanBase { */ protected int maxParameterCount = 1000; + private int maxPartCount = 10; + + private int maxPartHeaderSize = 512; + /** * Maximum size of a POST which will be automatically parsed by the container. 2 MiB by default. */ @@ -479,6 +483,26 @@ public class Connector extends LifecycleMBeanBase { } + public int getMaxPartCount() { + return maxPartCount; + } + + + public void setMaxPartCount(int maxPartCount) { + this.maxPartCount = maxPartCount; + } + + + public int getMaxPartHeaderSize() { + return maxPartHeaderSize; + } + + + public void setMaxPartHeaderSize(int maxPartHeaderSize) { + this.maxPartHeaderSize = maxPartHeaderSize; + } + + /** * @return the maximum size of a POST which will be automatically parsed by the container. */ diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index ab1397d9a2..9f2fd10a48 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -2490,13 +2490,29 @@ public class Request implements HttpServletRequest { upload.setFileItemFactory(factory); upload.setFileSizeMax(mce.getMaxFileSize()); upload.setSizeMax(mce.getMaxRequestSize()); - if (maxParameterCount > -1) { - // There is a limit. The limit for parts needs to be reduced by - // the number of parameters we have already parsed. - // Must be under the limit else parsing parameters would have - // triggered an exception. - upload.setFileCountMax(maxParameterCount - parameters.size()); + upload.setPartHeaderSizeMax(connector.getMaxPartHeaderSize()); + /* + * There are two independent limits on the number of parts. + * + * 1. The limit based on parameters. This is maxParameterCount less the number of parameters already processed. + * + * 2. The limit based on parts. This is maxPartCount. + * + * The lower of these two limits will be applied to this request. + * + * Note: Either of both limits may be set to -1 (unlimited). + */ + int partLimit = maxParameterCount; + if (partLimit > -1) { + partLimit = partLimit - parameters.size(); + } + int maxPartCount = connector.getMaxPartCount(); + if (maxPartCount > -1) { + if (partLimit < 0 || partLimit > maxPartCount) { + partLimit = maxPartCount; + } } + upload.setFileCountMax(partLimit); parts = new ArrayList<>(); try { diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 4579221830..b57d6bddda 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -150,6 +150,13 @@ <code>BlockingQueue</code> implementation. Pull request provided by Paulo Almeida. (markt) </scode> + <add> + Provide finer grained control of multi-part request processing via two + new attributes on the <code>Connector</code> element. + <code>maxPartCount</code> limits the total number of parts in a + multi-part request and <code>maxPartHeaderSize</code> limits the size of + the headers provided with each part. (markt) + </add> </changelog> </subsection> <subsection name="Jasper"> diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml index 4e7b81aec8..e566bde6c4 100644 --- a/webapps/docs/config/ajp.xml +++ b/webapps/docs/config/ajp.xml @@ -185,6 +185,21 @@ default of 1000 is used.</p> </attribute> + <attribute name="maxPartCount" required="false"> + <p>The maximum total number of parts permitted in a request where the + content type is <code>multipart/form-data</code>. This limit is in + addition to <code>maxParameterCount</code>. Requests that exceed this + limit will be rejected. A value of less than 0 means no limit. If not + specified, a default of 10 is used.</p> + </attribute> + + <attribute name="maxPartHeaderSize" required="false"> + <p>The maximum number of header bytes permitted per part in a request + where the content type is <code>multipart/form-data</code>. Requests that + exceed this limit will be rejected. A value of less than 0 means no limit. + If not specified, a default of 512 is used.</p> + </attribute> + <attribute name="maxPostSize" required="false"> <p>The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing. The limit can be disabled by diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml index 1ff2146d03..743796c095 100644 --- a/webapps/docs/config/http.xml +++ b/webapps/docs/config/http.xml @@ -181,6 +181,21 @@ default of 1000 is used.</p> </attribute> + <attribute name="maxPartCount" required="false"> + <p>The maximum total number of parts permitted in a request where the + content type is <code>multipart/form-data</code>. This limit is in + addition to <code>maxParameterCount</code>. Requests that exceed this + limit will be rejected. A value of less than 0 means no limit. If not + specified, a default of 10 is used.</p> + </attribute> + + <attribute name="maxPartHeaderSize" required="false"> + <p>The maximum number of header bytes permitted per part in a request + where the content type is <code>multipart/form-data</code>. Requests that + exceed this limit will be rejected. A value of less than 0 means no limit. + If not specified, a default of 512 is used.</p> + </attribute> + <attribute name="maxPostSize" required="false"> <p>The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing. The limit can be disabled by diff --git a/webapps/docs/config/http2.xml b/webapps/docs/config/http2.xml index 49592bc9e1..3f1760e6cc 100644 --- a/webapps/docs/config/http2.xml +++ b/webapps/docs/config/http2.xml @@ -240,6 +240,8 @@ <li>maxHttpHeaderSize</li> <li>maxHttpRequestHeaderSize</li> <li>maxParameterCount</li> + <li>maxPartCount</li> + <li>maxPartHeaderSize</li> <li>maxPostSize</li> <li>maxSavePostSize</li> <li>maxTrailerSize</li> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org