From e8e24e65d25dc54b951f1a4c9a869d74b6b10f95 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 13 Feb 2026 16:19:46 +0100 Subject: [PATCH] Detect all common size exceptions from Tomcat and Commons FileUpload 2.x Closes gh-36317 --- .../StandardMultipartHttpServletRequest.java | 7 +- ...ndardMultipartHttpServletRequestTests.java | 68 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java index 9e9de67ee57..1e05d139e8b 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java @@ -117,10 +117,11 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe // MaxUploadSizeExceededException ? Throwable cause = ex; do { - String msg = cause.getMessage(); + String msg = cause.toString(); if (msg != null) { msg = msg.toLowerCase(Locale.ROOT); - if ((msg.contains("exceed") && (msg.contains("size") || msg.contains("length"))) || + if (((msg.contains("exceed") || msg.contains("limit")) && + (msg.contains("size") || msg.contains("length") || msg.contains("count"))) || (msg.contains("request") && (msg.contains("big") || msg.contains("large")))) { throw new MaxUploadSizeExceededException(-1, ex); } @@ -266,7 +267,7 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe if (dest.isAbsolute() && !dest.exists()) { // Servlet Part.write is not guaranteed to support absolute file paths: // may translate the given path to a relative location within a temp dir - // (for example, on Jetty whereas Tomcat detects absolute paths). + // (for example, on Jetty whereas Tomcat and Undertow detect absolute paths). // At least we offloaded the file from memory storage; it'll get deleted // from the temp dir eventually in any case. And for our user's purposes, // we can manually copy it to the requested location as a fallback. diff --git a/spring-web/src/test/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequestTests.java b/spring-web/src/test/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequestTests.java index ea7c68914b3..cdd68832b1e 100644 --- a/spring-web/src/test/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequestTests.java +++ b/spring-web/src/test/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequestTests.java @@ -123,6 +123,47 @@ class StandardMultipartHttpServletRequestTests { .isThrownBy(() -> requestWithException(ex)).withCause(ex); } + @Test // gh-32549 + void undertowRequestTooBigException() { + IOException ex = new IOException("Connection terminated as request was larger than 10000"); + + assertThatExceptionOfType(MaxUploadSizeExceededException.class) + .isThrownBy(() -> requestWithException(ex)).withCause(ex); + } + + @Test // gh-36317: Tomcat's Commons FileUpload + void commonsFileSizeLimitExceededException() { + IOException ex = new FileSizeLimitExceededException(); + + assertThatExceptionOfType(MaxUploadSizeExceededException.class) + .isThrownBy(() -> requestWithException(ex)).withCause(ex); + } + + @Test // gh-36317: Tomcat's Commons FileUpload + void commonsFileCountLimitExceededException() { + IOException ex = new FileCountLimitExceededException(); + + assertThatExceptionOfType(MaxUploadSizeExceededException.class) + .isThrownBy(() -> requestWithException(ex)).withCause(ex); + } + + @Test // gh-36317: Commons FileUpload 2.x + void commonsFileUploadByteCountLimitException() { + IOException ex = new FileUploadByteCountLimitException(); + + assertThatExceptionOfType(MaxUploadSizeExceededException.class) + .isThrownBy(() -> requestWithException(ex)).withCause(ex); + } + + @Test // gh-36317: Commons FileUpload 2.x + void commonsFileUploadFileCountLimitException() { + IOException ex = new FileUploadFileCountLimitException(); + + assertThatExceptionOfType(MaxUploadSizeExceededException.class) + .isThrownBy(() -> requestWithException(ex)).withCause(ex); + } + + private static StandardMultipartHttpServletRequest requestWithPart(String name, String disposition, String content) { MockHttpServletRequest request = new MockHttpServletRequest(); MockPart part = new MockPart(name, null, content.getBytes(StandardCharsets.UTF_8)); @@ -141,4 +182,31 @@ class StandardMultipartHttpServletRequestTests { return new StandardMultipartHttpServletRequest(request); } + private static StandardMultipartHttpServletRequest requestWithException(IOException ex) { + MockHttpServletRequest request = new MockHttpServletRequest() { + @Override + public Collection getParts() throws IOException { + throw ex; + } + }; + return new StandardMultipartHttpServletRequest(request); + } + + + @SuppressWarnings("serial") + private static class FileSizeLimitExceededException extends IOException { + } + + @SuppressWarnings("serial") + private static class FileCountLimitExceededException extends IOException { + } + + @SuppressWarnings("serial") + private static class FileUploadByteCountLimitException extends IOException { + } + + @SuppressWarnings("serial") + private static class FileUploadFileCountLimitException extends IOException { + } + }