Index: httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java =================================================================== --- httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (revision 1023967) +++ httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (working copy) @@ -1930,7 +1930,60 @@ verifyMocks(); 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); } Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java =================================================================== --- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (revision 1023967) +++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (working copy) @@ -407,6 +407,11 @@ 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 @@ 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 @@ 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()) {