Skip to content

Commit 8a9b082

Browse files
committed
Improve MappingMatch determination in mock request
MockHttpServletRequest now checks the requestURI and servletPath to check whether they imply a Servlet path mapping, which is the case when the requestURI is longer than the contextPath + servletPath. This is essential when parsed patterns are in use in which case the request path is parsed taking into account only the requestURI and the contextPath. However, if the MappingMatch indicates a match by Servlet path, then the servletPath is also taken into account. See gh-28607
1 parent 9c2ad4a commit 8a9b082

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -52,10 +52,12 @@
5252
import jakarta.servlet.ServletRequest;
5353
import jakarta.servlet.ServletResponse;
5454
import jakarta.servlet.http.Cookie;
55+
import jakarta.servlet.http.HttpServletMapping;
5556
import jakarta.servlet.http.HttpServletRequest;
5657
import jakarta.servlet.http.HttpServletResponse;
5758
import jakarta.servlet.http.HttpSession;
5859
import jakarta.servlet.http.HttpUpgradeHandler;
60+
import jakarta.servlet.http.MappingMatch;
5961
import jakarta.servlet.http.Part;
6062

6163
import org.springframework.http.HttpHeaders;
@@ -69,6 +71,7 @@
6971
import org.springframework.util.ObjectUtils;
7072
import org.springframework.util.StreamUtils;
7173
import org.springframework.util.StringUtils;
74+
import org.springframework.web.util.UrlPathHelper;
7275

7376
/**
7477
* Mock implementation of the {@link jakarta.servlet.http.HttpServletRequest} interface.
@@ -274,6 +277,9 @@ public class MockHttpServletRequest implements HttpServletRequest {
274277

275278
private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();
276279

280+
@Nullable
281+
private HttpServletMapping httpServletMapping;
282+
277283

278284
// ---------------------------------------------------------------------
279285
// Constructors
@@ -1389,6 +1395,33 @@ public Collection<Part> getParts() throws IOException, ServletException {
13891395
return result;
13901396
}
13911397

1398+
public void setHttpServletMapping(@Nullable HttpServletMapping httpServletMapping) {
1399+
this.httpServletMapping = httpServletMapping;
1400+
}
1401+
1402+
@Override
1403+
public HttpServletMapping getHttpServletMapping() {
1404+
return (this.httpServletMapping == null ?
1405+
new MockHttpServletMapping("", "", "", determineMappingMatch()) :
1406+
this.httpServletMapping);
1407+
}
1408+
1409+
/**
1410+
* Best effort to detect a Servlet path mapping, e.g. {@code "/foo/*"}, by
1411+
* checking whether the length of requestURI > contextPath + servletPath.
1412+
* This helps {@link org.springframework.web.util.ServletRequestPathUtils}
1413+
* to take into account the Servlet path when parsing the requestURI.
1414+
*/
1415+
@Nullable
1416+
private MappingMatch determineMappingMatch() {
1417+
if (StringUtils.hasText(this.requestURI) && StringUtils.hasText(this.servletPath)) {
1418+
String path = UrlPathHelper.defaultInstance.getRequestUri(this);
1419+
String prefix = this.contextPath + this.servletPath;
1420+
return (path.startsWith(prefix) && (path.length() > prefix.length()) ? MappingMatch.PATH : null);
1421+
}
1422+
return null;
1423+
}
1424+
13921425
@Override
13931426
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
13941427
throw new UnsupportedOperationException();

spring-web/src/testFixtures/java/org/springframework/web/testfixture/servlet/MockHttpServletRequest.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -57,6 +57,7 @@
5757
import jakarta.servlet.http.HttpServletResponse;
5858
import jakarta.servlet.http.HttpSession;
5959
import jakarta.servlet.http.HttpUpgradeHandler;
60+
import jakarta.servlet.http.MappingMatch;
6061
import jakarta.servlet.http.Part;
6162

6263
import org.springframework.http.HttpHeaders;
@@ -70,6 +71,7 @@
7071
import org.springframework.util.ObjectUtils;
7172
import org.springframework.util.StreamUtils;
7273
import org.springframework.util.StringUtils;
74+
import org.springframework.web.util.UrlPathHelper;
7375

7476
/**
7577
* Mock implementation of the {@link jakarta.servlet.http.HttpServletRequest} interface.
@@ -275,7 +277,8 @@ public class MockHttpServletRequest implements HttpServletRequest {
275277

276278
private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();
277279

278-
private HttpServletMapping httpServletMapping = new MockHttpServletMapping("", "", "", null);
280+
@Nullable
281+
private HttpServletMapping httpServletMapping;
279282

280283

281284
// ---------------------------------------------------------------------
@@ -1392,13 +1395,31 @@ public Collection<Part> getParts() throws IOException, ServletException {
13921395
return result;
13931396
}
13941397

1395-
public void setHttpServletMapping(HttpServletMapping httpServletMapping) {
1398+
public void setHttpServletMapping(@Nullable HttpServletMapping httpServletMapping) {
13961399
this.httpServletMapping = httpServletMapping;
13971400
}
13981401

13991402
@Override
14001403
public HttpServletMapping getHttpServletMapping() {
1401-
return this.httpServletMapping;
1404+
return (this.httpServletMapping == null ?
1405+
new MockHttpServletMapping("", "", "", determineMappingMatch()) :
1406+
this.httpServletMapping);
1407+
}
1408+
1409+
/**
1410+
* Best effort to detect a Servlet path mapping, e.g. {@code "/foo/*"}, by
1411+
* checking whether the length of requestURI > contextPath + servletPath.
1412+
* This helps {@link org.springframework.web.util.ServletRequestPathUtils}
1413+
* to take into account the Servlet path when parsing the requestURI.
1414+
*/
1415+
@Nullable
1416+
private MappingMatch determineMappingMatch() {
1417+
if (StringUtils.hasText(this.requestURI) && StringUtils.hasText(this.servletPath)) {
1418+
String path = UrlPathHelper.defaultInstance.getRequestUri(this);
1419+
String prefix = this.contextPath + this.servletPath;
1420+
return (path.startsWith(prefix) && (path.length() > prefix.length()) ? MappingMatch.PATH : null);
1421+
}
1422+
return null;
14021423
}
14031424

14041425
@Override

0 commit comments

Comments
 (0)