diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java index 32d4b31eb..df334b685 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java @@ -506,11 +506,16 @@ public class CachingHttpClient implements HttpClient { } private void recordCacheHit(HttpHost target, HttpRequest request) { + cacheHits.getAndIncrement(); if (log.isDebugEnabled()) { RequestLine rl = request.getRequestLine(); log.debug("Cache hit [host: " + target + "; uri: " + rl.getUri() + "]"); } - cacheHits.getAndIncrement(); + } + + private void recordCacheUpdate(HttpContext context) { + cacheUpdates.getAndIncrement(); + setResponseStatus(context, CacheResponseStatus.VALIDATED); } private void flushEntriesInvalidatedByRequest(HttpHost target, @@ -737,11 +742,6 @@ public class CachingHttpClient implements HttpClient { return callBackend(target, unconditional, context); } - private void recordCacheUpdate(HttpContext context) { - cacheUpdates.getAndIncrement(); - setResponseStatus(context, CacheResponseStatus.VALIDATED); - } - private HttpCacheEntry getUpdatedVariantEntry(HttpHost target, HttpRequest conditionalRequest, Date requestDate, Date responseDate, HttpResponse backendResponse, @@ -809,6 +809,7 @@ public class CachingHttpClient implements HttpClient { } if (staleIfErrorAppliesTo(statusCode) + && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate()) && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) { final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry); cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java index aa5177fb9..2906de594 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java @@ -26,9 +26,7 @@ */ package org.apache.http.impl.client.cache; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import static org.junit.Assert.*; import java.util.Date; import org.apache.http.Header; @@ -84,7 +82,105 @@ public class TestRFC5861Compliance extends AbstractProtocolTest { HttpTestUtils.assert110WarningFound(result); } + + @Test + public void testStaleIfErrorInResponseYieldsToMustRevalidate() + throws Exception{ + Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L); + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo, + "public, max-age=5, stale-if-error=60, must-revalidate"); + + backendExpectsAnyRequest().andReturn(resp1); + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp2 = HttpTestUtils.make500Response(); + + backendExpectsAnyRequest().andReturn(resp2); + + replayMocks(); + impl.execute(host,req1); + HttpResponse result = impl.execute(host,req2); + verifyMocks(); + + assertTrue(HttpStatus.SC_OK != result.getStatusLine().getStatusCode()); + } + + @Test + public void testStaleIfErrorInResponseYieldsToProxyRevalidateForSharedCache() + throws Exception{ + assertTrue(impl.isSharedCache()); + Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L); + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo, + "public, max-age=5, stale-if-error=60, proxy-revalidate"); + + backendExpectsAnyRequest().andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp2 = HttpTestUtils.make500Response(); + + backendExpectsAnyRequest().andReturn(resp2); + + replayMocks(); + impl.execute(host,req1); + HttpResponse result = impl.execute(host,req2); + verifyMocks(); + + assertTrue(HttpStatus.SC_OK != result.getStatusLine().getStatusCode()); + } + + @Test + public void testStaleIfErrorInResponseNeedNotYieldToProxyRevalidateForPrivateCache() + throws Exception{ + CacheConfig config = new CacheConfig(); + config.setSharedCache(false); + impl = new CachingHttpClient(mockBackend, config); + + Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L); + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo, + "public, max-age=5, stale-if-error=60, proxy-revalidate"); + + backendExpectsAnyRequest().andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp2 = HttpTestUtils.make500Response(); + + backendExpectsAnyRequest().andReturn(resp2); + + replayMocks(); + impl.execute(host,req1); + HttpResponse result = impl.execute(host,req2); + verifyMocks(); + + HttpTestUtils.assert110WarningFound(result); + } + + @Test + public void testStaleIfErrorInResponseYieldsToExplicitFreshnessRequest() + throws Exception{ + Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L); + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo, + "public, max-age=5, stale-if-error=60"); + + backendExpectsAnyRequest().andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + req2.setHeader("Cache-Control","min-fresh=2"); + HttpResponse resp2 = HttpTestUtils.make500Response(); + + backendExpectsAnyRequest().andReturn(resp2); + + replayMocks(); + impl.execute(host,req1); + HttpResponse result = impl.execute(host,req2); + verifyMocks(); + + assertTrue(HttpStatus.SC_OK != result.getStatusLine().getStatusCode()); + } + @Test public void testStaleIfErrorInRequestIsTrueReturnsStaleEntryWithWarning() throws Exception{ @@ -96,7 +192,7 @@ public class TestRFC5861Compliance extends AbstractProtocolTest { backendExpectsAnyRequest().andReturn(resp1); HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); - req2.setHeader("Cache-Control","public, max-age=5, stale-if-error=60"); + req2.setHeader("Cache-Control","public, stale-if-error=60"); HttpResponse resp2 = HttpTestUtils.make500Response(); backendExpectsAnyRequest().andReturn(resp2);