@@ -88,6 +88,10 @@ public class UriComponentsBuilder implements Cloneable {
88
88
"^" + HTTP_PATTERN + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN + ")?" + ")?" +
89
89
PATH_PATTERN + "(\\ ?" + LAST_PATTERN + ")?" );
90
90
91
+ private static final Pattern FORWARDED_HOST_PATTERN = Pattern .compile ("host=\" ?([^;,\" ]+)\" ?" );
92
+
93
+ private static final Pattern FORWARDED_PROTO_PATTERN = Pattern .compile ("proto=\" ?([^;,\" ]+)\" ?" );
94
+
91
95
92
96
private String scheme ;
93
97
@@ -267,7 +271,9 @@ public static UriComponentsBuilder fromHttpUrl(String httpUrl) {
267
271
/**
268
272
* Create a new {@code UriComponents} object from the URI associated with
269
273
* the given HttpRequest while also overlaying with values from the headers
270
- * "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if present.
274
+ * "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>, or
275
+ * "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if "Forwarded" is
276
+ * not found.
271
277
* @param request the source request
272
278
* @return the URI components of the URI
273
279
* @since 4.1.5
@@ -280,31 +286,45 @@ public static UriComponentsBuilder fromHttpRequest(HttpRequest request) {
280
286
String host = uri .getHost ();
281
287
int port = uri .getPort ();
282
288
283
- String hostHeader = request .getHeaders ().getFirst ("X-Forwarded-Host" );
284
- if (StringUtils .hasText (hostHeader )) {
285
- String [] hosts = StringUtils .commaDelimitedListToStringArray (hostHeader );
286
- String hostToUse = hosts [0 ];
287
- if (hostToUse .contains (":" )) {
288
- String [] hostAndPort = StringUtils .split (hostToUse , ":" );
289
- host = hostAndPort [0 ];
290
- port = Integer .parseInt (hostAndPort [1 ]);
289
+ String forwardedHeader = request .getHeaders ().getFirst ("Forwarded" );
290
+ if (StringUtils .hasText (forwardedHeader )) {
291
+ String forwardedToUse = StringUtils .commaDelimitedListToStringArray (forwardedHeader )[0 ];
292
+ Matcher m = FORWARDED_HOST_PATTERN .matcher (forwardedToUse );
293
+ if (m .find ()) {
294
+ host = m .group (1 ).trim ();
291
295
}
292
- else {
293
- host = hostToUse ;
294
- port = - 1 ;
296
+ m = FORWARDED_PROTO_PATTERN . matcher ( forwardedToUse );
297
+ if ( m . find ()) {
298
+ scheme = m . group ( 1 ). trim () ;
295
299
}
296
300
}
301
+ else {
302
+ String hostHeader = request .getHeaders ().getFirst ("X-Forwarded-Host" );
303
+ if (StringUtils .hasText (hostHeader )) {
304
+ String [] hosts = StringUtils .commaDelimitedListToStringArray (hostHeader );
305
+ String hostToUse = hosts [0 ];
306
+ if (hostToUse .contains (":" )) {
307
+ String [] hostAndPort = StringUtils .split (hostToUse , ":" );
308
+ host = hostAndPort [0 ];
309
+ port = Integer .parseInt (hostAndPort [1 ]);
310
+ }
311
+ else {
312
+ host = hostToUse ;
313
+ port = -1 ;
314
+ }
315
+ }
297
316
298
- String portHeader = request .getHeaders ().getFirst ("X-Forwarded-Port" );
299
- if (StringUtils .hasText (portHeader )) {
300
- String [] ports = StringUtils .commaDelimitedListToStringArray (portHeader );
301
- port = Integer .parseInt (ports [0 ]);
302
- }
317
+ String portHeader = request .getHeaders ().getFirst ("X-Forwarded-Port" );
318
+ if (StringUtils .hasText (portHeader )) {
319
+ String [] ports = StringUtils .commaDelimitedListToStringArray (portHeader );
320
+ port = Integer .parseInt (ports [0 ]);
321
+ }
303
322
304
- String protocolHeader = request .getHeaders ().getFirst ("X-Forwarded-Proto" );
305
- if (StringUtils .hasText (protocolHeader )) {
306
- String [] protocols = StringUtils .commaDelimitedListToStringArray (protocolHeader );
307
- scheme = protocols [0 ];
323
+ String protocolHeader = request .getHeaders ().getFirst ("X-Forwarded-Proto" );
324
+ if (StringUtils .hasText (protocolHeader )) {
325
+ String [] protocols = StringUtils .commaDelimitedListToStringArray (protocolHeader );
326
+ scheme = protocols [0 ];
327
+ }
308
328
}
309
329
310
330
builder .scheme (scheme );
0 commit comments