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
This commit is contained in:
Sébastien Deleuze
2023-10-25 12:06:55 +02:00
parent 7582bd8667
commit 3b80f2c4cb
4 changed files with 63 additions and 2 deletions

View File

@@ -50,6 +50,7 @@ import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
@@ -128,6 +129,7 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
NoResourceFoundException.class,
AsyncRequestTimeoutException.class,
ErrorResponseException.class,
MaxUploadSizeExceededException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
@@ -176,6 +178,9 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
else if (ex instanceof ErrorResponseException subEx) {
return handleErrorResponseException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
}
else if (ex instanceof MaxUploadSizeExceededException subEx) {
return handleMaxUploadSizeExceededException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
}
// Lower level exceptions, and exceptions used symmetrically on client and server
@@ -435,6 +440,24 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
return handleExceptionInternal(ex, null, headers, status, request);
}
/**
* Customize the handling of any {@link MaxUploadSizeExceededException}.
* <p>This method delegates to {@link #handleExceptionInternal}.
* @param ex the exception to handle
* @param headers the headers to use for the response
* @param status the status code to use for the response
* @param request the current request
* @return a {@code ResponseEntity} for the response to use, possibly
* {@code null} when the response is already committed
* @since 6.1
*/
@Nullable
protected ResponseEntity<Object> handleMaxUploadSizeExceededException(
MaxUploadSizeExceededException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
return handleExceptionInternal(ex, null, headers, status, request);
}
/**
* Customize the handling of {@link ConversionNotSupportedException}.
* <p>By default this method creates a {@link ProblemDetail} with the status

View File

@@ -61,6 +61,7 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
@@ -78,6 +79,7 @@ import static org.mockito.BDDMockito.mock;
* Unit tests for {@link ResponseEntityExceptionHandler}.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
public class ResponseEntityExceptionHandlerTests {
@@ -290,6 +292,11 @@ public class ResponseEntityExceptionHandlerTests {
testException(new AsyncRequestTimeoutException());
}
@Test
public void maxUploadSizeExceededException() {
testException(new MaxUploadSizeExceededException(1000));
}
@Test
public void controllerAdvice() throws Exception {
StaticWebApplicationContext ctx = new StaticWebApplicationContext();

View File

@@ -44,6 +44,7 @@ import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
@@ -58,6 +59,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Unit tests for {@link DefaultHandlerExceptionResolver}.
*
* @author Arjen Poutsma
* @author Sebastien Deleuze
*/
public class DefaultHandlerExceptionResolverTests {
@@ -246,6 +248,16 @@ public class DefaultHandlerExceptionResolverTests {
assertThat(response.getStatus()).as("Invalid status code").isEqualTo(503);
}
@Test
public void handleMaxUploadSizeExceededException() {
MaxUploadSizeExceededException ex = new MaxUploadSizeExceededException(1000);
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
assertThat(mav).as("No ModelAndView returned").isNotNull();
assertThat(mav.isEmpty()).as("No Empty ModelAndView returned").isTrue();
assertThat(response.getStatus()).as("Invalid status code").isEqualTo(413);
assertThat(response.getErrorMessage()).isEqualTo("Maximum upload size exceeded");
}
@Test
public void customModelAndView() {
ModelAndView expected = new ModelAndView();