21
21
import java .util .List ;
22
22
import java .util .Map ;
23
23
import java .util .function .Consumer ;
24
- import java .util .function .Function ;
25
- import java .util .function .Predicate ;
26
24
27
25
import jakarta .servlet .FilterChain ;
28
26
import jakarta .servlet .ServletException ;
@@ -67,10 +65,10 @@ public final class UrlHandlerFilter extends OncePerRequestFilter {
67
65
private static final Log logger = LogFactory .getLog (UrlHandlerFilter .class );
68
66
69
67
70
- private final MultiValueMap <UrlHandler , PathPattern > handlers ;
68
+ private final MultiValueMap <Handler , PathPattern > handlers ;
71
69
72
70
73
- private UrlHandlerFilter (MultiValueMap <UrlHandler , PathPattern > handlers ) {
71
+ private UrlHandlerFilter (MultiValueMap <Handler , PathPattern > handlers ) {
74
72
this .handlers = new LinkedMultiValueMap <>(handlers );
75
73
}
76
74
@@ -95,7 +93,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
95
93
if (path == null ) {
96
94
path = ServletRequestPathUtils .parseAndCache (request );
97
95
}
98
- for (Map .Entry <UrlHandler , List <PathPattern >> entry : this .handlers .entrySet ()) {
96
+ for (Map .Entry <Handler , List <PathPattern >> entry : this .handlers .entrySet ()) {
99
97
if (!entry .getKey ().canHandle (request )) {
100
98
continue ;
101
99
}
@@ -188,14 +186,14 @@ private static final class DefaultBuilder implements Builder {
188
186
189
187
private final PathPatternParser patternParser = new PathPatternParser ();
190
188
191
- private final MultiValueMap <UrlHandler , PathPattern > handlers = new LinkedMultiValueMap <>();
189
+ private final MultiValueMap <Handler , PathPattern > handlers = new LinkedMultiValueMap <>();
192
190
193
191
@ Override
194
192
public TrailingSlashSpec trailingSlashHandler (String ... patterns ) {
195
193
return new DefaultTrailingSlashSpec (patterns );
196
194
}
197
195
198
- private DefaultBuilder addHandler (List <PathPattern > pathPatterns , UrlHandler handler ) {
196
+ private DefaultBuilder addHandler (List <PathPattern > pathPatterns , Handler handler ) {
199
197
pathPatterns .forEach (pattern -> this .handlers .add (handler , pattern ));
200
198
return this ;
201
199
}
@@ -207,18 +205,10 @@ public UrlHandlerFilter build() {
207
205
208
206
private final class DefaultTrailingSlashSpec implements TrailingSlashSpec {
209
207
210
- private static final Predicate <HttpServletRequest > trailingSlashPredicate =
211
- request -> request .getRequestURI ().endsWith ("/" );
212
-
213
- private static final Function <String , String > tralingSlashTrimFunction = path -> {
214
- int index = (StringUtils .hasLength (path ) ? path .lastIndexOf ('/' ) : -1 );
215
- return (index != -1 ? path .substring (0 , index ) : path );
216
- };
217
-
218
208
private final List <PathPattern > pathPatterns ;
219
209
220
210
@ Nullable
221
- private Consumer <HttpServletRequest > requestConsumer ;
211
+ private Consumer <HttpServletRequest > interceptor ;
222
212
223
213
private DefaultTrailingSlashSpec (String [] patterns ) {
224
214
this .pathPatterns = Arrays .stream (patterns )
@@ -229,33 +219,20 @@ private DefaultTrailingSlashSpec(String[] patterns) {
229
219
230
220
@ Override
231
221
public TrailingSlashSpec intercept (Consumer <HttpServletRequest > consumer ) {
232
- this .requestConsumer = (this .requestConsumer != null ?
233
- this .requestConsumer .andThen (consumer ) : consumer );
222
+ this .interceptor = (this .interceptor != null ? this .interceptor .andThen (consumer ) : consumer );
234
223
return this ;
235
224
}
236
225
237
226
@ Override
238
227
public Builder redirect (HttpStatus status ) {
239
- return DefaultBuilder .this .addHandler (
240
- this .pathPatterns , new RedirectUrlHandler (
241
- trailingSlashPredicate , tralingSlashTrimFunction , status , initRequestConsumer ()));
228
+ Handler handler = new RedirectTrailingSlashHandler (status , this .interceptor );
229
+ return DefaultBuilder .this .addHandler (this .pathPatterns , handler );
242
230
}
243
231
244
232
@ Override
245
233
public Builder wrapRequest () {
246
- return DefaultBuilder .this .addHandler (
247
- this .pathPatterns , new RequestWrappingUrlHandler (
248
- trailingSlashPredicate , tralingSlashTrimFunction , initRequestConsumer ()));
249
- }
250
-
251
- private Consumer <HttpServletRequest > initRequestConsumer () {
252
- return this .requestConsumer != null ? this .requestConsumer :
253
- (request -> {
254
- if (logger .isTraceEnabled ()) {
255
- logger .trace ("Trimmed trailing slash: " +
256
- request .getMethod () + " " + request .getRequestURI ());
257
- }
258
- });
234
+ Handler handler = new RequestWrappingTrailingSlashHandler (this .interceptor );
235
+ return DefaultBuilder .this .addHandler (this .pathPatterns , handler );
259
236
}
260
237
}
261
238
}
@@ -265,7 +242,7 @@ private Consumer<HttpServletRequest> initRequestConsumer() {
265
242
/**
266
243
* Internal handler to encapsulate different ways to handle a request.
267
244
*/
268
- private interface UrlHandler {
245
+ private interface Handler {
269
246
270
247
/**
271
248
* Whether the handler handles the given request.
@@ -281,72 +258,66 @@ void handle(HttpServletRequest request, HttpServletResponse response, FilterChai
281
258
282
259
283
260
/**
284
- * Base class for {@code UrlHandler } implementations.
261
+ * Base class for trailing slash {@link Handler } implementations.
285
262
*/
286
- private abstract static class AbstractUrlHandler implements UrlHandler {
287
-
288
- private final Predicate <HttpServletRequest > requestPredicate ;
263
+ private abstract static class AbstractTrailingSlashHandler implements Handler {
289
264
290
- private final Function <String , String > pathFunction ;
291
-
292
- private final Consumer <HttpServletRequest > requestConsumer ;
265
+ private static final Consumer <HttpServletRequest > defaultInterceptor = request -> {
266
+ if (logger .isTraceEnabled ()) {
267
+ logger .trace ("Handling trailing slash URL: " +
268
+ request .getMethod () + " " + request .getRequestURI ());
269
+ }
270
+ };
293
271
294
- AbstractUrlHandler (
295
- Predicate <HttpServletRequest > requestPredicate , Function <String , String > pathFunction ,
296
- Consumer <HttpServletRequest > requestConsumer ) {
272
+ private final Consumer <HttpServletRequest > interceptor ;
297
273
298
- this .requestPredicate = requestPredicate ;
299
- this .pathFunction = pathFunction ;
300
- this .requestConsumer = requestConsumer ;
301
- }
302
-
303
- protected Function <String , String > getPathFunction () {
304
- return this .pathFunction ;
274
+ protected AbstractTrailingSlashHandler (@ Nullable Consumer <HttpServletRequest > interceptor ) {
275
+ this .interceptor = (interceptor != null ? interceptor : defaultInterceptor );
305
276
}
306
277
307
278
@ Override
308
279
public boolean canHandle (HttpServletRequest request ) {
309
- return this . requestPredicate . test ( request );
280
+ return request . getRequestURI (). endsWith ( "/" );
310
281
}
311
282
312
283
@ Override
313
284
public void handle (HttpServletRequest request , HttpServletResponse response , FilterChain chain )
314
285
throws ServletException , IOException {
315
286
316
- this .requestConsumer .accept (request );
287
+ this .interceptor .accept (request );
317
288
handleInternal (request , response , chain );
318
289
}
319
290
320
291
protected abstract void handleInternal (
321
292
HttpServletRequest request , HttpServletResponse response , FilterChain chain )
322
293
throws ServletException , IOException ;
294
+
295
+ protected String trimTrailingSlash (String path ) {
296
+ int index = (StringUtils .hasLength (path ) ? path .lastIndexOf ('/' ) : -1 );
297
+ return (index != -1 ? path .substring (0 , index ) : path );
298
+ }
323
299
}
324
300
325
301
326
302
/**
327
303
* Path handler that sends a redirect.
328
304
*/
329
- private static final class RedirectUrlHandler extends AbstractUrlHandler {
305
+ private static final class RedirectTrailingSlashHandler extends AbstractTrailingSlashHandler {
330
306
331
307
private final HttpStatus httpStatus ;
332
308
333
- RedirectUrlHandler (
334
- Predicate <HttpServletRequest > pathPredicate , Function <String , String > pathFunction ,
335
- HttpStatus httpStatus , Consumer <HttpServletRequest > interceptor ) {
336
-
337
- super (pathPredicate , pathFunction , interceptor );
309
+ RedirectTrailingSlashHandler (HttpStatus httpStatus , @ Nullable Consumer <HttpServletRequest > interceptor ) {
310
+ super (interceptor );
338
311
this .httpStatus = httpStatus ;
339
312
}
340
313
341
314
@ Override
342
315
public void handleInternal (HttpServletRequest request , HttpServletResponse response , FilterChain chain )
343
316
throws IOException {
344
317
345
- String location = getPathFunction ().apply (request .getRequestURI ());
346
-
347
318
response .resetBuffer ();
348
319
response .setStatus (this .httpStatus .value ());
349
- response .setHeader (HttpHeaders .LOCATION , location );
320
+ response .setHeader (HttpHeaders .LOCATION , trimTrailingSlash ( request . getRequestURI ()) );
350
321
response .flushBuffer ();
351
322
}
352
323
}
@@ -355,20 +326,27 @@ public void handleInternal(HttpServletRequest request, HttpServletResponse respo
355
326
/**
356
327
* Path handler that wraps the request and continues processing.
357
328
*/
358
- private static final class RequestWrappingUrlHandler extends AbstractUrlHandler {
329
+ private static final class RequestWrappingTrailingSlashHandler extends AbstractTrailingSlashHandler {
359
330
360
- RequestWrappingUrlHandler (
361
- Predicate <HttpServletRequest > pathPredicate , Function <String , String > pathFunction ,
362
- Consumer <HttpServletRequest > interceptor ) {
363
-
364
- super (pathPredicate , pathFunction , interceptor );
331
+ RequestWrappingTrailingSlashHandler (@ Nullable Consumer <HttpServletRequest > interceptor ) {
332
+ super (interceptor );
365
333
}
366
334
367
335
@ Override
368
336
public void handleInternal (HttpServletRequest request , HttpServletResponse response , FilterChain chain )
369
337
throws ServletException , IOException {
370
338
371
- request = new PathHttpServletRequestWrapper (request , getPathFunction ());
339
+ String servletPath = request .getServletPath ();
340
+ String pathInfo = request .getPathInfo ();
341
+ boolean hasPathInfo = StringUtils .hasText (pathInfo );
342
+
343
+ request = new TrailingSlashHttpServletRequest (
344
+ request ,
345
+ trimTrailingSlash (request .getRequestURI ()),
346
+ trimTrailingSlash (request .getRequestURL ().toString ()),
347
+ hasPathInfo ? servletPath : trimTrailingSlash (servletPath ),
348
+ hasPathInfo ? trimTrailingSlash (pathInfo ) : pathInfo );
349
+
372
350
chain .doFilter (request , response );
373
351
}
374
352
}
@@ -377,7 +355,7 @@ public void handleInternal(HttpServletRequest request, HttpServletResponse respo
377
355
/**
378
356
* Wraps the request to return modified path information.
379
357
*/
380
- private static class PathHttpServletRequestWrapper extends HttpServletRequestWrapper {
358
+ private static class TrailingSlashHttpServletRequest extends HttpServletRequestWrapper {
381
359
382
360
private final String requestURI ;
383
361
@@ -387,18 +365,14 @@ private static class PathHttpServletRequestWrapper extends HttpServletRequestWra
387
365
388
366
private final String pathInfo ;
389
367
390
- PathHttpServletRequestWrapper (HttpServletRequest request , Function <String , String > pathFunction ) {
368
+ TrailingSlashHttpServletRequest (HttpServletRequest request ,
369
+ String requestURI , String requestURL , String servletPath , String pathInfo ) {
370
+
391
371
super (request );
392
- this .requestURI = pathFunction .apply (request .getRequestURI ());
393
- this .requestURL = new StringBuffer (pathFunction .apply (request .getRequestURL ().toString ()));
394
- if (StringUtils .hasText (request .getPathInfo ())) {
395
- this .servletPath = request .getServletPath ();
396
- this .pathInfo = pathFunction .apply (request .getPathInfo ());
397
- }
398
- else {
399
- this .servletPath = pathFunction .apply (request .getServletPath ());
400
- this .pathInfo = request .getPathInfo ();
401
- }
372
+ this .requestURI = requestURI ;
373
+ this .requestURL = new StringBuffer (requestURL );
374
+ this .servletPath = servletPath ;
375
+ this .pathInfo = pathInfo ;
402
376
}
403
377
404
378
@ Override
0 commit comments