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:
@@ -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 @@
|
||||
|
||||
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 {
|
||||
return this.maxUploadSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatusCode getStatusCode() {
|
||||
return HttpStatus.PAYLOAD_TOO_LARGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemDetail getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user