Parse Cache-Control request and response headers only once
This commit is contained in:
parent
cd2930af1f
commit
fbed77880b
|
@ -239,7 +239,9 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
requestCompliance.makeRequestCompliant(request);
|
||||
request.addHeader(HttpHeaders.VIA,via);
|
||||
|
||||
if (!cacheableRequestPolicy.isServableFromCache(request)) {
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
|
||||
if (!cacheableRequestPolicy.isServableFromCache(requestCacheControl, request)) {
|
||||
LOG.debug("Request is not servable from cache");
|
||||
operation.setDependency(responseCache.flushCacheEntriesInvalidatedByRequest(target, request, new FutureCallback<Boolean>() {
|
||||
|
||||
|
@ -266,9 +268,10 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
public void completed(final HttpCacheEntry entry) {
|
||||
if (entry == null) {
|
||||
LOG.debug("Cache miss");
|
||||
handleCacheMiss(target, request, entityProducer, scope, chain, asyncExecCallback);
|
||||
handleCacheMiss(requestCacheControl, target, request, entityProducer, scope, chain, asyncExecCallback);
|
||||
} else {
|
||||
handleCacheHit(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
handleCacheHit(requestCacheControl, responseCacheControl, target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,7 +491,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
|
||||
});
|
||||
final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
|
||||
final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(backendResponse);
|
||||
final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
|
||||
if (cacheable) {
|
||||
cachingConsumerRef.set(new CachingAsyncDataConsumer(asyncExecCallback, backendResponse, entityDetails));
|
||||
storeRequestIfModifiedSinceFor304Response(request, backendResponse);
|
||||
|
@ -612,6 +616,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
|
||||
private void handleCacheHit(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final AsyncEntityProducer entityProducer,
|
||||
|
@ -623,28 +629,30 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
recordCacheHit(target, request);
|
||||
final Instant now = getCurrentDate();
|
||||
|
||||
if (requestContainsNoCacheDirective(request)) {
|
||||
if (requestCacheControl.isNoCache()) {
|
||||
// Revalidate with the server due to no-cache directive in response
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Revalidating with server due to no-cache directive in response.");
|
||||
}
|
||||
revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
revalidateCacheEntry(requestCacheControl, responseCacheControl,
|
||||
target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
if (suitabilityChecker.canCachedResponseBeUsed(request, entry, now)) {
|
||||
if (responseCachingPolicy.responseContainsNoCacheDirective(entry)) {
|
||||
if (suitabilityChecker.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now)) {
|
||||
if (responseCachingPolicy.responseContainsNoCacheDirective(responseCacheControl, entry)) {
|
||||
// Revalidate with the server due to no-cache directive in response
|
||||
revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
revalidateCacheEntry(requestCacheControl, responseCacheControl,
|
||||
target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
return;
|
||||
}
|
||||
LOG.debug("Cache hit");
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl, request, context, entry, now);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex) {
|
||||
recordCacheFailure(target, request);
|
||||
if (!mayCallBackend(request)) {
|
||||
if (!mayCallBackend(requestCacheControl)) {
|
||||
final SimpleHttpResponse cacheResponse = generateGatewayTimeout(context);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} else {
|
||||
|
@ -656,20 +664,20 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (!mayCallBackend(request)) {
|
||||
} else if (!mayCallBackend(requestCacheControl)) {
|
||||
LOG.debug("Cache entry not suitable but only-if-cached requested");
|
||||
final SimpleHttpResponse cacheResponse = generateGatewayTimeout(context);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} else if (!(entry.getStatus() == HttpStatus.SC_NOT_MODIFIED && !suitabilityChecker.isConditional(request))) {
|
||||
LOG.debug("Revalidating cache entry");
|
||||
final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(entry);
|
||||
final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(responseCacheControl, entry);
|
||||
if (cacheRevalidator != null
|
||||
&& !staleResponseNotAllowed(request, entry, now)
|
||||
&& validityPolicy.mayReturnStaleWhileRevalidating(entry, now)
|
||||
&& !staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)
|
||||
&& validityPolicy.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now)
|
||||
|| staleIfErrorEnabled) {
|
||||
LOG.debug("Serving stale with asynchronous revalidation");
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl, request, context, entry, now);
|
||||
final String exchangeId = ExecSupport.getNextExchangeId();
|
||||
context.setExchangeId(exchangeId);
|
||||
final AsyncExecChain.Scope fork = new AsyncExecChain.Scope(
|
||||
|
@ -684,7 +692,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
cacheRevalidator.revalidateCacheEntry(
|
||||
responseCache.generateKey(target, request, entry),
|
||||
asyncExecCallback,
|
||||
asyncExecCallback1 -> revalidateCacheEntry(target, request, entityProducer, fork, chain, asyncExecCallback1, entry));
|
||||
asyncExecCallback1 -> revalidateCacheEntry(requestCacheControl, responseCacheControl,
|
||||
target, request, entityProducer, fork, chain, asyncExecCallback1, entry));
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex) {
|
||||
if (staleIfErrorEnabled) {
|
||||
|
@ -692,7 +701,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
LOG.debug("Serving stale response due to IOException and stale-if-error enabled");
|
||||
}
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
|
||||
final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl,
|
||||
request, context, entry, now);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex2) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
|
@ -705,7 +715,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
}
|
||||
} else {
|
||||
revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
revalidateCacheEntry(requestCacheControl, responseCacheControl,
|
||||
target, request, entityProducer, scope, chain, asyncExecCallback, entry);
|
||||
}
|
||||
} else {
|
||||
LOG.debug("Cache entry not usable; calling backend");
|
||||
|
@ -714,6 +725,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
|
||||
void revalidateCacheEntry(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final AsyncEntityProducer entityProducer,
|
||||
|
@ -723,6 +736,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
final HttpCacheEntry cacheEntry) {
|
||||
final Instant requestDate = getCurrentDate();
|
||||
final HttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
|
||||
responseCacheControl,
|
||||
BasicRequestBuilder.copy(scope.originalRequest).build(),
|
||||
cacheEntry);
|
||||
chainProceed(conditionalRequest, entityProducer, scope, chain, new AsyncExecCallback() {
|
||||
|
@ -791,8 +805,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
return new AsyncExecCallbackWrapper(asyncExecCallback, () -> triggerUpdatedCacheEntryResponse(backendResponse, responseDate));
|
||||
}
|
||||
if (staleIfErrorAppliesTo(statusCode)
|
||||
&& !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
|
||||
&& validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
|
||||
&& !staleResponseNotAllowed(requestCacheControl, responseCacheControl, cacheEntry, getCurrentDate())
|
||||
&& validityPolicy.mayReturnStaleIfError(requestCacheControl, responseCacheControl, cacheEntry, responseDate)) {
|
||||
return new AsyncExecCallbackWrapper(asyncExecCallback, this::triggerResponseStaleCacheEntry);
|
||||
}
|
||||
return new BackendResponseHandler(target, conditionalRequest, requestDate, responseDate, scope, asyncExecCallback);
|
||||
|
@ -897,6 +911,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
}
|
||||
|
||||
private void handleCacheMiss(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final AsyncEntityProducer entityProducer,
|
||||
|
@ -905,7 +920,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
|
|||
final AsyncExecCallback asyncExecCallback) {
|
||||
recordCacheMiss(target, request);
|
||||
|
||||
if (mayCallBackend(request)) {
|
||||
if (mayCallBackend(requestCacheControl)) {
|
||||
final CancellableDependency operation = scope.cancellableDependency;
|
||||
operation.setDependency(responseCache.getVariantCacheEntriesWithEtags(
|
||||
target,
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.apache.hc.client5.http.cache.Resource;
|
|||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.util.TimeValue;
|
||||
|
||||
class CacheValidityPolicy {
|
||||
|
@ -50,8 +49,8 @@ class CacheValidityPolicy {
|
|||
return TimeValue.ofSeconds(getCorrectedInitialAge(entry).toSeconds() + getResidentTime(entry, now).toSeconds());
|
||||
}
|
||||
|
||||
public TimeValue getFreshnessLifetime(final HttpCacheEntry entry) {
|
||||
final long maxAge = getMaxAge(entry);
|
||||
public TimeValue getFreshnessLifetime(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry) {
|
||||
final long maxAge = getMaxAge(responseCacheControl);
|
||||
if (maxAge > -1) {
|
||||
return TimeValue.ofSeconds(maxAge);
|
||||
}
|
||||
|
@ -69,8 +68,9 @@ class CacheValidityPolicy {
|
|||
return TimeValue.ofSeconds(diff.getSeconds());
|
||||
}
|
||||
|
||||
public boolean isResponseFresh(final HttpCacheEntry entry, final Instant now) {
|
||||
return getCurrentAge(entry, now).compareTo(getFreshnessLifetime(entry)) == -1;
|
||||
public boolean isResponseFresh(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
|
||||
final Instant now) {
|
||||
return getCurrentAge(entry, now).compareTo(getFreshnessLifetime(responseCacheControl, entry)) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,36 +114,28 @@ class CacheValidityPolicy {
|
|||
|| entry.getFirstHeader(HttpHeaders.LAST_MODIFIED) != null;
|
||||
}
|
||||
|
||||
public boolean mustRevalidate(final HttpCacheEntry entry) {
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
return cacheControl.isMustRevalidate();
|
||||
}
|
||||
|
||||
public boolean proxyRevalidate(final HttpCacheEntry entry) {
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
return cacheControl.isProxyRevalidate();
|
||||
}
|
||||
|
||||
public boolean mayReturnStaleWhileRevalidating(final HttpCacheEntry entry, final Instant now) {
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
if (cacheControl.getStaleWhileRevalidate() >= 0) {
|
||||
final TimeValue staleness = getStaleness(entry, now);
|
||||
if (staleness.compareTo(TimeValue.ofSeconds(cacheControl.getStaleWhileRevalidate())) <= 0) {
|
||||
public boolean mayReturnStaleWhileRevalidating(final ResponseCacheControl responseCacheControl,
|
||||
final HttpCacheEntry entry, final Instant now) {
|
||||
if (responseCacheControl.getStaleWhileRevalidate() >= 0) {
|
||||
final TimeValue staleness = getStaleness(responseCacheControl, entry, now);
|
||||
if (staleness.compareTo(TimeValue.ofSeconds(responseCacheControl.getStaleWhileRevalidate())) <= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mayReturnStaleIfError(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
final TimeValue staleness = getStaleness(entry, now);
|
||||
return mayReturnStaleIfError(requestCacheControl, staleness) || mayReturnStaleIfError(cacheControl, staleness);
|
||||
public boolean mayReturnStaleIfError(final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
|
||||
final Instant now) {
|
||||
final TimeValue staleness = getStaleness(responseCacheControl, entry, now);
|
||||
return mayReturnStaleIfError(requestCacheControl, staleness) ||
|
||||
mayReturnStaleIfError(responseCacheControl, staleness);
|
||||
}
|
||||
|
||||
private boolean mayReturnStaleIfError(final CacheControl cacheControl, final TimeValue staleness) {
|
||||
return cacheControl.getStaleIfError() >= 0 && staleness.compareTo(TimeValue.ofSeconds(cacheControl.getStaleIfError())) <= 0;
|
||||
private boolean mayReturnStaleIfError(final CacheControl responseCacheControl, final TimeValue staleness) {
|
||||
return responseCacheControl.getStaleIfError() >= 0 &&
|
||||
staleness.compareTo(TimeValue.ofSeconds(responseCacheControl.getStaleIfError())) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,10 +214,9 @@ class CacheValidityPolicy {
|
|||
}
|
||||
|
||||
|
||||
protected long getMaxAge(final HttpCacheEntry entry) {
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
final long maxAge = cacheControl.getMaxAge();
|
||||
final long sharedMaxAge = cacheControl.getSharedMaxAge();
|
||||
protected long getMaxAge(final ResponseCacheControl responseCacheControl) {
|
||||
final long maxAge = responseCacheControl.getMaxAge();
|
||||
final long sharedMaxAge = responseCacheControl.getSharedMaxAge();
|
||||
if (sharedMaxAge == -1) {
|
||||
return maxAge;
|
||||
} else if (maxAge == -1) {
|
||||
|
@ -235,9 +226,9 @@ class CacheValidityPolicy {
|
|||
}
|
||||
}
|
||||
|
||||
public TimeValue getStaleness(final HttpCacheEntry entry, final Instant now) {
|
||||
public TimeValue getStaleness(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry, final Instant now) {
|
||||
final TimeValue age = getCurrentAge(entry, now);
|
||||
final TimeValue freshness = getFreshnessLifetime(entry);
|
||||
final TimeValue freshness = getFreshnessLifetime(responseCacheControl, entry);
|
||||
if (age.compareTo(freshness) <= 0) {
|
||||
return TimeValue.ZERO_MILLISECONDS;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class CacheableRequestPolicy {
|
|||
* an HttpRequest
|
||||
* @return boolean Is it possible to serve this request from cache
|
||||
*/
|
||||
public boolean isServableFromCache(final HttpRequest request) {
|
||||
public boolean isServableFromCache(final RequestCacheControl cacheControl, final HttpRequest request) {
|
||||
final String method = request.getMethod();
|
||||
|
||||
final ProtocolVersion pv = request.getVersion() != null ? request.getVersion() : HttpVersion.DEFAULT;
|
||||
|
@ -69,7 +69,6 @@ class CacheableRequestPolicy {
|
|||
return false;
|
||||
}
|
||||
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
if (cacheControl.isNoStore()) {
|
||||
LOG.debug("Request with no-store is not serveable from cache");
|
||||
return false;
|
||||
|
|
|
@ -70,56 +70,50 @@ class CachedResponseSuitabilityChecker {
|
|||
this(new CacheValidityPolicy(), config);
|
||||
}
|
||||
|
||||
private boolean isFreshEnough(final HttpCacheEntry entry, final HttpRequest request, final Instant now) {
|
||||
if (validityStrategy.isResponseFresh(entry, now)) {
|
||||
private boolean isFreshEnough(final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
|
||||
final Instant now) {
|
||||
if (validityStrategy.isResponseFresh(responseCacheControl, entry, now)) {
|
||||
return true;
|
||||
}
|
||||
if (useHeuristicCaching &&
|
||||
validityStrategy.isResponseHeuristicallyFresh(entry, now, heuristicCoefficient, heuristicDefaultLifetime)) {
|
||||
return true;
|
||||
}
|
||||
if (originInsistsOnFreshness(entry)) {
|
||||
if (originInsistsOnFreshness(responseCacheControl)) {
|
||||
return false;
|
||||
}
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
if (cacheControl.getMaxStale() == -1) {
|
||||
if (requestCacheControl.getMaxStale() == -1) {
|
||||
return false;
|
||||
}
|
||||
return (cacheControl.getMaxStale() > validityStrategy.getStaleness(entry, now).toSeconds());
|
||||
return (requestCacheControl.getMaxStale() > validityStrategy.getStaleness(responseCacheControl, entry, now).toSeconds());
|
||||
}
|
||||
|
||||
private boolean originInsistsOnFreshness(final HttpCacheEntry entry) {
|
||||
if (validityStrategy.mustRevalidate(entry)) {
|
||||
private boolean originInsistsOnFreshness(final ResponseCacheControl responseCacheControl) {
|
||||
if (responseCacheControl.isMustRevalidate()) {
|
||||
return true;
|
||||
}
|
||||
if (!sharedCache) {
|
||||
return false;
|
||||
}
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
return cacheControl.isProxyRevalidate() || cacheControl.getSharedMaxAge() >= 0;
|
||||
return responseCacheControl.isProxyRevalidate() || responseCacheControl.getSharedMaxAge() >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if I can utilize a {@link HttpCacheEntry} to respond to the given
|
||||
* {@link HttpRequest}
|
||||
*
|
||||
* @param request
|
||||
* {@link HttpRequest}
|
||||
* @param entry
|
||||
* {@link HttpCacheEntry}
|
||||
* @param now
|
||||
* Right now in time
|
||||
* @return boolean yes/no answer
|
||||
* @since 5.3
|
||||
*/
|
||||
public boolean canCachedResponseBeUsed(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
|
||||
public boolean canCachedResponseBeUsed(final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl, final HttpRequest request,
|
||||
final HttpCacheEntry entry, final Instant now) {
|
||||
|
||||
if (isGetRequestWithHeadCacheEntry(request, entry)) {
|
||||
LOG.debug("Cache entry created by HEAD request cannot be used to serve GET request");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isFreshEnough(entry, request, now)) {
|
||||
if (!isFreshEnough(requestCacheControl, responseCacheControl, entry, now)) {
|
||||
LOG.debug("Cache entry is not fresh enough");
|
||||
return false;
|
||||
}
|
||||
|
@ -149,38 +143,37 @@ class CachedResponseSuitabilityChecker {
|
|||
"request method, entity or a 204 response");
|
||||
return false;
|
||||
}
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
if (cacheControl.isNoCache()) {
|
||||
if (requestCacheControl.isNoCache()) {
|
||||
LOG.debug("Response contained NO CACHE directive, cache was not suitable");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cacheControl.isNoStore()) {
|
||||
if (requestCacheControl.isNoStore()) {
|
||||
LOG.debug("Response contained NO STORE directive, cache was not suitable");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cacheControl.getMaxAge() >= 0) {
|
||||
if (validityStrategy.getCurrentAge(entry, now).toSeconds() > cacheControl.getMaxAge()) {
|
||||
if (requestCacheControl.getMaxAge() >= 0) {
|
||||
if (validityStrategy.getCurrentAge(entry, now).toSeconds() > requestCacheControl.getMaxAge()) {
|
||||
LOG.debug("Response from cache was not suitable due to max age");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheControl.getMaxStale() >= 0) {
|
||||
if (validityStrategy.getFreshnessLifetime(entry).toSeconds() > cacheControl.getMaxStale()) {
|
||||
if (requestCacheControl.getMaxStale() >= 0) {
|
||||
if (validityStrategy.getFreshnessLifetime(responseCacheControl, entry).toSeconds() > requestCacheControl.getMaxStale()) {
|
||||
LOG.debug("Response from cache was not suitable due to max stale freshness");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheControl.getMinFresh() >= 0) {
|
||||
if (cacheControl.getMinFresh() == 0) {
|
||||
if (requestCacheControl.getMinFresh() >= 0) {
|
||||
if (requestCacheControl.getMinFresh() == 0) {
|
||||
return false;
|
||||
}
|
||||
final TimeValue age = validityStrategy.getCurrentAge(entry, now);
|
||||
final TimeValue freshness = validityStrategy.getFreshnessLifetime(entry);
|
||||
if (freshness.toSeconds() - age.toSeconds() < cacheControl.getMinFresh()) {
|
||||
final TimeValue freshness = validityStrategy.getFreshnessLifetime(responseCacheControl, entry);
|
||||
if (freshness.toSeconds() - age.toSeconds() < requestCacheControl.getMinFresh()) {
|
||||
LOG.debug("Response from cache was not suitable due to min fresh " +
|
||||
"freshness requirement");
|
||||
return false;
|
||||
|
|
|
@ -217,7 +217,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
requestCompliance.makeRequestCompliant(request);
|
||||
request.addHeader(HttpHeaders.VIA, via);
|
||||
|
||||
if (!cacheableRequestPolicy.isServableFromCache(request)) {
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
if (!cacheableRequestPolicy.isServableFromCache(requestCacheControl, request)) {
|
||||
LOG.debug("Request is not servable from cache");
|
||||
responseCache.flushCacheEntriesInvalidatedByRequest(target, request);
|
||||
return callBackend(target, request, scope, chain);
|
||||
|
@ -226,9 +227,10 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
final HttpCacheEntry entry = responseCache.getCacheEntry(target, request);
|
||||
if (entry == null) {
|
||||
LOG.debug("Cache miss");
|
||||
return handleCacheMiss(target, request, scope, chain);
|
||||
return handleCacheMiss(target, request, requestCacheControl, scope, chain);
|
||||
} else {
|
||||
return handleCacheHit(target, request, scope, chain, entry);
|
||||
final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
|
||||
return handleCacheHit(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,6 +278,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
}
|
||||
|
||||
private ClassicHttpResponse handleCacheHit(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpHost target,
|
||||
final ClassicHttpRequest request,
|
||||
final ExecChain.Scope scope,
|
||||
|
@ -286,41 +290,40 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
recordCacheHit(target, request);
|
||||
final Instant now = getCurrentDate();
|
||||
|
||||
|
||||
if (requestContainsNoCacheDirective(request)) {
|
||||
if (requestCacheControl.isNoCache()) {
|
||||
// Revalidate with the server
|
||||
return revalidateCacheEntry(target, request, scope, chain, entry);
|
||||
return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
|
||||
}
|
||||
|
||||
if (suitabilityChecker.canCachedResponseBeUsed(request, entry, now)) {
|
||||
if (responseCachingPolicy.responseContainsNoCacheDirective(entry)) {
|
||||
if (suitabilityChecker.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now)) {
|
||||
if (responseCachingPolicy.responseContainsNoCacheDirective(responseCacheControl, entry)) {
|
||||
// Revalidate with the server due to no-cache directive in response
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Revalidating with server due to no-cache directive in response.");
|
||||
}
|
||||
return revalidateCacheEntry(target, request, scope, chain, entry);
|
||||
return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
|
||||
}
|
||||
LOG.debug("Cache hit");
|
||||
try {
|
||||
return convert(generateCachedResponse(request, context, entry, now), scope);
|
||||
return convert(generateCachedResponse(responseCacheControl, request, context, entry, now), scope);
|
||||
} catch (final ResourceIOException ex) {
|
||||
recordCacheFailure(target, request);
|
||||
if (!mayCallBackend(request)) {
|
||||
if (!mayCallBackend(requestCacheControl)) {
|
||||
return convert(generateGatewayTimeout(context), scope);
|
||||
}
|
||||
setResponseStatus(scope.clientContext, CacheResponseStatus.FAILURE);
|
||||
return chain.proceed(request, scope);
|
||||
}
|
||||
} else if (!mayCallBackend(request)) {
|
||||
} else if (!mayCallBackend(requestCacheControl)) {
|
||||
LOG.debug("Cache entry not suitable but only-if-cached requested");
|
||||
return convert(generateGatewayTimeout(context), scope);
|
||||
} else if (!(entry.getStatus() == HttpStatus.SC_NOT_MODIFIED && !suitabilityChecker.isConditional(request))) {
|
||||
LOG.debug("Revalidating cache entry");
|
||||
final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(entry);
|
||||
final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(responseCacheControl, entry);
|
||||
try {
|
||||
if (cacheRevalidator != null
|
||||
&& !staleResponseNotAllowed(request, entry, now)
|
||||
&& validityPolicy.mayReturnStaleWhileRevalidating(entry, now)
|
||||
&& !staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)
|
||||
&& validityPolicy.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now)
|
||||
|| staleIfErrorEnabled) {
|
||||
LOG.debug("Serving stale with asynchronous revalidation");
|
||||
final String exchangeId = ExecSupport.getNextExchangeId();
|
||||
|
@ -331,21 +334,21 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
scope.originalRequest,
|
||||
scope.execRuntime.fork(null),
|
||||
HttpClientContext.create());
|
||||
final SimpleHttpResponse response = generateCachedResponse(request, context, entry, now);
|
||||
final SimpleHttpResponse response = generateCachedResponse(responseCacheControl, request, context, entry, now);
|
||||
cacheRevalidator.revalidateCacheEntry(
|
||||
responseCache.generateKey(target, request, entry),
|
||||
() -> revalidateCacheEntry(target, request, fork, chain, entry));
|
||||
() -> revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, fork, chain, entry));
|
||||
return convert(response, scope);
|
||||
}
|
||||
return revalidateCacheEntry(target, request, scope, chain, entry);
|
||||
return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
|
||||
} catch (final IOException ioex) {
|
||||
if (staleIfErrorEnabled) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Serving stale response due to IOException and stale-if-error enabled");
|
||||
}
|
||||
return convert(generateCachedResponse(request, context, entry, now), scope);
|
||||
return convert(generateCachedResponse(responseCacheControl, request, context, entry, now), scope);
|
||||
}
|
||||
return convert(handleRevalidationFailure(request, context, entry, now), scope);
|
||||
return convert(handleRevalidationFailure(requestCacheControl, responseCacheControl, request, context, entry, now), scope);
|
||||
}
|
||||
} else {
|
||||
LOG.debug("Cache entry not usable; calling backend");
|
||||
|
@ -354,6 +357,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
}
|
||||
|
||||
ClassicHttpResponse revalidateCacheEntry(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpHost target,
|
||||
final ClassicHttpRequest request,
|
||||
final ExecChain.Scope scope,
|
||||
|
@ -361,7 +366,7 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
final HttpCacheEntry cacheEntry) throws IOException, HttpException {
|
||||
Instant requestDate = getCurrentDate();
|
||||
final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
|
||||
scope.originalRequest, cacheEntry);
|
||||
responseCacheControl, scope.originalRequest, cacheEntry);
|
||||
|
||||
ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
|
||||
try {
|
||||
|
@ -394,8 +399,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
}
|
||||
|
||||
if (staleIfErrorAppliesTo(statusCode)
|
||||
&& !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
|
||||
&& validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
|
||||
&& !staleResponseNotAllowed(requestCacheControl, responseCacheControl, cacheEntry, getCurrentDate())
|
||||
&& validityPolicy.mayReturnStaleIfError(requestCacheControl, responseCacheControl, cacheEntry, responseDate)) {
|
||||
try {
|
||||
final SimpleHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
|
||||
cachedResponse.addHeader(HttpHeaders.WARNING, "110 localhost \"Response is stale\"");
|
||||
|
@ -422,7 +427,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
responseCompliance.ensureProtocolCompliance(scope.originalRequest, request, backendResponse);
|
||||
|
||||
responseCache.flushCacheEntriesInvalidatedByExchange(target, request, backendResponse);
|
||||
final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
|
||||
final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(backendResponse);
|
||||
final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
|
||||
if (cacheable) {
|
||||
storeRequestIfModifiedSinceFor304Response(request, backendResponse);
|
||||
return cacheAndReturnResponse(target, request, backendResponse, scope, requestDate, responseDate);
|
||||
|
@ -498,11 +504,12 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
private ClassicHttpResponse handleCacheMiss(
|
||||
final HttpHost target,
|
||||
final ClassicHttpRequest request,
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ExecChain.Scope scope,
|
||||
final ExecChain chain) throws IOException, HttpException {
|
||||
recordCacheMiss(target, request);
|
||||
|
||||
if (!mayCallBackend(request)) {
|
||||
if (!mayCallBackend(requestCacheControl)) {
|
||||
return new BasicClassicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ package org.apache.hc.client5.http.impl.cache;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -184,6 +183,7 @@ public class CachingExecBase {
|
|||
}
|
||||
|
||||
SimpleHttpResponse generateCachedResponse(
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpRequest request,
|
||||
final HttpContext context,
|
||||
final HttpCacheEntry entry,
|
||||
|
@ -196,7 +196,7 @@ public class CachingExecBase {
|
|||
cachedResponse = responseGenerator.generateResponse(request, entry);
|
||||
}
|
||||
setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
|
||||
if (TimeValue.isPositive(validityPolicy.getStaleness(entry, now))) {
|
||||
if (TimeValue.isPositive(validityPolicy.getStaleness(responseCacheControl, entry, now))) {
|
||||
cachedResponse.addHeader(HttpHeaders.WARNING,"110 localhost \"Response is stale\"");
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ public class CachingExecBase {
|
|||
final Header header = entry.getFirstHeader(HttpHeaders.DATE);
|
||||
if (header != null) {
|
||||
final Instant responseDate = DateUtils.parseStandardDate(header.getValue());
|
||||
final TimeValue freshnessLifetime = validityPolicy.getFreshnessLifetime(entry);
|
||||
final TimeValue freshnessLifetime = validityPolicy.getFreshnessLifetime(responseCacheControl, entry);
|
||||
final TimeValue currentAge = validityPolicy.getCurrentAge(entry, responseDate);
|
||||
if (freshnessLifetime.compareTo(ONE_DAY) > 0 && currentAge.compareTo(ONE_DAY) > 0) {
|
||||
cachedResponse.addHeader(HttpHeaders.WARNING,"113 localhost \"Heuristic expiration\"");
|
||||
|
@ -220,11 +220,13 @@ public class CachingExecBase {
|
|||
}
|
||||
|
||||
SimpleHttpResponse handleRevalidationFailure(
|
||||
final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpRequest request,
|
||||
final HttpContext context,
|
||||
final HttpCacheEntry entry,
|
||||
final Instant now) throws IOException {
|
||||
if (staleResponseNotAllowed(request, entry, now)) {
|
||||
if (staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)) {
|
||||
return generateGatewayTimeout(context);
|
||||
} else {
|
||||
return unvalidatedCacheHit(request, context, entry);
|
||||
|
@ -247,14 +249,16 @@ public class CachingExecBase {
|
|||
return cachedResponse;
|
||||
}
|
||||
|
||||
boolean staleResponseNotAllowed(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
|
||||
return validityPolicy.mustRevalidate(entry)
|
||||
|| (cacheConfig.isSharedCache() && validityPolicy.proxyRevalidate(entry))
|
||||
|| explicitFreshnessRequest(request, entry, now);
|
||||
boolean staleResponseNotAllowed(final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl,
|
||||
final HttpCacheEntry entry,
|
||||
final Instant now) {
|
||||
return responseCacheControl.isMustRevalidate()
|
||||
|| (cacheConfig.isSharedCache() && responseCacheControl.isProxyRevalidate())
|
||||
|| explicitFreshnessRequest(requestCacheControl, responseCacheControl, entry, now);
|
||||
}
|
||||
|
||||
boolean mayCallBackend(final HttpRequest request) {
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
boolean mayCallBackend(final RequestCacheControl cacheControl) {
|
||||
if (cacheControl.isOnlyIfCached()) {
|
||||
LOG.debug("Request marked only-if-cached");
|
||||
return false;
|
||||
|
@ -262,15 +266,16 @@ public class CachingExecBase {
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean explicitFreshnessRequest(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
|
||||
if (cacheControl.getMaxStale() >= 0) {
|
||||
boolean explicitFreshnessRequest(final RequestCacheControl requestCacheControl,
|
||||
final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
|
||||
final Instant now) {
|
||||
if (requestCacheControl.getMaxStale() >= 0) {
|
||||
final TimeValue age = validityPolicy.getCurrentAge(entry, now);
|
||||
final TimeValue lifetime = validityPolicy.getFreshnessLifetime(entry);
|
||||
if (age.toSeconds() - lifetime.toSeconds() > cacheControl.getMaxStale()) {
|
||||
final TimeValue lifetime = validityPolicy.getFreshnessLifetime(responseCacheControl, entry);
|
||||
if (age.toSeconds() - lifetime.toSeconds() > requestCacheControl.getMaxStale()) {
|
||||
return true;
|
||||
}
|
||||
} else if (cacheControl.getMinFresh() >= 0 || cacheControl.getMaxAge() >= 0) {
|
||||
} else if (requestCacheControl.getMinFresh() >= 0 || requestCacheControl.getMaxAge() >= 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -375,25 +380,4 @@ public class CachingExecBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided HttpRequest contains a 'no-cache' directive in its Cache-Control header.
|
||||
* <p>
|
||||
* According to the HTTP/1.1 specification, a 'no-cache' directive in a request message means
|
||||
* that the client allows a stored response to be used only if it is first validated with the
|
||||
* origin server (or with an intermediate cache that has a fresh response). This directive
|
||||
* applies to both shared and private caches.
|
||||
*
|
||||
* @param request the HttpRequest to check for the 'no-cache' directive
|
||||
* @return true if the 'no-cache' directive is present in the Cache-Control header of the request,
|
||||
* false otherwise
|
||||
*/
|
||||
boolean requestContainsNoCacheDirective(final HttpRequest request) {
|
||||
final Iterator<Header> it = request.headerIterator(HttpHeaders.CACHE_CONTROL);
|
||||
if (it == null || !it.hasNext()) {
|
||||
return false;
|
||||
} else {
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parseResponse(it);
|
||||
return cacheControl.isNoCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,11 +49,12 @@ class ConditionalRequestBuilder<T extends HttpRequest> {
|
|||
* the entry with the origin. Build the origin {@link org.apache.hc.core5.http.HttpRequest}
|
||||
* here and return it.
|
||||
*
|
||||
* @param cacheControl the cache control directives.
|
||||
* @param request the original request from the caller
|
||||
* @param cacheEntry the entry that needs to be re-validated
|
||||
* @return the wrapped request
|
||||
*/
|
||||
public T buildConditionalRequest(final T request, final HttpCacheEntry cacheEntry) {
|
||||
public T buildConditionalRequest(final ResponseCacheControl cacheControl, final T request, final HttpCacheEntry cacheEntry) {
|
||||
final T newRequest = messageCopier.create(request);
|
||||
|
||||
final Header eTag = cacheEntry.getFirstHeader(HttpHeaders.ETAG);
|
||||
|
@ -64,7 +65,6 @@ class ConditionalRequestBuilder<T extends HttpRequest> {
|
|||
if (lastModified != null) {
|
||||
newRequest.setHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified.getValue());
|
||||
}
|
||||
final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(cacheEntry);
|
||||
if (cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate()) {
|
||||
newRequest.addHeader(HttpHeaders.CACHE_CONTROL, HeaderConstants.CACHE_CONTROL_MAX_AGE + "=0");
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ final class ResponseCacheControl implements CacheControl {
|
|||
*/
|
||||
private final Set<String> noCacheFields;
|
||||
|
||||
private final boolean undefined;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code CacheControl} with the specified values.
|
||||
*
|
||||
|
@ -129,6 +131,16 @@ final class ResponseCacheControl implements CacheControl {
|
|||
this.staleWhileRevalidate = staleWhileRevalidate;
|
||||
this.staleIfError = staleIfError;
|
||||
this.noCacheFields = noCacheFields != null ? Collections.unmodifiableSet(noCacheFields) : Collections.emptySet();
|
||||
this.undefined = maxAge == -1 &&
|
||||
sharedMaxAge == -1 &&
|
||||
!noCache &&
|
||||
!noStore &&
|
||||
!cachePrivate &&
|
||||
!mustRevalidate &&
|
||||
!proxyRevalidate &&
|
||||
!cachePublic &&
|
||||
staleWhileRevalidate == -1
|
||||
&& staleIfError == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,6 +247,10 @@ final class ResponseCacheControl implements CacheControl {
|
|||
return noCacheFields;
|
||||
}
|
||||
|
||||
public boolean isUndefined() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CacheControl{" +
|
||||
|
@ -252,7 +268,7 @@ final class ResponseCacheControl implements CacheControl {
|
|||
'}';
|
||||
}
|
||||
|
||||
static Builder create() {
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,8 @@ import org.apache.hc.core5.http.HttpRequest;
|
|||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.HttpVersion;
|
||||
import org.apache.hc.core5.http.MessageHeaders;
|
||||
import org.apache.hc.core5.http.ProtocolVersion;
|
||||
import org.apache.hc.core5.http.message.MessageSupport;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -161,11 +159,9 @@ class ResponseCachingPolicy {
|
|||
/**
|
||||
* Determines if an HttpResponse can be cached.
|
||||
*
|
||||
* @param httpMethod What type of request was this, a GET, PUT, other?
|
||||
* @param response The origin response
|
||||
* @return {@code true} if response is cacheable
|
||||
*/
|
||||
public boolean isResponseCacheable(final String httpMethod, final HttpResponse response, final ResponseCacheControl cacheControl) {
|
||||
public boolean isResponseCacheable(final ResponseCacheControl cacheControl, final String httpMethod, final HttpResponse response) {
|
||||
boolean cacheable = false;
|
||||
|
||||
if (!HeaderConstants.GET_METHOD.equals(httpMethod) && !HeaderConstants.HEAD_METHOD.equals(httpMethod)
|
||||
|
@ -242,7 +238,7 @@ class ResponseCachingPolicy {
|
|||
}
|
||||
|
||||
// calculate freshness lifetime
|
||||
final Duration freshnessLifetime = calculateFreshnessLifetime(response, cacheControl);
|
||||
final Duration freshnessLifetime = calculateFreshnessLifetime(cacheControl, response);
|
||||
if (freshnessLifetime.isNegative() || freshnessLifetime.isZero()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Freshness lifetime is invalid");
|
||||
|
@ -250,7 +246,7 @@ class ResponseCachingPolicy {
|
|||
return false;
|
||||
}
|
||||
|
||||
return cacheable || isExplicitlyCacheable(response, cacheControl);
|
||||
return cacheable || isExplicitlyCacheable(cacheControl, response);
|
||||
}
|
||||
|
||||
private boolean unknownStatusCode(final int status) {
|
||||
|
@ -295,57 +291,21 @@ class ResponseCachingPolicy {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean isExplicitlyCacheable(final HttpResponse response, final ResponseCacheControl cacheControl ) {
|
||||
protected boolean isExplicitlyCacheable(final ResponseCacheControl cacheControl, final HttpResponse response) {
|
||||
if (response.getFirstHeader(HttpHeaders.EXPIRES) != null) {
|
||||
return true;
|
||||
}
|
||||
if (cacheControl == null) {
|
||||
return false;
|
||||
}else {
|
||||
return cacheControl.getMaxAge() > 0 || cacheControl.getSharedMaxAge()>0 ||
|
||||
cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate() || (cacheControl.isPublic());
|
||||
}
|
||||
return cacheControl.getMaxAge() > 0 || cacheControl.getSharedMaxAge()>0 ||
|
||||
cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate() || (cacheControl.isPublic());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the {@link HttpResponse} gotten from the origin is a
|
||||
* cacheable response.
|
||||
*
|
||||
* @param request the {@link HttpRequest} that generated an origin hit. Can't be {@code null}.
|
||||
* @param response the {@link HttpResponse} from the origin. Can't be {@code null}.
|
||||
* @return {@code true} if response is cacheable
|
||||
* @since 5.3
|
||||
*/
|
||||
public boolean isResponseCacheable(final HttpRequest request, final HttpResponse response) {
|
||||
Args.notNull(request, "Request");
|
||||
Args.notNull(response, "Response");
|
||||
return isResponseCacheable(request, response, parseCacheControlHeader(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an HttpResponse can be cached.
|
||||
*
|
||||
* @param httpMethod What type of request was this, a GET, PUT, other?. Can't be {@code null}.
|
||||
* @param response The origin response. Can't be {@code null}.
|
||||
* @return {@code true} if response is cacheable
|
||||
* @since 5.3
|
||||
*/
|
||||
public boolean isResponseCacheable(final String httpMethod, final HttpResponse response) {
|
||||
Args.notEmpty(httpMethod, "httpMethod");
|
||||
Args.notNull(response, "Response");
|
||||
return isResponseCacheable(httpMethod, response, parseCacheControlHeader(response));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the {@link HttpResponse} gotten from the origin is a
|
||||
* cacheable response.
|
||||
*
|
||||
* @param request the {@link HttpRequest} that generated an origin hit
|
||||
* @param response the {@link HttpResponse} from the origin
|
||||
* @return {@code true} if response is cacheable
|
||||
*/
|
||||
public boolean isResponseCacheable(final HttpRequest request, final HttpResponse response, final ResponseCacheControl cacheControl) {
|
||||
public boolean isResponseCacheable(final ResponseCacheControl cacheControl, final HttpRequest request, final HttpResponse response) {
|
||||
final ProtocolVersion version = request.getVersion() != null ? request.getVersion() : HttpVersion.DEFAULT;
|
||||
if (version.compareToVersion(HttpVersion.HTTP_1_1) > 0) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
|
@ -353,7 +313,7 @@ class ResponseCachingPolicy {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
if (cacheControl != null && cacheControl.isNoStore()) {
|
||||
if (cacheControl.isNoStore()) {
|
||||
LOG.debug("Response is explicitly non-cacheable per cache control directive");
|
||||
return false;
|
||||
}
|
||||
|
@ -362,31 +322,31 @@ class ResponseCachingPolicy {
|
|||
if (neverCache1_0ResponsesWithQueryString && from1_0Origin(response)) {
|
||||
LOG.debug("Response is not cacheable as it had a query string");
|
||||
return false;
|
||||
} else if (!neverCache1_1ResponsesWithQueryString && !isExplicitlyCacheable(response, cacheControl)) {
|
||||
} else if (!neverCache1_1ResponsesWithQueryString && !isExplicitlyCacheable(cacheControl, response)) {
|
||||
LOG.debug("Response is not cacheable as it is missing explicit caching headers");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(response, cacheControl)) {
|
||||
if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(cacheControl, response)) {
|
||||
LOG.debug("Expires header less or equal to Date header and no cache control directives");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sharedCache) {
|
||||
if (request.countHeaders(HttpHeaders.AUTHORIZATION) > 0
|
||||
&& cacheControl != null && !(cacheControl.getSharedMaxAge() > -1 || cacheControl.isMustRevalidate() || cacheControl.isPublic())) {
|
||||
&& !(cacheControl.getSharedMaxAge() > -1 || cacheControl.isMustRevalidate() || cacheControl.isPublic())) {
|
||||
LOG.debug("Request contains private credentials");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final String method = request.getMethod();
|
||||
return isResponseCacheable(method, response, cacheControl);
|
||||
return isResponseCacheable(cacheControl, method, response);
|
||||
}
|
||||
|
||||
private boolean expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(final HttpResponse response, final ResponseCacheControl cacheControl) {
|
||||
if (cacheControl != null) {
|
||||
private boolean expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(final ResponseCacheControl cacheControl, final HttpResponse response) {
|
||||
if (!cacheControl.isUndefined()) {
|
||||
return false;
|
||||
}
|
||||
final Header expiresHdr = response.getFirstHeader(HttpHeaders.EXPIRES);
|
||||
|
@ -446,9 +406,9 @@ class ResponseCachingPolicy {
|
|||
* @param response the HTTP response for which to calculate the freshness lifetime
|
||||
* @return the freshness lifetime of the response, in seconds
|
||||
*/
|
||||
private Duration calculateFreshnessLifetime(final HttpResponse response, final ResponseCacheControl cacheControl) {
|
||||
private Duration calculateFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpResponse response) {
|
||||
|
||||
if (cacheControl == null) {
|
||||
if (cacheControl.isUndefined()) {
|
||||
// If no cache-control header is present, assume no caching directives and return a default value
|
||||
return DEFAULT_FRESHNESS_DURATION; // 5 minutes
|
||||
}
|
||||
|
@ -488,43 +448,21 @@ class ResponseCachingPolicy {
|
|||
* {@code stale-while-revalidate} directive in its Cache-Control header. If it does, this method returns {@code true},
|
||||
* indicating that a stale response can be served. If not, it returns {@code false}.
|
||||
*
|
||||
* @param entry the cached HTTP message entry to check
|
||||
* @return {@code true} if a stale response can be served in case of an error status code, {@code false} otherwise
|
||||
*/
|
||||
boolean isStaleIfErrorEnabled(final HttpCacheEntry entry) {
|
||||
boolean isStaleIfErrorEnabled(final ResponseCacheControl cacheControl, final HttpCacheEntry entry) {
|
||||
// Check if the stale-while-revalidate extension is enabled
|
||||
if (staleIfErrorEnabled) {
|
||||
// Check if the cached response has an error status code
|
||||
final int statusCode = entry.getStatus();
|
||||
if (statusCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode <= HttpStatus.SC_GATEWAY_TIMEOUT) {
|
||||
// Check if the cached response has a stale-while-revalidate directive
|
||||
final ResponseCacheControl cacheControl = parseCacheControlHeader(entry);
|
||||
if (cacheControl == null) {
|
||||
return false;
|
||||
} else {
|
||||
return cacheControl.getStaleWhileRevalidate() > 0;
|
||||
}
|
||||
return cacheControl.getStaleWhileRevalidate() > 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Cache-Control header from the given HTTP messageHeaders and returns the corresponding CacheControl instance.
|
||||
* If the header is not present, returns a CacheControl instance with default values for all directives.
|
||||
*
|
||||
* @param messageHeaders the HTTP message to parse the header from
|
||||
* @return a CacheControl instance with the parsed directives or default values if the header is not present
|
||||
*/
|
||||
private ResponseCacheControl parseCacheControlHeader(final MessageHeaders messageHeaders) {
|
||||
final Iterator<Header> it = messageHeaders.headerIterator(HttpHeaders.CACHE_CONTROL);
|
||||
if (it == null || !it.hasNext()) {
|
||||
return null;
|
||||
} else {
|
||||
return CacheControlHeaderParser.INSTANCE.parseResponse(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given {@link HttpCacheEntry} requires revalidation based on the presence of the {@code no-cache} directive
|
||||
* in the Cache-Control header.
|
||||
|
@ -539,33 +477,26 @@ class ResponseCachingPolicy {
|
|||
* @param entry the {@link HttpCacheEntry} containing the headers to check for the {@code no-cache} directive.
|
||||
* @return true if revalidation is required based on the {@code no-cache} directive, {@code false} otherwise.
|
||||
*/
|
||||
boolean responseContainsNoCacheDirective(final HttpCacheEntry entry) {
|
||||
final ResponseCacheControl responseCacheControl = parseCacheControlHeader(entry);
|
||||
boolean responseContainsNoCacheDirective(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry) {
|
||||
final Set<String> noCacheFields = responseCacheControl.getNoCacheFields();
|
||||
|
||||
if (responseCacheControl != null) {
|
||||
final Set<String> noCacheFields = responseCacheControl.getNoCacheFields();
|
||||
// If no-cache directive is present and has no field names
|
||||
if (responseCacheControl.isNoCache() && noCacheFields.isEmpty()) {
|
||||
LOG.debug("No-cache directive present without field names. Revalidation required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no-cache directive is present and has no field names
|
||||
if (responseCacheControl.isNoCache() && noCacheFields.isEmpty()) {
|
||||
LOG.debug("No-cache directive present without field names. Revalidation required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no-cache directive is present with field names
|
||||
if (responseCacheControl.isNoCache()) {
|
||||
for (final String field : noCacheFields) {
|
||||
if (entry.getFirstHeader(field) != null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("No-cache directive field '{}' found in response headers. Revalidation required.", field);
|
||||
}
|
||||
return true;
|
||||
// If no-cache directive is present with field names
|
||||
if (responseCacheControl.isNoCache()) {
|
||||
for (final String field : noCacheFields) {
|
||||
if (entry.getFirstHeader(field) != null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("No-cache directive field '{}' found in response headers. Revalidation required.", field);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("No no-cache directives found in response headers. No revalidation required.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,7 @@ import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
|||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicHeader;
|
||||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||
import org.apache.hc.core5.util.TimeValue;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -161,68 +159,75 @@ public class TestCacheValidityPolicy {
|
|||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsSMaxAgeIfPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.setSharedMaxAge(10)
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsMaxAgeIfPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(10)
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsMostRestrictiveOfMaxAgeAndSMaxAge() {
|
||||
Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
|
||||
new BasicHeader("Cache-Control", "s-maxage=20") };
|
||||
HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(10)
|
||||
.setSharedMaxAge(20)
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
|
||||
headers = new Header[] { new BasicHeader("Cache-Control", "max-age=20"),
|
||||
new BasicHeader("Cache-Control", "s-maxage=10") };
|
||||
entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
final ResponseCacheControl cacheControl2 = ResponseCacheControl.builder()
|
||||
.setMaxAge(20)
|
||||
.setSharedMaxAge(10)
|
||||
.build();
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl2, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsMaxAgeEvenIfExpiresIsPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(10)
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
|
||||
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsSMaxAgeEvenIfExpiresIsPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10"),
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.setSharedMaxAge(10)
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
|
||||
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
|
||||
assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshnessLifetimeIsFromExpiresHeaderIfNoMaxAge() {
|
||||
final Header[] headers = new Header[] {
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
|
||||
.build();
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
|
||||
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(entry));
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
|
||||
assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(cacheControl, entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeuristicFreshnessLifetime() {
|
||||
final Header[] headers = new Header[] {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(oneSecondAgo)),
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(elevenSecondsAgo))
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(elevenSecondsAgo)));
|
||||
assertEquals(TimeValue.ofSeconds(1), impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ZERO_MILLISECONDS));
|
||||
}
|
||||
|
||||
|
@ -235,18 +240,16 @@ public class TestCacheValidityPolicy {
|
|||
|
||||
@Test
|
||||
public void testHeuristicFreshnessLifetimeIsNonNegative() {
|
||||
final Header[] headers = new Header[] {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(elevenSecondsAgo)),
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(oneSecondAgo))
|
||||
};
|
||||
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(oneSecondAgo)));
|
||||
assertTrue(TimeValue.isNonNegative(impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ofSeconds(10))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseIsFreshIfFreshnessLifetimeExceedsCurrentAge() {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
|
||||
impl = new CacheValidityPolicy() {
|
||||
@Override
|
||||
public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
|
||||
|
@ -255,17 +258,18 @@ public class TestCacheValidityPolicy {
|
|||
return TimeValue.ofSeconds(6);
|
||||
}
|
||||
@Override
|
||||
public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
|
||||
public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
|
||||
assertSame(entry, e);
|
||||
return TimeValue.ofSeconds(10);
|
||||
}
|
||||
};
|
||||
assertTrue(impl.isResponseFresh(entry, now));
|
||||
assertTrue(impl.isResponseFresh(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseIsNotFreshIfFreshnessLifetimeEqualsCurrentAge() {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
|
||||
impl = new CacheValidityPolicy() {
|
||||
@Override
|
||||
public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
|
||||
|
@ -274,17 +278,18 @@ public class TestCacheValidityPolicy {
|
|||
return TimeValue.ofSeconds(6);
|
||||
}
|
||||
@Override
|
||||
public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
|
||||
public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
|
||||
assertSame(entry, e);
|
||||
return TimeValue.ofSeconds(6);
|
||||
}
|
||||
};
|
||||
assertFalse(impl.isResponseFresh(entry, now));
|
||||
assertFalse(impl.isResponseFresh(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseIsNotFreshIfCurrentAgeExceedsFreshnessLifetime() {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
|
||||
impl = new CacheValidityPolicy() {
|
||||
@Override
|
||||
public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
|
||||
|
@ -293,70 +298,70 @@ public class TestCacheValidityPolicy {
|
|||
return TimeValue.ofSeconds(10);
|
||||
}
|
||||
@Override
|
||||
public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
|
||||
public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
|
||||
assertSame(entry, e);
|
||||
return TimeValue.ofSeconds(6);
|
||||
}
|
||||
};
|
||||
assertFalse(impl.isResponseFresh(entry, now));
|
||||
assertFalse(impl.isResponseFresh(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheEntryIsRevalidatableIfHeadersIncludeETag() {
|
||||
final Header[] headers = {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
|
||||
new BasicHeader("ETag", "somevalue")};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
new BasicHeader("ETag", "somevalue"));
|
||||
assertTrue(impl.isRevalidatable(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheEntryIsRevalidatableIfHeadersIncludeLastModifiedDate() {
|
||||
final Header[] headers = {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(Instant.now())) };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
new BasicHeader("Last-Modified", DateUtils.formatStandardDate(Instant.now())));
|
||||
assertTrue(impl.isRevalidatable(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheEntryIsNotRevalidatableIfNoAppropriateHeaders() {
|
||||
final Header[] headers = {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
|
||||
new BasicHeader("Cache-Control", "public") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
new BasicHeader("Cache-Control", "public"));
|
||||
assertFalse(impl.isRevalidatable(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingContentLengthDoesntInvalidateEntry() {
|
||||
final int contentLength = 128;
|
||||
final Header[] headers = {}; // no Content-Length header
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new Header[] { }, // no Content-Length header
|
||||
HttpTestUtils.getRandomBytes(contentLength));
|
||||
assertTrue(impl.contentLengthHeaderMatchesActualLength(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectContentLengthDoesntInvalidateEntry() {
|
||||
final int contentLength = 128;
|
||||
final Header[] headers = { new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)) };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new Header[] { new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)) },
|
||||
HttpTestUtils.getRandomBytes(contentLength));
|
||||
assertTrue(impl.contentLengthHeaderMatchesActualLength(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongContentLengthInvalidatesEntry() {
|
||||
final int contentLength = 128;
|
||||
final Header[] headers = {new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength+1))};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new Header[]{ new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength+1)) },
|
||||
HttpTestUtils.getRandomBytes(contentLength));
|
||||
assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullResourceInvalidatesEntry() {
|
||||
final int contentLength = 128;
|
||||
final Header[] headers = {new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength))};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(
|
||||
new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)));
|
||||
assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
|
||||
}
|
||||
|
||||
|
@ -370,133 +375,108 @@ public class TestCacheValidityPolicy {
|
|||
|
||||
@Test
|
||||
public void testMalformedAgeHeaderValueReturnsMaxAge() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Age", "asdf") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
|
||||
new BasicHeader("Age", "asdf"));
|
||||
// in seconds
|
||||
assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), impl.getAgeValue(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformedCacheControlMaxAgeHeaderReturnsZero() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=asdf") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
// in seconds
|
||||
assertEquals(0L, impl.getMaxAge(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMustRevalidateIsFalseIfDirectiveNotPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertFalse(impl.mustRevalidate(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMustRevalidateIsTrueWhenDirectiveIsPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public, must-revalidate") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertTrue(impl.mustRevalidate(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyRevalidateIsFalseIfDirectiveNotPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertFalse(impl.proxyRevalidate(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyRevalidateIsTrueWhenDirectiveIsPresent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public, proxy-revalidate") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
assertTrue(impl.proxyRevalidate(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleIfErrorInResponseIsTrueWithinStaleness(){
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5, stale-if-error=15")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpRequest req = new BasicHttpRequest("GET","/");
|
||||
assertTrue(impl.mayReturnStaleIfError(req, entry, now));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
|
||||
final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
|
||||
.build();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setStaleIfError(15)
|
||||
.build();
|
||||
assertTrue(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleIfErrorInRequestIsTrueWithinStaleness(){
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpRequest req = new BasicHttpRequest("GET","/");
|
||||
req.setHeader("Cache-Control","stale-if-error=15");
|
||||
assertTrue(impl.mayReturnStaleIfError(req, entry, now));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
|
||||
final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
|
||||
.build();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setStaleIfError(15)
|
||||
.build();
|
||||
assertTrue(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayNotReturnStaleIfErrorInResponseAndAfterResponseWindow(){
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5, stale-if-error=1")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpRequest req = new BasicHttpRequest("GET","/");
|
||||
assertFalse(impl.mayReturnStaleIfError(req, entry, now));
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
|
||||
final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
|
||||
.build();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setStaleIfError(1)
|
||||
.build();
|
||||
assertFalse(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayNotReturnStaleIfErrorInResponseAndAfterRequestWindow(){
|
||||
final Header[] headers = new Header[] {
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpRequest req = new BasicHttpRequest("GET","/");
|
||||
req.setHeader("Cache-Control","stale-if-error=1");
|
||||
assertFalse(impl.mayReturnStaleIfError(req, entry, now));
|
||||
new BasicHeader("Cache-Control", "max-age=5"));
|
||||
final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
|
||||
.setStaleIfError(1)
|
||||
.build();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.build();
|
||||
assertFalse(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveIsAbsent() {
|
||||
final Header[] headers = new Header[] { new BasicHeader("Cache-control", "public") };
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setCachePublic(true)
|
||||
.build();
|
||||
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleWhileRevalidatingIsTrueWhenWithinStaleness() {
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=15")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setStaleWhileRevalidate(15)
|
||||
.build();
|
||||
|
||||
assertTrue(impl.mayReturnStaleWhileRevalidating(entry, now));
|
||||
assertTrue(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleWhileRevalidatingIsFalseWhenPastStaleness() {
|
||||
final Instant twentyFiveSecondsAgo = now.minusSeconds(25);
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(twentyFiveSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=15")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(twentyFiveSecondsAgo)));
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setStaleWhileRevalidate(15)
|
||||
.build();
|
||||
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveEmpty() {
|
||||
final Header[] headers = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=")
|
||||
};
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
|
||||
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setStaleWhileRevalidate(0)
|
||||
.build();
|
||||
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
|
||||
assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,100 +43,106 @@ public class TestCacheableRequestPolicy {
|
|||
@Test
|
||||
public void testIsGetServableFromCache() {
|
||||
final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder().build();
|
||||
|
||||
Assertions.assertTrue(policy.isServableFromCache(request));
|
||||
Assertions.assertTrue(policy.isServableFromCache(cacheControl, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithCacheControlServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
|
||||
request.addHeader("Cache-Control", "no-cache");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder()
|
||||
.setNoCache(true)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("GET", "someUri");
|
||||
request.addHeader("Cache-Control", "no-store");
|
||||
request.addHeader("Cache-Control", "max-age=20");
|
||||
final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
|
||||
.setNoStore(true)
|
||||
.setMaxAge(20)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
|
||||
request = new BasicHttpRequest("GET", "someUri");
|
||||
request.addHeader("Cache-Control", "public");
|
||||
request.addHeader("Cache-Control", "no-store, max-age=20");
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGetWithPragmaServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
|
||||
request.addHeader("Pragma", "no-cache");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder()
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("GET", "someUri");
|
||||
request.addHeader("Pragma", "value1");
|
||||
request.addHeader("Pragma", "value2");
|
||||
final BasicHttpRequest request2 = new BasicHttpRequest("GET", "someUri");
|
||||
request2.addHeader("Pragma", "value1");
|
||||
request2.addHeader("Pragma", "value2");
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder().build();
|
||||
|
||||
Assertions.assertTrue(policy.isServableFromCache(request));
|
||||
Assertions.assertTrue(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Cache-Control", "public");
|
||||
request.addHeader("Cache-Control", "max-age=20");
|
||||
final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
|
||||
.setMaxAge(20)
|
||||
.build();
|
||||
|
||||
Assertions.assertTrue(policy.isServableFromCache(request));
|
||||
Assertions.assertTrue(policy.isServableFromCache(cacheControl2, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithCacheControlServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Cache-Control", "no-cache");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder()
|
||||
.setNoCache(true)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Cache-Control", "no-store");
|
||||
request.addHeader("Cache-Control", "max-age=20");
|
||||
final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
|
||||
.setNoStore(true)
|
||||
.setMaxAge(20)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
|
||||
request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Cache-Control", "public");
|
||||
request.addHeader("Cache-Control", "no-store, max-age=20");
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHeadWithPragmaServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Pragma", "no-cache");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder()
|
||||
.setNoCache(true)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("HEAD", "someUri");
|
||||
request.addHeader("Pragma", "value1");
|
||||
request.addHeader("Pragma", "value2");
|
||||
final BasicHttpRequest request2 = new BasicHttpRequest("HEAD", "someUri");
|
||||
request2.addHeader("Pragma", "value1");
|
||||
request2.addHeader("Pragma", "value2");
|
||||
final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsArbitraryMethodServableFromCache() {
|
||||
BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri");
|
||||
final BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri");
|
||||
final RequestCacheControl cacheControl = RequestCacheControl.builder()
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
|
||||
|
||||
request = new BasicHttpRequest("get", "someUri");
|
||||
final BasicHttpRequest request2 = new BasicHttpRequest("get", "someUri");
|
||||
|
||||
Assertions.assertFalse(policy.isServableFromCache(request));
|
||||
Assertions.assertFalse(policy.isServableFromCache(cacheControl, request2));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.apache.hc.client5.http.cache.HeaderConstants;
|
|||
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
||||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicHeader;
|
||||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||
|
@ -48,9 +47,10 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
private Instant tenSecondsAgo;
|
||||
private Instant nineSecondsAgo;
|
||||
|
||||
private HttpHost host;
|
||||
private HttpRequest request;
|
||||
private HttpCacheEntry entry;
|
||||
private RequestCacheControl requestCacheControl;
|
||||
private ResponseCacheControl responseCacheControl;
|
||||
private CachedResponseSuitabilityChecker impl;
|
||||
|
||||
@BeforeEach
|
||||
|
@ -60,9 +60,10 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
tenSecondsAgo = now.minusSeconds(10);
|
||||
nineSecondsAgo = now.minusSeconds(9);
|
||||
|
||||
host = new HttpHost("foo.example.com");
|
||||
request = new BasicHttpRequest("GET", "/foo");
|
||||
entry = HttpTestUtils.makeCacheEntry();
|
||||
requestCacheControl = RequestCacheControl.builder().build();
|
||||
responseCacheControl = ResponseCacheControl.builder().build();
|
||||
|
||||
impl = new CachedResponseSuitabilityChecker(CacheConfig.DEFAULT);
|
||||
}
|
||||
|
@ -75,117 +76,152 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
public void testNotSuitableIfContentLengthHeaderIsWrong() {
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","1")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableIfCacheEntryIsFresh() {
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfCacheEntryIsNotFresh() {
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.build();
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfRequestHasNoCache() {
|
||||
request.addHeader("Cache-Control", "no-cache");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setNoCache(true)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfAgeExceedsRequestMaxAge() {
|
||||
request.addHeader("Cache-Control", "max-age=10");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMaxAge(10)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableIfFreshAndAgeIsUnderRequestMaxAge() {
|
||||
request.addHeader("Cache-Control", "max-age=15");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMaxAge(15)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableIfFreshAndFreshnessLifetimeGreaterThanRequestMinFresh() {
|
||||
request.addHeader("Cache-Control", "min-fresh=10");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMinFresh(10)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfFreshnessLifetimeLessThanRequestMinFresh() {
|
||||
request.addHeader("Cache-Control", "min-fresh=10");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMinFresh(10)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=15"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(15)
|
||||
.build();
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuitableEvenIfStaleButPermittedByRequestMaxStale() {
|
||||
request.addHeader("Cache-Control", "max-stale=10");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMaxStale(10)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.build();
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfStaleButTooStaleForRequestMaxStale() {
|
||||
request.addHeader("Cache-Control", "max-stale=2");
|
||||
requestCacheControl = RequestCacheControl.builder()
|
||||
.setMaxStale(2)
|
||||
.build();
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=5"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.build();
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -206,7 +242,7 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
.setHeuristicCoefficient(0.1f).build();
|
||||
impl = new CachedResponseSuitabilityChecker(config);
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -224,7 +260,7 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
.build();
|
||||
impl = new CachedResponseSuitabilityChecker(config);
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -232,24 +268,28 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo");
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(headRequest, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, headRequest, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotSuitableIfRequestMethodIsGETAndEntryResourceIsNull() {
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeHeadCacheEntry(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -257,12 +297,14 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeCacheEntryWithNoRequestMethodOrEntity(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -270,12 +312,14 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeCacheEntryWithNoRequestMethod(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -283,11 +327,13 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600")
|
||||
};
|
||||
entry = HttpTestUtils.make204CacheEntryWithNoRequestMethod(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -296,12 +342,14 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Content-Length","128")
|
||||
};
|
||||
entry = HttpTestUtils.makeHeadCacheEntryWithNoRequestMethod(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(headRequest, entry, now));
|
||||
Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, headRequest, entry, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -309,11 +357,13 @@ public class TestCachedResponseSuitabilityChecker {
|
|||
// Prepare a cache entry with HEAD method
|
||||
final Header[] headers = {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("Cache-Control", "max-age=3600"),
|
||||
new BasicHeader("Hc-Request-Method", HeaderConstants.HEAD_METHOD)
|
||||
};
|
||||
entry = getEntry(headers);
|
||||
responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(3600)
|
||||
.build();
|
||||
// Validate that the cache entry is not suitable for the GET request
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
|
||||
Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ import java.time.Duration;
|
|||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
@ -1498,16 +1498,16 @@ public class TestCachingExecChain {
|
|||
|
||||
// Set up the mock response chain
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any())).thenReturn(true);
|
||||
Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any())).thenReturn(true);
|
||||
Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
|
||||
Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any(), Mockito.any())).thenReturn(true);
|
||||
Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any(), Mockito.any())).thenReturn(true);
|
||||
Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
|
||||
|
||||
// Assuming validityPolicy is a Mockito mock
|
||||
Mockito.when(validityPolicy.getCurrentAge(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(TimeValue.ofMilliseconds(0));
|
||||
|
||||
// Assuming validityPolicy is a Mockito mock
|
||||
Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any()))
|
||||
Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(TimeValue.ofMilliseconds(0));
|
||||
|
||||
final SimpleHttpResponse response = SimpleHttpResponse.create(HttpStatus.SC_OK);
|
||||
|
@ -1599,16 +1599,16 @@ public class TestCachingExecChain {
|
|||
|
||||
// Set up the mock response chain
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any())).thenReturn(true);
|
||||
Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any())).thenReturn(true);
|
||||
Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
|
||||
Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any(), Mockito.any())).thenReturn(true);
|
||||
Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any(), Mockito.any())).thenReturn(true);
|
||||
Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
|
||||
|
||||
// Assuming validityPolicy is a Mockito mock
|
||||
Mockito.when(validityPolicy.getCurrentAge(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(TimeValue.ofDays(2));
|
||||
|
||||
// Assuming validityPolicy is a Mockito mock
|
||||
Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any()))
|
||||
Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(TimeValue.ofDays(2));
|
||||
|
||||
final SimpleHttpResponse response = SimpleHttpResponse.create(HttpStatus.SC_OK);
|
||||
|
|
|
@ -70,7 +70,8 @@ public class TestConditionalRequestBuilder {
|
|||
new BasicHeader("Last-Modified", lastModified) };
|
||||
|
||||
final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
|
||||
final HttpRequest newRequest = impl.buildConditionalRequest(basicRequest, cacheEntry);
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
|
||||
final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
|
||||
|
||||
Assertions.assertEquals(theMethod, newRequest.getMethod());
|
||||
Assertions.assertEquals(theUri, newRequest.getRequestUri());
|
||||
|
@ -98,7 +99,8 @@ public class TestConditionalRequestBuilder {
|
|||
};
|
||||
final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
|
||||
final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
|
||||
final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
|
||||
final HttpRequest result = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
|
||||
Assertions.assertEquals(lmDate,
|
||||
result.getFirstHeader("If-Modified-Since").getValue());
|
||||
Assertions.assertEquals(etag,
|
||||
|
@ -121,7 +123,8 @@ public class TestConditionalRequestBuilder {
|
|||
|
||||
final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
|
||||
|
||||
final HttpRequest newRequest = impl.buildConditionalRequest(basicRequest, cacheEntry);
|
||||
final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
|
||||
final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
|
||||
|
||||
Assertions.assertEquals(theMethod, newRequest.getMethod());
|
||||
Assertions.assertEquals(theUri, newRequest.getRequestUri());
|
||||
|
@ -145,14 +148,18 @@ public class TestConditionalRequestBuilder {
|
|||
|
||||
final Header[] cacheEntryHeaders = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("ETag", "\"etag\""),
|
||||
new BasicHeader("Cache-Control","max-age=5, must-revalidate") };
|
||||
new BasicHeader("ETag", "\"etag\"")
|
||||
};
|
||||
final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
|
||||
|
||||
final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setMustRevalidate(true)
|
||||
.build();
|
||||
final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
|
||||
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertEquals(0, cacheControl.getMaxAge());
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertEquals(0, requestCacheControl.getMaxAge());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -165,14 +172,18 @@ public class TestConditionalRequestBuilder {
|
|||
|
||||
final Header[] cacheEntryHeaders = new Header[] {
|
||||
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
|
||||
new BasicHeader("ETag", "\"etag\""),
|
||||
new BasicHeader("Cache-Control","max-age=5, proxy-revalidate") };
|
||||
new BasicHeader("ETag", "\"etag\"")
|
||||
};
|
||||
final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
|
||||
|
||||
final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
|
||||
final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
|
||||
.setMaxAge(5)
|
||||
.setProxyRevalidate(true)
|
||||
.build();
|
||||
final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
|
||||
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertEquals(0, cacheControl.getMaxAge());
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertEquals(0, requestCacheControl.getMaxAge());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,8 +206,8 @@ public class TestConditionalRequestBuilder {
|
|||
public void testBuildUnconditionalRequestAddsCacheControlNoCache()
|
||||
throws Exception {
|
||||
final HttpRequest result = impl.buildUnconditionalRequest(request);
|
||||
final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertTrue(cacheControl.isNoCache());
|
||||
final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
|
||||
Assertions.assertTrue(requestCacheControl.isNoCache());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue