ServletResponseHttpHeaders consistently overrides HttpHeaders again
Issue: SPR-14406
This commit is contained in:
parent
ea5baeb05a
commit
15c96b8efd
|
@ -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
|
|||
* 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
|
|||
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
|
|||
|
||||
/**
|
||||
* 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
|
|||
|
||||
/**
|
||||
* 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
|
|||
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
|
|||
* 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
|
|||
|
||||
/**
|
||||
* 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
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,13 +29,12 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ServletServerHttpResponseTests {
|
||||
|
||||
|
@ -79,7 +78,6 @@ public class ServletServerHttpResponseTests {
|
|||
|
||||
@Test
|
||||
public void preExistingHeadersFromHttpServletResponse() {
|
||||
|
||||
String headerName = "Access-Control-Allow-Origin";
|
||||
String headerValue = "localhost:8080";
|
||||
|
||||
|
@ -89,6 +87,8 @@ public class ServletServerHttpResponseTests {
|
|||
assertEquals(headerValue, this.response.getHeaders().getFirst(headerName));
|
||||
assertEquals(Collections.singletonList(headerValue), this.response.getHeaders().get(headerName));
|
||||
assertTrue(this.response.getHeaders().containsKey(headerName));
|
||||
assertEquals(headerValue, this.response.getHeaders().getFirst(headerName));
|
||||
assertEquals(headerValue, this.response.getHeaders().getAccessControlAllowOrigin());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,4 +98,5 @@ public class ServletServerHttpResponseTests {
|
|||
|
||||
assertArrayEquals("Invalid content written", content, mockResponse.getContentAsByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue