diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCache.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCache.java index 7eb696b37..67ac0827e 100644 --- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCache.java @@ -27,19 +27,34 @@ package org.apache.http.client.cache; import java.io.IOException; +import java.util.Date; + +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; /** * @since 4.1 */ public interface HttpCache { - void putEntry(String key, HttpCacheEntry entry) throws IOException; + void flushCacheEntriesFor(HttpHost host, HttpRequest request) + throws IOException; - HttpCacheEntry getEntry(String key) throws IOException; + void flushInvalidatedCacheEntriesFor(HttpHost host, HttpRequest request) + throws IOException; - void removeEntry(String key) throws IOException; + HttpCacheEntry getCacheEntry(HttpHost host, HttpRequest request) + throws IOException; - void updateEntry( - String key, HttpCacheUpdateCallback callback) throws IOException; + HttpResponse cacheAndReturnResponse( + HttpHost host, HttpRequest request, HttpResponse originResponse, + Date requestSent, Date responseReceived) + throws IOException; + + HttpResponse updateCacheEntry( + HttpHost target, HttpRequest request, HttpCacheEntry stale, HttpResponse originResponse, + Date requestSent, Date responseReceived) + throws IOException; } diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java new file mode 100644 index 000000000..bde082a9c --- /dev/null +++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java @@ -0,0 +1,45 @@ +/* + * ==================================================================== + * 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; + +/** + * @since 4.1 + */ +public interface HttpCacheStorage { + + void putEntry(String key, HttpCacheEntry entry) throws IOException; + + HttpCacheEntry getEntry(String key) throws IOException; + + void removeEntry(String key) throws IOException; + + void updateEntry( + String key, HttpCacheUpdateCallback callback) throws IOException; + +} diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java index e31e74306..ea91ce0ba 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java @@ -1,93 +1,204 @@ -/* - * ==================================================================== - * 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.util.LinkedHashMap; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; -import org.apache.http.annotation.ThreadSafe; +import org.apache.http.Header; +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.client.cache.HttpCache; import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.HttpCacheStorage; import org.apache.http.client.cache.HttpCacheUpdateCallback; +import org.apache.http.client.cache.Resource; +import org.apache.http.client.cache.ResourceFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.message.BasicHttpResponse; -/** - * Basic {@link HttpCache} implementation backed by an instance of {@link LinkedHashMap}. - * This cache does NOT deallocate resources associated with the cache entries. It is intended - * for use with {@link MemCacheEntry} and similar. - * - * @since 4.1 - */ -@ThreadSafe public class BasicHttpCache implements HttpCache { - private final CacheMap entries; + private final URIExtractor uriExtractor; + private final ResourceFactory resourceFactory; + private final int maxObjectSizeBytes; + private final CacheEntryUpdater cacheEntryUpdater; + private final CachedHttpResponseGenerator responseGenerator; + private final CacheInvalidator cacheInvalidator; + private final HttpCacheStorage storage; - public BasicHttpCache(int maxEntries) { - this.entries = new CacheMap(maxEntries); + public BasicHttpCache(ResourceFactory resourceFactory, HttpCacheStorage storage, CacheConfig config) { + this.resourceFactory = resourceFactory; + this.uriExtractor = new URIExtractor(); + this.cacheEntryUpdater = new CacheEntryUpdater(resourceFactory); + this.maxObjectSizeBytes = config.getMaxObjectSizeBytes(); + this.responseGenerator = new CachedHttpResponseGenerator(); + this.storage = storage; + this.cacheInvalidator = new CacheInvalidator(this.uriExtractor, this.storage); } - /** - * Places a HttpCacheEntry in the cache - * - * @param url - * Url to use as the cache key - * @param entry - * HttpCacheEntry to place in the cache - */ - public synchronized void putEntry(String url, HttpCacheEntry entry) throws IOException { - entries.put(url, entry); + public BasicHttpCache(CacheConfig config) { + this(new HeapResourceFactory(), new BasicHttpCacheStorage(config), config); } - /** - * Gets an entry from the cache, if it exists - * - * @param url - * Url that is the cache key - * @return HttpCacheEntry if one exists, or null for cache miss - */ - public synchronized HttpCacheEntry getEntry(String url) throws IOException { - return entries.get(url); + public BasicHttpCache() { + this(new CacheConfig()); } - /** - * Removes a HttpCacheEntry from the cache - * - * @param url - * Url that is the cache key - */ - public synchronized void removeEntry(String url) throws IOException { - entries.remove(url); + public void flushCacheEntriesFor(HttpHost host, HttpRequest request) + throws IOException { + String uri = uriExtractor.getURI(host, request); + storage.removeEntry(uri); } - public synchronized void updateEntry( - String url, - HttpCacheUpdateCallback callback) throws IOException { - HttpCacheEntry existingEntry = entries.get(url); - entries.put(url, callback.update(existingEntry)); + void storeInCache( + HttpHost target, HttpRequest request, HttpCacheEntry entry) throws IOException { + if (entry.hasVariants()) { + storeVariantEntry(target, request, entry); + } else { + storeNonVariantEntry(target, request, entry); + } } -} + void storeNonVariantEntry( + HttpHost target, HttpRequest req, HttpCacheEntry entry) throws IOException { + String uri = uriExtractor.getURI(target, req); + storage.putEntry(uri, entry); + } + + void storeVariantEntry( + final HttpHost target, + final HttpRequest req, + final HttpCacheEntry entry) throws IOException { + final String parentURI = uriExtractor.getURI(target, req); + final String variantURI = uriExtractor.getVariantURI(target, req, entry); + storage.putEntry(variantURI, entry); + + HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() { + + public HttpCacheEntry update(HttpCacheEntry existing) throws IOException { + return doGetUpdatedParentEntry( + req.getRequestLine().getUri(), existing, entry, variantURI); + } + + }; + storage.updateEntry(parentURI, callback); + } + + + boolean isIncompleteResponse(HttpResponse resp, Resource resource) { + int status = resp.getStatusLine().getStatusCode(); + if (status != HttpStatus.SC_OK + && status != HttpStatus.SC_PARTIAL_CONTENT) { + return false; + } + Header hdr = resp.getFirstHeader("Content-Length"); + if (hdr == null) return false; + int contentLength; + try { + contentLength = Integer.parseInt(hdr.getValue()); + } catch (NumberFormatException nfe) { + return false; + } + return (resource.length() < contentLength); + } + + HttpResponse generateIncompleteResponseError(HttpResponse response, + Resource resource) { + int contentLength = Integer.parseInt(response.getFirstHeader("Content-Length").getValue()); + HttpResponse error = + new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_GATEWAY, "Bad Gateway"); + error.setHeader("Content-Type","text/plain;charset=UTF-8"); + String msg = String.format("Received incomplete response " + + "with Content-Length %d but actual body length %d", + contentLength, resource.length()); + byte[] msgBytes = msg.getBytes(); + error.setHeader("Content-Length", Integer.toString(msgBytes.length)); + error.setEntity(new ByteArrayEntity(msgBytes)); + return error; + } + + HttpCacheEntry doGetUpdatedParentEntry( + final String requestId, + final HttpCacheEntry existing, + final HttpCacheEntry entry, + final String variantURI) throws IOException { + HttpCacheEntry src = existing; + if (src == null) { + src = entry; + } + Set variants = new HashSet(src.getVariantURIs()); + variants.add(variantURI); + Resource resource = resourceFactory.copy(requestId, src.getResource()); + return new HttpCacheEntry( + src.getRequestDate(), + src.getResponseDate(), + src.getStatusLine(), + src.getAllHeaders(), + resource, + variants); + } + + public HttpResponse updateCacheEntry(HttpHost target, HttpRequest request, + HttpCacheEntry stale, HttpResponse originResponse, + Date requestSent, Date responseReceived) throws IOException { + HttpCacheEntry updatedEntry = cacheEntryUpdater.updateCacheEntry( + request.getRequestLine().getUri(), + stale, + requestSent, + responseReceived, + originResponse); + storeInCache(target, request, updatedEntry); + return responseGenerator.generateResponse(updatedEntry); + } + + public HttpResponse cacheAndReturnResponse(HttpHost host, HttpRequest request, + HttpResponse originResponse, Date requestSent, Date responseReceived) + throws IOException { + + SizeLimitedResponseReader responseReader = getResponseReader(request, originResponse); + responseReader.readResponse(); + + if (responseReader.isLimitReached()) { + return responseReader.getReconstructedResponse(); + } + + Resource resource = responseReader.getResource(); + if (isIncompleteResponse(originResponse, resource)) { + return generateIncompleteResponseError(originResponse, resource); + } + + HttpCacheEntry entry = new HttpCacheEntry( + requestSent, + responseReceived, + originResponse.getStatusLine(), + originResponse.getAllHeaders(), + resource, + null); + storeInCache(host, request, entry); + return responseGenerator.generateResponse(entry); + } + + SizeLimitedResponseReader getResponseReader(HttpRequest request, HttpResponse backEndResponse) { + return new SizeLimitedResponseReader( + resourceFactory, maxObjectSizeBytes, request, backEndResponse); + } + + public HttpCacheEntry getCacheEntry(HttpHost host, HttpRequest request) throws IOException { + HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request)); + if (root == null) return null; + if (!root.hasVariants()) return root; + HttpCacheEntry variant = storage.getEntry(uriExtractor.getVariantURI(host, request, root)); + return variant; + } + + public void flushInvalidatedCacheEntriesFor(HttpHost host, + HttpRequest request) throws IOException { + cacheInvalidator.flushInvalidatedCacheEntries(host, request); + + } + +} \ No newline at end of file diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java new file mode 100644 index 000000000..2221cc0f7 --- /dev/null +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java @@ -0,0 +1,94 @@ +/* + * ==================================================================== + * 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.util.LinkedHashMap; + +import org.apache.http.annotation.ThreadSafe; +import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.HttpCacheStorage; +import org.apache.http.client.cache.HttpCacheUpdateCallback; + +/** + * Basic {@link HttpCacheStorage} implementation backed by an instance of {@link LinkedHashMap}. + * This cache does NOT deallocate resources associated with the cache entries. It is intended + * for use with {@link MemCacheEntry} and similar. + * + * @since 4.1 + */ +@ThreadSafe +public class BasicHttpCacheStorage implements HttpCacheStorage { + + private final CacheMap entries; + + public BasicHttpCacheStorage(CacheConfig config) { + super(); + this.entries = new CacheMap(config.getMaxCacheEntries()); + } + + /** + * Places a HttpCacheEntry in the cache + * + * @param url + * Url to use as the cache key + * @param entry + * HttpCacheEntry to place in the cache + */ + public synchronized void putEntry(String url, HttpCacheEntry entry) throws IOException { + entries.put(url, entry); + } + + /** + * Gets an entry from the cache, if it exists + * + * @param url + * Url that is the cache key + * @return HttpCacheEntry if one exists, or null for cache miss + */ + public synchronized HttpCacheEntry getEntry(String url) throws IOException { + return entries.get(url); + } + + /** + * Removes a HttpCacheEntry from the cache + * + * @param url + * Url that is the cache key + */ + public synchronized void removeEntry(String url) throws IOException { + entries.remove(url); + } + + public synchronized void updateEntry( + String url, + HttpCacheUpdateCallback callback) throws IOException { + HttpCacheEntry existingEntry = entries.get(url); + entries.put(url, callback.update(existingEntry)); + } + +} diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java index c4f1a88bc..7fc1ccf53 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java @@ -37,7 +37,14 @@ public class CacheConfig { */ public final static int DEFAULT_MAX_OBJECT_SIZE_BYTES = 8192; + /** Default setting for the maximum number of cache entries + * that will be retained. + */ + public final static int DEFAULT_MAX_CACHE_ENTRIES = 1000; + private int maxObjectSizeBytes = DEFAULT_MAX_OBJECT_SIZE_BYTES; + private int maxCacheEntries = DEFAULT_MAX_CACHE_ENTRIES; + private boolean isSharedCache = true; /** @@ -74,4 +81,19 @@ public class CacheConfig { this.isSharedCache = isSharedCache; } + /** + * Returns the maximum number of cache entries the cache will retain. + * @return int + */ + public int getMaxCacheEntries() { + return maxCacheEntries; + } + + /** + * Sets the maximum number of cache entries the cache will retain. + * @param maxCacheEntries int + */ + public void setMaxCacheEntries(int maxCacheEntries) { + this.maxCacheEntries = maxCacheEntries; + } } diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java index 552755d15..7345bbace 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java @@ -40,6 +40,7 @@ import org.apache.http.annotation.ThreadSafe; 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.HttpCacheStorage; /** * Given a particular HttpRequest, flush any cache entries that this request @@ -50,7 +51,7 @@ import org.apache.http.client.cache.HttpCacheEntry; @ThreadSafe // so long as the cache implementation is thread-safe class CacheInvalidator { - private final HttpCache cache; + private final HttpCacheStorage storage; private final URIExtractor uriExtractor; private final Log log = LogFactory.getLog(getClass()); @@ -60,13 +61,13 @@ class CacheInvalidator { * {@link URIExtractor}. * * @param uriExtractor Provides identifiers for the keys to store cache entries - * @param cache the cache to store items away in + * @param storage the cache to store items away in */ public CacheInvalidator( final URIExtractor uriExtractor, - final HttpCache cache) { + final HttpCacheStorage storage) { this.uriExtractor = uriExtractor; - this.cache = cache; + this.storage = storage; } /** @@ -82,15 +83,15 @@ class CacheInvalidator { String theUri = uriExtractor.getURI(host, req); - HttpCacheEntry parent = cache.getEntry(theUri); + HttpCacheEntry parent = storage.getEntry(theUri); log.debug("parent entry: " + parent); if (parent != null) { for (String variantURI : parent.getVariantURIs()) { - cache.removeEntry(variantURI); + storage.removeEntry(variantURI); } - cache.removeEntry(theUri); + storage.removeEntry(theUri); } URL reqURL; try { @@ -115,7 +116,7 @@ class CacheInvalidator { protected void flushUriIfSameHost(URL requestURL, URL targetURL) throws IOException { if (targetURL.getAuthority().equalsIgnoreCase(requestURL.getAuthority())) { - cache.removeEntry(targetURL.toString()); + storage.removeEntry(targetURL.toString()); } } 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 1161e0d22..534fa7928 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 @@ -29,14 +29,11 @@ package org.apache.http.impl.client.cache; import java.io.IOException; import java.net.URI; import java.util.Date; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -52,12 +49,8 @@ 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.HttpCacheUpdateCallback; -import org.apache.http.client.cache.Resource; -import org.apache.http.client.cache.ResourceFactory; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicStatusLine; @@ -70,7 +63,6 @@ import org.apache.http.protocol.HttpContext; @ThreadSafe // So long as the responseCache implementation is threadsafe public class CachingHttpClient implements HttpClient { - private final static int MAX_CACHE_ENTRIES = 1000; private final static boolean SUPPORTS_RANGE_AND_CONTENT_RANGE_HEADERS = false; private final AtomicLong cacheHits = new AtomicLong(); @@ -79,19 +71,14 @@ public class CachingHttpClient implements HttpClient { private final HttpClient backend; private final HttpCache responseCache; - private final ResourceFactory resourceFactory; private final CacheValidityPolicy validityPolicy; private final ResponseCachingPolicy responseCachingPolicy; - private final URIExtractor uriExtractor; private final CachedHttpResponseGenerator responseGenerator; - private final CacheInvalidator cacheInvalidator; private final CacheableRequestPolicy cacheableRequestPolicy; private final CachedResponseSuitabilityChecker suitabilityChecker; private final ConditionalRequestBuilder conditionalRequestBuilder; - private final CacheEntryUpdater cacheEntryUpdater; - private final int maxObjectSizeBytes; private final boolean sharedCache; @@ -103,7 +90,6 @@ public class CachingHttpClient implements HttpClient { public CachingHttpClient( HttpClient client, HttpCache cache, - ResourceFactory resourceFactory, CacheConfig config) { super(); if (client == null) { @@ -112,9 +98,6 @@ public class CachingHttpClient implements HttpClient { if (cache == null) { throw new IllegalArgumentException("HttpCache may not be null"); } - if (resourceFactory == null) { - throw new IllegalArgumentException("ResourceFactory may not be null"); - } if (config == null) { throw new IllegalArgumentException("CacheConfig may not be null"); } @@ -122,16 +105,12 @@ public class CachingHttpClient implements HttpClient { this.sharedCache = config.isSharedCache(); this.backend = client; this.responseCache = cache; - this.resourceFactory = resourceFactory; this.validityPolicy = new CacheValidityPolicy(); this.responseCachingPolicy = new ResponseCachingPolicy(maxObjectSizeBytes, sharedCache); this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy); - 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.resourceFactory); this.responseCompliance = new ResponseProtocolCompliance(); this.requestCompliance = new RequestProtocolCompliance(); @@ -139,91 +118,73 @@ public class CachingHttpClient implements HttpClient { public CachingHttpClient() { this(new DefaultHttpClient(), - new BasicHttpCache(MAX_CACHE_ENTRIES), - new HeapResourceFactory(), + new BasicHttpCache(), new CacheConfig()); } public CachingHttpClient(CacheConfig config) { this(new DefaultHttpClient(), - new BasicHttpCache(MAX_CACHE_ENTRIES), - new HeapResourceFactory(), + new BasicHttpCache(config), config); } public CachingHttpClient(HttpClient client) { this(client, - new BasicHttpCache(MAX_CACHE_ENTRIES), - new HeapResourceFactory(), + new BasicHttpCache(), new CacheConfig()); } public CachingHttpClient(HttpClient client, CacheConfig config) { this(client, - new BasicHttpCache(MAX_CACHE_ENTRIES), - new HeapResourceFactory(), + new BasicHttpCache(config), config); } public CachingHttpClient( - HttpCache cache, - ResourceFactory resourceFactory) { + HttpCache cache) { this(new DefaultHttpClient(), cache, - resourceFactory, new CacheConfig()); } public CachingHttpClient( HttpCache cache, - ResourceFactory resourceFactory, CacheConfig config) { this(new DefaultHttpClient(), cache, - resourceFactory, config); } public CachingHttpClient( HttpClient client, - HttpCache cache, - ResourceFactory resourceFactory) { + HttpCache cache) { this(client, cache, - resourceFactory, new CacheConfig()); } CachingHttpClient( HttpClient backend, - ResourceFactory resourceFactory, CacheValidityPolicy validityPolicy, ResponseCachingPolicy responseCachingPolicy, - URIExtractor uriExtractor, HttpCache responseCache, CachedHttpResponseGenerator responseGenerator, - CacheInvalidator cacheInvalidator, CacheableRequestPolicy cacheableRequestPolicy, CachedResponseSuitabilityChecker suitabilityChecker, ConditionalRequestBuilder conditionalRequestBuilder, - CacheEntryUpdater entryUpdater, ResponseProtocolCompliance responseCompliance, RequestProtocolCompliance requestCompliance) { CacheConfig config = new CacheConfig(); this.maxObjectSizeBytes = config.getMaxObjectSizeBytes(); this.sharedCache = config.isSharedCache(); this.backend = backend; - this.resourceFactory = resourceFactory; this.validityPolicy = validityPolicy; this.responseCachingPolicy = responseCachingPolicy; - this.uriExtractor = uriExtractor; this.responseCache = responseCache; this.responseGenerator = responseGenerator; - this.cacheInvalidator = cacheInvalidator; this.cacheableRequestPolicy = cacheableRequestPolicy; this.suitabilityChecker = suitabilityChecker; this.conditionalRequestBuilder = conditionalRequestBuilder; - this.cacheEntryUpdater = entryUpdater; this.responseCompliance = responseCompliance; this.requestCompliance = requestCompliance; } @@ -409,13 +370,13 @@ public class CachingHttpClient implements HttpClient { throw new ClientProtocolException(e); } - cacheInvalidator.flushInvalidatedCacheEntries(target, request); + responseCache.flushInvalidatedCacheEntriesFor(target, request); if (!cacheableRequestPolicy.isServableFromCache(request)) { return callBackend(target, request, context); } - HttpCacheEntry entry = getCacheEntry(target, request); + HttpCacheEntry entry = responseCache.getCacheEntry(target, request); if (entry == null) { cacheMisses.getAndIncrement(); if (log.isDebugEnabled()) { @@ -471,18 +432,6 @@ public class CachingHttpClient implements HttpClient { return new Date(); } - HttpCacheEntry getCacheEntry(HttpHost target, HttpRequest request) throws IOException { - String uri = uriExtractor.getURI(target, request); - HttpCacheEntry entry = responseCache.getEntry(uri); - - if (entry == null || !entry.hasVariants()) { - return entry; - } - - String variantUri = uriExtractor.getVariantURI(target, request, entry); - return responseCache.getEntry(variantUri); - } - boolean clientRequestsOurOptions(HttpRequest request) { RequestLine line = request.getRequestLine(); @@ -533,101 +482,14 @@ public class CachingHttpClient implements HttpClient { int statusCode = backendResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) { cacheUpdates.getAndIncrement(); - HttpCacheEntry updatedEntry = cacheEntryUpdater.updateCacheEntry( - request.getRequestLine().getUri(), - cacheEntry, - requestDate, - responseDate, - backendResponse); - storeInCache(target, request, updatedEntry); - return responseGenerator.generateResponse(updatedEntry); + return responseCache.updateCacheEntry(target, request, cacheEntry, + backendResponse, requestDate, responseDate); } return handleBackendResponse(target, conditionalRequest, requestDate, responseDate, backendResponse); } - void storeInCache( - HttpHost target, HttpRequest request, HttpCacheEntry entry) throws IOException { - if (entry.hasVariants()) { - storeVariantEntry(target, request, entry); - } else { - storeNonVariantEntry(target, request, entry); - } - } - - void storeNonVariantEntry( - HttpHost target, HttpRequest req, HttpCacheEntry entry) throws IOException { - String uri = uriExtractor.getURI(target, req); - responseCache.putEntry(uri, entry); - } - - void storeVariantEntry( - final HttpHost target, - final HttpRequest req, - final HttpCacheEntry entry) throws IOException { - final String parentURI = uriExtractor.getURI(target, req); - final String variantURI = uriExtractor.getVariantURI(target, req, entry); - responseCache.putEntry(variantURI, entry); - - HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() { - - public HttpCacheEntry update(HttpCacheEntry existing) throws IOException { - return doGetUpdatedParentEntry( - req.getRequestLine().getUri(), existing, entry, variantURI); - } - - }; - responseCache.updateEntry(parentURI, callback); - } - - HttpCacheEntry doGetUpdatedParentEntry( - final String requestId, - final HttpCacheEntry existing, - final HttpCacheEntry entry, - final String variantURI) throws IOException { - HttpCacheEntry src = existing; - if (src == null) { - src = entry; - } - Set variants = new HashSet(src.getVariantURIs()); - variants.add(variantURI); - Resource resource = resourceFactory.copy(requestId, src.getResource()); - return new HttpCacheEntry( - src.getRequestDate(), - src.getResponseDate(), - src.getStatusLine(), - src.getAllHeaders(), - resource, - variants); - } - - HttpResponse correctIncompleteResponse(HttpResponse resp, Resource resource) { - int status = resp.getStatusLine().getStatusCode(); - if (status != HttpStatus.SC_OK - && status != HttpStatus.SC_PARTIAL_CONTENT) { - return resp; - } - Header hdr = resp.getFirstHeader("Content-Length"); - if (hdr == null) return resp; - int contentLength; - try { - contentLength = Integer.parseInt(hdr.getValue()); - } catch (NumberFormatException nfe) { - return resp; - } - if (resource.length() >= contentLength) return resp; - HttpResponse error = - new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_GATEWAY, "Bad Gateway"); - error.setHeader("Content-Type","text/plain;charset=UTF-8"); - String msg = String.format("Received incomplete response " + - "with Content-Length %d but actual body length %d", contentLength, resource.length()); - byte[] msgBytes = msg.getBytes(); - error.setHeader("Content-Length", Integer.toString(msgBytes.length)); - error.setEntity(new ByteArrayEntity(msgBytes)); - return error; - } - HttpResponse handleBackendResponse( HttpHost target, HttpRequest request, @@ -640,40 +502,13 @@ public class CachingHttpClient implements HttpClient { boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse); - HttpResponse corrected = backendResponse; if (cacheable) { - - SizeLimitedResponseReader responseReader = getResponseReader(request, backendResponse); - responseReader.readResponse(); - - if (responseReader.isLimitReached()) { - return responseReader.getReconstructedResponse(); - } - - Resource resource = responseReader.getResource(); - corrected = correctIncompleteResponse(backendResponse, resource); - int correctedStatus = corrected.getStatusLine().getStatusCode(); - if (HttpStatus.SC_BAD_GATEWAY != correctedStatus) { - HttpCacheEntry entry = new HttpCacheEntry( - requestDate, - responseDate, - corrected.getStatusLine(), - corrected.getAllHeaders(), - resource, - null); - storeInCache(target, request, entry); - return responseGenerator.generateResponse(entry); - } + return responseCache.cacheAndReturnResponse(target, request, backendResponse, requestDate, + responseDate); } - String uri = uriExtractor.getURI(target, request); - responseCache.removeEntry(uri); - return corrected; - } - - SizeLimitedResponseReader getResponseReader(HttpRequest request, HttpResponse backEndResponse) { - return new SizeLimitedResponseReader( - resourceFactory, maxObjectSizeBytes, request, backEndResponse); + responseCache.flushCacheEntriesFor(target, request); + return backendResponse; } } 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/ManagedHttpCacheStorage.java similarity index 92% rename from httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCache.java rename to httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCacheStorage.java index cac9f5439..06563cff6 100644 --- 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/ManagedHttpCacheStorage.java @@ -33,13 +33,13 @@ 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.HttpCacheStorage; import org.apache.http.client.cache.HttpCacheUpdateCallback; import org.apache.http.client.cache.Resource; /** - * {@link HttpCache} implementation capable of deallocating resources associated with + * {@link HttpCacheStorage} 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()} @@ -47,13 +47,13 @@ import org.apache.http.client.cache.Resource; * 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} + * This {@link HttpCacheStorage} implementation is intended for use with {@link FileCacheEntry} * and similar. * * @since 4.1 */ @ThreadSafe -public class ManagedHttpCache implements HttpCache { +public class ManagedHttpCacheStorage implements HttpCacheStorage { private final CacheMap entries; private final ReferenceQueue morque; @@ -61,9 +61,9 @@ public class ManagedHttpCache implements HttpCache { private volatile boolean shutdown; - public ManagedHttpCache(int maxEntries) { + public ManagedHttpCacheStorage(final CacheConfig config) { super(); - this.entries = new CacheMap(maxEntries); + this.entries = new CacheMap(config.getMaxCacheEntries()); this.morque = new ReferenceQueue(); this.resources = new HashSet(); } diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java index b142bb6c0..e102bdb64 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java @@ -32,7 +32,6 @@ import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; import org.apache.http.annotation.NotThreadSafe; import org.apache.http.client.cache.InputLimit; import org.apache.http.client.cache.Resource; @@ -116,8 +115,7 @@ class SizeLimitedResponseReader { HttpResponse getReconstructedResponse() throws IOException { ensureConsumed(); - HttpResponse reconstructed = new BasicHttpResponse(response.getProtocolVersion(), - HttpStatus.SC_OK, "Success"); + HttpResponse reconstructed = new BasicHttpResponse(response.getStatusLine()); reconstructed.setHeaders(response.getAllHeaders()); reconstructed.setEntity(new CombinedEntity(resource, instream)); return reconstructed; diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java similarity index 93% rename from httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCache.java rename to httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java index 49be4304b..69b80b4d4 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java @@ -31,15 +31,15 @@ import java.io.IOException; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; -import org.apache.http.client.cache.HttpCache; import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.HttpCacheStorage; import org.apache.http.client.cache.HttpCacheUpdateCallback; -public class EhcacheHttpCache implements HttpCache { +public class EhcacheHttpCacheStorage implements HttpCacheStorage { private final Ehcache cache; - public EhcacheHttpCache(Ehcache cache) { + public EhcacheHttpCacheStorage(Ehcache cache) { this.cache = cache; } 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 000d932f7..fe1a12233 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 @@ -48,12 +48,13 @@ public abstract class AbstractProtocolTest { originResponse = make200Response(); - cache = new BasicHttpCache(MAX_ENTRIES); + params = new CacheConfig(); + params.setMaxCacheEntries(MAX_ENTRIES); + params.setMaxObjectSizeBytes(MAX_BYTES); + cache = new BasicHttpCache(params); mockBackend = EasyMock.createMock(HttpClient.class); mockCache = EasyMock.createMock(HttpCache.class); - params = new CacheConfig(); - params.setMaxObjectSizeBytes(MAX_BYTES); - impl = new CachingHttpClient(mockBackend, cache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, cache, params); } protected void replayMocks() { @@ -89,18 +90,23 @@ public abstract class AbstractProtocolTest { mockBackend = EasyMock.createMock(HttpClient.class); mockCache = EasyMock.createMock(HttpCache.class); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, mockCache, params); - EasyMock.expect(mockCache.getEntry((String) EasyMock.anyObject())).andReturn(null) - .anyTimes(); + EasyMock.expect(mockCache.getCacheEntry(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class))) + .andReturn(null).anyTimes(); + mockCache.flushCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)); + EasyMock.expectLastCall().anyTimes(); - mockCache.removeEntry(EasyMock.isA(String.class)); + mockCache.flushCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)); + EasyMock.expectLastCall().anyTimes(); + + mockCache.flushInvalidatedCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)); EasyMock.expectLastCall().anyTimes(); } protected void behaveAsNonSharedCache() { params.setSharedCache(false); - impl = new CachingHttpClient(mockBackend, cache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, cache, params); } public AbstractProtocolTest() { diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/CacheEntry.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/CacheEntry.java index 4502a7c57..20c487957 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/CacheEntry.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/CacheEntry.java @@ -27,6 +27,7 @@ package org.apache.http.impl.client.cache; import java.util.Date; +import java.util.Set; import org.apache.http.Header; import org.apache.http.client.cache.HttpCacheEntry; @@ -78,4 +79,8 @@ public class CacheEntry extends HttpCacheEntry { super(new Date(), new Date(), new OKStatus(), new Header[] {}, new HeapResource(content), null); } + public CacheEntry(Set variants) { + super(new Date(), new Date(), new OKStatus(), new Header[] {}, BODY, variants); + } + } 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 594f5912b..1a92f382e 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 @@ -75,14 +75,15 @@ public class DoNotTestProtocolRequirements { request = new BasicHttpRequest("GET", "/foo", HTTP_1_1); originResponse = make200Response(); + CacheConfig params = new CacheConfig(); + params.setMaxObjectSizeBytes(MAX_BYTES); + params.setMaxCacheEntries(MAX_ENTRIES); - HttpCache cache = new BasicHttpCache(MAX_ENTRIES); + HttpCache cache = new BasicHttpCache(params); mockBackend = EasyMock.createMock(HttpClient.class); mockEntity = EasyMock.createMock(HttpEntity.class); mockCache = EasyMock.createMock(HttpCache.class); - CacheConfig params = new CacheConfig(); - params.setMaxObjectSizeBytes(MAX_BYTES); - impl = new CachingHttpClient(mockBackend, cache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, cache, params); } private HttpResponse make200Response() { diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java index 2975b49f5..88a9ce914 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java @@ -195,9 +195,13 @@ public class HttpTestUtils { */ public static boolean semanticallyTransparent(HttpResponse r1, HttpResponse r2) throws Exception { - return (equivalent(r1.getEntity(), r2.getEntity()) - && semanticallyTransparent(r1.getStatusLine(), r2.getStatusLine()) && isEndToEndHeaderSubset( - r1, r2)); + final boolean entitiesEquivalent = equivalent(r1.getEntity(), r2.getEntity()); + if (!entitiesEquivalent) return false; + final boolean statusLinesEquivalent = semanticallyTransparent(r1.getStatusLine(), r2.getStatusLine()); + if (!statusLinesEquivalent) return false; + final boolean e2eHeadersEquivalentSubset = isEndToEndHeaderSubset( + r1, r2); + return e2eHeadersEquivalentSubset; } /* Assert.asserts that two requests are morally equivalent. */ diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java new file mode 100644 index 000000000..8cdfd1e34 --- /dev/null +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java @@ -0,0 +1,64 @@ +/* + * ==================================================================== + * 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.util.HashMap; +import java.util.Map; + +import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.HttpCacheStorage; +import org.apache.http.client.cache.HttpCacheUpdateCallback; + +class SimpleHttpCacheStorage implements HttpCacheStorage { + + public final Map map; + + public SimpleHttpCacheStorage() { + map = new HashMap(); + } + + public void putEntry(String key, HttpCacheEntry entry) throws IOException { + map.put(key, entry); + } + + public HttpCacheEntry getEntry(String key) throws IOException { + return map.get(key); + } + + public void removeEntry(String key) throws IOException { + map.remove(key); + } + + public void updateEntry(String key, HttpCacheUpdateCallback callback) + throws IOException { + HttpCacheEntry v1 = map.get(key); + HttpCacheEntry v2 = callback.update(v1); + map.put(key,v2); + } + +} diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java new file mode 100644 index 000000000..bc0c11b6f --- /dev/null +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java @@ -0,0 +1,335 @@ +/* + * ==================================================================== + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.io.InputStream; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +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.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.Resource; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.cookie.DateUtils; +import org.apache.http.message.BasicHttpResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TestBasicHttpCache { + + private BasicHttpCache impl; + private SimpleHttpCacheStorage backing; + + @Before + public void setUp() throws Exception { + backing = new SimpleHttpCacheStorage(); + impl = new BasicHttpCache(new HeapResourceFactory(), backing, new CacheConfig()); + } + + @Test + public void testCanFlushCacheEntriesAtUri() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest req = new HttpDelete("/bar"); + final String key = (new URIExtractor()).getURI(host, req); + HttpCacheEntry entry = new CacheEntry(); + + backing.map.put(key, entry); + + impl.flushCacheEntriesFor(host, req); + + assertNull(backing.map.get(key)); + } + + @Test + public void testRecognizesComplete200Response() + throws Exception { + 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"); + Resource resource = new HeapResource(bytes); + + assertFalse(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testRecognizesComplete206Response() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + resp.setHeader("Content-Length","128"); + resp.setHeader("Content-Range","bytes 0-127/255"); + + assertFalse(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testRecognizesIncomplete200Response() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + resp.setHeader("Content-Length","256"); + + assertTrue(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testIgnoresIncompleteNon200Or206Responses() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_FORBIDDEN, "Forbidden"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + resp.setHeader("Content-Length","256"); + + assertFalse(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testResponsesWithoutExplicitContentLengthAreComplete() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + + assertFalse(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testResponsesWithUnparseableContentLengthHeaderAreComplete() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setHeader("Content-Length","foo"); + resp.setEntity(new ByteArrayEntity(bytes)); + + assertFalse(impl.isIncompleteResponse(resp, resource)); + } + + @Test + public void testIncompleteResponseErrorProvidesPlainTextErrorMessage() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + resp.setHeader("Content-Length","256"); + + HttpResponse result = impl.generateIncompleteResponseError(resp, resource); + Header ctype = result.getFirstHeader("Content-Type"); + assertEquals("text/plain;charset=UTF-8", ctype.getValue()); + } + + @Test + public void testIncompleteResponseErrorProvidesNonEmptyErrorMessage() + throws Exception { + HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + byte[] bytes = HttpTestUtils.getRandomBytes(128); + Resource resource = new HeapResource(bytes); + resp.setEntity(new ByteArrayEntity(bytes)); + resp.setHeader("Content-Length","256"); + + HttpResponse result = impl.generateIncompleteResponseError(resp, resource); + int clen = Integer.parseInt(result.getFirstHeader("Content-Length").getValue()); + assertTrue(clen > 0); + HttpEntity body = result.getEntity(); + if (body.getContentLength() < 0) { + InputStream is = body.getContent(); + int bytes_read = 0; + while((is.read()) != -1) { + bytes_read++; + } + is.close(); + assertEquals(clen, bytes_read); + } else { + assertTrue(body.getContentLength() == clen); + } + } + + @Test + public void testCacheUpdateAddsVariantURIToParentEntry() throws Exception { + final String parentKey = "parentKey"; + final String variantKey = "variantKey"; + final String existingVariantKey = "existingVariantKey"; + final Set existingVariants = new HashSet(); + existingVariants.add(existingVariantKey); + final CacheEntry parent = new CacheEntry(existingVariants); + final CacheEntry variant = new CacheEntry(); + + HttpCacheEntry result = impl.doGetUpdatedParentEntry(parentKey, parent, variant, variantKey); + assertEquals(2, result.getVariantURIs().size()); + assertTrue(result.getVariantURIs().contains(existingVariantKey)); + assertTrue(result.getVariantURIs().contains(variantKey)); + } + + @Test + public void testStoreInCachePutsNonVariantEntryInPlace() throws Exception { + CacheEntry entry = new CacheEntry(); + assertFalse(entry.hasVariants()); + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest req = new HttpGet("http://foo.example.com/bar"); + String key = (new URIExtractor()).getURI(host, req); + + impl.storeInCache(host, req, entry); + assertSame(entry, backing.map.get(key)); + } + + @Test + public void testTooLargeResponsesAreNotCached() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + + Date now = new Date(); + Date requestSent = new Date(now.getTime() - 3 * 1000L); + Date responseGenerated = new Date(now.getTime() - 2 * 1000L); + Date responseReceived = new Date(now.getTime() - 1 * 1000L); + + HttpResponse originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + originResponse.setEntity(HttpTestUtils.makeBody(CacheConfig.DEFAULT_MAX_OBJECT_SIZE_BYTES + 1)); + originResponse.setHeader("Cache-Control","public, max-age=3600"); + originResponse.setHeader("Date", DateUtils.formatDate(responseGenerated)); + originResponse.setHeader("ETag", "\"etag\""); + + HttpResponse result = impl.cacheAndReturnResponse(host, request, originResponse, requestSent, responseReceived); + assertEquals(0, backing.map.size()); + assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result)); + } + + + @Test + public void testSmallEnoughResponsesAreCached() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + + Date now = new Date(); + Date requestSent = new Date(now.getTime() - 3 * 1000L); + Date responseGenerated = new Date(now.getTime() - 2 * 1000L); + Date responseReceived = new Date(now.getTime() - 1 * 1000L); + + HttpResponse originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + originResponse.setEntity(HttpTestUtils.makeBody(CacheConfig.DEFAULT_MAX_OBJECT_SIZE_BYTES - 1)); + originResponse.setHeader("Cache-Control","public, max-age=3600"); + originResponse.setHeader("Date", DateUtils.formatDate(responseGenerated)); + originResponse.setHeader("ETag", "\"etag\""); + + HttpResponse result = impl.cacheAndReturnResponse(host, request, originResponse, requestSent, responseReceived); + assertEquals(1, backing.map.size()); + assertTrue(backing.map.containsKey((new URIExtractor()).getURI(host, request))); + assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result)); + } + + @Test + public void testGetCacheEntryReturnsNullOnCacheMiss() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + HttpCacheEntry result = impl.getCacheEntry(host, request); + Assert.assertNull(result); + } + + @Test + public void testGetCacheEntryFetchesFromCacheOnCacheHitIfNoVariants() throws Exception { + CacheEntry entry = new CacheEntry(); + assertFalse(entry.hasVariants()); + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + + String key = (new URIExtractor()).getURI(host, request); + + backing.map.put(key,entry); + + HttpCacheEntry result = impl.getCacheEntry(host, request); + Assert.assertSame(entry, result); + } + + @Test + public void testGetCacheEntryReturnsNullIfNoVariantInCache() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + + HttpRequest origRequest = new HttpGet("http://foo.example.com/bar"); + origRequest.setHeader("Accept-Encoding","gzip"); + + HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + origResponse.setEntity(HttpTestUtils.makeBody(128)); + origResponse.setHeader("Date", DateUtils.formatDate(new Date())); + origResponse.setHeader("Cache-Control", "max-age=3600, public"); + origResponse.setHeader("ETag", "\"etag\""); + origResponse.setHeader("Vary", "Accept-Encoding"); + origResponse.setHeader("Content-Encoding","gzip"); + + impl.cacheAndReturnResponse(host, origRequest, origResponse, new Date(), new Date()); + HttpCacheEntry result = impl.getCacheEntry(host, request); + assertNull(result); + } + + @Test + public void testGetCacheEntryReturnsVariantIfPresentInCache() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + request.setHeader("Accept-Encoding","gzip"); + + HttpRequest origRequest = new HttpGet("http://foo.example.com/bar"); + origRequest.setHeader("Accept-Encoding","gzip"); + + HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + origResponse.setEntity(HttpTestUtils.makeBody(128)); + origResponse.setHeader("Date", DateUtils.formatDate(new Date())); + origResponse.setHeader("Cache-Control", "max-age=3600, public"); + origResponse.setHeader("ETag", "\"etag\""); + origResponse.setHeader("Vary", "Accept-Encoding"); + origResponse.setHeader("Content-Encoding","gzip"); + + impl.cacheAndReturnResponse(host, origRequest, origResponse, new Date(), new Date()); + HttpCacheEntry result = impl.getCacheEntry(host, request); + assertNotNull(result); + } + + +} diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java index 6182ef192..92aa6e94d 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java @@ -34,7 +34,7 @@ import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.ProtocolVersion; -import org.apache.http.client.cache.HttpCache; +import org.apache.http.client.cache.HttpCacheStorage; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; import org.easymock.classextension.EasyMock; @@ -46,7 +46,7 @@ public class TestCacheInvalidator { private static final ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1); private CacheInvalidator impl; - private HttpCache mockCache; + private HttpCacheStorage mockStorage; private HttpHost host; private URIExtractor extractor; private CacheEntry mockEntry; @@ -54,20 +54,20 @@ public class TestCacheInvalidator { @Before public void setUp() { host = new HttpHost("foo.example.com"); - mockCache = EasyMock.createMock(HttpCache.class); + mockStorage = EasyMock.createMock(HttpCacheStorage.class); extractor = new URIExtractor(); mockEntry = EasyMock.createMock(CacheEntry.class); - impl = new CacheInvalidator(extractor, mockCache); + impl = new CacheInvalidator(extractor, mockStorage); } private void replayMocks() { - EasyMock.replay(mockCache); + EasyMock.replay(mockStorage); EasyMock.replay(mockEntry); } private void verifyMocks() { - EasyMock.verify(mockCache); + EasyMock.verify(mockStorage); EasyMock.verify(mockEntry); } @@ -283,16 +283,16 @@ public class TestCacheInvalidator { } private void cacheReturnsEntryForUri(String theUri) throws IOException { - org.easymock.EasyMock.expect(mockCache.getEntry(theUri)).andReturn(mockEntry); + org.easymock.EasyMock.expect(mockStorage.getEntry(theUri)).andReturn(mockEntry); } private void cacheReturnsExceptionForUri(String theUri) throws IOException { - org.easymock.EasyMock.expect(mockCache.getEntry(theUri)).andThrow( + org.easymock.EasyMock.expect(mockStorage.getEntry(theUri)).andThrow( new IOException("TOTAL FAIL")); } private void entryIsRemoved(String theUri) throws IOException { - mockCache.removeEntry(theUri); + mockStorage.removeEntry(theUri); } } \ No newline at end of file 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 ce343a208..ba412ede5 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 @@ -27,14 +27,11 @@ package org.apache.http.impl.client.cache; import java.io.IOException; -import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.List; -import org.apache.http.Header; -import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -47,13 +44,9 @@ 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.cache.Resource; -import org.apache.http.client.cache.ResourceFactory; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.entity.ByteArrayEntity; import org.apache.http.message.BasicHttpRequest; -import org.apache.http.message.BasicHttpResponse; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpContext; @@ -73,17 +66,9 @@ public class TestCachingHttpClient { private static final String REVALIDATE_CACHE_ENTRY = "revalidateCacheEntry"; - private static final String GET_CACHE_ENTRY = "getCacheEntry"; - - private static final String STORE_IN_CACHE = "storeInCache"; - - private static final String GET_RESPONSE_READER = "getResponseReader"; - private CachingHttpClient impl; private boolean mockedImpl; - private ResourceFactory mockResourceFactory; - private CacheInvalidator mockInvalidator; private CacheValidityPolicy mockValidityPolicy; private CacheableRequestPolicy mockRequestPolicy; private HttpClient mockBackend; @@ -92,20 +77,14 @@ public class TestCachingHttpClient { private ResponseCachingPolicy mockResponsePolicy; private HttpResponse mockBackendResponse; private CacheEntry mockCacheEntry; - private CacheEntry mockVariantCacheEntry; - private CacheEntry mockUpdatedCacheEntry; - private URIExtractor mockExtractor; private CachedHttpResponseGenerator mockResponseGenerator; - private SizeLimitedResponseReader mockResponseReader; private ClientConnectionManager mockConnectionManager; private ResponseHandler mockHandler; private HttpUriRequest mockUriRequest; private HttpResponse mockCachedResponse; - private HttpResponse mockReconstructedResponse; private ConditionalRequestBuilder mockConditionalRequestBuilder; private HttpRequest mockConditionalRequest; private StatusLine mockStatusLine; - private CacheEntryUpdater mockCacheEntryUpdater; private ResponseProtocolCompliance mockResponseProtocolCompliance; private RequestProtocolCompliance mockRequestProtocolCompliance; @@ -119,8 +98,6 @@ public class TestCachingHttpClient { @SuppressWarnings("unchecked") @Before public void setUp() { - mockResourceFactory = EasyMock.createMock(ResourceFactory.class); - mockInvalidator = EasyMock.createMock(CacheInvalidator.class); mockRequestPolicy = EasyMock.createMock(CacheableRequestPolicy.class); mockValidityPolicy = EasyMock.createMock(CacheValidityPolicy.class); mockBackend = EasyMock.createMock(HttpClient.class); @@ -132,17 +109,11 @@ public class TestCachingHttpClient { mockBackendResponse = EasyMock.createMock(HttpResponse.class); mockUriRequest = EasyMock.createMock(HttpUriRequest.class); mockCacheEntry = EasyMock.createMock(CacheEntry.class); - mockUpdatedCacheEntry = EasyMock.createMock(CacheEntry.class); - mockVariantCacheEntry = EasyMock.createMock(CacheEntry.class); - mockExtractor = EasyMock.createMock(URIExtractor.class); mockResponseGenerator = EasyMock.createMock(CachedHttpResponseGenerator.class); mockCachedResponse = EasyMock.createMock(HttpResponse.class); mockConditionalRequestBuilder = EasyMock.createMock(ConditionalRequestBuilder.class); mockConditionalRequest = EasyMock.createMock(HttpRequest.class); mockStatusLine = EasyMock.createMock(StatusLine.class); - mockCacheEntryUpdater = EasyMock.createMock(CacheEntryUpdater.class); - mockResponseReader = EasyMock.createMock(SizeLimitedResponseReader.class); - mockReconstructedResponse = EasyMock.createMock(HttpResponse.class); mockResponseProtocolCompliance = EasyMock.createMock(ResponseProtocolCompliance.class); mockRequestProtocolCompliance = EasyMock.createMock(RequestProtocolCompliance.class); @@ -154,32 +125,24 @@ public class TestCachingHttpClient { params = new BasicHttpParams(); impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance); } private void replayMocks() { - EasyMock.replay(mockResourceFactory); - EasyMock.replay(mockInvalidator); EasyMock.replay(mockRequestPolicy); EasyMock.replay(mockValidityPolicy); EasyMock.replay(mockSuitabilityChecker); EasyMock.replay(mockResponsePolicy); EasyMock.replay(mockCacheEntry); - EasyMock.replay(mockVariantCacheEntry); EasyMock.replay(mockResponseGenerator); - EasyMock.replay(mockExtractor); EasyMock.replay(mockBackend); EasyMock.replay(mockCache); EasyMock.replay(mockConnectionManager); @@ -190,9 +153,6 @@ public class TestCachingHttpClient { EasyMock.replay(mockConditionalRequestBuilder); EasyMock.replay(mockConditionalRequest); EasyMock.replay(mockStatusLine); - EasyMock.replay(mockCacheEntryUpdater); - EasyMock.replay(mockResponseReader); - EasyMock.replay(mockReconstructedResponse); EasyMock.replay(mockResponseProtocolCompliance); EasyMock.replay(mockRequestProtocolCompliance); if (mockedImpl) { @@ -201,16 +161,12 @@ public class TestCachingHttpClient { } private void verifyMocks() { - EasyMock.verify(mockResourceFactory); - EasyMock.verify(mockInvalidator); EasyMock.verify(mockRequestPolicy); EasyMock.verify(mockValidityPolicy); EasyMock.verify(mockSuitabilityChecker); EasyMock.verify(mockResponsePolicy); EasyMock.verify(mockCacheEntry); - EasyMock.verify(mockVariantCacheEntry); EasyMock.verify(mockResponseGenerator); - EasyMock.verify(mockExtractor); EasyMock.verify(mockBackend); EasyMock.verify(mockCache); EasyMock.verify(mockConnectionManager); @@ -221,9 +177,6 @@ public class TestCachingHttpClient { EasyMock.verify(mockConditionalRequestBuilder); EasyMock.verify(mockConditionalRequest); EasyMock.verify(mockStatusLine); - EasyMock.verify(mockCacheEntryUpdater); - EasyMock.verify(mockResponseReader); - EasyMock.verify(mockReconstructedResponse); EasyMock.verify(mockResponseProtocolCompliance); EasyMock.verify(mockRequestProtocolCompliance); if (mockedImpl) { @@ -233,20 +186,12 @@ public class TestCachingHttpClient { @Test public void testCacheableResponsesGoIntoCache() throws Exception { - mockImplMethods(STORE_IN_CACHE, GET_RESPONSE_READER); responsePolicyAllowsCaching(true); responseProtocolValidationIsCalled(); - getMockResponseReader(); - responseRead(); - responseLimitReached(false); - responseGetResource(); - storeInCacheWasCalled(); - responseIsGeneratedFromCache(); - responseStatusLineIsInspectable(); - responseGetHeaders(); - responseDoesNotHaveExplicitContentLength(); + EasyMock.expect(mockCache.cacheAndReturnResponse(host, request, mockBackendResponse, requestDate, responseDate)) + .andReturn(mockCachedResponse); replayMocks(); HttpResponse result = impl.handleBackendResponse(host, request, requestDate, @@ -283,37 +228,13 @@ public class TestCachingHttpClient { errors); } - @Test - public void testStoreInCachePutsNonVariantEntryInPlace() throws Exception { - - final String theURI = "theURI"; - - cacheEntryHasVariants(false); - extractTheURI(theURI); - putInCache(theURI); - - replayMocks(); - impl.storeInCache(host, request, mockCacheEntry); - verifyMocks(); - } - - @Test - public void testCacheUpdateAddsVariantURIToParentEntry() throws Exception { - final String variantURI = "variantURI"; - final CacheEntry entry = new CacheEntry(); - copyResource(); - replayMocks(); - impl.doGetUpdatedParentEntry("/stuff", null, entry, variantURI); - verifyMocks(); - } - - @Test public void testCacheMissCausesBackendRequest() throws Exception { - mockImplMethods(GET_CACHE_ENTRY, CALL_BACKEND); + mockImplMethods(CALL_BACKEND); cacheInvalidatorWasCalled(); requestPolicyAllowsCaching(true); getCacheEntryReturns(null); + requestProtocolValidationIsCalled(); requestIsFatallyNonCompliant(null); @@ -331,7 +252,7 @@ public class TestCachingHttpClient { @Test public void testUnsuitableUnvalidatableCacheEntryCausesBackendRequest() throws Exception { - mockImplMethods(GET_CACHE_ENTRY, CALL_BACKEND); + mockImplMethods(CALL_BACKEND); cacheInvalidatorWasCalled(); requestPolicyAllowsCaching(true); requestProtocolValidationIsCalled(); @@ -354,7 +275,7 @@ public class TestCachingHttpClient { @Test public void testUnsuitableValidatableCacheEntryCausesRevalidation() throws Exception { - mockImplMethods(GET_CACHE_ENTRY, REVALIDATE_CACHE_ENTRY); + mockImplMethods(REVALIDATE_CACHE_ENTRY); cacheInvalidatorWasCalled(); requestPolicyAllowsCaching(true); requestProtocolValidationIsCalled(); @@ -384,11 +305,9 @@ public class TestCachingHttpClient { backendCallWasMadeWithRequest(mockConditionalRequest); getCurrentDateReturns(responseDate); backendResponseCodeIs(HttpStatus.SC_OK); - cacheEntryUpdaterCalled(); - cacheEntryHasVariants(false, mockUpdatedCacheEntry); - extractTheURI("http://foo.example.com"); - putInCache("http://foo.example.com", mockUpdatedCacheEntry); - responseIsGeneratedFromCache(mockUpdatedCacheEntry); + EasyMock.expect(mockCache.updateCacheEntry(host, request, + mockCacheEntry, mockBackendResponse, requestDate, responseDate)) + .andReturn(mockCachedResponse); replayMocks(); @@ -406,17 +325,15 @@ public class TestCachingHttpClient { @Test public void testRevalidationUpdatesCacheEntryAndPutsItToCacheWhen304ReturningCachedResponse() throws Exception { - mockImplMethods(GET_CURRENT_DATE, STORE_IN_CACHE); + mockImplMethods(GET_CURRENT_DATE); conditionalRequestBuilderCalled(); getCurrentDateReturns(requestDate); backendCallWasMadeWithRequest(mockConditionalRequest); getCurrentDateReturns(responseDate); backendResponseCodeIs(HttpStatus.SC_NOT_MODIFIED); - - cacheEntryUpdaterCalled(); - storeInCacheWasCalled(mockUpdatedCacheEntry); - - responseIsGeneratedFromCache(mockUpdatedCacheEntry); + EasyMock.expect(mockCache.updateCacheEntry(host, request, + mockCacheEntry, mockBackendResponse, requestDate, responseDate)) + .andReturn(mockCachedResponse); replayMocks(); @@ -432,7 +349,6 @@ public class TestCachingHttpClient { @Test public void testSuitableCacheEntryDoesNotCauseBackendRequest() throws Exception { - mockImplMethods(GET_CACHE_ENTRY); cacheInvalidatorWasCalled(); requestPolicyAllowsCaching(true); requestProtocolValidationIsCalled(); @@ -465,13 +381,11 @@ public class TestCachingHttpClient { @Test public void testNonCacheableResponseIsNotCachedAndIsReturnedAsIs() throws Exception { - final String theURI = "theURI"; Date currentDate = new Date(); responsePolicyAllowsCaching(false); responseProtocolValidationIsCalled(); - extractTheURI(theURI); - removeFromCache(theURI); + flushCache(); replayMocks(); HttpResponse result = impl.handleBackendResponse(host, request, currentDate, @@ -481,115 +395,6 @@ public class TestCachingHttpClient { Assert.assertSame(mockBackendResponse, result); } - @Test - public void testGetCacheEntryReturnsNullOnCacheMiss() throws Exception { - - final String theURI = "theURI"; - extractTheURI(theURI); - gotCacheMiss(theURI); - - replayMocks(); - HttpCacheEntry result = impl.getCacheEntry(host, request); - verifyMocks(); - Assert.assertNull(result); - } - - @Test - public void testGetCacheEntryFetchesFromCacheOnCacheHitIfNoVariants() throws Exception { - - final String theURI = "theURI"; - extractTheURI(theURI); - gotCacheHit(theURI); - cacheEntryHasVariants(false); - - replayMocks(); - HttpCacheEntry result = impl.getCacheEntry(host, request); - verifyMocks(); - Assert.assertSame(mockCacheEntry, result); - } - - @Test - public void testGetCacheEntryReturnsNullIfNoVariantInCache() throws Exception { - - final String theURI = "theURI"; - final String variantURI = "variantURI"; - extractTheURI(theURI); - gotCacheHit(theURI); - cacheEntryHasVariants(true); - extractVariantURI(variantURI); - gotCacheMiss(variantURI); - - replayMocks(); - HttpCacheEntry result = impl.getCacheEntry(host, request); - verifyMocks(); - Assert.assertNull(result); - } - - @Test - public void testGetCacheEntryReturnsVariantIfPresentInCache() throws Exception { - - final String theURI = "theURI"; - final String variantURI = "variantURI"; - extractTheURI(theURI); - gotCacheHit(theURI, mockCacheEntry); - cacheEntryHasVariants(true); - extractVariantURI(variantURI); - gotCacheHit(variantURI, mockVariantCacheEntry); - - replayMocks(); - HttpCacheEntry result = impl.getCacheEntry(host, request); - verifyMocks(); - Assert.assertSame(mockVariantCacheEntry, result); - } - - @Test - public void testTooLargeResponsesAreNotCached() throws Exception { - mockImplMethods(GET_CURRENT_DATE, GET_RESPONSE_READER, STORE_IN_CACHE); - getCurrentDateReturns(requestDate); - backendCallWasMadeWithRequest(request); - responseProtocolValidationIsCalled(); - - getCurrentDateReturns(responseDate); - responsePolicyAllowsCaching(true); - getMockResponseReader(); - responseRead(); - responseLimitReached(true); - responseGetReconstructed(); - - replayMocks(); - - impl.callBackend(host, request, context); - - verifyMocks(); - } - - @Test - public void testSmallEnoughResponsesAreCached() throws Exception { - requestDate = new Date(); - responseDate = new Date(); - mockImplMethods(GET_CURRENT_DATE, GET_RESPONSE_READER, STORE_IN_CACHE); - getCurrentDateReturns(requestDate); - responseProtocolValidationIsCalled(); - - backendCallWasMadeWithRequest(request); - getCurrentDateReturns(responseDate); - responsePolicyAllowsCaching(true); - getMockResponseReader(); - responseRead(); - responseLimitReached(false); - responseGetResource(); - storeInCacheWasCalled(); - responseIsGeneratedFromCache(); - responseStatusLineIsInspectable(); - responseGetHeaders(); - responseDoesNotHaveExplicitContentLength(); - - replayMocks(); - - impl.callBackend(host, request, context); - - verifyMocks(); - } @Test public void testCallsSelfForExecuteOnHostRequestWithNullContext() throws Exception { @@ -599,17 +404,13 @@ public class TestCachingHttpClient { final HttpResponse theResponse = mockBackendResponse; impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -641,17 +442,13 @@ public class TestCachingHttpClient { final Object value = new Object(); impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -691,17 +488,13 @@ public class TestCachingHttpClient { final HttpContext theContext = context; impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -733,17 +526,13 @@ public class TestCachingHttpClient { final HttpResponse theResponse = mockBackendResponse; impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -773,17 +562,13 @@ public class TestCachingHttpClient { final HttpResponse theResponse = mockBackendResponse; impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -816,17 +601,13 @@ public class TestCachingHttpClient { final Object theValue = new Object(); impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -861,17 +642,13 @@ public class TestCachingHttpClient { final Object theValue = new Object(); impl = new CachingHttpClient( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance) { @Override @@ -916,17 +693,13 @@ public class TestCachingHttpClient { @Test public void testResponseIsGeneratedWhenCacheEntryIsUsable() throws Exception { - final String theURI = "http://foo"; - requestIsFatallyNonCompliant(null); requestProtocolValidationIsCalled(); cacheInvalidatorWasCalled(); requestPolicyAllowsCaching(true); cacheEntrySuitable(true); - extractTheURI(theURI); - gotCacheHit(theURI); + getCacheEntryReturns(mockCacheEntry); responseIsGeneratedFromCache(); - cacheEntryHasVariants(false); replayMocks(); impl.execute(host, request, context); @@ -953,123 +726,17 @@ public class TestCachingHttpClient { Assert.assertTrue(gotException); } - @Test - public void testCorrectIncompleteResponseDoesNotCorrectComplete200Response() - throws Exception { - 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"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result)); - } - - @Test - public void testCorrectIncompleteResponseDoesNotCorrectComplete206Response() - throws Exception { - 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"); - resp.setHeader("Content-Range","bytes 0-127/255"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result)); - } - - @Test - public void testCorrectIncompleteResponseGenerates502ForIncomplete200Response() - throws Exception { - 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"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpStatus.SC_BAD_GATEWAY == result.getStatusLine().getStatusCode()); - } - - @Test - public void testCorrectIncompleteResponseDoesNotCorrectIncompleteNon200Or206Responses() - throws Exception { - 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"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result)); - } - - @Test - public void testCorrectIncompleteResponseDoesNotCorrectResponsesWithoutExplicitContentLength() - throws Exception { - HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); - byte[] bytes = HttpTestUtils.getRandomBytes(128); - resp.setEntity(new ByteArrayEntity(bytes)); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result)); - } - - @Test - public void testCorrectIncompleteResponseDoesNotCorrectResponsesWithUnparseableContentLengthHeader() - throws Exception { - 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)); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result)); - } - - @Test - public void testCorrectIncompleteResponseProvidesPlainTextErrorMessage() - throws Exception { - 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"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - Header ctype = result.getFirstHeader("Content-Type"); - Assert.assertEquals("text/plain;charset=UTF-8", ctype.getValue()); - } - - @Test - public void testCorrectIncompleteResponseProvidesNonEmptyErrorMessage() - throws Exception { - 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"); - - HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes)); - int clen = Integer.parseInt(result.getFirstHeader("Content-Length").getValue()); - Assert.assertTrue(clen > 0); - HttpEntity body = result.getEntity(); - if (body.getContentLength() < 0) { - InputStream is = body.getContent(); - int bytes_read = 0; - while((is.read()) != -1) { - bytes_read++; - } - is.close(); - Assert.assertEquals(clen, bytes_read); - } else { - Assert.assertTrue(body.getContentLength() == clen); - } - } - @Test public void testIsSharedCache() { Assert.assertTrue(impl.isSharedCache()); } + private void getCacheEntryReturns(HttpCacheEntry result) throws IOException { + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(result); + } + private void cacheInvalidatorWasCalled() throws IOException { - mockInvalidator.flushInvalidatedCacheEntries( + mockCache.flushInvalidatedCacheEntriesFor( EasyMock.anyObject(), EasyMock.anyObject()); } @@ -1096,22 +763,6 @@ public class TestCachingHttpClient { EasyMock.anyObject())).andReturn(b); } - private void cacheEntryUpdaterCalled() throws IOException { - EasyMock.expect( - mockCacheEntryUpdater.updateCacheEntry( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(mockUpdatedCacheEntry); - } - - private void getCacheEntryReturns(CacheEntry entry) throws IOException { - EasyMock.expect(impl.getCacheEntry( - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(entry); - } - private void backendResponseCodeIs(int code) { EasyMock.expect(mockBackendResponse.getStatusLine()).andReturn(mockStatusLine); EasyMock.expect(mockStatusLine.getStatusCode()).andReturn(code); @@ -1128,42 +779,11 @@ public class TestCachingHttpClient { EasyMock.expect(impl.getCurrentDate()).andReturn(date); } - private void getMockResponseReader() { - EasyMock.expect(impl.getResponseReader( - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(mockResponseReader); - } - - private void removeFromCache(String theURI) throws Exception { - mockCache.removeEntry(theURI); - } - private void requestPolicyAllowsCaching(boolean allow) { EasyMock.expect(mockRequestPolicy.isServableFromCache( EasyMock.anyObject())).andReturn(allow); } - private void responseDoesNotHaveExplicitContentLength() { - EasyMock.expect(mockBackendResponse.getFirstHeader("Content-Length")) - .andReturn(null).anyTimes(); - } - - private void responseRead() throws Exception { - mockResponseReader.readResponse(); - } - - private void responseLimitReached(boolean limitReached) throws Exception { - EasyMock.expect(mockResponseReader.isLimitReached()).andReturn(limitReached); - } - - private void responseGetResource() throws Exception { - EasyMock.expect(mockResponseReader.getResource()).andReturn(new HeapResource(new byte[] {} )); - } - - private void responseGetReconstructed() throws Exception { - EasyMock.expect(mockResponseReader.getReconstructedResponse()).andReturn(mockReconstructedResponse); - } - private void backendCallWasMadeWithRequest(HttpRequest request) throws IOException { EasyMock.expect(mockBackend.execute( EasyMock.anyObject(), @@ -1178,10 +798,6 @@ public class TestCachingHttpClient { EasyMock.anyObject())).andReturn(allow); } - private void gotCacheMiss(String theURI) throws Exception { - EasyMock.expect(mockCache.getEntry(theURI)).andReturn(null); - } - private void cacheEntrySuitable(boolean suitable) { EasyMock.expect( mockSuitabilityChecker.canCachedResponseBeUsed( @@ -1190,68 +806,13 @@ public class TestCachingHttpClient { EasyMock.anyObject())).andReturn(suitable); } - private void gotCacheHit(String theURI) throws Exception { - EasyMock.expect(mockCache.getEntry(theURI)).andReturn(mockCacheEntry); - } - - private void gotCacheHit(String theURI, CacheEntry entry) throws Exception { - EasyMock.expect(mockCache.getEntry(theURI)).andReturn(entry); - } - - private void cacheEntryHasVariants(boolean b) { - EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(b); - } - - private void cacheEntryHasVariants(boolean b, CacheEntry entry) { - EasyMock.expect(entry.hasVariants()).andReturn(b); - } - private void responseIsGeneratedFromCache() { EasyMock.expect(mockResponseGenerator.generateResponse( EasyMock.anyObject())).andReturn(mockCachedResponse); } - private void responseStatusLineIsInspectable() { - EasyMock.expect(mockBackendResponse.getStatusLine()).andReturn(new OKStatus()).anyTimes(); - } - - private void responseGetHeaders() { - EasyMock.expect(mockBackendResponse.getAllHeaders()).andReturn(new Header[] {}).anyTimes(); - } - - private void responseIsGeneratedFromCache(CacheEntry entry) { - EasyMock.expect(mockResponseGenerator.generateResponse(entry)) - .andReturn(mockCachedResponse); - } - - private void extractTheURI(String theURI) { - EasyMock.expect(mockExtractor.getURI(host, request)).andReturn(theURI); - } - - private void extractVariantURI(String variantURI) { - extractVariantURI(variantURI,mockCacheEntry); - } - - private void extractVariantURI(String variantURI, CacheEntry entry){ - EasyMock.expect(mockExtractor.getVariantURI( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.same(entry))).andReturn(variantURI); - } - - private void putInCache(String theURI) throws Exception { - mockCache.putEntry(theURI, mockCacheEntry); - } - - private void putInCache(String theURI, CacheEntry entry) throws Exception { - mockCache.putEntry(theURI, entry); - } - - private void copyResource() throws IOException { - EasyMock.expect( - mockResourceFactory.copy( - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(new HeapResource(new byte[] {})); + private void flushCache() throws IOException { + mockCache.flushCacheEntriesFor(host, request); } private void handleBackendResponseReturnsResponse(HttpRequest request, HttpResponse response) @@ -1265,20 +826,6 @@ public class TestCachingHttpClient { EasyMock.anyObject())).andReturn(response); } - private void storeInCacheWasCalled() throws IOException { - impl.storeInCache( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject()); - } - - private void storeInCacheWasCalled(CacheEntry entry) throws IOException { - impl.storeInCache( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.same(entry)); - } - private void responseProtocolValidationIsCalled() throws ClientProtocolException { mockResponseProtocolCompliance.ensureProtocolCompliance( EasyMock.anyObject(), @@ -1301,17 +848,13 @@ public class TestCachingHttpClient { mockedImpl = true; impl = EasyMock.createMockBuilder(CachingHttpClient.class).withConstructor( mockBackend, - mockResourceFactory, mockValidityPolicy, mockResponsePolicy, - mockExtractor, mockCache, mockResponseGenerator, - mockInvalidator, mockRequestPolicy, mockSuitabilityChecker, mockConditionalRequestBuilder, - mockCacheEntryUpdater, mockResponseProtocolCompliance, mockRequestProtocolCompliance).addMockedMethods(methods).createMock(); } 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 76a009ef5..dbf595e74 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 @@ -93,14 +93,16 @@ public class TestProtocolDeviations { originResponse = make200Response(); - HttpCache cache = new BasicHttpCache(MAX_ENTRIES); + CacheConfig params = new CacheConfig(); + params.setMaxObjectSizeBytes(MAX_BYTES); + params.setMaxCacheEntries(MAX_ENTRIES); + + HttpCache cache = new BasicHttpCache(params); mockBackend = EasyMock.createMock(HttpClient.class); mockEntity = EasyMock.createMock(HttpEntity.class); mockCache = EasyMock.createMock(HttpCache.class); - CacheConfig params = new CacheConfig(); - params.setMaxObjectSizeBytes(MAX_BYTES); - impl = new CachingHttpClient(mockBackend, cache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, cache, 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 1ef944b89..8f308439f 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 @@ -42,7 +42,6 @@ import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.ProtocolVersion; import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.cache.HttpCacheEntry; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.RequestWrapper; @@ -2220,9 +2219,9 @@ public class TestProtocolRequirements extends AbstractProtocolTest { CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes); - mockCache.putEntry(EasyMock.eq("http://foo.example.com/thing"), EasyMock.isA(HttpCacheEntry.class)); + impl = new CachingHttpClient(mockBackend, mockCache, params); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpRequest validate = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); validate.setHeader("If-None-Match", "\"etag\""); @@ -2232,17 +2231,23 @@ public class TestProtocolRequirements extends AbstractProtocolTest { notModified.setHeader("Date", DateUtils.formatDate(now)); notModified.setHeader("ETag", "\"etag\""); - EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry); + HttpResponse reconstructed = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + + mockCache.flushInvalidatedCacheEntriesFor(host, request); + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); EasyMock.expect( mockBackend.execute(EasyMock.eq(host), eqRequest(validate), (HttpContext) EasyMock .isNull())).andReturn(notModified); + EasyMock.expect(mockCache.updateCacheEntry(EasyMock.same(host), EasyMock.same(request), + EasyMock.same(entry), EasyMock.same(notModified), EasyMock.isA(Date.class), + EasyMock.isA(Date.class))) + .andReturn(reconstructed); replayMocks(); - request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse result = impl.execute(host, request); verifyMocks(); - Assert.assertEquals(200, result.getStatusLine().getStatusCode()); + Assert.assertSame(reconstructed, result); } @Test @@ -2264,12 +2269,13 @@ public class TestProtocolRequirements extends AbstractProtocolTest { CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, mockCache, params); + request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); - EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry); + mockCache.flushInvalidatedCacheEntriesFor(host, request); + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); replayMocks(); - request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse result = impl.execute(host, request); verifyMocks(); @@ -2305,16 +2311,17 @@ public class TestProtocolRequirements extends AbstractProtocolTest { CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, mockCache, params); + request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); - EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry); + mockCache.flushInvalidatedCacheEntriesFor(host, request); + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); EasyMock.expect( mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class), (HttpContext) EasyMock.isNull())).andThrow( new IOException("can't talk to origin!")).anyTimes(); replayMocks(); - request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse result = impl.execute(host, request); @@ -2506,12 +2513,13 @@ public class TestProtocolRequirements extends AbstractProtocolTest { CacheEntry entry = new CacheEntry(tenSecondsAgo, eightSecondsAgo, hdrs, bytes); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, mockCache, params); + request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); - EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry); + mockCache.flushInvalidatedCacheEntriesFor(host, request); + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); replayMocks(); - request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse result = impl.execute(host, request); verifyMocks(); @@ -2550,7 +2558,9 @@ public class TestProtocolRequirements extends AbstractProtocolTest { CacheEntry entry = new CacheEntry(requestTime, responseTime, hdrs, bytes); - impl = new CachingHttpClient(mockBackend, mockCache, new HeapResourceFactory(), params); + impl = new CachingHttpClient(mockBackend, mockCache, params); + + request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse validated = make200Response(); validated.setHeader("Cache-Control", "public"); @@ -2558,18 +2568,20 @@ public class TestProtocolRequirements extends AbstractProtocolTest { validated.setHeader("Content-Length", "128"); validated.setEntity(new ByteArrayEntity(bytes)); + HttpResponse reconstructed = make200Response(); + Capture cap = new Capture(); - EasyMock.expect(mockCache.getEntry("http://foo.example.com/thing")).andReturn(entry); - - mockCache.putEntry(EasyMock.isA(String.class), EasyMock.isA(HttpCacheEntry.class)); - + mockCache.flushInvalidatedCacheEntriesFor(host, request); + EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); EasyMock.expect( mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.capture(cap), (HttpContext) EasyMock.isNull())).andReturn(validated).times(0, 1); + EasyMock.expect(mockCache.updateCacheEntry(EasyMock.same(host), EasyMock.same(request), EasyMock.same(entry), + EasyMock.same(validated), EasyMock.isA(Date.class), EasyMock.isA(Date.class))) + .andReturn(reconstructed).times(0, 1); replayMocks(); - request = new BasicHttpRequest("GET", "/thing", HttpVersion.HTTP_1_1); HttpResponse result = impl.execute(host, request); verifyMocks(); diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCache.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCache.java index 8e60bc695..e69de29bb 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCache.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCache.java @@ -1,171 +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 - * . - * - */ -package org.apache.http.impl.client.cache; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; - -import org.apache.http.client.cache.HttpCacheEntry; -import org.apache.http.client.cache.HttpCacheUpdateCallback; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestResponseCache { - - private BasicHttpCache cache; - private HttpCacheEntry entry; - - @Before - public void setUp() { - cache = new BasicHttpCache(5); - entry = new CacheEntry(); - } - - @Test - public void testEntryRemainsInCacheWhenPutThere() throws Exception { - cache.putEntry("foo", entry); - - HttpCacheEntry cachedEntry = cache.getEntry("foo"); - - Assert.assertSame(entry, cachedEntry); - } - - @Test - public void testRemovedEntriesDoNotExistAnymore() throws Exception { - cache.putEntry("foo", entry); - - cache.removeEntry("foo"); - - HttpCacheEntry nullEntry = cache.getEntry("foo"); - - Assert.assertNull(nullEntry); - } - - @Test - public void testCacheHoldsNoMoreThanSpecifiedMaxEntries() throws Exception { - BasicHttpCache cache = new BasicHttpCache(1); - - HttpCacheEntry entry1 = new CacheEntry(); - cache.putEntry("foo", entry1); - - HttpCacheEntry entry2 = new CacheEntry(); - cache.putEntry("bar", entry2); - - HttpCacheEntry entry3 = new CacheEntry(); - cache.putEntry("baz", entry3); - - HttpCacheEntry e1 = cache.getEntry("foo"); - Assert.assertNull("Got foo entry when we should not", e1); - - HttpCacheEntry e2 = cache.getEntry("bar"); - Assert.assertNull("Got bar entry when we should not", e2); - - HttpCacheEntry e3 = cache.getEntry("baz"); - Assert.assertNotNull("Did not get baz entry, but should have", e3); - } - - @Test - public void testSmallCacheKeepsMostRecentlyUsedEntry() throws Exception { - - final int max_size = 3; - BasicHttpCache cache = new BasicHttpCache(max_size); - - // fill the cache with entries - for (int i = 0; i < max_size; i++) { - HttpCacheEntry entry = new CacheEntry(); - cache.putEntry("entry" + i, entry); - } - - // read the eldest entry to make it the MRU entry - cache.getEntry("entry0"); - - // add another entry, which kicks out the eldest (should be the 2nd one - // created), and becomes the new MRU entry - HttpCacheEntry newMru = new CacheEntry(); - cache.putEntry("newMru", newMru); - - // get the original second eldest - HttpCacheEntry gone = cache.getEntry("entry1"); - Assert.assertNull("entry1 should be gone", gone); - - HttpCacheEntry latest = cache.getEntry("newMru"); - Assert.assertNotNull("latest entry should still be there", latest); - - HttpCacheEntry originalEldest = cache.getEntry("entry0"); - Assert.assertNotNull("original eldest entry should still be there", originalEldest); - } - - @Test - public void testZeroMaxSizeCacheDoesNotStoreAnything() throws Exception { - BasicHttpCache cache = new BasicHttpCache(0); - - HttpCacheEntry entry = new CacheEntry(); - cache.putEntry("foo", entry); - - HttpCacheEntry gone = cache.getEntry("foo"); - - Assert.assertNull("This cache should not have anything in it!", gone); - } - - @Test - public void testCacheEntryCallbackUpdatesCacheEntry() throws Exception { - - final byte[] expectedArray = new byte[] { 1, 2, 3, 4, 5 }; - - HttpCacheEntry entry = new CacheEntry(); - - cache.putEntry("foo", entry); - - cache.updateEntry("foo", new HttpCacheUpdateCallback() { - - public HttpCacheEntry update(HttpCacheEntry existing) { - HttpCacheEntry updated = new HttpCacheEntry( - existing.getRequestDate(), - existing.getRequestDate(), - existing.getStatusLine(), - existing.getAllHeaders(), - new HeapResource(expectedArray), - null); - return updated; - } - }); - - HttpCacheEntry afterUpdate = cache.getEntry("foo"); - - ByteArrayOutputStream outstream = new ByteArrayOutputStream(); - InputStream instream = afterUpdate.getResource().getInputStream(); - byte[] buf = new byte[2048]; - int len; - while ((len = instream.read(buf)) != -1) { - outstream.write(buf, 0, len); - } - byte[] bytes = outstream.toByteArray(); - Assert.assertArrayEquals(expectedArray, bytes); - } - -} diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java index 02141bb2b..a86fe215e 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java @@ -26,18 +26,14 @@ */ package org.apache.http.impl.client.cache; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; -import org.apache.http.message.BasicRequestLine; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.message.BasicHttpResponse; import org.apache.http.util.EntityUtils; -import org.easymock.classextension.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -46,56 +42,44 @@ public class TestSizeLimitedResponseReader { private static final long MAX_SIZE = 4; + private HttpRequest request; private SizeLimitedResponseReader impl; - private HttpRequest mockRequest; - private HttpResponse mockResponse; - private HttpEntity mockEntity; - - private boolean mockedImpl; @Before public void setUp() { - mockRequest = EasyMock.createMock(HttpRequest.class); - mockResponse = EasyMock.createMock(HttpResponse.class); - mockEntity = EasyMock.createMock(HttpEntity.class); + request = new HttpGet("http://foo.example.com/bar"); } @Test public void testLargeResponseIsTooLarge() throws Exception { - byte[] buf = new byte[] { 1, 2, 3, 4, 5}; - requestReturnsRequestLine(); - responseReturnsProtocolVersion(); - responseReturnsHeaders(); - responseReturnsContent(new ByteArrayInputStream(buf)); - initReader(); - replayMocks(); + byte[] buf = new byte[] { 1, 2, 3, 4, 5 }; + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + response.setEntity(new ByteArrayEntity(buf)); + + impl = new SizeLimitedResponseReader(new HeapResourceFactory(), MAX_SIZE, request, response); impl.readResponse(); boolean tooLarge = impl.isLimitReached(); - HttpResponse response = impl.getReconstructedResponse(); - byte[] result = EntityUtils.toByteArray(response.getEntity()); + HttpResponse result = impl.getReconstructedResponse(); + byte[] body = EntityUtils.toByteArray(result.getEntity()); - verifyMocks(); Assert.assertTrue(tooLarge); - Assert.assertArrayEquals(buf, result); + Assert.assertArrayEquals(buf, body); } @Test public void testExactSizeResponseIsNotTooLarge() throws Exception { byte[] buf = new byte[] { 1, 2, 3, 4 }; - requestReturnsRequestLine(); - responseReturnsProtocolVersion(); - responseReturnsHeaders(); - responseReturnsContent(new ByteArrayInputStream(buf)); - initReader(); - replayMocks(); + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + response.setEntity(new ByteArrayEntity(buf)); + + impl = new SizeLimitedResponseReader(new HeapResourceFactory(), MAX_SIZE, request, response); impl.readResponse(); boolean tooLarge = impl.isLimitReached(); - HttpResponse response = impl.getReconstructedResponse(); - byte[] result = EntityUtils.toByteArray(response.getEntity()); + HttpResponse reconstructed = impl.getReconstructedResponse(); + byte[] result = EntityUtils.toByteArray(reconstructed.getEntity()); - verifyMocks(); Assert.assertFalse(tooLarge); Assert.assertArrayEquals(buf, result); } @@ -103,18 +87,15 @@ public class TestSizeLimitedResponseReader { @Test public void testSmallResponseIsNotTooLarge() throws Exception { byte[] buf = new byte[] { 1, 2, 3 }; - requestReturnsRequestLine(); - responseReturnsProtocolVersion(); - responseReturnsHeaders(); - responseReturnsContent(new ByteArrayInputStream(buf)); - initReader(); - replayMocks(); + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + response.setEntity(new ByteArrayEntity(buf)); + + impl = new SizeLimitedResponseReader(new HeapResourceFactory(), MAX_SIZE, request, response); impl.readResponse(); boolean tooLarge = impl.isLimitReached(); - HttpResponse response = impl.getReconstructedResponse(); - byte[] result = EntityUtils.toByteArray(response.getEntity()); - verifyMocks(); + HttpResponse reconstructed = impl.getReconstructedResponse(); + byte[] result = EntityUtils.toByteArray(reconstructed.getEntity()); Assert.assertFalse(tooLarge); Assert.assertArrayEquals(buf, result); @@ -122,56 +103,14 @@ public class TestSizeLimitedResponseReader { @Test public void testResponseWithNoEntityIsNotTooLarge() throws Exception { - responseHasNullEntity(); + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + + impl = new SizeLimitedResponseReader(new HeapResourceFactory(), MAX_SIZE, request, response); - initReader(); - replayMocks(); impl.readResponse(); boolean tooLarge = impl.isLimitReached(); - verifyMocks(); Assert.assertFalse(tooLarge); } - private void responseReturnsContent(InputStream buffer) throws IOException { - EasyMock.expect(mockResponse.getEntity()).andReturn(mockEntity); - EasyMock.expect(mockEntity.getContent()).andReturn(buffer); - } - - private void requestReturnsRequestLine() { - EasyMock.expect(mockRequest.getRequestLine()).andReturn( - new BasicRequestLine("GET", "/", HttpVersion.HTTP_1_1)); - } - - private void responseReturnsProtocolVersion() { - EasyMock.expect(mockResponse.getProtocolVersion()).andReturn(HttpVersion.HTTP_1_1); - } - - private void responseReturnsHeaders() { - EasyMock.expect(mockResponse.getAllHeaders()).andReturn(new Header[] {}); - } - - private void responseHasNullEntity() { - EasyMock.expect(mockResponse.getEntity()).andReturn(null); - } - - private void verifyMocks() { - EasyMock.verify(mockRequest, mockResponse, mockEntity); - if (mockedImpl) { - EasyMock.verify(impl); - } - } - - private void replayMocks() { - EasyMock.replay(mockRequest, mockResponse, mockEntity); - if (mockedImpl) { - EasyMock.replay(impl); - } - } - - private void initReader() { - impl = new SizeLimitedResponseReader( - new HeapResourceFactory(), MAX_SIZE, mockRequest, mockResponse); - } - } diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCache.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCache.java index 393cf7093..f512421bf 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCache.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCache.java @@ -40,11 +40,11 @@ import org.junit.Test; public class TestEhcacheHttpCache extends TestCase { private Ehcache mockCache; - private EhcacheHttpCache impl; + private EhcacheHttpCacheStorage impl; public void setUp() { mockCache = EasyMock.createMock(Ehcache.class); - impl = new EhcacheHttpCache(mockCache); + impl = new EhcacheHttpCacheStorage(mockCache); } @Test diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtcolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtcolRequirements.java index b21de0330..e69de29bb 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtcolRequirements.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtcolRequirements.java @@ -1,99 +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 - * . - * - */ -package org.apache.http.impl.client.cache.ehcache; - -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.config.CacheConfiguration; -import net.sf.ehcache.config.Configuration; -import net.sf.ehcache.store.MemoryStoreEvictionPolicy; - -import org.apache.http.HttpHost; -import org.apache.http.HttpVersion; -import org.apache.http.client.HttpClient; -import org.apache.http.client.cache.HttpCache; -import org.apache.http.impl.client.cache.CacheConfig; -import org.apache.http.impl.client.cache.CachingHttpClient; -import org.apache.http.impl.client.cache.HeapResourceFactory; -import org.apache.http.impl.client.cache.HttpTestUtils; -import org.apache.http.impl.client.cache.TestProtocolRequirements; -import org.apache.http.message.BasicHttpRequest; -import org.easymock.classextension.EasyMock; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; - -public class TestEhcacheProtcolRequirements extends TestProtocolRequirements{ - - private final String TEST_EHCACHE_NAME = "TestEhcacheProtocolRequirements-cache"; - - private static CacheManager CACHE_MANAGER; - - @BeforeClass - public static void setUpGlobal() { - Configuration config = new Configuration(); - config.addDefaultCache( - new CacheConfiguration("default", Integer.MAX_VALUE) - .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU) - .overflowToDisk(false)); - CACHE_MANAGER = CacheManager.create(config); - } - - @Override - @Before - public void setUp() { - host = new HttpHost("foo.example.com"); - - body = HttpTestUtils.makeBody(entityLength); - - request = new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1); - - originResponse = make200Response(); - - if (CACHE_MANAGER.cacheExists(TEST_EHCACHE_NAME)){ - CACHE_MANAGER.removeCache(TEST_EHCACHE_NAME); - } - CACHE_MANAGER.addCache(TEST_EHCACHE_NAME); - cache = new EhcacheHttpCache(CACHE_MANAGER.getCache(TEST_EHCACHE_NAME)); - mockBackend = EasyMock.createMock(HttpClient.class); - mockCache = EasyMock.createMock(HttpCache.class); - params = new CacheConfig(); - params.setMaxObjectSizeBytes(MAX_BYTES); - impl = new CachingHttpClient(mockBackend, cache, new HeapResourceFactory(), params); - } - - @After - public void tearDown(){ - CACHE_MANAGER.removeCache(TEST_EHCACHE_NAME); - } - - @AfterClass - public static void tearDownGlobal(){ - CACHE_MANAGER.shutdown(); - } - -}