Browse Source

ServletResponseHttpHeaders consistently overrides HttpHeaders again

Issue: SPR-14406
pull/1081/merge
Juergen Hoeller 9 years ago
parent
commit
15c96b8efd
  1. 187
      spring-web/src/main/java/org/springframework/http/HttpHeaders.java
  2. 13
      spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java

187
spring-web/src/main/java/org/springframework/http/HttpHeaders.java

@ -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

13
spring-web/src/test/java/org/springframework/http/server/ServletServerHttpResponseTests.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -98,4 +98,5 @@ public class ServletServerHttpResponseTests {
assertArrayEquals("Invalid content written", content, mockResponse.getContentAsByteArray());
}
}
}

Loading…
Cancel
Save