Tomcat by default disables TRACE request. Each TRACE reqeust retrives response like below:

HTTP/1.1 405
Allow: HEAD, GET, OPTIONS
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 735
Date: Thu, 22 Dec 2022 22:22:22 GMT

<!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</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 405 – Method Not Allowed</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> TRACE method is not allowed</p><p><b>Description</b> The method received in the request-line is known by the origin server but not supported by the target resource.</p><hr class="line" /><h3>Apache Tomcat/10.0.27</h3></body></html>

Spring Boot follows the similar behaviour by responding 405 (Method Not Allowed). However, although response status code is set to 405, Spring Boot still outputs request headers in the body:

HTTP/1.1 405
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT
Content-Type: message/http
Content-Length: 273
Date: Thu, 22 Dec 2022 22:22:22 GMT

TRACE /error HTTP/1.1
host: localhost:8080
user-agent: curl/7.87.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.5

IMO it is wrong behavior. If it's not, then we need an option to disable/forbid TRACE completely.


Below is my thoughts on this issue.

By default, allowTrace attribute of Tomcat connector is set as false. This causes TRACE request forwarded to error page. In vanilla Spring Boot application, there is a BasicErrorController, by which the TRACE request is handled. We know that DispatcherServlet accepts and handles all requests, so if we take a look into implementation details of doTrace (Inherited from FrameworkServlet), we can easily figure it out why request headers are printed.

@Override
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    if (this.dispatchTraceRequest) {
        processRequest(request, response);
        if ("message/http".equals(response.getContentType())) {
            // Proper TRACE response coming from a handler - we're done.
            return;
        }
    }
    super.doTrace(request, response);
}

By default, spring.mvc.dispatch-trace-request is set to false, therefore this.processRequest is bypassed and super.doTrace is called. In this context, HttpServlet.doTrace is called, by which request headers are printed.

What problem there is here is that FrameworkServlet.doTrace enforces corresponding handler to construct response in content type of message/http, but BasicErrorController does not handle TRACE request specifically.

Currently I find two ways to disable TRACE request completely.

One workaround is to disable ErrorMvcAutoConfiguration. When ErrorMvcAutoConfiguration is execluded on startup, Spring Boot will respond like below:

HTTP/1.1 405
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 449
Date: Thu, 22 Dec 2022 22:22:22 GMT

<!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</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 405 – Method Not Allowed</h1></body></html>

The other workaround is to enable spring.mvc.dispatch-trace-request and implements my own ErrorController which handles requests case by case.

However, neither of them is concise and good enough. The former cuts off global error handling at the same time, and the latter is also restricted to construct message/http compatible response, and may expose unexpected TRACE endpoints.

Furthermore to say, I think we need a mechanism to whitelist error handler and avoid it being handled by FrameworkServlet.doTrace, or least add an option to allow us to bypass message/http requirement for TRACE request, giving us maximum freedom to customize TRACE response.

Comment From: jojopad

It seems that this behavior can also be replicated with Spring Boot 3.1.0.

Comment From: mhalbritter

I've looked at this issue, and I think we need either something from the Framework team or maybe even from the Tomcat team.

I tried to implement trace handling in the BasicErrorController, but this needs spring.mvc.dispatch-trace-request set to true. Code is here: https://github.com/mhalbritter/spring-boot/tree/mh/33623-option-to-disable-trace-completely

I'll contact the Framework / Tomcat team and see what they think.

Comment From: wilkinsona

I think this will be resolved by https://github.com/spring-projects/spring-framework/issues/31457 and then ultimately by https://github.com/jakartaee/servlet/pull/545. We should double-check that's the case once the Framework change is in place.

Comment From: mhalbritter

Can confirm, using Spring Framework 6.0.14-SNAPSHOT fixes this issue.

Comment From: donaldjohn

I override the doTrace method to overcome this problem(actually I give the idea, copliot made it):


@Component("dispatcherServlet")
public class CustomDispatcherServlet extends DispatcherServlet {

    @Override
    protected void doTrace(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 自定义处理逻辑
        // 例如,你可以决定不处理TRACE请求,直接返回405状态码
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }
}

Comment From: amanlai

Related Stack Overflow discussion.