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 9f6d7eb09..9a80caf29 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 @@ -407,6 +407,11 @@ public class CachingHttpClient implements HttpClient { log.debug("Cache miss [host: " + target + "; uri: " + rl.getUri() + "]"); } + if (!mayCallBackend(request)) { + return new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, + "Gateway Timeout"); + } + Set variantEntries = null; try { responseCache.getVariantCacheEntries(target, request); @@ -447,6 +452,11 @@ public class CachingHttpClient implements HttpClient { return cachedResponse; } + if (!mayCallBackend(request)) { + return new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, + "Gateway Timeout"); + } + if (validityPolicy.isRevalidatable(entry)) { log.debug("Revalidating the cache entry"); @@ -472,6 +482,17 @@ public class CachingHttpClient implements HttpClient { return callBackend(target, request, context); } + private boolean mayCallBackend(HttpRequest request) { + for (Header h: request.getHeaders("Cache-Control")) { + for (HeaderElement elt : h.getElements()) { + if ("only-if-cached".equals(elt.getName())) { + return false; + } + } + } + return true; + } + private boolean explicitFreshnessRequest(HttpRequest request, HttpCacheEntry entry, Date now) { for(Header h : request.getHeaders("Cache-Control")) { for(HeaderElement elt : h.getElements()) { diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java index fd629badb..3d84d09ee 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java @@ -1931,6 +1931,59 @@ public class TestCachingHttpClient { Assert.assertSame(resp, result); } + @Test + public void testIfOnlyIfCachedAndNoCacheEntryBackendNotCalled() throws IOException { + impl = new CachingHttpClient(mockBackend); + + request.addHeader("Cache-Control", "only-if-cached"); + + HttpResponse resp = impl.execute(host, request); + + Assert.assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT, resp.getStatusLine().getStatusCode()); + } + + @Test + public void testIfOnlyIfCachedAndEntryNotSuitableBackendNotCalled() throws Exception { + + request.setHeader("Cache-Control", "only-if-cached"); + + entry = HttpTestUtils.makeCacheEntry(new Header[]{new BasicHeader("Cache-Control", "must-revalidate")}); + + requestIsFatallyNonCompliant(null); + requestProtocolValidationIsCalled(); + cacheInvalidatorWasCalled(); + requestPolicyAllowsCaching(true); + getCacheEntryReturns(entry); + cacheEntrySuitable(false); + + replayMocks(); + HttpResponse resp = impl.execute(host, request); + verifyMocks(); + + Assert.assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT, resp.getStatusLine().getStatusCode()); + } + + @Test + public void testIfOnlyIfCachedAndEntryExistsAndIsSuitableReturnsEntry() throws Exception { + + request.setHeader("Cache-Control", "only-if-cached"); + + requestIsFatallyNonCompliant(null); + requestProtocolValidationIsCalled(); + cacheInvalidatorWasCalled(); + requestPolicyAllowsCaching(true); + getCacheEntryReturns(entry); + cacheEntrySuitable(true); + responseIsGeneratedFromCache(); + entryHasStaleness(0); + + replayMocks(); + HttpResponse resp = impl.execute(host, request); + verifyMocks(); + + Assert.assertSame(mockCachedResponse, resp); + } + private void getCacheEntryReturns(HttpCacheEntry result) throws IOException { EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(result); }