-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Description
During request mapping, when the Accept header contains a large number of media types (e.g., 50+), Spring MVC throws HttpMediaTypeException while parsing the header inside content negotiation.
Spring Boot version
3.5.9
Spring Framework version
6.2.15 (managed by Boot 3.5.9)
However, this exception is swallowed inside ProducesRequestCondition#getMatchingCondition() and null is returned instead of propagating the exception.
Because of this:
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class) is never invoked
@ControllerAdvice cannot catch the error
request mapping fails silently
This makes it impossible to handle malformed or oversized Accept headers using standard MVC exception handling.
Observed behaviour
When calling an endpoint with many Accept values:
Accept: application/type1,application/type2, ... (60+)
Internally:
MediaType.parseMediaTypes()
→ throws HttpMediaTypeException
ProducesRequestCondition#getMatchingCondition()
catch (HttpMediaTypeException)
→ returns null
Result:
handler mapping fails
controller not executed
exception never surfaces
Expected behaviour
One of the following:
Propagate HttpMediaTypeException to the MVC exception chain so @ExceptionHandler can handle it
Return 406/400 directly from DispatcherServlet
Currently, there is no way to handle large/malformed Accept headers inside MVC.
Reproduction
Request
curl -X GET http://localhost:8080/test \
$(for i in $(seq 1 60); do printf ' -H "Accept: application/type%d"' "$i"; done)
Result
handler not invoked
exception handler not invoked
Root cause (code reference)
Inside Spring Framework:
ProducesRequestCondition#getMatchingCondition
try {
acceptedMediaTypes = this.getAcceptedMediaTypes(request);
}
catch (HttpMediaTypeException ex) {
return null; **//The exception is swallowed here**
}
This swallowing prevents the exception from propagating to controller-level handlers.
Workaround
Add a OncePerRequestFilter to validate the Accept header before it reaches MVC:
public class AcceptHeaderLimitFilter extends OncePerRequestFilter {
private static final int MAX_ACCEPT_VALUES = 50;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String accept = request.getHeader("Accept");
if (accept != null) {
int count = 1;
for (int i = 0; i < accept.length(); i++) {
if (accept.charAt(i) == ',') count++;
}
if (count > MAX_ACCEPT_VALUES) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType("application/json");
response.getWriter().write(
"{\"error\":\"Bad Request\",\"error_description\":\"Too many Accept-header mime-types\"}"
);
return;
}
}
chain.doFilter(request, response);
}
}
Note: This workaround works but requires infrastructure-level filtering; ideally, MVC should allow handling this exception at the controller level.
Additional Notes
Behaviour became more visible after upgrading to Spring Boot 3.5.x (Spring Framework 6.2)
Is swallowing HttpMediaTypeException inside ProducesRequestCondition#getMatchingCondition() the intended design?
If yes, is there a recommended way to propagate it to @ExceptionHandler or customized the response without using a pre-filter?