提交 794e859e 编写于 作者: J Juergen Hoeller

checkNotModified leniently handles IE-10-style If-Modified-Since values and...

checkNotModified leniently handles IE-10-style If-Modified-Since values and silently proceeds if header value cannot be parsed at all

Issue: SPR-11727
上级 5b478161
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.web.context.request; package org.springframework.web.context.request;
import java.security.Principal; import java.security.Principal;
import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
...@@ -103,6 +104,14 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ ...@@ -103,6 +104,14 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
} }
/**
* Return the HTTP method of the request.
* @since 4.0.2
*/
public HttpMethod getHttpMethod() {
return HttpMethod.valueOf(getRequest().getMethod().trim().toUpperCase());
}
@Override @Override
public String getHeader(String headerName) { public String getHeader(String headerName) {
return getRequest().getHeader(headerName); return getRequest().getHeader(headerName);
...@@ -170,10 +179,28 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ ...@@ -170,10 +179,28 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
} }
@Override @Override
@SuppressWarnings("deprecation")
public boolean checkNotModified(long lastModifiedTimestamp) { public boolean checkNotModified(long lastModifiedTimestamp) {
if (lastModifiedTimestamp >= 0 && !this.notModified && if (lastModifiedTimestamp >= 0 && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) { (this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE); long ifModifiedSince = -1;
try {
ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
}
catch (IllegalArgumentException ex) {
String headerValue = getRequest().getHeader(HEADER_IF_MODIFIED_SINCE);
// Possibly an IE 10 style value: "Wed, 09 Apr 2014 09:57:42 GMT; length=13774"
int separatorIndex = headerValue.indexOf(';');
if (separatorIndex != -1) {
String datePart = headerValue.substring(0, separatorIndex);
try {
ifModifiedSince = Date.parse(datePart);
}
catch (IllegalArgumentException ex2) {
// Giving up
}
}
}
this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000)); this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
if (this.response != null) { if (this.response != null) {
if (this.notModified && supportsNotModifiedStatus()) { if (this.notModified && supportsNotModifiedStatus()) {
...@@ -188,17 +215,17 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ ...@@ -188,17 +215,17 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
} }
@Override @Override
public boolean checkNotModified(String eTag) { public boolean checkNotModified(String etag) {
if (StringUtils.hasLength(eTag) && !this.notModified && if (StringUtils.hasLength(etag) && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_ETAG))) { (this.response == null || !this.response.containsHeader(HEADER_ETAG))) {
String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH); String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH);
this.notModified = eTag.equals(ifNoneMatch); this.notModified = etag.equals(ifNoneMatch);
if (this.response != null) { if (this.response != null) {
if (this.notModified && supportsNotModifiedStatus()) { if (this.notModified && supportsNotModifiedStatus()) {
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
} }
else { else {
this.response.setHeader(HEADER_ETAG, eTag); this.response.setHeader(HEADER_ETAG, etag);
} }
} }
} }
...@@ -236,14 +263,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ ...@@ -236,14 +263,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
return sb.toString(); return sb.toString();
} }
/**
* Return the HTTP method of the request.
* @since 4.0.2
*/
public HttpMethod getHttpMethod() {
return HttpMethod.valueOf(getRequest().getMethod().trim().toUpperCase());
}
@Override @Override
public String toString() { public String toString() {
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -142,8 +142,11 @@ public interface WebRequest extends RequestAttributes { ...@@ -142,8 +142,11 @@ public interface WebRequest extends RequestAttributes {
* return "myViewName"; * return "myViewName";
* }</pre> * }</pre>
* <p><strong>Note:</strong> that you typically want to use either * <p><strong>Note:</strong> that you typically want to use either
* this {@link #checkNotModified(long)} method; or * this {@code #checkNotModified(long)} method; or
* {@link #checkNotModified(String)}, but not both. * {@link #checkNotModified(String)}, but not both.
* <p>If the "If-Modified-Since" header is set but cannot be parsed
* to a date value, this method will ignore the header and proceed
* with setting the last-modified timestamp on the response.
* @param lastModifiedTimestamp the last-modified timestamp that * @param lastModifiedTimestamp the last-modified timestamp that
* the application determined for the underlying resource * the application determined for the underlying resource
* @return whether the request qualifies as not modified, * @return whether the request qualifies as not modified,
...@@ -170,16 +173,16 @@ public interface WebRequest extends RequestAttributes { ...@@ -170,16 +173,16 @@ public interface WebRequest extends RequestAttributes {
* return "myViewName"; * return "myViewName";
* }</pre> * }</pre>
* <p><strong>Note:</strong> that you typically want to use either * <p><strong>Note:</strong> that you typically want to use either
* this {@link #checkNotModified(String)} method; or * this {@code #checkNotModified(String)} method; or
* {@link #checkNotModified(long)}, but not both. * {@link #checkNotModified(long)}, but not both.
* @param eTag the entity tag that the application determined * @param etag the entity tag that the application determined
* for the underlying resource. This parameter will be padded * for the underlying resource. This parameter will be padded
* with quotes (") if necessary. * with quotes (") if necessary.
* @return whether the request qualifies as not modified, * @return whether the request qualifies as not modified,
* allowing to abort request processing and relying on the response * allowing to abort request processing and relying on the response
* telling the client that the content has not been modified * telling the client that the content has not been modified
*/ */
boolean checkNotModified(String eTag); boolean checkNotModified(String etag);
/** /**
* Get a short description of this request, * Get a short description of this request,
......
...@@ -19,7 +19,6 @@ package org.springframework.web.context.request; ...@@ -19,7 +19,6 @@ package org.springframework.web.context.request;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -118,75 +117,90 @@ public class ServletWebRequestTests { ...@@ -118,75 +117,90 @@ public class ServletWebRequestTests {
} }
@Test @Test
public void checkNotModifiedTimeStampForGET() { public void checkNotModifiedTimestampForGET() {
long currentTime = new Date().getTime(); long currentTime = new Date().getTime();
servletRequest.setMethod("GET"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-Modified-Since", currentTime); servletRequest.addHeader("If-Modified-Since", currentTime);
request.checkNotModified(currentTime); assertTrue(request.checkNotModified(currentTime));
assertEquals(304, servletResponse.getStatus()); assertEquals(304, servletResponse.getStatus());
} }
@Test @Test
public void checkModifiedTimeStampForGET() { public void checkModifiedTimestampForGET() {
long currentTime = new Date().getTime(); long currentTime = new Date().getTime();
long oneMinuteAgo = currentTime - (1000 * 60); long oneMinuteAgo = currentTime - (1000 * 60);
servletRequest.setMethod("GET"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
request.checkNotModified(currentTime); assertFalse(request.checkNotModified(currentTime));
assertEquals(200, servletResponse.getStatus());
assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
}
@Test
public void checkNotModifiedTimestampForHEAD() {
long currentTime = new Date().getTime();
servletRequest.setMethod("HEAD");
servletRequest.addHeader("If-Modified-Since", currentTime);
assertTrue(request.checkNotModified(currentTime));
assertEquals(304, servletResponse.getStatus());
}
@Test
public void checkModifiedTimestampForHEAD() {
long currentTime = new Date().getTime();
long oneMinuteAgo = currentTime - (1000 * 60);
servletRequest.setMethod("HEAD");
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
assertFalse(request.checkNotModified(currentTime));
assertEquals(200, servletResponse.getStatus()); assertEquals(200, servletResponse.getStatus());
assertEquals(""+currentTime, servletResponse.getHeader("Last-Modified")); assertEquals(""+currentTime, servletResponse.getHeader("Last-Modified"));
} }
@Test @Test
public void checkNotModifiedETagForGET() { public void checkNotModifiedTimestampWithLengthPart() {
String eTag = "\"Foo\""; long currentTime = Date.parse("Wed, 09 Apr 2014 09:57:42 GMT");
servletRequest.setMethod("GET"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-None-Match", eTag ); servletRequest.addHeader("If-Modified-Since", "Wed, 09 Apr 2014 09:57:42 GMT; length=13774");
request.checkNotModified(eTag);
assertTrue(request.checkNotModified(currentTime));
assertEquals(304, servletResponse.getStatus()); assertEquals(304, servletResponse.getStatus());
} }
@Test @Test
public void checkModifiedETagForGET() { public void checkModifiedTimestampWithLengthPart() {
String currentETag = "\"Foo\""; long currentTime = Date.parse("Wed, 09 Apr 2014 09:57:42 GMT");
String oldEtag = "Bar";
servletRequest.setMethod("GET"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-None-Match", oldEtag); servletRequest.addHeader("If-Modified-Since", "Wed, 08 Apr 2014 09:57:42 GMT; length=13774");
request.checkNotModified(currentETag);
assertFalse(request.checkNotModified(currentTime));
assertEquals(200, servletResponse.getStatus()); assertEquals(200, servletResponse.getStatus());
assertEquals(currentETag, servletResponse.getHeader("ETag")); assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified"));
} }
@Test @Test
public void checkNotModifiedTimeStampForHEAD() { public void checkNotModifiedETagForGET() {
long currentTime = new Date().getTime(); String eTag = "\"Foo\"";
servletRequest.setMethod("HEAD"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-Modified-Since", currentTime); servletRequest.addHeader("If-None-Match", eTag );
request.checkNotModified(currentTime);
assertTrue(request.checkNotModified(eTag));
assertEquals(304, servletResponse.getStatus()); assertEquals(304, servletResponse.getStatus());
} }
@Test @Test
public void checkModifiedTimeStampForHEAD() { public void checkModifiedETagForGET() {
long currentTime = new Date().getTime(); String currentETag = "\"Foo\"";
long oneMinuteAgo = currentTime - (1000 * 60); String oldEtag = "Bar";
servletRequest.setMethod("HEAD"); servletRequest.setMethod("GET");
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); servletRequest.addHeader("If-None-Match", oldEtag);
request.checkNotModified(currentTime);
assertFalse(request.checkNotModified(currentETag));
assertEquals(200, servletResponse.getStatus()); assertEquals(200, servletResponse.getStatus());
assertEquals(""+currentTime, servletResponse.getHeader("Last-Modified")); assertEquals(currentETag, servletResponse.getHeader("ETag"));
} }
@Test @Test
...@@ -195,8 +209,7 @@ public class ServletWebRequestTests { ...@@ -195,8 +209,7 @@ public class ServletWebRequestTests {
servletRequest.setMethod("HEAD"); servletRequest.setMethod("HEAD");
servletRequest.addHeader("If-None-Match", eTag ); servletRequest.addHeader("If-None-Match", eTag );
request.checkNotModified(eTag); assertTrue(request.checkNotModified(eTag));
assertEquals(304, servletResponse.getStatus()); assertEquals(304, servletResponse.getStatus());
} }
...@@ -207,8 +220,7 @@ public class ServletWebRequestTests { ...@@ -207,8 +220,7 @@ public class ServletWebRequestTests {
servletRequest.setMethod("HEAD"); servletRequest.setMethod("HEAD");
servletRequest.addHeader("If-None-Match", oldEtag); servletRequest.addHeader("If-None-Match", oldEtag);
request.checkNotModified(currentETag); assertFalse(request.checkNotModified(currentETag));
assertEquals(200, servletResponse.getStatus()); assertEquals(200, servletResponse.getStatus());
assertEquals(currentETag, servletResponse.getHeader("ETag")); assertEquals(currentETag, servletResponse.getHeader("ETag"));
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册