We have an issue where embedded Tomcat is throwing IllegalArgumentException
from the LegacyCookieProcessor
. It throws a 500 HTTP response code.
We need to handle the exception and do something with it (specifically, send it as a 400 instead).
The typical @ExceptionHandler(IllegalArgumentException.class)
doesn't seem to get triggered and Google only seems to give results for dealing with Spring Boot specific exceptions.
Example:
Here is an example to reproduce the behavior. You can execute the example by downloading the initial project including spring-web (https://start.spring.io/) in version 2.1.5.RELEASE. Then add the following two classes to your project.
DemoControllerAdvice.java
package com.example.demo;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class DemoControllerAdvice {
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public Map<String, String> forbiddenHandler() {
Map<String, String> map = new HashMap<>();
map.put("error", "An error occurred.");
map.put("status", HttpStatus.FORBIDDEN.value() + " " + HttpStatus.FORBIDDEN.name());
return map;
}
}
DemoRestController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoRestController {
@GetMapping(value = "/working")
public void working() {
throw new java.lang.IllegalArgumentException();
}
@GetMapping(value = "/not-working")
public String notWorking(@RequestParam String demo) {
return "You need to pass e.g. the character ^ as a request param to test this.";
}
}
Then, start the server and request the following URLs in the browser:
http://localhost:8080/working
AnIllegalArgumentException
is thrown manually in the controller. It is then caught by the ControllerAdvice and will therefore produce a JSON string containing the information defined in theDemoControllerAdvice
http://localhost:8080/not-working?demo=test^123
AnIllegalArgumentException
is thrown by the Tomcat, because the request param cannot be parsed (because of the invalid character^
). The exception however is not caught by the ControllerAdvice. It shows the default HTML page provided by Tomcat. It also provides a different error code than defined in theDemoControllerAdvice
.
In the logs the following message is shown:
o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:467) ~[tomcat-embed-core-9.0.19.jar:9.0.19]