|
|
|
@ -58,6 +58,7 @@ import org.springframework.util.StringUtils;
@@ -58,6 +58,7 @@ import org.springframework.util.StringUtils;
|
|
|
|
|
* @author Arjen Poutsma |
|
|
|
|
* @author Sebastien Deleuze |
|
|
|
|
* @author Brian Clozel |
|
|
|
|
* @author Juergen Hoeller |
|
|
|
|
* @since 3.0 |
|
|
|
|
*/ |
|
|
|
|
public class HttpHeaders implements MultiValueMap<String, String>, Serializable { |
|
|
|
@ -454,7 +455,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -454,7 +455,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
* Returns the value of the {@code Access-Control-Allow-Credentials} response header. |
|
|
|
|
*/ |
|
|
|
|
public boolean getAccessControlAllowCredentials() { |
|
|
|
|
return new Boolean(getFirst(ACCESS_CONTROL_ALLOW_CREDENTIALS)); |
|
|
|
|
return Boolean.parseBoolean(getFirst(ACCESS_CONTROL_ALLOW_CREDENTIALS)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -510,22 +511,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -510,22 +511,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
return getFieldValues(ACCESS_CONTROL_ALLOW_ORIGIN); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected String getFieldValues(String headerName) { |
|
|
|
|
List<String> headerValues = this.headers.get(headerName); |
|
|
|
|
if (headerValues != null) { |
|
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
|
for (Iterator<String> iterator = headerValues.iterator(); iterator.hasNext(); ) { |
|
|
|
|
String ifNoneMatch = iterator.next(); |
|
|
|
|
builder.append(ifNoneMatch); |
|
|
|
|
if (iterator.hasNext()) { |
|
|
|
|
builder.append(", "); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return builder.toString(); |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the (new) value of the {@code Access-Control-Expose-Headers} response header. |
|
|
|
|
*/ |
|
|
|
@ -809,6 +794,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -809,6 +794,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the (new) value of the {@code If-Match} header. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public void setIfMatch(String ifMatch) { |
|
|
|
|
set(IF_MATCH, ifMatch); |
|
|
|
@ -816,55 +802,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -816,55 +802,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the (new) value of the {@code If-Match} header. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public void setIfMatch(List<String> ifMatchList) { |
|
|
|
|
set(IF_MATCH, toCommaDelimitedString(ifMatchList)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected String toCommaDelimitedString(List<String> list) { |
|
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
|
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) { |
|
|
|
|
String ifNoneMatch = iterator.next(); |
|
|
|
|
builder.append(ifNoneMatch); |
|
|
|
|
if (iterator.hasNext()) { |
|
|
|
|
builder.append(", "); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return builder.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return the value of the {@code If-Match} header. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public List<String> getIfMatch() { |
|
|
|
|
return getETagValuesAsList(IF_MATCH); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected List<String> getETagValuesAsList(String headerName) { |
|
|
|
|
List<String> values = get(headerName); |
|
|
|
|
if (values != null) { |
|
|
|
|
List<String> result = new ArrayList<String>(); |
|
|
|
|
for (String value : values) { |
|
|
|
|
if (value != null) { |
|
|
|
|
Matcher matcher = ETAG_HEADER_VALUE_PATTERN.matcher(value); |
|
|
|
|
while (matcher.find()) { |
|
|
|
|
if ("*".equals(matcher.group())) { |
|
|
|
|
result.add(matcher.group()); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
result.add(matcher.group(1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(result.size() == 0) { |
|
|
|
|
throw new IllegalArgumentException("Could not parse '" + headerName + "' value=" + value); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the (new) value of the {@code If-Modified-Since} header. |
|
|
|
|
* <p>The date should be specified as the number of milliseconds since |
|
|
|
@ -904,32 +855,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -904,32 +855,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
return getETagValuesAsList(IF_NONE_MATCH); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return all values of a given header name, |
|
|
|
|
* even if this header is set multiple times. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public List<String> getValuesAsList(String headerName) { |
|
|
|
|
List<String> values = get(headerName); |
|
|
|
|
if (values != null) { |
|
|
|
|
List<String> result = new ArrayList<String>(); |
|
|
|
|
for (String value : values) { |
|
|
|
|
if (value != null) { |
|
|
|
|
String[] tokens = StringUtils.tokenizeToStringArray(value, ","); |
|
|
|
|
for (String token : tokens) { |
|
|
|
|
result.add(token); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the (new) value of the {@code If-Unmodified-Since} header. |
|
|
|
|
* <p>The date should be specified as the number of milliseconds since |
|
|
|
|
* January 1, 1970 GMT. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public void setIfUnmodifiedSince(long ifUnmodifiedSince) { |
|
|
|
|
setDate(IF_UNMODIFIED_SINCE, ifUnmodifiedSince); |
|
|
|
@ -939,6 +869,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -939,6 +869,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
* Return the value of the {@code If-Unmodified-Since} header. |
|
|
|
|
* <p>The date is returned as the number of milliseconds since |
|
|
|
|
* January 1, 1970 GMT. Returns -1 when the date is unknown. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public long getIfUnmodifiedSince() { |
|
|
|
|
return getFirstDate(IF_UNMODIFIED_SINCE, false); |
|
|
|
@ -1054,17 +985,31 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -1054,17 +985,31 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return the request header names subject to content negotiation. |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public List<String> getVary() { |
|
|
|
|
return getValuesAsList(VARY); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the given date under the given header name after formatting it as a string |
|
|
|
|
* using the pattern {@code "EEE, dd MMM yyyy HH:mm:ss zzz"}. The equivalent of |
|
|
|
|
* {@link #set(String, String)} but for date headers. |
|
|
|
|
* @since 3.2.4 |
|
|
|
|
*/ |
|
|
|
|
public void setDate(String headerName, long date) { |
|
|
|
|
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMATS[0], Locale.US); |
|
|
|
|
dateFormat.setTimeZone(GMT); |
|
|
|
|
set(headerName, dateFormat.format(new Date(date))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Parse the first header value for the given header name as a date, |
|
|
|
|
* return -1 if there is no value, or raise {@link IllegalArgumentException} |
|
|
|
|
* if the value cannot be parsed as a date. |
|
|
|
|
* @param headerName the header name |
|
|
|
|
* @return the parsed date header, or -1 if none |
|
|
|
|
* @since 3.2.4 |
|
|
|
|
*/ |
|
|
|
|
public long getFirstDate(String headerName) { |
|
|
|
|
return getFirstDate(headerName, true); |
|
|
|
@ -1109,16 +1054,92 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@@ -1109,16 +1054,92 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the given date under the given header name after formatting it as a string |
|
|
|
|
* using the pattern {@code "EEE, dd MMM yyyy HH:mm:ss zzz"}. The equivalent of |
|
|
|
|
* {@link #set(String, String)} but for date headers. |
|
|
|
|
* Return all values of a given header name, |
|
|
|
|
* even if this header is set multiple times. |
|
|
|
|
* @param headerName the header name |
|
|
|
|
* @return all associated values |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
public void setDate(String headerName, long date) { |
|
|
|
|
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMATS[0], Locale.US); |
|
|
|
|
dateFormat.setTimeZone(GMT); |
|
|
|
|
set(headerName, dateFormat.format(new Date(date))); |
|
|
|
|
public List<String> getValuesAsList(String headerName) { |
|
|
|
|
List<String> values = get(headerName); |
|
|
|
|
if (values != null) { |
|
|
|
|
List<String> result = new ArrayList<String>(); |
|
|
|
|
for (String value : values) { |
|
|
|
|
if (value != null) { |
|
|
|
|
String[] tokens = StringUtils.tokenizeToStringArray(value, ","); |
|
|
|
|
for (String token : tokens) { |
|
|
|
|
result.add(token); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Retrieve a combined result from the field values of the ETag header. |
|
|
|
|
* @param headerName the header name |
|
|
|
|
* @return the combined result |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
protected List<String> getETagValuesAsList(String headerName) { |
|
|
|
|
List<String> values = get(headerName); |
|
|
|
|
if (values != null) { |
|
|
|
|
List<String> result = new ArrayList<String>(); |
|
|
|
|
for (String value : values) { |
|
|
|
|
if (value != null) { |
|
|
|
|
Matcher matcher = ETAG_HEADER_VALUE_PATTERN.matcher(value); |
|
|
|
|
while (matcher.find()) { |
|
|
|
|
if ("*".equals(matcher.group())) { |
|
|
|
|
result.add(matcher.group()); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
result.add(matcher.group(1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (result.isEmpty()) { |
|
|
|
|
throw new IllegalArgumentException( |
|
|
|
|
"Could not parse header '" + headerName + "' with value '" + value + "'"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
return Collections.emptyList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Retrieve a combined result from the field values of multi-valued headers. |
|
|
|
|
* @param headerName the header name |
|
|
|
|
* @return the combined result |
|
|
|
|
* @since 4.3 |
|
|
|
|
*/ |
|
|
|
|
protected String getFieldValues(String headerName) { |
|
|
|
|
List<String> headerValues = get(headerName); |
|
|
|
|
return (headerValues != null ? toCommaDelimitedString(headerValues) : null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Turn the given list of header values into a comma-delimited result. |
|
|
|
|
* @param headerValues the list of header values |
|
|
|
|
* @return a combined result with comma delimitation |
|
|
|
|
*/ |
|
|
|
|
protected String toCommaDelimitedString(List<String> headerValues) { |
|
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
|
for (Iterator<String> it = headerValues.iterator(); it.hasNext(); ) { |
|
|
|
|
String val = it.next(); |
|
|
|
|
builder.append(val); |
|
|
|
|
if (it.hasNext()) { |
|
|
|
|
builder.append(", "); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return builder.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MultiValueMap implementation
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return the first header value for the given header name, if any. |
|
|
|
|
* @param headerName the header name |
|
|
|
|