An invalid HTTP header sent to an endpoint results in a tomcat's default HTML error response.
# This is ok
curl http://localhost:8080/person
{"name":"John","age":50}
# This is not
curl -H '(request): test' http://localhost:8080/person
<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1></body></html>
On the server, we get this stack trace
INFO 49412 --- [nio-8080-exec-1] 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: The HTTP header line [(request): test] does not conform to RFC 7230 and has been ignored.
at org.apache.coyote.http11.Http11InputBuffer.skipLine(Http11InputBuffer.java:1020) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.http11.Http11InputBuffer.parseHeader(Http11InputBuffer.java:872) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.http11.Http11InputBuffer.parseHeaders(Http11InputBuffer.java:594) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:283) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Since our API "promises" a JSON response, the clients cannot handle html content in response.
This used to work fine with spring-boot-starter-parent:2.0.9.RELEASE
(where it pulled in org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.39
which did not have this issue)
It seems to have been broken in later versions of spring boot like spring-boot-starter-parent:2.3.1.RELEASE
(which pulls in org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.36
which has this issue)
Ideally we would like to hide/transform any and all html responses coming from tomcat.
See github repo on how to reproduce this issue: https://github.com/iyogi/spring-issue-tomcat-error-response
Comment From: wilkinsona
Thanks for the report and sample application. The way that errors that occur very early during HTTP request processing are reported is the same in Spring Boot 2.3.1 as it was in 2.0.x. What has changed here is that Tomcat is now generating an error where it was not previously. Tomcat 9 more strictly enforces the HTTP specification, rejecting non-compliant header names and values with a 400 response. You can get back to Tomcat 8.5's behaviour where your non-spec-compliant request was still accepted by customising Tomcat's connector so that illegal headers are not rejected:
@Bean
TomcatConnectorCustomizer headerRejectionCustomizer() {
return (connector) ->
((AbstractHttp11Protocol<?>)connector.getProtocolHandler()).setRejectIllegalHeader(false);
}
We can take a look at preventing the ErrorReportValve
from returning its standard response when such an error occurs, but we may be quite limited in what's possible given how early in the request's processing the error occurs.
Comment From: wilkinsona