From a50ea80e4e5ebb6e656737a6a32967967563eaa4 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 27 Apr 2016 12:02:33 +0200 Subject: [PATCH] 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 --- .../web/context/request/ServletWebRequest.java | 18 +++++++++++++----- .../ServletWebRequestHttpMethodsTests.java | 5 +++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java index b9ff874f9b..1d5e1963d7 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java @@ -237,7 +237,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ if (StringUtils.hasLength(etag) && !this.notModified) { if (isCompatibleWithConditionalRequests(response)) { 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 (supportsNotModifiedStatus()) { if (this.notModified) { @@ -287,6 +292,10 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return (response.getHeader(header) == null); } + private boolean hasRequestHeader(String headerName) { + return StringUtils.hasLength(getHeader(headerName)); + } + private boolean supportsNotModifiedStatus() { String method = getRequest().getMethod(); return (METHOD_GET.equals(method) || METHOD_HEAD.equals(method)); @@ -294,9 +303,8 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ private boolean supportsConditionalUpdate() { 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)) - && StringUtils.hasLength(ifUnmodifiedHeader); + && hasRequestHeader(HEADER_IF_UNMODIFIED_SINCE); } private boolean isTimestampNotModified(long lastModifiedTimestamp) { @@ -318,7 +326,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ dateValue = getRequest().getDateHeader(headerName); } 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" int separatorIndex = headerValue.indexOf(';'); if (separatorIndex != -1) { @@ -336,7 +344,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ private boolean isEtagNotModified(String etag) { if (StringUtils.hasLength(etag)) { - String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH); + String ifNoneMatch = getHeader(HEADER_IF_NONE_MATCH); if (StringUtils.hasLength(ifNoneMatch)) { String[] clientEtags = StringUtils.delimitedListToStringArray(ifNoneMatch, ",", " "); for (String clientEtag : clientEtags) { diff --git a/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java index 6dd2adf9ed..eccf61ba46 100644 --- a/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java +++ b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java @@ -204,6 +204,7 @@ public class ServletWebRequestHttpMethodsTests { assertEquals(dateFormat.format(currentDate.getTime()), servletResponse.getHeader("Last-Modified")); } + // SPR-14224 @Test public void checkNotModifiedETagAndModifiedTimestamp() { String eTag = "\"Foo\""; @@ -212,9 +213,9 @@ public class ServletWebRequestHttpMethodsTests { long oneMinuteAgo = currentEpoch - (1000 * 60); 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(dateFormat.format(currentEpoch), servletResponse.getHeader("Last-Modified")); }