You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by jo...@apache.org on 2010/12/23 13:02:37 UTC
svn commit: r1052234 - in
/httpcomponents/httpclient/trunk/httpclient-cache/src:
main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
Author: jonm
Date: Thu Dec 23 12:02:37 2010
New Revision: 1052234
URL: http://svn.apache.org/viewvc?rev=1052234&view=rev
Log:
HTTPCLIENT-1035: finished cache-flushing logic for updated
entries mentioned by Content-Location in responses. Still
not hooked in to main request handling flow yet.
Modified:
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java?rev=1052234&r1=1052233&r2=1052234&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java Thu Dec 23 12:02:37 2010
@@ -54,7 +54,7 @@ import org.apache.http.impl.cookie.DateU
class CacheInvalidator {
private final HttpCacheStorage storage;
- private final CacheKeyGenerator uriExtractor;
+ private final CacheKeyGenerator cacheKeyGenerator;
private final Log log = LogFactory.getLog(getClass());
@@ -68,7 +68,7 @@ class CacheInvalidator {
public CacheInvalidator(
final CacheKeyGenerator uriExtractor,
final HttpCacheStorage storage) {
- this.uriExtractor = uriExtractor;
+ this.cacheKeyGenerator = uriExtractor;
this.storage = storage;
}
@@ -79,26 +79,24 @@ class CacheInvalidator {
* @param host The backend host we are talking to
* @param req The HttpRequest to that host
*/
- public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) throws IOException {
+ public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) {
if (requestShouldNotBeCached(req)) {
log.debug("Request should not be cached");
- String theUri = uriExtractor.getURI(host, req);
+ String theUri = cacheKeyGenerator.getURI(host, req);
- HttpCacheEntry parent = storage.getEntry(theUri);
+ HttpCacheEntry parent = getEntry(theUri);
log.debug("parent entry: " + parent);
if (parent != null) {
for (String variantURI : parent.getVariantMap().values()) {
- storage.removeEntry(variantURI);
+ flushEntry(variantURI);
}
- storage.removeEntry(theUri);
+ flushEntry(theUri);
}
- URL reqURL;
- try {
- reqURL = new URL(theUri);
- } catch (MalformedURLException mue) {
+ URL reqURL = getAbsoluteURL(theUri);
+ if (reqURL == null) {
log.error("Couldn't transform request into valid URL");
return;
}
@@ -116,35 +114,65 @@ class CacheInvalidator {
}
}
- protected void flushUriIfSameHost(URL requestURL, URL targetURL) throws IOException {
- URL canonicalTarget = new URL(uriExtractor.canonicalizeUri(targetURL.toString()));
- if (canonicalTarget.getAuthority().equalsIgnoreCase(requestURL.getAuthority())) {
- storage.removeEntry(canonicalTarget.toString());
+ private void flushEntry(String uri) {
+ try {
+ storage.removeEntry(uri);
+ } catch (IOException ioe) {
+ log.warn("unable to flush cache entry", ioe);
}
}
- protected void flushRelativeUriFromSameHost(URL reqURL, String relUri) throws IOException {
- URL relURL;
+ private HttpCacheEntry getEntry(String theUri) {
try {
- relURL = new URL(reqURL,relUri);
- } catch (MalformedURLException e) {
- log.debug("Invalid relative URI",e);
- return;
+ return storage.getEntry(theUri);
+ } catch (IOException ioe) {
+ log.warn("could not retrieve entry from storage", ioe);
}
+ return null;
+ }
+
+ protected void flushUriIfSameHost(URL requestURL, URL targetURL) {
+ URL canonicalTarget = getAbsoluteURL(cacheKeyGenerator.canonicalizeUri(targetURL.toString()));
+ if (canonicalTarget == null) return;
+ if (canonicalTarget.getAuthority().equalsIgnoreCase(requestURL.getAuthority())) {
+ flushEntry(canonicalTarget.toString());
+ }
+ }
+
+ protected void flushRelativeUriFromSameHost(URL reqURL, String relUri) {
+ URL relURL = getRelativeURL(reqURL, relUri);
+ if (relURL == null) return;
flushUriIfSameHost(reqURL, relURL);
}
- protected boolean flushAbsoluteUriFromSameHost(URL reqURL, String uri) throws IOException {
- URL absURL;
+
+ protected boolean flushAbsoluteUriFromSameHost(URL reqURL, String uri) {
+ URL absURL = getAbsoluteURL(uri);
+ if (absURL == null) return false;
+ flushUriIfSameHost(reqURL,absURL);
+ return true;
+ }
+
+ private URL getAbsoluteURL(String uri) {
+ URL absURL = null;
try {
absURL = new URL(uri);
} catch (MalformedURLException mue) {
- return false;
+ // nop
}
- flushUriIfSameHost(reqURL,absURL);
- return true;
+ return absURL;
}
+ private URL getRelativeURL(URL reqURL, String relUri) {
+ URL relURL = null;
+ try {
+ relURL = new URL(reqURL,relUri);
+ } catch (MalformedURLException e) {
+ // nop
+ }
+ return relURL;
+ }
+
protected boolean requestShouldNotBeCached(HttpRequest req) {
String method = req.getRequestLine().getMethod();
return notGetOrHeadRequest(method);
@@ -160,16 +188,28 @@ class CacheInvalidator {
* @throws IOException
*/
public void flushInvalidatedCacheEntries(HttpHost host,
- HttpRequest request, HttpResponse response) throws IOException {
- Header contentLocation = response.getFirstHeader("Content-Location");
- if (contentLocation == null) return;
- HttpCacheEntry entry = storage.getEntry(contentLocation.getValue());
+ HttpRequest request, HttpResponse response) {
+ URL reqURL = getAbsoluteURL(cacheKeyGenerator.getURI(host, request));
+ if (reqURL == null) return;
+ URL canonURL = getContentLocationURL(reqURL, response);
+ if (canonURL == null) return;
+ String cacheKey = cacheKeyGenerator.canonicalizeUri(canonURL.toString());
+ HttpCacheEntry entry = getEntry(cacheKey);
if (entry == null) return;
if (!responseDateNewerThanEntryDate(response, entry)) return;
if (!responseAndEntryEtagsDiffer(response, entry)) return;
- storage.removeEntry(contentLocation.getValue());
+ flushUriIfSameHost(reqURL, canonURL);
+ }
+
+ private URL getContentLocationURL(URL reqURL, HttpResponse response) {
+ Header clHeader = response.getFirstHeader("Content-Location");
+ if (clHeader == null) return null;
+ String contentLocation = clHeader.getValue();
+ URL canonURL = getAbsoluteURL(contentLocation);
+ if (canonURL != null) return canonURL;
+ return getRelativeURL(reqURL, contentLocation);
}
private boolean responseAndEntryEtagsDiffer(HttpResponse response,
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java?rev=1052234&r1=1052233&r2=1052234&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java Thu Dec 23 12:02:37 2010
@@ -72,6 +72,7 @@ public class TestCacheInvalidator {
mockStorage = createMock(HttpCacheStorage.class);
cacheKeyGenerator = new CacheKeyGenerator();
mockEntry = createMock(HttpCacheEntry.class);
+ request = HttpTestUtils.makeDefaultRequest();
response = HttpTestUtils.make200Response();
impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
@@ -249,7 +250,7 @@ public class TestCacheInvalidator {
verifyMocks();
}
- @Test(expected=IOException.class)
+ @Test
public void testCacheFlushException() throws Exception {
request = new BasicHttpRequest("POST","/",HTTP_1_1);
String theURI = "http://foo.example.com:80/";
@@ -258,12 +259,12 @@ public class TestCacheInvalidator {
replayMocks();
impl.flushInvalidatedCacheEntries(host, request);
+ verifyMocks();
}
@Test
public void doesNotFlushForResponsesWithoutContentLocation()
throws Exception {
- request = HttpTestUtils.makeDefaultRequest();
replayMocks();
impl.flushInvalidatedCacheEntries(host, request, response);
verifyMocks();
@@ -291,6 +292,70 @@ public class TestCacheInvalidator {
}
@Test
+ public void flushesEntryIfFresherAndSpecifiedByNonCanonicalContentLocation()
+ throws Exception {
+ response.setHeader("ETag","\"new-etag\"");
+ response.setHeader("Date", formatDate(now));
+ String cacheKey = "http://foo.example.com:80/bar";
+ response.setHeader("Content-Location", "http://foo.example.com/bar");
+
+ HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+ new BasicHeader("Date", formatDate(tenSecondsAgo)),
+ new BasicHeader("ETag", "\"old-etag\"")
+ });
+
+ expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
+ mockStorage.removeEntry(cacheKey);
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, request, response);
+ verifyMocks();
+ }
+
+ @Test
+ public void flushesEntryIfFresherAndSpecifiedByRelativeContentLocation()
+ throws Exception {
+ response.setHeader("ETag","\"new-etag\"");
+ response.setHeader("Date", formatDate(now));
+ String cacheKey = "http://foo.example.com:80/bar";
+ response.setHeader("Content-Location", "/bar");
+
+ HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+ new BasicHeader("Date", formatDate(tenSecondsAgo)),
+ new BasicHeader("ETag", "\"old-etag\"")
+ });
+
+ expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
+ mockStorage.removeEntry(cacheKey);
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, request, response);
+ verifyMocks();
+ }
+
+ @Test
+ public void doesNotFlushEntryIfContentLocationFromDifferentHost()
+ throws Exception {
+ response.setHeader("ETag","\"new-etag\"");
+ response.setHeader("Date", formatDate(now));
+ String cacheKey = "http://baz.example.com:80/bar";
+ response.setHeader("Content-Location", cacheKey);
+
+ HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+ new BasicHeader("Date", formatDate(tenSecondsAgo)),
+ new BasicHeader("ETag", "\"old-etag\"")
+ });
+
+ expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, request, response);
+ verifyMocks();
+ }
+
+
+
+ @Test
public void doesNotFlushEntrySpecifiedByContentLocationIfEtagsMatch()
throws Exception {
response.setHeader("ETag","\"same-etag\"");
@@ -423,6 +488,46 @@ public class TestCacheInvalidator {
verifyMocks();
}
+ @Test
+ public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasMalformedDate()
+ throws Exception {
+ response.setHeader("ETag","\"new-etag\"");
+ response.setHeader("Date", "blarg");
+ String theURI = "http://foo.example.com:80/bar";
+ response.setHeader("Content-Location", theURI);
+
+ HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+ new BasicHeader("ETag", "\"old-etag\""),
+ new BasicHeader("Date", formatDate(tenSecondsAgo))
+ });
+
+ expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, request, response);
+ verifyMocks();
+ }
+
+ @Test
+ public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasMalformedDate()
+ throws Exception {
+ response.setHeader("ETag","\"new-etag\"");
+ response.setHeader("Date", formatDate(now));
+ String theURI = "http://foo.example.com:80/bar";
+ response.setHeader("Content-Location", theURI);
+
+ HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+ new BasicHeader("ETag", "\"old-etag\""),
+ new BasicHeader("Date", "foo")
+ });
+
+ expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, request, response);
+ verifyMocks();
+ }
+
// Expectations
private void cacheEntryHasVariantMap(Map<String,String> variantMap) {