HTTPCLIENT-975: stale-if-error now yields to higher-priority

directives, like must-revalidate, proxy-revalidate, and requests
with explicit freshness constraints.


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1051206 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Moore 2010-12-20 16:55:03 +00:00
parent 7573bf8284
commit df577a7e8f
2 changed files with 107 additions and 10 deletions

View File

@ -506,11 +506,16 @@ public class CachingHttpClient implements HttpClient {
} }
private void recordCacheHit(HttpHost target, HttpRequest request) { private void recordCacheHit(HttpHost target, HttpRequest request) {
cacheHits.getAndIncrement();
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
RequestLine rl = request.getRequestLine(); RequestLine rl = request.getRequestLine();
log.debug("Cache hit [host: " + target + "; uri: " + rl.getUri() + "]"); 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, private void flushEntriesInvalidatedByRequest(HttpHost target,
@ -737,11 +742,6 @@ public class CachingHttpClient implements HttpClient {
return callBackend(target, unconditional, context); return callBackend(target, unconditional, context);
} }
private void recordCacheUpdate(HttpContext context) {
cacheUpdates.getAndIncrement();
setResponseStatus(context, CacheResponseStatus.VALIDATED);
}
private HttpCacheEntry getUpdatedVariantEntry(HttpHost target, private HttpCacheEntry getUpdatedVariantEntry(HttpHost target,
HttpRequest conditionalRequest, Date requestDate, HttpRequest conditionalRequest, Date requestDate,
Date responseDate, HttpResponse backendResponse, Date responseDate, HttpResponse backendResponse,
@ -809,6 +809,7 @@ public class CachingHttpClient implements HttpClient {
} }
if (staleIfErrorAppliesTo(statusCode) if (staleIfErrorAppliesTo(statusCode)
&& !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
&& validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) { && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry); final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");

View File

@ -26,9 +26,7 @@
*/ */
package org.apache.http.impl.client.cache; package org.apache.http.impl.client.cache;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.util.Date; import java.util.Date;
import org.apache.http.Header; import org.apache.http.Header;
@ -84,7 +82,105 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
HttpTestUtils.assert110WarningFound(result); 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 @Test
public void testStaleIfErrorInRequestIsTrueReturnsStaleEntryWithWarning() public void testStaleIfErrorInRequestIsTrueReturnsStaleEntryWithWarning()
throws Exception{ throws Exception{
@ -96,7 +192,7 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
backendExpectsAnyRequest().andReturn(resp1); backendExpectsAnyRequest().andReturn(resp1);
HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); 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(); HttpResponse resp2 = HttpTestUtils.make500Response();
backendExpectsAnyRequest().andReturn(resp2); backendExpectsAnyRequest().andReturn(resp2);