From e4ec79b5f3f8ab73de83d43fd9e431a7740c457e Mon Sep 17 00:00:00 2001 From: Matt Metlis Date: Wed, 4 Sep 2019 14:05:20 -0400 Subject: [PATCH] #37 Updating isCachedClientSide method to ignore If-Modified-Since when If-None-Match is also specified. --- .../bundles/assets/AssetServlet.java | 23 ++++++-- .../bundles/assets/AssetServletTest.java | 52 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/dropwizard/bundles/assets/AssetServlet.java b/src/main/java/io/dropwizard/bundles/assets/AssetServlet.java index 8c79999..84c4e19 100644 --- a/src/main/java/io/dropwizard/bundles/assets/AssetServlet.java +++ b/src/main/java/io/dropwizard/bundles/assets/AssetServlet.java @@ -231,9 +231,26 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) } private boolean isCachedClientSide(HttpServletRequest req, Asset cachedAsset) { - return cachedAsset.getETag().equals(req.getHeader(HttpHeaders.IF_NONE_MATCH)) - || (req.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE) - >= cachedAsset.getLastModifiedTime()); + String ifNoneMatchHeader = req.getHeader(HttpHeaders.IF_NONE_MATCH); + long ifModifiedSinceHeader = req.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE); + + boolean ifNoneMatchHeaderExists = ifNoneMatchHeader != null && !ifNoneMatchHeader.isEmpty(); + boolean ifModifiedSinceHeaderExists = ifModifiedSinceHeader >= 0; + + // If there is an If-None-Match header, determine caching based on eTag. + // Per RFC 7232, if If-None-Match is present, ignore If-Modified-Since. + if (ifNoneMatchHeaderExists) { + return cachedAsset.getETag().equals(ifNoneMatchHeader); + } else if (ifModifiedSinceHeaderExists) { + // If there is no If-None-Match header, but there is an If-Modified-Since header, + // determine caching based on last modified time. + return ifModifiedSinceHeader >= cachedAsset.getLastModifiedTime(); + } else { + // If there is neither an If-None-Match header nor am If-Modified-Since header, + // we cannot determine that the entity is cached. + return false; + } + } /** diff --git a/src/test/java/io/dropwizard/bundles/assets/AssetServletTest.java b/src/test/java/io/dropwizard/bundles/assets/AssetServletTest.java index 7970f70..38668fb 100644 --- a/src/test/java/io/dropwizard/bundles/assets/AssetServletTest.java +++ b/src/test/java/io/dropwizard/bundles/assets/AssetServletTest.java @@ -410,6 +410,58 @@ public void supportsIfModifiedSinceRequests() throws Exception { .isEqualTo(304); } + @Test + // Verify conformance with the HTTP/1.1 spec which requires ignoring the If-Modified-Since + // header when the If-None-Match header is present (RFC 7232). + public void supportsIfNoneMatchAndIfModifiedSinceRequests() throws Exception { + response = makeRequest(); + final long lastModifiedTime = response.getDateField(HttpHeaders.LAST_MODIFIED); + final String correctEtag = response.get(HttpHeaders.ETAG); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag); + response = makeRequest(); + final int statusWithMatchingLastModifiedTimeAndMatchingEtag = response.getStatus(); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime - 100); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag); + response = makeRequest(); + final int statusWithStaleLastModifiedTimeAndMatchingEtag = response.getStatus(); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime + 100); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag); + response = makeRequest(); + final int statusWithRecentLastModifiedTimeAndMatchingEtag = response.getStatus(); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag + "FOO"); + response = makeRequest(); + final int statusWithMatchingLastModifiedTimeAndNonMatchingEtag = response.getStatus(); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime - 100); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag + "FOO"); + response = makeRequest(); + final int statusWithStaleLastModifiedTimeAndNonMatchingEtag = response.getStatus(); + + request.putDateField(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedTime + 100); + request.setHeader(HttpHeaders.IF_NONE_MATCH, correctEtag + "FOO"); + response = makeRequest(); + final int statusWithRecentLastModifiedTimeAndNonMatchingEtag = response.getStatus(); + + assertThat(statusWithMatchingLastModifiedTimeAndMatchingEtag) + .isEqualTo(304); + assertThat(statusWithStaleLastModifiedTimeAndMatchingEtag) + .isEqualTo(304); + assertThat(statusWithRecentLastModifiedTimeAndMatchingEtag) + .isEqualTo(304); + assertThat(statusWithMatchingLastModifiedTimeAndNonMatchingEtag) + .isEqualTo(200); + assertThat(statusWithStaleLastModifiedTimeAndNonMatchingEtag) + .isEqualTo(200); + assertThat(statusWithRecentLastModifiedTimeAndNonMatchingEtag) + .isEqualTo(200); + } + @Test public void guessesMimeTypes() throws Exception { response = makeRequest();