This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit e34fe96ef8ee782b0e56b64358e8dc57cbe336a6 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 9973996014..4fefd870b4 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -2382,13 +2382,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 da5354ed31..2024fd91c9 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -223,6 +223,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 662c0a27fd..8a1af5750b 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 8d84b06dd9..318d2e23db 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 079ad57f51..df9ae57d67 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