hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject [2/2] httpcomponents-client git commit: Renamed class (no functional changes)
Date Mon, 16 Oct 2017 21:43:20 GMT
Renamed class (no functional changes)


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/f70c9742
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/f70c9742
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/f70c9742

Branch: refs/heads/master
Commit: f70c9742411ebffc32118c9226ee96ba8d51838d
Parents: fc41f47
Author: Oleg Kalnichevski <olegk@apache.org>
Authored: Mon Oct 16 23:41:40 2017 +0200
Committer: Oleg Kalnichevski <olegk@apache.org>
Committed: Mon Oct 16 23:41:40 2017 +0200

----------------------------------------------------------------------
 .../client5/http/impl/cache/BasicHttpCache.java |   2 +-
 .../http/impl/cache/CacheInvalidator.java       | 290 --------
 .../cache/CachingHttpAsyncClientBuilder.java    |   2 +-
 .../impl/cache/CachingHttpClientBuilder.java    |   2 +-
 .../impl/cache/DefaultCacheInvalidator.java     | 290 ++++++++
 .../http/impl/cache/TestCacheInvalidator.java   | 675 -------------------
 .../impl/cache/TestDefaultCacheInvalidator.java | 674 ++++++++++++++++++
 7 files changed, 967 insertions(+), 968 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
