1
1
/*
2
- * Copyright 2002-2020 the original author or authors.
2
+ * Copyright 2002-2021 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
23
23
import java .util .Map ;
24
24
import java .util .Properties ;
25
25
import java .util .concurrent .ConcurrentHashMap ;
26
+ import java .util .function .BiFunction ;
26
27
import java .util .stream .Collectors ;
27
28
28
29
import javax .servlet .http .HttpServletRequest ;
36
37
import org .springframework .core .io .ClassPathResource ;
37
38
import org .springframework .core .io .Resource ;
38
39
import org .springframework .core .io .support .PropertiesLoaderUtils ;
40
+ import org .springframework .http .server .RequestPath ;
39
41
import org .springframework .lang .Nullable ;
40
42
import org .springframework .util .Assert ;
41
43
import org .springframework .util .ClassUtils ;
46
48
import org .springframework .web .servlet .HandlerExecutionChain ;
47
49
import org .springframework .web .servlet .HandlerInterceptor ;
48
50
import org .springframework .web .servlet .HandlerMapping ;
51
+ import org .springframework .web .util .ServletRequestPathUtils ;
49
52
import org .springframework .web .util .UrlPathHelper ;
50
53
51
54
/**
@@ -79,8 +82,7 @@ public class HandlerMappingIntrospector
79
82
private List <HandlerMapping > handlerMappings ;
80
83
81
84
@ Nullable
82
- private Map <HandlerMapping , MatchableHandlerMapping > pathPatternMatchableHandlerMappings =
83
- new ConcurrentHashMap <>();
85
+ private Map <HandlerMapping , PathPatternMatchableHandlerMapping > pathPatternHandlerMappings = new ConcurrentHashMap <>();
84
86
85
87
86
88
/**
@@ -119,7 +121,7 @@ public void afterPropertiesSet() {
119
121
if (this .handlerMappings == null ) {
120
122
Assert .notNull (this .applicationContext , "No ApplicationContext" );
121
123
this .handlerMappings = initHandlerMappings (this .applicationContext );
122
- this .pathPatternMatchableHandlerMappings = initPathPatternMatchableHandlerMappings (this .handlerMappings );
124
+ this .pathPatternHandlerMappings = initPathPatternMatchableHandlerMappings (this .handlerMappings );
123
125
}
124
126
}
125
127
@@ -136,51 +138,90 @@ public void afterPropertiesSet() {
136
138
*/
137
139
@ Nullable
138
140
public MatchableHandlerMapping getMatchableHandlerMapping (HttpServletRequest request ) throws Exception {
139
- Assert . notNull ( this . handlerMappings , "Handler mappings not initialized" );
140
- Assert . notNull ( this . pathPatternMatchableHandlerMappings , "Handler mappings with PathPatterns not initialized" );
141
- HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper ( request );
142
- for ( HandlerMapping handlerMapping : this .handlerMappings ) {
143
- Object handler = handlerMapping . getHandler ( wrapper );
144
- if ( handler == null ) {
145
- continue ;
146
- }
147
- if ( handlerMapping instanceof MatchableHandlerMapping ) {
148
- return this . pathPatternMatchableHandlerMappings . getOrDefault (
149
- handlerMapping , ( MatchableHandlerMapping ) handlerMapping );
141
+ HttpServletRequest wrappedRequest = new RequestAttributeChangeIgnoringWrapper ( request );
142
+ return doWithMatchingMapping ( wrappedRequest , false , ( matchedMapping , executionChain ) -> {
143
+ if ( matchedMapping instanceof MatchableHandlerMapping ) {
144
+ PathPatternMatchableHandlerMapping mapping = this .pathPatternHandlerMappings . get ( matchedMapping );
145
+ if ( mapping != null ) {
146
+ RequestPath requestPath = ServletRequestPathUtils . getParsedRequestPath ( request );
147
+ return mapping . decorate ( requestPath ) ;
148
+ }
149
+ else {
150
+ return ( MatchableHandlerMapping ) matchedMapping ;
151
+ }
150
152
}
151
153
throw new IllegalStateException ("HandlerMapping is not a MatchableHandlerMapping" );
152
- }
153
- return null ;
154
+ });
154
155
}
155
156
156
157
@ Override
157
158
@ Nullable
158
159
public CorsConfiguration getCorsConfiguration (HttpServletRequest request ) {
159
- Assert .notNull (this .handlerMappings , "Handler mappings not initialized" );
160
- RequestAttributeChangeIgnoringWrapper wrapper = new RequestAttributeChangeIgnoringWrapper (request );
161
- for (HandlerMapping handlerMapping : this .handlerMappings ) {
162
- HandlerExecutionChain handler = null ;
163
- try {
164
- handler = handlerMapping .getHandler (wrapper );
165
- }
166
- catch (Exception ex ) {
167
- // Ignore
160
+ RequestAttributeChangeIgnoringWrapper wrappedRequest = new RequestAttributeChangeIgnoringWrapper (request );
161
+ return doWithMatchingMappingIgnoringException (wrappedRequest , (handlerMapping , executionChain ) -> {
162
+ for (HandlerInterceptor interceptor : executionChain .getInterceptorList ()) {
163
+ if (interceptor instanceof CorsConfigurationSource ) {
164
+ return ((CorsConfigurationSource ) interceptor ).getCorsConfiguration (wrappedRequest );
165
+ }
168
166
}
169
- if (handler == null ) {
170
- continue ;
167
+ if (executionChain . getHandler () instanceof CorsConfigurationSource ) {
168
+ return (( CorsConfigurationSource ) executionChain . getHandler ()). getCorsConfiguration ( wrappedRequest ) ;
171
169
}
172
- for (HandlerInterceptor interceptor : handler .getInterceptorList ()) {
173
- if (interceptor instanceof CorsConfigurationSource ) {
174
- return ((CorsConfigurationSource ) interceptor ).getCorsConfiguration (wrapper );
170
+ return null ;
171
+ });
172
+ }
173
+
174
+ @ Nullable
175
+ private <T > T doWithMatchingMapping (
176
+ HttpServletRequest request , boolean ignoreException ,
177
+ BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) throws Exception {
178
+
179
+ Assert .notNull (this .handlerMappings , "Handler mappings not initialized" );
180
+ Assert .notNull (this .pathPatternHandlerMappings , "Handler mappings with PathPatterns not initialized" );
181
+
182
+ boolean parseRequestPath = !this .pathPatternHandlerMappings .isEmpty ();
183
+ RequestPath previousPath = null ;
184
+ if (parseRequestPath ) {
185
+ previousPath = (RequestPath ) request .getAttribute (ServletRequestPathUtils .PATH_ATTRIBUTE );
186
+ ServletRequestPathUtils .parseAndCache (request );
187
+ }
188
+ try {
189
+ for (HandlerMapping handlerMapping : this .handlerMappings ) {
190
+ HandlerExecutionChain chain = null ;
191
+ try {
192
+ chain = handlerMapping .getHandler (request );
193
+ }
194
+ catch (Exception ex ) {
195
+ if (!ignoreException ) {
196
+ throw ex ;
197
+ }
175
198
}
199
+ if (chain == null ) {
200
+ continue ;
201
+ }
202
+ return matchHandler .apply (handlerMapping , chain );
176
203
}
177
- if (handler .getHandler () instanceof CorsConfigurationSource ) {
178
- return ((CorsConfigurationSource ) handler .getHandler ()).getCorsConfiguration (wrapper );
204
+ }
205
+ finally {
206
+ if (parseRequestPath ) {
207
+ ServletRequestPathUtils .setParsedRequestPath (previousPath , request );
179
208
}
180
209
}
181
210
return null ;
182
211
}
183
212
213
+ @ Nullable
214
+ private <T > T doWithMatchingMappingIgnoringException (
215
+ HttpServletRequest request , BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) {
216
+
217
+ try {
218
+ return doWithMatchingMapping (request , true , matchHandler );
219
+ }
220
+ catch (Exception ex ) {
221
+ throw new IllegalStateException ("HandlerMapping exception not suppressed" , ex );
222
+ }
223
+ }
224
+
184
225
185
226
private static List <HandlerMapping > initHandlerMappings (ApplicationContext applicationContext ) {
186
227
Map <String , HandlerMapping > beans = BeanFactoryUtils .beansOfTypeIncludingAncestors (
@@ -219,7 +260,7 @@ private static List<HandlerMapping> initFallback(ApplicationContext applicationC
219
260
return result ;
220
261
}
221
262
222
- private static Map <HandlerMapping , MatchableHandlerMapping > initPathPatternMatchableHandlerMappings (
263
+ private static Map <HandlerMapping , PathPatternMatchableHandlerMapping > initPathPatternMatchableHandlerMappings (
223
264
List <HandlerMapping > mappings ) {
224
265
225
266
return mappings .stream ()
@@ -241,8 +282,7 @@ private static class RequestAttributeChangeIgnoringWrapper extends HttpServletRe
241
282
242
283
@ Override
243
284
public void setAttribute (String name , Object value ) {
244
- // Allow UrlPathHelper-resolved lookupPath to be saved for efficiency
245
- if (name .equals (UrlPathHelper .PATH_ATTRIBUTE )) {
285
+ if (name .equals (ServletRequestPathUtils .PATH_ATTRIBUTE ) || name .equals (UrlPathHelper .PATH_ATTRIBUTE )) {
246
286
super .setAttribute (name , value );
247
287
}
248
288
}
0 commit comments