Skip to content

Commit e6eb8a8

Browse files
committed
Added support for request body to the cache key generator
1 parent 3a46ebc commit e6eb8a8

7 files changed

Lines changed: 104 additions & 67 deletions

File tree

httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ public void completed(final CacheMatch result) {
302302
final CacheHit root = result != null ? result.root : null;
303303
if (hit == null) {
304304
if (requestCollapsingEnabled && root == null && !requestCacheControl.isOnlyIfCached()) {
305-
final String cacheKey = CacheKeyGenerator.INSTANCE.generateKey(target, cacheRequest);
305+
final String cacheKey = CacheKeyGenerator.INSTANCE.generateKey(target, cacheRequest, SimpleHttpRequest::getBodyText);
306306
final CacheRequestCollapser.Token token = collapser.enter(cacheKey);
307307
if (token.isLeader()) {
308308
handleCacheMiss(requestCacheControl, null, target, cacheRequest, scope, chain, new AsyncExecCallback() {

httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpAsyncCache.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public BasicHttpAsyncCache(final ResourceFactory resourceFactory, final HttpAsyn
9494

9595
@Override
9696
public Cancellable match(final HttpHost host, final SimpleHttpRequest request, final FutureCallback<CacheMatch> callback) {
97-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
97+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
9898
if (LOG.isDebugEnabled()) {
9999
LOG.debug("Get cache entry: {}", rootKey);
100100
}
@@ -390,7 +390,7 @@ public Cancellable store(
390390
final Instant requestSent,
391391
final Instant responseReceived,
392392
final FutureCallback<CacheHit> callback) {
393-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
393+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
394394
if (LOG.isDebugEnabled()) {
395395
LOG.debug("Create cache entry: {}", rootKey);
396396
}
@@ -465,7 +465,7 @@ public Cancellable storeFromNegotiated(
465465

466466
storeInternal(negotiated.getEntryKey(), updatedEntry, null);
467467

468-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
468+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
469469
final HttpCacheEntry copy = cacheEntryFactory.copy(updatedEntry);
470470
final String variantKey = cacheKeyGenerator.generateVariantKey(request, copy);
471471
return store(rootKey, variantKey, copy, callback);
@@ -551,7 +551,7 @@ public Cancellable evictInvalidatedEntries(
551551
final int status = response.getCode();
552552
if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_CLIENT_ERROR &&
553553
!Method.isSafe(request.getMethod())) {
554-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
554+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
555555
evict(rootKey);
556556
final URI requestUri = CacheSupport.requestUriNormalizedOrNull(host, request);
557557
if (requestUri != null) {

httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCache.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private void removeInternal(final String cacheKey) {
140140

141141
@Override
142142
public CacheMatch match(final HttpHost host, final SimpleHttpRequest request) {
143-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
143+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
144144
if (LOG.isDebugEnabled()) {
145145
LOG.debug("Get cache root entry: {}", rootKey);
146146
}
@@ -223,7 +223,7 @@ public CacheHit store(
223223
final ByteArrayBuffer content,
224224
final Instant requestSent,
225225
final Instant responseReceived) {
226-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
226+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
227227
if (LOG.isDebugEnabled()) {
228228
LOG.debug("Create cache entry: {}", rootKey);
229229
}
@@ -294,7 +294,7 @@ public CacheHit storeFromNegotiated(
294294
negotiated.entry);
295295
storeInternal(negotiated.getEntryKey(), updatedEntry);
296296

297-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
297+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
298298
final HttpCacheEntry copy = cacheEntryFactory.copy(updatedEntry);
299299
final String variantKey = cacheKeyGenerator.generateVariantKey(request, copy);
300300
return store(rootKey, variantKey, copy);
@@ -347,7 +347,7 @@ public void evictInvalidatedEntries(final HttpHost host, final SimpleHttpRequest
347347
final int status = response.getCode();
348348
if (status >= HttpStatus.SC_SUCCESS && status < HttpStatus.SC_CLIENT_ERROR &&
349349
!Method.isSafe(request.getMethod())) {
350-
final String rootKey = cacheKeyGenerator.generateKey(host, request);
350+
final String rootKey = cacheKeyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
351351
evict(rootKey);
352352
final URI requestUri = CacheSupport.requestUriNormalizedOrNull(host, request);
353353
if (requestUri != null) {

httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheKeyGenerator.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.Spliterators;
3939
import java.util.concurrent.atomic.AtomicBoolean;
4040
import java.util.function.Consumer;
41+
import java.util.function.Function;
4142
import java.util.stream.StreamSupport;
4243

4344
import org.apache.hc.client5.http.cache.HttpCacheEntry;
@@ -72,6 +73,10 @@ public class CacheKeyGenerator implements Resolver<URI, String> {
7273
*/
7374
public static final CacheKeyGenerator INSTANCE = new CacheKeyGenerator();
7475

76+
/**
77+
* @deprecated Do not use.
78+
*/
79+
@Deprecated
7580
@Override
7681
public String resolve(final URI uri) {
7782
return generateKey(uri);
@@ -135,9 +140,33 @@ public String generateKey(final URI requestUri) {
135140
* @param host The host for this request
136141
* @param request the {@link HttpRequest}
137142
* @return cache key
143+
*
144+
* @deprecated Use {@link #generateKey(HttpHost, HttpRequest, Function)}
138145
*/
146+
@Deprecated
139147
public String generateKey(final HttpHost host, final HttpRequest request) {
148+
return generateKey(host, request, r -> null);
149+
}
150+
151+
/**
152+
* Computes a root key for the given {@link HttpHost}, {@link HttpRequest} and
153+
* request body that can be used as a unique identifier for cached resources.
154+
*
155+
* @param host The host for this request
156+
* @param request the {@link HttpRequest}
157+
* @param bodyExtractor function to extract request body. May be {@code null}
158+
* @return cache key
159+
*
160+
* @since 5.7
161+
*/
162+
public <T extends HttpRequest> String generateKey(final HttpHost host,
163+
final T request,
164+
final Function<T, String> bodyExtractor) {
140165
final String s = CacheSupport.requestUriRaw(host, request);
166+
final String body = bodyExtractor != null ? bodyExtractor.apply(request) : null;
167+
if (body != null) {
168+
throw new UnsupportedOperationException();
169+
}
141170
try {
142171
return generateKey(new URI(s));
143172
} catch (final URISyntaxException ex) {

httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestBasicHttpAsyncCache.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class TestBasicHttpAsyncCache {
6969
private Instant now;
7070
private Instant tenSecondsAgo;
7171
private SimpleHttpAsyncCacheStorage backing;
72+
private CacheKeyGenerator keyGenerator;
7273
private BasicHttpAsyncCache impl;
7374

7475
@BeforeEach
@@ -77,6 +78,7 @@ void setUp() {
7778
now = Instant.now();
7879
tenSecondsAgo = now.minusSeconds(10);
7980
backing = Mockito.spy(new SimpleHttpAsyncCacheStorage());
81+
keyGenerator = CacheKeyGenerator.INSTANCE;
8082
impl = new BasicHttpAsyncCache(HeapResourceFactory.INSTANCE, backing);
8183
}
8284

@@ -102,7 +104,7 @@ void testGetCacheEntryFetchesFromCacheOnCacheHitIfNoVariants() throws Exception
102104
final HttpHost host = new HttpHost("foo.example.com");
103105
final SimpleHttpRequest request = new SimpleHttpRequest("GET", "http://foo.example.com/bar");
104106

105-
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, request);
107+
final String key = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
106108

107109
backing.map.put(key,entry);
108110

@@ -275,7 +277,7 @@ void testGetVariantCacheEntriesReturnsAllVariants() throws Exception {
275277
final SimpleHttpRequest req1 = new SimpleHttpRequest("GET", uri);
276278
req1.setHeader("Accept-Encoding", "gzip");
277279

278-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(uri);
280+
final String rootKey = keyGenerator.generateKey(uri);
279281

280282
final HttpResponse resp1 = HttpTestUtils.make200Response();
281283
resp1.setHeader("Date", DateUtils.formatStandardDate(now));
@@ -547,7 +549,7 @@ void testInvalidatesUnsafeRequests() throws Exception {
547549
final SimpleHttpRequest request = new SimpleHttpRequest( "POST", "/path");
548550
final HttpResponse response = HttpTestUtils.make200Response();
549551

550-
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, request);
552+
final String key = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
551553

552554
backing.putEntry(key, HttpTestUtils.makeCacheEntry());
553555

@@ -587,7 +589,7 @@ void testDoesNotInvalidateSafeRequests() throws Exception {
587589
@Test
588590
void testInvalidatesUnsafeRequestsWithVariants() throws Exception {
589591
final SimpleHttpRequest request = new SimpleHttpRequest( "POST", "/path");
590-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
592+
final String rootKey = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
591593
final Set<String> variants = new HashSet<>();
592594
variants.add("{var1}");
593595
variants.add("{var2}");
@@ -618,12 +620,12 @@ void testInvalidatesUnsafeRequestsWithVariants() throws Exception {
618620
@Test
619621
void testInvalidateUriSpecifiedByContentLocationAndFresher() throws Exception {
620622
final SimpleHttpRequest request = new SimpleHttpRequest( "PUT", "/foo");
621-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
623+
final String rootKey = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
622624
final URI contentUri = new URIBuilder()
623625
.setHttpHost(host)
624626
.setPath("/bar")
625627
.build();
626-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
628+
final String contentKey = keyGenerator.generateKey(contentUri);
627629

628630
final HttpResponse response = HttpTestUtils.make200Response();
629631
response.setHeader("ETag","\"new-etag\"");
@@ -650,12 +652,12 @@ void testInvalidateUriSpecifiedByContentLocationAndFresher() throws Exception {
650652
@Test
651653
void testInvalidateUriSpecifiedByLocationAndFresher() throws Exception {
652654
final SimpleHttpRequest request = new SimpleHttpRequest( "PUT", "/foo");
653-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
655+
final String rootKey = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
654656
final URI contentUri = new URIBuilder()
655657
.setHttpHost(host)
656658
.setPath("/bar")
657659
.build();
658-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
660+
final String contentKey = keyGenerator.generateKey(contentUri);
659661

660662
final HttpResponse response = HttpTestUtils.make200Response();
661663
response.setHeader("ETag","\"new-etag\"");
@@ -702,12 +704,12 @@ void testDoesNotInvalidateForUnsuccessfulResponse() throws Exception {
702704
@Test
703705
void testInvalidateUriSpecifiedByContentLocationNonCanonical() throws Exception {
704706
final SimpleHttpRequest request = new SimpleHttpRequest( "PUT", "/foo");
705-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
707+
final String rootKey = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
706708
final URI contentUri = new URIBuilder()
707709
.setHttpHost(host)
708710
.setPath("/bar")
709711
.build();
710-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
712+
final String contentKey = keyGenerator.generateKey(contentUri);
711713

712714
final HttpResponse response = HttpTestUtils.make200Response();
713715
response.setHeader("ETag","\"new-etag\"");
@@ -737,12 +739,12 @@ void testInvalidateUriSpecifiedByContentLocationNonCanonical() throws Exception
737739
@Test
738740
void testInvalidateUriSpecifiedByContentLocationRelative() throws Exception {
739741
final SimpleHttpRequest request = new SimpleHttpRequest( "PUT", "/foo");
740-
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
742+
final String rootKey = keyGenerator.generateKey(host, request, SimpleHttpRequest::getBodyText);
741743
final URI contentUri = new URIBuilder()
742744
.setHttpHost(host)
743745
.setPath("/bar")
744746
.build();
745-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
747+
final String contentKey = keyGenerator.generateKey(contentUri);
746748

747749
final HttpResponse response = HttpTestUtils.make200Response();
748750
response.setHeader("ETag","\"new-etag\"");
@@ -776,7 +778,7 @@ void testDoesNotInvalidateUriSpecifiedByContentLocationOtherOrigin() throws Exce
776778
.setHost("bar.example.com")
777779
.setPath("/")
778780
.build();
779-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
781+
final String contentKey = keyGenerator.generateKey(contentUri);
780782

781783
final HttpResponse response = HttpTestUtils.make200Response();
782784
response.setHeader("ETag","\"new-etag\"");
@@ -801,7 +803,7 @@ void testDoesNotInvalidateUriSpecifiedByContentLocationIfEtagsMatch() throws Exc
801803
.setHttpHost(host)
802804
.setPath("/bar")
803805
.build();
804-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
806+
final String contentKey = keyGenerator.generateKey(contentUri);
805807

806808
final HttpResponse response = HttpTestUtils.make200Response();
807809
response.setHeader("ETag","\"same-etag\"");
@@ -828,7 +830,7 @@ void testDoesNotInvalidateUriSpecifiedByContentLocationIfOlder() throws Exceptio
828830
.setHttpHost(host)
829831
.setPath("/bar")
830832
.build();
831-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
833+
final String contentKey = keyGenerator.generateKey(contentUri);
832834

833835
final HttpResponse response = HttpTestUtils.make200Response();
834836
response.setHeader("ETag","\"new-etag\"");
@@ -855,7 +857,7 @@ void testDoesNotInvalidateUriSpecifiedByContentLocationIfResponseHasNoEtag() thr
855857
.setHttpHost(host)
856858
.setPath("/bar")
857859
.build();
858-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
860+
final String contentKey = keyGenerator.generateKey(contentUri);
859861

860862
final HttpResponse response = HttpTestUtils.make200Response();
861863
response.removeHeaders("ETag");
@@ -882,7 +884,7 @@ void testDoesNotInvalidateUriSpecifiedByContentLocationIfEntryHasNoEtag() throws
882884
.setHttpHost(host)
883885
.setPath("/bar")
884886
.build();
885-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
887+
final String contentKey = keyGenerator.generateKey(contentUri);
886888

887889
final HttpResponse response = HttpTestUtils.make200Response();
888890
response.setHeader("ETag", "\"some-etag\"");
@@ -908,7 +910,7 @@ void testInvalidatesUriSpecifiedByContentLocationIfResponseHasNoDate() throws Ex
908910
.setHttpHost(host)
909911
.setPath("/bar")
910912
.build();
911-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
913+
final String contentKey = keyGenerator.generateKey(contentUri);
912914

913915
final HttpResponse response = HttpTestUtils.make200Response();
914916
response.setHeader("ETag", "\"new-etag\"");
@@ -935,7 +937,7 @@ void testInvalidatesUriSpecifiedByContentLocationIfEntryHasNoDate() throws Excep
935937
.setHttpHost(host)
936938
.setPath("/bar")
937939
.build();
938-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
940+
final String contentKey = keyGenerator.generateKey(contentUri);
939941

940942
final HttpResponse response = HttpTestUtils.make200Response();
941943
response.setHeader("ETag","\"new-etag\"");
@@ -961,7 +963,7 @@ void testInvalidatesUriSpecifiedByContentLocationIfResponseHasMalformedDate() th
961963
.setHttpHost(host)
962964
.setPath("/bar")
963965
.build();
964-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
966+
final String contentKey = keyGenerator.generateKey(contentUri);
965967

966968
final HttpResponse response = HttpTestUtils.make200Response();
967969
response.setHeader("ETag","\"new-etag\"");
@@ -988,7 +990,7 @@ void testInvalidatesUriSpecifiedByContentLocationIfEntryHasMalformedDate() throw
988990
.setHttpHost(host)
989991
.setPath("/bar")
990992
.build();
991-
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
993+
final String contentKey = keyGenerator.generateKey(contentUri);
992994

993995
final HttpResponse response = HttpTestUtils.make200Response();
994996
response.setHeader("ETag","\"new-etag\"");

0 commit comments

Comments
 (0)