Merge remote-tracking branch 'J-Cutajar/cache-head-responses' into trunk
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1637389 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
114a5bf4ab
commit
2883531e92
|
@ -162,6 +162,7 @@ public class CachingHttpClient implements HttpClient {
|
|||
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 implements HttpClient {
|
|||
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 implements HttpClient {
|
|||
this.requestCompliance = new RequestProtocolCompliance(config.isWeakETagOnPutDeleteAllowed());
|
||||
|
||||
this.asynchRevalidator = makeAsynchronousValidator(config);
|
||||
this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,6 +304,7 @@ public class CachingHttpClient implements HttpClient {
|
|||
this.responseCompliance = responseCompliance;
|
||||
this.requestCompliance = requestCompliance;
|
||||
this.asynchRevalidator = makeAsynchronousValidator(config);
|
||||
this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled();
|
||||
}
|
||||
|
||||
private AsynchronousValidator makeAsynchronousValidator(
|
||||
|
@ -445,7 +449,7 @@ public class CachingHttpClient implements HttpClient {
|
|||
|
||||
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 implements HttpClient {
|
|||
|| 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 implements HttpClient {
|
|||
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 implements HttpClient {
|
|||
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 implements HttpClient {
|
|||
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 implements HttpClient {
|
|||
&& 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) {
|
||||
|
|
|
@ -62,6 +62,7 @@ public class HttpCacheEntry implements Serializable {
|
|||
private final Resource resource;
|
||||
private final Map<String,String> variantMap;
|
||||
private final Date date;
|
||||
private final String requestMethod;
|
||||
|
||||
/**
|
||||
* Create a new {@link HttpCacheEntry} with variants.
|
||||
|
@ -80,6 +81,7 @@ public class HttpCacheEntry implements Serializable {
|
|||
* 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 Serializable {
|
|||
final StatusLine statusLine,
|
||||
final Header[] responseHeaders,
|
||||
final Resource resource,
|
||||
final Map<String,String> variantMap) {
|
||||
final Map<String,String> variantMap,
|
||||
final String requestMethod) {
|
||||
super();
|
||||
Args.notNull(requestDate, "Request date");
|
||||
Args.notNull(responseDate, "Response date");
|
||||
|
@ -103,6 +106,7 @@ public class HttpCacheEntry implements Serializable {
|
|||
? new HashMap<String,String>(variantMap)
|
||||
: null;
|
||||
this.date = parseDate();
|
||||
this.requestMethod = requestMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,11 +123,12 @@ public class HttpCacheEntry implements Serializable {
|
|||
* @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<String,String>());
|
||||
new HashMap<String,String>(), requestMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,6 +255,16 @@ public class HttpCacheEntry implements Serializable {
|
|||
return Collections.unmodifiableMap(variantMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.apache.http.client.cache.HttpCacheUpdateException;
|
|||
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 HttpCache {
|
|||
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 HttpCache {
|
|||
this.responseGenerator = new CachedHttpResponseGenerator();
|
||||
this.storage = storage;
|
||||
this.cacheInvalidator = cacheInvalidator;
|
||||
this.allowHeadResponseCaching = config.isHeadResponseCachingEnabled();
|
||||
}
|
||||
|
||||
public BasicHttpCache(
|
||||
|
@ -92,7 +95,7 @@ class BasicHttpCache implements HttpCache {
|
|||
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 HttpCache {
|
|||
} catch (final NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
if (resource == null) {
|
||||
return false;
|
||||
}
|
||||
return (resource.length() < contentLength);
|
||||
}
|
||||
|
||||
|
@ -219,7 +225,7 @@ class BasicHttpCache implements HttpCache {
|
|||
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 HttpCache {
|
|||
src.getStatusLine(),
|
||||
src.getAllHeaders(),
|
||||
resource,
|
||||
variantMap);
|
||||
variantMap,
|
||||
allowHeadResponseCaching ? src.getRequestMethod() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -261,7 +268,8 @@ class BasicHttpCache implements HttpCache {
|
|||
stale,
|
||||
requestSent,
|
||||
responseReceived,
|
||||
originResponse);
|
||||
originResponse,
|
||||
allowHeadResponseCaching);
|
||||
storeInCache(target, request, updatedEntry);
|
||||
return updatedEntry;
|
||||
}
|
||||
|
@ -275,7 +283,8 @@ class BasicHttpCache implements HttpCache {
|
|||
stale,
|
||||
requestSent,
|
||||
responseReceived,
|
||||
originResponse);
|
||||
originResponse,
|
||||
allowHeadResponseCaching);
|
||||
storage.putEntry(cacheKey, updatedEntry);
|
||||
return updatedEntry;
|
||||
}
|
||||
|
@ -317,9 +326,10 @@ class BasicHttpCache implements HttpCache {
|
|||
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();
|
||||
|
|
|
@ -175,6 +175,7 @@ public class CacheConfig implements Cloneable {
|
|||
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 Cloneable {
|
|||
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 Cloneable {
|
|||
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 Cloneable {
|
|||
this.asynchronousWorkersCore = asynchronousWorkersCore;
|
||||
this.asynchronousWorkerIdleLifetimeSecs = asynchronousWorkerIdleLifetimeSecs;
|
||||
this.revalidationQueueSize = revalidationQueueSize;
|
||||
this.allowHeadResponseCaching = allowHeadResponseCaching;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -500,6 +504,14 @@ public class CacheConfig implements Cloneable {
|
|||
return revalidationQueueSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -533,6 +545,7 @@ public class CacheConfig implements Cloneable {
|
|||
.setAsynchronousWorkersCore(config.getAsynchronousWorkersCore())
|
||||
.setAsynchronousWorkerIdleLifetimeSecs(config.getAsynchronousWorkerIdleLifetimeSecs())
|
||||
.setRevalidationQueueSize(config.getRevalidationQueueSize())
|
||||
.setAllowHeadResponseCaching(config.isHeadResponseCachingEnabled())
|
||||
.setNeverCacheHTTP10ResponsesWithQueryString(config.isNeverCacheHTTP10ResponsesWithQuery());
|
||||
}
|
||||
|
||||
|
@ -553,6 +566,7 @@ public class CacheConfig implements Cloneable {
|
|||
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 Cloneable {
|
|||
this.asynchronousWorkersCore = DEFAULT_ASYNCHRONOUS_WORKERS_CORE;
|
||||
this.asynchronousWorkerIdleLifetimeSecs = DEFAULT_ASYNCHRONOUS_WORKER_IDLE_LIFETIME_SECS;
|
||||
this.revalidationQueueSize = DEFAULT_REVALIDATION_QUEUE_SIZE;
|
||||
this.allowHeadResponseCaching = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -707,6 +722,17 @@ public class CacheConfig implements Cloneable {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -735,7 +761,8 @@ public class CacheConfig implements Cloneable {
|
|||
asynchronousWorkersCore,
|
||||
asynchronousWorkerIdleLifetimeSecs,
|
||||
revalidationQueueSize,
|
||||
neverCacheHTTP10ResponsesWithQuery);
|
||||
neverCacheHTTP10ResponsesWithQuery,
|
||||
allowHeadResponseCaching);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -757,6 +784,7 @@ public class CacheConfig implements Cloneable {
|
|||
.append(", asynchronousWorkerIdleLifetimeSecs=").append(this.asynchronousWorkerIdleLifetimeSecs)
|
||||
.append(", revalidationQueueSize=").append(this.revalidationQueueSize)
|
||||
.append(", neverCacheHTTP10ResponsesWithQuery=").append(this.neverCacheHTTP10ResponsesWithQuery)
|
||||
.append(", headResponseCachingEnabled=").append(this.allowHeadResponseCaching)
|
||||
.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -56,6 +56,7 @@ class CacheInvalidator implements HttpCacheInvalidator {
|
|||
|
||||
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 HttpCacheInvalidator {
|
|||
*
|
||||
* @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 HttpCacheInvalidator {
|
|||
*/
|
||||
@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 HttpCacheInvalidator {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.http.annotation.Immutable;
|
|||
import org.apache.http.client.cache.HeaderConstants;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -153,7 +153,8 @@ public class CachingExec implements ClientExecChain {
|
|||
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 ClientExecChain {
|
|||
|
||||
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 ClientExecChain {
|
|||
}
|
||||
}
|
||||
|
||||
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 ClientExecChain {
|
|||
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 ClientExecChain {
|
|||
}
|
||||
|
||||
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 ClientExecChain {
|
|||
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 ClientExecChain {
|
|||
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 ClientExecChain {
|
|||
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 {
|
||||
|
|
|
@ -140,7 +140,7 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
|
|||
|
||||
HttpCacheInvalidator cacheInvalidator = this.httpCacheInvalidator;
|
||||
if (cacheInvalidator == null) {
|
||||
cacheInvalidator = new CacheInvalidator(uriExtractor, storageCopy);
|
||||
cacheInvalidator = new CacheInvalidator(uriExtractor, storageCopy, config.isHeadResponseCachingEnabled());
|
||||
}
|
||||
|
||||
return new CachingExec(mainExec,
|
||||
|
|
|
@ -67,6 +67,8 @@ class ResponseCachingPolicy {
|
|||
HttpStatus.SC_MOVED_PERMANENTLY,
|
||||
HttpStatus.SC_GONE));
|
||||
private final Set<Integer> 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<Integer>(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;
|
||||
}
|
||||
|
|
|
@ -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<headers.length; i++) {
|
||||
|
@ -258,7 +258,7 @@ public class TestHttpCacheEntry {
|
|||
@Test
|
||||
public void canConstructWithoutVariants() {
|
||||
new HttpCacheEntry(new Date(), new Date(), statusLine,
|
||||
new Header[]{}, mockResource);
|
||||
new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -266,7 +266,7 @@ public class TestHttpCacheEntry {
|
|||
public void canProvideVariantMap() {
|
||||
new HttpCacheEntry(new Date(), new Date(), statusLine,
|
||||
new Header[]{}, mockResource,
|
||||
new HashMap<String,String>());
|
||||
new HashMap<String,String>(), 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<String,String> 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<String,String> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.apache.http.impl.client.cache;
|
|||
|
||||
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<String,String> 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<String, String> makeDefaultVariantMap(final String key, final String value) {
|
||||
final Map<String, String> variants = new HashMap<String, String>();
|
||||
variants.put(key, value);
|
||||
|
||||
return variants;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -262,6 +262,15 @@ public class TestBasicHttpCache {
|
|||
assertFalse(impl.isIncompleteResponse(resp, resource));
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
@ -221,6 +221,81 @@ public class TestCacheInvalidator {
|
|||
verifyMocks();
|
||||
}
|
||||
|
||||
@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<String, String>());
|
||||
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<String, String> 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);
|
||||
|
@ -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<String,String> mapOfURIs = new HashMap<String,String>();
|
||||
mapOfURIs.put(variantUri,variantUri);
|
||||
final Map<String,String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -354,6 +354,14 @@ public class TestCacheValidityPolicy {
|
|||
assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
|
||||
}
|
||||
|
||||
@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") };
|
||||
|
|
|
@ -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 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");
|
||||
|
||||
BasicHttpRequest request = new BasicHttpRequest("HEAD", "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));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 TestCachedHttpResponseGenerator {
|
|||
@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<String, String>());
|
||||
request = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest());
|
||||
mockValidityPolicy = EasyMock.createNiceMock(CacheValidityPolicy.class);
|
||||
impl = new CachedHttpResponseGenerator(mockValidityPolicy);
|
||||
}
|
||||
|
@ -71,7 +73,7 @@ public class TestCachedHttpResponseGenerator {
|
|||
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 TestCachedHttpResponseGenerator {
|
|||
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 TestCachedHttpResponseGenerator {
|
|||
|
||||
@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 TestCachedHttpResponseGenerator {
|
|||
|
||||
@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 TestCachedHttpResponseGenerator {
|
|||
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 TestCachedHttpResponseGenerator {
|
|||
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 TestCachedHttpResponseGenerator {
|
|||
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 TestCachedHttpResponseGenerator {
|
|||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -261,4 +261,81 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
|
||||
Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableIfRequestMethodisHEAD() {
|
||||
final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo", HttpVersion.HTTP_1_1);
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
|
||||
Assert.assertTrue(impl.canCachedResponseBeUsed(host, headRequest, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfRequestMethodIsGETAndEntryResourceIsNull() {
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeHeadCacheEntry(headers);
|
||||
|
||||
Assert.assertFalse(impl.canCachedResponseBeUsed(host, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableForGETIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethodOrEntity() {
|
||||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().setAllowHeadResponseCaching(true).build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeCacheEntryWithNoRequestMethodOrEntity(headers);
|
||||
|
||||
Assert.assertFalse(impl.canCachedResponseBeUsed(host, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableForGETIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethodButContainsEntity() {
|
||||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().setAllowHeadResponseCaching(true).build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeCacheEntryWithNoRequestMethod(headers);
|
||||
|
||||
Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableForGETIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethodButContains204Response() {
|
||||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().setAllowHeadResponseCaching(true).build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600")
|
||||
};
|
||||
entry = HttpTestUtils.make204CacheEntryWithNoRequestMethod(headers);
|
||||
|
||||
Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableForHEADIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethod() {
|
||||
final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo", HttpVersion.HTTP_1_1);
|
||||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().setAllowHeadResponseCaching(true).build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeHeadCacheEntryWithNoRequestMethod(headers);
|
||||
|
||||
Assert.assertTrue(impl.canCachedResponseBeUsed(host, headRequest, entry, now));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
package org.apache.http.impl.client.cache;
|
||||
|
||||
import static org.easymock.EasyMock.anyObject;
|
||||
import static org.easymock.EasyMock.anyBoolean;
|
||||
import static org.easymock.EasyMock.eq;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
|
@ -1764,7 +1765,7 @@ public abstract class TestCachingExecChain {
|
|||
}
|
||||
|
||||
protected void requestPolicyAllowsCaching(final boolean allow) {
|
||||
expect(mockRequestPolicy.isServableFromCache((HttpRequest) anyObject())).andReturn(allow);
|
||||
expect(mockRequestPolicy.isServableFromCache((HttpRequest) anyObject(), anyBoolean())).andReturn(allow);
|
||||
}
|
||||
|
||||
protected void cacheEntrySuitable(final boolean suitable) {
|
||||
|
@ -1781,8 +1782,9 @@ public abstract class TestCachingExecChain {
|
|||
}
|
||||
|
||||
protected void responseIsGeneratedFromCache() {
|
||||
expect(mockResponseGenerator.generateResponse((HttpCacheEntry) anyObject())).andReturn(
|
||||
mockCachedResponse);
|
||||
expect(
|
||||
mockResponseGenerator.generateResponse((HttpRequestWrapper) anyObject(), (HttpCacheEntry) anyObject()))
|
||||
.andReturn(mockCachedResponse);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.apache.commons.codec.binary.Base64;
|
|||
import org.apache.http.Header;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.cache.HeaderConstants;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.cache.HttpCacheEntrySerializer;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
@ -93,7 +94,7 @@ public class TestHttpCacheEntrySerializers {
|
|||
variantMap.put("test variant 2","true");
|
||||
final HttpCacheEntry cacheEntry = new HttpCacheEntry(new Date(), new Date(),
|
||||
slObj, headers, new HeapResource(Base64.decodeBase64(body
|
||||
.getBytes(UTF8))), variantMap);
|
||||
.getBytes(UTF8))), variantMap, HeaderConstants.GET_METHOD);
|
||||
|
||||
return cacheEntry;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class TestResponseCachingPolicy {
|
|||
sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
|
||||
tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
|
||||
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
request = new BasicHttpRequest("GET","/",HTTP_1_1);
|
||||
response = new BasicHttpResponse(
|
||||
new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, ""));
|
||||
|
@ -75,6 +75,19 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadCacheableIfHeadResponseCachingIsEnabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadIsNotCacheableIfHeadResponseCachingIsDisabled() {
|
||||
request = new BasicHttpRequest("HEAD","/",HTTP_1_1);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToRequestsWithAuthorizationHeadersAreNotCacheableBySharedCache() {
|
||||
request = new BasicHttpRequest("GET","/",HTTP_1_1);
|
||||
|
@ -84,7 +97,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponsesToRequestsWithAuthorizationHeadersAreCacheableByNonSharedCache() {
|
||||
policy = new ResponseCachingPolicy(0, false, false, false);
|
||||
policy = new ResponseCachingPolicy(0, false, false, false, false);
|
||||
request = new BasicHttpRequest("GET","/",HTTP_1_1);
|
||||
request.setHeader("Authorization","Basic dXNlcjpwYXNzd2Q=");
|
||||
Assert.assertTrue(policy.isResponseCacheable(request,response));
|
||||
|
@ -136,7 +149,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void test206ResponseCodeIsNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setStatusCode(HttpStatus.SC_PARTIAL_CONTENT);
|
||||
|
@ -180,7 +193,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testPlain303ResponseCodeIsNotCacheableEvenIf303CachingEnabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, true);
|
||||
policy = new ResponseCachingPolicy(0, true, false, true, false);
|
||||
response.setStatusCode(HttpStatus.SC_SEE_OTHER);
|
||||
response.removeHeaders("Expires");
|
||||
response.removeHeaders("Cache-Control");
|
||||
|
@ -254,7 +267,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void test200ResponseWithPrivateCacheControlIsCacheableByNonSharedCache() {
|
||||
policy = new ResponseCachingPolicy(0, false, false, false);
|
||||
policy = new ResponseCachingPolicy(0, false, false, false, false);
|
||||
response.setStatusCode(HttpStatus.SC_OK);
|
||||
response.setHeader("Cache-Control", "private");
|
||||
Assert.assertTrue(policy.isResponseCacheable("GET", response));
|
||||
|
@ -267,6 +280,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoCacheCacheable() {
|
||||
response.addHeader("Cache-Control", "no-cache");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithNoStoreCacheable() {
|
||||
response.addHeader("Cache-Control", "no-store");
|
||||
|
@ -274,6 +294,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoStoreCacheable() {
|
||||
response.addHeader("Cache-Control", "no-store");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithNoStoreEmbeddedInListCacheable() {
|
||||
response.addHeader("Cache-Control", "public, no-store");
|
||||
|
@ -281,6 +308,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoStoreEmbeddedInListCacheable() {
|
||||
response.addHeader("Cache-Control", "public, no-store");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithNoCacheEmbeddedInListCacheable() {
|
||||
response.addHeader("Cache-Control", "public, no-cache");
|
||||
|
@ -288,6 +322,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoCacheEmbeddedInListCacheable() {
|
||||
response.addHeader("Cache-Control", "public, no-cache");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
|
||||
response.addHeader("Cache-Control", "max-age=20");
|
||||
|
@ -296,6 +337,14 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
|
||||
response.addHeader("Cache-Control", "max-age=20");
|
||||
response.addHeader("Cache-Control", "public, no-cache");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
|
||||
response.addHeader("Cache-Control", "max-age=20");
|
||||
|
@ -304,6 +353,14 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
|
||||
response.addHeader("Cache-Control", "max-age=20");
|
||||
response.addHeader("Cache-Control", "public, no-store");
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithAnyCacheControlCacheable() {
|
||||
response.addHeader("Cache-Control", "max=10");
|
||||
|
@ -319,6 +376,22 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithAnyCacheControlCacheable() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
response.addHeader("Cache-Control", "max=10");
|
||||
|
||||
Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
|
||||
|
||||
response = new BasicHttpResponse(
|
||||
new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, ""));
|
||||
response.setHeader("Date", DateUtils.formatDate(new Date()));
|
||||
response.addHeader("Cache-Control", "no-transform");
|
||||
response.setHeader("Content-Length", "0");
|
||||
|
||||
Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithout200Cacheable() {
|
||||
HttpResponse response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
|
||||
|
@ -332,6 +405,19 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable("GET", response404));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithout200Cacheable() {
|
||||
HttpResponse response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
|
||||
HttpStatus.SC_NOT_FOUND, ""));
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response404));
|
||||
|
||||
response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
|
||||
HttpStatus.SC_GATEWAY_TIMEOUT, ""));
|
||||
|
||||
Assert.assertFalse(policy.isResponseCacheable("HEAD", response404));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVaryStarIsNotCacheable() {
|
||||
response.setHeader("Vary", "*");
|
||||
|
@ -340,7 +426,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testVaryStarIsNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -354,6 +440,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable("GET", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithVaryHeaderCacheable() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
response.addHeader("Vary", "Accept-Encoding");
|
||||
Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsArbitraryMethodCacheable() {
|
||||
|
||||
|
@ -364,7 +457,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testIsArbitraryMethodCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request = new HttpOptions("http://foo.example.com/");
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
|
@ -390,7 +483,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponsesWithMultipleAgeHeadersAreNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -408,7 +501,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponsesWithMultipleDateHeadersAreNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -425,7 +518,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponsesWithMalformedDateHeadersAreNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -442,7 +535,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponsesWithMultipleExpiresHeadersAreNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -465,7 +558,7 @@ public class TestResponseCachingPolicy {
|
|||
|
||||
@Test
|
||||
public void testResponseThatHasTooMuchContentIsNotCacheableUsingSharedPublicCache() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false);
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, false);
|
||||
|
||||
request.setHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
|
||||
response.setHeader("Cache-Control", "public");
|
||||
|
@ -485,13 +578,26 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false);
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -500,15 +606,33 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheable() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false);
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -516,14 +640,29 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false);
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -533,9 +672,19 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false);
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
@ -543,6 +692,16 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -550,6 +709,13 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Via", "1.0 someproxy");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -559,9 +725,19 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
response.setHeader("Via", "1.0 someproxy");
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, true);
|
||||
policy = new ResponseCachingPolicy(0, true, true, true, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
|
@ -569,6 +745,16 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, true, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
response.setHeader("Via", "1.0 someproxy");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -578,9 +764,19 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
response.setHeader("Via", "HTTP/1.0 someproxy");
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, true);
|
||||
policy = new ResponseCachingPolicy(0, true, true, true, false);
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
|
@ -588,6 +784,16 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, true, true, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
response.setHeader("Via", "HTTP/1.0 someproxy");
|
||||
Assert.assertFalse(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
|
||||
request = new BasicHttpRequest("GET", "/foo?s=bar");
|
||||
|
@ -598,6 +804,17 @@ public class TestResponseCachingPolicy {
|
|||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
|
||||
policy = new ResponseCachingPolicy(0, true, false, false, true);
|
||||
request = new BasicHttpRequest("HEAD", "/foo?s=bar");
|
||||
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
|
||||
response.setHeader("Via", "1.1 someproxy");
|
||||
Assert.assertTrue(policy.isResponseCacheable(request, response));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
@ -635,7 +852,7 @@ public class TestResponseCachingPolicy {
|
|||
public void test303WithExplicitCachingHeadersWhenPermittedByConfig() {
|
||||
// HTTPbis working group says ok if explicitly indicated by
|
||||
// response headers
|
||||
policy = new ResponseCachingPolicy(0, true, false, true);
|
||||
policy = new ResponseCachingPolicy(0, true, false, true, false);
|
||||
response.setStatusCode(HttpStatus.SC_SEE_OTHER);
|
||||
response.setHeader("Date", DateUtils.formatDate(now));
|
||||
response.setHeader("Cache-Control","max-age=300");
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
*/
|
||||
package org.apache.http.impl.client.cache;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Date;
|
||||
|
@ -151,4 +151,5 @@ public class TestResponseProtocolCompliance {
|
|||
}
|
||||
assertTrue(closed.set || bais.read() == -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue