Handle multiple conditional request headers
Prior to this change, setting both "If-None-Match" and "If-Unmodified-Since" conditional request headers would check for both conditions to be met. This commit fixes this behavior to follow the RFC7232 Section 6: > entity tags are presumed to be more accurate than date validators So in case both conditions are present, the "If-None-Match" condition takes precedence. Issue: SPR-14224
This commit is contained in:
@@ -237,7 +237,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
|||||||
if (StringUtils.hasLength(etag) && !this.notModified) {
|
if (StringUtils.hasLength(etag) && !this.notModified) {
|
||||||
if (isCompatibleWithConditionalRequests(response)) {
|
if (isCompatibleWithConditionalRequests(response)) {
|
||||||
etag = addEtagPadding(etag);
|
etag = addEtagPadding(etag);
|
||||||
this.notModified = isEtagNotModified(etag) && isTimestampNotModified(lastModifiedTimestamp);
|
if (hasRequestHeader(HEADER_IF_NONE_MATCH)) {
|
||||||
|
this.notModified = isEtagNotModified(etag);
|
||||||
|
}
|
||||||
|
else if (hasRequestHeader(HEADER_IF_MODIFIED_SINCE)) {
|
||||||
|
this.notModified = isTimestampNotModified(lastModifiedTimestamp);
|
||||||
|
}
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
if (supportsNotModifiedStatus()) {
|
if (supportsNotModifiedStatus()) {
|
||||||
if (this.notModified) {
|
if (this.notModified) {
|
||||||
@@ -287,6 +292,10 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
|||||||
return (response.getHeader(header) == null);
|
return (response.getHeader(header) == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasRequestHeader(String headerName) {
|
||||||
|
return StringUtils.hasLength(getHeader(headerName));
|
||||||
|
}
|
||||||
|
|
||||||
private boolean supportsNotModifiedStatus() {
|
private boolean supportsNotModifiedStatus() {
|
||||||
String method = getRequest().getMethod();
|
String method = getRequest().getMethod();
|
||||||
return (METHOD_GET.equals(method) || METHOD_HEAD.equals(method));
|
return (METHOD_GET.equals(method) || METHOD_HEAD.equals(method));
|
||||||
@@ -294,9 +303,8 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
|||||||
|
|
||||||
private boolean supportsConditionalUpdate() {
|
private boolean supportsConditionalUpdate() {
|
||||||
String method = getRequest().getMethod();
|
String method = getRequest().getMethod();
|
||||||
String ifUnmodifiedHeader = getRequest().getHeader(HEADER_IF_UNMODIFIED_SINCE);
|
|
||||||
return (METHOD_POST.equals(method) || METHOD_PUT.equals(method) || METHOD_DELETE.equals(method))
|
return (METHOD_POST.equals(method) || METHOD_PUT.equals(method) || METHOD_DELETE.equals(method))
|
||||||
&& StringUtils.hasLength(ifUnmodifiedHeader);
|
&& hasRequestHeader(HEADER_IF_UNMODIFIED_SINCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTimestampNotModified(long lastModifiedTimestamp) {
|
private boolean isTimestampNotModified(long lastModifiedTimestamp) {
|
||||||
@@ -318,7 +326,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
|||||||
dateValue = getRequest().getDateHeader(headerName);
|
dateValue = getRequest().getDateHeader(headerName);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
String headerValue = getRequest().getHeader(headerName);
|
String headerValue = getHeader(headerName);
|
||||||
// Possibly an IE 10 style value: "Wed, 09 Apr 2014 09:57:42 GMT; length=13774"
|
// Possibly an IE 10 style value: "Wed, 09 Apr 2014 09:57:42 GMT; length=13774"
|
||||||
int separatorIndex = headerValue.indexOf(';');
|
int separatorIndex = headerValue.indexOf(';');
|
||||||
if (separatorIndex != -1) {
|
if (separatorIndex != -1) {
|
||||||
@@ -336,7 +344,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
|
|||||||
|
|
||||||
private boolean isEtagNotModified(String etag) {
|
private boolean isEtagNotModified(String etag) {
|
||||||
if (StringUtils.hasLength(etag)) {
|
if (StringUtils.hasLength(etag)) {
|
||||||
String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH);
|
String ifNoneMatch = getHeader(HEADER_IF_NONE_MATCH);
|
||||||
if (StringUtils.hasLength(ifNoneMatch)) {
|
if (StringUtils.hasLength(ifNoneMatch)) {
|
||||||
String[] clientEtags = StringUtils.delimitedListToStringArray(ifNoneMatch, ",", " ");
|
String[] clientEtags = StringUtils.delimitedListToStringArray(ifNoneMatch, ",", " ");
|
||||||
for (String clientEtag : clientEtags) {
|
for (String clientEtag : clientEtags) {
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ public class ServletWebRequestHttpMethodsTests {
|
|||||||
assertEquals(dateFormat.format(currentDate.getTime()), servletResponse.getHeader("Last-Modified"));
|
assertEquals(dateFormat.format(currentDate.getTime()), servletResponse.getHeader("Last-Modified"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SPR-14224
|
||||||
@Test
|
@Test
|
||||||
public void checkNotModifiedETagAndModifiedTimestamp() {
|
public void checkNotModifiedETagAndModifiedTimestamp() {
|
||||||
String eTag = "\"Foo\"";
|
String eTag = "\"Foo\"";
|
||||||
@@ -212,9 +213,9 @@ public class ServletWebRequestHttpMethodsTests {
|
|||||||
long oneMinuteAgo = currentEpoch - (1000 * 60);
|
long oneMinuteAgo = currentEpoch - (1000 * 60);
|
||||||
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
|
servletRequest.addHeader("If-Modified-Since", oneMinuteAgo);
|
||||||
|
|
||||||
assertFalse(request.checkNotModified(eTag, currentEpoch));
|
assertTrue(request.checkNotModified(eTag, currentEpoch));
|
||||||
|
|
||||||
assertEquals(200, servletResponse.getStatus());
|
assertEquals(304, servletResponse.getStatus());
|
||||||
assertEquals(eTag, servletResponse.getHeader("ETag"));
|
assertEquals(eTag, servletResponse.getHeader("ETag"));
|
||||||
assertEquals(dateFormat.format(currentEpoch), servletResponse.getHeader("Last-Modified"));
|
assertEquals(dateFormat.format(currentEpoch), servletResponse.getHeader("Last-Modified"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user