-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Spring Module and Version
Spring Web – v7.0.1
Issue Description
When using the RedirectTrailingSlashHandler variant of the UrlHandlerFilter, the path portion of the request URI is stripped of it's trailing slash, and the result is used as the new Location header. The location becomes a relative URL to the original request.
E.g. for a request to https://www.example.com/foo/bar/////:
- the path of the request URI will be
/foo/bar///// - the
Locationheader will be set to/foo/bar - the client will redirect to
https://www.example.com/foo/bar
However for the same request with query parameters and/or a fragment, such as https://www.example.com/foo/bar/////?key=value#fragment:
- the path of the request URI will still be
/foo/bar///// - the
Locationheader will again be set to/foo/bar - the client will redirect to
https://www.example.com/foo/barand the query parameters and fragment will become lost
Expected Behaviour
The redirect should remove the trailing slashes from the path only, and should not remove the query parameters and fragment from the original request, as they are important parts of the original request.
E.g. for https://www.example.com/foo/bar/////?key=value#fragment, the Location header should be either of the following:
/foo/bar?key=value#fragment(relative)https://www.example.com/foo/bar?key=value#fragment(absolute)
Code Reference
This issue affects both the standard and reactive implementations of UrlHandlerFilter, so should be fixed for both classes:
-
Standard:
spring-framework/spring-web/src/main/java/org/springframework/web/filter/UrlHandlerFilter.java
Lines 315 to 323 in 16edf98
@Override public void handleInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException { response.resetBuffer(); response.setStatus(this.httpStatus.value()); response.setHeader(HttpHeaders.LOCATION, trimTrailingSlash(request.getRequestURI())); response.flushBuffer(); } -
Reactive:
Lines 291 to 297 in 16edf98
@Override public Mono<Void> handleInternal(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(this.statusCode); response.getHeaders().set(HttpHeaders.LOCATION, trimTrailingSlash(exchange.getRequest())); return Mono.empty(); } As an aside, I think the reactive variant should return
response.setComplete()instead ofMono.empty()?