23
23
import java .util .Locale ;
24
24
import java .util .Map ;
25
25
import java .util .Set ;
26
+ import java .util .function .Supplier ;
26
27
import javax .servlet .FilterChain ;
27
28
import javax .servlet .ServletException ;
28
29
import javax .servlet .http .HttpServletRequest ;
@@ -219,11 +220,7 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem
219
220
220
221
private final int port ;
221
222
222
- private final String contextPath ;
223
-
224
- private final String requestUri ;
225
-
226
- private final String requestUrl ;
223
+ private final ForwardedPrefixExtractor forwardedPrefixExtractor ;
227
224
228
225
229
226
ForwardedHeaderExtractingRequest (HttpServletRequest request , UrlPathHelper pathHelper ) {
@@ -238,28 +235,9 @@ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRem
238
235
this .host = uriComponents .getHost ();
239
236
this .port = (port == -1 ? (this .secure ? 443 : 80 ) : port );
240
237
241
- String prefix = getForwardedPrefix (request );
242
- this .contextPath = (prefix != null ? prefix : request .getContextPath ());
243
- this .requestUri = this .contextPath + pathHelper .getPathWithinApplication (request );
244
- this .requestUrl = this .scheme + "://" + this .host + (port == -1 ? "" : ":" + port ) + this .requestUri ;
245
- }
246
-
247
- @ Nullable
248
- private static String getForwardedPrefix (HttpServletRequest request ) {
249
- String prefix = null ;
250
- Enumeration <String > names = request .getHeaderNames ();
251
- while (names .hasMoreElements ()) {
252
- String name = names .nextElement ();
253
- if ("X-Forwarded-Prefix" .equalsIgnoreCase (name )) {
254
- prefix = request .getHeader (name );
255
- }
256
- }
257
- if (prefix != null ) {
258
- while (prefix .endsWith ("/" )) {
259
- prefix = prefix .substring (0 , prefix .length () - 1 );
260
- }
261
- }
262
- return prefix ;
238
+ String baseUrl = this .scheme + "://" + this .host + (port == -1 ? "" : ":" + port );
239
+ Supplier <HttpServletRequest > delegateRequest = () -> (HttpServletRequest ) getRequest ();
240
+ this .forwardedPrefixExtractor = new ForwardedPrefixExtractor (delegateRequest , pathHelper , baseUrl );
263
241
}
264
242
265
243
@@ -287,18 +265,122 @@ public boolean isSecure() {
287
265
288
266
@ Override
289
267
public String getContextPath () {
290
- return this .contextPath ;
268
+ return this .forwardedPrefixExtractor . getContextPath () ;
291
269
}
292
270
293
271
@ Override
294
272
public String getRequestURI () {
295
- return this .requestUri ;
273
+ return this .forwardedPrefixExtractor . getRequestUri () ;
296
274
}
297
275
298
276
@ Override
299
277
public StringBuffer getRequestURL () {
278
+ return this .forwardedPrefixExtractor .getRequestUrl ();
279
+ }
280
+ }
281
+
282
+
283
+ /**
284
+ * Responsible for the contextPath, requestURI, and requestURL with forwarded
285
+ * headers in mind, and also taking into account changes to the path of the
286
+ * underlying delegate request (e.g. on a Servlet FORWARD).
287
+ */
288
+ private static class ForwardedPrefixExtractor {
289
+
290
+ private final Supplier <HttpServletRequest > delegate ;
291
+
292
+ private final UrlPathHelper pathHelper ;
293
+
294
+ private final String baseUrl ;
295
+
296
+ private String actualRequestUri ;
297
+
298
+ @ Nullable
299
+ private final String forwardedPrefix ;
300
+
301
+ @ Nullable
302
+ private String requestUri ;
303
+
304
+ private String requestUrl ;
305
+
306
+
307
+ /**
308
+ * Constructor with required information.
309
+ * @param delegateRequest supplier for the current
310
+ * {@link HttpServletRequestWrapper#getRequest() delegate request} which
311
+ * may change during a forward (e.g. Tocat.
312
+ * @param pathHelper the path helper instance
313
+ * @param baseUrl the host, scheme, and port based on forwarded headers
314
+ */
315
+ public ForwardedPrefixExtractor (
316
+ Supplier <HttpServletRequest > delegateRequest , UrlPathHelper pathHelper , String baseUrl ) {
317
+
318
+ this .delegate = delegateRequest ;
319
+ this .pathHelper = pathHelper ;
320
+ this .baseUrl = baseUrl ;
321
+ this .actualRequestUri = delegateRequest .get ().getRequestURI ();
322
+
323
+ this .forwardedPrefix = initForwardedPrefix (delegateRequest .get ());
324
+ this .requestUri = initRequestUri ();
325
+ this .requestUrl = initRequestUrl (); // Keep the order: depends on requestUri
326
+ }
327
+
328
+ @ Nullable
329
+ private static String initForwardedPrefix (HttpServletRequest request ) {
330
+ String result = null ;
331
+ Enumeration <String > names = request .getHeaderNames ();
332
+ while (names .hasMoreElements ()) {
333
+ String name = names .nextElement ();
334
+ if ("X-Forwarded-Prefix" .equalsIgnoreCase (name )) {
335
+ result = request .getHeader (name );
336
+ }
337
+ }
338
+ if (result != null ) {
339
+ while (result .endsWith ("/" )) {
340
+ result = result .substring (0 , result .length () - 1 );
341
+ }
342
+ }
343
+ return result ;
344
+ }
345
+
346
+ @ Nullable
347
+ private String initRequestUri () {
348
+ if (this .forwardedPrefix != null ) {
349
+ return this .forwardedPrefix + this .pathHelper .getPathWithinApplication (this .delegate .get ());
350
+ }
351
+ return null ;
352
+ }
353
+
354
+ private String initRequestUrl () {
355
+ return this .baseUrl + (this .requestUri != null ? this .requestUri : this .delegate .get ().getRequestURI ());
356
+ }
357
+
358
+
359
+ public String getContextPath () {
360
+ return this .forwardedPrefix == null ? this .delegate .get ().getContextPath () : this .forwardedPrefix ;
361
+ }
362
+
363
+ public String getRequestUri () {
364
+ if (this .requestUri == null ) {
365
+ return this .delegate .get ().getRequestURI ();
366
+ }
367
+ recalculatePathsIfNecesary ();
368
+ return this .requestUri ;
369
+ }
370
+
371
+ public StringBuffer getRequestUrl () {
372
+ recalculatePathsIfNecesary ();
300
373
return new StringBuffer (this .requestUrl );
301
374
}
375
+
376
+ private void recalculatePathsIfNecesary () {
377
+ if (!this .actualRequestUri .equals (this .delegate .get ().getRequestURI ())) {
378
+ // Underlying path change (e.g. Servlet FORWARD).
379
+ this .actualRequestUri = this .delegate .get ().getRequestURI ();
380
+ this .requestUri = initRequestUri ();
381
+ this .requestUrl = initRequestUrl (); // Keep the order: depends on requestUri
382
+ }
383
+ }
302
384
}
303
385
304
386
0 commit comments