Skip to content

Commit 3b80f2c

Browse files
committed
Refine MaxUploadSizeExceededException handling
This commit refines MaxUploadSizeExceededException handling in order to translate to a "413 Payload Too Large" status code instead of "500 Internal Server Error", with related ProblemDetail body. Closes gh-27170
1 parent 7582bd8 commit 3b80f2c

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

spring-web/src/main/java/org/springframework/web/multipart/MaxUploadSizeExceededException.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,17 +16,26 @@
1616

1717
package org.springframework.web.multipart;
1818

19+
import org.springframework.http.HttpStatus;
20+
import org.springframework.http.HttpStatusCode;
21+
import org.springframework.http.ProblemDetail;
1922
import org.springframework.lang.Nullable;
23+
import org.springframework.web.ErrorResponse;
2024

2125
/**
2226
* MultipartException subclass thrown when an upload exceeds the
2327
* maximum upload size allowed.
2428
*
2529
* @author Juergen Hoeller
30+
* @author Sebastien Deleuze
2631
* @since 1.0.1
2732
*/
2833
@SuppressWarnings("serial")
29-
public class MaxUploadSizeExceededException extends MultipartException {
34+
public class MaxUploadSizeExceededException extends MultipartException implements ErrorResponse {
35+
36+
private static final ProblemDetail body =
37+
ProblemDetail.forStatusAndDetail(HttpStatus.PAYLOAD_TOO_LARGE, "Maximum upload size exceeded");
38+
3039

3140
private final long maxUploadSize;
3241

@@ -60,4 +69,14 @@ public long getMaxUploadSize() {
6069
return this.maxUploadSize;
6170
}
6271

72+
@Override
73+
public HttpStatusCode getStatusCode() {
74+
return HttpStatus.PAYLOAD_TOO_LARGE;
75+
}
76+
77+
@Override
78+
public ProblemDetail getBody() {
79+
return body;
80+
}
81+
6382
}

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.springframework.web.context.request.WebRequest;
5151
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
5252
import org.springframework.web.method.annotation.HandlerMethodValidationException;
53+
import org.springframework.web.multipart.MaxUploadSizeExceededException;
5354
import org.springframework.web.multipart.support.MissingServletRequestPartException;
5455
import org.springframework.web.servlet.NoHandlerFoundException;
5556
import org.springframework.web.servlet.resource.NoResourceFoundException;
@@ -128,6 +129,7 @@ protected MessageSource getMessageSource() {
128129
NoResourceFoundException.class,
129130
AsyncRequestTimeoutException.class,
130131
ErrorResponseException.class,
132+
MaxUploadSizeExceededException.class,
131133
ConversionNotSupportedException.class,
132134
TypeMismatchException.class,
133135
HttpMessageNotReadableException.class,
@@ -176,6 +178,9 @@ else if (ex instanceof AsyncRequestTimeoutException subEx) {
176178
else if (ex instanceof ErrorResponseException subEx) {
177179
return handleErrorResponseException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
178180
}
181+
else if (ex instanceof MaxUploadSizeExceededException subEx) {
182+
return handleMaxUploadSizeExceededException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
183+
}
179184

180185
// Lower level exceptions, and exceptions used symmetrically on client and server
181186

@@ -435,6 +440,24 @@ protected ResponseEntity<Object> handleErrorResponseException(
435440
return handleExceptionInternal(ex, null, headers, status, request);
436441
}
437442

443+
/**
444+
* Customize the handling of any {@link MaxUploadSizeExceededException}.
445+
* <p>This method delegates to {@link #handleExceptionInternal}.
446+
* @param ex the exception to handle
447+
* @param headers the headers to use for the response
448+
* @param status the status code to use for the response
449+
* @param request the current request
450+
* @return a {@code ResponseEntity} for the response to use, possibly
451+
* {@code null} when the response is already committed
452+
* @since 6.1
453+
*/
454+
@Nullable
455+
protected ResponseEntity<Object> handleMaxUploadSizeExceededException(
456+
MaxUploadSizeExceededException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
457+
458+
return handleExceptionInternal(ex, null, headers, status, request);
459+
}
460+
438461
/**
439462
* Customize the handling of {@link ConversionNotSupportedException}.
440463
* <p>By default this method creates a {@link ProblemDetail} with the status

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
6262
import org.springframework.web.context.support.StaticWebApplicationContext;
6363
import org.springframework.web.method.annotation.HandlerMethodValidationException;
64+
import org.springframework.web.multipart.MaxUploadSizeExceededException;
6465
import org.springframework.web.multipart.support.MissingServletRequestPartException;
6566
import org.springframework.web.servlet.DispatcherServlet;
6667
import org.springframework.web.servlet.ModelAndView;
@@ -78,6 +79,7 @@
7879
* Unit tests for {@link ResponseEntityExceptionHandler}.
7980
*
8081
* @author Rossen Stoyanchev
82+
* @author Sebastien Deleuze
8183
*/
8284
public class ResponseEntityExceptionHandlerTests {
8385

@@ -290,6 +292,11 @@ public void asyncRequestTimeoutException() {
290292
testException(new AsyncRequestTimeoutException());
291293
}
292294

295+
@Test
296+
public void maxUploadSizeExceededException() {
297+
testException(new MaxUploadSizeExceededException(1000));
298+
}
299+
293300
@Test
294301
public void controllerAdvice() throws Exception {
295302
StaticWebApplicationContext ctx = new StaticWebApplicationContext();

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.web.bind.MissingServletRequestParameterException;
4545
import org.springframework.web.bind.ServletRequestBindingException;
4646
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
47+
import org.springframework.web.multipart.MaxUploadSizeExceededException;
4748
import org.springframework.web.multipart.support.MissingServletRequestPartException;
4849
import org.springframework.web.servlet.HandlerExceptionResolver;
4950
import org.springframework.web.servlet.ModelAndView;
@@ -58,6 +59,7 @@
5859
* Unit tests for {@link DefaultHandlerExceptionResolver}.
5960
*
6061
* @author Arjen Poutsma
62+
* @author Sebastien Deleuze
6163
*/
6264
public class DefaultHandlerExceptionResolverTests {
6365

@@ -246,6 +248,16 @@ public void handleAsyncRequestTimeoutException() {
246248
assertThat(response.getStatus()).as("Invalid status code").isEqualTo(503);
247249
}
248250

251+
@Test
252+
public void handleMaxUploadSizeExceededException() {
253+
MaxUploadSizeExceededException ex = new MaxUploadSizeExceededException(1000);
254+
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
255+
assertThat(mav).as("No ModelAndView returned").isNotNull();
256+
assertThat(mav.isEmpty()).as("No Empty ModelAndView returned").isTrue();
257+
assertThat(response.getStatus()).as("Invalid status code").isEqualTo(413);
258+
assertThat(response.getErrorMessage()).isEqualTo("Maximum upload size exceeded");
259+
}
260+
249261
@Test
250262
public void customModelAndView() {
251263
ModelAndView expected = new ModelAndView();

0 commit comments

Comments
 (0)