Affects: Spring Framework 5.2.7
Context
I have a WebFlux application with many controllers, and the particular need of having to pre-process and inject additional data in some cases.
In order to do so, a WebFilter is used, and the ServerHttpRequest as well as its containing ServerWebExchange is mutated through their .mutate() methods.
Additionally, I use Spring Boot 2.3.1+, which comes with a new spring.webflux.base-path configuration property that seemingly sets up a ContextPathCompositeHandler to emulate how the context path is handled in, e.g., servlets.
Issue
The problem here is that setting a WebFilter that mutates the incoming ServerHttpRequest seems to break WebFlux applications that are using the new Spring Boot spring.webflux.base-path. Requests end up never being routed to their respective controllers, and the affected URLs will always return a 404 Not Found HTTP response.
While this is a Spring Boot configuration property, I believe that it is caused by an underlying Spring Web bug:
- getRequest().getPath().pathWithinApplication() from ServerWebExchange seems to be used for routing by Spring WebFlux, as evidenced by this line in AbstractUrlHandlerMapping.
- This value is set by the aforementioned ContextPathCompositeHandler by mutating the context path of the incoming request.
- When the request is mutated again by the WebFilter, neither the uriPath nor the contextPath is copied into the internally used builder. The URI itself is copied, but the information about which part is the internal application path and which part is the context path is lost.
While I'm not 100% sure that this is a bug (this might be intended?), I think that it is fair to expect no information to be lost or changed when a ServerHttpRequest is mutated - except of course the parts that are explicitly written otherwise.
Resolution
I think that changing the mutate() method mentioned above to create a carbon copy of the initial ServerHttpRequest is the way to go - or at least using its getPath().contextPath() as the default context path in DefaultServerHttpRequestBuilder. It would definitely fix the problem, although I'm not entirely sure about backwards compatibility.
As such, and since I wasn't even sure whether it was a bug or not, I wanted to open a discussion first and didn't try to fix it myself - although I would gladly open a pull request if this is confirmed to be a bug and the proposed resolution seems acceptable.
Example
I quickly built a small, straightforward Spring Boot project that reproduces and demonstrates the issue.
Related issues
I only found one similar issue that might be related to this underlying "bug": - GH-25270