index 4569e93..7d831ea 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java
@@ -80,7 +80,7 @@ class BasicHttpCache implements HttpCache {
             final ResourceFactory resourceFactory,
             final HttpCacheStorage storage,
             final CacheKeyGenerator uriExtractor) {
-        this(resourceFactory, storage, uriExtractor, new CacheInvalidator(uriExtractor, storage));
+        this(resourceFactory, storage, uriExtractor, new DefaultCacheInvalidator(uriExtractor, storage));
     }
 
     public BasicHttpCache(final ResourceFactory resourceFactory, final HttpCacheStorage storage) {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheInvalidator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheInvalidator.java
deleted file mode 100644
index 3240fff..0000000
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheInvalidator.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.impl.cache;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Date;
-
-import org.apache.hc.client5.http.cache.HeaderConstants;
-import org.apache.hc.client5.http.cache.HttpCacheEntry;
-import org.apache.hc.client5.http.cache.HttpCacheInvalidator;
-import org.apache.hc.client5.http.cache.HttpCacheStorage;
-import org.apache.hc.client5.http.utils.DateUtils;
-import org.apache.hc.client5.http.utils.URIUtils;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-/**
- * Given a particular HttpRequest, flush any cache entries that this request
- * would invalidate.
- *
- * @since 4.1
- */
-@Contract(threading = ThreadingBehavior.IMMUTABLE)
-class CacheInvalidator implements HttpCacheInvalidator {
-
-    private final HttpCacheStorage storage;
-    private final CacheKeyGenerator cacheKeyGenerator;
-
-    private final Logger log = LogManager.getLogger(getClass());
-
-    /**
-     * Create a new {@link CacheInvalidator} for a given {@link HttpCache} and
-     * {@link CacheKeyGenerator}.
-     *
-     * @param cacheKeyGenerator Provides identifiers for the keys to store cache entries
-     * @param storage the cache to store items away in
-     */
-    public CacheInvalidator(
-            final CacheKeyGenerator cacheKeyGenerator,
-            final HttpCacheStorage storage) {
-        this.cacheKeyGenerator = cacheKeyGenerator;
-        this.storage = storage;
-    }
-
-    private static URI parse(final String uri) {
-        if (uri == null) {
-            return null;
-        }
-        try {
-            return new URI(uri);
-        } catch (final URISyntaxException ex) {
-            return null;
-        }
-    }
-
-    /**
-     * Remove cache entries from the cache that are no longer fresh or
-     * have been invalidated in some way.
-     *
-     * @param host The backend host we are talking to
-     * @param req The HttpRequest to that host
-     */
-    @Override
-    public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest req)  {
-        final String key = cacheKeyGenerator.generateKey(host, req);
-        final HttpCacheEntry parent = getEntry(key);
-
-        if (requestShouldNotBeCached(req) || shouldInvalidateHeadCacheEntry(req, parent)) {
-            if (log.isDebugEnabled()) {
-                log.debug("Invalidating parent cache entry: " + parent);
-            }
-            if (parent != null) {
-                for (final String variantURI : parent.getVariantMap().values()) {
-                    flushEntry(variantURI);
-                }
-                flushEntry(key);
-            }
-            final URI uri = parse(key);
-            if (uri == null) {
-                log.error("Couldn't transform request into valid URI");
-                return;
-            }
-            final Header clHdr = req.getFirstHeader("Content-Location");
-            if (clHdr != null) {
-                final URI contentLocation = parse(clHdr.getValue());
-                if (contentLocation != null) {
-                    if (!flushAbsoluteUriFromSameHost(uri, contentLocation)) {
-                        flushRelativeUriFromSameHost(uri, contentLocation);
-                    }
-                }
-            }
-            final Header lHdr = req.getFirstHeader("Location");
-            if (lHdr != null) {
-                flushAbsoluteUriFromSameHost(uri, parse(lHdr.getValue()));
-            }
-        }
-    }
-
-    private boolean shouldInvalidateHeadCacheEntry(final HttpRequest req, final HttpCacheEntry parentCacheEntry) {
-        return requestIsGet(req) && isAHeadCacheEntry(parentCacheEntry);
-    }
-
-    private boolean requestIsGet(final HttpRequest req) {
-        return req.getMethod().equals((HeaderConstants.GET_METHOD));
-    }
-
-    private boolean isAHeadCacheEntry(final HttpCacheEntry parentCacheEntry) {
-        return parentCacheEntry != null && parentCacheEntry.getRequestMethod().equals(HeaderConstants.HEAD_METHOD);
-    }
-
-    private void flushEntry(final String uri) {
-        try {
-            storage.removeEntry(uri);
-        } catch (final IOException ioe) {
-            log.warn("unable to flush cache entry", ioe);
-        }
-    }
-
-    private HttpCacheEntry getEntry(final String theUri) {
-        try {
-            return storage.getEntry(theUri);
-        } catch (final IOException ioe) {
-            log.warn("could not retrieve entry from storage", ioe);
-        }
-        return null;
-    }
-
-    protected void flushUriIfSameHost(final URI requestURI, final URI targetURI) {
-        final URI canonicalTarget = parse(cacheKeyGenerator.generateKey(targetURI));
-        if (canonicalTarget == null) {
-            return;
-        }
-        if (canonicalTarget.getAuthority().equalsIgnoreCase(requestURI.getAuthority())) {
-            flushEntry(canonicalTarget.toString());
-        }
-    }
-
-    protected void flushRelativeUriFromSameHost(final URI requestUri, final URI uri) {
-        final URI resolvedUri = uri != null ? URIUtils.resolve(requestUri, uri) : null;
-        if (resolvedUri != null) {
-            flushUriIfSameHost(requestUri, resolvedUri);
-        }
-    }
-
-
-    protected boolean flushAbsoluteUriFromSameHost(final URI requestUri, final URI uri) {
-        if (uri != null && uri.isAbsolute()) {
-            flushUriIfSameHost(requestUri, uri);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected boolean requestShouldNotBeCached(final HttpRequest req) {
-        final String method = req.getMethod();
-        return notGetOrHeadRequest(method);
-    }
-
-    private boolean notGetOrHeadRequest(final String method) {
-        return !(HeaderConstants.GET_METHOD.equals(method) || HeaderConstants.HEAD_METHOD
-                .equals(method));
-    }
-
-    /** Flushes entries that were invalidated by the given response
-     * received for the given host/request pair.
-     */
-    @Override
-    public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest request, final HttpResponse response) {
-        final int status = response.getCode();
-        if (status < 200 || status > 299) {
-            return;
-        }
-        final URI uri = parse(cacheKeyGenerator.generateKey(host, request));
-        if (uri == null) {
-            return;
-        }
-        final URI contentLocation = getContentLocationURI(uri, response);
-        if (contentLocation != null) {
-            flushLocationCacheEntry(uri, response, contentLocation);
-        }
-        final URI location = getLocationURI(uri, response);
-        if (location != null) {
-            flushLocationCacheEntry(uri, response, location);
-        }
-    }
-
-    private void flushLocationCacheEntry(final URI requestUri, final HttpResponse response, final URI location) {
-        final String cacheKey = cacheKeyGenerator.generateKey(location);
-        final HttpCacheEntry entry = getEntry(cacheKey);
-        if (entry == null) {
-            return;
-        }
-
-        // do not invalidate if response is strictly older than entry
-        // or if the etags match
-
-        if (responseDateOlderThanEntryDate(response, entry)) {
-            return;
-        }
-        if (!responseAndEntryEtagsDiffer(response, entry)) {
-            return;
-        }
-
-        flushUriIfSameHost(requestUri, location);
-    }
-
-    private static URI getLocationURI(final URI requestUri, final HttpResponse response, final String headerName) {
-        final Header h = response.getFirstHeader(headerName);
-        if (h == null) {
-            return null;
-        }
-        final URI locationUri = parse(h.getValue());
-        if (locationUri == null) {
-            return requestUri;
-        }
-        if (locationUri.isAbsolute()) {
-            return locationUri;
-        } else {
-            return URIUtils.resolve(requestUri, locationUri);
-        }
-    }
-
-    private URI getContentLocationURI(final URI requestUri, final HttpResponse response) {
-        return getLocationURI(requestUri, response, HttpHeaders.CONTENT_LOCATION);
-    }
-
-    private URI getLocationURI(final URI requestUri, final HttpResponse response) {
-        return getLocationURI(requestUri, response, HttpHeaders.LOCATION);
-    }
-
-    private boolean responseAndEntryEtagsDiffer(final HttpResponse response,
-            final HttpCacheEntry entry) {
-        final Header entryEtag = entry.getFirstHeader(HeaderConstants.ETAG);
-        final Header responseEtag = response.getFirstHeader(HeaderConstants.ETAG);
-        if (entryEtag == null || responseEtag == null) {
-            return false;
-        }
-        return (!entryEtag.getValue().equals(responseEtag.getValue()));
-    }
-
-    private boolean responseDateOlderThanEntryDate(final HttpResponse response,
-            final HttpCacheEntry entry) {
-        final Header entryDateHeader = entry.getFirstHeader(HttpHeaders.DATE);
-        final Header responseDateHeader = response.getFirstHeader(HttpHeaders.DATE);
-        if (entryDateHeader == null || responseDateHeader == null) {
-            /* be conservative; should probably flush */
-            return false;
-        }
-        final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
-        final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
-        if (entryDate == null || responseDate == null) {
-            return false;
-        }
-        return responseDate.before(entryDate);
-    }
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
index 9891265..4a92692 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpAsyncClientBuilder.java
@@ -135,7 +135,7 @@ public class CachingHttpAsyncClientBuilder extends HttpAsyncClientBuilder {
                 resourceFactoryCopy,
                 storageCopy,
                 uriExtractor,
-                this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new CacheInvalidator(uriExtractor, storageCopy));
+                this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new DefaultCacheInvalidator(uriExtractor, storageCopy));
 
         final AsyncCachingExec cachingExec = new AsyncCachingExec(httpCache, config);
         execChainDefinition.addBefore(ChainElements.PROTOCOL.name(), cachingExec, ChainElements.CACHING.name());

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
index 158361e..4ae9025 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingHttpClientBuilder.java
@@ -135,7 +135,7 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
                 resourceFactoryCopy,
                 storageCopy,
                 uriExtractor,
-                this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new CacheInvalidator(uriExtractor, storageCopy));
+                this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new DefaultCacheInvalidator(uriExtractor, storageCopy));
 
         final CachingExec cachingExec = new CachingExec(httpCache, config);
         execChainDefinition.addBefore(ChainElements.PROTOCOL.name(), cachingExec, ChainElements.CACHING.name());

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
new file mode 100644
index 0000000..553bd42
--- /dev/null
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
@@ -0,0 +1,290 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.impl.cache;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+
+import org.apache.hc.client5.http.cache.HeaderConstants;
+import org.apache.hc.client5.http.cache.HttpCacheEntry;
+import org.apache.hc.client5.http.cache.HttpCacheInvalidator;
+import org.apache.hc.client5.http.cache.HttpCacheStorage;
+import org.apache.hc.client5.http.utils.DateUtils;
+import org.apache.hc.client5.http.utils.URIUtils;
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Given a particular HttpRequest, flush any cache entries that this request
+ * would invalidate.
+ *
+ * @since 4.1
+ */
+@Contract(threading = ThreadingBehavior.IMMUTABLE)
+class DefaultCacheInvalidator implements HttpCacheInvalidator {
+
+    private final HttpCacheStorage storage;
+    private final CacheKeyGenerator cacheKeyGenerator;
+
+    private final Logger log = LogManager.getLogger(getClass());
+
+    /**
+     * Create a new {@link DefaultCacheInvalidator} for a given {@link HttpCache} and
+     * {@link CacheKeyGenerator}.
+     *
+     * @param cacheKeyGenerator Provides identifiers for the keys to store cache entries
+     * @param storage the cache to store items away in
+     */
+    public DefaultCacheInvalidator(
+            final CacheKeyGenerator cacheKeyGenerator,
+            final HttpCacheStorage storage) {
+        this.cacheKeyGenerator = cacheKeyGenerator;
+        this.storage = storage;
+    }
+
+    private static URI parse(final String uri) {
+        if (uri == null) {
+            return null;
+        }
+        try {
+            return new URI(uri);
+        } catch (final URISyntaxException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Remove cache entries from the cache that are no longer fresh or
+     * have been invalidated in some way.
+     *
+     * @param host The backend host we are talking to
+     * @param req The HttpRequest to that host
+     */
+    @Override
+    public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest req)  {
+        final String key = cacheKeyGenerator.generateKey(host, req);
+        final HttpCacheEntry parent = getEntry(key);
+
+        if (requestShouldNotBeCached(req) || shouldInvalidateHeadCacheEntry(req, parent)) {
+            if (log.isDebugEnabled()) {
+                log.debug("Invalidating parent cache entry: " + parent);
+            }
+            if (parent != null) {
+                for (final String variantURI : parent.getVariantMap().values()) {
+                    flushEntry(variantURI);
+                }
+                flushEntry(key);
+            }
+            final URI uri = parse(key);
+            if (uri == null) {
+                log.error("Couldn't transform request into valid URI");
+                return;
+            }
+            final Header clHdr = req.getFirstHeader("Content-Location");
+            if (clHdr != null) {
+                final URI contentLocation = parse(clHdr.getValue());
+                if (contentLocation != null) {
+                    if (!flushAbsoluteUriFromSameHost(uri, contentLocation)) {
+                        flushRelativeUriFromSameHost(uri, contentLocation);
+                    }
+                }
+            }
+            final Header lHdr = req.getFirstHeader("Location");
+            if (lHdr != null) {
+                flushAbsoluteUriFromSameHost(uri, parse(lHdr.getValue()));
+            }
+        }
+    }
+
+    private boolean shouldInvalidateHeadCacheEntry(final HttpRequest req, final HttpCacheEntry parentCacheEntry) {
+        return requestIsGet(req) && isAHeadCacheEntry(parentCacheEntry);
+    }
+
+    private boolean requestIsGet(final HttpRequest req) {
+        return req.getMethod().equals((HeaderConstants.GET_METHOD));
+    }
+
+    private boolean isAHeadCacheEntry(final HttpCacheEntry parentCacheEntry) {
+        return parentCacheEntry != null && parentCacheEntry.getRequestMethod().equals(HeaderConstants.HEAD_METHOD);
+    }
+
+    private void flushEntry(final String uri) {
+        try {
+            storage.removeEntry(uri);
+        } catch (final IOException ioe) {
+            log.warn("unable to flush cache entry", ioe);
+        }
+    }
+
+    private HttpCacheEntry getEntry(final String theUri) {
+        try {
+            return storage.getEntry(theUri);
+        } catch (final IOException ioe) {
+            log.warn("could not retrieve entry from storage", ioe);
+        }
+        return null;
+    }
+
+    protected void flushUriIfSameHost(final URI requestURI, final URI targetURI) {
+        final URI canonicalTarget = parse(cacheKeyGenerator.generateKey(targetURI));
+        if (canonicalTarget == null) {
+            return;
+        }
+        if (canonicalTarget.getAuthority().equalsIgnoreCase(requestURI.getAuthority())) {
+            flushEntry(canonicalTarget.toString());
+        }
+    }
+
+    protected void flushRelativeUriFromSameHost(final URI requestUri, final URI uri) {
+        final URI resolvedUri = uri != null ? URIUtils.resolve(requestUri, uri) : null;
+        if (resolvedUri != null) {
+            flushUriIfSameHost(requestUri, resolvedUri);
+        }
+    }
+
+
+    protected boolean flushAbsoluteUriFromSameHost(final URI requestUri, final URI uri) {
+        if (uri != null && uri.isAbsolute()) {
+            flushUriIfSameHost(requestUri, uri);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean requestShouldNotBeCached(final HttpRequest req) {
+        final String method = req.getMethod();
+        return notGetOrHeadRequest(method);
+    }
+
+    private boolean notGetOrHeadRequest(final String method) {
+        return !(HeaderConstants.GET_METHOD.equals(method) || HeaderConstants.HEAD_METHOD
+                .equals(method));
+    }
+
+    /** Flushes entries that were invalidated by the given response
+     * received for the given host/request pair.
+     */
+    @Override
+    public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest request, final HttpResponse response) {
+        final int status = response.getCode();
+        if (status < 200 || status > 299) {
+            return;
+        }
+        final URI uri = parse(cacheKeyGenerator.generateKey(host, request));
+        if (uri == null) {
+            return;
+        }
+        final URI contentLocation = getContentLocationURI(uri, response);
+        if (contentLocation != null) {
+            flushLocationCacheEntry(uri, response, contentLocation);
+        }
+        final URI location = getLocationURI(uri, response);
+        if (location != null) {
+            flushLocationCacheEntry(uri, response, location);
+        }
+    }
+
+    private void flushLocationCacheEntry(final URI requestUri, final HttpResponse response, final URI location) {
+        final String cacheKey = cacheKeyGenerator.generateKey(location);
+        final HttpCacheEntry entry = getEntry(cacheKey);
+        if (entry == null) {
+            return;
+        }
+
+        // do not invalidate if response is strictly older than entry
+        // or if the etags match
+
+        if (responseDateOlderThanEntryDate(response, entry)) {
+            return;
+        }
+        if (!responseAndEntryEtagsDiffer(response, entry)) {
+            return;
+        }
+
+        flushUriIfSameHost(requestUri, location);
+    }
+
+    private static URI getLocationURI(final URI requestUri, final HttpResponse response, final String headerName) {
+        final Header h = response.getFirstHeader(headerName);
+        if (h == null) {
+            return null;
+        }
+        final URI locationUri = parse(h.getValue());
+        if (locationUri == null) {
+            return requestUri;
+        }
+        if (locationUri.isAbsolute()) {
+            return locationUri;
+        } else {
+            return URIUtils.resolve(requestUri, locationUri);
+        }
+    }
+
+    private URI getContentLocationURI(final URI requestUri, final HttpResponse response) {
+        return getLocationURI(requestUri, response, HttpHeaders.CONTENT_LOCATION);
+    }
+
+    private URI getLocationURI(final URI requestUri, final HttpResponse response) {
+        return getLocationURI(requestUri, response, HttpHeaders.LOCATION);
+    }
+
+    private boolean responseAndEntryEtagsDiffer(final HttpResponse response,
+            final HttpCacheEntry entry) {
+        final Header entryEtag = entry.getFirstHeader(HeaderConstants.ETAG);
+        final Header responseEtag = response.getFirstHeader(HeaderConstants.ETAG);
+        if (entryEtag == null || responseEtag == null) {
+            return false;
+        }
+        return (!entryEtag.getValue().equals(responseEtag.getValue()));
+    }
+
+    private boolean responseDateOlderThanEntryDate(final HttpResponse response,
+            final HttpCacheEntry entry) {
+        final Header entryDateHeader = entry.getFirstHeader(HttpHeaders.DATE);
+        final Header responseDateHeader = response.getFirstHeader(HttpHeaders.DATE);
+        if (entryDateHeader == null || responseDateHeader == null) {
+            /* be conservative; should probably flush */
+            return false;
+        }
+        final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
+        final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
+        if (entryDate == null || responseDate == null) {
+            return false;
+        }
+        return responseDate.before(entryDate);
+    }
+}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheInvalidator.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheInvalidator.java
deleted file mode 100644
index 1f55518..0000000
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheInvalidator.java
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.impl.cache;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.hc.client5.http.cache.HttpCacheEntry;
-import org.apache.hc.client5.http.cache.HttpCacheStorage;
-import org.apache.hc.client5.http.cache.ResourceIOException;
-import org.apache.hc.client5.http.utils.DateUtils;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.ProtocolVersion;
-import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
-import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
-import org.apache.hc.core5.http.message.BasicHeader;
-import org.junit.Before;
-import org.junit.Test;
-
-public class TestCacheInvalidator {
-
-    private CacheInvalidator impl;
-    private HttpCacheStorage mockStorage;
-    private HttpHost host;
-    private CacheKeyGenerator cacheKeyGenerator;
-    private HttpCacheEntry mockEntry;
-    private ClassicHttpRequest request;
-    private ClassicHttpResponse response;
-
-    private Date now;
-    private Date tenSecondsAgo;
-
-    @Before
-    public void setUp() {
-        now = new Date();
-        tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
-
-        host = new HttpHost("foo.example.com");
-        mockStorage = mock(HttpCacheStorage.class);
-        cacheKeyGenerator = new CacheKeyGenerator();
-        mockEntry = mock(HttpCacheEntry.class);
-        request = HttpTestUtils.makeDefaultRequest();
-        response = HttpTestUtils.make200Response();
-
-        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
-    }
-
-    // Tests
-    @Test
-    public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
-        request = new BasicClassicHttpRequest("POST","/path");
-        final String theUri = "http://foo.example.com:80/path";
-        final Map<String,String> variantMap = new HashMap<>();
-        cacheEntryHasVariantMap(variantMap);
-
-        cacheReturnsEntryForUri(theUri);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theUri);
-        verify(mockStorage).removeEntry(theUri);
-    }
-
-    @Test
-    public void testInvalidatesUrisInContentLocationHeadersOnPUTs() throws Exception {
-        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
-        putRequest.setEntity(HttpTestUtils.makeBody(128));
-        putRequest.setHeader("Content-Length","128");
-
-        final String contentLocation = "http://foo.example.com/content";
-        putRequest.setHeader("Content-Location", contentLocation);
-
-        final String theUri = "http://foo.example.com:80/";
-        cacheEntryHasVariantMap(new HashMap<String,String>());
-
-        cacheReturnsEntryForUri(theUri);
-
-        impl.flushInvalidatedCacheEntries(host, putRequest);
-
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theUri);
-        verify(mockStorage).removeEntry(theUri);
-        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
-    }
-
-    @Test
-    public void testInvalidatesUrisInLocationHeadersOnPUTs() throws Exception {
-        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
-        putRequest.setEntity(HttpTestUtils.makeBody(128));
-        putRequest.setHeader("Content-Length","128");
-
-        final String contentLocation = "http://foo.example.com/content";
-        putRequest.setHeader("Location",contentLocation);
-
-        final String theUri = "http://foo.example.com:80/";
-        cacheEntryHasVariantMap(new HashMap<String,String>());
-
-        cacheReturnsEntryForUri(theUri);
-
-        impl.flushInvalidatedCacheEntries(host, putRequest);
-
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theUri);
-        verify(mockStorage).removeEntry(theUri);
-        verify(mockStorage).removeEntry(cacheKeyGenerator.generateKey(new URI(contentLocation)));
-    }
-
-    @Test
-    public void testInvalidatesRelativeUrisInContentLocationHeadersOnPUTs() throws Exception {
-        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
-        putRequest.setEntity(HttpTestUtils.makeBody(128));
-        putRequest.setHeader("Content-Length","128");
-
-        final String relativePath = "/content";
-        putRequest.setHeader("Content-Location",relativePath);
-
-        final String theUri = "http://foo.example.com:80/";
-        cacheEntryHasVariantMap(new HashMap<String,String>());
-
-        cacheReturnsEntryForUri(theUri);
-
-        impl.flushInvalidatedCacheEntries(host, putRequest);
-
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theUri);
-        verify(mockStorage).removeEntry(theUri);
-        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
-    }
-
-    @Test
-    public void testDoesNotInvalidateUrisInContentLocationHeadersOnPUTsToDifferentHosts() throws Exception {
-        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
-        putRequest.setEntity(HttpTestUtils.makeBody(128));
-        putRequest.setHeader("Content-Length","128");
-
-        final String contentLocation = "http://bar.example.com/content";
-        putRequest.setHeader("Content-Location",contentLocation);
-
-        final String theUri = "http://foo.example.com:80/";
-        cacheEntryHasVariantMap(new HashMap<String,String>());
-
-        cacheReturnsEntryForUri(theUri);
-
-        impl.flushInvalidatedCacheEntries(host, putRequest);
-
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theUri);
-        verify(mockStorage).removeEntry(theUri);
-    }
-
-    @Test
-    public void testDoesNotInvalidateGETRequest() throws Exception {
-        request = new BasicClassicHttpRequest("GET","/");
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry("http://foo.example.com:80/");
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testDoesNotInvalidateHEADRequest() throws Exception {
-        request = new BasicClassicHttpRequest("HEAD","/");
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry("http://foo.example.com:80/");
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
-        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
-        final String theURI = "http://foo.example.com:80/";
-        request = new BasicClassicHttpRequest("GET", theURI);
-
-        cacheEntryisForMethod("HEAD");
-        cacheEntryHasVariantMap(new HashMap<String, String>());
-        cacheReturnsEntryForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockEntry).getRequestMethod();
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-    }
-
-    @Test
-    public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
-        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
-        final String theURI = "http://foo.example.com:80/";
-        request = new BasicClassicHttpRequest("GET", theURI);
-        final String theVariantKey = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}";
-        final String theVariantURI = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}http://foo.example.com:80/";
-        final Map<String, String> variants = HttpTestUtils.makeDefaultVariantMap(theVariantKey, theVariantURI);
-
-        cacheEntryisForMethod("HEAD");
-        cacheEntryHasVariantMap(variants);
-        cacheReturnsEntryForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockEntry).getRequestMethod();
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-        verify(mockStorage).removeEntry(theVariantURI);
-    }
-
-    @Test
-    public void testDoesNotInvalidateHEADCacheEntry() throws Exception {
-        final String theURI = "http://foo.example.com:80/";
-        request = new BasicClassicHttpRequest("HEAD", theURI);
-
-        cacheReturnsEntryForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() throws Exception {
-        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
-        final String theURI = "http://foo.example.com:80/";
-        request = new BasicClassicHttpRequest("HEAD", theURI);
-
-        cacheReturnsEntryForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
-        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
-        final String theURI = "http://foo.example.com:80/";
-        request = new BasicClassicHttpRequest("GET", theURI);
-
-        cacheEntryisForMethod("GET");
-        cacheReturnsEntryForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockEntry).getRequestMethod();
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws Exception {
-        request = new BasicClassicHttpRequest("GET","/");
-        request.setHeader("Cache-Control","no-cache");
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry("http://foo.example.com:80/");
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testDoesNotInvalidateRequestsWithClientPragmaHeaders() throws Exception {
-        request = new BasicClassicHttpRequest("GET","/");
-        request.setHeader("Pragma","no-cache");
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry("http://foo.example.com:80/");
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void testVariantURIsAreFlushedAlso() throws Exception {
-        request = new BasicClassicHttpRequest("POST","/");
-        final String theUri = "http://foo.example.com:80/";
-        final String variantUri = "theVariantURI";
-        final Map<String,String> mapOfURIs = HttpTestUtils.makeDefaultVariantMap(variantUri, variantUri);
-
-        cacheReturnsEntryForUri(theUri);
-        cacheEntryHasVariantMap(mapOfURIs);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry(theUri);
-        verify(mockEntry).getVariantMap();
-        verify(mockStorage).removeEntry(variantUri);
-        verify(mockStorage).removeEntry(theUri);
-    }
-
-    @Test
-    public void testCacheFlushException() throws Exception {
-        request = new BasicClassicHttpRequest("POST","/");
-        final String theURI = "http://foo.example.com:80/";
-
-        cacheReturnsExceptionForUri(theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void doesNotFlushForResponsesWithoutContentLocation()
-            throws Exception {
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntryIfFresherAndSpecifiedByContentLocation()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-    }
-
-    @Test
-    public void flushesEntryIfFresherAndSpecifiedByLocation()
-            throws Exception {
-        response.setCode(201);
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-    }
-
-    @Test
-    public void doesNotFlushEntryForUnsuccessfulResponse()
-            throws Exception {
-        response = new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, "Bad Request");
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntryIfFresherAndSpecifiedByNonCanonicalContentLocation()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String cacheKey = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", "http://foo.example.com/bar");
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(cacheKey);
-        verify(mockStorage).removeEntry(cacheKey);
-    }
-
-    @Test
-    public void flushesEntryIfFresherAndSpecifiedByRelativeContentLocation()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String cacheKey = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", "/bar");
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(cacheKey);
-        verify(mockStorage).removeEntry(cacheKey);
-    }
-
-    @Test
-    public void doesNotFlushEntryIfContentLocationFromDifferentHost()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String cacheKey = "http://baz.example.com:80/bar";
-        response.setHeader("Content-Location", cacheKey);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(cacheKey);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-
-
-    @Test
-    public void doesNotFlushEntrySpecifiedByContentLocationIfEtagsMatch()
-            throws Exception {
-        response.setHeader("ETag","\"same-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"same-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void doesNotFlushEntrySpecifiedByContentLocationIfOlder()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(now)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void doesNotFlushEntryIfNotInCache()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        when(mockStorage.getEntry(theURI)).thenReturn(null);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasNoEtag()
-            throws Exception {
-        response.removeHeaders("ETag");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasNoEtag()
-            throws Exception {
-        response.setHeader("ETag", "\"some-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntrySpecifiedByContentLocationIfResponseHasNoDate()
-            throws Exception {
-        response.setHeader("ETag", "\"new-etag\"");
-        response.removeHeaders("Date");
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-                new BasicHeader("ETag", "\"old-etag\""),
-                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntrySpecifiedByContentLocationIfEntryHasNoDate()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntrySpecifiedByContentLocationIfResponseHasMalformedDate()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", "blarg");
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-                new BasicHeader("ETag", "\"old-etag\""),
-                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo))
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void flushesEntrySpecifiedByContentLocationIfEntryHasMalformedDate()
-            throws Exception {
-        response.setHeader("ETag","\"new-etag\"");
-        response.setHeader("Date", DateUtils.formatDate(now));
-        final String theURI = "http://foo.example.com:80/bar";
-        response.setHeader("Content-Location", theURI);
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-                new BasicHeader("ETag", "\"old-etag\""),
-                new BasicHeader("Date", "foo")
-        });
-
-        when(mockStorage.getEntry(theURI)).thenReturn(entry);
-
-        impl.flushInvalidatedCacheEntries(host, request, response);
-
-        verify(mockStorage).getEntry(theURI);
-        verify(mockStorage).removeEntry(theURI);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-
-    // Expectations
-    private void cacheEntryHasVariantMap(final Map<String,String> variantMap) {
-        when(mockEntry.getVariantMap()).thenReturn(variantMap);
-    }
-
-    private void cacheReturnsEntryForUri(final String theUri) throws IOException {
-        when(mockStorage.getEntry(theUri)).thenReturn(mockEntry);
-    }
-
-    private void cacheReturnsExceptionForUri(final String theUri) throws IOException {
-        when(mockStorage.getEntry(theUri)).thenThrow(
-                new ResourceIOException("TOTAL FAIL"));
-    }
-
-    private void cacheEntryisForMethod(final String httpMethod) {
-        when(mockEntry.getRequestMethod()).thenReturn(httpMethod);
-    }
-}

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/f70c9742/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
new file mode 100644
index 0000000..5cd202a
--- /dev/null
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestDefaultCacheInvalidator.java
@@ -0,0 +1,674 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.impl.cache;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hc.client5.http.cache.HttpCacheEntry;
+import org.apache.hc.client5.http.cache.HttpCacheStorage;
+import org.apache.hc.client5.http.cache.ResourceIOException;
+import org.apache.hc.client5.http.utils.DateUtils;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestDefaultCacheInvalidator {
+
+    private DefaultCacheInvalidator impl;
+    private HttpCacheStorage mockStorage;
+    private HttpHost host;
+    private CacheKeyGenerator cacheKeyGenerator;
+    private HttpCacheEntry mockEntry;
+    private ClassicHttpRequest request;
+    private ClassicHttpResponse response;
+
+    private Date now;
+    private Date tenSecondsAgo;
+
+    @Before
+    public void setUp() {
+        now = new Date();
+        tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+
+        host = new HttpHost("foo.example.com");
+        mockStorage = mock(HttpCacheStorage.class);
+        cacheKeyGenerator = new CacheKeyGenerator();
+        mockEntry = mock(HttpCacheEntry.class);
+        request = HttpTestUtils.makeDefaultRequest();
+        response = HttpTestUtils.make200Response();
+
+        impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+    }
+
+    // Tests
+    @Test
+    public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
+        request = new BasicClassicHttpRequest("POST","/path");
+        final String theUri = "http://foo.example.com:80/path";
+        final Map<String,String> variantMap = new HashMap<>();
+        cacheEntryHasVariantMap(variantMap);
+
+        cacheReturnsEntryForUri(theUri);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+    }
+
+    @Test
+    public void testInvalidatesUrisInContentLocationHeadersOnPUTs() throws Exception {
+        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
+
+        final String contentLocation = "http://foo.example.com/content";
+        putRequest.setHeader("Content-Location", contentLocation);
+
+        final String theUri = "http://foo.example.com:80/";
+        cacheEntryHasVariantMap(new HashMap<String,String>());
+
+        cacheReturnsEntryForUri(theUri);
+
+        impl.flushInvalidatedCacheEntries(host, putRequest);
+
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
+    }
+
+    @Test
+    public void testInvalidatesUrisInLocationHeadersOnPUTs() throws Exception {
+        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
+
+        final String contentLocation = "http://foo.example.com/content";
+        putRequest.setHeader("Location",contentLocation);
+
+        final String theUri = "http://foo.example.com:80/";
+        cacheEntryHasVariantMap(new HashMap<String,String>());
+
+        cacheReturnsEntryForUri(theUri);
+
+        impl.flushInvalidatedCacheEntries(host, putRequest);
+
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry(cacheKeyGenerator.generateKey(new URI(contentLocation)));
+    }
+
+    @Test
+    public void testInvalidatesRelativeUrisInContentLocationHeadersOnPUTs() throws Exception {
+        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
+
+        final String relativePath = "/content";
+        putRequest.setHeader("Content-Location",relativePath);
+
+        final String theUri = "http://foo.example.com:80/";
+        cacheEntryHasVariantMap(new HashMap<String,String>());
+
+        cacheReturnsEntryForUri(theUri);
+
+        impl.flushInvalidatedCacheEntries(host, putRequest);
+
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
+    }
+
+    @Test
+    public void testDoesNotInvalidateUrisInContentLocationHeadersOnPUTsToDifferentHosts() throws Exception {
+        final ClassicHttpRequest putRequest = new BasicClassicHttpRequest("PUT","/");
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
+
+        final String contentLocation = "http://bar.example.com/content";
+        putRequest.setHeader("Content-Location",contentLocation);
+
+        final String theUri = "http://foo.example.com:80/";
+        cacheEntryHasVariantMap(new HashMap<String,String>());
+
+        cacheReturnsEntryForUri(theUri);
+
+        impl.flushInvalidatedCacheEntries(host, putRequest);
+
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+    }
+
+    @Test
+    public void testDoesNotInvalidateGETRequest() throws Exception {
+        request = new BasicClassicHttpRequest("GET","/");
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateHEADRequest() throws Exception {
+        request = new BasicClassicHttpRequest("HEAD","/");
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicClassicHttpRequest("GET", theURI);
+
+        cacheEntryisForMethod("HEAD");
+        cacheEntryHasVariantMap(new HashMap<String, String>());
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+    }
+
+    @Test
+    public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicClassicHttpRequest("GET", theURI);
+        final String theVariantKey = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}";
+        final String theVariantURI = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}http://foo.example.com:80/";
+        final Map<String, String> variants = HttpTestUtils.makeDefaultVariantMap(theVariantKey, theVariantURI);
+
+        cacheEntryisForMethod("HEAD");
+        cacheEntryHasVariantMap(variants);
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verify(mockStorage).removeEntry(theVariantURI);
+    }
+
+    @Test
+    public void testDoesNotInvalidateHEADCacheEntry() throws Exception {
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicClassicHttpRequest("HEAD", theURI);
+
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicClassicHttpRequest("HEAD", theURI);
+
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new DefaultCacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicClassicHttpRequest("GET", theURI);
+
+        cacheEntryisForMethod("GET");
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws Exception {
+        request = new BasicClassicHttpRequest("GET","/");
+        request.setHeader("Cache-Control","no-cache");
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateRequestsWithClientPragmaHeaders() throws Exception {
+        request = new BasicClassicHttpRequest("GET","/");
+        request.setHeader("Pragma","no-cache");
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testVariantURIsAreFlushedAlso() throws Exception {
+        request = new BasicClassicHttpRequest("POST","/");
+        final String theUri = "http://foo.example.com:80/";
+        final String variantUri = "theVariantURI";
+        final Map<String,String> mapOfURIs = HttpTestUtils.makeDefaultVariantMap(variantUri, variantUri);
+
+        cacheReturnsEntryForUri(theUri);
+        cacheEntryHasVariantMap(mapOfURIs);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theUri);
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).removeEntry(variantUri);
+        verify(mockStorage).removeEntry(theUri);
+    }
+
+    @Test
+    public void testCacheFlushException() throws Exception {
+        request = new BasicClassicHttpRequest("POST","/");
+        final String theURI = "http://foo.example.com:80/";
+
+        cacheReturnsExceptionForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void doesNotFlushForResponsesWithoutContentLocation()
+            throws Exception {
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntryIfFresherAndSpecifiedByContentLocation()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+    }
+
+    @Test
+    public void flushesEntryIfFresherAndSpecifiedByLocation()
+            throws Exception {
+        response.setCode(201);
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+    }
+
+    @Test
+    public void doesNotFlushEntryForUnsuccessfulResponse()
+            throws Exception {
+        response = new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, "Bad Request");
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntryIfFresherAndSpecifiedByNonCanonicalContentLocation()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String cacheKey = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", "http://foo.example.com/bar");
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(cacheKey);
+        verify(mockStorage).removeEntry(cacheKey);
+    }
+
+    @Test
+    public void flushesEntryIfFresherAndSpecifiedByRelativeContentLocation()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String cacheKey = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", "/bar");
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(cacheKey);
+        verify(mockStorage).removeEntry(cacheKey);
+    }
+
+    @Test
+    public void doesNotFlushEntryIfContentLocationFromDifferentHost()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String cacheKey = "http://baz.example.com:80/bar";
+        response.setHeader("Content-Location", cacheKey);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(cacheKey);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfEtagsMatch()
+            throws Exception {
+        response.setHeader("ETag","\"same-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"same-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfOlder()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(now)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void doesNotFlushEntryIfNotInCache()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        when(mockStorage.getEntry(theURI)).thenReturn(null);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasNoEtag()
+            throws Exception {
+        response.removeHeaders("ETag");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasNoEtag()
+            throws Exception {
+        response.setHeader("ETag", "\"some-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntrySpecifiedByContentLocationIfResponseHasNoDate()
+            throws Exception {
+        response.setHeader("ETag", "\"new-etag\"");
+        response.removeHeaders("Date");
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+                new BasicHeader("ETag", "\"old-etag\""),
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntrySpecifiedByContentLocationIfEntryHasNoDate()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntrySpecifiedByContentLocationIfResponseHasMalformedDate()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", "blarg");
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+                new BasicHeader("ETag", "\"old-etag\""),
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo))
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void flushesEntrySpecifiedByContentLocationIfEntryHasMalformedDate()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        final String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+                new BasicHeader("ETag", "\"old-etag\""),
+                new BasicHeader("Date", "foo")
+        });
+
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
+
+        impl.flushInvalidatedCacheEntries(host, request, response);
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+
+    // Expectations
+    private void cacheEntryHasVariantMap(final Map<String,String> variantMap) {
+        when(mockEntry.getVariantMap()).thenReturn(variantMap);
+    }
+
+    private void cacheReturnsEntryForUri(final String theUri) throws IOException {
+        when(mockStorage.getEntry(theUri)).thenReturn(mockEntry);
+    }
+
+    private void cacheReturnsExceptionForUri(final String theUri) throws IOException {
+        when(mockStorage.getEntry(theUri)).thenThrow(
+                new ResourceIOException("TOTAL FAIL"));
+    }
+
+    private void cacheEntryisForMethod(final String httpMethod) {
+        when(mockEntry.getRequestMethod()).thenReturn(httpMethod);
+    }
+}


Mime
View raw message