HTTPCLIENT-975: stale-while-revalidate also yields to must-revalidate,

proxy-revalidate on a shared cache, and requests with explicit
freshness constraints.


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1051235 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Moore 2010-12-20 18:30:46 +00:00
parent df577a7e8f
commit 52f311f5de
3 changed files with 151 additions and 1 deletions

View File

@ -430,7 +430,9 @@ public class CachingHttpClient implements HttpClient {
log.debug("Revalidating the cache entry"); log.debug("Revalidating the cache entry");
try { try {
if (asynchRevalidator != null && validityPolicy.mayReturnStaleWhileRevalidating(entry, now)) { if (asynchRevalidator != null
&& !staleResponseNotAllowed(request, entry, now)
&& validityPolicy.mayReturnStaleWhileRevalidating(entry, now)) {
final HttpResponse resp = responseGenerator.generateResponse(entry); final HttpResponse resp = responseGenerator.generateResponse(entry);
resp.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); resp.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");

View File

@ -351,6 +351,8 @@ public class TestCachingHttpClient {
getCacheEntryReturns(mockCacheEntry); getCacheEntryReturns(mockCacheEntry);
cacheEntrySuitable(false); cacheEntrySuitable(false);
cacheEntryValidatable(true); cacheEntryValidatable(true);
cacheEntryMustRevalidate(false);
cacheEntryProxyRevalidate(false);
mayReturnStaleWhileRevalidating(false); mayReturnStaleWhileRevalidating(false);
revalidateCacheEntryReturns(mockBackendResponse); revalidateCacheEntryReturns(mockBackendResponse);
@ -1944,6 +1946,16 @@ public class TestCachingHttpClient {
EasyMock.<HttpCacheEntry>anyObject())).andReturn(b); EasyMock.<HttpCacheEntry>anyObject())).andReturn(b);
} }
private void cacheEntryMustRevalidate(boolean b) {
EasyMock.expect(mockValidityPolicy.mustRevalidate(mockCacheEntry))
.andReturn(b);
}
private void cacheEntryProxyRevalidate(boolean b) {
EasyMock.expect(mockValidityPolicy.proxyRevalidate(mockCacheEntry))
.andReturn(b);
}
private void mayReturnStaleWhileRevalidating(boolean b) { private void mayReturnStaleWhileRevalidating(boolean b) {
EasyMock.expect(mockValidityPolicy.mayReturnStaleWhileRevalidating( EasyMock.expect(mockValidityPolicy.mayReturnStaleWhileRevalidating(
EasyMock.<HttpCacheEntry>anyObject(), EasyMock.<Date>anyObject())).andReturn(b); EasyMock.<HttpCacheEntry>anyObject(), EasyMock.<Date>anyObject())).andReturn(b);

View File

@ -300,4 +300,140 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
} }
assertTrue(warning110Found); assertTrue(warning110Found);
} }
@Test
public void testStaleWhileRevalidateYieldsToMustRevalidate()
throws Exception {
Date now = new Date();
Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
params.setAsynchronousWorkersMax(1);
impl = new CachingHttpClient(mockBackend, cache, params);
HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, must-revalidate");
resp1.setHeader("ETag","\"etag\"");
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
backendExpectsAnyRequest().andReturn(resp1);
HttpRequest req2 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpResponse resp2 = HttpTestUtils.make200Response();
resp2.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, must-revalidate");
resp2.setHeader("ETag","\"etag\"");
resp2.setHeader("Date", DateUtils.formatDate(now));
backendExpectsAnyRequest().andReturn(resp2);
replayMocks();
impl.execute(host, req1);
HttpResponse result = impl.execute(host, req2);
verifyMocks();
assertEquals(HttpStatus.SC_OK, result.getStatusLine().getStatusCode());
boolean warning110Found = false;
for(Header h : result.getHeaders("Warning")) {
for(WarningValue wv : WarningValue.getWarningValues(h)) {
if (wv.getWarnCode() == 110) {
warning110Found = true;
break;
}
}
}
assertFalse(warning110Found);
}
@Test
public void testStaleWhileRevalidateYieldsToProxyRevalidateForSharedCache()
throws Exception {
Date now = new Date();
Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
params.setAsynchronousWorkersMax(1);
params.setSharedCache(true);
impl = new CachingHttpClient(mockBackend, cache, params);
HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, proxy-revalidate");
resp1.setHeader("ETag","\"etag\"");
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
backendExpectsAnyRequest().andReturn(resp1);
HttpRequest req2 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpResponse resp2 = HttpTestUtils.make200Response();
resp2.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, proxy-revalidate");
resp2.setHeader("ETag","\"etag\"");
resp2.setHeader("Date", DateUtils.formatDate(now));
backendExpectsAnyRequest().andReturn(resp2);
replayMocks();
impl.execute(host, req1);
HttpResponse result = impl.execute(host, req2);
verifyMocks();
assertEquals(HttpStatus.SC_OK, result.getStatusLine().getStatusCode());
boolean warning110Found = false;
for(Header h : result.getHeaders("Warning")) {
for(WarningValue wv : WarningValue.getWarningValues(h)) {
if (wv.getWarnCode() == 110) {
warning110Found = true;
break;
}
}
}
assertFalse(warning110Found);
}
@Test
public void testStaleWhileRevalidateYieldsToExplicitFreshnessRequest()
throws Exception {
Date now = new Date();
Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
params.setAsynchronousWorkersMax(1);
params.setSharedCache(true);
impl = new CachingHttpClient(mockBackend, cache, params);
HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15");
resp1.setHeader("ETag","\"etag\"");
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
backendExpectsAnyRequest().andReturn(resp1);
HttpRequest req2 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
req2.setHeader("Cache-Control","min-fresh=2");
HttpResponse resp2 = HttpTestUtils.make200Response();
resp2.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15");
resp2.setHeader("ETag","\"etag\"");
resp2.setHeader("Date", DateUtils.formatDate(now));
backendExpectsAnyRequest().andReturn(resp2);
replayMocks();
impl.execute(host, req1);
HttpResponse result = impl.execute(host, req2);
verifyMocks();
assertEquals(HttpStatus.SC_OK, result.getStatusLine().getStatusCode());
boolean warning110Found = false;
for(Header h : result.getHeaders("Warning")) {
for(WarningValue wv : WarningValue.getWarningValues(h)) {
if (wv.getWarnCode() == 110) {
warning110Found = true;
break;
}
}
}
assertFalse(warning110Found);
}
} }