HTTPCLIENT-2277: Revision and optimization of cache key generation
This commit is contained in:
parent
0c79379827
commit
abbfd8202a
|
@ -28,6 +28,7 @@ package org.apache.hc.client5.http.impl.cache;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -90,11 +91,15 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry cacheEntry) {
|
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry cacheEntry) {
|
||||||
if (cacheEntry == null) {
|
final String root = cacheKeyGenerator.generateKey(host, request);
|
||||||
return cacheKeyGenerator.generateKey(host, request);
|
if (cacheEntry != null && cacheEntry.isVariantRoot()) {
|
||||||
} else {
|
final List<String> variantNames = CacheKeyGenerator.variantNames(cacheEntry);
|
||||||
return cacheKeyGenerator.generateKey(host, request, cacheEntry);
|
if (!variantNames.isEmpty()) {
|
||||||
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
|
return variantKey + root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -104,8 +109,8 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
LOG.debug("Flush cache entries: {}; {}", host, new RequestLine(request));
|
LOG.debug("Flush cache entries: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
if (!Method.isSafe(request.getMethod())) {
|
if (!Method.isSafe(request.getMethod())) {
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
return storage.removeEntry(cacheKey, new FutureCallback<Boolean>() {
|
return storage.removeEntry(rootKey, new FutureCallback<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(final Boolean result) {
|
public void completed(final Boolean result) {
|
||||||
|
@ -116,7 +121,7 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
public void failed(final Exception ex) {
|
public void failed(final Exception ex) {
|
||||||
if (ex instanceof ResourceIOException) {
|
if (ex instanceof ResourceIOException) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error removing cache entry with key {}", cacheKey);
|
LOG.warn("I/O error removing cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
callback.completed(Boolean.TRUE);
|
callback.completed(Boolean.TRUE);
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,18 +163,17 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
Cancellable storeInCache(
|
Cancellable storeInCache(
|
||||||
final HttpHost host,
|
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpResponse originResponse,
|
final HttpResponse originResponse,
|
||||||
final Instant requestSent,
|
final Instant requestSent,
|
||||||
final Instant responseReceived,
|
final Instant responseReceived,
|
||||||
final String cacheKey,
|
final String rootKey,
|
||||||
final HttpCacheEntry entry,
|
final HttpCacheEntry entry,
|
||||||
final FutureCallback<Boolean> callback) {
|
final FutureCallback<Boolean> callback) {
|
||||||
if (entry.hasVariants()) {
|
if (entry.hasVariants()) {
|
||||||
return storeVariantEntry(host, request, originResponse, requestSent, responseReceived, cacheKey, entry, callback);
|
return storeVariantEntry(request, originResponse, requestSent, responseReceived, rootKey, entry, callback);
|
||||||
} else {
|
} else {
|
||||||
return storeEntry(cacheKey, entry, callback);
|
return storeEntry(rootKey, entry, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,21 +209,21 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
Cancellable storeVariantEntry(
|
Cancellable storeVariantEntry(
|
||||||
final HttpHost host,
|
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpResponse originResponse,
|
final HttpResponse originResponse,
|
||||||
final Instant requestSent,
|
final Instant requestSent,
|
||||||
final Instant responseReceived,
|
final Instant responseReceived,
|
||||||
final String cacheKey,
|
final String rootKey,
|
||||||
final HttpCacheEntry entry,
|
final HttpCacheEntry entry,
|
||||||
final FutureCallback<Boolean> callback) {
|
final FutureCallback<Boolean> callback) {
|
||||||
final String variantKey = cacheKeyGenerator.generateVariantKey(request, entry);
|
final List<String> variantNames = CacheKeyGenerator.variantNames(entry);
|
||||||
final String variantCacheKey = cacheKeyGenerator.generateKey(host, request, entry);
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
|
final String variantCacheKey = variantKey + rootKey;
|
||||||
return storage.putEntry(variantCacheKey, entry, new FutureCallback<Boolean>() {
|
return storage.putEntry(variantCacheKey, entry, new FutureCallback<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(final Boolean result) {
|
public void completed(final Boolean result) {
|
||||||
storage.updateEntry(cacheKey,
|
storage.updateEntry(rootKey,
|
||||||
existing -> {
|
existing -> {
|
||||||
final Map<String,String> variantMap = existing != null ? new HashMap<>(existing.getVariantMap()) : new HashMap<>();
|
final Map<String,String> variantMap = existing != null ? new HashMap<>(existing.getVariantMap()) : new HashMap<>();
|
||||||
variantMap.put(variantKey, variantCacheKey);
|
variantMap.put(variantKey, variantCacheKey);
|
||||||
|
@ -236,11 +240,11 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
public void failed(final Exception ex) {
|
public void failed(final Exception ex) {
|
||||||
if (ex instanceof HttpCacheUpdateException) {
|
if (ex instanceof HttpCacheUpdateException) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("Cannot update cache entry with key {}", cacheKey);
|
LOG.warn("Cannot update cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
} else if (ex instanceof ResourceIOException) {
|
} else if (ex instanceof ResourceIOException) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error updating cache entry with key {}", cacheKey);
|
LOG.warn("I/O error updating cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback.failed(ex);
|
callback.failed(ex);
|
||||||
|
@ -287,8 +291,8 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Re-use variant entry: {}; {} / {}", host, new RequestLine(request), entry);
|
LOG.debug("Re-use variant entry: {}; {} / {}", host, new RequestLine(request), entry);
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
return storeVariantEntry(host, request, originResponse, requestSent, responseReceived, cacheKey, entry, callback);
|
return storeVariantEntry(request, originResponse, requestSent, responseReceived, rootKey, entry, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -303,19 +307,18 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Update cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Update cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
originResponse,
|
originResponse,
|
||||||
stale);
|
stale);
|
||||||
return storeInCache(
|
return storeInCache(
|
||||||
host,
|
|
||||||
request,
|
request,
|
||||||
originResponse,
|
originResponse,
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
cacheKey,
|
rootKey,
|
||||||
updatedEntry,
|
updatedEntry,
|
||||||
new FutureCallback<Boolean>() {
|
new FutureCallback<Boolean>() {
|
||||||
|
|
||||||
|
@ -349,13 +352,13 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Update variant cache entry: {}; {} / {}", host, new RequestLine(request), entry);
|
LOG.debug("Update variant cache entry: {}; {} / {}", host, new RequestLine(request), entry);
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
originResponse,
|
originResponse,
|
||||||
entry);
|
entry);
|
||||||
return storeEntry(cacheKey, updatedEntry, new FutureCallback<Boolean>() {
|
return storeEntry(rootKey, updatedEntry, new FutureCallback<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(final Boolean result) {
|
public void completed(final Boolean result) {
|
||||||
|
@ -387,17 +390,16 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Create cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Create cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
try {
|
try {
|
||||||
final HttpCacheEntry entry = cacheEntryFactory.create(requestSent, responseReceived, request, originResponse,
|
final HttpCacheEntry entry = cacheEntryFactory.create(requestSent, responseReceived, request, originResponse,
|
||||||
content != null ? resourceFactory.generate(request.getRequestUri(), content.array(), 0, content.length()) : null);
|
content != null ? resourceFactory.generate(request.getRequestUri(), content.array(), 0, content.length()) : null);
|
||||||
return storeInCache(
|
return storeInCache(
|
||||||
host,
|
|
||||||
request,
|
request,
|
||||||
originResponse,
|
originResponse,
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
cacheKey,
|
rootKey,
|
||||||
entry, new FutureCallback<Boolean>() {
|
entry, new FutureCallback<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -418,7 +420,7 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
});
|
});
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error creating cache entry with key {}", cacheKey);
|
LOG.warn("I/O error creating cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
callback.completed(cacheEntryFactory.create(
|
callback.completed(cacheEntryFactory.create(
|
||||||
requestSent,
|
requestSent,
|
||||||
|
@ -436,14 +438,15 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
LOG.debug("Get cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Get cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final ComplexCancellable complexCancellable = new ComplexCancellable();
|
final ComplexCancellable complexCancellable = new ComplexCancellable();
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
complexCancellable.setDependency(storage.getEntry(cacheKey, new FutureCallback<HttpCacheEntry>() {
|
complexCancellable.setDependency(storage.getEntry(rootKey, new FutureCallback<HttpCacheEntry>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(final HttpCacheEntry root) {
|
public void completed(final HttpCacheEntry root) {
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
if (root.isVariantRoot()) {
|
if (root.isVariantRoot()) {
|
||||||
final String variantKey = cacheKeyGenerator.generateVariantKey(request, root);
|
final List<String> variantNames = CacheKeyGenerator.variantNames(root);
|
||||||
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
final String variantCacheKey = root.getVariantMap().get(variantKey);
|
final String variantCacheKey = root.getVariantMap().get(variantKey);
|
||||||
if (variantCacheKey != null) {
|
if (variantCacheKey != null) {
|
||||||
complexCancellable.setDependency(storage.getEntry(
|
complexCancellable.setDependency(storage.getEntry(
|
||||||
|
@ -484,7 +487,7 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
public void failed(final Exception ex) {
|
public void failed(final Exception ex) {
|
||||||
if (ex instanceof ResourceIOException) {
|
if (ex instanceof ResourceIOException) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error retrieving cache entry with key {}", cacheKey);
|
LOG.warn("I/O error retrieving cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
callback.completed(null);
|
callback.completed(null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -508,9 +511,9 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
LOG.debug("Get variant cache entries: {}; {}", host, new RequestLine(request));
|
LOG.debug("Get variant cache entries: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final ComplexCancellable complexCancellable = new ComplexCancellable();
|
final ComplexCancellable complexCancellable = new ComplexCancellable();
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final Map<String, Variant> variants = new HashMap<>();
|
final Map<String, Variant> variants = new HashMap<>();
|
||||||
complexCancellable.setDependency(storage.getEntry(cacheKey, new FutureCallback<HttpCacheEntry>() {
|
complexCancellable.setDependency(storage.getEntry(rootKey, new FutureCallback<HttpCacheEntry>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(final HttpCacheEntry rootEntry) {
|
public void completed(final HttpCacheEntry rootEntry) {
|
||||||
|
@ -560,7 +563,7 @@ class BasicHttpAsyncCache implements HttpAsyncCache {
|
||||||
public void failed(final Exception ex) {
|
public void failed(final Exception ex) {
|
||||||
if (ex instanceof ResourceIOException) {
|
if (ex instanceof ResourceIOException) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error retrieving cache entry with key {}", cacheKey);
|
LOG.warn("I/O error retrieving cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
callback.completed(variants);
|
callback.completed(variants);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.apache.hc.client5.http.impl.cache;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
||||||
|
@ -93,11 +94,15 @@ class BasicHttpCache implements HttpCache {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry cacheEntry) {
|
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry cacheEntry) {
|
||||||
if (cacheEntry == null) {
|
final String root = cacheKeyGenerator.generateKey(host, request);
|
||||||
return cacheKeyGenerator.generateKey(host, request);
|
if (cacheEntry != null && cacheEntry.isVariantRoot()) {
|
||||||
} else {
|
final List<String> variantNames = CacheKeyGenerator.variantNames(cacheEntry);
|
||||||
return cacheKeyGenerator.generateKey(host, request, cacheEntry);
|
if (!variantNames.isEmpty()) {
|
||||||
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
|
return variantKey + root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,12 +111,12 @@ class BasicHttpCache implements HttpCache {
|
||||||
LOG.debug("Flush cache entries: {}; {}", host, new RequestLine(request));
|
LOG.debug("Flush cache entries: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
if (!Method.isSafe(request.getMethod())) {
|
if (!Method.isSafe(request.getMethod())) {
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
try {
|
try {
|
||||||
storage.removeEntry(cacheKey);
|
storage.removeEntry(rootKey);
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error removing cache entry with key {}", cacheKey);
|
LOG.warn("I/O error removing cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,17 +141,16 @@ class BasicHttpCache implements HttpCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeInCache(
|
void storeInCache(
|
||||||
final HttpHost host,
|
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpResponse originResponse,
|
final HttpResponse originResponse,
|
||||||
final Instant requestSent,
|
final Instant requestSent,
|
||||||
final Instant responseReceived,
|
final Instant responseReceived,
|
||||||
final String cacheKey,
|
final String rootKey,
|
||||||
final HttpCacheEntry entry) {
|
final HttpCacheEntry entry) {
|
||||||
if (entry.hasVariants()) {
|
if (entry.hasVariants()) {
|
||||||
storeVariantEntry(host, request, originResponse, requestSent, responseReceived, cacheKey, entry);
|
storeVariantEntry(request, originResponse, requestSent, responseReceived, rootKey, entry);
|
||||||
} else {
|
} else {
|
||||||
storeEntry(cacheKey, entry);
|
storeEntry(rootKey, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,29 +165,29 @@ class BasicHttpCache implements HttpCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeVariantEntry(
|
void storeVariantEntry(
|
||||||
final HttpHost host,
|
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpResponse originResponse,
|
final HttpResponse originResponse,
|
||||||
final Instant requestSent,
|
final Instant requestSent,
|
||||||
final Instant responseReceived,
|
final Instant responseReceived,
|
||||||
final String cacheKey,
|
final String rootKey,
|
||||||
final HttpCacheEntry entry) {
|
final HttpCacheEntry entry) {
|
||||||
final String variantKey = cacheKeyGenerator.generateVariantKey(request, entry);
|
final List<String> variantNames = CacheKeyGenerator.variantNames(entry);
|
||||||
final String variantCacheKey = cacheKeyGenerator.generateKey(host, request, entry);
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
|
final String variantCacheKey = variantKey + request;
|
||||||
storeEntry(variantCacheKey, entry);
|
storeEntry(variantCacheKey, entry);
|
||||||
try {
|
try {
|
||||||
storage.updateEntry(cacheKey, existing -> {
|
storage.updateEntry(rootKey, existing -> {
|
||||||
final Map<String,String> variantMap = existing != null ? new HashMap<>(existing.getVariantMap()) : new HashMap<>();
|
final Map<String,String> variantMap = existing != null ? new HashMap<>(existing.getVariantMap()) : new HashMap<>();
|
||||||
variantMap.put(variantKey, variantCacheKey);
|
variantMap.put(variantKey, variantCacheKey);
|
||||||
return cacheEntryFactory.createRoot(requestSent, responseReceived, request, originResponse, variantMap);
|
return cacheEntryFactory.createRoot(requestSent, responseReceived, request, originResponse, variantMap);
|
||||||
});
|
});
|
||||||
} catch (final HttpCacheUpdateException ex) {
|
} catch (final HttpCacheUpdateException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("Cannot update cache entry with key {}", cacheKey);
|
LOG.warn("Cannot update cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error updating cache entry with key {}", cacheKey);
|
LOG.warn("I/O error updating cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,8 +203,8 @@ class BasicHttpCache implements HttpCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Re-use variant entry: {}; {} / {}", host, new RequestLine(request), entry);
|
LOG.debug("Re-use variant entry: {}; {} / {}", host, new RequestLine(request), entry);
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
storeVariantEntry(host, request, originResponse, requestSent, responseReceived, cacheKey, entry);
|
storeVariantEntry(request, originResponse, requestSent, responseReceived, rootKey, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -214,13 +218,13 @@ class BasicHttpCache implements HttpCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Update cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Update cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
originResponse,
|
originResponse,
|
||||||
stale);
|
stale);
|
||||||
storeInCache(host, request, originResponse, requestSent, responseReceived, cacheKey, updatedEntry);
|
storeInCache(request, originResponse, requestSent, responseReceived, rootKey, updatedEntry);
|
||||||
return updatedEntry;
|
return updatedEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,13 +239,13 @@ class BasicHttpCache implements HttpCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Update variant cache entry: {}; {} / {}", host, new RequestLine(request), entry);
|
LOG.debug("Update variant cache entry: {}; {} / {}", host, new RequestLine(request), entry);
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
final HttpCacheEntry updatedEntry = cacheEntryFactory.createUpdated(
|
||||||
requestSent,
|
requestSent,
|
||||||
responseReceived,
|
responseReceived,
|
||||||
originResponse,
|
originResponse,
|
||||||
entry);
|
entry);
|
||||||
storeEntry(cacheKey, updatedEntry);
|
storeEntry(rootKey, updatedEntry);
|
||||||
return updatedEntry;
|
return updatedEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,15 +260,15 @@ class BasicHttpCache implements HttpCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Create cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Create cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
try {
|
try {
|
||||||
final HttpCacheEntry entry = cacheEntryFactory.create(requestSent, responseReceived, request, originResponse,
|
final HttpCacheEntry entry = cacheEntryFactory.create(requestSent, responseReceived, request, originResponse,
|
||||||
content != null ? resourceFactory.generate(request.getRequestUri(), content.array(), 0, content.length()) : null);
|
content != null ? resourceFactory.generate(request.getRequestUri(), content.array(), 0, content.length()) : null);
|
||||||
storeInCache(host, request, originResponse, requestSent, responseReceived, cacheKey, entry);
|
storeInCache(request, originResponse, requestSent, responseReceived, rootKey, entry);
|
||||||
return entry;
|
return entry;
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error creating cache entry with key {}", cacheKey);
|
LOG.warn("I/O error creating cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
return cacheEntryFactory.create(
|
return cacheEntryFactory.create(
|
||||||
requestSent,
|
requestSent,
|
||||||
|
@ -280,13 +284,13 @@ class BasicHttpCache implements HttpCache {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Get cache entry: {}; {}", host, new RequestLine(request));
|
LOG.debug("Get cache entry: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry root;
|
final HttpCacheEntry root;
|
||||||
try {
|
try {
|
||||||
root = storage.getEntry(cacheKey);
|
root = storage.getEntry(rootKey);
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error retrieving cache entry with key {}", cacheKey);
|
LOG.warn("I/O error retrieving cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +298,8 @@ class BasicHttpCache implements HttpCache {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (root.isVariantRoot()) {
|
if (root.isVariantRoot()) {
|
||||||
final String variantKey = cacheKeyGenerator.generateVariantKey(request, root);
|
final List<String> variantNames = CacheKeyGenerator.variantNames(root);
|
||||||
|
final String variantKey = cacheKeyGenerator.generateVariantKey(request, variantNames);
|
||||||
final String variantCacheKey = root.getVariantMap().get(variantKey);
|
final String variantCacheKey = root.getVariantMap().get(variantKey);
|
||||||
if (variantCacheKey != null) {
|
if (variantCacheKey != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -317,13 +322,13 @@ class BasicHttpCache implements HttpCache {
|
||||||
LOG.debug("Get variant cache entries: {}; {}", host, new RequestLine(request));
|
LOG.debug("Get variant cache entries: {}; {}", host, new RequestLine(request));
|
||||||
}
|
}
|
||||||
final Map<String,Variant> variants = new HashMap<>();
|
final Map<String,Variant> variants = new HashMap<>();
|
||||||
final String cacheKey = cacheKeyGenerator.generateKey(host, request);
|
final String rootKey = cacheKeyGenerator.generateKey(host, request);
|
||||||
final HttpCacheEntry root;
|
final HttpCacheEntry root;
|
||||||
try {
|
try {
|
||||||
root = storage.getEntry(cacheKey);
|
root = storage.getEntry(rootKey);
|
||||||
} catch (final ResourceIOException ex) {
|
} catch (final ResourceIOException ex) {
|
||||||
if (LOG.isWarnEnabled()) {
|
if (LOG.isWarnEnabled()) {
|
||||||
LOG.warn("I/O error retrieving cache entry with key {}", cacheKey);
|
LOG.warn("I/O error retrieving cache entry with key {}", rootKey);
|
||||||
}
|
}
|
||||||
return variants;
|
return variants;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,26 +26,27 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http.impl.cache;
|
package org.apache.hc.client5.http.impl.cache;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.function.Resolver;
|
import org.apache.hc.core5.function.Resolver;
|
||||||
import org.apache.hc.core5.http.Header;
|
import org.apache.hc.core5.http.Header;
|
||||||
import org.apache.hc.core5.http.HeaderElement;
|
|
||||||
import org.apache.hc.core5.http.HttpHeaders;
|
import org.apache.hc.core5.http.HttpHeaders;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpRequest;
|
import org.apache.hc.core5.http.HttpRequest;
|
||||||
import org.apache.hc.core5.http.message.MessageSupport;
|
import org.apache.hc.core5.http.MessageHeaders;
|
||||||
|
import org.apache.hc.core5.net.PercentCodec;
|
||||||
|
import org.apache.hc.core5.util.Args;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
|
@ -78,7 +79,7 @@ public class CacheKeyGenerator implements Resolver<URI, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes a key for the given {@link HttpHost} and {@link HttpRequest}
|
* Computes a root key for the given {@link HttpHost} and {@link HttpRequest}
|
||||||
* that can be used as a unique identifier for cached resources.
|
* that can be used as a unique identifier for cached resources.
|
||||||
*
|
*
|
||||||
* @param host The host for this request
|
* @param host The host for this request
|
||||||
|
@ -94,18 +95,64 @@ public class CacheKeyGenerator implements Resolver<URI, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFullHeaderValue(final Header[] headers) {
|
/**
|
||||||
if (headers == null) {
|
* Returns all variant names contained in {@literal VARY} headers of the given message.
|
||||||
return "";
|
*
|
||||||
|
* @since 5.3
|
||||||
|
*/
|
||||||
|
public static List<String> variantNames(final MessageHeaders message) {
|
||||||
|
if (message == null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
final StringBuilder buf = new StringBuilder();
|
final List<String> names = new ArrayList<>();
|
||||||
for (int i = 0; i < headers.length; i++) {
|
for (final Iterator<Header> it = message.headerIterator(HttpHeaders.VARY); it.hasNext(); ) {
|
||||||
final Header hdr = headers[i];
|
final Header header = it.next();
|
||||||
if (i > 0) {
|
CacheSupport.parseTokens(header, names::add);
|
||||||
buf.append(", ");
|
|
||||||
}
|
|
||||||
buf.append(hdr.getValue().trim());
|
|
||||||
}
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a "variant key" for the given request and the given variants.
|
||||||
|
* @param request originating request
|
||||||
|
* @param variantNames variant names
|
||||||
|
* @return variant key
|
||||||
|
*
|
||||||
|
* @since 5.3
|
||||||
|
*/
|
||||||
|
public String generateVariantKey(final HttpRequest request, final Collection<String> variantNames) {
|
||||||
|
Args.notNull(variantNames, "Variant names");
|
||||||
|
final StringBuilder buf = new StringBuilder("{");
|
||||||
|
final AtomicBoolean firstHeader = new AtomicBoolean();
|
||||||
|
variantNames.stream()
|
||||||
|
.map(h -> h.toLowerCase(Locale.ROOT))
|
||||||
|
.sorted()
|
||||||
|
.distinct()
|
||||||
|
.forEach(h -> {
|
||||||
|
if (!firstHeader.compareAndSet(false, true)) {
|
||||||
|
buf.append("&");
|
||||||
|
}
|
||||||
|
buf.append(PercentCodec.encode(h, StandardCharsets.UTF_8)).append("=");
|
||||||
|
final List<String> tokens = new ArrayList<>();
|
||||||
|
final Iterator<Header> headerIterator = request.headerIterator(h);
|
||||||
|
while (headerIterator.hasNext()) {
|
||||||
|
final Header header = headerIterator.next();
|
||||||
|
CacheSupport.parseTokens(header, tokens::add);
|
||||||
|
}
|
||||||
|
final AtomicBoolean firstToken = new AtomicBoolean();
|
||||||
|
tokens.stream()
|
||||||
|
.filter(t -> !t.isEmpty())
|
||||||
|
.map(t -> t.toLowerCase(Locale.ROOT))
|
||||||
|
.sorted()
|
||||||
|
.distinct()
|
||||||
|
.forEach(t -> {
|
||||||
|
if (!firstToken.compareAndSet(false, true)) {
|
||||||
|
buf.append(",");
|
||||||
|
}
|
||||||
|
buf.append(PercentCodec.encode(t, StandardCharsets.UTF_8));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
buf.append("}");
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,12 +165,18 @@ public class CacheKeyGenerator implements Resolver<URI, String> {
|
||||||
* @param request the {@link HttpRequest}
|
* @param request the {@link HttpRequest}
|
||||||
* @param entry the parent entry used to track the variants
|
* @param entry the parent entry used to track the variants
|
||||||
* @return cache key
|
* @return cache key
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #generateKey(HttpHost, HttpRequest)} or {@link #generateVariantKey(HttpRequest, Collection)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry entry) {
|
public String generateKey(final HttpHost host, final HttpRequest request, final HttpCacheEntry entry) {
|
||||||
if (!entry.hasVariants()) {
|
final String rootKey = generateKey(host, request);
|
||||||
return generateKey(host, request);
|
final List<String> variantNames = variantNames(entry);
|
||||||
|
if (variantNames.isEmpty()) {
|
||||||
|
return rootKey;
|
||||||
|
} else {
|
||||||
|
return generateVariantKey(request, variantNames) + rootKey;
|
||||||
}
|
}
|
||||||
return generateVariantKey(request, entry) + generateKey(host, request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,35 +187,12 @@ public class CacheKeyGenerator implements Resolver<URI, String> {
|
||||||
* @param req originating request
|
* @param req originating request
|
||||||
* @param entry cache entry in question that has variants
|
* @param entry cache entry in question that has variants
|
||||||
* @return variant key
|
* @return variant key
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #generateVariantKey(HttpRequest, Collection)}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String generateVariantKey(final HttpRequest req, final HttpCacheEntry entry) {
|
public String generateVariantKey(final HttpRequest req, final HttpCacheEntry entry) {
|
||||||
final List<String> variantHeaderNames = new ArrayList<>();
|
return generateVariantKey(req, variantNames(entry));
|
||||||
final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HttpHeaders.VARY);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
final HeaderElement elt = it.next();
|
|
||||||
variantHeaderNames.add(elt.getName());
|
|
||||||
}
|
|
||||||
Collections.sort(variantHeaderNames);
|
|
||||||
|
|
||||||
final StringBuilder buf;
|
|
||||||
try {
|
|
||||||
buf = new StringBuilder("{");
|
|
||||||
boolean first = true;
|
|
||||||
for (final String headerName : variantHeaderNames) {
|
|
||||||
if (!first) {
|
|
||||||
buf.append("&");
|
|
||||||
}
|
|
||||||
buf.append(URLEncoder.encode(headerName, StandardCharsets.UTF_8.name()));
|
|
||||||
buf.append("=");
|
|
||||||
buf.append(URLEncoder.encode(getFullHeaderValue(req.getHeaders(headerName)),
|
|
||||||
StandardCharsets.UTF_8.name()));
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
buf.append("}");
|
|
||||||
} catch (final UnsupportedEncodingException uee) {
|
|
||||||
throw new RuntimeException("couldn't encode to UTF-8", uee);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class TestBasicHttpCache {
|
||||||
|
|
||||||
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, req);
|
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, req);
|
||||||
|
|
||||||
impl.storeInCache(host, req, resp, Instant.now(), Instant.now(), key, entry);
|
impl.storeInCache(req, resp, Instant.now(), Instant.now(), key, entry);
|
||||||
assertSame(entry, backing.map.get(key));
|
assertSame(entry, backing.map.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,18 +26,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http.impl.cache;
|
package org.apache.hc.client5.http.impl.cache;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import java.util.Arrays;
|
||||||
import static org.mockito.Mockito.verify;
|
import java.util.Collections;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
|
||||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.hc.core5.http.Header;
|
import org.apache.hc.core5.http.HttpHeaders;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpRequest;
|
import org.apache.hc.core5.http.HttpRequest;
|
||||||
import org.apache.hc.core5.http.message.BasicHeader;
|
|
||||||
import org.apache.hc.core5.http.message.BasicHeaderIterator;
|
|
||||||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||||
|
import org.apache.hc.core5.http.support.BasicRequestBuilder;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -45,20 +42,12 @@ import org.junit.jupiter.api.Test;
|
||||||
@SuppressWarnings({"boxing","static-access"}) // this is test code
|
@SuppressWarnings({"boxing","static-access"}) // this is test code
|
||||||
public class TestCacheKeyGenerator {
|
public class TestCacheKeyGenerator {
|
||||||
|
|
||||||
private static final BasicHttpRequest REQUEST_FULL_EPISODES = new BasicHttpRequest("GET",
|
|
||||||
"/full_episodes");
|
|
||||||
private static final BasicHttpRequest REQUEST_ROOT = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
private CacheKeyGenerator extractor;
|
private CacheKeyGenerator extractor;
|
||||||
private HttpHost defaultHost;
|
private HttpHost defaultHost;
|
||||||
private HttpCacheEntry mockEntry;
|
|
||||||
private HttpRequest mockRequest;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
defaultHost = new HttpHost("foo.example.com");
|
defaultHost = new HttpHost("foo.example.com");
|
||||||
mockEntry = mock(HttpCacheEntry.class);
|
|
||||||
mockRequest = mock(HttpRequest.class);
|
|
||||||
extractor = CacheKeyGenerator.INSTANCE;
|
extractor = CacheKeyGenerator.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,203 +60,46 @@ public class TestCacheKeyGenerator {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetURIWithDefaultPortAndScheme() {
|
public void testGetURIWithDefaultPortAndScheme() {
|
||||||
Assertions.assertEquals("http://www.comcast.net:80/", extractor.generateKey(new HttpHost(
|
Assertions.assertEquals("http://www.comcast.net:80/", extractor.generateKey(
|
||||||
"www.comcast.net"), REQUEST_ROOT));
|
new HttpHost("www.comcast.net"),
|
||||||
|
new BasicHttpRequest("GET", "/")));
|
||||||
|
|
||||||
Assertions.assertEquals("http://www.fancast.com:80/full_episodes", extractor.generateKey(new HttpHost(
|
Assertions.assertEquals("http://www.fancast.com:80/full_episodes", extractor.generateKey(
|
||||||
"www.fancast.com"), REQUEST_FULL_EPISODES));
|
new HttpHost("www.fancast.com"),
|
||||||
|
new BasicHttpRequest("GET", "/full_episodes")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetURIWithDifferentScheme() {
|
public void testGetURIWithDifferentScheme() {
|
||||||
Assertions.assertEquals("https://www.comcast.net:443/", extractor.generateKey(
|
Assertions.assertEquals("https://www.comcast.net:443/", extractor.generateKey(
|
||||||
new HttpHost("https", "www.comcast.net", -1), REQUEST_ROOT));
|
new HttpHost("https", "www.comcast.net", -1),
|
||||||
|
new BasicHttpRequest("GET", "/")));
|
||||||
|
|
||||||
Assertions.assertEquals("myhttp://www.fancast.com/full_episodes", extractor.generateKey(
|
Assertions.assertEquals("myhttp://www.fancast.com/full_episodes", extractor.generateKey(
|
||||||
new HttpHost("myhttp", "www.fancast.com", -1), REQUEST_FULL_EPISODES));
|
new HttpHost("myhttp", "www.fancast.com", -1),
|
||||||
|
new BasicHttpRequest("GET", "/full_episodes")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetURIWithDifferentPort() {
|
public void testGetURIWithDifferentPort() {
|
||||||
Assertions.assertEquals("http://www.comcast.net:8080/", extractor.generateKey(new HttpHost(
|
Assertions.assertEquals("http://www.comcast.net:8080/", extractor.generateKey(
|
||||||
"www.comcast.net", 8080), REQUEST_ROOT));
|
new HttpHost("www.comcast.net", 8080),
|
||||||
|
new BasicHttpRequest("GET", "/")));
|
||||||
|
|
||||||
Assertions.assertEquals("http://www.fancast.com:9999/full_episodes", extractor.generateKey(
|
Assertions.assertEquals("http://www.fancast.com:9999/full_episodes", extractor.generateKey(
|
||||||
new HttpHost("www.fancast.com", 9999), REQUEST_FULL_EPISODES));
|
new HttpHost("www.fancast.com", 9999),
|
||||||
|
new BasicHttpRequest("GET", "/full_episodes")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetURIWithDifferentPortAndScheme() {
|
public void testGetURIWithDifferentPortAndScheme() {
|
||||||
Assertions.assertEquals("https://www.comcast.net:8080/", extractor.generateKey(
|
Assertions.assertEquals("https://www.comcast.net:8080/", extractor.generateKey(
|
||||||
new HttpHost("https", "www.comcast.net", 8080), REQUEST_ROOT));
|
new HttpHost("https", "www.comcast.net", 8080),
|
||||||
|
new BasicHttpRequest("GET", "/")));
|
||||||
|
|
||||||
Assertions.assertEquals("myhttp://www.fancast.com:9999/full_episodes", extractor.generateKey(
|
Assertions.assertEquals("myhttp://www.fancast.com:9999/full_episodes", extractor.generateKey(
|
||||||
new HttpHost("myhttp", "www.fancast.com", 9999), REQUEST_FULL_EPISODES));
|
new HttpHost("myhttp", "www.fancast.com", 9999),
|
||||||
}
|
new BasicHttpRequest("GET", "/full_episodes")));
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetURIWithQueryParameters() {
|
|
||||||
Assertions.assertEquals("http://www.comcast.net:80/?foo=bar", extractor.generateKey(
|
|
||||||
new HttpHost("http", "www.comcast.net", -1), new BasicHttpRequest("GET", "/?foo=bar")));
|
|
||||||
Assertions.assertEquals("http://www.fancast.com:80/full_episodes?foo=bar", extractor.generateKey(
|
|
||||||
new HttpHost("http", "www.fancast.com", -1), new BasicHttpRequest("GET",
|
|
||||||
"/full_episodes?foo=bar")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIWithNoVaryHeaderReturnsNormalURI() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(false);
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
Assertions.assertSame(theURI, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIWithSingleValueVaryHeaderPrepends() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
final Header[] varyHeaders = { new BasicHeader("Vary", "Accept-Encoding") };
|
|
||||||
final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
|
|
||||||
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(true);
|
|
||||||
when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
|
|
||||||
when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
verify(mockEntry).headerIterator("Vary");
|
|
||||||
verify(mockRequest).getHeaders("Accept-Encoding");
|
|
||||||
Assertions.assertEquals("{Accept-Encoding=gzip}" + theURI, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIWithMissingRequestHeader() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
final Header[] noHeaders = new Header[0];
|
|
||||||
final Header[] varyHeaders = { new BasicHeader("Vary", "Accept-Encoding") };
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(true);
|
|
||||||
when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
|
|
||||||
when(mockRequest.getHeaders("Accept-Encoding"))
|
|
||||||
.thenReturn(noHeaders);
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
verify(mockEntry).headerIterator("Vary");
|
|
||||||
verify(mockRequest).getHeaders("Accept-Encoding");
|
|
||||||
Assertions.assertEquals("{Accept-Encoding=}" + theURI, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIAlphabetizesWithMultipleVaryingHeaders() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent, Accept-Encoding") };
|
|
||||||
final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
|
|
||||||
final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(true);
|
|
||||||
when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
|
|
||||||
when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
|
|
||||||
when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
verify(mockEntry).headerIterator("Vary");
|
|
||||||
verify(mockRequest).getHeaders("Accept-Encoding");
|
|
||||||
verify(mockRequest).getHeaders("User-Agent");
|
|
||||||
Assertions.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIHandlesMultipleVaryHeaders() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent"),
|
|
||||||
new BasicHeader("Vary", "Accept-Encoding") };
|
|
||||||
final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
|
|
||||||
final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(true);
|
|
||||||
when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
|
|
||||||
when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
|
|
||||||
when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
verify(mockEntry).headerIterator("Vary");
|
|
||||||
verify(mockRequest).getHeaders("Accept-Encoding");
|
|
||||||
verify(mockRequest).getHeaders("User-Agent");
|
|
||||||
Assertions.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetVariantURIHandlesMultipleLineRequestHeaders() {
|
|
||||||
final String theURI = "theURI";
|
|
||||||
final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent, Accept-Encoding") };
|
|
||||||
final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip"),
|
|
||||||
new BasicHeader("Accept-Encoding", "deflate") };
|
|
||||||
final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
|
|
||||||
extractor = new CacheKeyGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateKey(final HttpHost h, final HttpRequest request) {
|
|
||||||
Assertions.assertSame(defaultHost, h);
|
|
||||||
Assertions.assertSame(mockRequest, request);
|
|
||||||
return theURI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
when(mockEntry.hasVariants()).thenReturn(true);
|
|
||||||
when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
|
|
||||||
when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
|
|
||||||
when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
|
|
||||||
|
|
||||||
final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
|
|
||||||
|
|
||||||
verify(mockEntry).hasVariants();
|
|
||||||
verify(mockEntry).headerIterator("Vary");
|
|
||||||
verify(mockRequest).getHeaders("Accept-Encoding");
|
|
||||||
verify(mockRequest).getHeaders("User-Agent");
|
|
||||||
Assertions.assertEquals("{Accept-Encoding=gzip%2C+deflate&User-Agent=browser}" + theURI, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -417,4 +249,66 @@ public class TestCacheKeyGenerator {
|
||||||
final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/home%20folder.html");
|
final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/home%20folder.html");
|
||||||
Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
|
Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetURIWithQueryParameters() {
|
||||||
|
Assertions.assertEquals("http://www.comcast.net:80/?foo=bar", extractor.generateKey(
|
||||||
|
new HttpHost("http", "www.comcast.net", -1), new BasicHttpRequest("GET", "/?foo=bar")));
|
||||||
|
Assertions.assertEquals("http://www.fancast.com:80/full_episodes?foo=bar", extractor.generateKey(
|
||||||
|
new HttpHost("http", "www.fancast.com", -1), new BasicHttpRequest("GET",
|
||||||
|
"/full_episodes?foo=bar")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetVariantKey() {
|
||||||
|
final HttpRequest request = BasicRequestBuilder.get("/blah")
|
||||||
|
.addHeader(HttpHeaders.USER_AGENT, "some-agent")
|
||||||
|
.addHeader(HttpHeaders.ACCEPT_ENCODING, "gzip,zip")
|
||||||
|
.addHeader(HttpHeaders.ACCEPT_ENCODING, "deflate")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assertions.assertEquals("{user-agent=some-agent}",
|
||||||
|
extractor.generateVariantKey(request, Collections.singletonList(HttpHeaders.USER_AGENT)));
|
||||||
|
Assertions.assertEquals("{accept-encoding=deflate,gzip,zip}",
|
||||||
|
extractor.generateVariantKey(request, Collections.singletonList(HttpHeaders.ACCEPT_ENCODING)));
|
||||||
|
Assertions.assertEquals("{accept-encoding=deflate,gzip,zip&user-agent=some-agent}",
|
||||||
|
extractor.generateVariantKey(request, Arrays.asList(HttpHeaders.USER_AGENT, HttpHeaders.ACCEPT_ENCODING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetVariantKeyInputNormalization() {
|
||||||
|
final HttpRequest request = BasicRequestBuilder.get("/blah")
|
||||||
|
.addHeader(HttpHeaders.USER_AGENT, "Some-Agent")
|
||||||
|
.addHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, ZIP,,")
|
||||||
|
.addHeader(HttpHeaders.ACCEPT_ENCODING, "deflate")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assertions.assertEquals("{user-agent=some-agent}",
|
||||||
|
extractor.generateVariantKey(request, Collections.singletonList(HttpHeaders.USER_AGENT)));
|
||||||
|
Assertions.assertEquals("{accept-encoding=deflate,gzip,zip}",
|
||||||
|
extractor.generateVariantKey(request, Collections.singletonList(HttpHeaders.ACCEPT_ENCODING)));
|
||||||
|
Assertions.assertEquals("{accept-encoding=deflate,gzip,zip&user-agent=some-agent}",
|
||||||
|
extractor.generateVariantKey(request, Arrays.asList(HttpHeaders.USER_AGENT, HttpHeaders.ACCEPT_ENCODING)));
|
||||||
|
Assertions.assertEquals("{accept-encoding=deflate,gzip,zip&user-agent=some-agent}",
|
||||||
|
extractor.generateVariantKey(request, Arrays.asList(HttpHeaders.USER_AGENT, HttpHeaders.ACCEPT_ENCODING, "USER-AGENT", HttpHeaders.ACCEPT_ENCODING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetVariantKeyInputNormalizationReservedChars() {
|
||||||
|
final HttpRequest request = BasicRequestBuilder.get("/blah")
|
||||||
|
.addHeader(HttpHeaders.USER_AGENT, "*===some-agent===*")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assertions.assertEquals("{user-agent=%2A%3D%3D%3Dsome-agent%3D%3D%3D%2A}",
|
||||||
|
extractor.generateVariantKey(request, Collections.singletonList(HttpHeaders.USER_AGENT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetVariantKeyInputNoMatchingHeaders() {
|
||||||
|
final HttpRequest request = BasicRequestBuilder.get("/blah")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assertions.assertEquals("{accept-encoding=&user-agent=}",
|
||||||
|
extractor.generateVariantKey(request, Arrays.asList(HttpHeaders.ACCEPT_ENCODING, HttpHeaders.USER_AGENT)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue