Browse Source

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
pull/31518/head
Sébastien Deleuze 1 year ago
parent
commit
3b80f2c4cb
  1. 23
      spring-web/src/main/java/org/springframework/web/multipart/MaxUploadSizeExceededException.java
  2. 23
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java
  3. 7
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java
  4. 12
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,17 +16,26 @@ @@ -16,17 +16,26 @@
package org.springframework.web.multipart;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail;
import org.springframework.lang.Nullable;
import org.springframework.web.ErrorResponse;
/**
* MultipartException subclass thrown when an upload exceeds the
* maximum upload size allowed.
*
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 1.0.1
*/
@SuppressWarnings("serial")
public class MaxUploadSizeExceededException extends MultipartException {
public class MaxUploadSizeExceededException extends MultipartException implements ErrorResponse {
private static final ProblemDetail body =
ProblemDetail.forStatusAndDetail(HttpStatus.PAYLOAD_TOO_LARGE, "Maximum upload size exceeded");
private final long maxUploadSize;
@ -60,4 +69,14 @@ public class MaxUploadSizeExceededException extends MultipartException { @@ -60,4 +69,14 @@ public class MaxUploadSizeExceededException extends MultipartException {
return this.maxUploadSize;
}
@Override
public HttpStatusCode getStatusCode() {
return HttpStatus.PAYLOAD_TOO_LARGE;
}
@Override
public ProblemDetail getBody() {
return body;
}
}

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

@ -50,6 +50,7 @@ import org.springframework.web.context.request.ServletWebRequest; @@ -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 @@ -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 @@ -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 @@ -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

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

@ -61,6 +61,7 @@ import org.springframework.web.context.request.WebRequest; @@ -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; @@ -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 { @@ -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();

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

@ -44,6 +44,7 @@ import org.springframework.web.bind.MissingPathVariableException; @@ -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; @@ -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 { @@ -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();

Loading…
Cancel
Save