Improve Last-Modified & ETag support
Prior to this change, the `"Last-Modified"` and "`Etag`" support had been improved with SPR-11324: HTTP response headers are now automatically added for conditional requests and more. This commit fixes the format of the "`Last-Modified`" and "`ETag`" values, which were using an epoch timestamp rather than an HTTP-date format defined in RFC 7231 section 7.1.1.1. Also, Conditional responses are only applied when the given response applies, i.e. when it has an compatible HTTP status (2xx). Issue: SPR-13090
This commit is contained in:
@@ -17,16 +17,19 @@
|
||||
package org.springframework.web.context.request;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -55,6 +58,10 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
|
||||
private static final String METHOD_HEAD = "HEAD";
|
||||
|
||||
private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
||||
|
||||
private static TimeZone GMT = TimeZone.getTimeZone("GMT");
|
||||
|
||||
|
||||
private boolean notModified = false;
|
||||
|
||||
@@ -174,19 +181,33 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
public boolean checkNotModified(long lastModifiedTimestamp) {
|
||||
HttpServletResponse response = getResponse();
|
||||
if (lastModifiedTimestamp >= 0 && !this.notModified) {
|
||||
if (response == null || !response.containsHeader(HEADER_LAST_MODIFIED)) {
|
||||
if (response == null || isResponseCompatibleWithConditional(response, HEADER_LAST_MODIFIED)) {
|
||||
this.notModified = isTimeStampNotModified(lastModifiedTimestamp);
|
||||
if (response != null) {
|
||||
if (this.notModified && supportsNotModifiedStatus()) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
}
|
||||
response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
|
||||
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.notModified;
|
||||
}
|
||||
|
||||
private boolean isResponseCompatibleWithConditional(HttpServletResponse response, String... headers) {
|
||||
if (response != null) {
|
||||
if (HttpStatus.valueOf(response.getStatus()).is2xxSuccessful()) {
|
||||
for (String header : headers) {
|
||||
if (response.containsHeader(header)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean isTimeStampNotModified(long lastModifiedTimestamp) {
|
||||
long ifModifiedSince = -1;
|
||||
@@ -214,7 +235,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
public boolean checkNotModified(String etag) {
|
||||
HttpServletResponse response = getResponse();
|
||||
if (StringUtils.hasLength(etag) && !this.notModified) {
|
||||
if (response == null || !response.containsHeader(HEADER_ETAG)) {
|
||||
if (response == null || isResponseCompatibleWithConditional(response, HEADER_ETAG)) {
|
||||
etag = addEtagPadding(etag);
|
||||
this.notModified = isETagNotModified(etag);
|
||||
if (response != null) {
|
||||
@@ -244,7 +265,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
// compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3
|
||||
if (StringUtils.hasLength(clientETag) &&
|
||||
(clientETag.replaceFirst("^W/", "").equals(etag.replaceFirst("^W/", ""))
|
||||
|| clientETag.equals("*"))) {
|
||||
|| clientETag.equals("*"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -262,8 +283,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
public boolean checkNotModified(String etag, long lastModifiedTimestamp) {
|
||||
HttpServletResponse response = getResponse();
|
||||
if (StringUtils.hasLength(etag) && !this.notModified) {
|
||||
if (response == null ||
|
||||
(!response.containsHeader(HEADER_ETAG) && !response.containsHeader(HEADER_LAST_MODIFIED))) {
|
||||
if (response == null || isResponseCompatibleWithConditional(response, HEADER_ETAG, HEADER_LAST_MODIFIED)) {
|
||||
etag = addEtagPadding(etag);
|
||||
this.notModified = isETagNotModified(etag) && isTimeStampNotModified(lastModifiedTimestamp);
|
||||
if (response != null) {
|
||||
@@ -271,13 +291,19 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
}
|
||||
response.setHeader(HEADER_ETAG, etag);
|
||||
response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
|
||||
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.notModified;
|
||||
}
|
||||
|
||||
private String formatDate(long date) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
|
||||
dateFormat.setTimeZone(GMT);
|
||||
return dateFormat.format(new Date(date));
|
||||
}
|
||||
|
||||
public boolean isNotModified() {
|
||||
return this.notModified;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ public interface WebRequest extends RequestAttributes {
|
||||
* Check whether the request qualifies as not modified given the
|
||||
* supplied {@code ETag} (entity tag) and last-modified timestamp,
|
||||
* as determined by the application.
|
||||
* <p>This will also transparently set the appropriate response headers,
|
||||
* <p>This will also transparently set the "Etag" and "Last-Modified" response headers,
|
||||
* for both the modified case and the not-modified case.
|
||||
* <p>Typical usage:
|
||||
* <pre class="code">
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -42,6 +43,8 @@ import static org.junit.Assert.*;
|
||||
@RunWith(Parameterized.class)
|
||||
public class ServletWebRequestHttpMethodsTests {
|
||||
|
||||
private static final String CURRENT_TIME = "Wed, 09 Apr 2014 09:57:42 GMT";
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
|
||||
private MockHttpServletRequest servletRequest;
|
||||
@@ -50,6 +53,8 @@ public class ServletWebRequestHttpMethodsTests {
|
||||
|
||||
private ServletWebRequest request;
|
||||
|
||||
private Date currentDate;
|
||||
|
||||
@Parameter
|
||||
public String method;
|
||||
|
||||
@@ -63,33 +68,57 @@ public class ServletWebRequestHttpMethodsTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
currentDate = new Date();
|
||||
dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
servletRequest = new MockHttpServletRequest(method, "http://example.org");
|
||||
servletResponse = new MockHttpServletResponse();
|
||||
request = new ServletWebRequest(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNotModifiedTimestamp() {
|
||||
long currentTime = new Date().getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", currentTime);
|
||||
public void checkNotModifiedNon2xxStatus() {
|
||||
long epochTime = currentDate.getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", epochTime);
|
||||
servletResponse.setStatus(304);
|
||||
|
||||
assertTrue(request.checkNotModified(currentTime));
|
||||
assertFalse(request.checkNotModified(epochTime));
|
||||
assertEquals(304, servletResponse.getStatus());
|
||||
assertNull(servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNotModifiedHeaderAlreadySet() {
|
||||
long epochTime = currentDate.getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", epochTime);
|
||||
servletResponse.addHeader("Last-Modified", CURRENT_TIME);
|
||||
|
||||
assertFalse(request.checkNotModified(epochTime));
|
||||
assertEquals(200, servletResponse.getStatus());
|
||||
assertEquals(1, servletResponse.getHeaders("Last-Modified").size());
|
||||
assertEquals(CURRENT_TIME, servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNotModifiedTimestamp() throws Exception {
|
||||
long epochTime = currentDate.getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", epochTime);
|
||||
|
||||
assertTrue(request.checkNotModified(epochTime));
|
||||
|
||||
assertEquals(304, servletResponse.getStatus());
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(dateFormat.format(currentDate), servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkModifiedTimestamp() {
|
||||
long currentTime = new Date().getTime();
|
||||
long oneMinuteAgo = currentTime - (1000 * 60);
|
||||
long oneMinuteAgo = currentDate.getTime() - (1000 * 60);
|
||||
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
|
||||
|
||||
assertFalse(request.checkNotModified(currentTime));
|
||||
assertFalse(request.checkNotModified(currentDate.getTime()));
|
||||
|
||||
assertEquals(200, servletResponse.getStatus());
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(dateFormat.format(currentDate), servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -154,44 +183,43 @@ public class ServletWebRequestHttpMethodsTests {
|
||||
public void checkNotModifiedETagAndTimestamp() {
|
||||
String eTag = "\"Foo\"";
|
||||
servletRequest.addHeader("If-None-Match", eTag);
|
||||
long currentTime = new Date().getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", currentTime);
|
||||
servletRequest.addHeader("If-Modified-Since", currentDate.getTime());
|
||||
|
||||
assertTrue(request.checkNotModified(eTag, currentTime));
|
||||
assertTrue(request.checkNotModified(eTag, currentDate.getTime()));
|
||||
|
||||
assertEquals(304, servletResponse.getStatus());
|
||||
assertEquals(eTag, servletResponse.getHeader("ETag"));
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(dateFormat.format(currentDate), servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkNotModifiedETagAndModifiedTimestamp() {
|
||||
String eTag = "\"Foo\"";
|
||||
servletRequest.addHeader("If-None-Match", eTag);
|
||||
long currentTime = new Date().getTime();
|
||||
long oneMinuteAgo = currentTime - (1000 * 60);
|
||||
long currentEpoch = currentDate.getTime();
|
||||
long oneMinuteAgo = currentEpoch - (1000 * 60);
|
||||
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
|
||||
|
||||
assertFalse(request.checkNotModified(eTag, currentTime));
|
||||
assertFalse(request.checkNotModified(eTag, currentEpoch));
|
||||
|
||||
assertEquals(200, servletResponse.getStatus());
|
||||
assertEquals(eTag, servletResponse.getHeader("ETag"));
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(dateFormat.format(currentDate), servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkModifiedETagAndNotModifiedTimestamp() {
|
||||
public void checkModifiedETagAndNotModifiedTimestamp() throws Exception {
|
||||
String currentETag = "\"Foo\"";
|
||||
String oldEtag = "\"Bar\"";
|
||||
servletRequest.addHeader("If-None-Match", oldEtag);
|
||||
long currentTime = new Date().getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", currentTime);
|
||||
long epochTime = currentDate.getTime();
|
||||
servletRequest.addHeader("If-Modified-Since", epochTime);
|
||||
|
||||
assertFalse(request.checkNotModified(currentETag, currentTime));
|
||||
assertFalse(request.checkNotModified(currentETag, epochTime));
|
||||
|
||||
assertEquals(200, servletResponse.getStatus());
|
||||
assertEquals(currentETag, servletResponse.getHeader("ETag"));
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(dateFormat.format(currentDate), servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -231,26 +259,26 @@ public class ServletWebRequestHttpMethodsTests {
|
||||
|
||||
@Test
|
||||
public void checkNotModifiedTimestampWithLengthPart() throws Exception {
|
||||
long currentTime = dateFormat.parse("Wed, 09 Apr 2014 09:57:42 GMT").getTime();
|
||||
long epochTime = dateFormat.parse(CURRENT_TIME).getTime();
|
||||
servletRequest.setMethod("GET");
|
||||
servletRequest.addHeader("If-Modified-Since", "Wed, 09 Apr 2014 09:57:42 GMT; length=13774");
|
||||
|
||||
assertTrue(request.checkNotModified(currentTime));
|
||||
assertTrue(request.checkNotModified(epochTime));
|
||||
|
||||
assertEquals(304, servletResponse.getStatus());
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(CURRENT_TIME, servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkModifiedTimestampWithLengthPart() throws Exception {
|
||||
long currentTime = dateFormat.parse("Wed, 09 Apr 2014 09:57:42 GMT").getTime();
|
||||
long epochTime = dateFormat.parse(CURRENT_TIME).getTime();
|
||||
servletRequest.setMethod("GET");
|
||||
servletRequest.addHeader("If-Modified-Since", "Wed, 08 Apr 2014 09:57:42 GMT; length=13774");
|
||||
|
||||
assertFalse(request.checkNotModified(currentTime));
|
||||
assertFalse(request.checkNotModified(epochTime));
|
||||
|
||||
assertEquals(200, servletResponse.getStatus());
|
||||
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
|
||||
assertEquals(CURRENT_TIME, servletResponse.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.web.servlet.support;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
@@ -91,6 +94,8 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
|
||||
private boolean usePreviousHttpCachingBehavior = false;
|
||||
|
||||
private final SimpleDateFormat dateFormat;
|
||||
|
||||
private CacheControl cacheControl;
|
||||
|
||||
|
||||
@@ -115,6 +120,8 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
this.supportedMethods.add(METHOD_HEAD);
|
||||
this.supportedMethods.add(METHOD_POST);
|
||||
}
|
||||
dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +130,8 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
*/
|
||||
public WebContentGenerator(String... supportedMethods) {
|
||||
this.supportedMethods = new HashSet<String>(Arrays.asList(supportedMethods));
|
||||
dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
|
||||
@@ -404,7 +413,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
protected final void cacheForSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate) {
|
||||
if (this.useExpiresHeader) {
|
||||
// HTTP 1.0 header
|
||||
response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);
|
||||
response.setHeader(HEADER_EXPIRES, dateFormat.format(System.currentTimeMillis() + seconds * 1000L));
|
||||
}
|
||||
if (this.useCacheControlHeader) {
|
||||
// HTTP 1.1 header
|
||||
@@ -424,7 +433,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
response.setHeader(HEADER_PRAGMA, "no-cache");
|
||||
if (this.useExpiresHeader) {
|
||||
// HTTP 1.0 header
|
||||
response.setDateHeader(HEADER_EXPIRES, 1L);
|
||||
response.setHeader(HEADER_EXPIRES, dateFormat.format(System.currentTimeMillis()));
|
||||
}
|
||||
if (this.useCacheControlHeader) {
|
||||
// HTTP 1.1 header: "no-cache" is the standard value,
|
||||
|
||||
@@ -460,7 +460,7 @@ public class ComplexWebApplicationContext extends StaticWebApplicationContext {
|
||||
|
||||
@Override
|
||||
public long lastModified() {
|
||||
return 99;
|
||||
return 1427846401000L;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -177,7 +177,7 @@ public class DispatcherServletTests extends TestCase {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
simpleDispatcherServlet.service(request, response);
|
||||
assertTrue("Not forwarded", response.getForwardedUrl() == null);
|
||||
assertEquals("98", response.getHeader("Last-Modified"));
|
||||
assertEquals("Wed, 01 Apr 2015 00:00:00 GMT", response.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
public void testUnknownRequest() throws Exception {
|
||||
@@ -205,7 +205,7 @@ public class DispatcherServletTests extends TestCase {
|
||||
assertTrue(request.getAttribute("test3") != null);
|
||||
assertTrue(request.getAttribute("test3x") != null);
|
||||
assertTrue(request.getAttribute("test3y") != null);
|
||||
assertEquals("99", response.getHeader("Last-Modified"));
|
||||
assertEquals("Wed, 01 Apr 2015 00:00:01 GMT", response.getHeader("Last-Modified"));
|
||||
}
|
||||
|
||||
public void testExistingMultipartRequest() throws Exception {
|
||||
|
||||
@@ -90,7 +90,7 @@ public class SimpleWebApplicationContext extends StaticWebApplicationContext {
|
||||
|
||||
@Override
|
||||
public long getLastModified(HttpServletRequest request) {
|
||||
return 98;
|
||||
return 1427846400000L;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,12 @@ import static org.springframework.web.servlet.HandlerMapping.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -61,6 +64,8 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
*/
|
||||
public class HttpEntityMethodProcessorMockTests {
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
|
||||
private HttpEntityMethodProcessor processor;
|
||||
|
||||
private HttpMessageConverter<String> messageConverter;
|
||||
@@ -87,6 +92,9 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
messageConverter = mock(HttpMessageConverter.class);
|
||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
|
||||
@@ -341,7 +349,7 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.NOT_MODIFIED.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(dateFormat.format(oneMinuteAgo), servletResponse.getHeader(HttpHeaders.LAST_MODIFIED));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
@@ -385,7 +393,7 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.NOT_MODIFIED.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(dateFormat.format(oneMinuteAgo), servletResponse.getHeader(HttpHeaders.LAST_MODIFIED));
|
||||
assertEquals(etagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
@@ -411,7 +419,7 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.OK.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(dateFormat.format(oneMinuteAgo), servletResponse.getHeader(HttpHeaders.LAST_MODIFIED));
|
||||
assertEquals(changedEtagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
@@ -23,9 +23,13 @@ import static org.mockito.Mockito.*;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -52,6 +56,8 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
*/
|
||||
public class ResourceHttpRequestHandlerTests {
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
|
||||
private ResourceHttpRequestHandler handler;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
@@ -61,6 +67,9 @@ public class ResourceHttpRequestHandlerTests {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
List<Resource> paths = new ArrayList<>(2);
|
||||
paths.add(new ClassPathResource("test/", getClass()));
|
||||
paths.add(new ClassPathResource("testalternatepath/", getClass()));
|
||||
@@ -127,7 +136,7 @@ public class ResourceHttpRequestHandlerTests {
|
||||
|
||||
assertEquals("no-cache", this.response.getHeader("Pragma"));
|
||||
assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.contains("no-cache", "no-store"));
|
||||
assertTrue(headerAsLong("Expires") == 1);
|
||||
assertEquals(this.response.getHeaderValue("Expires"), dateFormat.format(System.currentTimeMillis()));
|
||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||
assertEquals(headerAsLong("Last-Modified"), resourceLastModified("test/foo.css"));
|
||||
}
|
||||
@@ -467,8 +476,8 @@ public class ResourceHttpRequestHandlerTests {
|
||||
}
|
||||
|
||||
|
||||
private long headerAsLong(String responseHeaderName) {
|
||||
return Long.valueOf(this.response.getHeader(responseHeaderName));
|
||||
private long headerAsLong(String responseHeaderName) throws Exception {
|
||||
return dateFormat.parse(this.response.getHeader(responseHeaderName)).getTime();
|
||||
}
|
||||
|
||||
private long resourceLastModified(String resourceName) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user