diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index cc8a3f825..525668188 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,5 +1,8 @@ Changes since 4.2 ------------------- +* [HTTPCLIENT-1202] ResponseCachingPolicy should honor explicit cache-control + directives for other status codes + Contributed by Jon Moore * [HTTPCLIENT-1199] DecompressingHttpClient strips content from entity enclosing requests Contributed by Oleg Kalnichevski diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java index b564c75bc..825873718 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java @@ -26,7 +26,10 @@ */ package org.apache.http.impl.client.cache; +import java.util.Arrays; import java.util.Date; +import java.util.HashSet; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -54,7 +57,16 @@ class ResponseCachingPolicy { private final long maxObjectSizeBytes; private final boolean sharedCache; private final Log log = LogFactory.getLog(getClass()); - + private static final Set cacheableStatuses = + new HashSet(Arrays.asList(HttpStatus.SC_OK, + HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, + HttpStatus.SC_MULTIPLE_CHOICES, + HttpStatus.SC_MOVED_PERMANENTLY, + HttpStatus.SC_GONE)); + private static final Set uncacheableStatuses = + new HashSet(Arrays.asList(HttpStatus.SC_PARTIAL_CONTENT, + HttpStatus.SC_SEE_OTHER)); + /** * Define a cache policy that limits the size of things that should be stored * in the cache to a maximum of {@link HttpResponse} bytes in size. @@ -82,30 +94,19 @@ class ResponseCachingPolicy { log.debug("Response was not cacheable."); return false; } - - switch (response.getStatusLine().getStatusCode()) { - case HttpStatus.SC_OK: - case HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION: - case HttpStatus.SC_MULTIPLE_CHOICES: - case HttpStatus.SC_MOVED_PERMANENTLY: - case HttpStatus.SC_GONE: - // these response codes MAY be cached - cacheable = true; - log.debug("Response was cacheable"); - break; - case HttpStatus.SC_PARTIAL_CONTENT: - // we don't implement Range requests and hence are not - // allowed to cache partial content - log.debug("Response was not cacheable (Partial Content)"); - return cacheable; - - default: - // If the status code is not one of the recognized - // available codes in HttpStatus Don't Cache - log.debug("Response was not cacheable (Unknown Status code)"); - return cacheable; + + int status = response.getStatusLine().getStatusCode(); + if (cacheableStatuses.contains(status)) { + // these response codes MAY be cached + cacheable = true; + } else if (uncacheableStatuses.contains(status)) { + return false; + } else if (unknownStatusCode(status)) { + // a response with an unknown status code MUST NOT be + // cached + return false; } - + Header contentLength = response.getFirstHeader(HTTP.CONTENT_LEN); if (contentLength != null) { int contentLengthValue = Integer.parseInt(contentLength.getValue()); @@ -148,7 +149,16 @@ class ResponseCachingPolicy { return (cacheable || isExplicitlyCacheable(response)); } - protected boolean isExplicitlyNonCacheable(HttpResponse response) { + private boolean unknownStatusCode(int status) { + if (status >= 100 && status <= 101) return false; + if (status >= 200 && status <= 206) return false; + if (status >= 300 && status <= 307) return false; + if (status >= 400 && status <= 417) return false; + if (status >= 500 && status <= 505) return false; + return true; + } + + protected boolean isExplicitlyNonCacheable(HttpResponse response) { Header[] cacheControlHeaders = response.getHeaders(HeaderConstants.CACHE_CONTROL); for (Header header : cacheControlHeaders) { for (HeaderElement elem : header.getElements()) { diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java index e92a590a8..e1f28da0d 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java @@ -459,6 +459,14 @@ public class TestResponseCachingPolicy { response.removeHeaders("Cache-Control"); Assert.assertFalse(policy.isResponseCacheable(request, response)); } + + @Test + public void otherStatusCodesAreCacheableWithExplicitCachingHeaders() { + response.setStatusCode(HttpStatus.SC_NOT_FOUND); + response.setHeader("Date", formatDate(now)); + response.setHeader("Cache-Control","max-age=300"); + Assert.assertTrue(policy.isResponseCacheable(request, response)); + } private int getRandomStatus() { int rnd = (new Random()).nextInt(acceptableCodes.length);