1
1
/*
2
- * Copyright 2002-2015 the original author or authors.
2
+ * Copyright 2002-2016 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.
24
24
import java .util .regex .Matcher ;
25
25
import java .util .regex .Pattern ;
26
26
27
+ import org .springframework .http .HttpHeaders ;
27
28
import org .springframework .http .HttpRequest ;
28
29
import org .springframework .util .Assert ;
29
30
import org .springframework .util .LinkedMultiValueMap ;
@@ -130,7 +131,7 @@ protected UriComponentsBuilder(UriComponentsBuilder other) {
130
131
this .userInfo = other .userInfo ;
131
132
this .host = other .host ;
132
133
this .port = other .port ;
133
- this .pathBuilder = ( CompositePathComponentBuilder ) other .pathBuilder .clone ();
134
+ this .pathBuilder = other .pathBuilder .cloneBuilder ();
134
135
this .queryParams .putAll (other .queryParams );
135
136
this .fragment = other .fragment ;
136
137
}
@@ -271,72 +272,17 @@ public static UriComponentsBuilder fromHttpUrl(String httpUrl) {
271
272
/**
272
273
* Create a new {@code UriComponents} object from the URI associated with
273
274
* the given HttpRequest while also overlaying with values from the headers
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.
275
+ * "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>,
276
+ * or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
277
+ * "Forwarded" is not found.
277
278
* @param request the source request
278
279
* @return the URI components of the URI
279
280
* @since 4.1.5
280
281
*/
281
282
public static UriComponentsBuilder fromHttpRequest (HttpRequest request ) {
282
- URI uri = request .getURI ();
283
- UriComponentsBuilder builder = UriComponentsBuilder .fromUri (uri );
284
-
285
- String scheme = uri .getScheme ();
286
- String host = uri .getHost ();
287
- int port = uri .getPort ();
288
-
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 ();
295
- }
296
- m = FORWARDED_PROTO_PATTERN .matcher (forwardedToUse );
297
- if (m .find ()) {
298
- scheme = m .group (1 ).trim ();
299
- }
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
- }
316
-
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
- }
322
-
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
- }
328
- }
329
-
330
- builder .scheme (scheme );
331
- builder .host (host );
332
- builder .port (null );
333
- if (scheme .equals ("http" ) && port != 80 || scheme .equals ("https" ) && port != 443 ) {
334
- builder .port (port );
335
- }
336
- return builder ;
283
+ return fromUri (request .getURI ()).adaptFromForwardedHeaders (request .getHeaders ());
337
284
}
338
285
339
-
340
286
/**
341
287
* Create an instance by parsing the "Origin" header of an HTTP request.
342
288
* @see <a href="https://tools.ietf.org/html/rfc6454">RFC 6454</a>
@@ -463,18 +409,6 @@ public UriComponentsBuilder uri(URI uri) {
463
409
return this ;
464
410
}
465
411
466
- private void resetHierarchicalComponents () {
467
- this .userInfo = null ;
468
- this .host = null ;
469
- this .port = null ;
470
- this .pathBuilder = new CompositePathComponentBuilder ();
471
- this .queryParams .clear ();
472
- }
473
-
474
- private void resetSchemeSpecificPart () {
475
- this .ssp = null ;
476
- }
477
-
478
412
/**
479
413
* Set the URI scheme. The given scheme may contain URI template variables,
480
414
* and may also be {@code null} to clear the scheme of this builder.
@@ -724,17 +658,103 @@ public UriComponentsBuilder fragment(String fragment) {
724
658
return this ;
725
659
}
726
660
661
+ /**
662
+ * Adapt this builder's scheme+host+port from the given headers, specifically
663
+ * "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>,
664
+ * or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
665
+ * "Forwarded" is not found.
666
+ * @param headers the HTTP headers to consider
667
+ * @return this UriComponentsBuilder
668
+ * @since 4.3
669
+ */
670
+ UriComponentsBuilder adaptFromForwardedHeaders (HttpHeaders headers ) {
671
+ String forwardedHeader = headers .getFirst ("Forwarded" );
672
+ if (StringUtils .hasText (forwardedHeader )) {
673
+ String forwardedToUse = StringUtils .commaDelimitedListToStringArray (forwardedHeader )[0 ];
674
+ Matcher matcher = FORWARDED_HOST_PATTERN .matcher (forwardedToUse );
675
+ if (matcher .find ()) {
676
+ host (matcher .group (1 ).trim ());
677
+ }
678
+ matcher = FORWARDED_PROTO_PATTERN .matcher (forwardedToUse );
679
+ if (matcher .find ()) {
680
+ scheme (matcher .group (1 ).trim ());
681
+ }
682
+ }
683
+ else {
684
+ String hostHeader = headers .getFirst ("X-Forwarded-Host" );
685
+ if (StringUtils .hasText (hostHeader )) {
686
+ String [] hosts = StringUtils .commaDelimitedListToStringArray (hostHeader );
687
+ String hostToUse = hosts [0 ];
688
+ if (hostToUse .contains (":" )) {
689
+ String [] hostAndPort = StringUtils .split (hostToUse , ":" );
690
+ host (hostAndPort [0 ]);
691
+ port (Integer .parseInt (hostAndPort [1 ]));
692
+ }
693
+ else {
694
+ host (hostToUse );
695
+ port (null );
696
+ }
697
+ }
698
+
699
+ String portHeader = headers .getFirst ("X-Forwarded-Port" );
700
+ if (StringUtils .hasText (portHeader )) {
701
+ String [] ports = StringUtils .commaDelimitedListToStringArray (portHeader );
702
+ port (Integer .parseInt (ports [0 ]));
703
+ }
704
+
705
+ String protocolHeader = headers .getFirst ("X-Forwarded-Proto" );
706
+ if (StringUtils .hasText (protocolHeader )) {
707
+ String [] protocols = StringUtils .commaDelimitedListToStringArray (protocolHeader );
708
+ scheme (protocols [0 ]);
709
+ }
710
+ }
711
+
712
+ if ((this .scheme .equals ("http" ) && "80" .equals (this .port )) ||
713
+ (this .scheme .equals ("https" ) && "443" .equals (this .port ))) {
714
+ this .port = null ;
715
+ }
716
+
717
+ return this ;
718
+ }
719
+
720
+ private void resetHierarchicalComponents () {
721
+ this .userInfo = null ;
722
+ this .host = null ;
723
+ this .port = null ;
724
+ this .pathBuilder = new CompositePathComponentBuilder ();
725
+ this .queryParams .clear ();
726
+ }
727
+
728
+ private void resetSchemeSpecificPart () {
729
+ this .ssp = null ;
730
+ }
731
+
732
+
733
+ /**
734
+ * Public declaration of Object's {@code clone()} method.
735
+ * Delegates to {@link #cloneBuilder()}.
736
+ * @see Object#clone()
737
+ */
727
738
@ Override
728
739
public Object clone () {
740
+ return cloneBuilder ();
741
+ }
742
+
743
+ /**
744
+ * Clone this {@code UriComponentsBuilder}.
745
+ * @return the cloned {@code UriComponentsBuilder} object
746
+ * @since 4.3
747
+ */
748
+ public UriComponentsBuilder cloneBuilder () {
729
749
return new UriComponentsBuilder (this );
730
750
}
731
751
732
752
733
- private interface PathComponentBuilder extends Cloneable {
753
+ private interface PathComponentBuilder {
734
754
735
755
PathComponent build ();
736
756
737
- Object clone ();
757
+ PathComponentBuilder cloneBuilder ();
738
758
}
739
759
740
760
@@ -810,10 +830,10 @@ public PathComponent build() {
810
830
}
811
831
812
832
@ Override
813
- public Object clone () {
833
+ public CompositePathComponentBuilder cloneBuilder () {
814
834
CompositePathComponentBuilder compositeBuilder = new CompositePathComponentBuilder ();
815
835
for (PathComponentBuilder builder : this .builders ) {
816
- compositeBuilder .builders .add (( PathComponentBuilder ) builder .clone ());
836
+ compositeBuilder .builders .add (builder .cloneBuilder ());
817
837
}
818
838
return compositeBuilder ;
819
839
}
@@ -852,7 +872,7 @@ public void removeTrailingSlash() {
852
872
}
853
873
854
874
@ Override
855
- public Object clone () {
875
+ public FullPathComponentBuilder cloneBuilder () {
856
876
FullPathComponentBuilder builder = new FullPathComponentBuilder ();
857
877
builder .append (this .path .toString ());
858
878
return builder ;
@@ -879,7 +899,7 @@ public PathComponent build() {
879
899
}
880
900
881
901
@ Override
882
- public Object clone () {
902
+ public PathSegmentComponentBuilder cloneBuilder () {
883
903
PathSegmentComponentBuilder builder = new PathSegmentComponentBuilder ();
884
904
builder .pathSegments .addAll (this .pathSegments );
885
905
return builder ;
0 commit comments