diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
index 0c7292cba..378251921 100644
--- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
@@ -149,7 +149,7 @@ public abstract class HttpCacheEntry implements Serializable {
public abstract Resource getResource();
- public abstract InputStream getBody();
+ public abstract InputStream getBody() throws IOException;
public abstract long getBodyLength();
diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntryFactory.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntryFactory.java
new file mode 100644
index 000000000..9dc24609a
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntryFactory.java
@@ -0,0 +1,53 @@
+/*
+ * ====================================================================
+ * 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
+ * .
+ *
+ */
+package org.apache.http.client.cache;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.http.Header;
+import org.apache.http.StatusLine;
+
+/**
+ * Generates {@link HttpCacheEntry} instances.
+ *
+ * @since 4.1
+ */
+public interface HttpCacheEntryFactory {
+
+ HttpCacheEntry generate(
+ Date requestDate,
+ Date responseDate,
+ StatusLine statusLine,
+ Header[] headers,
+ byte[] body) throws IOException;
+
+ HttpCacheEntry copyVariant(
+ HttpCacheEntry entry,
+ String variantURI) throws IOException;
+
+}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
index 0319dfd0e..2a94c440b 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
@@ -69,7 +69,7 @@ class CacheEntity implements HttpEntity, Serializable {
return this.cacheEntry.getBodyLength();
}
- public InputStream getContent() {
+ public InputStream getContent() throws IOException {
return this.cacheEntry.getBody();
}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryGenerator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryGenerator.java
index 44998b772..70667a2d9 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryGenerator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryGenerator.java
@@ -33,17 +33,20 @@ import java.util.Date;
import java.util.HashSet;
import java.util.Set;
+import org.apache.http.Header;
import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.HttpCacheEntryFactory;
/**
- * Generates a {@link CacheEntry} from a {@link HttpResponse}
+ * Generates {@link MemCacheEntry}s.
*
* @since 4.1
*/
@Immutable
-class CacheEntryGenerator {
+class CacheEntryGenerator implements HttpCacheEntryFactory {
public HttpCacheEntry generateEntry(
Date requestDate,
@@ -51,14 +54,28 @@ class CacheEntryGenerator {
HttpResponse response,
byte[] body) {
return new MemCacheEntry(requestDate,
- responseDate,
- response.getStatusLine(),
- response.getAllHeaders(),
- body,
- null);
+ responseDate,
+ response.getStatusLine(),
+ response.getAllHeaders(),
+ body,
+ null);
}
- public HttpCacheEntry copyWithVariant(
+ public HttpCacheEntry generate(
+ final Date requestDate,
+ final Date responseDate,
+ final StatusLine statusLine,
+ final Header[] headers,
+ byte[] body) throws IOException {
+ return new MemCacheEntry(requestDate,
+ responseDate,
+ statusLine,
+ headers,
+ body,
+ null);
+ }
+
+ public HttpCacheEntry copyVariant(
final HttpCacheEntry entry, final String variantURI) throws IOException {
Set variants = new HashSet(entry.getVariantURIs());
variants.add(variantURI);
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
index 6bf987dde..a667de641 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
@@ -40,6 +40,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.cache.HeaderConstants;
import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.HttpCacheEntryFactory;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.protocol.HTTP;
@@ -54,6 +55,17 @@ import org.apache.http.protocol.HTTP;
@Immutable
class CacheEntryUpdater {
+ private final HttpCacheEntryFactory cacheEntryFactory;
+
+ CacheEntryUpdater() {
+ this(new CacheEntryGenerator());
+ }
+
+ CacheEntryUpdater(final HttpCacheEntryFactory cacheEntryFactory) {
+ super();
+ this.cacheEntryFactory = cacheEntryFactory;
+ }
+
/**
* Update the entry with the new information from the response.
*
@@ -78,11 +90,12 @@ class CacheEntryUpdater {
while ((len = instream.read(buf)) != -1) {
outstream.write(buf, 0, len);
}
- HttpCacheEntry updated = new MemCacheEntry(requestDate, responseDate,
- entry.getStatusLine(),
- mergedHeaders,
- outstream.toByteArray(),
- null);
+ HttpCacheEntry updated = cacheEntryFactory.generate(
+ requestDate,
+ responseDate,
+ entry.getStatusLine(),
+ mergedHeaders,
+ outstream.toByteArray());
return updated;
}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
index e5dec67d7..33e777aac 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
@@ -50,6 +50,7 @@ import org.apache.http.client.ResponseHandler;
import org.apache.http.client.cache.HeaderConstants;
import org.apache.http.client.cache.HttpCache;
import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.HttpCacheEntryFactory;
import org.apache.http.client.cache.HttpCacheUpdateCallback;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
@@ -75,9 +76,9 @@ public class CachingHttpClient implements HttpClient {
private final HttpClient backend;
private final HttpCache responseCache;
+ private final HttpCacheEntryFactory cacheEntryFactory;
private final CacheValidityPolicy validityPolicy;
private final ResponseCachingPolicy responseCachingPolicy;
- private final CacheEntryGenerator cacheEntryGenerator;
private final URIExtractor uriExtractor;
private final CachedHttpResponseGenerator responseGenerator;
private final CacheInvalidator cacheInvalidator;
@@ -96,7 +97,11 @@ public class CachingHttpClient implements HttpClient {
private final Log log = LogFactory.getLog(getClass());
- public CachingHttpClient(HttpClient client, HttpCache cache, CacheConfig config) {
+ public CachingHttpClient(
+ HttpClient client,
+ HttpCache cache,
+ HttpCacheEntryFactory cacheEntryFactory,
+ CacheConfig config) {
super();
if (client == null) {
throw new IllegalArgumentException("HttpClient may not be null");
@@ -104,6 +109,9 @@ public class CachingHttpClient implements HttpClient {
if (cache == null) {
throw new IllegalArgumentException("HttpCache may not be null");
}
+ if (cacheEntryFactory == null) {
+ throw new IllegalArgumentException("HttpCacheEntryFactory may not be null");
+ }
if (config == null) {
throw new IllegalArgumentException("CacheConfig may not be null");
}
@@ -111,51 +119,81 @@ public class CachingHttpClient implements HttpClient {
this.sharedCache = config.isSharedCache();
this.backend = client;
this.responseCache = cache;
+ this.cacheEntryFactory = cacheEntryFactory;
+
this.validityPolicy = new CacheValidityPolicy();
this.responseCachingPolicy = new ResponseCachingPolicy(maxObjectSizeBytes, sharedCache);
this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy);
- this.cacheEntryGenerator = new CacheEntryGenerator();
this.uriExtractor = new URIExtractor();
this.cacheInvalidator = new CacheInvalidator(this.uriExtractor, this.responseCache);
this.cacheableRequestPolicy = new CacheableRequestPolicy();
this.suitabilityChecker = new CachedResponseSuitabilityChecker(this.validityPolicy);
this.conditionalRequestBuilder = new ConditionalRequestBuilder();
- this.cacheEntryUpdater = new CacheEntryUpdater();
+ this.cacheEntryUpdater = new CacheEntryUpdater(this.cacheEntryFactory);
this.responseCompliance = new ResponseProtocolCompliance();
this.requestCompliance = new RequestProtocolCompliance();
}
public CachingHttpClient() {
- this(new DefaultHttpClient(), new BasicHttpCache(MAX_CACHE_ENTRIES), new CacheConfig());
+ this(new DefaultHttpClient(),
+ new BasicHttpCache(MAX_CACHE_ENTRIES),
+ new CacheEntryGenerator(),
+ new CacheConfig());
}
public CachingHttpClient(CacheConfig config) {
- this(new DefaultHttpClient(), new BasicHttpCache(MAX_CACHE_ENTRIES), config);
+ this(new DefaultHttpClient(),
+ new BasicHttpCache(MAX_CACHE_ENTRIES),
+ new CacheEntryGenerator(),
+ config);
}
public CachingHttpClient(HttpClient client) {
- this(client, new BasicHttpCache(MAX_CACHE_ENTRIES), new CacheConfig());
+ this(client,
+ new BasicHttpCache(MAX_CACHE_ENTRIES),
+ new CacheEntryGenerator(),
+ new CacheConfig());
}
public CachingHttpClient(HttpClient client, CacheConfig config) {
- this(client, new BasicHttpCache(MAX_CACHE_ENTRIES), config);
+ this(client,
+ new BasicHttpCache(MAX_CACHE_ENTRIES),
+ new CacheEntryGenerator(),
+ config);
}
- public CachingHttpClient(HttpCache cache) {
- this(new DefaultHttpClient(), cache, new CacheConfig());
+ public CachingHttpClient(
+ HttpCache cache,
+ HttpCacheEntryFactory cacheEntryFactory) {
+ this(new DefaultHttpClient(),
+ cache,
+ cacheEntryFactory,
+ new CacheConfig());
}
- public CachingHttpClient(HttpCache cache, CacheConfig config) {
- this(new DefaultHttpClient(), cache, config);
+ public CachingHttpClient(
+ HttpCache cache,
+ HttpCacheEntryFactory cacheEntryFactory,
+ CacheConfig config) {
+ this(new DefaultHttpClient(),
+ cache,
+ cacheEntryFactory,
+ config);
}
- public CachingHttpClient(HttpClient client, HttpCache cache) {
- this(client, cache, new CacheConfig());
+ public CachingHttpClient(
+ HttpClient client,
+ HttpCache cache,
+ HttpCacheEntryFactory cacheEntryFactory) {
+ this(client,
+ cache,
+ cacheEntryFactory,
+ new CacheConfig());
}
CachingHttpClient(HttpClient backend, CacheValidityPolicy validityPolicy, ResponseCachingPolicy responseCachingPolicy,
- CacheEntryGenerator cacheEntryGenerator, URIExtractor uriExtractor,
+ HttpCacheEntryFactory cacheEntryFactory, URIExtractor uriExtractor,
HttpCache responseCache, CachedHttpResponseGenerator responseGenerator,
CacheInvalidator cacheInvalidator, CacheableRequestPolicy cacheableRequestPolicy,
CachedResponseSuitabilityChecker suitabilityChecker,
@@ -166,9 +204,9 @@ public class CachingHttpClient implements HttpClient {
this.maxObjectSizeBytes = config.getMaxObjectSizeBytes();
this.sharedCache = config.isSharedCache();
this.backend = backend;
+ this.cacheEntryFactory = cacheEntryFactory;
this.validityPolicy = validityPolicy;
this.responseCachingPolicy = responseCachingPolicy;
- this.cacheEntryGenerator = cacheEntryGenerator;
this.uriExtractor = uriExtractor;
this.responseCache = responseCache;
this.responseGenerator = responseGenerator;
@@ -532,9 +570,9 @@ public class CachingHttpClient implements HttpClient {
HttpCacheEntry existing,
HttpCacheEntry entry, String variantURI) throws IOException {
if (existing != null) {
- return cacheEntryGenerator.copyWithVariant(existing, variantURI);
+ return cacheEntryFactory.copyVariant(existing, variantURI);
} else {
- return cacheEntryGenerator.copyWithVariant(entry, variantURI);
+ return cacheEntryFactory.copyVariant(entry, variantURI);
}
}
@@ -590,9 +628,12 @@ public class CachingHttpClient implements HttpClient {
responseBytes);
int correctedStatus = corrected.getStatusLine().getStatusCode();
if (HttpStatus.SC_BAD_GATEWAY != correctedStatus) {
- HttpCacheEntry entry = cacheEntryGenerator
- .generateEntry(requestDate, responseDate, corrected,
- responseBytes);
+ HttpCacheEntry entry = cacheEntryFactory.generate(
+ requestDate,
+ responseDate,
+ corrected.getStatusLine(),
+ corrected.getAllHeaders(),
+ responseBytes);
storeInCache(target, request, entry);
return responseGenerator.generateResponse(entry);
}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileCacheEntry.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileCacheEntry.java
new file mode 100644
index 000000000..60420d003
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileCacheEntry.java
@@ -0,0 +1,98 @@
+/*
+ * ====================================================================
+ * 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
+ * .
+ *
+ */
+package org.apache.http.impl.client.cache;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.Set;
+
+import org.apache.http.Header;
+import org.apache.http.StatusLine;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.Resource;
+
+/**
+ * {@link File} backed {@link HttpCacheEntry} that requires explicit deallocation.
+ */
+@Immutable
+class FileCacheEntry extends HttpCacheEntry {
+
+ private static final long serialVersionUID = -8396589100351931966L;
+
+ private final File file;
+ private final FileResource resource;
+
+ public FileCacheEntry(
+ final Date requestDate,
+ final Date responseDate,
+ final StatusLine statusLine,
+ final Header[] responseHeaders,
+ final File file,
+ final Set variants) {
+ super(requestDate, responseDate, statusLine, responseHeaders, variants);
+ this.file = file;
+ this.resource = new FileResource(file);
+ }
+
+ @Override
+ public long getBodyLength() {
+ return this.file.length();
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return new FileInputStream(this.file);
+ }
+
+ @Override
+ public Resource getResource() {
+ return this.resource;
+ }
+
+ class FileResource implements Resource {
+
+ private File file;
+
+ FileResource(final File file) {
+ super();
+ this.file = file;
+ }
+
+ public synchronized void dispose() {
+ if (this.file != null) {
+ this.file.delete();
+ this.file = null;
+ }
+ }
+
+ }
+
+}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCache.java
new file mode 100644
index 000000000..cac9f5439
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCache.java
@@ -0,0 +1,171 @@
+/*
+ * ====================================================================
+ * 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
+ * .
+ *
+ */
+package org.apache.http.impl.client.cache;
+
+import java.io.IOException;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.client.cache.HttpCache;
+import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.HttpCacheUpdateCallback;
+import org.apache.http.client.cache.Resource;
+
+/**
+ * {@link HttpCache} implementation capable of deallocating resources associated with
+ * the cache entries. This cache keeps track of cache entries using {@link PhantomReference}
+ * and maintains a collection of all resources that are no longer in use. The cache, however,
+ * does not automatically deallocates associated resources by invoking {@link Resource#dispose()}
+ * method. The consumer MUST periodically call {@link #cleanResources()} method to trigger
+ * resource deallocation. The cache can be permanently shut down using {@link #shutdown()}
+ * method. All resources associated with the entries used by the cache will be deallocated.
+ *
+ * This {@link HttpCache} implementation is intended for use with {@link FileCacheEntry}
+ * and similar.
+ *
+ * @since 4.1
+ */
+@ThreadSafe
+public class ManagedHttpCache implements HttpCache {
+
+ private final CacheMap entries;
+ private final ReferenceQueue morque;
+ private final Set resources;
+
+ private volatile boolean shutdown;
+
+ public ManagedHttpCache(int maxEntries) {
+ super();
+ this.entries = new CacheMap(maxEntries);
+ this.morque = new ReferenceQueue();
+ this.resources = new HashSet();
+ }
+
+ private void ensureValidState() throws IllegalStateException {
+ if (this.shutdown) {
+ throw new IllegalStateException("Cache has been shut down");
+ }
+ }
+
+ private void keepResourceReference(final HttpCacheEntry entry) {
+ Resource resource = entry.getResource();
+ if (resource != null) {
+ // Must deallocate the resource when the entry is no longer in used
+ ResourceReference ref = new ResourceReference(entry, this.morque);
+ this.resources.add(ref);
+ }
+ }
+
+ public void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
+ if (url == null) {
+ throw new IllegalArgumentException("URL may not be null");
+ }
+ if (entry == null) {
+ throw new IllegalArgumentException("Cache entry may not be null");
+ }
+ ensureValidState();
+ synchronized (this) {
+ this.entries.put(url, entry);
+ keepResourceReference(entry);
+ }
+ }
+
+ public HttpCacheEntry getEntry(final String url) throws IOException {
+ if (url == null) {
+ throw new IllegalArgumentException("URL may not be null");
+ }
+ ensureValidState();
+ synchronized (this) {
+ return this.entries.get(url);
+ }
+ }
+
+ public void removeEntry(String url) throws IOException {
+ if (url == null) {
+ throw new IllegalArgumentException("URL may not be null");
+ }
+ ensureValidState();
+ synchronized (this) {
+ // Cannot deallocate the associated resources immediately as the
+ // cache entry may still be in use
+ this.entries.remove(url);
+ }
+ }
+
+ public void updateEntry(
+ final String url,
+ final HttpCacheUpdateCallback callback) throws IOException {
+ if (url == null) {
+ throw new IllegalArgumentException("URL may not be null");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback may not be null");
+ }
+ ensureValidState();
+ synchronized (this) {
+ HttpCacheEntry existing = this.entries.get(url);
+ HttpCacheEntry updated = callback.update(existing);
+ this.entries.put(url, updated);
+ if (existing != updated) {
+ keepResourceReference(updated);
+ }
+ }
+ }
+
+ public void cleanResources() {
+ if (this.shutdown) {
+ return;
+ }
+ ResourceReference ref;
+ while ((ref = (ResourceReference) this.morque.poll()) != null) {
+ synchronized (this) {
+ this.resources.remove(ref);
+ }
+ ref.getResource().dispose();
+ }
+ }
+
+ public void shutdown() {
+ if (this.shutdown) {
+ return;
+ }
+ this.shutdown = true;
+ synchronized (this) {
+ this.entries.clear();
+ for (ResourceReference ref: this.resources) {
+ ref.getResource().dispose();
+ }
+ this.resources.clear();
+ while (this.morque.poll() != null) {
+ }
+ }
+ }
+
+}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/MemCacheEntry.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/MemCacheEntry.java
index 4b809bdc2..9bcd06c79 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/MemCacheEntry.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/MemCacheEntry.java
@@ -42,7 +42,7 @@ import org.apache.http.client.cache.Resource;
* explicit deallocation.
*/
@Immutable
-public class MemCacheEntry extends HttpCacheEntry {
+class MemCacheEntry extends HttpCacheEntry {
private static final long serialVersionUID = -8464486112875881235L;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResourceReference.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResourceReference.java
new file mode 100644
index 000000000..91e9a0b16
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResourceReference.java
@@ -0,0 +1,63 @@
+/*
+ * ====================================================================
+ * 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
+ * .
+ *
+ */
+package org.apache.http.impl.client.cache;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.cache.Resource;
+
+@Immutable
+class ResourceReference extends PhantomReference {
+
+ private final Resource resource;
+
+ public ResourceReference(final HttpCacheEntry entry, final ReferenceQueue q) {
+ super(entry, q);
+ if (entry.getResource() == null) {
+ throw new IllegalArgumentException("Resource may not be null");
+ }
+ this.resource = entry.getResource();
+ }
+
+ public Resource getResource() {
+ return this.resource;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.resource.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return this.resource.equals(obj);
+ }
+
+}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
index d0d9f14b3..62b4b0471 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
@@ -10,6 +10,7 @@ import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.cache.HttpCache;
+import org.apache.http.client.cache.HttpCacheEntryFactory;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.BasicHttpResponse;
@@ -32,7 +33,8 @@ public abstract class AbstractProtocolTest {
protected HttpResponse originResponse;
protected CacheConfig params;
protected CachingHttpClient impl;
- private HttpCache cache;
+ protected HttpCache cache;
+ protected HttpCacheEntryFactory cacheEntryFactory;
public static HttpRequest eqRequest(HttpRequest in) {
EasyMock.reportMatcher(new RequestEquivalent(in));
@@ -50,12 +52,13 @@ public abstract class AbstractProtocolTest {
originResponse = make200Response();
cache = new BasicHttpCache(MAX_ENTRIES);
+ cacheEntryFactory = new CacheEntryGenerator();
mockBackend = EasyMock.createMock(HttpClient.class);
mockEntity = EasyMock.createMock(HttpEntity.class);
mockCache = EasyMock.createMock(HttpCache.class);
params = new CacheConfig();
params.setMaxObjectSizeBytes(MAX_BYTES);
- impl = new CachingHttpClient(mockBackend, cache, params);
+ impl = new CachingHttpClient(mockBackend, cache, cacheEntryFactory, params);
}
protected void replayMocks() {
@@ -94,7 +97,7 @@ public abstract class AbstractProtocolTest {
mockCache = EasyMock.createMock(HttpCache.class);
mockEntity = EasyMock.createMock(HttpEntity.class);
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
EasyMock.expect(mockCache.getEntry((String) EasyMock.anyObject())).andReturn(null)
.anyTimes();
@@ -105,7 +108,7 @@ public abstract class AbstractProtocolTest {
protected void behaveAsNonSharedCache() {
params.setSharedCache(false);
- impl = new CachingHttpClient(mockBackend, cache, params);
+ impl = new CachingHttpClient(mockBackend, cache, cacheEntryFactory, params);
}
public AbstractProtocolTest() {
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DoNotTestProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DoNotTestProtocolRequirements.java
index 36d8383af..47cfc4967 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DoNotTestProtocolRequirements.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DoNotTestProtocolRequirements.java
@@ -82,7 +82,7 @@ public class DoNotTestProtocolRequirements {
mockCache = EasyMock.createMock(HttpCache.class);
CacheConfig params = new CacheConfig();
params.setMaxObjectSizeBytes(MAX_BYTES);
- impl = new CachingHttpClient(mockBackend, cache, params);
+ impl = new CachingHttpClient(mockBackend, cache, new CacheEntryGenerator(), params);
}
private HttpResponse make200Response() {
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntry.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntry.java
index 055a6f41a..9a1d584de 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntry.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntry.java
@@ -110,8 +110,8 @@ public class TestCacheEntry {
CacheEntryGenerator entryGenerator = new CacheEntryGenerator();
- HttpCacheEntry addedOne = entryGenerator.copyWithVariant(entry, "foo");
- HttpCacheEntry addedTwo = entryGenerator.copyWithVariant(addedOne, "bar");
+ HttpCacheEntry addedOne = entryGenerator.copyVariant(entry, "foo");
+ HttpCacheEntry addedTwo = entryGenerator.copyVariant(addedOne, "bar");
Set variants = addedTwo.getVariantURIs();
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
index 9dfa6a1d9..7b98f3ff5 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
@@ -26,7 +26,6 @@
*/
package org.apache.http.impl.client.cache;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
@@ -40,8 +39,8 @@ import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
import org.apache.http.ProtocolException;
-import org.apache.http.ProtocolVersion;
import org.apache.http.RequestLine;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
@@ -49,16 +48,10 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.cache.HttpCache;
import org.apache.http.client.cache.HttpCacheEntry;
-import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.cache.HttpCacheEntryFactory;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.params.HttpParams;
@@ -66,13 +59,10 @@ import org.apache.http.protocol.HttpContext;
import org.easymock.classextension.EasyMock;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class TestCachingHttpClient {
- private static final ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP",1,1);
-
private static final String GET_CURRENT_DATE = "getCurrentDate";
private static final String HANDLE_BACKEND_RESPONSE = "handleBackendResponse";
@@ -87,6 +77,9 @@ public class TestCachingHttpClient {
private static final String GET_RESPONSE_READER = "getResponseReader";
+ private static final StatusLine SC_OK = new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK");
+ private static final Header[] HEADERS = new Header[] {};
+
private CachingHttpClient impl;
private boolean mockedImpl;
@@ -103,7 +96,7 @@ public class TestCachingHttpClient {
private CacheEntry mockVariantCacheEntry;
private CacheEntry mockUpdatedCacheEntry;
private URIExtractor mockExtractor;
- private CacheEntryGenerator mockEntryGenerator;
+ private HttpCacheEntryFactory mockEntryGenerator;
private CachedHttpResponseGenerator mockResponseGenerator;
private SizeLimitedResponseReader mockResponseReader;
@@ -151,7 +144,7 @@ public class TestCachingHttpClient {
mockUpdatedCacheEntry = EasyMock.createMock(CacheEntry.class);
mockVariantCacheEntry = EasyMock.createMock(CacheEntry.class);
mockExtractor = EasyMock.createMock(URIExtractor.class);
- mockEntryGenerator = EasyMock.createMock(CacheEntryGenerator.class);
+ mockEntryGenerator = EasyMock.createMock(HttpCacheEntryFactory.class);
mockResponseGenerator = EasyMock.createMock(CachedHttpResponseGenerator.class);
mockCachedResponse = EasyMock.createMock(HttpResponse.class);
mockConditionalRequestBuilder = EasyMock.createMock(ConditionalRequestBuilder.class);
@@ -259,6 +252,7 @@ public class TestCachingHttpClient {
storeInCacheWasCalled();
responseIsGeneratedFromCache();
responseStatusLineIsInspectable();
+ responseGetHeaders();
responseDoesNotHaveExplicitContentLength();
replayMocks();
@@ -602,6 +596,7 @@ public class TestCachingHttpClient {
storeInCacheWasCalled();
responseIsGeneratedFromCache();
responseStatusLineIsInspectable();
+ responseGetHeaders();
responseDoesNotHaveExplicitContentLength();
replayMocks();
@@ -863,34 +858,6 @@ public class TestCachingHttpClient {
Assert.assertSame(mockParams, result);
}
- @Test
- @Ignore
- public void testRealResultsMatch() throws IOException {
-
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
- schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
-
- ClientConnectionManager cm = new ThreadSafeClientConnManager(schemeRegistry);
- HttpClient httpClient = new DefaultHttpClient(cm);
-
- HttpCache cacheImpl = new BasicHttpCache(100);
-
- CachingHttpClient cachingClient = new CachingHttpClient(httpClient, cacheImpl);
-
- HttpUriRequest request = new HttpGet("http://www.fancast.com/static-28262/styles/base.css");
-
- HttpClient baseClient = new DefaultHttpClient();
-
- HttpResponse cachedResponse = cachingClient.execute(request);
- HttpResponse realResponse = baseClient.execute(request);
-
- byte[] cached = readResponse(cachedResponse);
- byte[] real = readResponse(realResponse);
-
- Assert.assertArrayEquals(cached, real);
- }
-
@Test
public void testResponseIsGeneratedWhenCacheEntryIsUsable() throws Exception {
@@ -936,7 +903,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseDoesNotCorrectComplete200Response()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","128");
@@ -948,7 +915,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseDoesNotCorrectComplete206Response()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","128");
@@ -961,7 +928,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseGenerates502ForIncomplete200Response()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
@@ -973,7 +940,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseDoesNotCorrectIncompleteNon200Or206Responses()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_FORBIDDEN, "Forbidden");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_FORBIDDEN, "Forbidden");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
@@ -985,7 +952,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseDoesNotCorrectResponsesWithoutExplicitContentLength()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
@@ -996,7 +963,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseDoesNotCorrectResponsesWithUnparseableContentLengthHeader()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setHeader("Content-Length","foo");
resp.setEntity(new ByteArrayEntity(bytes));
@@ -1008,7 +975,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseProvidesPlainTextErrorMessage()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
@@ -1021,7 +988,7 @@ public class TestCachingHttpClient {
@Test
public void testCorrectIncompleteResponseProvidesNonEmptyErrorMessage()
throws Exception {
- HttpResponse resp = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
@@ -1048,18 +1015,6 @@ public class TestCachingHttpClient {
Assert.assertTrue(impl.isSharedCache());
}
- private byte[] readResponse(HttpResponse response) {
- try {
- ByteArrayOutputStream s1 = new ByteArrayOutputStream();
- response.getEntity().writeTo(s1);
- return s1.toByteArray();
- } catch (Exception ex) {
- return new byte[]{};
-
- }
-
- }
-
private void cacheInvalidatorWasCalled() throws IOException {
mockInvalidator.flushInvalidatedCacheEntries(host, mockRequest);
}
@@ -1182,9 +1137,11 @@ public class TestCachingHttpClient {
}
private void responseStatusLineIsInspectable() {
- StatusLine statusLine = new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, "OK");
- EasyMock.expect(mockBackendResponse.getStatusLine())
- .andReturn(statusLine).anyTimes();
+ EasyMock.expect(mockBackendResponse.getStatusLine()).andReturn(SC_OK).anyTimes();
+ }
+
+ private void responseGetHeaders() {
+ EasyMock.expect(mockBackendResponse.getAllHeaders()).andReturn(HEADERS).anyTimes();
}
private void responseIsGeneratedFromCache(CacheEntry entry) {
@@ -1214,15 +1171,15 @@ public class TestCachingHttpClient {
mockCache.putEntry(theURI, entry);
}
- private void generateCacheEntry(Date requestDate, Date responseDate, byte[] bytes) {
+ private void generateCacheEntry(Date requestDate, Date responseDate, byte[] bytes) throws IOException {
EasyMock.expect(
- mockEntryGenerator.generateEntry(requestDate, responseDate, mockBackendResponse,
- bytes)).andReturn(mockCacheEntry);
+ mockEntryGenerator.generate(requestDate, responseDate, SC_OK, HEADERS,
+ bytes)).andReturn(mockCacheEntry);
}
private void copyCacheEntry(CacheEntry entry, String variantURI) throws IOException {
EasyMock.expect(
- mockEntryGenerator.copyWithVariant(entry, variantURI)).andReturn(entry);
+ mockEntryGenerator.copyVariant(entry, variantURI)).andReturn(entry);
}
private void handleBackendResponseReturnsResponse(HttpRequest request, HttpResponse response)
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
index d6a7b2619..b8b3ddee2 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
@@ -100,7 +100,7 @@ public class TestProtocolDeviations {
CacheConfig params = new CacheConfig();
params.setMaxObjectSizeBytes(MAX_BYTES);
- impl = new CachingHttpClient(mockBackend, cache, params);
+ impl = new CachingHttpClient(mockBackend, cache, new CacheEntryGenerator(), params);
}
private HttpResponse make200Response() {
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
index f3a45853a..a15013fba 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
@@ -2221,7 +2221,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
mockCache.putEntry(EasyMock.eq("http://foo.example.com/thing"), EasyMock.isA(HttpCacheEntry.class));
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
HttpRequest validate = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1);
validate.setHeader("If-None-Match", "\"etag\"");
@@ -2263,7 +2263,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes);
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry);
@@ -2304,7 +2304,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes);
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry);
EasyMock.expect(
@@ -2505,7 +2505,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes);
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry);
@@ -2549,7 +2549,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
CacheEntry entry = new CacheEntry(requestTime, responseTime, hdrs, bytes);
- impl = new CachingHttpClient(mockBackend, mockCache, params);
+ impl = new CachingHttpClient(mockBackend, mockCache, cacheEntryFactory, params);
HttpResponse validated = make200Response();
validated.setHeader("Cache-Control", "public");