According to the Servlet spec 5.5 Convenience Methods, sendRedirect()
should commit the response.
These methods will have the side effect of committing the response, if it has not already been committed, and terminating it. No further output to the client should be made by the servlet after these methods are called. If data is written to the response after these methods are called, the data is ignored.
Currently, it could cause a problem where the server couldn't redirect the user to the URL passed in. Though it might be rare.
We encountered the problem aforementioned. We configured the ForwardedHeaderFilter
with relativeRedirect
set to true
, inside the ForwardedHeaderFilter
, it will use RelativeRedirectResponseWrapper
to wrap the response. I our application, we called sendRedirect()
to redirect to the home page when the user logged in. But we found that the server responds with a 404 status code and the Location
response header.
We found that the authentication filter didn't stop the filter chain when logged in, it continues, and the endpoint for handling the login process doesn't actually exist as we are using the filter to intercept the matched login request and perform the login process. So, in the later process, it couldn't find the handler and set the status code to 404. Thus this problem.
We called sendRedirect()
in successHandler.onAuthenticationSuccess(request, response, authentication)
, and the filter continues after it.
The filter we are using is SpnegoAuthenticationProcessingFilter
from https://github.com/spring-projects/spring-security-kerberos/blob/0c9be90a7480edd48276a3703258258beeef59ff/spring-security-kerberos-web/src/main/java/org/springframework/security/kerberos/web/authentication/SpnegoAuthenticationProcessingFilter.java#L169-L175
Comment From: bclozel
Could we take a step back here?
Could you share a sample application that shows the incorrect behavior? Ideally, a Spring Boot application created on https://start.spring.io with the ForwardedHeaderFilter
and a custom filter (not the authentication one) that reproduces the behavior you're seeing.
Even if we were to flush the buffer where it's suggested, it would not prevent some code to further write to the response, still leading to an incorrect HTTP message (a redirect+location response with invalid HTML content?).
Comment From: yuezk
I will try to provide minimal reproducible code.
Comment From: yuezk
@bclozel Here is the demo repo: https://github.com/yuezk/RelativeRedirectFilter-bug. It uses RelativeRedirectFilter
instead of the ForwardedHeaderFilter
, but the problem is the same.
Comment From: yuezk
Even if we were to flush the buffer where it's suggested, it would not prevent some code to further write to the response, still leading to an incorrect HTTP message (a redirect+location response with invalid HTML content?).
We also need to call resetBuffer()
first to make sure the redirect response won't contain the body. Below are the examples from the popular Java EE implementations
- Tomcat: https://github.com/apache/tomcat/blob/14300d9bf1b6a4d351b6674ef8200718d2c69be7/java/org/apache/catalina/connector/Response.java#L1286
- Undertow: https://github.com/undertow-io/undertow/blob/fde1ca6ffc8c6248a62179e98c59eb09202545c5/servlet/src/main/java/io/undertow/servlet/spec/HttpServletResponseImpl.java#L184
- Jetty: https://github.com/dekellum/jetty/blob/3dc0120d573816de7d6a83e2d6a97035288bdd4a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java#L449
Comment From: bclozel
Thanks @yuezk , this will be shipped in the next maintenance release.