You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/10/03 08:51:42 UTC
[7/7] httpcomponents-client git commit: Reduced dependency on classic
(blocking) I/O APIs in CacheExec
Reduced dependency on classic (blocking) I/O APIs in CacheExec
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/212d7a2e
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/212d7a2e
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/212d7a2e
Branch: refs/heads/master
Commit: 212d7a2e831ec9cfc8734d55ae7fb19dfdec26fb
Parents: e71d8fa
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Tue Oct 3 10:41:15 2017 +0200
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Tue Oct 3 10:41:15 2017 +0200
----------------------------------------------------------------------
.../hc/client5/http/impl/cache/CachingExec.java | 581 +++++++++----------
.../http/impl/cache/OptionsHttp11Response.java | 184 ------
2 files changed, 273 insertions(+), 492 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/212d7a2e/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java
index a4d6aee..5622e2a 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java
@@ -225,26 +225,6 @@ public class CachingExec implements ExecChainHandler {
return cacheUpdates.get();
}
- private static ClassicHttpResponse convert(final SimpleHttpResponse cacheResponse) {
- if (cacheResponse == null) {
- return null;
- }
- final ClassicHttpResponse response = new BasicClassicHttpResponse(cacheResponse.getCode(), cacheResponse.getReasonPhrase());
- for (final Iterator<Header> it = cacheResponse.headerIterator(); it.hasNext(); ) {
- response.addHeader(it.next());
- }
- response.setVersion(cacheResponse.getVersion() != null ? cacheResponse.getVersion() : HttpVersion.DEFAULT);
- final SimpleBody body = cacheResponse.getBody();
- if (body != null) {
- if (body.isText()) {
- response.setEntity(new StringEntity(body.getBodyText(), body.getContentType()));
- } else {
- response.setEntity(new ByteArrayEntity(body.getBodyBytes(), body.getContentType()));
- }
- }
- return response;
- }
-
@Override
public ClassicHttpResponse execute(
final ClassicHttpRequest request,
@@ -266,12 +246,12 @@ public class CachingExec implements ExecChainHandler {
if (clientRequestsOurOptions(request)) {
setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE);
- return new OptionsHttp11Response();
+ return new BasicClassicHttpResponse(HttpStatus.SC_NOT_IMPLEMENTED);
}
- final ClassicHttpResponse fatalErrorResponse = getFatallyNoncompliantResponse(request, context);
+ final SimpleHttpResponse fatalErrorResponse = getFatallyNoncompliantResponse(request, context);
if (fatalErrorResponse != null) {
- return fatalErrorResponse;
+ return convert(fatalErrorResponse);
}
requestCompliance.makeRequestCompliant(request);
@@ -297,6 +277,45 @@ public class CachingExec implements ExecChainHandler {
}
}
+ private static ClassicHttpResponse convert(final SimpleHttpResponse cacheResponse) {
+ if (cacheResponse == null) {
+ return null;
+ }
+ final ClassicHttpResponse response = new BasicClassicHttpResponse(cacheResponse.getCode(), cacheResponse.getReasonPhrase());
+ for (final Iterator<Header> it = cacheResponse.headerIterator(); it.hasNext(); ) {
+ response.addHeader(it.next());
+ }
+ response.setVersion(cacheResponse.getVersion() != null ? cacheResponse.getVersion() : HttpVersion.DEFAULT);
+ final SimpleBody body = cacheResponse.getBody();
+ if (body != null) {
+ if (body.isText()) {
+ response.setEntity(new StringEntity(body.getBodyText(), body.getContentType()));
+ } else {
+ response.setEntity(new ByteArrayEntity(body.getBodyBytes(), body.getContentType()));
+ }
+ }
+ return response;
+ }
+
+ ClassicHttpResponse callBackend(
+ final HttpHost target,
+ final ClassicHttpRequest request,
+ final ExecChain.Scope scope,
+ final ExecChain chain) throws IOException, HttpException {
+
+ final Date requestDate = getCurrentDate();
+
+ log.trace("Calling the backend");
+ final ClassicHttpResponse backendResponse = chain.proceed(request, scope);
+ try {
+ backendResponse.addHeader("Via", generateViaHeader(backendResponse));
+ return handleBackendResponse(target, request, scope, requestDate, getCurrentDate(), backendResponse);
+ } catch (final IOException | RuntimeException ex) {
+ backendResponse.close();
+ throw ex;
+ }
+ }
+
private ClassicHttpResponse handleCacheHit(
final HttpHost target,
final ClassicHttpRequest request,
@@ -310,10 +329,10 @@ public class CachingExec implements ExecChainHandler {
final Date now = getCurrentDate();
if (suitabilityChecker.canCachedResponseBeUsed(target, request, entry, now)) {
log.debug("Cache hit");
- out = generateCachedResponse(request, context, entry, now);
+ out = convert(generateCachedResponse(request, context, entry, now));
} else if (!mayCallBackend(request)) {
log.debug("Cache entry not suitable but only-if-cached requested");
- out = generateGatewayTimeout(context);
+ out = convert(generateGatewayTimeout(context));
} else if (!(entry.getStatus() == HttpStatus.SC_NOT_MODIFIED
&& !suitabilityChecker.isConditional(request))) {
log.debug("Revalidating cache entry");
@@ -342,14 +361,140 @@ public class CachingExec implements ExecChainHandler {
&& !staleResponseNotAllowed(request, entry, now)
&& validityPolicy.mayReturnStaleWhileRevalidating(entry, now)) {
log.trace("Serving stale with asynchronous revalidation");
- final ClassicHttpResponse resp = generateCachedResponse(request, context, entry, now);
+ final SimpleHttpResponse resp = generateCachedResponse(request, context, entry, now);
asynchRevalidator.revalidateCacheEntry(this, target, request, scope, chain, entry);
- return resp;
+ return convert(resp);
}
return revalidateCacheEntry(target, request, scope, chain, entry);
} catch (final IOException ioex) {
- return handleRevalidationFailure(request, context, entry, now);
+ return convert(handleRevalidationFailure(request, context, entry, now));
+ }
+ }
+
+ ClassicHttpResponse revalidateCacheEntry(
+ final HttpHost target,
+ final ClassicHttpRequest request,
+ final ExecChain.Scope scope,
+ final ExecChain chain,
+ final HttpCacheEntry cacheEntry) throws IOException, HttpException {
+
+ final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
+ scope.originalRequest, cacheEntry);
+
+ Date requestDate = getCurrentDate();
+ ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
+ try {
+ Date responseDate = getCurrentDate();
+
+ if (revalidationResponseIsTooOld(backendResponse, cacheEntry)) {
+ backendResponse.close();
+ final ClassicHttpRequest unconditional = conditionalRequestBuilder.buildUnconditionalRequest(
+ scope.originalRequest);
+ requestDate = getCurrentDate();
+ backendResponse = chain.proceed(unconditional, scope);
+ responseDate = getCurrentDate();
+ }
+
+ backendResponse.addHeader(HeaderConstants.VIA, generateViaHeader(backendResponse));
+
+ final int statusCode = backendResponse.getCode();
+ if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) {
+ recordCacheUpdate(scope.clientContext);
+ }
+
+ if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
+ final HttpCacheEntry updatedEntry = responseCache.updateCacheEntry(
+ target, request, cacheEntry,
+ backendResponse, requestDate, responseDate);
+ if (suitabilityChecker.isConditional(request)
+ && suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) {
+ return convert(responseGenerator.generateNotModifiedResponse(updatedEntry));
+ }
+ return convert(responseGenerator.generateResponse(request, updatedEntry));
+ }
+
+ if (staleIfErrorAppliesTo(statusCode)
+ && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
+ && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
+ try {
+ final SimpleHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
+ cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
+ return convert(cachedResponse);
+ } finally {
+ backendResponse.close();
+ }
+ }
+ return handleBackendResponse(target, conditionalRequest, scope, requestDate, responseDate, backendResponse);
+ } catch (final IOException | RuntimeException ex) {
+ backendResponse.close();
+ throw ex;
+ }
+ }
+
+ ClassicHttpResponse handleBackendResponse(
+ final HttpHost target,
+ final ClassicHttpRequest request,
+ final ExecChain.Scope scope,
+ final Date requestDate,
+ final Date responseDate,
+ final ClassicHttpResponse backendResponse) throws IOException {
+
+ log.trace("Handling Backend response");
+ responseCompliance.ensureProtocolCompliance(scope.originalRequest, request, backendResponse);
+
+ final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
+ responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse);
+ if (cacheable && !alreadyHaveNewerCacheEntry(target, request, backendResponse)) {
+ storeRequestIfModifiedSinceFor304Response(request, backendResponse);
+ return cacheAndReturnResponse(target, request, backendResponse, requestDate, responseDate);
}
+ if (!cacheable) {
+ try {
+ responseCache.flushCacheEntriesFor(target, request);
+ } catch (final IOException ioe) {
+ log.warn("Unable to flush invalid cache entries", ioe);
+ }
+ }
+ return backendResponse;
+ }
+
+ ClassicHttpResponse cacheAndReturnResponse(
+ final HttpHost target,
+ final HttpRequest request,
+ final ClassicHttpResponse backendResponse,
+ final Date requestSent,
+ final Date responseReceived) throws IOException { final ByteArrayBuffer buf;
+ final HttpEntity entity = backendResponse.getEntity();
+ if (entity != null) {
+ buf = new ByteArrayBuffer(1024);
+ final InputStream instream = entity.getContent();
+ final byte[] tmp = new byte[2048];
+ long total = 0;
+ int l;
+ while ((l = instream.read(tmp)) != -1) {
+ buf.append(tmp, 0, l);
+ total += l;
+ if (total > cacheConfig.getMaxObjectSize()) {
+ backendResponse.setEntity(new CombinedEntity(entity, buf));
+ return backendResponse;
+ }
+ }
+ } else {
+ buf = null;
+ }
+ if (buf != null && isIncompleteResponse(backendResponse, buf)) {
+ final Header h = backendResponse.getFirstHeader(HttpHeaders.CONTENT_LENGTH);
+ final ClassicHttpResponse error = new BasicClassicHttpResponse(HttpStatus.SC_BAD_GATEWAY, "Bad Gateway");
+ final String msg = String.format("Received incomplete response " +
+ "with Content-Length %s but actual body length %d",
+ h != null ? h.getValue() : null, buf.length());
+ error.setEntity(new StringEntity(msg, ContentType.TEXT_PLAIN));
+ backendResponse.close();
+ return error;
+ }
+ backendResponse.close();
+ final HttpCacheEntry entry = responseCache.createCacheEntry(target, request, backendResponse, buf, requestSent, responseReceived);
+ return convert(responseGenerator.generateResponse(request, entry));
}
private ClassicHttpResponse handleCacheMiss(
@@ -371,6 +516,77 @@ public class CachingExec implements ExecChainHandler {
return callBackend(target, request, scope, chain);
}
+ ClassicHttpResponse negotiateResponseFromVariants(
+ final HttpHost target,
+ final ClassicHttpRequest request,
+ final ExecChain.Scope scope,
+ final ExecChain chain,
+ final Map<String, Variant> variants) throws IOException, HttpException {
+ final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequestFromVariants(
+ request, variants);
+
+ final Date requestDate = getCurrentDate();
+ final ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
+ try {
+ final Date responseDate = getCurrentDate();
+
+ backendResponse.addHeader("Via", generateViaHeader(backendResponse));
+
+ if (backendResponse.getCode() != HttpStatus.SC_NOT_MODIFIED) {
+ return handleBackendResponse(target, request, scope, requestDate, responseDate, backendResponse);
+ }
+
+ final Header resultEtagHeader = backendResponse.getFirstHeader(HeaderConstants.ETAG);
+ if (resultEtagHeader == null) {
+ log.warn("304 response did not contain ETag");
+ EntityUtils.consume(backendResponse.getEntity());
+ backendResponse.close();
+ return callBackend(target, request, scope, chain);
+ }
+
+ final String resultEtag = resultEtagHeader.getValue();
+ final Variant matchingVariant = variants.get(resultEtag);
+ if (matchingVariant == null) {
+ log.debug("304 response did not contain ETag matching one sent in If-None-Match");
+ EntityUtils.consume(backendResponse.getEntity());
+ backendResponse.close();
+ return callBackend(target, request, scope, chain);
+ }
+
+ final HttpCacheEntry matchedEntry = matchingVariant.getEntry();
+
+ if (revalidationResponseIsTooOld(backendResponse, matchedEntry)) {
+ EntityUtils.consume(backendResponse.getEntity());
+ backendResponse.close();
+ final ClassicHttpRequest unconditional = conditionalRequestBuilder.buildUnconditionalRequest(request);
+ return callBackend(target, unconditional, scope, chain);
+ }
+
+ recordCacheUpdate(scope.clientContext);
+
+ HttpCacheEntry responseEntry = matchedEntry;
+ try {
+ responseEntry = responseCache.updateVariantCacheEntry(target, conditionalRequest,
+ matchedEntry, backendResponse, requestDate, responseDate, matchingVariant.getCacheKey());
+ } catch (final IOException ioe) {
+ log.warn("Could not processChallenge cache entry", ioe);
+ } finally {
+ backendResponse.close();
+ }
+
+ final SimpleHttpResponse resp = responseGenerator.generateResponse(request, responseEntry);
+ tryToUpdateVariantMap(target, request, matchingVariant);
+
+ if (shouldSendNotModifiedResponse(request, responseEntry)) {
+ return convert(responseGenerator.generateNotModifiedResponse(responseEntry));
+ }
+ return convert(resp);
+ } catch (final IOException | RuntimeException ex) {
+ backendResponse.close();
+ throw ex;
+ }
+ }
+
private ClassicHttpResponse handleCacheFailure(
final HttpHost target,
final ClassicHttpRequest request,
@@ -385,8 +601,8 @@ public class CachingExec implements ExecChainHandler {
setResponseStatus(scope.clientContext, CacheResponseStatus.FAILURE);
return chain.proceed(request, scope);
}
- private HttpCacheEntry satisfyFromCache(
- final HttpHost target, final ClassicHttpRequest request) {
+
+ private HttpCacheEntry satisfyFromCache(final HttpHost target, final HttpRequest request) {
HttpCacheEntry entry = null;
try {
entry = responseCache.getCacheEntry(target, request);
@@ -396,21 +612,19 @@ public class CachingExec implements ExecChainHandler {
return entry;
}
- private ClassicHttpResponse getFatallyNoncompliantResponse(
- final ClassicHttpRequest request,
+ private SimpleHttpResponse getFatallyNoncompliantResponse(
+ final HttpRequest request,
final HttpContext context) {
final List<RequestProtocolError> fatalError = requestCompliance.requestIsFatallyNonCompliant(request);
if (fatalError != null && !fatalError.isEmpty()) {
setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE);
- return convert(responseGenerator.getErrorForRequest(fatalError.get(0)));
+ return responseGenerator.getErrorForRequest(fatalError.get(0));
} else {
return null;
}
}
- private Map<String, Variant> getExistingCacheVariants(
- final HttpHost target,
- final ClassicHttpRequest request) {
+ private Map<String, Variant> getExistingCacheVariants(final HttpHost target, final HttpRequest request) {
Map<String,Variant> variants = null;
try {
variants = responseCache.getVariantCacheEntriesWithEtags(target, request);
@@ -420,21 +634,21 @@ public class CachingExec implements ExecChainHandler {
return variants;
}
- private void recordCacheMiss(final HttpHost target, final ClassicHttpRequest request) {
+ private void recordCacheMiss(final HttpHost target, final HttpRequest request) {
cacheMisses.getAndIncrement();
if (log.isTraceEnabled()) {
log.trace("Cache miss [host: " + target + "; uri: " + request.getRequestUri() + "]");
}
}
- private void recordCacheHit(final HttpHost target, final ClassicHttpRequest request) {
+ private void recordCacheHit(final HttpHost target, final HttpRequest request) {
cacheHits.getAndIncrement();
if (log.isTraceEnabled()) {
log.trace("Cache hit [host: " + target + "; uri: " + request.getRequestUri() + "]");
}
}
- private void recordCacheFailure(final HttpHost target, final ClassicHttpRequest request) {
+ private void recordCacheFailure(final HttpHost target, final HttpRequest request) {
cacheMisses.getAndIncrement();
if (log.isTraceEnabled()) {
log.trace("Cache failure [host: " + target + "; uri: " + request.getRequestUri() + "]");
@@ -446,9 +660,7 @@ public class CachingExec implements ExecChainHandler {
setResponseStatus(context, CacheResponseStatus.VALIDATED);
}
- private void flushEntriesInvalidatedByRequest(
- final HttpHost target,
- final ClassicHttpRequest request) {
+ private void flushEntriesInvalidatedByRequest(final HttpHost target, final HttpRequest request) {
try {
responseCache.flushInvalidatedCacheEntriesFor(target, request);
} catch (final IOException ioe) {
@@ -456,17 +668,17 @@ public class CachingExec implements ExecChainHandler {
}
}
- private ClassicHttpResponse generateCachedResponse(
- final ClassicHttpRequest request,
+ private SimpleHttpResponse generateCachedResponse(
+ final HttpRequest request,
final HttpContext context,
final HttpCacheEntry entry,
final Date now) throws IOException {
- final ClassicHttpResponse cachedResponse;
+ final SimpleHttpResponse cachedResponse;
if (request.containsHeader(HeaderConstants.IF_NONE_MATCH)
|| request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) {
- cachedResponse = convert(responseGenerator.generateNotModifiedResponse(entry));
+ cachedResponse = responseGenerator.generateNotModifiedResponse(entry);
} else {
- cachedResponse = convert(responseGenerator.generateResponse(request, entry));
+ cachedResponse = responseGenerator.generateResponse(request, entry);
}
setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
if (validityPolicy.getStalenessSecs(entry, now) > 0L) {
@@ -475,8 +687,8 @@ public class CachingExec implements ExecChainHandler {
return cachedResponse;
}
- private ClassicHttpResponse handleRevalidationFailure(
- final ClassicHttpRequest request,
+ private SimpleHttpResponse handleRevalidationFailure(
+ final HttpRequest request,
final HttpContext context,
final HttpCacheEntry entry,
final Date now) throws IOException {
@@ -487,32 +699,29 @@ public class CachingExec implements ExecChainHandler {
}
}
- private ClassicHttpResponse generateGatewayTimeout(
+ private SimpleHttpResponse generateGatewayTimeout(
final HttpContext context) {
setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE);
- return new BasicClassicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
+ return SimpleHttpResponse.create(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
}
- private ClassicHttpResponse unvalidatedCacheHit(
- final ClassicHttpRequest request,
+ private SimpleHttpResponse unvalidatedCacheHit(
+ final HttpRequest request,
final HttpContext context,
final HttpCacheEntry entry) throws IOException {
- final ClassicHttpResponse cachedResponse = convert(responseGenerator.generateResponse(request, entry));
+ final SimpleHttpResponse cachedResponse = responseGenerator.generateResponse(request, entry);
setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\"");
return cachedResponse;
}
- private boolean staleResponseNotAllowed(
- final ClassicHttpRequest request,
- final HttpCacheEntry entry,
- final Date now) {
+ private boolean staleResponseNotAllowed(final HttpRequest request, final HttpCacheEntry entry, final Date now) {
return validityPolicy.mustRevalidate(entry)
|| (cacheConfig.isSharedCache() && validityPolicy.proxyRevalidate(entry))
|| explicitFreshnessRequest(request, entry, now);
}
- private boolean mayCallBackend(final ClassicHttpRequest request) {
+ private boolean mayCallBackend(final HttpRequest request) {
final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL);
while (it.hasNext()) {
final HeaderElement elt = it.next();
@@ -524,10 +733,7 @@ public class CachingExec implements ExecChainHandler {
return true;
}
- private boolean explicitFreshnessRequest(
- final ClassicHttpRequest request,
- final HttpCacheEntry entry,
- final Date now) {
+ private boolean explicitFreshnessRequest(final HttpRequest request, final HttpCacheEntry entry, final Date now) {
final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL);
while (it.hasNext()) {
final HeaderElement elt = it.next();
@@ -615,25 +821,6 @@ public class CachingExec implements ExecChainHandler {
return true;
}
- ClassicHttpResponse callBackend(
- final HttpHost target,
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final ExecChain chain) throws IOException, HttpException {
-
- final Date requestDate = getCurrentDate();
-
- log.trace("Calling the backend");
- final ClassicHttpResponse backendResponse = chain.proceed(request, scope);
- try {
- backendResponse.addHeader("Via", generateViaHeader(backendResponse));
- return handleBackendResponse(target, request, scope, requestDate, getCurrentDate(), backendResponse);
- } catch (final IOException | RuntimeException ex) {
- backendResponse.close();
- throw ex;
- }
- }
-
private boolean revalidationResponseIsTooOld(final HttpResponse backendResponse,
final HttpCacheEntry cacheEntry) {
final Header entryDateHeader = cacheEntry.getFirstHeader(HttpHeaders.DATE);
@@ -655,103 +842,9 @@ public class CachingExec implements ExecChainHandler {
return false;
}
- ClassicHttpResponse negotiateResponseFromVariants(
- final HttpHost target,
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final ExecChain chain,
- final Map<String, Variant> variants) throws IOException, HttpException {
- final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequestFromVariants(
- request, variants);
-
- final Date requestDate = getCurrentDate();
- final ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
- try {
- final Date responseDate = getCurrentDate();
-
- backendResponse.addHeader("Via", generateViaHeader(backendResponse));
-
- if (backendResponse.getCode() != HttpStatus.SC_NOT_MODIFIED) {
- return handleBackendResponse(target, request, scope, requestDate, responseDate, backendResponse);
- }
-
- final Header resultEtagHeader = backendResponse.getFirstHeader(HeaderConstants.ETAG);
- if (resultEtagHeader == null) {
- log.warn("304 response did not contain ETag");
- EntityUtils.consume(backendResponse.getEntity());
- backendResponse.close();
- return callBackend(target, request, scope, chain);
- }
-
- final String resultEtag = resultEtagHeader.getValue();
- final Variant matchingVariant = variants.get(resultEtag);
- if (matchingVariant == null) {
- log.debug("304 response did not contain ETag matching one sent in If-None-Match");
- EntityUtils.consume(backendResponse.getEntity());
- backendResponse.close();
- return callBackend(target, request, scope, chain);
- }
-
- final HttpCacheEntry matchedEntry = matchingVariant.getEntry();
-
- if (revalidationResponseIsTooOld(backendResponse, matchedEntry)) {
- EntityUtils.consume(backendResponse.getEntity());
- backendResponse.close();
- return retryRequestUnconditionally(target, request, scope, chain);
- }
-
- recordCacheUpdate(scope.clientContext);
-
- final HttpCacheEntry responseEntry = getUpdatedVariantEntry(
- target, conditionalRequest, requestDate, responseDate,
- backendResponse, matchingVariant, matchedEntry);
- backendResponse.close();
-
- final SimpleHttpResponse resp = responseGenerator.generateResponse(request, responseEntry);
- tryToUpdateVariantMap(target, request, matchingVariant);
-
- if (shouldSendNotModifiedResponse(request, responseEntry)) {
- return convert(responseGenerator.generateNotModifiedResponse(responseEntry));
- }
- return convert(resp);
- } catch (final IOException | RuntimeException ex) {
- backendResponse.close();
- throw ex;
- }
- }
-
- private ClassicHttpResponse retryRequestUnconditionally(
- final HttpHost target,
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final ExecChain chain) throws IOException, HttpException {
- final ClassicHttpRequest unconditional = conditionalRequestBuilder.buildUnconditionalRequest(request);
- return callBackend(target, unconditional, scope, chain);
- }
-
- private HttpCacheEntry getUpdatedVariantEntry(
- final HttpHost target,
- final ClassicHttpRequest conditionalRequest,
- final Date requestDate,
- final Date responseDate,
- final ClassicHttpResponse backendResponse,
- final Variant matchingVariant,
- final HttpCacheEntry matchedEntry) throws IOException {
- HttpCacheEntry responseEntry = matchedEntry;
- try {
- responseEntry = responseCache.updateVariantCacheEntry(target, conditionalRequest,
- matchedEntry, backendResponse, requestDate, responseDate, matchingVariant.getCacheKey());
- } catch (final IOException ioe) {
- log.warn("Could not processChallenge cache entry", ioe);
- } finally {
- backendResponse.close();
- }
- return responseEntry;
- }
-
private void tryToUpdateVariantMap(
final HttpHost target,
- final ClassicHttpRequest request,
+ final HttpRequest request,
final Variant matchingVariant) {
try {
responseCache.reuseVariantEntryFor(target, request, matchingVariant);
@@ -760,73 +853,11 @@ public class CachingExec implements ExecChainHandler {
}
}
- private boolean shouldSendNotModifiedResponse(
- final ClassicHttpRequest request,
- final HttpCacheEntry responseEntry) {
+ private boolean shouldSendNotModifiedResponse(final HttpRequest request, final HttpCacheEntry responseEntry) {
return (suitabilityChecker.isConditional(request)
&& suitabilityChecker.allConditionalsMatch(request, responseEntry, new Date()));
}
- ClassicHttpResponse revalidateCacheEntry(
- final HttpHost target,
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final ExecChain chain,
- final HttpCacheEntry cacheEntry) throws IOException, HttpException {
-
- final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
- scope.originalRequest, cacheEntry);
-
- Date requestDate = getCurrentDate();
- ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
- try {
- Date responseDate = getCurrentDate();
-
- if (revalidationResponseIsTooOld(backendResponse, cacheEntry)) {
- backendResponse.close();
- final ClassicHttpRequest unconditional = conditionalRequestBuilder.buildUnconditionalRequest(
- scope.originalRequest);
- requestDate = getCurrentDate();
- backendResponse = chain.proceed(unconditional, scope);
- responseDate = getCurrentDate();
- }
-
- backendResponse.addHeader(HeaderConstants.VIA, generateViaHeader(backendResponse));
-
- final int statusCode = backendResponse.getCode();
- if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) {
- recordCacheUpdate(scope.clientContext);
- }
-
- if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
- final HttpCacheEntry updatedEntry = responseCache.updateCacheEntry(
- target, request, cacheEntry,
- backendResponse, requestDate, responseDate);
- if (suitabilityChecker.isConditional(request)
- && suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) {
- return convert(responseGenerator.generateNotModifiedResponse(updatedEntry));
- }
- return convert(responseGenerator.generateResponse(request, updatedEntry));
- }
-
- if (staleIfErrorAppliesTo(statusCode)
- && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
- && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
- try {
- final SimpleHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
- cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
- return convert(cachedResponse);
- } finally {
- backendResponse.close();
- }
- }
- return handleBackendResponse(target, conditionalRequest, scope, requestDate, responseDate, backendResponse);
- } catch (final IOException | RuntimeException ex) {
- backendResponse.close();
- throw ex;
- }
- }
-
private boolean staleIfErrorAppliesTo(final int statusCode) {
return statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR
|| statusCode == HttpStatus.SC_BAD_GATEWAY
@@ -855,72 +886,6 @@ public class CachingExec implements ExecChainHandler {
return buffer.length() < contentLength;
}
- public ClassicHttpResponse cacheAndReturnResponse(
- final HttpHost target,
- final HttpRequest request,
- final ClassicHttpResponse backendResponse,
- final Date requestSent,
- final Date responseReceived) throws IOException { final ByteArrayBuffer buf;
- final HttpEntity entity = backendResponse.getEntity();
- if (entity != null) {
- buf = new ByteArrayBuffer(1024);
- final InputStream instream = entity.getContent();
- final byte[] tmp = new byte[2048];
- long total = 0;
- int l;
- while ((l = instream.read(tmp)) != -1) {
- buf.append(tmp, 0, l);
- total += l;
- if (total > cacheConfig.getMaxObjectSize()) {
- backendResponse.setEntity(new CombinedEntity(entity, buf));
- return backendResponse;
- }
- }
- } else {
- buf = null;
- }
- if (buf != null && isIncompleteResponse(backendResponse, buf)) {
- final Header h = backendResponse.getFirstHeader(HttpHeaders.CONTENT_LENGTH);
- final ClassicHttpResponse error = new BasicClassicHttpResponse(HttpStatus.SC_BAD_GATEWAY, "Bad Gateway");
- final String msg = String.format("Received incomplete response " +
- "with Content-Length %s but actual body length %d",
- h != null ? h.getValue() : null, buf.length());
- error.setEntity(new StringEntity(msg, ContentType.TEXT_PLAIN));
- backendResponse.close();
- return error;
- }
- backendResponse.close();
- final HttpCacheEntry entry = responseCache.createCacheEntry(target, request, backendResponse, buf, requestSent, responseReceived);
- return convert(responseGenerator.generateResponse(request, entry));
- }
-
- ClassicHttpResponse handleBackendResponse(
- final HttpHost target,
- final ClassicHttpRequest request,
- final ExecChain.Scope scope,
- final Date requestDate,
- final Date responseDate,
- final ClassicHttpResponse backendResponse) throws IOException {
-
- log.trace("Handling Backend response");
- responseCompliance.ensureProtocolCompliance(scope.originalRequest, request, backendResponse);
-
- final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
- responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse);
- if (cacheable && !alreadyHaveNewerCacheEntry(target, request, backendResponse)) {
- storeRequestIfModifiedSinceFor304Response(request, backendResponse);
- return cacheAndReturnResponse(target, request, backendResponse, requestDate, responseDate);
- }
- if (!cacheable) {
- try {
- responseCache.flushCacheEntriesFor(target, request);
- } catch (final IOException ioe) {
- log.warn("Unable to flush invalid cache entries", ioe);
- }
- }
- return backendResponse;
- }
-
/**
* For 304 Not modified responses, adds a "Last-Modified" header with the
* value of the "If-Modified-Since" header passed in the request. This
@@ -939,8 +904,8 @@ public class CachingExec implements ExecChainHandler {
}
}
- private boolean alreadyHaveNewerCacheEntry(final HttpHost target, final ClassicHttpRequest request,
- final HttpResponse backendResponse) {
+ private boolean alreadyHaveNewerCacheEntry(
+ final HttpHost target, final HttpRequest request, final HttpResponse backendResponse) {
HttpCacheEntry existing = null;
try {
existing = responseCache.getCacheEntry(target, request);
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/212d7a2e/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/OptionsHttp11Response.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/OptionsHttp11Response.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/OptionsHttp11Response.java
deleted file mode 100644
index 9a42507..0000000
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/OptionsHttp11Response.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.impl.cache;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Locale;
-
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolException;
-import org.apache.hc.core5.http.ProtocolVersion;
-
-/**
- * @since 4.1
- */
-@Contract(threading = ThreadingBehavior.IMMUTABLE)
-final class OptionsHttp11Response implements ClassicHttpResponse, Serializable {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public int getCode() {
- return HttpStatus.SC_NOT_IMPLEMENTED;
- }
-
- @Override
- public void setCode(final int code) {
- }
-
- @Override
- public String getReasonPhrase() {
- return null;
- }
-
- @Override
- public void setVersion(final ProtocolVersion version) {
- }
-
- @Override
- public int containsHeaders(final String name) {
- return 0;
- }
-
- @Override
- public Header getSingleHeader(final String name) throws ProtocolException {
- return null;
- }
-
- @Override
- public void setReasonPhrase(final String reason) throws IllegalStateException {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public Locale getLocale() {
- return null;
- }
-
- @Override
- public void setLocale(final Locale loc) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public ProtocolVersion getVersion() {
- return HttpVersion.HTTP_1_1;
- }
-
- @Override
- public boolean containsHeader(final String name) {
- return false;
- }
-
- @Override
- public Header[] getHeaders(final String name) {
- return null;
- }
-
- @Override
- public Header getFirstHeader(final String name) {
- return null;
- }
-
- @Override
- public Header getLastHeader(final String name) {
- return null;
- }
-
- @Override
- public Header[] getAllHeaders() {
- return null;
- }
-
- @Override
- public void addHeader(final Header header) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void addHeader(final String name, final Object value) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void setHeader(final Header header) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void setHeader(final String name, final Object value) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void setHeaders(final Header[] headers) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void removeHeader(final Header header) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public void removeHeaders(final String name) {
- // No-op on purpose, this class is not going to be doing any work.
- }
-
- @Override
- public Iterator<Header> headerIterator() {
- return Collections.emptyIterator();
- }
-
- @Override
- public Iterator<Header> headerIterator(final String name) {
- return Collections.emptyIterator();
- }
-
- @Override
- public HttpEntity getEntity() {
- return null;
- }
-
- @Override
- public void setEntity(final HttpEntity entity) {
- }
-
- @Override
- public void close() throws IOException {
- }
-
-}