Skip to content

Commit

Permalink
Fall back on */* during content negotiation for errors
Browse files Browse the repository at this point in the history
Prior to this commit, gh-31936 enabled content negotiation for
`@ExceptionHandler` annotated methods in Spring MVC and WebFlux.
In the case of WebFlux, HTTP clients sending invalid media types in the
"Accept" request header would fail with a `NotAcceptableStatusException`
This exception would be handled with an HTTP 406 response status,
instead of processing the original exception.

This commit ensures that invalid media types are ignored during the
exception handling phase and that we fall back to "*/*".

Fixes gh-32878
  • Loading branch information
bclozel committed May 23, 2024
1 parent 94348d9 commit 51f6e78
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;

/**
Expand Down Expand Up @@ -416,7 +417,15 @@ private InvocableHandlerMethod createAttributeMethod(Object bean, Method method)
public InvocableHandlerMethod getExceptionHandlerMethod(Throwable ex, ServerWebExchange exchange, @Nullable HandlerMethod handlerMethod) {

Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null);
List<MediaType> requestedMediaTypes = this.contentTypeResolver.resolveMediaTypes(exchange);
List<MediaType> requestedMediaTypes = List.of(MediaType.ALL);
try {
requestedMediaTypes = this.contentTypeResolver.resolveMediaTypes(exchange);
}
catch (NotAcceptableStatusException exc) {
if (logger.isDebugEnabled()) {
logger.debug("Could not parse Accept header for requested media types", exc);
}
}

// Controller-local first
if (handlerType != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,18 @@ void exceptionHandlerWithMediaType() {
assertThat(producibleMediaTypes).isNotEmpty().contains(MediaType.APPLICATION_JSON);
}

@Test
void exceptionHandlerWithInvalidAcceptHeader() {
Method method = ResolvableMethod.on(ExceptionHandlerController.class).mockCall(ExceptionHandlerController::handle).method();
this.handlerMethod = new HandlerMethod(new ExceptionHandlerController(), method);
MockServerHttpRequest httpRequest = MockServerHttpRequest.get("/test").header("Accept", "v=12").build();
MockServerWebExchange serverWebExchange = MockServerWebExchange.builder(httpRequest).build();
InvocableHandlerMethod invocable = this.methodResolver.getExceptionHandlerMethod(
new ResponseStatusException(HttpStatus.BAD_REQUEST, "reason"), serverWebExchange, this.handlerMethod);

assertThat(invocable).as("No match").isNotNull();
}


private static HandlerMethodArgumentResolver next(
List<? extends HandlerMethodArgumentResolver> resolvers, AtomicInteger index) {
Expand Down

0 comments on commit 51f6e78

Please sign in to comment.