Info
Spring Boot version: 3.3.3/3.3.4
Description
spring-boot-starter-jetty does not handle the TRACE HTTP method as spring-boot-starter-tomcat does.
As per my tests, I see the following scenarios:
- Tomcat blocks the TRACE method no matter the port
- Jetty allows the TRACE method by default on either the server port or management port
- Jetty with a custom DispatcherServlet returns 405 on the server port and 200 on the management port
Custom DispatcherServlet:
public class CustomDispatcherServlet extends DispatcherServlet {
@Override
protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("TRACE IS NOT ALLOWED");
response.sendError(SC_METHOD_NOT_ALLOWED);
}
}
I built this simple project to replicate the issue.
Comment From: wilkinsona
The behaviour that you have described is to be expected as Tomcat and Jetty have different default behavior in this area. The differences between the different embedded servers are one reason why we offer support for Jetty and Undertow in addition to Tomcat as one container may be a better fit for an application's needs than another.
When you configure a custom dispatcher servlet, the management server on a separate port continues to respond with 200 as it's using a separate dispatcher servlet.
You may find this Q&A on Stack Overflow helpful in learning how to customize Jetty's configuration. You can apply that sort of customization in a Spring Boot app using a JettyServerCustomizer bean:
@Bean
JettyServerCustomizer jettyServerCustomizer() {
return (server) -> {
ServletContextHandler servletContextHandler = findServletContextHandler(server);
// Customize handler to disable TRACE support
};
}
private static ServletContextHandler findServletContextHandler(Container container) {
for (Handler handler : container.getHandlers()) {
if (handler instanceof ServletContextHandler servletContextHandler) {
return servletContextHandler;
}
if (handler instanceof Container containerHandler) {
ServletContextHandler servletContextHandler = findServletContextHandler(containerHandler);
if (servletContextHandler != null) {
return servletContextHandler;
}
}
}
return null;
}
Alternatively, you may want to use Tomcat if its defaults are a better match for your needs and expectations.
If you have any further questions, please follow up on Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.
Comment From: bu3
Thanks for the quick reply @wilkinsona.
I thought it was a bug since my application running on Spring Boot 2 and Jetty 9 was working fine.
When I moved the code to SB3 the same configuration won't work and the management server seems to be ignoring any kind of customization and always returning 200.
I can extend my test project if you want with the code snipped you shared above
Comment From: wilkinsona
Jetty's behavior may well have changed between 9 and 12. Thanks for the offer, but there's no need to extend your test project from my perspective as I don't think this is a Spring Boot problem.
Comment From: bu3
Even if I show you it has the same issue using JettyServerCustomizer and Jetty 12? I managed to create a Jetty constraint for TRACE using the customizer but it gets applied to the main server only. Mgmt server keeps responding with 200. I have no clue what Spring boot does under the hood to start two different servers. Could not that be a bug?
Comment From: wilkinsona
When using a separate port there's a separate Jetty instance running in the management context. You can use @ManagementContextConfiguration to declare beans that should be applied to that context.
Comment From: bu3
Exactly. That's what I thought as well. I used that Annotation here and the same logic in the main class.
Still not working but this time instead of returning 405 on the server port it returns 403. While MgmtServer keeps returning a 200
Server
Expected: <405 METHOD_NOT_ALLOWED>
but: was <403 FORBIDDEN>
Expected :<405 METHOD_NOT_ALLOWED>
Actual :<403 FORBIDDEN>
MgmtServer
Expected: <405 METHOD_NOT_ALLOWED>
but: was <200 OK>
Expected :<405 METHOD_NOT_ALLOWED>
Actual :<200 OK>
Comment From: wilkinsona
You're not using @ManagementContextConfiguration correctly. As described in the javadoc, it needs to be registered in a /META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports file. It also shouldn't be in a package that's covered by component scanning.
I'm afraid the issue tracker isn't the right place for this sort of support. If you have any further questions, please follow up on Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.
Comment From: bu3
Done. Just posted in there. Sorry if I bothered you
Comment From: bu3
In case anybody arrives here, this is my Stack Overflow post
Comment From: bu3
I managed to make this work using WebServerFactoryCustomizer<JettyServletWebServerFactory> instead of JettyServerCustomizer
@Bean
WebServerFactoryCustomizer<JettyServletWebServerFactory> disableTrace() {
return (factory) -> {
factory.addServerCustomizers((server) -> {
ServletContextHandler servletContextHandler = findServletContextHandler(server);
disableTraceMethodForHandler(servletContextHandler);
});
};
}
More details in this StackOverflow post