16
16
17
17
package org .springframework .security .web .servlet .util .matcher ;
18
18
19
- import java .util .Collection ;
20
- import java .util .LinkedHashMap ;
21
- import java .util .Map ;
22
19
import java .util .Objects ;
23
- import java .util .concurrent .atomic .AtomicReference ;
24
20
25
- import jakarta .servlet .ServletContext ;
26
- import jakarta .servlet .ServletRegistration ;
27
21
import jakarta .servlet .http .HttpServletRequest ;
28
22
29
23
import org .springframework .http .HttpMethod ;
40
34
41
35
/**
42
36
* A {@link RequestMatcher} that uses {@link PathPattern}s to match against each
43
- * {@link HttpServletRequest}. The provided path should be relative to the servlet (that
44
- * is, it should exclude any context or servlet path).
37
+ * {@link HttpServletRequest}. The provided path should be relative to the context path
38
+ * (that is, it should exclude any context path).
45
39
*
46
40
* <p>
47
- * To also match the servlet, please see {@link PathPatternRequestMatcher#servletPath}
41
+ * You can provide the servlet path in {@link PathPatternRequestMatcher#servletPath} and
42
+ * reuse for multiple matchers.
48
43
*
49
44
* <p>
50
45
* Note that the {@link org.springframework.web.servlet.HandlerMapping} that contains the
@@ -113,7 +108,7 @@ public MatchResult matcher(HttpServletRequest request) {
113
108
if (!this .method .matches (request )) {
114
109
return MatchResult .notMatch ();
115
110
}
116
- PathContainer path = getRequestPath (request ). pathWithinApplication ( );
111
+ PathContainer path = getPathContainer (request );
117
112
PathPattern .PathMatchInfo info = this .pattern .matchAndExtract (path );
118
113
return (info != null ) ? MatchResult .match (info .getUriVariables ()) : MatchResult .notMatch ();
119
114
}
@@ -122,11 +117,7 @@ void setMethod(RequestMatcher method) {
122
117
this .method = method ;
123
118
}
124
119
125
- void setServletPath (RequestMatcher servletPath ) {
126
- this .servletPath = servletPath ;
127
- }
128
-
129
- private RequestPath getRequestPath (HttpServletRequest request ) {
120
+ private PathContainer getPathContainer (HttpServletRequest request ) {
130
121
RequestPath path ;
131
122
if (ServletRequestPathUtils .hasParsedRequestPath (request )) {
132
123
path = ServletRequestPathUtils .getParsedRequestPath (request );
@@ -135,7 +126,8 @@ private RequestPath getRequestPath(HttpServletRequest request) {
135
126
path = ServletRequestPathUtils .parseAndCache (request );
136
127
ServletRequestPathUtils .clearParsedRequestPath (request );
137
128
}
138
- return path ;
129
+ PathContainer contextPath = path .contextPath ();
130
+ return path .subPath (contextPath .elements ().size ());
139
131
}
140
132
141
133
/**
@@ -166,9 +158,6 @@ public String toString() {
166
158
if (this .method instanceof HttpMethodRequestMatcher m ) {
167
159
request .append (m .method .name ()).append (' ' );
168
160
}
169
- if (this .servletPath instanceof ServletPathRequestMatcher s ) {
170
- request .append (s .path );
171
- }
172
161
return "PathPattern [" + request + this .pattern + "]" ;
173
162
}
174
163
@@ -194,17 +183,17 @@ public static final class Builder {
194
183
195
184
private final PathPatternParser parser ;
196
185
197
- private final RequestMatcher servletPath ;
186
+ private final String servletPath ;
198
187
199
188
Builder () {
200
189
this (PathPatternParser .defaultInstance );
201
190
}
202
191
203
192
Builder (PathPatternParser parser ) {
204
- this (parser , AnyRequestMatcher . INSTANCE );
193
+ this (parser , "" );
205
194
}
206
195
207
- Builder (PathPatternParser parser , RequestMatcher servletPath ) {
196
+ Builder (PathPatternParser parser , String servletPath ) {
208
197
this .parser = parser ;
209
198
this .servletPath = servletPath ;
210
199
}
@@ -215,7 +204,11 @@ public static final class Builder {
215
204
* @return the {@link Builder} for more configuration
216
205
*/
217
206
public Builder servletPath (String servletPath ) {
218
- return new Builder (this .parser , new ServletPathRequestMatcher (servletPath ));
207
+ Assert .notNull (servletPath , "servletPath cannot be null" );
208
+ Assert .isTrue (servletPath .startsWith ("/" ), "servletPath must start with '/'" );
209
+ Assert .isTrue (!servletPath .endsWith ("/" ), "servletPath must not end with a slash" );
210
+ Assert .isTrue (!servletPath .contains ("*" ), "servletPath must not contain a star" );
211
+ return new Builder (this .parser , servletPath );
219
212
}
220
213
221
214
/**
@@ -286,14 +279,11 @@ public PathPatternRequestMatcher matcher(String path) {
286
279
public PathPatternRequestMatcher matcher (@ Nullable HttpMethod method , String path ) {
287
280
Assert .notNull (path , "pattern cannot be null" );
288
281
Assert .isTrue (path .startsWith ("/" ), "pattern must start with a /" );
289
- PathPattern pathPattern = this .parser .parse (path );
282
+ PathPattern pathPattern = this .parser .parse (this . servletPath + path );
290
283
PathPatternRequestMatcher requestMatcher = new PathPatternRequestMatcher (pathPattern );
291
284
if (method != null ) {
292
285
requestMatcher .setMethod (new HttpMethodRequestMatcher (method ));
293
286
}
294
- if (this .servletPath != AnyRequestMatcher .INSTANCE ) {
295
- requestMatcher .setServletPath (this .servletPath );
296
- }
297
287
return requestMatcher ;
298
288
}
299
289
@@ -319,60 +309,4 @@ public String toString() {
319
309
320
310
}
321
311
322
- private static final class ServletPathRequestMatcher implements RequestMatcher {
323
-
324
- private final String path ;
325
-
326
- private final AtomicReference <Boolean > servletExists = new AtomicReference <>();
327
-
328
- ServletPathRequestMatcher (String servletPath ) {
329
- Assert .notNull (servletPath , "servletPath cannot be null" );
330
- Assert .isTrue (servletPath .startsWith ("/" ), "servletPath must start with '/'" );
331
- Assert .isTrue (!servletPath .endsWith ("/" ), "servletPath must not end with a slash" );
332
- Assert .isTrue (!servletPath .contains ("*" ), "servletPath must not contain a star" );
333
- this .path = servletPath ;
334
- }
335
-
336
- @ Override
337
- public boolean matches (HttpServletRequest request ) {
338
- Assert .isTrue (servletExists (request ), () -> this .path + "/* does not exist in your servlet registration "
339
- + registrationMappings (request ));
340
- return Objects .equals (this .path , ServletRequestPathUtils .getServletPathPrefix (request ));
341
- }
342
-
343
- private boolean servletExists (HttpServletRequest request ) {
344
- return this .servletExists .updateAndGet ((value ) -> {
345
- if (value != null ) {
346
- return value ;
347
- }
348
- if (request .getAttribute ("org.springframework.test.web.servlet.MockMvc.MVC_RESULT_ATTRIBUTE" ) != null ) {
349
- return true ;
350
- }
351
- for (ServletRegistration registration : request .getServletContext ()
352
- .getServletRegistrations ()
353
- .values ()) {
354
- if (registration .getMappings ().contains (this .path + "/*" )) {
355
- return true ;
356
- }
357
- }
358
- return false ;
359
- });
360
- }
361
-
362
- private Map <String , Collection <String >> registrationMappings (HttpServletRequest request ) {
363
- Map <String , Collection <String >> map = new LinkedHashMap <>();
364
- ServletContext servletContext = request .getServletContext ();
365
- for (ServletRegistration registration : servletContext .getServletRegistrations ().values ()) {
366
- map .put (registration .getName (), registration .getMappings ());
367
- }
368
- return map ;
369
- }
370
-
371
- @ Override
372
- public String toString () {
373
- return "ServletPath [" + this .path + "]" ;
374
- }
375
-
376
- }
377
-
378
312
}
0 commit comments