Add support for setting the "Vary" response header
Issue: SPR-14070
This commit is contained in:
@@ -38,6 +38,7 @@ import java.util.TimeZone;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -947,6 +948,24 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||||||
return getFirst(UPGRADE);
|
return getFirst(UPGRADE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request header names (e.g. "Accept-Language") for which the
|
||||||
|
* response is subject to content negotiation and variances based on the
|
||||||
|
* value of those request headers.
|
||||||
|
* @param requestHeaders the request header names
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public void setVary(List<String> requestHeaders) {
|
||||||
|
set(VARY, toCommaDelimitedString(requestHeaders));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the request header names subject to content negotiation.
|
||||||
|
*/
|
||||||
|
public List<String> getVary() {
|
||||||
|
return getFirstValueAsList(VARY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the first header value for the given header name as a 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}
|
* return -1 if there is no value, or raise {@link IllegalArgumentException}
|
||||||
|
|||||||
@@ -332,6 +332,17 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
|||||||
*/
|
*/
|
||||||
B cacheControl(CacheControl cacheControl);
|
B cacheControl(CacheControl cacheControl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure one or more request header names (e.g. "Accept-Language") to
|
||||||
|
* add to the "Vary" response header to inform clients that the response is
|
||||||
|
* subject to content negotiation and variances based on the value of the
|
||||||
|
* given request headers. The configured request header names are added only
|
||||||
|
* if not already present in the response "Vary" header.
|
||||||
|
* @param requestHeaders request header names
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
B varyBy(String... requestHeaders);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the response entity with no body.
|
* Build the response entity with no body.
|
||||||
* @return the response entity
|
* @return the response entity
|
||||||
@@ -454,6 +465,12 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BodyBuilder varyBy(String... requestHeaders) {
|
||||||
|
this.headers.setVary(Arrays.asList(requestHeaders));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<Void> build() {
|
public ResponseEntity<Void> build() {
|
||||||
return new ResponseEntity<Void>(null, this.headers, this.status);
|
return new ResponseEntity<Void>(null, this.headers, this.status);
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
@@ -40,6 +43,8 @@ import org.springframework.web.bind.support.WebDataBinderFactory;
|
|||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
|
||||||
|
import static org.springframework.http.HttpHeaders.VARY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves {@link HttpEntity} and {@link RequestEntity} method argument values
|
* Resolves {@link HttpEntity} and {@link RequestEntity} method argument values
|
||||||
* and also handles {@link HttpEntity} and {@link ResponseEntity} return values.
|
* and also handles {@link HttpEntity} and {@link ResponseEntity} return values.
|
||||||
@@ -162,9 +167,18 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||||||
Assert.isInstanceOf(HttpEntity.class, returnValue);
|
Assert.isInstanceOf(HttpEntity.class, returnValue);
|
||||||
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
|
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
|
||||||
|
|
||||||
|
HttpHeaders outputHeaders = outputMessage.getHeaders();
|
||||||
HttpHeaders entityHeaders = responseEntity.getHeaders();
|
HttpHeaders entityHeaders = responseEntity.getHeaders();
|
||||||
|
if (outputHeaders.containsKey(VARY) && entityHeaders.containsKey(VARY)) {
|
||||||
|
List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
outputHeaders.setVary(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!entityHeaders.isEmpty()) {
|
if (!entityHeaders.isEmpty()) {
|
||||||
outputMessage.getHeaders().putAll(entityHeaders);
|
for (Map.Entry<String, List<String>> entry : entityHeaders.entrySet()) {
|
||||||
|
outputHeaders.putIfAbsent(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object body = responseEntity.getBody();
|
Object body = responseEntity.getBody();
|
||||||
@@ -188,6 +202,27 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||||||
outputMessage.flush();
|
outputMessage.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getVaryRequestHeadersToAdd(HttpHeaders responseHeaders, HttpHeaders entityHeaders) {
|
||||||
|
if (!responseHeaders.containsKey(HttpHeaders.VARY)) {
|
||||||
|
return entityHeaders.getVary();
|
||||||
|
}
|
||||||
|
List<String> entityHeadersVary = entityHeaders.getVary();
|
||||||
|
List<String> result = new ArrayList<String>(entityHeadersVary);
|
||||||
|
for (String header : responseHeaders.get(HttpHeaders.VARY)) {
|
||||||
|
for (String existing : StringUtils.tokenizeToStringArray(header, ",")) {
|
||||||
|
if ("*".equals(existing)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
for (String value : entityHeadersVary) {
|
||||||
|
if (value.equalsIgnoreCase(existing)) {
|
||||||
|
result.remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isResourceNotModified(ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
|
private boolean isResourceNotModified(ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
|
||||||
List<String> ifNoneMatch = inputMessage.getHeaders().getIfNoneMatch();
|
List<String> ifNoneMatch = inputMessage.getHeaders().getIfNoneMatch();
|
||||||
long ifModifiedSince = inputMessage.getHeaders().getIfModifiedSince();
|
long ifModifiedSince = inputMessage.getHeaders().getIfModifiedSince();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.springframework.web.servlet.support;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -27,7 +28,9 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.http.CacheControl;
|
import org.springframework.http.CacheControl;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
@@ -77,6 +80,10 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||||||
|
|
||||||
protected static final String HEADER_CACHE_CONTROL = "Cache-Control";
|
protected static final String HEADER_CACHE_CONTROL = "Cache-Control";
|
||||||
|
|
||||||
|
/** Checking for Servlet 3.0+ HttpServletResponse.getHeaders(String) */
|
||||||
|
private static final boolean servlet3Present =
|
||||||
|
ClassUtils.hasMethod(HttpServletResponse.class, "getHeaders", String.class);
|
||||||
|
|
||||||
|
|
||||||
/** Set of supported HTTP methods */
|
/** Set of supported HTTP methods */
|
||||||
private Set<String> supportedMethods;
|
private Set<String> supportedMethods;
|
||||||
@@ -89,6 +96,11 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||||||
|
|
||||||
private int cacheSeconds = -1;
|
private int cacheSeconds = -1;
|
||||||
|
|
||||||
|
private String[] varyByRequestHeaders;
|
||||||
|
|
||||||
|
|
||||||
|
// deprecated fields
|
||||||
|
|
||||||
/** Use HTTP 1.0 expires header? */
|
/** Use HTTP 1.0 expires header? */
|
||||||
private boolean useExpiresHeader = false;
|
private boolean useExpiresHeader = false;
|
||||||
|
|
||||||
@@ -245,6 +257,29 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||||||
return this.cacheSeconds;
|
return this.cacheSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure one or more request header names (e.g. "Accept-Language") to
|
||||||
|
* add to the "Vary" response header to inform clients that the response is
|
||||||
|
* subject to content negotiation and variances based on the value of the
|
||||||
|
* given request headers. The configured request header names are added only
|
||||||
|
* if not already present in the response "Vary" header.
|
||||||
|
*
|
||||||
|
* <p><strong>Note:</strong> this property is only supported on Servlet 3.0+
|
||||||
|
* which allows checking existing response header values.
|
||||||
|
* @param varyByRequestHeaders one or more request header names
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public void setVaryByRequestHeaders(String... varyByRequestHeaders) {
|
||||||
|
this.varyByRequestHeaders = varyByRequestHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured request header names for the "Vary" response header.
|
||||||
|
*/
|
||||||
|
public String[] getVaryByRequestHeaders() {
|
||||||
|
return this.varyByRequestHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether to use the HTTP 1.0 expires header. Default is "false",
|
* Set whether to use the HTTP 1.0 expires header. Default is "false",
|
||||||
* as of 4.2.
|
* as of 4.2.
|
||||||
@@ -363,6 +398,11 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||||||
else {
|
else {
|
||||||
applyCacheSeconds(response, this.cacheSeconds);
|
applyCacheSeconds(response, this.cacheSeconds);
|
||||||
}
|
}
|
||||||
|
if (servlet3Present && this.varyByRequestHeaders != null) {
|
||||||
|
for (String value : getVaryRequestHeadersToAdd(response)) {
|
||||||
|
response.addHeader("Vary", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -546,4 +586,25 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<String> getVaryRequestHeadersToAdd(HttpServletResponse response) {
|
||||||
|
if (!response.containsHeader(HttpHeaders.VARY)) {
|
||||||
|
return Arrays.asList(getVaryByRequestHeaders());
|
||||||
|
}
|
||||||
|
Collection<String> result = new ArrayList<String>(getVaryByRequestHeaders().length);
|
||||||
|
Collections.addAll(result, getVaryByRequestHeaders());
|
||||||
|
for (String header : response.getHeaders(HttpHeaders.VARY)) {
|
||||||
|
for (String existing : StringUtils.tokenizeToStringArray(header, ",")) {
|
||||||
|
if ("*".equals(existing)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
for (String value : getVaryByRequestHeaders()) {
|
||||||
|
if (value.equalsIgnoreCase(existing)) {
|
||||||
|
result.remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.net.URI;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -517,6 +518,47 @@ public class HttpEntityMethodProcessorMockTests {
|
|||||||
assertEquals(etagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
assertEquals(etagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeader() throws Exception {
|
||||||
|
String[] entityValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] existingValues = {};
|
||||||
|
String[] expected = {"Accept-Language, User-Agent"};
|
||||||
|
testVaryHeader(entityValues, existingValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingWildcard() throws Exception {
|
||||||
|
String[] entityValues = {"Accept-Language"};
|
||||||
|
String[] existingValues = {"*"};
|
||||||
|
String[] expected = {"*"};
|
||||||
|
testVaryHeader(entityValues, existingValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingCommaValues() throws Exception {
|
||||||
|
String[] entityValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] existingValues = {"Accept-Encoding", "Accept-Language"};
|
||||||
|
String[] expected = {"Accept-Encoding", "Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(entityValues, existingValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingCommaSeparatedValues() throws Exception {
|
||||||
|
String[] entityValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] existingValues = {"Accept-Encoding, Accept-Language"};
|
||||||
|
String[] expected = {"Accept-Encoding, Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(entityValues, existingValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handleReturnValueVaryHeader() throws Exception {
|
||||||
|
String[] entityValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] existingValues = {"Accept-Encoding, Accept-Language"};
|
||||||
|
String[] expected = {"Accept-Encoding, Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(entityValues, existingValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initStringMessageConversion(MediaType accepted) {
|
private void initStringMessageConversion(MediaType accepted) {
|
||||||
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
||||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||||
@@ -536,6 +578,20 @@ public class HttpEntityMethodProcessorMockTests {
|
|||||||
verify(messageConverter).write(eq(body), eq(MediaType.TEXT_PLAIN), outputMessage.capture());
|
verify(messageConverter).write(eq(body), eq(MediaType.TEXT_PLAIN), outputMessage.capture());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void testVaryHeader(String[] entityValues, String[] existingValues, String[] expected) throws Exception {
|
||||||
|
ResponseEntity<String> returnValue = ResponseEntity.ok().varyBy(entityValues).body("Foo");
|
||||||
|
for (String value : existingValues) {
|
||||||
|
servletResponse.addHeader("Vary", value);
|
||||||
|
}
|
||||||
|
initStringMessageConversion(MediaType.TEXT_PLAIN);
|
||||||
|
processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
|
||||||
|
|
||||||
|
assertTrue(mavContainer.isRequestHandled());
|
||||||
|
assertEquals(Arrays.asList(expected), servletResponse.getHeaders("Vary"));
|
||||||
|
verify(messageConverter).write(eq("Foo"), eq(MediaType.TEXT_PLAIN), isA(HttpOutputMessage.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public ResponseEntity<String> handle1(HttpEntity<String> httpEntity, ResponseEntity<String> entity,
|
public ResponseEntity<String> handle1(HttpEntity<String> httpEntity, ResponseEntity<String> entity,
|
||||||
int i, RequestEntity<String> requestEntity) {
|
int i, RequestEntity<String> requestEntity) {
|
||||||
|
|||||||
@@ -15,9 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.web.servlet.support;
|
package org.springframework.web.servlet.support;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link WebContentGenerator}.
|
* Unit tests for {@link WebContentGenerator}.
|
||||||
@@ -25,7 +30,6 @@ import static org.junit.Assert.assertEquals;
|
|||||||
*/
|
*/
|
||||||
public class WebContentGeneratorTests {
|
public class WebContentGeneratorTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllowHeaderWithConstructorTrue() throws Exception {
|
public void getAllowHeaderWithConstructorTrue() throws Exception {
|
||||||
WebContentGenerator generator = new TestWebContentGenerator(true);
|
WebContentGenerator generator = new TestWebContentGenerator(true);
|
||||||
@@ -59,6 +63,58 @@ public class WebContentGeneratorTests {
|
|||||||
"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS", generator.getAllowHeader());
|
"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS", generator.getAllowHeader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderNone() throws Exception {
|
||||||
|
WebContentGenerator generator = new TestWebContentGenerator();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
generator.prepareResponse(response);
|
||||||
|
|
||||||
|
assertNull(response.getHeader("Vary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeader() throws Exception {
|
||||||
|
String[] configuredValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] responseValues = {};
|
||||||
|
String[] expected = {"Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(configuredValues, responseValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingWildcard() throws Exception {
|
||||||
|
String[] configuredValues = {"Accept-Language"};
|
||||||
|
String[] responseValues = {"*"};
|
||||||
|
String[] expected = {"*"};
|
||||||
|
testVaryHeader(configuredValues, responseValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingCommaValues() throws Exception {
|
||||||
|
String[] configuredValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] responseValues = {"Accept-Encoding", "Accept-Language"};
|
||||||
|
String[] expected = {"Accept-Encoding", "Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(configuredValues, responseValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void varyHeaderWithExistingCommaSeparatedValues() throws Exception {
|
||||||
|
String[] configuredValues = {"Accept-Language", "User-Agent"};
|
||||||
|
String[] responseValues = {"Accept-Encoding, Accept-Language"};
|
||||||
|
String[] expected = {"Accept-Encoding, Accept-Language", "User-Agent"};
|
||||||
|
testVaryHeader(configuredValues, responseValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testVaryHeader(String[] configuredValues, String[] responseValues, String[] expected) {
|
||||||
|
WebContentGenerator generator = new TestWebContentGenerator();
|
||||||
|
generator.setVaryByRequestHeaders(configuredValues);
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
for (String value : responseValues) {
|
||||||
|
response.addHeader("Vary", value);
|
||||||
|
}
|
||||||
|
generator.prepareResponse(response);
|
||||||
|
assertEquals(Arrays.asList(expected), response.getHeaderValues("Vary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class TestWebContentGenerator extends WebContentGenerator {
|
private static class TestWebContentGenerator extends WebContentGenerator {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user