Return-Path: X-Original-To: apmail-hc-commits-archive@www.apache.org Delivered-To: apmail-hc-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id EB8A717F69 for ; Fri, 7 Nov 2014 15:24:10 +0000 (UTC) Received: (qmail 69550 invoked by uid 500); 7 Nov 2014 15:24:10 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 69505 invoked by uid 500); 7 Nov 2014 15:24:10 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 69446 invoked by uid 99); 7 Nov 2014 15:24:10 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 07 Nov 2014 15:24:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 07 Nov 2014 15:23:38 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 0E572238899C for ; Fri, 7 Nov 2014 15:23:05 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1637389 [1/2] - in /httpcomponents/httpclient/trunk/httpclient-cache/src: main/java-deprecated/org/apache/http/impl/client/cache/ main/java/org/apache/http/client/cache/ main/java/org/apache/http/impl/client/cache/ test/java/org/apache/htt... Date: Fri, 07 Nov 2014 15:23:03 -0000 To: commits@hc.apache.org From: fx@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20141107152305.0E572238899C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fx Date: Fri Nov 7 15:23:03 2014 New Revision: 1637389 URL: http://svn.apache.org/r1637389 Log: Merge remote-tracking branch 'J-Cutajar/cache-head-responses' into trunk Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedResponseSuitabilityChecker.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExecChain.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseProtocolCompliance.java Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java Fri Nov 7 15:23:03 2014 @@ -162,6 +162,7 @@ public class CachingHttpClient implement private final RequestProtocolCompliance requestCompliance; private final AsynchronousValidator asynchRevalidator; + private final boolean allowHeadResponseCaching; private final Log log = LogFactory.getLog(getClass()); @@ -179,7 +180,8 @@ public class CachingHttpClient implement this.responseCache = cache; this.validityPolicy = new CacheValidityPolicy(); this.responseCachingPolicy = new ResponseCachingPolicy(maxObjectSizeBytes, sharedCache, - config.isNeverCacheHTTP10ResponsesWithQuery(), config.is303CachingEnabled()); + config.isNeverCacheHTTP10ResponsesWithQuery(), config.is303CachingEnabled(), + config.isHeadResponseCachingEnabled()); this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy); this.cacheableRequestPolicy = new CacheableRequestPolicy(); this.suitabilityChecker = new CachedResponseSuitabilityChecker(this.validityPolicy, config); @@ -189,6 +191,7 @@ public class CachingHttpClient implement this.requestCompliance = new RequestProtocolCompliance(config.isWeakETagOnPutDeleteAllowed()); this.asynchRevalidator = makeAsynchronousValidator(config); + this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled(); } /** @@ -301,6 +304,7 @@ public class CachingHttpClient implement this.responseCompliance = responseCompliance; this.requestCompliance = requestCompliance; this.asynchRevalidator = makeAsynchronousValidator(config); + this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled(); } private AsynchronousValidator makeAsynchronousValidator( @@ -445,7 +449,7 @@ public class CachingHttpClient implement flushEntriesInvalidatedByRequest(target, request); - if (!cacheableRequestPolicy.isServableFromCache(request)) { + if (!cacheableRequestPolicy.isServableFromCache(request, allowHeadResponseCaching)) { log.debug("Request is not servable from cache"); return callBackend(target, request, context); } @@ -595,7 +599,7 @@ public class CachingHttpClient implement || request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) { cachedResponse = responseGenerator.generateNotModifiedResponse(entry); } else { - cachedResponse = responseGenerator.generateResponse(entry); + cachedResponse = responseGenerator.generateResponse(request, entry); } setResponseStatus(context, CacheResponseStatus.CACHE_HIT); if (validityPolicy.getStalenessSecs(entry, now) > 0L) { @@ -609,7 +613,7 @@ public class CachingHttpClient implement if (staleResponseNotAllowed(request, entry, now)) { return generateGatewayTimeout(context); } else { - return unvalidatedCacheHit(context, entry); + return unvalidatedCacheHit(request, context, entry); } } @@ -619,9 +623,11 @@ public class CachingHttpClient implement HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout"); } - private HttpResponse unvalidatedCacheHit(final HttpContext context, + private HttpResponse unvalidatedCacheHit( + final HttpRequestWrapper request, + final HttpContext context, final HttpCacheEntry entry) { - final HttpResponse cachedResponse = responseGenerator.generateResponse(entry); + final HttpResponse cachedResponse = responseGenerator.generateResponse(request, entry); setResponseStatus(context, CacheResponseStatus.CACHE_HIT); cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\""); return cachedResponse; @@ -819,7 +825,7 @@ public class CachingHttpClient implement conditionalRequest, requestDate, responseDate, backendResponse, matchingVariant, matchedEntry); - final HttpResponse resp = responseGenerator.generateResponse(responseEntry); + final HttpResponse resp = responseGenerator.generateResponse(request, responseEntry); tryToUpdateVariantMap(target, request, matchingVariant); if (shouldSendNotModifiedResponse(request, responseEntry)) { @@ -901,13 +907,13 @@ public class CachingHttpClient implement && suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) { return responseGenerator.generateNotModifiedResponse(updatedEntry); } - return responseGenerator.generateResponse(updatedEntry); + return responseGenerator.generateResponse(request, updatedEntry); } if (staleIfErrorAppliesTo(statusCode) && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate()) && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) { - final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry); + final HttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry); cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); final HttpEntity errorBody = backendResponse.getEntity(); if (errorBody != null) { Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java Fri Nov 7 15:23:03 2014 @@ -62,6 +62,7 @@ public class HttpCacheEntry implements S private final Resource resource; private final Map variantMap; private final Date date; + private final String requestMethod; /** * Create a new {@link HttpCacheEntry} with variants. @@ -80,6 +81,7 @@ public class HttpCacheEntry implements S * of this parent entry; this maps a "variant key" (derived * from the varying request headers) to a "cache key" (where * in the cache storage the particular variant is located) + * @param requestMethod HTTP method used when the request was made */ public HttpCacheEntry( final Date requestDate, @@ -87,7 +89,8 @@ public class HttpCacheEntry implements S final StatusLine statusLine, final Header[] responseHeaders, final Resource resource, - final Map variantMap) { + final Map variantMap, + final String requestMethod) { super(); Args.notNull(requestDate, "Request date"); Args.notNull(responseDate, "Response date"); @@ -103,6 +106,7 @@ public class HttpCacheEntry implements S ? new HashMap(variantMap) : null; this.date = parseDate(); + this.requestMethod = requestMethod; } /** @@ -119,11 +123,12 @@ public class HttpCacheEntry implements S * @param responseHeaders * Header[] from original HTTP Response * @param resource representing origin response body + * @param requestMethod HTTP method used when the request was made */ public HttpCacheEntry(final Date requestDate, final Date responseDate, final StatusLine statusLine, - final Header[] responseHeaders, final Resource resource) { + final Header[] responseHeaders, final Resource resource, final String requestMethod) { this(requestDate, responseDate, statusLine, responseHeaders, resource, - new HashMap()); + new HashMap(), requestMethod); } /** @@ -251,6 +256,16 @@ public class HttpCacheEntry implements S } /** + * Returns the HTTP request method that was used to create the cached + * response entry. + * + * @since 4.4 + */ + public String getRequestMethod() { + return requestMethod; + } + + /** * Provides a string representation of this instance suitable for * human consumption. */ Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java Fri Nov 7 15:23:03 2014 @@ -51,6 +51,7 @@ import org.apache.http.client.cache.Http import org.apache.http.client.cache.Resource; import org.apache.http.client.cache.ResourceFactory; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpRequestWrapper; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.message.BasicHttpResponse; import org.apache.http.protocol.HTTP; @@ -68,6 +69,7 @@ class BasicHttpCache implements HttpCach private final CachedHttpResponseGenerator responseGenerator; private final HttpCacheInvalidator cacheInvalidator; private final HttpCacheStorage storage; + private final boolean allowHeadResponseCaching; private final Log log = LogFactory.getLog(getClass()); @@ -84,6 +86,7 @@ class BasicHttpCache implements HttpCach this.responseGenerator = new CachedHttpResponseGenerator(); this.storage = storage; this.cacheInvalidator = cacheInvalidator; + this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled(); } public BasicHttpCache( @@ -92,7 +95,7 @@ class BasicHttpCache implements HttpCach final CacheConfig config, final CacheKeyGenerator uriExtractor) { this( resourceFactory, storage, config, uriExtractor, - new CacheInvalidator(uriExtractor, storage)); + new CacheInvalidator(uriExtractor, storage, config.isHeadResponseCachingEnabled())); } public BasicHttpCache( @@ -208,6 +211,9 @@ class BasicHttpCache implements HttpCach } catch (final NumberFormatException nfe) { return false; } + if (resource == null) { + return false; + } return (resource.length() < contentLength); } @@ -219,7 +225,7 @@ class BasicHttpCache implements HttpCach error.setHeader("Content-Type","text/plain;charset=UTF-8"); final String msg = String.format("Received incomplete response " + "with Content-Length %d but actual body length %d", - contentLength, Long.valueOf(resource.length())); + contentLength, resource.length()); final byte[] msgBytes = msg.getBytes(); error.setHeader("Content-Length", Integer.toString(msgBytes.length)); error.setEntity(new ByteArrayEntity(msgBytes)); @@ -249,7 +255,8 @@ class BasicHttpCache implements HttpCach src.getStatusLine(), src.getAllHeaders(), resource, - variantMap); + variantMap, + allowHeadResponseCaching ? src.getRequestMethod() : null); } @Override @@ -261,7 +268,8 @@ class BasicHttpCache implements HttpCach stale, requestSent, responseReceived, - originResponse); + originResponse, + allowHeadResponseCaching); storeInCache(target, request, updatedEntry); return updatedEntry; } @@ -275,7 +283,8 @@ class BasicHttpCache implements HttpCach stale, requestSent, responseReceived, - originResponse); + originResponse, + allowHeadResponseCaching); storage.putEntry(cacheKey, updatedEntry); return updatedEntry; } @@ -317,9 +326,10 @@ class BasicHttpCache implements HttpCach responseReceived, originResponse.getStatusLine(), originResponse.getAllHeaders(), - resource); + resource, + allowHeadResponseCaching ? request.getRequestLine().getMethod() : null); storeInCache(host, request, entry); - return responseGenerator.generateResponse(entry); + return responseGenerator.generateResponse(HttpRequestWrapper.wrap(request, host), entry); } finally { if (closeOriginResponse) { originResponse.close(); Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java Fri Nov 7 15:23:03 2014 @@ -175,6 +175,7 @@ public class CacheConfig implements Clon private int asynchronousWorkerIdleLifetimeSecs; private int revalidationQueueSize; private boolean neverCacheHTTP10ResponsesWithQuery; + private final boolean allowHeadResponseCaching; /** * @deprecated (4.3) use {@link Builder}. @@ -195,6 +196,7 @@ public class CacheConfig implements Clon this.asynchronousWorkersCore = DEFAULT_ASYNCHRONOUS_WORKERS_CORE; this.asynchronousWorkerIdleLifetimeSecs = DEFAULT_ASYNCHRONOUS_WORKER_IDLE_LIFETIME_SECS; this.revalidationQueueSize = DEFAULT_REVALIDATION_QUEUE_SIZE; + this.allowHeadResponseCaching = false; } CacheConfig( @@ -211,7 +213,8 @@ public class CacheConfig implements Clon final int asynchronousWorkersCore, final int asynchronousWorkerIdleLifetimeSecs, final int revalidationQueueSize, - final boolean neverCacheHTTP10ResponsesWithQuery) { + final boolean neverCacheHTTP10ResponsesWithQuery, + final boolean allowHeadResponseCaching) { super(); this.maxObjectSize = maxObjectSize; this.maxCacheEntries = maxCacheEntries; @@ -226,6 +229,7 @@ public class CacheConfig implements Clon this.asynchronousWorkersCore = asynchronousWorkersCore; this.asynchronousWorkerIdleLifetimeSecs = asynchronousWorkerIdleLifetimeSecs; this.revalidationQueueSize = revalidationQueueSize; + this.allowHeadResponseCaching = allowHeadResponseCaching; } /** @@ -501,6 +505,14 @@ public class CacheConfig implements Clon } /** + * Returns whether HEAD response caching is enabled. + * @return {@code true} if it is enabled. + */ + public boolean isHeadResponseCachingEnabled() { + return allowHeadResponseCaching; + } + + /** * Sets the current maximum queue size for background revalidations. * * @deprecated (4.3) use {@link Builder}. @@ -533,6 +545,7 @@ public class CacheConfig implements Clon .setAsynchronousWorkersCore(config.getAsynchronousWorkersCore()) .setAsynchronousWorkerIdleLifetimeSecs(config.getAsynchronousWorkerIdleLifetimeSecs()) .setRevalidationQueueSize(config.getRevalidationQueueSize()) + .setAllowHeadResponseCaching(config.isHeadResponseCachingEnabled()) .setNeverCacheHTTP10ResponsesWithQueryString(config.isNeverCacheHTTP10ResponsesWithQuery()); } @@ -553,6 +566,7 @@ public class CacheConfig implements Clon private int asynchronousWorkerIdleLifetimeSecs; private int revalidationQueueSize; private boolean neverCacheHTTP10ResponsesWithQuery; + private boolean allowHeadResponseCaching; Builder() { this.maxObjectSize = DEFAULT_MAX_OBJECT_SIZE_BYTES; @@ -568,6 +582,7 @@ public class CacheConfig implements Clon this.asynchronousWorkersCore = DEFAULT_ASYNCHRONOUS_WORKERS_CORE; this.asynchronousWorkerIdleLifetimeSecs = DEFAULT_ASYNCHRONOUS_WORKER_IDLE_LIFETIME_SECS; this.revalidationQueueSize = DEFAULT_REVALIDATION_QUEUE_SIZE; + this.allowHeadResponseCaching = false; } /** @@ -708,6 +723,17 @@ public class CacheConfig implements Clon } /** + * Sets whether responses to HEAD requests should be cached or not. + * @param allowHeadResponseCaching should be {@code true} to + * permit HEAD response caching, {@code false} to disable it. + * @param allowHeadResponseCaching + */ + public Builder setAllowHeadResponseCaching(final boolean allowHeadResponseCaching) { + this.allowHeadResponseCaching = allowHeadResponseCaching; + return this; + } + + /** * Sets whether the cache should never cache HTTP 1.0 responses with a query string or not. * @param neverCacheHTTP10ResponsesWithQuery true to never cache responses with a query * string, false to cache if explicit cache headers are found. Set this to {@code true} @@ -735,7 +761,8 @@ public class CacheConfig implements Clon asynchronousWorkersCore, asynchronousWorkerIdleLifetimeSecs, revalidationQueueSize, - neverCacheHTTP10ResponsesWithQuery); + neverCacheHTTP10ResponsesWithQuery, + allowHeadResponseCaching); } } @@ -757,6 +784,7 @@ public class CacheConfig implements Clon .append(", asynchronousWorkerIdleLifetimeSecs=").append(this.asynchronousWorkerIdleLifetimeSecs) .append(", revalidationQueueSize=").append(this.revalidationQueueSize) .append(", neverCacheHTTP10ResponsesWithQuery=").append(this.neverCacheHTTP10ResponsesWithQuery) + .append(", headResponseCachingEnabled=").append(this.allowHeadResponseCaching) .append("]"); return builder.toString(); } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java Fri Nov 7 15:23:03 2014 @@ -75,6 +75,7 @@ class CacheEntryUpdater { * @param requestDate When the request was performed * @param responseDate When the response was gotten * @param response The HttpResponse from the backend server call + * @param allowHeadResponseCaching Should the cache entry include the request method * @return HttpCacheEntry an updated version of the cache entry * @throws java.io.IOException if something bad happens while trying to read the body from the original entry */ @@ -83,7 +84,8 @@ class CacheEntryUpdater { final HttpCacheEntry entry, final Date requestDate, final Date responseDate, - final HttpResponse response) throws IOException { + final HttpResponse response, + final boolean allowHeadResponseCaching) throws IOException { Args.check(response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED, "Response must have 304 status code"); final Header[] mergedHeaders = mergeHeaders(entry, response); @@ -96,7 +98,8 @@ class CacheEntryUpdater { responseDate, entry.getStatusLine(), mergedHeaders, - resource); + resource, + allowHeadResponseCaching ? entry.getRequestMethod() : null); } protected Header[] mergeHeaders(final HttpCacheEntry entry, final HttpResponse response) { Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java Fri Nov 7 15:23:03 2014 @@ -56,6 +56,7 @@ class CacheInvalidator implements HttpCa private final HttpCacheStorage storage; private final CacheKeyGenerator cacheKeyGenerator; + private final boolean allowHeadResponseCaching; private final Log log = LogFactory.getLog(getClass()); @@ -65,12 +66,15 @@ class CacheInvalidator implements HttpCa * * @param uriExtractor Provides identifiers for the keys to store cache entries * @param storage the cache to store items away in + * @param allowHeadResponseCaching is HEAD response caching enabled */ public CacheInvalidator( final CacheKeyGenerator uriExtractor, - final HttpCacheStorage storage) { + final HttpCacheStorage storage, + final boolean allowHeadResponseCaching) { this.cacheKeyGenerator = uriExtractor; this.storage = storage; + this.allowHeadResponseCaching = allowHeadResponseCaching; } /** @@ -82,15 +86,11 @@ class CacheInvalidator implements HttpCa */ @Override public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest req) { - if (requestShouldNotBeCached(req)) { - log.debug("Request should not be cached"); - - final String theUri = cacheKeyGenerator.getURI(host, req); - - final HttpCacheEntry parent = getEntry(theUri); - - log.debug("parent entry: " + parent); + final String theUri = cacheKeyGenerator.getURI(host, req); + final HttpCacheEntry parent = getEntry(theUri); + if (requestShouldNotBeCached(req) || shouldInvalidateHeadCacheEntry(req, parent)) { + log.debug("Invalidating parent cache entry: " + parent); if (parent != null) { for (final String variantURI : parent.getVariantMap().values()) { flushEntry(variantURI); @@ -116,6 +116,18 @@ class CacheInvalidator implements HttpCa } } + private boolean shouldInvalidateHeadCacheEntry(final HttpRequest req, final HttpCacheEntry parentCacheEntry) { + return allowHeadResponseCaching && requestIsGet(req) && isAHeadCacheEntry(parentCacheEntry); + } + + private boolean requestIsGet(final HttpRequest req) { + return req.getRequestLine().getMethod().equals((HeaderConstants.GET_METHOD)); + } + + private boolean isAHeadCacheEntry(final HttpCacheEntry parentCacheEntry) { + return parentCacheEntry != null && parentCacheEntry.getRequestMethod().equals(HeaderConstants.HEAD_METHOD); + } + private void flushEntry(final String uri) { try { storage.removeEntry(uri); Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java Fri Nov 7 15:23:03 2014 @@ -214,7 +214,8 @@ class CacheValidityPolicy { * @return boolean indicating whether actual length matches Content-Length */ protected boolean contentLengthHeaderMatchesActualLength(final HttpCacheEntry entry) { - return !hasContentLengthHeader(entry) || getContentLengthValue(entry) == entry.getResource().length(); + return !hasContentLengthHeader(entry) || + (entry.getResource() != null && getContentLengthValue(entry) == entry.getResource().length()); } protected long getApparentAgeSecs(final HttpCacheEntry entry) { Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java Fri Nov 7 15:23:03 2014 @@ -49,11 +49,11 @@ class CacheableRequestPolicy { /** * Determines if an HttpRequest can be served from the cache. * - * @param request - * an HttpRequest + * @param request an HttpRequest + * @param allowHeadResponseCaching is HEAD response caching enabled * @return boolean Is it possible to serve this request from cache */ - public boolean isServableFromCache(final HttpRequest request) { + public boolean isServableFromCache(final HttpRequest request, final boolean allowHeadResponseCaching) { final String method = request.getRequestLine().getMethod(); final ProtocolVersion pv = request.getRequestLine().getProtocolVersion(); @@ -62,8 +62,9 @@ class CacheableRequestPolicy { return false; } - if (!method.equals(HeaderConstants.GET_METHOD)) { - log.trace("non-GET request was not serveable from cache"); + if (!(method.equals(HeaderConstants.GET_METHOD) || + (allowHeadResponseCaching && method.equals(HeaderConstants.HEAD_METHOD)))) { + log.trace("non-GET or non-HEAD request was not serveable from cache"); return false; } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java Fri Nov 7 15:23:03 2014 @@ -37,6 +37,7 @@ import org.apache.http.annotation.Immuta import org.apache.http.client.cache.HeaderConstants; import org.apache.http.client.cache.HttpCacheEntry; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpRequestWrapper; import org.apache.http.client.utils.DateUtils; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpResponse; @@ -64,19 +65,18 @@ class CachedHttpResponseGenerator { /** * If I was able to use a {@link CacheEntity} to response to the {@link org.apache.http.HttpRequest} then * generate an {@link HttpResponse} based on the cache entry. - * @param entry - * {@link CacheEntity} to transform into an {@link HttpResponse} + * @param request {@link HttpRequestWrapper} to generate the response for + * @param entry {@link CacheEntity} to transform into an {@link HttpResponse} * @return {@link HttpResponse} that was constructed */ - CloseableHttpResponse generateResponse(final HttpCacheEntry entry) { - + CloseableHttpResponse generateResponse(final HttpRequestWrapper request, final HttpCacheEntry entry) { final Date now = new Date(); final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, entry .getStatusCode(), entry.getReasonPhrase()); response.setHeaders(entry.getAllHeaders()); - if (entry.getResource() != null) { + if (responseShouldContainEntity(request, entry)) { final HttpEntity entity = new CacheEntity(entry); addMissingContentLengthHeader(response, entity); response.setEntity(entity); @@ -163,4 +163,10 @@ class CachedHttpResponseGenerator { final Header hdr = response.getFirstHeader(HTTP.TRANSFER_ENCODING); return hdr != null; } + + private boolean responseShouldContainEntity(final HttpRequestWrapper request, final HttpCacheEntry cacheEntry) { + return request.getRequestLine().getMethod().equals(HeaderConstants.GET_METHOD) && + cacheEntry.getResource() != null; + } + } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java Fri Nov 7 15:23:03 2014 @@ -56,6 +56,7 @@ class CachedResponseSuitabilityChecker { private final float heuristicCoefficient; private final long heuristicDefaultLifetime; private final CacheValidityPolicy validityStrategy; + private final boolean allowHeadResponseCaching; CachedResponseSuitabilityChecker(final CacheValidityPolicy validityStrategy, final CacheConfig config) { @@ -65,6 +66,7 @@ class CachedResponseSuitabilityChecker { this.useHeuristicCaching = config.isHeuristicCachingEnabled(); this.heuristicCoefficient = config.getHeuristicCoefficient(); this.heuristicDefaultLifetime = config.getHeuristicDefaultLifetime(); + this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled(); } CachedResponseSuitabilityChecker(final CacheConfig config) { @@ -143,13 +145,12 @@ class CachedResponseSuitabilityChecker { * @return boolean yes/no answer */ public boolean canCachedResponseBeUsed(final HttpHost host, final HttpRequest request, final HttpCacheEntry entry, final Date now) { - if (!isFreshEnough(entry, request, now)) { log.trace("Cache entry was not fresh enough"); return false; } - if (!validityStrategy.contentLengthHeaderMatchesActualLength(entry)) { + if (isGet(request) && !validityStrategy.contentLengthHeaderMatchesActualLength(entry)) { log.debug("Cache entry Content-Length and header information do not match"); return false; } @@ -160,13 +161,19 @@ class CachedResponseSuitabilityChecker { } if (!isConditional(request) && entry.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { - return false; + return false; } if (isConditional(request) && !allConditionalsMatch(request, entry, now)) { return false; } + if (allowHeadResponseCaching && hasUnsupportedCacheEntryForGet(request, entry)) { + log.debug("HEAD response caching enabled but the cache entry does not contain a " + + "request method, entity or a 204 response"); + return false; + } + for (final Header ccHdr : request.getHeaders(HeaderConstants.CACHE_CONTROL)) { for (final HeaderElement elt : ccHdr.getElements()) { if (HeaderConstants.CACHE_CONTROL_NO_CACHE.equals(elt.getName())) { @@ -233,6 +240,22 @@ class CachedResponseSuitabilityChecker { return true; } + private boolean isGet(final HttpRequest request) { + return request.getRequestLine().getMethod().equals(HeaderConstants.GET_METHOD); + } + + private boolean entryIsNotA204Response(final HttpCacheEntry entry) { + return entry.getStatusCode() != HttpStatus.SC_NO_CONTENT; + } + + private boolean cacheEntryDoesNotContainMethodAndEntity(final HttpCacheEntry entry) { + return entry.getRequestMethod() == null && entry.getResource() == null; + } + + private boolean hasUnsupportedCacheEntryForGet(final HttpRequest request, final HttpCacheEntry entry) { + return isGet(request) && cacheEntryDoesNotContainMethodAndEntity(entry) && entryIsNotA204Response(entry); + } + /** * Is this request the type of conditional request we support? * @param request The current httpRequest being made Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java Fri Nov 7 15:23:03 2014 @@ -153,7 +153,8 @@ public class CachingExec implements Clie this.requestCompliance = new RequestProtocolCompliance(this.cacheConfig.isWeakETagOnPutDeleteAllowed()); this.responseCachingPolicy = new ResponseCachingPolicy( this.cacheConfig.getMaxObjectSize(), this.cacheConfig.isSharedCache(), - this.cacheConfig.isNeverCacheHTTP10ResponsesWithQuery(), this.cacheConfig.is303CachingEnabled()); + this.cacheConfig.isNeverCacheHTTP10ResponsesWithQuery(), this.cacheConfig.is303CachingEnabled(), + this.cacheConfig.isHeadResponseCachingEnabled()); this.asynchRevalidator = asynchRevalidator; } @@ -264,7 +265,7 @@ public class CachingExec implements Clie flushEntriesInvalidatedByRequest(context.getTargetHost(), request); - if (!cacheableRequestPolicy.isServableFromCache(request)) { + if (!cacheableRequestPolicy.isServableFromCache(request, cacheConfig.isHeadResponseCachingEnabled())) { log.debug("Request is not servable from cache"); return callBackend(route, request, context, execAware); } @@ -423,14 +424,17 @@ public class CachingExec implements Clie } } - private CloseableHttpResponse generateCachedResponse(final HttpRequestWrapper request, - final HttpContext context, final HttpCacheEntry entry, final Date now) { + private CloseableHttpResponse generateCachedResponse( + final HttpRequestWrapper request, + final HttpContext context, + final HttpCacheEntry entry, + final Date now) { final CloseableHttpResponse cachedResponse; if (request.containsHeader(HeaderConstants.IF_NONE_MATCH) || request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) { cachedResponse = responseGenerator.generateNotModifiedResponse(entry); } else { - cachedResponse = responseGenerator.generateResponse(entry); + cachedResponse = responseGenerator.generateResponse(request, entry); } setResponseStatus(context, CacheResponseStatus.CACHE_HIT); if (validityPolicy.getStalenessSecs(entry, now) > 0L) { @@ -447,7 +451,7 @@ public class CachingExec implements Clie if (staleResponseNotAllowed(request, entry, now)) { return generateGatewayTimeout(context); } else { - return unvalidatedCacheHit(context, entry); + return unvalidatedCacheHit(request, context, entry); } } @@ -460,8 +464,10 @@ public class CachingExec implements Clie } private CloseableHttpResponse unvalidatedCacheHit( - final HttpContext context, final HttpCacheEntry entry) { - final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(entry); + final HttpRequestWrapper request, + final HttpContext context, + final HttpCacheEntry entry) { + final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(request, entry); setResponseStatus(context, CacheResponseStatus.CACHE_HIT); cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\""); return cachedResponse; @@ -526,8 +532,8 @@ public class CachingExec implements Clie final String release = (vi != null) ? vi.getRelease() : VersionInfo.UNAVAILABLE; String value; - final Integer major = Integer.valueOf(pv.getMajor()); - final Integer minor = Integer.valueOf(pv.getMinor()); + final int major = pv.getMajor(); + final int minor = pv.getMinor(); if ("http".equalsIgnoreCase(pv.getProtocol())) { value = String.format("%d.%d localhost (Apache-HttpClient/%s (cache))", major, minor, release); @@ -676,7 +682,7 @@ public class CachingExec implements Clie backendResponse, matchingVariant, matchedEntry); backendResponse.close(); - final CloseableHttpResponse resp = responseGenerator.generateResponse(responseEntry); + final CloseableHttpResponse resp = responseGenerator.generateResponse(request, responseEntry); tryToUpdateVariantMap(context.getTargetHost(), request, matchingVariant); if (shouldSendNotModifiedResponse(request, responseEntry)) { @@ -788,14 +794,14 @@ public class CachingExec implements Clie return responseGenerator .generateNotModifiedResponse(updatedEntry); } - return responseGenerator.generateResponse(updatedEntry); + return responseGenerator.generateResponse(request, updatedEntry); } if (staleIfErrorAppliesTo(statusCode) && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate()) && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) { try { - final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry); + final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry); cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); return cachedResponse; } finally { Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java Fri Nov 7 15:23:03 2014 @@ -140,7 +140,7 @@ public class CachingHttpClientBuilder ex HttpCacheInvalidator cacheInvalidator = this.httpCacheInvalidator; if (cacheInvalidator == null) { - cacheInvalidator = new CacheInvalidator(uriExtractor, storageCopy); + cacheInvalidator = new CacheInvalidator(uriExtractor, storageCopy, config.isHeadResponseCachingEnabled()); } return new CachingExec(mainExec, Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java Fri Nov 7 15:23:03 2014 @@ -67,6 +67,8 @@ class ResponseCachingPolicy { HttpStatus.SC_MOVED_PERMANENTLY, HttpStatus.SC_GONE)); private final Set uncacheableStatuses; + private final boolean allowHeadResponseCaching; + /** * Define a cache policy that limits the size of things that should be stored * in the cache to a maximum of {@link HttpResponse} bytes in size. @@ -77,11 +79,13 @@ class ResponseCachingPolicy { * @param neverCache1_0ResponsesWithQueryString true to never cache HTTP 1.0 responses with a query string, false * to cache if explicit cache headers are found. * @param allow303Caching if this policy is permitted to cache 303 response + * @param allowHeadResponseCaching is HEAD response caching enabled */ public ResponseCachingPolicy(final long maxObjectSizeBytes, final boolean sharedCache, final boolean neverCache1_0ResponsesWithQueryString, - final boolean allow303Caching) { + final boolean allow303Caching, + final boolean allowHeadResponseCaching) { this.maxObjectSizeBytes = maxObjectSizeBytes; this.sharedCache = sharedCache; this.neverCache1_0ResponsesWithQueryString = neverCache1_0ResponsesWithQueryString; @@ -92,6 +96,7 @@ class ResponseCachingPolicy { uncacheableStatuses = new HashSet(Arrays.asList( HttpStatus.SC_PARTIAL_CONTENT, HttpStatus.SC_SEE_OTHER)); } + this.allowHeadResponseCaching = allowHeadResponseCaching; } /** @@ -104,7 +109,8 @@ class ResponseCachingPolicy { public boolean isResponseCacheable(final String httpMethod, final HttpResponse response) { boolean cacheable = false; - if (!HeaderConstants.GET_METHOD.equals(httpMethod)) { + if (!(HeaderConstants.GET_METHOD.equals(httpMethod) || + (allowHeadResponseCaching && HeaderConstants.HEAD_METHOD.equals(httpMethod)))) { log.debug("Response was not cacheable."); return false; } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java Fri Nov 7 15:23:03 2014 @@ -70,7 +70,7 @@ public class TestHttpCacheEntry { private HttpCacheEntry makeEntry(final Header[] headers) { return new HttpCacheEntry(elevenSecondsAgo, nineSecondsAgo, - statusLine, headers, mockResource); + statusLine, headers, mockResource, HeaderConstants.GET_METHOD); } @Test @@ -148,7 +148,7 @@ public class TestHttpCacheEntry { public void mustProvideRequestDate() { try { new HttpCacheEntry(null, new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); fail("Should have thrown exception"); } catch (final IllegalArgumentException expected) { } @@ -159,7 +159,7 @@ public class TestHttpCacheEntry { public void mustProvideResponseDate() { try { new HttpCacheEntry(new Date(), null, statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); fail("Should have thrown exception"); } catch (final IllegalArgumentException expected) { } @@ -170,7 +170,7 @@ public class TestHttpCacheEntry { public void mustProvideStatusLine() { try { new HttpCacheEntry(new Date(), new Date(), null, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); fail("Should have thrown exception"); } catch (final IllegalArgumentException expected) { } @@ -181,7 +181,7 @@ public class TestHttpCacheEntry { public void mustProvideResponseHeaders() { try { new HttpCacheEntry(new Date(), new Date(), statusLine, - null, mockResource); + null, mockResource, HeaderConstants.GET_METHOD); fail("Should have thrown exception"); } catch (final IllegalArgumentException expected) { } @@ -190,14 +190,14 @@ public class TestHttpCacheEntry { @Test public void canRetrieveOriginalStatusLine() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(statusLine, entry.getStatusLine()); } @Test public void protocolVersionComesFromOriginalStatusLine() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(statusLine.getProtocolVersion(), entry.getProtocolVersion()); } @@ -205,14 +205,14 @@ public class TestHttpCacheEntry { @Test public void reasonPhraseComesFromOriginalStatusLine() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(statusLine.getReasonPhrase(), entry.getReasonPhrase()); } @Test public void statusCodeComesFromOriginalStatusLine() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertEquals(statusLine.getStatusCode(), entry.getStatusCode()); } @@ -220,7 +220,7 @@ public class TestHttpCacheEntry { public void canGetOriginalRequestDate() { final Date requestDate = new Date(); entry = new HttpCacheEntry(requestDate, new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(requestDate, entry.getRequestDate()); } @@ -228,14 +228,14 @@ public class TestHttpCacheEntry { public void canGetOriginalResponseDate() { final Date responseDate = new Date(); entry = new HttpCacheEntry(new Date(), responseDate, statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(responseDate, entry.getResponseDate()); } @Test public void canGetOriginalResource() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertSame(mockResource, entry.getResource()); } @@ -246,7 +246,7 @@ public class TestHttpCacheEntry { new BasicHeader("Date", DateUtils.formatDate(now)) }; entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - headers, mockResource); + headers, mockResource, HeaderConstants.GET_METHOD); final Header[] result = entry.getAllHeaders(); assertEquals(headers.length, result.length); for(int i=0; i()); + new HashMap(), HeaderConstants.GET_METHOD); } @Test @@ -276,7 +276,7 @@ public class TestHttpCacheEntry { variantMap.put("C","D"); entry = new HttpCacheEntry(new Date(), new Date(), statusLine, new Header[]{}, mockResource, - variantMap); + variantMap, HeaderConstants.GET_METHOD); final Map result = entry.getVariantMap(); assertEquals(2, result.size()); assertEquals("B", result.get("A")); @@ -290,7 +290,7 @@ public class TestHttpCacheEntry { variantMap.put("C","D"); entry = new HttpCacheEntry(new Date(), new Date(), statusLine, new Header[]{}, mockResource, - variantMap); + variantMap, HeaderConstants.GET_METHOD); final Map result = entry.getVariantMap(); try { result.remove("A"); @@ -307,7 +307,7 @@ public class TestHttpCacheEntry { @Test public void canConvertToString() { entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - new Header[]{}, mockResource); + new Header[]{}, mockResource, HeaderConstants.GET_METHOD); assertNotNull(entry.toString()); assertFalse("".equals(entry.toString())); } @@ -316,7 +316,7 @@ public class TestHttpCacheEntry { public void testMissingDateHeaderIsIgnored() { final Header[] headers = new Header[] {}; entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - headers, mockResource); + headers, mockResource, HeaderConstants.GET_METHOD); assertNull(entry.getDate()); } @@ -324,7 +324,7 @@ public class TestHttpCacheEntry { public void testMalformedDateHeaderIsIgnored() { final Header[] headers = new Header[] { new BasicHeader("Date", "asdf") }; entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - headers, mockResource); + headers, mockResource, HeaderConstants.GET_METHOD); assertNull(entry.getDate()); } @@ -335,10 +335,19 @@ public class TestHttpCacheEntry { final Date date = new Date(nowMs - (nowMs % 1000L)); final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils.formatDate(date)) }; entry = new HttpCacheEntry(new Date(), new Date(), statusLine, - headers, mockResource); + headers, mockResource, HeaderConstants.GET_METHOD); final Date dateHeaderValue = entry.getDate(); assertNotNull(dateHeaderValue); assertEquals(date.getTime(), dateHeaderValue.getTime()); } + @Test + public void testGetMethodReturnsCorrectRequestMethod() { + final Header[] headers = { new BasicHeader("foo", "fooValue"), + new BasicHeader("bar", "barValue1"), + new BasicHeader("bar", "barValue2") + }; + entry = makeEntry(headers); + assertEquals(HeaderConstants.GET_METHOD, entry.getRequestMethod()); + } } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java Fri Nov 7 15:23:03 2014 @@ -28,6 +28,7 @@ package org.apache.http.impl.client.cach import java.io.InputStream; import java.util.Date; +import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -41,6 +42,7 @@ import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.RequestLine; import org.apache.http.StatusLine; +import org.apache.http.client.cache.HeaderConstants; import org.apache.http.client.cache.HttpCacheEntry; import org.apache.http.client.utils.DateUtils; import org.apache.http.entity.ByteArrayEntity; @@ -299,8 +301,7 @@ public class HttpTestUtils { public static HttpCacheEntry makeCacheEntry(final Date requestDate, final Date responseDate, final Header[] headers, final byte[] bytes, final Map variantMap) { - final StatusLine statusLine = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); - return new HttpCacheEntry(requestDate, responseDate, statusLine, headers, new HeapResource(bytes), variantMap); + return new HttpCacheEntry(requestDate, responseDate, makeStatusLine(), headers, new HeapResource(bytes), variantMap, HeaderConstants.GET_METHOD); } public static HttpCacheEntry makeCacheEntry(final Header[] headers, final byte[] bytes) { @@ -321,6 +322,39 @@ public class HttpTestUtils { return makeCacheEntry(now, now); } + public static HttpCacheEntry makeCacheEntryWithNoRequestMethodOrEntity(final Header[] headers) { + final Date now = new Date(); + return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null); + } + + public static HttpCacheEntry makeCacheEntryWithNoRequestMethod(final Header[] headers) { + final Date now = new Date(); + return new HttpCacheEntry(now, now, makeStatusLine(), headers, new HeapResource(getRandomBytes(128)), null, null); + } + + public static HttpCacheEntry make204CacheEntryWithNoRequestMethod(final Header[] headers) { + final Date now = new Date(); + return new HttpCacheEntry(now, now, make204StatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD); + } + + public static HttpCacheEntry makeHeadCacheEntry(final Header[] headers) { + final Date now = new Date(); + return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD); + } + + public static HttpCacheEntry makeHeadCacheEntryWithNoRequestMethod(final Header[] headers) { + final Date now = new Date(); + return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null); + } + + public static StatusLine makeStatusLine() { + return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + } + + public static StatusLine make204StatusLine() { + return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "OK"); + } + public static HttpResponse make200Response() { final HttpResponse out = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); out.setHeader("Date", DateUtils.formatDate(new Date())); @@ -356,8 +390,19 @@ public class HttpTestUtils { return new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1); } + public static HttpRequest makeDefaultHEADRequest() { + return new BasicHttpRequest("HEAD","/",HttpVersion.HTTP_1_1); + } + public static HttpResponse make500Response() { return new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); } + + public static Map makeDefaultVariantMap(final String key, final String value) { + final Map variants = new HashMap(); + variants.put(key, value); + + return variants; + } } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java Fri Nov 7 15:23:03 2014 @@ -263,6 +263,15 @@ public class TestBasicHttpCache { } @Test + public void testNullResourcesAreComplete() + throws Exception { + final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + resp.setHeader("Content-Length","256"); + + assertFalse(impl.isIncompleteResponse(resp, null)); + } + + @Test public void testIncompleteResponseErrorProvidesPlainTextErrorMessage() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java Fri Nov 7 15:23:03 2014 @@ -80,7 +80,7 @@ public class TestCacheEntryUpdater { throws IOException { entry = HttpTestUtils.makeCacheEntry(); final HttpCacheEntry newEntry = impl.updateCacheEntry(null, entry, - requestDate, responseDate, response); + requestDate, responseDate, response, false); assertNotSame(newEntry, entry); } @@ -93,7 +93,7 @@ public class TestCacheEntryUpdater { response.setHeaders(new Header[]{}); final HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, entry, - new Date(), new Date(), response); + new Date(), new Date(), response, false); final Header[] updatedHeaders = updatedEntry.getAllHeaders(); @@ -117,7 +117,7 @@ public class TestCacheEntryUpdater { new BasicHeader("Cache-Control", "public")}); final HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, entry, - new Date(), new Date(), response); + new Date(), new Date(), response, false); final Header[] updatedHeaders = updatedEntry.getAllHeaders(); @@ -141,7 +141,7 @@ public class TestCacheEntryUpdater { new BasicHeader("Cache-Control", "public"),}); final HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, entry, - new Date(), new Date(), response); + new Date(), new Date(), response, false); final Header[] updatedHeaders = updatedEntry.getAllHeaders(); assertEquals(4, updatedHeaders.length); @@ -163,7 +163,7 @@ public class TestCacheEntryUpdater { response.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); response.setHeader("ETag", "\"old-etag\""); final HttpCacheEntry result = impl.updateCacheEntry("A", entry, new Date(), - new Date(), response); + new Date(), response, false); assertEquals(2, result.getAllHeaders().length); headersContain(result.getAllHeaders(), "Date", DateUtils.formatDate(oneSecondAgo)); headersContain(result.getAllHeaders(), "ETag", "\"new-etag\""); @@ -174,7 +174,7 @@ public class TestCacheEntryUpdater { throws IOException { entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, eightSecondsAgo); final HttpCacheEntry updated = impl.updateCacheEntry(null, entry, - twoSecondsAgo, oneSecondAgo, response); + twoSecondsAgo, oneSecondAgo, response, false); assertEquals(twoSecondsAgo, updated.getRequestDate()); assertEquals(oneSecondAgo, updated.getResponseDate()); @@ -191,7 +191,7 @@ public class TestCacheEntryUpdater { response.setHeader("ETag", "\"new\""); response.setHeader("Date", DateUtils.formatDate(twoSecondsAgo)); final HttpCacheEntry updated = impl.updateCacheEntry(null, entry, - twoSecondsAgo, oneSecondAgo, response); + twoSecondsAgo, oneSecondAgo, response, false); assertEquals(0, updated.getHeaders("Warning").length); } @@ -206,7 +206,7 @@ public class TestCacheEntryUpdater { response.setHeader("ETag", "\"new\""); response.setHeader("Date", DateUtils.formatDate(twoSecondsAgo)); final HttpCacheEntry updated = impl.updateCacheEntry(null, entry, - twoSecondsAgo, oneSecondAgo, response); + twoSecondsAgo, oneSecondAgo, response, false); assertEquals("\"new\"", updated.getFirstHeader("ETag").getValue()); } @@ -221,7 +221,7 @@ public class TestCacheEntryUpdater { response.setHeader("ETag", "\"new\""); response.setHeader("Date", "bad-date"); final HttpCacheEntry updated = impl.updateCacheEntry(null, entry, - twoSecondsAgo, oneSecondAgo, response); + twoSecondsAgo, oneSecondAgo, response, false); assertEquals("\"new\"", updated.getFirstHeader("ETag").getValue()); } @@ -233,7 +233,7 @@ public class TestCacheEntryUpdater { HttpStatus.SC_OK, "OK"); try { impl.updateCacheEntry("A", entry, new Date(), new Date(), - response); + response, false); fail("should have thrown exception"); } catch (final IllegalArgumentException expected) { } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java Fri Nov 7 15:23:03 2014 @@ -84,7 +84,7 @@ public class TestCacheInvalidator { request = HttpTestUtils.makeDefaultRequest(); response = HttpTestUtils.make200Response(); - impl = new CacheInvalidator(cacheKeyGenerator, mockStorage); + impl = new CacheInvalidator(cacheKeyGenerator, mockStorage, false); } private void replayMocks() { @@ -222,6 +222,81 @@ public class TestCacheInvalidator { } @Test + public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception { + impl = new CacheInvalidator(cacheKeyGenerator, mockStorage, true); + final String theURI = "http://foo.example.com:80/"; + request = new BasicHttpRequest("GET", theURI,HTTP_1_1); + + cacheEntryisForMethod("HEAD"); + cacheEntryHasVariantMap(new HashMap()); + cacheReturnsEntryForUri(theURI); + entryIsRemoved(theURI); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request); + verifyMocks(); + } + + @Test + public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception { + impl = new CacheInvalidator(cacheKeyGenerator, mockStorage, true); + final String theURI = "http://foo.example.com:80/"; + request = new BasicHttpRequest("GET", theURI,HTTP_1_1); + final String theVariantKey = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}"; + final String theVariantURI = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}http://foo.example.com:80/"; + final Map variants = HttpTestUtils.makeDefaultVariantMap(theVariantKey, theVariantURI); + + cacheEntryisForMethod("HEAD"); + cacheEntryHasVariantMap(variants); + cacheReturnsEntryForUri(theURI); + entryIsRemoved(theURI); + entryIsRemoved(theVariantURI); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request); + verifyMocks(); + } + + @Test + public void testDoesNotInvalidateHEADCacheEntryIfHEADResponseCachingIsNotEnabled() throws Exception { + final String theURI = "http://foo.example.com:80/"; + request = new BasicHttpRequest("HEAD", theURI,HTTP_1_1); + + cacheReturnsEntryForUri(theURI); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request); + verifyMocks(); + } + + @Test + public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() throws Exception { + impl = new CacheInvalidator(cacheKeyGenerator, mockStorage, true); + final String theURI = "http://foo.example.com:80/"; + request = new BasicHttpRequest("HEAD", theURI,HTTP_1_1); + + cacheReturnsEntryForUri(theURI); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request); + verifyMocks(); + } + + @Test + public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception { + impl = new CacheInvalidator(cacheKeyGenerator, mockStorage, true); + final String theURI = "http://foo.example.com:80/"; + request = new BasicHttpRequest("GET", theURI,HTTP_1_1); + + cacheEntryisForMethod("GET"); + cacheReturnsEntryForUri(theURI); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request); + verifyMocks(); + } + + @Test public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws Exception { request = new BasicHttpRequest("GET","/",HTTP_1_1); request.setHeader("Cache-Control","no-cache"); @@ -244,9 +319,7 @@ public class TestCacheInvalidator { request = new BasicHttpRequest("POST","/",HTTP_1_1); final String theUri = "http://foo.example.com:80/"; final String variantUri = "theVariantURI"; - - final Map mapOfURIs = new HashMap(); - mapOfURIs.put(variantUri,variantUri); + final Map mapOfURIs = HttpTestUtils.makeDefaultVariantMap(variantUri, variantUri); cacheReturnsEntryForUri(theUri); cacheEntryHasVariantMap(mapOfURIs); @@ -651,4 +724,8 @@ public class TestCacheInvalidator { mockStorage.removeEntry(theUri); } + private void cacheEntryisForMethod(final String httpMethod) { + expect(mockEntry.getRequestMethod()).andReturn(httpMethod); + } + } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java Fri Nov 7 15:23:03 2014 @@ -355,6 +355,14 @@ public class TestCacheValidityPolicy { } @Test + public void testNullResourceInvalidatesEntry() { + final int contentLength = 128; + final Header[] headers = {new BasicHeader(HTTP.CONTENT_LEN, Integer.toString(contentLength))}; + final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(headers); + assertFalse(impl.contentLengthHeaderMatchesActualLength(entry)); + } + + @Test public void testMalformedContentLengthReturnsNegativeOne() { final Header[] headers = new Header[] { new BasicHeader("Content-Length", "asdf") }; final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers); Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java Fri Nov 7 15:23:03 2014 @@ -35,6 +35,8 @@ public class TestCacheableRequestPolicy private CacheableRequestPolicy policy; + private final boolean allowHeadResponseCaching = true; + @Before public void setUp() throws Exception { policy = new CacheableRequestPolicy(); @@ -44,8 +46,7 @@ public class TestCacheableRequestPolicy public void testIsGetServableFromCache() { final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri"); - Assert.assertTrue(policy.isServableFromCache(request)); - + Assert.assertTrue(policy.isServableFromCache(request, !allowHeadResponseCaching)); } @Test @@ -53,19 +54,19 @@ public class TestCacheableRequestPolicy BasicHttpRequest request = new BasicHttpRequest("GET", "someUri"); request.addHeader("Cache-Control", "no-cache"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); request = new BasicHttpRequest("GET", "someUri"); request.addHeader("Cache-Control", "no-store"); request.addHeader("Cache-Control", "max-age=20"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); request = new BasicHttpRequest("GET", "someUri"); request.addHeader("Cache-Control", "public"); request.addHeader("Cache-Control", "no-store, max-age=20"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); } @Test @@ -73,25 +74,71 @@ public class TestCacheableRequestPolicy BasicHttpRequest request = new BasicHttpRequest("GET", "someUri"); request.addHeader("Pragma", "no-cache"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); request = new BasicHttpRequest("GET", "someUri"); request.addHeader("Pragma", "value1"); request.addHeader("Pragma", "value2"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); } @Test - public void testIsArbitraryMethodServableFromCache() { + public void testIsHeadServableFromCache() { + BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri"); + + Assert.assertTrue(policy.isServableFromCache(request, allowHeadResponseCaching)); + + request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Cache-Control", "public"); + request.addHeader("Cache-Control", "max-age=20"); + + Assert.assertTrue(policy.isServableFromCache(request, allowHeadResponseCaching)); + } + @Test + public void testIsHeadWithCacheControlServableFromCache() { BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Cache-Control", "no-cache"); + + Assert.assertFalse(policy.isServableFromCache(request, allowHeadResponseCaching)); + + request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Cache-Control", "no-store"); + request.addHeader("Cache-Control", "max-age=20"); + + Assert.assertFalse(policy.isServableFromCache(request, allowHeadResponseCaching)); + + request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Cache-Control", "public"); + request.addHeader("Cache-Control", "no-store, max-age=20"); + + Assert.assertFalse(policy.isServableFromCache(request, allowHeadResponseCaching)); + } + + @Test + public void testIsHeadWithPragmaServableFromCache() { + BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Pragma", "no-cache"); + + Assert.assertFalse(policy.isServableFromCache(request, allowHeadResponseCaching)); + + request = new BasicHttpRequest("HEAD", "someUri"); + request.addHeader("Pragma", "value1"); + request.addHeader("Pragma", "value2"); + + Assert.assertFalse(policy.isServableFromCache(request, allowHeadResponseCaching)); + } + + @Test + public void testIsArbitraryMethodServableFromCache() { + BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); request = new BasicHttpRequest("get", "someUri"); - Assert.assertFalse(policy.isServableFromCache(request)); + Assert.assertFalse(policy.isServableFromCache(request, !allowHeadResponseCaching)); } Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java?rev=1637389&r1=1637388&r2=1637389&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java (original) +++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java Fri Nov 7 15:23:03 2014 @@ -27,10 +27,12 @@ package org.apache.http.impl.client.cache; import java.util.Date; +import java.util.HashMap; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.methods.HttpRequestWrapper; import org.apache.http.client.utils.DateUtils; import org.apache.http.message.BasicHeader; import org.easymock.classextension.EasyMock; @@ -42,6 +44,7 @@ import org.junit.Test; public class TestCachedHttpResponseGenerator { private HttpCacheEntry entry; + private HttpRequestWrapper request; private CacheValidityPolicy mockValidityPolicy; private CachedHttpResponseGenerator impl; private Date now; @@ -49,15 +52,14 @@ public class TestCachedHttpResponseGener @Before public void setUp() { now = new Date(); - final Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L); final Date eightSecondsAgo = new Date(now.getTime() - 8 * 1000L); - final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); final Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L); final Header[] hdrs = { new BasicHeader("Date", DateUtils.formatDate(eightSecondsAgo)), new BasicHeader("Expires", DateUtils.formatDate(tenSecondsFromNow)), new BasicHeader("Content-Length", "150") }; - entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, sixSecondsAgo, hdrs); + entry = HttpTestUtils.makeCacheEntry(new HashMap()); + request = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest()); mockValidityPolicy = EasyMock.createNiceMock(CacheValidityPolicy.class); impl = new CachedHttpResponseGenerator(mockValidityPolicy); } @@ -71,7 +73,7 @@ public class TestCachedHttpResponseGener final byte[] buf = new byte[] { 1, 2, 3, 4, 5 }; final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(buf); - final HttpResponse response = impl.generateResponse(entry1); + final HttpResponse response = impl.generateResponse(request, entry1); final Header length = response.getFirstHeader("Content-Length"); Assert.assertNotNull("Content-Length Header is missing", length); @@ -87,7 +89,7 @@ public class TestCachedHttpResponseGener final byte[] buf = new byte[] { 1, 2, 3, 4, 5 }; final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(hdrs, buf); - final HttpResponse response = impl.generateResponse(entry1); + final HttpResponse response = impl.generateResponse(request, entry1); final Header length = response.getFirstHeader("Content-Length"); @@ -96,7 +98,7 @@ public class TestCachedHttpResponseGener @Test public void testResponseMatchesCacheEntry() { - final HttpResponse response = impl.generateResponse(entry); + final HttpResponse response = impl.generateResponse(request, entry); Assert.assertTrue(response.containsHeader("Content-Length")); @@ -107,7 +109,7 @@ public class TestCachedHttpResponseGener @Test public void testResponseStatusCodeMatchesCacheEntry() { - final HttpResponse response = impl.generateResponse(entry); + final HttpResponse response = impl.generateResponse(request, entry); Assert.assertEquals(entry.getStatusCode(), response.getStatusLine().getStatusCode()); } @@ -117,7 +119,7 @@ public class TestCachedHttpResponseGener currentAge(10L); replayMocks(); - final HttpResponse response = impl.generateResponse(entry); + final HttpResponse response = impl.generateResponse(request, entry); final Header ageHdr = response.getFirstHeader("Age"); Assert.assertNotNull(ageHdr); @@ -129,7 +131,7 @@ public class TestCachedHttpResponseGener currentAge(0L); replayMocks(); - final HttpResponse response = impl.generateResponse(entry); + final HttpResponse response = impl.generateResponse(request, entry); final Header ageHdr = response.getFirstHeader("Age"); Assert.assertNull(ageHdr); @@ -140,7 +142,7 @@ public class TestCachedHttpResponseGener currentAge(CacheValidityPolicy.MAX_AGE + 1L); replayMocks(); - final HttpResponse response = impl.generateResponse(entry); + final HttpResponse response = impl.generateResponse(request, entry); final Header ageHdr = response.getFirstHeader("Age"); Assert.assertNotNull(ageHdr); @@ -153,4 +155,19 @@ public class TestCachedHttpResponseGener EasyMock.isA(Date.class))).andReturn(sec); } + @Test + public void testResponseContainsEntityToServeGETRequestIfEntryContainsResource() throws Exception { + final HttpResponse response = impl.generateResponse(request, entry); + + Assert.assertNotNull(response.getEntity()); + } + + @Test + public void testResponseDoesNotContainEntityToServeHEADRequestIfEntryContainsResource() throws Exception { + final HttpRequestWrapper headRequest = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultHEADRequest()); + final HttpResponse response = impl.generateResponse(headRequest, entry); + + Assert.assertNull(response.getEntity()); + } + }