58
58
* @author Arjen Poutsma
59
59
* @author Sebastien Deleuze
60
60
* @author Brian Clozel
61
+ * @author Juergen Hoeller
61
62
* @since 3.0
62
63
*/
63
64
public class HttpHeaders implements MultiValueMap <String , String >, Serializable {
@@ -454,7 +455,7 @@ public void setAccessControlAllowCredentials(boolean allowCredentials) {
454
455
* Returns the value of the {@code Access-Control-Allow-Credentials} response header.
455
456
*/
456
457
public boolean getAccessControlAllowCredentials () {
457
- return new Boolean (getFirst (ACCESS_CONTROL_ALLOW_CREDENTIALS ));
458
+ return Boolean . parseBoolean (getFirst (ACCESS_CONTROL_ALLOW_CREDENTIALS ));
458
459
}
459
460
460
461
/**
@@ -510,22 +511,6 @@ public String getAccessControlAllowOrigin() {
510
511
return getFieldValues (ACCESS_CONTROL_ALLOW_ORIGIN );
511
512
}
512
513
513
- protected String getFieldValues (String headerName ) {
514
- List <String > headerValues = this .headers .get (headerName );
515
- if (headerValues != null ) {
516
- StringBuilder builder = new StringBuilder ();
517
- for (Iterator <String > iterator = headerValues .iterator (); iterator .hasNext (); ) {
518
- String ifNoneMatch = iterator .next ();
519
- builder .append (ifNoneMatch );
520
- if (iterator .hasNext ()) {
521
- builder .append (", " );
522
- }
523
- }
524
- return builder .toString ();
525
- }
526
- return null ;
527
- }
528
-
529
514
/**
530
515
* Set the (new) value of the {@code Access-Control-Expose-Headers} response header.
531
516
*/
@@ -809,62 +794,28 @@ public long getExpires() {
809
794
810
795
/**
811
796
* Set the (new) value of the {@code If-Match} header.
797
+ * @since 4.3
812
798
*/
813
799
public void setIfMatch (String ifMatch ) {
814
800
set (IF_MATCH , ifMatch );
815
801
}
816
802
817
803
/**
818
804
* Set the (new) value of the {@code If-Match} header.
805
+ * @since 4.3
819
806
*/
820
807
public void setIfMatch (List <String > ifMatchList ) {
821
808
set (IF_MATCH , toCommaDelimitedString (ifMatchList ));
822
809
}
823
810
824
- protected String toCommaDelimitedString (List <String > list ) {
825
- StringBuilder builder = new StringBuilder ();
826
- for (Iterator <String > iterator = list .iterator (); iterator .hasNext (); ) {
827
- String ifNoneMatch = iterator .next ();
828
- builder .append (ifNoneMatch );
829
- if (iterator .hasNext ()) {
830
- builder .append (", " );
831
- }
832
- }
833
- return builder .toString ();
834
- }
835
-
836
811
/**
837
812
* Return the value of the {@code If-Match} header.
813
+ * @since 4.3
838
814
*/
839
815
public List <String > getIfMatch () {
840
816
return getETagValuesAsList (IF_MATCH );
841
817
}
842
818
843
- protected List <String > getETagValuesAsList (String headerName ) {
844
- List <String > values = get (headerName );
845
- if (values != null ) {
846
- List <String > result = new ArrayList <String >();
847
- for (String value : values ) {
848
- if (value != null ) {
849
- Matcher matcher = ETAG_HEADER_VALUE_PATTERN .matcher (value );
850
- while (matcher .find ()) {
851
- if ("*" .equals (matcher .group ())) {
852
- result .add (matcher .group ());
853
- }
854
- else {
855
- result .add (matcher .group (1 ));
856
- }
857
- }
858
- if (result .size () == 0 ) {
859
- throw new IllegalArgumentException ("Could not parse '" + headerName + "' value=" + value );
860
- }
861
- }
862
- }
863
- return result ;
864
- }
865
- return Collections .emptyList ();
866
- }
867
-
868
819
/**
869
820
* Set the (new) value of the {@code If-Modified-Since} header.
870
821
* <p>The date should be specified as the number of milliseconds since
@@ -904,32 +855,11 @@ public List<String> getIfNoneMatch() {
904
855
return getETagValuesAsList (IF_NONE_MATCH );
905
856
}
906
857
907
- /**
908
- * Return all values of a given header name,
909
- * even if this header is set multiple times.
910
- * @since 4.3
911
- */
912
- public List <String > getValuesAsList (String headerName ) {
913
- List <String > values = get (headerName );
914
- if (values != null ) {
915
- List <String > result = new ArrayList <String >();
916
- for (String value : values ) {
917
- if (value != null ) {
918
- String [] tokens = StringUtils .tokenizeToStringArray (value , "," );
919
- for (String token : tokens ) {
920
- result .add (token );
921
- }
922
- }
923
- }
924
- return result ;
925
- }
926
- return Collections .emptyList ();
927
- }
928
-
929
858
/**
930
859
* Set the (new) value of the {@code If-Unmodified-Since} header.
931
860
* <p>The date should be specified as the number of milliseconds since
932
861
* January 1, 1970 GMT.
862
+ * @since 4.3
933
863
*/
934
864
public void setIfUnmodifiedSince (long ifUnmodifiedSince ) {
935
865
setDate (IF_UNMODIFIED_SINCE , ifUnmodifiedSince );
@@ -939,6 +869,7 @@ public void setIfUnmodifiedSince(long ifUnmodifiedSince) {
939
869
* Return the value of the {@code If-Unmodified-Since} header.
940
870
* <p>The date is returned as the number of milliseconds since
941
871
* January 1, 1970 GMT. Returns -1 when the date is unknown.
872
+ * @since 4.3
942
873
*/
943
874
public long getIfUnmodifiedSince () {
944
875
return getFirstDate (IF_UNMODIFIED_SINCE , false );
@@ -1054,17 +985,31 @@ public void setVary(List<String> requestHeaders) {
1054
985
1055
986
/**
1056
987
* Return the request header names subject to content negotiation.
988
+ * @since 4.3
1057
989
*/
1058
990
public List <String > getVary () {
1059
991
return getValuesAsList (VARY );
1060
992
}
1061
993
994
+ /**
995
+ * Set the given date under the given header name after formatting it as a string
996
+ * using the pattern {@code "EEE, dd MMM yyyy HH:mm:ss zzz"}. The equivalent of
997
+ * {@link #set(String, String)} but for date headers.
998
+ * @since 3.2.4
999
+ */
1000
+ public void setDate (String headerName , long date ) {
1001
+ SimpleDateFormat dateFormat = new SimpleDateFormat (DATE_FORMATS [0 ], Locale .US );
1002
+ dateFormat .setTimeZone (GMT );
1003
+ set (headerName , dateFormat .format (new Date (date )));
1004
+ }
1005
+
1062
1006
/**
1063
1007
* Parse the first header value for the given header name as a date,
1064
1008
* return -1 if there is no value, or raise {@link IllegalArgumentException}
1065
1009
* if the value cannot be parsed as a date.
1066
1010
* @param headerName the header name
1067
1011
* @return the parsed date header, or -1 if none
1012
+ * @since 3.2.4
1068
1013
*/
1069
1014
public long getFirstDate (String headerName ) {
1070
1015
return getFirstDate (headerName , true );
@@ -1109,16 +1054,92 @@ private long getFirstDate(String headerName, boolean rejectInvalid) {
1109
1054
}
1110
1055
1111
1056
/**
1112
- * Set the given date under the given header name after formatting it as a string
1113
- * using the pattern {@code "EEE, dd MMM yyyy HH:mm:ss zzz"}. The equivalent of
1114
- * {@link #set(String, String)} but for date headers.
1057
+ * Return all values of a given header name,
1058
+ * even if this header is set multiple times.
1059
+ * @param headerName the header name
1060
+ * @return all associated values
1061
+ * @since 4.3
1115
1062
*/
1116
- public void setDate (String headerName , long date ) {
1117
- SimpleDateFormat dateFormat = new SimpleDateFormat (DATE_FORMATS [0 ], Locale .US );
1118
- dateFormat .setTimeZone (GMT );
1119
- set (headerName , dateFormat .format (new Date (date )));
1063
+ public List <String > getValuesAsList (String headerName ) {
1064
+ List <String > values = get (headerName );
1065
+ if (values != null ) {
1066
+ List <String > result = new ArrayList <String >();
1067
+ for (String value : values ) {
1068
+ if (value != null ) {
1069
+ String [] tokens = StringUtils .tokenizeToStringArray (value , "," );
1070
+ for (String token : tokens ) {
1071
+ result .add (token );
1072
+ }
1073
+ }
1074
+ }
1075
+ return result ;
1076
+ }
1077
+ return Collections .emptyList ();
1078
+ }
1079
+
1080
+ /**
1081
+ * Retrieve a combined result from the field values of the ETag header.
1082
+ * @param headerName the header name
1083
+ * @return the combined result
1084
+ * @since 4.3
1085
+ */
1086
+ protected List <String > getETagValuesAsList (String headerName ) {
1087
+ List <String > values = get (headerName );
1088
+ if (values != null ) {
1089
+ List <String > result = new ArrayList <String >();
1090
+ for (String value : values ) {
1091
+ if (value != null ) {
1092
+ Matcher matcher = ETAG_HEADER_VALUE_PATTERN .matcher (value );
1093
+ while (matcher .find ()) {
1094
+ if ("*" .equals (matcher .group ())) {
1095
+ result .add (matcher .group ());
1096
+ }
1097
+ else {
1098
+ result .add (matcher .group (1 ));
1099
+ }
1100
+ }
1101
+ if (result .isEmpty ()) {
1102
+ throw new IllegalArgumentException (
1103
+ "Could not parse header '" + headerName + "' with value '" + value + "'" );
1104
+ }
1105
+ }
1106
+ }
1107
+ return result ;
1108
+ }
1109
+ return Collections .emptyList ();
1120
1110
}
1121
1111
1112
+ /**
1113
+ * Retrieve a combined result from the field values of multi-valued headers.
1114
+ * @param headerName the header name
1115
+ * @return the combined result
1116
+ * @since 4.3
1117
+ */
1118
+ protected String getFieldValues (String headerName ) {
1119
+ List <String > headerValues = get (headerName );
1120
+ return (headerValues != null ? toCommaDelimitedString (headerValues ) : null );
1121
+ }
1122
+
1123
+ /**
1124
+ * Turn the given list of header values into a comma-delimited result.
1125
+ * @param headerValues the list of header values
1126
+ * @return a combined result with comma delimitation
1127
+ */
1128
+ protected String toCommaDelimitedString (List <String > headerValues ) {
1129
+ StringBuilder builder = new StringBuilder ();
1130
+ for (Iterator <String > it = headerValues .iterator (); it .hasNext (); ) {
1131
+ String val = it .next ();
1132
+ builder .append (val );
1133
+ if (it .hasNext ()) {
1134
+ builder .append (", " );
1135
+ }
1136
+ }
1137
+ return builder .toString ();
1138
+ }
1139
+
1140
+
1141
+ // MultiValueMap implementation
1142
+
1122
1143
/**
1123
1144
* Return the first header value for the given header name, if any.
1124
1145
* @param headerName the header name
0 commit comments