Made caching of 403 responses by the classic and async protocol handlers more consistent

This commit is contained in:
Oleg Kalnichevski 2024-01-01 13:18:53 +01:00
parent c5de6961d1
commit f24c8010bb
2 changed files with 97 additions and 93 deletions

View File

@ -515,21 +515,20 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(backendResponse);
final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
if (cacheable) {
cachingConsumerRef.set(new CachingAsyncDataConsumer(exchangeId, asyncExecCallback, backendResponse, entityDetails));
storeRequestIfModifiedSinceFor304Response(request, backendResponse);
if (LOG.isDebugEnabled()) {
LOG.debug("{} caching backend response", exchangeId);
}
final CachingAsyncDataConsumer cachingDataConsumer = new CachingAsyncDataConsumer(
exchangeId, asyncExecCallback, backendResponse, entityDetails);
cachingConsumerRef.set(cachingDataConsumer);
return cachingDataConsumer;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("{} backend response is not cacheable", exchangeId);
}
return asyncExecCallback.handleResponse(backendResponse, entityDetails);
}
final CachingAsyncDataConsumer cachingDataConsumer = cachingConsumerRef.get();
if (cachingDataConsumer != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} caching backend response", exchangeId);
}
return cachingDataConsumer;
}
return asyncExecCallback.handleResponse(backendResponse, entityDetails);
}
@Override
@ -576,13 +575,87 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
}
void triggerCachedResponse(final HttpCacheEntry entry) {
try {
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, entry);
triggerResponse(cacheResponse, scope, asyncExecCallback);
} catch (final ResourceIOException ex) {
asyncExecCallback.failed(ex);
}
}
@Override
public void completed() {
final String exchangeId = scope.exchangeId;
final CachingAsyncDataConsumer cachingDataConsumer = cachingConsumerRef.getAndSet(null);
if (cachingDataConsumer != null && !cachingDataConsumer.writtenThrough.get()) {
final ByteArrayBuffer buffer = cachingDataConsumer.bufferRef.getAndSet(null);
final HttpResponse backendResponse = cachingDataConsumer.backendResponse;
if (cachingDataConsumer == null || cachingDataConsumer.writtenThrough.get()) {
asyncExecCallback.completed();
return;
}
final HttpResponse backendResponse = cachingDataConsumer.backendResponse;
final ByteArrayBuffer buffer = cachingDataConsumer.bufferRef.getAndSet(null);
// Handle 304 Not Modified responses
if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
responseCache.match(target, request, new FutureCallback<CacheMatch>() {
@Override
public void completed(final CacheMatch result) {
final CacheHit hit = result != null ? result.hit : null;
if (hit != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} existing cache entry found, updating cache entry", exchangeId);
}
responseCache.update(
hit,
target,
request,
backendResponse,
requestDate,
responseDate,
new FutureCallback<CacheHit>() {
@Override
public void completed(final CacheHit updated) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} cache entry updated, generating response from updated entry", exchangeId);
}
triggerCachedResponse(updated.entry);
}
@Override
public void failed(final Exception cause) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} request failed: {}", exchangeId, cause.getMessage());
}
asyncExecCallback.failed(cause);
}
@Override
public void cancelled() {
if (LOG.isDebugEnabled()) {
LOG.debug("{} cache entry updated aborted", exchangeId);
}
asyncExecCallback.failed(new InterruptedIOException());
}
});
} else {
triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
}
}
@Override
public void failed(final Exception cause) {
asyncExecCallback.failed(cause);
}
@Override
public void cancelled() {
asyncExecCallback.failed(new InterruptedIOException());
}
});
} else {
if (cacheConfig.isFreshnessCheckEnabled()) {
final CancellableDependency operation = scope.cancellableDependency;
operation.setDependency(responseCache.match(target, request, new FutureCallback<CacheMatch>() {
@ -594,12 +667,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
if (LOG.isDebugEnabled()) {
LOG.debug("{} backend already contains fresher cache entry", exchangeId);
}
try {
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, hit.entry);
triggerResponse(cacheResponse, scope, asyncExecCallback);
} catch (final ResourceIOException ex) {
asyncExecCallback.failed(ex);
}
triggerCachedResponse(hit.entry);
} else {
triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
}
@ -619,8 +687,6 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
} else {
triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
}
} else {
asyncExecCallback.completed();
}
}
@ -1183,69 +1249,6 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
final EntityDetails entityDetails) throws HttpException, IOException {
final Instant responseDate = getCurrentDate();
final AsyncExecCallback callback;
// Handle 304 Not Modified responses
if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
responseCache.match(target, request, new FutureCallback<CacheMatch>() {
@Override
public void completed(final CacheMatch result) {
final CacheHit hit = result != null ? result.hit : null;
if (hit != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} existing cache entry found, updating cache entry", exchangeId);
}
responseCache.update(
hit,
target,
request,
backendResponse,
requestDate,
responseDate,
new FutureCallback<CacheHit>() {
@Override
public void completed(final CacheHit updated) {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("{} cache entry updated, generating response from updated entry", exchangeId);
}
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, updated.entry);
triggerResponse(cacheResponse, scope, asyncExecCallback);
} catch (final ResourceIOException ex) {
asyncExecCallback.failed(ex);
}
}
@Override
public void failed(final Exception cause) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} request failed: {}", exchangeId, cause.getMessage());
}
asyncExecCallback.failed(cause);
}
@Override
public void cancelled() {
if (LOG.isDebugEnabled()) {
LOG.debug("{} cache entry updated aborted", exchangeId);
}
asyncExecCallback.failed(new InterruptedIOException());
}
});
}
}
@Override
public void failed(final Exception cause) {
asyncExecCallback.failed(cause);
}
@Override
public void cancelled() {
asyncExecCallback.failed(new InterruptedIOException());
}
});
}
if (backendResponse.getCode() != HttpStatus.SC_NOT_MODIFIED) {
callback = new BackendResponseHandler(target, request, requestDate, responseDate, scope, asyncExecCallback);
} else {

View File

@ -454,12 +454,16 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
if (cacheable) {
storeRequestIfModifiedSinceFor304Response(request, backendResponse);
if (LOG.isDebugEnabled()) {
LOG.debug("{} caching backend response", exchangeId);
}
return cacheAndReturnResponse(exchangeId, target, request, backendResponse, requestDate, responseDate);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("{} backend response is not cacheable", exchangeId);
}
return backendResponse;
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} backend response is not cacheable", exchangeId);
}
return backendResponse;
}
ClassicHttpResponse cacheAndReturnResponse(
@ -469,12 +473,9 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
final ClassicHttpResponse backendResponse,
final Instant requestSent,
final Instant responseReceived) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("{} caching backend response", exchangeId);
}
final int statusCode = backendResponse.getCode();
// handle 304 Not Modified responses
if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
final CacheMatch result = responseCache.match(target ,request);
final CacheHit hit = result != null ? result.hit : null;
if (hit != null) {
@ -514,7 +515,7 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
backendResponse.close();
CacheHit hit;
if (cacheConfig.isFreshnessCheckEnabled()) {
if (cacheConfig.isFreshnessCheckEnabled() && statusCode != HttpStatus.SC_NOT_MODIFIED) {
final CacheMatch result = responseCache.match(target ,request);
hit = result != null ? result.hit : null;
if (HttpCacheEntry.isNewer(hit != null ? hit.entry : null, backendResponse)) {