Skip to content

Commit c040cd7

Browse files
committed
Parsed RequestPath is recalculated on Forward
Closes gh-26318
1 parent dcc8dcd commit c040cd7

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

spring-web/src/main/java/org/springframework/web/filter/ServletRequestPathFilter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import javax.servlet.ServletResponse;
2525
import javax.servlet.http.HttpServletRequest;
2626

27+
import org.springframework.http.server.RequestPath;
2728
import org.springframework.web.util.ServletRequestPathUtils;
2829

2930
/**
@@ -48,12 +49,13 @@ public class ServletRequestPathFilter implements Filter {
4849
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
4950
throws IOException, ServletException {
5051

52+
RequestPath previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
5153
ServletRequestPathUtils.parseAndCache((HttpServletRequest) request);
5254
try {
5355
chain.doFilter(request, response);
5456
}
5557
finally {
56-
ServletRequestPathUtils.clearParsedRequestPath(request);
58+
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
5759
}
5860
}
5961

spring-web/src/main/java/org/springframework/web/util/ServletRequestPathUtils.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.http.server.PathContainer;
2222
import org.springframework.http.server.RequestPath;
23+
import org.springframework.lang.Nullable;
2324
import org.springframework.util.Assert;
2425

2526
/**
@@ -71,6 +72,22 @@ public static RequestPath getParsedRequestPath(ServletRequest request) {
7172
return path;
7273
}
7374

75+
/**
76+
* Set the cached, parsed {@code RequestPath} to the given value.
77+
* @param requestPath the value to set to, or if {@code null} the cache
78+
* value is cleared.
79+
* @param request the current request
80+
* @since 5.3.3
81+
*/
82+
public static void setParsedRequestPath(@Nullable RequestPath requestPath, ServletRequest request) {
83+
if (requestPath != null) {
84+
request.setAttribute(PATH_ATTRIBUTE, requestPath);
85+
}
86+
else {
87+
request.removeAttribute(PATH_ATTRIBUTE);
88+
}
89+
}
90+
7491
/**
7592
* Check for a {@link #parseAndCache previously} parsed and cached {@code RequestPath}.
7693
*/

spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -952,9 +952,10 @@ protected void doService(HttpServletRequest request, HttpServletResponse respons
952952
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
953953
}
954954

955-
RequestPath requestPath = null;
956-
if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
957-
requestPath = ServletRequestPathUtils.parseAndCache(request);
955+
RequestPath previousRequestPath = null;
956+
if (this.parseRequestPath) {
957+
previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
958+
ServletRequestPathUtils.parseAndCache(request);
958959
}
959960

960961
try {
@@ -967,9 +968,7 @@ protected void doService(HttpServletRequest request, HttpServletResponse respons
967968
restoreAttributesAfterInclude(request, attributesSnapshot);
968969
}
969970
}
970-
if (requestPath != null) {
971-
ServletRequestPathUtils.clearParsedRequestPath(request);
972-
}
971+
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
973972
}
974973
}
975974

spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
package org.springframework.web.servlet;
1818

1919
import java.io.IOException;
20+
import java.util.Collections;
2021
import java.util.Locale;
22+
import java.util.Map;
2123

24+
import javax.servlet.DispatcherType;
2225
import javax.servlet.Servlet;
2326
import javax.servlet.ServletConfig;
2427
import javax.servlet.ServletContext;
@@ -35,14 +38,18 @@
3538
import org.springframework.beans.testfixture.beans.TestBean;
3639
import org.springframework.context.ApplicationContextInitializer;
3740
import org.springframework.context.ConfigurableApplicationContext;
41+
import org.springframework.context.annotation.Bean;
3842
import org.springframework.core.env.ConfigurableEnvironment;
3943
import org.springframework.http.HttpHeaders;
44+
import org.springframework.http.server.RequestPath;
45+
import org.springframework.web.HttpRequestHandler;
4046
import org.springframework.web.context.ConfigurableWebApplicationContext;
4147
import org.springframework.web.context.ConfigurableWebEnvironment;
4248
import org.springframework.web.context.ContextLoader;
4349
import org.springframework.web.context.ServletConfigAwareBean;
4450
import org.springframework.web.context.ServletContextAwareBean;
4551
import org.springframework.web.context.WebApplicationContext;
52+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
4653
import org.springframework.web.context.support.StandardServletEnvironment;
4754
import org.springframework.web.context.support.StaticWebApplicationContext;
4855
import org.springframework.web.multipart.MaxUploadSizeExceededException;
@@ -56,7 +63,9 @@
5663
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
5764
import org.springframework.web.testfixture.servlet.MockServletConfig;
5865
import org.springframework.web.testfixture.servlet.MockServletContext;
66+
import org.springframework.web.util.ServletRequestPathUtils;
5967
import org.springframework.web.util.WebUtils;
68+
import org.springframework.web.util.pattern.PathPatternParser;
6069

6170
import static org.assertj.core.api.Assertions.assertThat;
6271
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -700,6 +709,27 @@ public void withNoViewAndSamePath() throws Exception {
700709
complexDispatcherServlet.service(request, response));
701710
}
702711

712+
@Test // gh-26318
713+
public void parsedRequestPathIsRestoredOnForward() throws Exception {
714+
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
715+
context.register(PathPatternParserConfig.class);
716+
DispatcherServlet servlet = new DispatcherServlet(context);
717+
servlet.init(servletConfig);
718+
719+
RequestPath previousRequestPath = RequestPath.parse("/", null);
720+
721+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
722+
request.setDispatcherType(DispatcherType.FORWARD);
723+
request.setAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE, previousRequestPath);
724+
725+
MockHttpServletResponse response = new MockHttpServletResponse();
726+
servlet.service(request, response);
727+
728+
assertThat(response.getStatus()).isEqualTo(200);
729+
assertThat(response.getContentAsString()).isEqualTo("test-body");
730+
assertThat(request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE)).isSameAs(previousRequestPath);
731+
}
732+
703733
@Test
704734
public void dispatcherServletRefresh() throws ServletException {
705735
MockServletContext servletContext = new MockServletContext("org/springframework/web/context");
@@ -867,4 +897,22 @@ public void initialize(ConfigurableWebApplicationContext applicationContext) {
867897
}
868898
}
869899

900+
901+
private static class PathPatternParserConfig {
902+
903+
@Bean
904+
public SimpleUrlHandlerMapping handlerMapping() {
905+
Map<String, Object> urlMap = Collections.singletonMap("/test",
906+
(HttpRequestHandler) (request, response) -> {
907+
response.setStatus(200);
908+
response.getWriter().print("test-body");
909+
});
910+
911+
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
912+
mapping.setPatternParser(new PathPatternParser());
913+
mapping.setUrlMap(urlMap);
914+
return mapping;
915+
}
916+
}
917+
870918
}

0 commit comments

Comments
 (0)