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 2023/05/21 13:51:39 UTC

[httpcomponents-client] 03/03: Parse Cache-Control request and response headers only once

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch 5.3.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 8a20b7a275be0d82cd6c9badac1c362623d90c93
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sun May 21 12:25:38 2023 +0200

    Parse Cache-Control request and response headers only once
---
 .../client5/http/impl/cache/AsyncCachingExec.java  |  59 ++-
 .../http/impl/cache/CacheValidityPolicy.java       |  57 ++-
 .../http/impl/cache/CacheableRequestPolicy.java    |   3 +-
 .../cache/CachedResponseSuitabilityChecker.java    |  55 ++-
 .../hc/client5/http/impl/cache/CachingExec.java    |  57 +--
 .../client5/http/impl/cache/CachingExecBase.java   |  58 +--
 .../http/impl/cache/ConditionalRequestBuilder.java |   4 +-
 .../http/impl/cache/ResponseCacheControl.java      |  18 +-
 .../http/impl/cache/ResponseCachingPolicy.java     | 133 ++----
 .../http/impl/cache/TestCacheValidityPolicy.java   | 284 ++++++------
 .../impl/cache/TestCacheableRequestPolicy.java     | 102 ++---
 .../TestCachedResponseSuitabilityChecker.java      | 142 ++++--
 .../http/impl/cache/TestCachingExecChain.java      |  18 +-
 .../impl/cache/TestConditionalRequestBuilder.java  |  41 +-
 .../http/impl/cache/TestResponseCachingPolicy.java | 480 +++++++++++----------
 15 files changed, 765 insertions(+), 746 deletions(-)

diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java
index 884842eb6..8234ef002 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AsyncCachingExec.java
@@ -239,7 +239,9 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
         requestCompliance.makeRequestCompliant(request);
         request.addHeader(HttpHeaders.VIA,via);
 
-        if (!cacheableRequestPolicy.isServableFromCache(request)) {
+        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
+
+        if (!cacheableRequestPolicy.isServableFromCache(requestCacheControl, request)) {
             LOG.debug("Request is not servable from cache");
             operation.setDependency(responseCache.flushCacheEntriesInvalidatedByRequest(target, request, new FutureCallback<Boolean>() {
 
@@ -266,9 +268,10 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                 public void completed(final HttpCacheEntry entry) {
                     if (entry == null) {
                         LOG.debug("Cache miss");
-                        handleCacheMiss(target, request, entityProducer, scope, chain, asyncExecCallback);
+                        handleCacheMiss(requestCacheControl, target, request, entityProducer, scope, chain, asyncExecCallback);
                     } else {
-                        handleCacheHit(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
+                        final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
+                        handleCacheHit(requestCacheControl, responseCacheControl, target, request, entityProducer, scope, chain, asyncExecCallback, entry);
                     }
                 }
 
@@ -488,7 +491,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                 }
 
             });
-            final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
+            final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(backendResponse);
+            final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
             if (cacheable) {
                 cachingConsumerRef.set(new CachingAsyncDataConsumer(asyncExecCallback, backendResponse, entityDetails));
                 storeRequestIfModifiedSinceFor304Response(request, backendResponse);
@@ -612,6 +616,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
     }
 
     private void handleCacheHit(
+            final RequestCacheControl requestCacheControl,
+            final ResponseCacheControl responseCacheControl,
             final HttpHost target,
             final HttpRequest request,
             final AsyncEntityProducer entityProducer,
@@ -623,28 +629,30 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
         recordCacheHit(target, request);
         final Instant now = getCurrentDate();
 
-        if (requestContainsNoCacheDirective(request)) {
+        if (requestCacheControl.isNoCache()) {
             // Revalidate with the server due to no-cache directive in response
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Revalidating with server due to no-cache directive in response.");
             }
-            revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
+            revalidateCacheEntry(requestCacheControl, responseCacheControl,
+                    target, request, entityProducer, scope, chain, asyncExecCallback, entry);
             return;
         }
 
-        if (suitabilityChecker.canCachedResponseBeUsed(request, entry, now)) {
-            if (responseCachingPolicy.responseContainsNoCacheDirective(entry)) {
+        if (suitabilityChecker.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now)) {
+            if (responseCachingPolicy.responseContainsNoCacheDirective(responseCacheControl, entry)) {
                 // Revalidate with the server due to no-cache directive in response
-                revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
+                revalidateCacheEntry(requestCacheControl, responseCacheControl,
+                        target, request, entityProducer, scope, chain, asyncExecCallback, entry);
                 return;
             }
             LOG.debug("Cache hit");
             try {
-                final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
+                final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl, request, context, entry, now);
                 triggerResponse(cacheResponse, scope, asyncExecCallback);
             } catch (final ResourceIOException ex) {
                 recordCacheFailure(target, request);
-                if (!mayCallBackend(request)) {
+                if (!mayCallBackend(requestCacheControl)) {
                     final SimpleHttpResponse cacheResponse = generateGatewayTimeout(context);
                     triggerResponse(cacheResponse, scope, asyncExecCallback);
                 } else {
@@ -656,20 +664,20 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                     }
                 }
             }
-        } else if (!mayCallBackend(request)) {
+        } else if (!mayCallBackend(requestCacheControl)) {
             LOG.debug("Cache entry not suitable but only-if-cached requested");
             final SimpleHttpResponse cacheResponse = generateGatewayTimeout(context);
             triggerResponse(cacheResponse, scope, asyncExecCallback);
         } else if (!(entry.getStatus() == HttpStatus.SC_NOT_MODIFIED && !suitabilityChecker.isConditional(request))) {
             LOG.debug("Revalidating cache entry");
-            final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(entry);
+            final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(responseCacheControl, entry);
             if (cacheRevalidator != null
-                    && !staleResponseNotAllowed(request, entry, now)
-                    && validityPolicy.mayReturnStaleWhileRevalidating(entry, now)
+                    && !staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)
+                    && validityPolicy.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now)
                     || staleIfErrorEnabled) {
                 LOG.debug("Serving stale with asynchronous revalidation");
                 try {
-                    final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
+                    final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl, request, context, entry, now);
                     final String exchangeId = ExecSupport.getNextExchangeId();
                     context.setExchangeId(exchangeId);
                     final AsyncExecChain.Scope fork = new AsyncExecChain.Scope(
@@ -684,7 +692,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                     cacheRevalidator.revalidateCacheEntry(
                             responseCache.generateKey(target, request, entry),
                             asyncExecCallback,
-                            asyncExecCallback1 -> revalidateCacheEntry(target, request, entityProducer, fork, chain, asyncExecCallback1, entry));
+                            asyncExecCallback1 -> revalidateCacheEntry(requestCacheControl, responseCacheControl,
+                                    target, request, entityProducer, fork, chain, asyncExecCallback1, entry));
                     triggerResponse(cacheResponse, scope, asyncExecCallback);
                 } catch (final ResourceIOException ex) {
                     if (staleIfErrorEnabled) {
@@ -692,7 +701,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                             LOG.debug("Serving stale response due to IOException and stale-if-error enabled");
                         }
                         try {
-                            final SimpleHttpResponse cacheResponse = generateCachedResponse(request, context, entry, now);
+                            final SimpleHttpResponse cacheResponse = generateCachedResponse(responseCacheControl,
+                                    request, context, entry, now);
                             triggerResponse(cacheResponse, scope, asyncExecCallback);
                         } catch (final ResourceIOException ex2) {
                             if (LOG.isDebugEnabled()) {
@@ -705,7 +715,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                     }
                 }
             } else {
-                revalidateCacheEntry(target, request, entityProducer, scope, chain, asyncExecCallback, entry);
+                revalidateCacheEntry(requestCacheControl, responseCacheControl,
+                        target, request, entityProducer, scope, chain, asyncExecCallback, entry);
             }
         } else {
             LOG.debug("Cache entry not usable; calling backend");
@@ -714,6 +725,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
     }
 
     void revalidateCacheEntry(
+            final RequestCacheControl requestCacheControl,
+            final ResponseCacheControl responseCacheControl,
             final HttpHost target,
             final HttpRequest request,
             final AsyncEntityProducer entityProducer,
@@ -723,6 +736,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
             final HttpCacheEntry cacheEntry) {
         final Instant requestDate = getCurrentDate();
         final HttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
+                responseCacheControl,
                 BasicRequestBuilder.copy(scope.originalRequest).build(),
                 cacheEntry);
         chainProceed(conditionalRequest, entityProducer, scope, chain, new AsyncExecCallback() {
@@ -791,8 +805,8 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
                     return new AsyncExecCallbackWrapper(asyncExecCallback, () -> triggerUpdatedCacheEntryResponse(backendResponse, responseDate));
                 }
                 if (staleIfErrorAppliesTo(statusCode)
-                        && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
-                        && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
+                        && !staleResponseNotAllowed(requestCacheControl, responseCacheControl, cacheEntry, getCurrentDate())
+                        && validityPolicy.mayReturnStaleIfError(requestCacheControl, responseCacheControl, cacheEntry, responseDate)) {
                     return new AsyncExecCallbackWrapper(asyncExecCallback, this::triggerResponseStaleCacheEntry);
                 }
                 return new BackendResponseHandler(target, conditionalRequest, requestDate, responseDate, scope, asyncExecCallback);
@@ -897,6 +911,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
     }
 
     private void handleCacheMiss(
+            final RequestCacheControl requestCacheControl,
             final HttpHost target,
             final HttpRequest request,
             final AsyncEntityProducer entityProducer,
@@ -905,7 +920,7 @@ class AsyncCachingExec extends CachingExecBase implements AsyncExecChainHandler
             final AsyncExecCallback asyncExecCallback) {
         recordCacheMiss(target, request);
 
-        if (mayCallBackend(request)) {
+        if (mayCallBackend(requestCacheControl)) {
             final CancellableDependency operation = scope.cancellableDependency;
             operation.setDependency(responseCache.getVariantCacheEntriesWithEtags(
                     target,
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
index 456bb834a..633506a02 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
@@ -34,7 +34,6 @@ import org.apache.hc.client5.http.cache.Resource;
 import org.apache.hc.client5.http.utils.DateUtils;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.util.TimeValue;
 
 class CacheValidityPolicy {
@@ -50,8 +49,8 @@ class CacheValidityPolicy {
         return TimeValue.ofSeconds(getCorrectedInitialAge(entry).toSeconds() + getResidentTime(entry, now).toSeconds());
     }
 
-    public TimeValue getFreshnessLifetime(final HttpCacheEntry entry) {
-        final long maxAge = getMaxAge(entry);
+    public TimeValue getFreshnessLifetime(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry) {
+        final long maxAge = getMaxAge(responseCacheControl);
         if (maxAge > -1) {
             return TimeValue.ofSeconds(maxAge);
         }
@@ -69,8 +68,9 @@ class CacheValidityPolicy {
         return TimeValue.ofSeconds(diff.getSeconds());
     }
 
-    public boolean isResponseFresh(final HttpCacheEntry entry, final Instant now) {
-        return getCurrentAge(entry, now).compareTo(getFreshnessLifetime(entry)) == -1;
+    public boolean isResponseFresh(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
+                                   final Instant now) {
+        return getCurrentAge(entry, now).compareTo(getFreshnessLifetime(responseCacheControl, entry)) == -1;
     }
 
     /**
@@ -114,36 +114,28 @@ class CacheValidityPolicy {
                 || entry.getFirstHeader(HttpHeaders.LAST_MODIFIED) != null;
     }
 
-    public boolean mustRevalidate(final HttpCacheEntry entry) {
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        return cacheControl.isMustRevalidate();
-    }
-
-    public boolean proxyRevalidate(final HttpCacheEntry entry) {
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        return cacheControl.isProxyRevalidate();
-    }
-
-    public boolean mayReturnStaleWhileRevalidating(final HttpCacheEntry entry, final Instant now) {
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        if (cacheControl.getStaleWhileRevalidate() >= 0) {
-            final TimeValue staleness = getStaleness(entry, now);
-            if (staleness.compareTo(TimeValue.ofSeconds(cacheControl.getStaleWhileRevalidate())) <= 0) {
+    public boolean mayReturnStaleWhileRevalidating(final ResponseCacheControl responseCacheControl,
+                                                   final HttpCacheEntry entry, final Instant now) {
+        if (responseCacheControl.getStaleWhileRevalidate() >= 0) {
+            final TimeValue staleness = getStaleness(responseCacheControl, entry, now);
+            if (staleness.compareTo(TimeValue.ofSeconds(responseCacheControl.getStaleWhileRevalidate())) <= 0) {
                 return true;
             }
         }
         return false;
     }
 
-    public boolean mayReturnStaleIfError(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
-        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        final TimeValue staleness = getStaleness(entry, now);
-        return mayReturnStaleIfError(requestCacheControl, staleness) || mayReturnStaleIfError(cacheControl, staleness);
+    public boolean mayReturnStaleIfError(final RequestCacheControl requestCacheControl,
+                                         final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
+                                         final Instant now) {
+        final TimeValue staleness = getStaleness(responseCacheControl, entry, now);
+        return mayReturnStaleIfError(requestCacheControl, staleness) ||
+                mayReturnStaleIfError(responseCacheControl, staleness);
     }
 
-    private boolean mayReturnStaleIfError(final CacheControl cacheControl, final TimeValue staleness) {
-        return cacheControl.getStaleIfError() >= 0 && staleness.compareTo(TimeValue.ofSeconds(cacheControl.getStaleIfError())) <= 0;
+    private boolean mayReturnStaleIfError(final CacheControl responseCacheControl, final TimeValue staleness) {
+        return responseCacheControl.getStaleIfError() >= 0 &&
+                staleness.compareTo(TimeValue.ofSeconds(responseCacheControl.getStaleIfError())) <= 0;
     }
 
     /**
@@ -222,10 +214,9 @@ class CacheValidityPolicy {
     }
 
 
-    protected long getMaxAge(final HttpCacheEntry entry) {
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        final long maxAge = cacheControl.getMaxAge();
-        final long sharedMaxAge = cacheControl.getSharedMaxAge();
+    protected long getMaxAge(final ResponseCacheControl responseCacheControl) {
+        final long maxAge = responseCacheControl.getMaxAge();
+        final long sharedMaxAge = responseCacheControl.getSharedMaxAge();
         if (sharedMaxAge == -1) {
             return maxAge;
         } else if (maxAge == -1) {
@@ -235,9 +226,9 @@ class CacheValidityPolicy {
         }
     }
 
-    public TimeValue getStaleness(final HttpCacheEntry entry, final Instant now) {
+    public TimeValue getStaleness(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry, final Instant now) {
         final TimeValue age = getCurrentAge(entry, now);
-        final TimeValue freshness = getFreshnessLifetime(entry);
+        final TimeValue freshness = getFreshnessLifetime(responseCacheControl, entry);
         if (age.compareTo(freshness) <= 0) {
             return TimeValue.ZERO_MILLISECONDS;
         }
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheableRequestPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheableRequestPolicy.java
index eef1034cd..d75da8fda 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheableRequestPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheableRequestPolicy.java
@@ -48,7 +48,7 @@ class CacheableRequestPolicy {
      *            an HttpRequest
      * @return boolean Is it possible to serve this request from cache
      */
-    public boolean isServableFromCache(final HttpRequest request) {
+    public boolean isServableFromCache(final RequestCacheControl cacheControl, final HttpRequest request) {
         final String method = request.getMethod();
 
         final ProtocolVersion pv = request.getVersion() != null ? request.getVersion() : HttpVersion.DEFAULT;
@@ -69,7 +69,6 @@ class CacheableRequestPolicy {
             return false;
         }
 
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
         if (cacheControl.isNoStore()) {
             LOG.debug("Request with no-store is not serveable from cache");
             return false;
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
index abb6fc559..e63cd7da7 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
@@ -70,56 +70,50 @@ class CachedResponseSuitabilityChecker {
         this(new CacheValidityPolicy(), config);
     }
 
-    private boolean isFreshEnough(final HttpCacheEntry entry, final HttpRequest request, final Instant now) {
-        if (validityStrategy.isResponseFresh(entry, now)) {
+    private boolean isFreshEnough(final RequestCacheControl requestCacheControl,
+                                  final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
+                                  final Instant now) {
+        if (validityStrategy.isResponseFresh(responseCacheControl, entry, now)) {
             return true;
         }
         if (useHeuristicCaching &&
                 validityStrategy.isResponseHeuristicallyFresh(entry, now, heuristicCoefficient, heuristicDefaultLifetime)) {
             return true;
         }
-        if (originInsistsOnFreshness(entry)) {
+        if (originInsistsOnFreshness(responseCacheControl)) {
             return false;
         }
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
-        if (cacheControl.getMaxStale() == -1) {
+        if (requestCacheControl.getMaxStale() == -1) {
             return false;
         }
-        return (cacheControl.getMaxStale() > validityStrategy.getStaleness(entry, now).toSeconds());
+        return (requestCacheControl.getMaxStale() > validityStrategy.getStaleness(responseCacheControl, entry, now).toSeconds());
     }
 
-    private boolean originInsistsOnFreshness(final HttpCacheEntry entry) {
-        if (validityStrategy.mustRevalidate(entry)) {
+    private boolean originInsistsOnFreshness(final ResponseCacheControl responseCacheControl) {
+        if (responseCacheControl.isMustRevalidate()) {
             return true;
         }
         if (!sharedCache) {
             return false;
         }
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
-        return cacheControl.isProxyRevalidate() || cacheControl.getSharedMaxAge() >= 0;
+        return responseCacheControl.isProxyRevalidate() || responseCacheControl.getSharedMaxAge() >= 0;
     }
 
     /**
      * Determine if I can utilize a {@link HttpCacheEntry} to respond to the given
      * {@link HttpRequest}
-     *
-     * @param request
-     *            {@link HttpRequest}
-     * @param entry
-     *            {@link HttpCacheEntry}
-     * @param now
-     *            Right now in time
-     * @return boolean yes/no answer
      * @since 5.3
      */
-    public boolean canCachedResponseBeUsed(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
+    public boolean canCachedResponseBeUsed(final RequestCacheControl requestCacheControl,
+                                           final ResponseCacheControl responseCacheControl, final HttpRequest request,
+                                           final HttpCacheEntry entry, final Instant now) {
 
         if (isGetRequestWithHeadCacheEntry(request, entry)) {
             LOG.debug("Cache entry created by HEAD request cannot be used to serve GET request");
             return false;
         }
 
-        if (!isFreshEnough(entry, request, now)) {
+        if (!isFreshEnough(requestCacheControl, responseCacheControl, entry, now)) {
             LOG.debug("Cache entry is not fresh enough");
             return false;
         }
@@ -149,38 +143,37 @@ class CachedResponseSuitabilityChecker {
                     "request method, entity or a 204 response");
             return false;
         }
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
-        if (cacheControl.isNoCache()) {
+        if (requestCacheControl.isNoCache()) {
             LOG.debug("Response contained NO CACHE directive, cache was not suitable");
             return false;
         }
 
-        if (cacheControl.isNoStore()) {
+        if (requestCacheControl.isNoStore()) {
             LOG.debug("Response contained NO STORE directive, cache was not suitable");
             return false;
         }
 
-        if (cacheControl.getMaxAge() >= 0) {
-            if (validityStrategy.getCurrentAge(entry, now).toSeconds() > cacheControl.getMaxAge()) {
+        if (requestCacheControl.getMaxAge() >= 0) {
+            if (validityStrategy.getCurrentAge(entry, now).toSeconds() > requestCacheControl.getMaxAge()) {
                 LOG.debug("Response from cache was not suitable due to max age");
                 return false;
             }
         }
 
-        if (cacheControl.getMaxStale() >= 0) {
-            if (validityStrategy.getFreshnessLifetime(entry).toSeconds() > cacheControl.getMaxStale()) {
+        if (requestCacheControl.getMaxStale() >= 0) {
+            if (validityStrategy.getFreshnessLifetime(responseCacheControl, entry).toSeconds() > requestCacheControl.getMaxStale()) {
                 LOG.debug("Response from cache was not suitable due to max stale freshness");
                 return false;
             }
         }
 
-        if (cacheControl.getMinFresh() >= 0) {
-            if (cacheControl.getMinFresh() == 0) {
+        if (requestCacheControl.getMinFresh() >= 0) {
+            if (requestCacheControl.getMinFresh() == 0) {
                 return false;
             }
             final TimeValue age = validityStrategy.getCurrentAge(entry, now);
-            final TimeValue freshness = validityStrategy.getFreshnessLifetime(entry);
-            if (freshness.toSeconds() - age.toSeconds() < cacheControl.getMinFresh()) {
+            final TimeValue freshness = validityStrategy.getFreshnessLifetime(responseCacheControl, entry);
+            if (freshness.toSeconds() - age.toSeconds() < requestCacheControl.getMinFresh()) {
                 LOG.debug("Response from cache was not suitable due to min fresh " +
                         "freshness requirement");
                 return false;
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 b89c834af..9d39cc7e5 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
@@ -217,7 +217,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
         requestCompliance.makeRequestCompliant(request);
         request.addHeader(HttpHeaders.VIA, via);
 
-        if (!cacheableRequestPolicy.isServableFromCache(request)) {
+        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
+        if (!cacheableRequestPolicy.isServableFromCache(requestCacheControl, request)) {
             LOG.debug("Request is not servable from cache");
             responseCache.flushCacheEntriesInvalidatedByRequest(target, request);
             return callBackend(target, request, scope, chain);
@@ -226,9 +227,10 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
         final HttpCacheEntry entry = responseCache.getCacheEntry(target, request);
         if (entry == null) {
             LOG.debug("Cache miss");
-            return handleCacheMiss(target, request, scope, chain);
+            return handleCacheMiss(target, request, requestCacheControl, scope, chain);
         } else {
-            return handleCacheHit(target, request, scope, chain, entry);
+            final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(entry);
+            return handleCacheHit(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
         }
     }
 
@@ -276,6 +278,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
     }
 
     private ClassicHttpResponse handleCacheHit(
+            final RequestCacheControl requestCacheControl,
+            final ResponseCacheControl responseCacheControl,
             final HttpHost target,
             final ClassicHttpRequest request,
             final ExecChain.Scope scope,
@@ -286,41 +290,40 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
         recordCacheHit(target, request);
         final Instant now = getCurrentDate();
 
-
-        if (requestContainsNoCacheDirective(request)) {
+        if (requestCacheControl.isNoCache()) {
             // Revalidate with the server
-            return revalidateCacheEntry(target, request, scope, chain, entry);
+            return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
         }
 
-        if (suitabilityChecker.canCachedResponseBeUsed(request, entry, now)) {
-            if (responseCachingPolicy.responseContainsNoCacheDirective(entry)) {
+        if (suitabilityChecker.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now)) {
+            if (responseCachingPolicy.responseContainsNoCacheDirective(responseCacheControl, entry)) {
                 // Revalidate with the server due to no-cache directive in response
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Revalidating with server due to no-cache directive in response.");
                 }
-                return revalidateCacheEntry(target, request, scope, chain, entry);
+                return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
             }
             LOG.debug("Cache hit");
             try {
-                return convert(generateCachedResponse(request, context, entry, now), scope);
+                return convert(generateCachedResponse(responseCacheControl, request, context, entry, now), scope);
             } catch (final ResourceIOException ex) {
                 recordCacheFailure(target, request);
-                if (!mayCallBackend(request)) {
+                if (!mayCallBackend(requestCacheControl)) {
                     return convert(generateGatewayTimeout(context), scope);
                 }
                 setResponseStatus(scope.clientContext, CacheResponseStatus.FAILURE);
                 return chain.proceed(request, scope);
             }
-        } else if (!mayCallBackend(request)) {
+        } else if (!mayCallBackend(requestCacheControl)) {
             LOG.debug("Cache entry not suitable but only-if-cached requested");
             return convert(generateGatewayTimeout(context), scope);
         } else if (!(entry.getStatus() == HttpStatus.SC_NOT_MODIFIED && !suitabilityChecker.isConditional(request))) {
             LOG.debug("Revalidating cache entry");
-            final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(entry);
+            final boolean staleIfErrorEnabled = responseCachingPolicy.isStaleIfErrorEnabled(responseCacheControl, entry);
             try {
                 if (cacheRevalidator != null
-                        && !staleResponseNotAllowed(request, entry, now)
-                        && validityPolicy.mayReturnStaleWhileRevalidating(entry, now)
+                        && !staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)
+                        && validityPolicy.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now)
                         || staleIfErrorEnabled) {
                     LOG.debug("Serving stale with asynchronous revalidation");
                     final String exchangeId = ExecSupport.getNextExchangeId();
@@ -331,21 +334,21 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
                             scope.originalRequest,
                             scope.execRuntime.fork(null),
                             HttpClientContext.create());
-                    final SimpleHttpResponse response = generateCachedResponse(request, context, entry, now);
+                    final SimpleHttpResponse response = generateCachedResponse(responseCacheControl, request, context, entry, now);
                     cacheRevalidator.revalidateCacheEntry(
                             responseCache.generateKey(target, request, entry),
-                            () -> revalidateCacheEntry(target, request, fork, chain, entry));
+                            () -> revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, fork, chain, entry));
                     return convert(response, scope);
                 }
-                return revalidateCacheEntry(target, request, scope, chain, entry);
+                return revalidateCacheEntry(requestCacheControl, responseCacheControl, target, request, scope, chain, entry);
             } catch (final IOException ioex) {
                 if (staleIfErrorEnabled) {
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("Serving stale response due to IOException and stale-if-error enabled");
                     }
-                    return convert(generateCachedResponse(request, context, entry, now), scope);
+                    return convert(generateCachedResponse(responseCacheControl, request, context, entry, now), scope);
                 }
-                return convert(handleRevalidationFailure(request, context, entry, now), scope);
+                return convert(handleRevalidationFailure(requestCacheControl, responseCacheControl, request, context, entry, now), scope);
             }
         } else {
             LOG.debug("Cache entry not usable; calling backend");
@@ -354,6 +357,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
     }
 
     ClassicHttpResponse revalidateCacheEntry(
+            final RequestCacheControl requestCacheControl,
+            final ResponseCacheControl responseCacheControl,
             final HttpHost target,
             final ClassicHttpRequest request,
             final ExecChain.Scope scope,
@@ -361,7 +366,7 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
             final HttpCacheEntry cacheEntry) throws IOException, HttpException {
         Instant requestDate = getCurrentDate();
         final ClassicHttpRequest conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(
-                scope.originalRequest, cacheEntry);
+                responseCacheControl, scope.originalRequest, cacheEntry);
 
         ClassicHttpResponse backendResponse = chain.proceed(conditionalRequest, scope);
         try {
@@ -394,8 +399,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
             }
 
             if (staleIfErrorAppliesTo(statusCode)
-                    && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
-                    && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
+                    && !staleResponseNotAllowed(requestCacheControl, responseCacheControl, cacheEntry, getCurrentDate())
+                    && validityPolicy.mayReturnStaleIfError(requestCacheControl, responseCacheControl, cacheEntry, responseDate)) {
                 try {
                     final SimpleHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
                     cachedResponse.addHeader(HttpHeaders.WARNING, "110 localhost \"Response is stale\"");
@@ -422,7 +427,8 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
         responseCompliance.ensureProtocolCompliance(scope.originalRequest, request, backendResponse);
 
         responseCache.flushCacheEntriesInvalidatedByExchange(target, request, backendResponse);
-        final boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse);
+        final ResponseCacheControl responseCacheControl = CacheControlHeaderParser.INSTANCE.parse(backendResponse);
+        final boolean cacheable = responseCachingPolicy.isResponseCacheable(responseCacheControl, request, backendResponse);
         if (cacheable) {
             storeRequestIfModifiedSinceFor304Response(request, backendResponse);
             return cacheAndReturnResponse(target, request, backendResponse, scope, requestDate, responseDate);
@@ -498,11 +504,12 @@ class CachingExec extends CachingExecBase implements ExecChainHandler {
     private ClassicHttpResponse handleCacheMiss(
             final HttpHost target,
             final ClassicHttpRequest request,
+            final RequestCacheControl requestCacheControl,
             final ExecChain.Scope scope,
             final ExecChain chain) throws IOException, HttpException {
         recordCacheMiss(target, request);
 
-        if (!mayCallBackend(request)) {
+        if (!mayCallBackend(requestCacheControl)) {
             return new BasicClassicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
         }
 
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
index 4f0f3fafe..535ec5e67 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
@@ -28,7 +28,6 @@ package org.apache.hc.client5.http.impl.cache;
 
 import java.io.IOException;
 import java.time.Instant;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -184,6 +183,7 @@ public class CachingExecBase {
     }
 
     SimpleHttpResponse generateCachedResponse(
+            final ResponseCacheControl responseCacheControl,
             final HttpRequest request,
             final HttpContext context,
             final HttpCacheEntry entry,
@@ -196,7 +196,7 @@ public class CachingExecBase {
             cachedResponse = responseGenerator.generateResponse(request, entry);
         }
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
-        if (TimeValue.isPositive(validityPolicy.getStaleness(entry, now))) {
+        if (TimeValue.isPositive(validityPolicy.getStaleness(responseCacheControl, entry, now))) {
             cachedResponse.addHeader(HttpHeaders.WARNING,"110 localhost \"Response is stale\"");
         }
 
@@ -205,7 +205,7 @@ public class CachingExecBase {
             final Header header = entry.getFirstHeader(HttpHeaders.DATE);
             if (header != null) {
                 final Instant responseDate = DateUtils.parseStandardDate(header.getValue());
-                final TimeValue freshnessLifetime = validityPolicy.getFreshnessLifetime(entry);
+                final TimeValue freshnessLifetime = validityPolicy.getFreshnessLifetime(responseCacheControl, entry);
                 final TimeValue currentAge = validityPolicy.getCurrentAge(entry, responseDate);
                 if (freshnessLifetime.compareTo(ONE_DAY) > 0 && currentAge.compareTo(ONE_DAY) > 0) {
                     cachedResponse.addHeader(HttpHeaders.WARNING,"113 localhost \"Heuristic expiration\"");
@@ -220,11 +220,13 @@ public class CachingExecBase {
     }
 
     SimpleHttpResponse handleRevalidationFailure(
+            final RequestCacheControl requestCacheControl,
+            final ResponseCacheControl responseCacheControl,
             final HttpRequest request,
             final HttpContext context,
             final HttpCacheEntry entry,
             final Instant now) throws IOException {
-        if (staleResponseNotAllowed(request, entry, now)) {
+        if (staleResponseNotAllowed(requestCacheControl, responseCacheControl, entry, now)) {
             return generateGatewayTimeout(context);
         } else {
             return unvalidatedCacheHit(request, context, entry);
@@ -247,14 +249,16 @@ public class CachingExecBase {
         return cachedResponse;
     }
 
-    boolean staleResponseNotAllowed(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
-        return validityPolicy.mustRevalidate(entry)
-            || (cacheConfig.isSharedCache() && validityPolicy.proxyRevalidate(entry))
-            || explicitFreshnessRequest(request, entry, now);
+    boolean staleResponseNotAllowed(final RequestCacheControl requestCacheControl,
+                                    final ResponseCacheControl responseCacheControl,
+                                    final HttpCacheEntry entry,
+                                    final Instant now) {
+        return responseCacheControl.isMustRevalidate()
+            || (cacheConfig.isSharedCache() && responseCacheControl.isProxyRevalidate())
+            || explicitFreshnessRequest(requestCacheControl, responseCacheControl, entry, now);
     }
 
-    boolean mayCallBackend(final HttpRequest request) {
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
+    boolean mayCallBackend(final RequestCacheControl cacheControl) {
         if (cacheControl.isOnlyIfCached()) {
             LOG.debug("Request marked only-if-cached");
             return false;
@@ -262,15 +266,16 @@ public class CachingExecBase {
         return true;
     }
 
-    boolean explicitFreshnessRequest(final HttpRequest request, final HttpCacheEntry entry, final Instant now) {
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(request);
-        if (cacheControl.getMaxStale() >= 0) {
+    boolean explicitFreshnessRequest(final RequestCacheControl requestCacheControl,
+                                     final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry,
+                                     final Instant now) {
+        if (requestCacheControl.getMaxStale() >= 0) {
             final TimeValue age = validityPolicy.getCurrentAge(entry, now);
-            final TimeValue lifetime = validityPolicy.getFreshnessLifetime(entry);
-            if (age.toSeconds() - lifetime.toSeconds() > cacheControl.getMaxStale()) {
+            final TimeValue lifetime = validityPolicy.getFreshnessLifetime(responseCacheControl, entry);
+            if (age.toSeconds() - lifetime.toSeconds() > requestCacheControl.getMaxStale()) {
                 return true;
             }
-        } else if (cacheControl.getMinFresh() >= 0 || cacheControl.getMaxAge() >= 0) {
+        } else if (requestCacheControl.getMinFresh() >= 0 || requestCacheControl.getMaxAge() >= 0) {
             return true;
         }
         return false;
@@ -375,25 +380,4 @@ public class CachingExecBase {
         }
     }
 
-    /**
-     * Checks if the provided HttpRequest contains a 'no-cache' directive in its Cache-Control header.
-     * <p>
-     * According to the HTTP/1.1 specification, a 'no-cache' directive in a request message means
-     * that the client allows a stored response to be used only if it is first validated with the
-     * origin server (or with an intermediate cache that has a fresh response). This directive
-     * applies to both shared and private caches.
-     *
-     * @param request the HttpRequest to check for the 'no-cache' directive
-     * @return true if the 'no-cache' directive is present in the Cache-Control header of the request,
-     * false otherwise
-     */
-    boolean requestContainsNoCacheDirective(final HttpRequest request) {
-        final Iterator<Header> it = request.headerIterator(HttpHeaders.CACHE_CONTROL);
-        if (it == null || !it.hasNext()) {
-            return false;
-        } else {
-            final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parseResponse(it);
-            return cacheControl.isNoCache();
-        }
-    }
 }
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ConditionalRequestBuilder.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ConditionalRequestBuilder.java
index 113a106db..ec923ab73 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ConditionalRequestBuilder.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ConditionalRequestBuilder.java
@@ -49,11 +49,12 @@ class ConditionalRequestBuilder<T extends HttpRequest> {
      * the entry with the origin.  Build the origin {@link org.apache.hc.core5.http.HttpRequest}
      * here and return it.
      *
+     * @param cacheControl the cache control directives.
      * @param request the original request from the caller
      * @param cacheEntry the entry that needs to be re-validated
      * @return the wrapped request
      */
-    public T buildConditionalRequest(final T request, final HttpCacheEntry cacheEntry) {
+    public T buildConditionalRequest(final ResponseCacheControl cacheControl, final T request, final HttpCacheEntry cacheEntry) {
         final T newRequest = messageCopier.create(request);
 
         final Header eTag = cacheEntry.getFirstHeader(HttpHeaders.ETAG);
@@ -64,7 +65,6 @@ class ConditionalRequestBuilder<T extends HttpRequest> {
         if (lastModified != null) {
             newRequest.setHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified.getValue());
         }
-        final ResponseCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(cacheEntry);
         if (cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate()) {
             newRequest.addHeader(HttpHeaders.CACHE_CONTROL, HeaderConstants.CACHE_CONTROL_MAX_AGE + "=0");
         }
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCacheControl.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCacheControl.java
index 845fcc702..54b10da60 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCacheControl.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCacheControl.java
@@ -99,6 +99,8 @@ final class ResponseCacheControl implements CacheControl {
      */
     private final Set<String> noCacheFields;
 
+    private final boolean undefined;
+
     /**
      * Creates a new instance of {@code CacheControl} with the specified values.
      *
@@ -129,6 +131,16 @@ final class ResponseCacheControl implements CacheControl {
         this.staleWhileRevalidate = staleWhileRevalidate;
         this.staleIfError = staleIfError;
         this.noCacheFields = noCacheFields != null ? Collections.unmodifiableSet(noCacheFields) : Collections.emptySet();
+        this.undefined = maxAge == -1 &&
+                sharedMaxAge == -1 &&
+                !noCache &&
+                !noStore &&
+                !cachePrivate &&
+                !mustRevalidate &&
+                !proxyRevalidate &&
+                !cachePublic &&
+                staleWhileRevalidate == -1
+                && staleIfError == -1;
     }
 
     /**
@@ -235,6 +247,10 @@ final class ResponseCacheControl implements CacheControl {
         return noCacheFields;
     }
 
+    public boolean isUndefined() {
+        return undefined;
+    }
+
     @Override
     public String toString() {
         return "CacheControl{" +
@@ -252,7 +268,7 @@ final class ResponseCacheControl implements CacheControl {
                 '}';
     }
 
-    static Builder create() {
+    static Builder builder() {
         return new Builder();
     }
 
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
index 2eb900892..82a09bd3c 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
@@ -45,10 +45,8 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.MessageHeaders;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.MessageSupport;
-import org.apache.hc.core5.util.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -161,11 +159,9 @@ class ResponseCachingPolicy {
     /**
      * Determines if an HttpResponse can be cached.
      *
-     * @param httpMethod What type of request was this, a GET, PUT, other?
-     * @param response The origin response
      * @return {@code true} if response is cacheable
      */
-    public boolean isResponseCacheable(final String httpMethod, final HttpResponse response, final ResponseCacheControl cacheControl) {
+    public boolean isResponseCacheable(final ResponseCacheControl cacheControl, final String httpMethod, final HttpResponse response) {
         boolean cacheable = false;
 
         if (!HeaderConstants.GET_METHOD.equals(httpMethod) && !HeaderConstants.HEAD_METHOD.equals(httpMethod)
@@ -242,7 +238,7 @@ class ResponseCachingPolicy {
         }
 
         // calculate freshness lifetime
-        final Duration freshnessLifetime = calculateFreshnessLifetime(response, cacheControl);
+        final Duration freshnessLifetime = calculateFreshnessLifetime(cacheControl, response);
         if (freshnessLifetime.isNegative() || freshnessLifetime.isZero()) {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Freshness lifetime is invalid");
@@ -250,7 +246,7 @@ class ResponseCachingPolicy {
             return false;
         }
 
-        return cacheable || isExplicitlyCacheable(response, cacheControl);
+        return cacheable || isExplicitlyCacheable(cacheControl, response);
     }
 
     private boolean unknownStatusCode(final int status) {
@@ -295,57 +291,21 @@ class ResponseCachingPolicy {
         }
     }
 
-    protected boolean isExplicitlyCacheable(final HttpResponse response, final ResponseCacheControl cacheControl ) {
+    protected boolean isExplicitlyCacheable(final ResponseCacheControl cacheControl, final HttpResponse response) {
         if (response.getFirstHeader(HttpHeaders.EXPIRES) != null) {
             return true;
         }
-        if (cacheControl == null) {
-            return false;
-        }else {
-            return cacheControl.getMaxAge() > 0 || cacheControl.getSharedMaxAge()>0 ||
-                    cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate() || (cacheControl.isPublic());
-        }
+        return cacheControl.getMaxAge() > 0 || cacheControl.getSharedMaxAge()>0 ||
+                cacheControl.isMustRevalidate() || cacheControl.isProxyRevalidate() || (cacheControl.isPublic());
     }
 
     /**
      * Determine if the {@link HttpResponse} gotten from the origin is a
      * cacheable response.
      *
-     * @param request  the {@link HttpRequest} that generated an origin hit. Can't be {@code null}.
-     * @param response the {@link HttpResponse} from the origin. Can't be {@code null}.
-     * @return {@code true} if response is cacheable
-     * @since 5.3
-     */
-    public boolean isResponseCacheable(final HttpRequest request, final HttpResponse response) {
-        Args.notNull(request, "Request");
-        Args.notNull(response, "Response");
-        return isResponseCacheable(request, response, parseCacheControlHeader(response));
-    }
-
-    /**
-     * Determines if an HttpResponse can be cached.
-     *
-     * @param httpMethod What type of request was this, a GET, PUT, other?. Can't be {@code null}.
-     * @param response   The origin response. Can't be {@code null}.
      * @return {@code true} if response is cacheable
-     * @since 5.3
      */
-    public boolean isResponseCacheable(final String httpMethod, final HttpResponse response) {
-        Args.notEmpty(httpMethod, "httpMethod");
-        Args.notNull(response, "Response");
-        return isResponseCacheable(httpMethod, response, parseCacheControlHeader(response));
-    }
-
-
-    /**
-     * Determine if the {@link HttpResponse} gotten from the origin is a
-     * cacheable response.
-     *
-     * @param request the {@link HttpRequest} that generated an origin hit
-     * @param response the {@link HttpResponse} from the origin
-     * @return {@code true} if response is cacheable
-     */
-    public boolean isResponseCacheable(final HttpRequest request, final HttpResponse response, final ResponseCacheControl cacheControl) {
+    public boolean isResponseCacheable(final ResponseCacheControl cacheControl, final HttpRequest request, final HttpResponse response) {
         final ProtocolVersion version = request.getVersion() != null ? request.getVersion() : HttpVersion.DEFAULT;
         if (version.compareToVersion(HttpVersion.HTTP_1_1) > 0) {
             if (LOG.isDebugEnabled()) {
@@ -353,7 +313,7 @@ class ResponseCachingPolicy {
             }
             return false;
         }
-        if (cacheControl != null && cacheControl.isNoStore()) {
+        if (cacheControl.isNoStore()) {
             LOG.debug("Response is explicitly non-cacheable per cache control directive");
             return false;
         }
@@ -362,31 +322,31 @@ class ResponseCachingPolicy {
             if (neverCache1_0ResponsesWithQueryString && from1_0Origin(response)) {
                 LOG.debug("Response is not cacheable as it had a query string");
                 return false;
-            } else if (!neverCache1_1ResponsesWithQueryString && !isExplicitlyCacheable(response, cacheControl)) {
+            } else if (!neverCache1_1ResponsesWithQueryString && !isExplicitlyCacheable(cacheControl, response)) {
                 LOG.debug("Response is not cacheable as it is missing explicit caching headers");
                 return false;
             }
         }
 
-        if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(response, cacheControl)) {
+        if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(cacheControl, response)) {
             LOG.debug("Expires header less or equal to Date header and no cache control directives");
             return false;
         }
 
         if (sharedCache) {
             if (request.countHeaders(HttpHeaders.AUTHORIZATION) > 0
-                    && cacheControl != null && !(cacheControl.getSharedMaxAge() > -1 || cacheControl.isMustRevalidate() || cacheControl.isPublic())) {
+                    && !(cacheControl.getSharedMaxAge() > -1 || cacheControl.isMustRevalidate() || cacheControl.isPublic())) {
                 LOG.debug("Request contains private credentials");
                 return false;
             }
         }
 
         final String method = request.getMethod();
-        return isResponseCacheable(method, response, cacheControl);
+        return isResponseCacheable(cacheControl, method, response);
     }
 
-    private boolean expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(final HttpResponse response, final ResponseCacheControl cacheControl) {
-        if (cacheControl != null) {
+    private boolean expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(final ResponseCacheControl cacheControl, final HttpResponse response) {
+        if (!cacheControl.isUndefined()) {
             return false;
         }
         final Header expiresHdr = response.getFirstHeader(HttpHeaders.EXPIRES);
@@ -446,9 +406,9 @@ class ResponseCachingPolicy {
      * @param response the HTTP response for which to calculate the freshness lifetime
      * @return the freshness lifetime of the response, in seconds
      */
-    private Duration calculateFreshnessLifetime(final HttpResponse response, final ResponseCacheControl cacheControl) {
+    private Duration calculateFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpResponse response) {
 
-        if (cacheControl == null) {
+        if (cacheControl.isUndefined()) {
             // If no cache-control header is present, assume no caching directives and return a default value
             return DEFAULT_FRESHNESS_DURATION; // 5 minutes
         }
@@ -488,43 +448,21 @@ class ResponseCachingPolicy {
      * {@code stale-while-revalidate} directive in its Cache-Control header. If it does, this method returns {@code true},
      * indicating that a stale response can be served. If not, it returns {@code false}.
      *
-     * @param entry the cached HTTP message entry to check
      * @return {@code true} if a stale response can be served in case of an error status code, {@code false} otherwise
      */
-    boolean isStaleIfErrorEnabled(final HttpCacheEntry entry) {
+    boolean isStaleIfErrorEnabled(final ResponseCacheControl cacheControl, final HttpCacheEntry entry) {
         // Check if the stale-while-revalidate extension is enabled
         if (staleIfErrorEnabled) {
             // Check if the cached response has an error status code
             final int statusCode = entry.getStatus();
             if (statusCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode <= HttpStatus.SC_GATEWAY_TIMEOUT) {
                 // Check if the cached response has a stale-while-revalidate directive
-                final ResponseCacheControl cacheControl = parseCacheControlHeader(entry);
-                if (cacheControl == null) {
-                    return false;
-                } else {
-                    return cacheControl.getStaleWhileRevalidate() > 0;
-                }
+                return cacheControl.getStaleWhileRevalidate() > 0;
             }
         }
         return false;
     }
 
-    /**
-     * Parses the Cache-Control header from the given HTTP messageHeaders and returns the corresponding CacheControl instance.
-     * If the header is not present, returns a CacheControl instance with default values for all directives.
-     *
-     * @param messageHeaders the HTTP message to parse the header from
-     * @return a CacheControl instance with the parsed directives or default values if the header is not present
-     */
-    private ResponseCacheControl parseCacheControlHeader(final MessageHeaders messageHeaders) {
-        final Iterator<Header> it = messageHeaders.headerIterator(HttpHeaders.CACHE_CONTROL);
-        if (it == null || !it.hasNext()) {
-            return null;
-        } else {
-            return CacheControlHeaderParser.INSTANCE.parseResponse(it);
-        }
-    }
-
     /**
      * Determines if the given {@link HttpCacheEntry} requires revalidation based on the presence of the {@code no-cache} directive
      * in the Cache-Control header.
@@ -539,33 +477,26 @@ class ResponseCachingPolicy {
      * @param entry the  {@link HttpCacheEntry} containing the headers to check for the {@code no-cache} directive.
      * @return true if revalidation is required based on the {@code no-cache} directive, {@code false} otherwise.
      */
-    boolean responseContainsNoCacheDirective(final HttpCacheEntry entry) {
-        final ResponseCacheControl responseCacheControl = parseCacheControlHeader(entry);
-
-        if (responseCacheControl != null) {
-            final Set<String> noCacheFields = responseCacheControl.getNoCacheFields();
+    boolean responseContainsNoCacheDirective(final ResponseCacheControl responseCacheControl, final HttpCacheEntry entry) {
+        final Set<String> noCacheFields = responseCacheControl.getNoCacheFields();
 
-            // If no-cache directive is present and has no field names
-            if (responseCacheControl.isNoCache() && noCacheFields.isEmpty()) {
-                LOG.debug("No-cache directive present without field names. Revalidation required.");
-                return true;
-            }
+        // If no-cache directive is present and has no field names
+        if (responseCacheControl.isNoCache() && noCacheFields.isEmpty()) {
+            LOG.debug("No-cache directive present without field names. Revalidation required.");
+            return true;
+        }
 
-            // If no-cache directive is present with field names
-            if (responseCacheControl.isNoCache()) {
-                for (final String field : noCacheFields) {
-                    if (entry.getFirstHeader(field) != null) {
-                        if (LOG.isDebugEnabled()) {
-                            LOG.debug("No-cache directive field '{}' found in response headers. Revalidation required.", field);
-                        }
-                        return true;
+        // If no-cache directive is present with field names
+        if (responseCacheControl.isNoCache()) {
+            for (final String field : noCacheFields) {
+                if (entry.getFirstHeader(field) != null) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("No-cache directive field '{}' found in response headers. Revalidation required.", field);
                     }
+                    return true;
                 }
             }
         }
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("No no-cache directives found in response headers. No revalidation required.");
-        }
         return false;
     }
 
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
index 60dc0f7d6..36fbad53f 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
@@ -38,9 +38,7 @@ import org.apache.hc.client5.http.cache.HttpCacheEntry;
 import org.apache.hc.client5.http.utils.DateUtils;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.message.BasicHeader;
-import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.util.TimeValue;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -161,68 +159,75 @@ public class TestCacheValidityPolicy {
 
     @Test
     public void testFreshnessLifetimeIsSMaxAgeIfPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .setSharedMaxAge(10)
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsMaxAgeIfPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .setMaxAge(10)
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsMostRestrictiveOfMaxAgeAndSMaxAge() {
-        Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
-                new BasicHeader("Cache-Control", "s-maxage=20") };
-        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .setMaxAge(10)
+                .setSharedMaxAge(20)
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
 
-        headers = new Header[] { new BasicHeader("Cache-Control", "max-age=20"),
-                new BasicHeader("Cache-Control", "s-maxage=10") };
-        entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+        final ResponseCacheControl cacheControl2 = ResponseCacheControl.builder()
+                .setMaxAge(20)
+                .setSharedMaxAge(10)
+                .build();
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl2, entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsMaxAgeEvenIfExpiresIsPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .setMaxAge(10)
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsSMaxAgeEvenIfExpiresIsPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10"),
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .setSharedMaxAge(10)
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
+                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsFromExpiresHeaderIfNoMaxAge() {
-        final Header[] headers = new Header[] {
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
+                .build();
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)) };
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(entry));
+                new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
+        assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(cacheControl, entry));
     }
 
     @Test
     public void testHeuristicFreshnessLifetime() {
-        final Header[] headers = new Header[] {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Date", DateUtils.formatStandardDate(oneSecondAgo)),
-                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(elevenSecondsAgo))
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(elevenSecondsAgo)));
         assertEquals(TimeValue.ofSeconds(1), impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ZERO_MILLISECONDS));
     }
 
@@ -235,18 +240,16 @@ public class TestCacheValidityPolicy {
 
     @Test
     public void testHeuristicFreshnessLifetimeIsNonNegative() {
-        final Header[] headers = new Header[] {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Date", DateUtils.formatStandardDate(elevenSecondsAgo)),
-                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(oneSecondAgo))
-        };
-
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(oneSecondAgo)));
         assertTrue(TimeValue.isNonNegative(impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ofSeconds(10))));
     }
 
     @Test
     public void testResponseIsFreshIfFreshnessLifetimeExceedsCurrentAge() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
         impl = new CacheValidityPolicy() {
             @Override
             public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
@@ -255,17 +258,18 @@ public class TestCacheValidityPolicy {
                 return TimeValue.ofSeconds(6);
             }
             @Override
-            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
                 assertSame(entry, e);
                 return TimeValue.ofSeconds(10);
             }
         };
-        assertTrue(impl.isResponseFresh(entry, now));
+        assertTrue(impl.isResponseFresh(responseCacheControl, entry, now));
     }
 
     @Test
     public void testResponseIsNotFreshIfFreshnessLifetimeEqualsCurrentAge() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
         impl = new CacheValidityPolicy() {
             @Override
             public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
@@ -274,17 +278,18 @@ public class TestCacheValidityPolicy {
                 return TimeValue.ofSeconds(6);
             }
             @Override
-            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
                 assertSame(entry, e);
                 return TimeValue.ofSeconds(6);
             }
         };
-        assertFalse(impl.isResponseFresh(entry, now));
+        assertFalse(impl.isResponseFresh(responseCacheControl, entry, now));
     }
 
     @Test
     public void testResponseIsNotFreshIfCurrentAgeExceedsFreshnessLifetime() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder().build();
         impl = new CacheValidityPolicy() {
             @Override
             public TimeValue getCurrentAge(final HttpCacheEntry e, final Instant d) {
@@ -293,70 +298,70 @@ public class TestCacheValidityPolicy {
                 return TimeValue.ofSeconds(10);
             }
             @Override
-            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final ResponseCacheControl cacheControl, final HttpCacheEntry e) {
                 assertSame(entry, e);
                 return TimeValue.ofSeconds(6);
             }
         };
-        assertFalse(impl.isResponseFresh(entry, now));
+        assertFalse(impl.isResponseFresh(responseCacheControl, entry, now));
     }
 
     @Test
     public void testCacheEntryIsRevalidatableIfHeadersIncludeETag() {
-        final Header[] headers = {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
-                new BasicHeader("ETag", "somevalue")};
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+                new BasicHeader("ETag", "somevalue"));
         assertTrue(impl.isRevalidatable(entry));
     }
 
     @Test
     public void testCacheEntryIsRevalidatableIfHeadersIncludeLastModifiedDate() {
-        final Header[] headers = {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
-                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(Instant.now())) };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+                new BasicHeader("Last-Modified", DateUtils.formatStandardDate(Instant.now())));
         assertTrue(impl.isRevalidatable(entry));
     }
 
     @Test
     public void testCacheEntryIsNotRevalidatableIfNoAppropriateHeaders() {
-        final Header[] headers =  {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
                 new BasicHeader("Expires", DateUtils.formatStandardDate(Instant.now())),
-                new BasicHeader("Cache-Control", "public") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+                new BasicHeader("Cache-Control", "public"));
         assertFalse(impl.isRevalidatable(entry));
     }
 
     @Test
     public void testMissingContentLengthDoesntInvalidateEntry() {
         final int contentLength = 128;
-        final Header[] headers = {}; // no Content-Length header
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
+                new Header[] { }, // no Content-Length header
+                HttpTestUtils.getRandomBytes(contentLength));
         assertTrue(impl.contentLengthHeaderMatchesActualLength(entry));
     }
 
     @Test
     public void testCorrectContentLengthDoesntInvalidateEntry() {
         final int contentLength = 128;
-        final Header[] headers = { new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)) };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
+                new Header[] { new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)) },
+                HttpTestUtils.getRandomBytes(contentLength));
         assertTrue(impl.contentLengthHeaderMatchesActualLength(entry));
     }
 
     @Test
     public void testWrongContentLengthInvalidatesEntry() {
         final int contentLength = 128;
-        final Header[] headers = {new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength+1))};
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers, HttpTestUtils.getRandomBytes(contentLength));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
+                new Header[]{ new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength+1)) },
+                HttpTestUtils.getRandomBytes(contentLength));
         assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
     }
 
     @Test
     public void testNullResourceInvalidatesEntry() {
         final int contentLength = 128;
-        final Header[] headers = {new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength))};
-        final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(headers);
+        final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(
+                new BasicHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(contentLength)));
         assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
     }
 
@@ -370,133 +375,108 @@ public class TestCacheValidityPolicy {
 
     @Test
     public void testMalformedAgeHeaderValueReturnsMaxAge() {
-        final Header[] headers = new Header[] { new BasicHeader("Age", "asdf") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
+                new BasicHeader("Age", "asdf"));
         // in seconds
         assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), impl.getAgeValue(entry));
     }
 
-    @Test
-    public void testMalformedCacheControlMaxAgeHeaderReturnsZero() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=asdf") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        // in seconds
-        assertEquals(0L, impl.getMaxAge(entry));
-    }
-
-    @Test
-    public void testMustRevalidateIsFalseIfDirectiveNotPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertFalse(impl.mustRevalidate(entry));
-    }
-
-    @Test
-    public void testMustRevalidateIsTrueWhenDirectiveIsPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public, must-revalidate") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertTrue(impl.mustRevalidate(entry));
-    }
-
-    @Test
-    public void testProxyRevalidateIsFalseIfDirectiveNotPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertFalse(impl.proxyRevalidate(entry));
-    }
-
-    @Test
-    public void testProxyRevalidateIsTrueWhenDirectiveIsPresent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public, proxy-revalidate") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertTrue(impl.proxyRevalidate(entry));
-    }
-
     @Test
     public void testMayReturnStaleIfErrorInResponseIsTrueWithinStaleness(){
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5, stale-if-error=15")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
-        final HttpRequest req = new BasicHttpRequest("GET","/");
-        assertTrue(impl.mayReturnStaleIfError(req, entry, now));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
+        final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
+                .build();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setStaleIfError(15)
+                .build();
+        assertTrue(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayReturnStaleIfErrorInRequestIsTrueWithinStaleness(){
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
-        final HttpRequest req = new BasicHttpRequest("GET","/");
-        req.setHeader("Cache-Control","stale-if-error=15");
-        assertTrue(impl.mayReturnStaleIfError(req, entry, now));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
+        final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
+                .build();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setStaleIfError(15)
+                .build();
+        assertTrue(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayNotReturnStaleIfErrorInResponseAndAfterResponseWindow(){
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5, stale-if-error=1")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
-        final HttpRequest req = new BasicHttpRequest("GET","/");
-        assertFalse(impl.mayReturnStaleIfError(req, entry, now));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
+        final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
+                .build();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setStaleIfError(1)
+                .build();
+        assertFalse(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayNotReturnStaleIfErrorInResponseAndAfterRequestWindow(){
-        final Header[] headers = new Header[] {
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
-        final HttpRequest req = new BasicHttpRequest("GET","/");
-        req.setHeader("Cache-Control","stale-if-error=1");
-        assertFalse(impl.mayReturnStaleIfError(req, entry, now));
+                new BasicHeader("Cache-Control", "max-age=5"));
+        final RequestCacheControl requestCacheControl = RequestCacheControl.builder()
+                .setStaleIfError(1)
+                .build();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .build();
+        assertFalse(impl.mayReturnStaleIfError(requestCacheControl, responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveIsAbsent() {
-        final Header[] headers = new Header[] { new BasicHeader("Cache-control", "public") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
 
-        assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
+        assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsTrueWhenWithinStaleness() {
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=15")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setStaleWhileRevalidate(15)
+                .build();
 
-        assertTrue(impl.mayReturnStaleWhileRevalidating(entry, now));
+        assertTrue(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenPastStaleness() {
         final Instant twentyFiveSecondsAgo = now.minusSeconds(25);
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(twentyFiveSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=15")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(twentyFiveSecondsAgo)));
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setStaleWhileRevalidate(15)
+                .build();
 
-        assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
+        assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveEmpty() {
-        final Header[] headers = new Header[] {
-                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=")
-        };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
-
-        assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
+        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now,
+                new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)));
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setStaleWhileRevalidate(0)
+                .build();
+
+        assertFalse(impl.mayReturnStaleWhileRevalidating(responseCacheControl, entry, now));
     }
 }
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheableRequestPolicy.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheableRequestPolicy.java
index b14405a86..8a2d088b3 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheableRequestPolicy.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheableRequestPolicy.java
@@ -43,100 +43,106 @@ public class TestCacheableRequestPolicy {
     @Test
     public void testIsGetServableFromCache() {
         final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder().build();
 
-        Assertions.assertTrue(policy.isServableFromCache(request));
+        Assertions.assertTrue(policy.isServableFromCache(cacheControl, request));
     }
 
     @Test
     public void testIsGetWithCacheControlServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
-        request.addHeader("Cache-Control", "no-cache");
-
-        Assertions.assertFalse(policy.isServableFromCache(request));
-
-        request = new BasicHttpRequest("GET", "someUri");
-        request.addHeader("Cache-Control", "no-store");
-        request.addHeader("Cache-Control", "max-age=20");
+        final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder()
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("GET", "someUri");
-        request.addHeader("Cache-Control", "public");
-        request.addHeader("Cache-Control", "no-store, max-age=20");
+        final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
+                .setNoStore(true)
+                .setMaxAge(20)
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request));
     }
 
     @Test
     public void testIsGetWithPragmaServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+        final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
         request.addHeader("Pragma", "no-cache");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder()
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("GET", "someUri");
-        request.addHeader("Pragma", "value1");
-        request.addHeader("Pragma", "value2");
+        final BasicHttpRequest request2 = new BasicHttpRequest("GET", "someUri");
+        request2.addHeader("Pragma", "value1");
+        request2.addHeader("Pragma", "value2");
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request2));
     }
 
     @Test
     public void testIsHeadServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder().build();
 
-        Assertions.assertTrue(policy.isServableFromCache(request));
+        Assertions.assertTrue(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("HEAD", "someUri");
-        request.addHeader("Cache-Control", "public");
-        request.addHeader("Cache-Control", "max-age=20");
+        final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
+                .setMaxAge(20)
+                .build();
 
-        Assertions.assertTrue(policy.isServableFromCache(request));
+        Assertions.assertTrue(policy.isServableFromCache(cacheControl2, request));
     }
 
     @Test
     public void testIsHeadWithCacheControlServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
-        request.addHeader("Cache-Control", "no-cache");
+        final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder()
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("HEAD", "someUri");
         request.addHeader("Cache-Control", "no-store");
         request.addHeader("Cache-Control", "max-age=20");
+        final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
+                .setNoStore(true)
+                .setMaxAge(20)
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
-
-        request = new BasicHttpRequest("HEAD", "someUri");
-        request.addHeader("Cache-Control", "public");
-        request.addHeader("Cache-Control", "no-store, max-age=20");
-
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request));
     }
 
     @Test
     public void testIsHeadWithPragmaServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
-        request.addHeader("Pragma", "no-cache");
+        final BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder()
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("HEAD", "someUri");
-        request.addHeader("Pragma", "value1");
-        request.addHeader("Pragma", "value2");
+        final BasicHttpRequest request2 = new BasicHttpRequest("HEAD", "someUri");
+        request2.addHeader("Pragma", "value1");
+        request2.addHeader("Pragma", "value2");
+        final RequestCacheControl cacheControl2 = RequestCacheControl.builder()
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl2, request2));
     }
 
     @Test
     public void testIsArbitraryMethodServableFromCache() {
-        BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri");
+        final BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri");
+        final RequestCacheControl cacheControl = RequestCacheControl.builder()
+                .build();
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request));
 
-        request = new BasicHttpRequest("get", "someUri");
+        final BasicHttpRequest request2 = new BasicHttpRequest("get", "someUri");
 
-        Assertions.assertFalse(policy.isServableFromCache(request));
+        Assertions.assertFalse(policy.isServableFromCache(cacheControl, request2));
 
     }
 
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedResponseSuitabilityChecker.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedResponseSuitabilityChecker.java
index cf081b43c..de79c737e 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedResponseSuitabilityChecker.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedResponseSuitabilityChecker.java
@@ -32,7 +32,6 @@ import org.apache.hc.client5.http.cache.HeaderConstants;
 import org.apache.hc.client5.http.cache.HttpCacheEntry;
 import org.apache.hc.client5.http.utils.DateUtils;
 import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
@@ -48,9 +47,10 @@ public class TestCachedResponseSuitabilityChecker {
     private Instant tenSecondsAgo;
     private Instant nineSecondsAgo;
 
-    private HttpHost host;
     private HttpRequest request;
     private HttpCacheEntry entry;
+    private RequestCacheControl requestCacheControl;
+    private ResponseCacheControl responseCacheControl;
     private CachedResponseSuitabilityChecker impl;
 
     @BeforeEach
@@ -60,9 +60,10 @@ public class TestCachedResponseSuitabilityChecker {
         tenSecondsAgo = now.minusSeconds(10);
         nineSecondsAgo = now.minusSeconds(9);
 
-        host = new HttpHost("foo.example.com");
         request = new BasicHttpRequest("GET", "/foo");
         entry = HttpTestUtils.makeCacheEntry();
+        requestCacheControl = RequestCacheControl.builder().build();
+        responseCacheControl = ResponseCacheControl.builder().build();
 
         impl = new CachedResponseSuitabilityChecker(CacheConfig.DEFAULT);
     }
@@ -75,117 +76,152 @@ public class TestCachedResponseSuitabilityChecker {
     public void testNotSuitableIfContentLengthHeaderIsWrong() {
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","1")
         };
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testSuitableIfCacheEntryIsFresh() {
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testNotSuitableIfCacheEntryIsNotFresh() {
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .build();
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testNotSuitableIfRequestHasNoCache() {
-        request.addHeader("Cache-Control", "no-cache");
+        requestCacheControl = RequestCacheControl.builder()
+                .setNoCache(true)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testNotSuitableIfAgeExceedsRequestMaxAge() {
-        request.addHeader("Cache-Control", "max-age=10");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMaxAge(10)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testSuitableIfFreshAndAgeIsUnderRequestMaxAge() {
-        request.addHeader("Cache-Control", "max-age=15");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMaxAge(15)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testSuitableIfFreshAndFreshnessLifetimeGreaterThanRequestMinFresh() {
-        request.addHeader("Cache-Control", "min-fresh=10");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMinFresh(10)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testNotSuitableIfFreshnessLifetimeLessThanRequestMinFresh() {
-        request.addHeader("Cache-Control", "min-fresh=10");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMinFresh(10)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=15"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(15)
+                .build();
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testSuitableEvenIfStaleButPermittedByRequestMaxStale() {
-        request.addHeader("Cache-Control", "max-stale=10");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMaxStale(10)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .build();
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
     public void testNotSuitableIfStaleButTooStaleForRequestMaxStale() {
-        request.addHeader("Cache-Control", "max-stale=2");
+        requestCacheControl = RequestCacheControl.builder()
+                .setMaxStale(2)
+                .build();
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=5"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .build();
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -206,7 +242,7 @@ public class TestCachedResponseSuitabilityChecker {
             .setHeuristicCoefficient(0.1f).build();
         impl = new CachedResponseSuitabilityChecker(config);
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -224,7 +260,7 @@ public class TestCachedResponseSuitabilityChecker {
             .build();
         impl = new CachedResponseSuitabilityChecker(config);
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -232,24 +268,28 @@ public class TestCachedResponseSuitabilityChecker {
         final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo");
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = getEntry(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(headRequest, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, headRequest, entry, now));
     }
 
     @Test
     public void testNotSuitableIfRequestMethodIsGETAndEntryResourceIsNull() {
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = HttpTestUtils.makeHeadCacheEntry(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -257,12 +297,14 @@ public class TestCachedResponseSuitabilityChecker {
         impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = HttpTestUtils.makeCacheEntryWithNoRequestMethodOrEntity(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -270,12 +312,14 @@ public class TestCachedResponseSuitabilityChecker {
         impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = HttpTestUtils.makeCacheEntryWithNoRequestMethod(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -283,11 +327,13 @@ public class TestCachedResponseSuitabilityChecker {
         impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600")
         };
         entry = HttpTestUtils.make204CacheEntryWithNoRequestMethod(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 
     @Test
@@ -296,12 +342,14 @@ public class TestCachedResponseSuitabilityChecker {
         impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Content-Length","128")
         };
         entry = HttpTestUtils.makeHeadCacheEntryWithNoRequestMethod(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
 
-        Assertions.assertTrue(impl.canCachedResponseBeUsed(headRequest, entry, now));
+        Assertions.assertTrue(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, headRequest, entry, now));
     }
 
     @Test
@@ -309,11 +357,13 @@ public class TestCachedResponseSuitabilityChecker {
         // Prepare a cache entry with HEAD method
         final Header[] headers = {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("Cache-Control", "max-age=3600"),
                 new BasicHeader("Hc-Request-Method", HeaderConstants.HEAD_METHOD)
         };
         entry = getEntry(headers);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
         // Validate that the cache entry is not suitable for the GET request
-        Assertions.assertFalse(impl.canCachedResponseBeUsed(request, entry, now));
+        Assertions.assertFalse(impl.canCachedResponseBeUsed(requestCacheControl, responseCacheControl, request, entry, now));
     }
 }
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
index 1395f6cc0..07b3c67c9 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
@@ -39,8 +39,8 @@ import java.time.Duration;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.Arrays;
-import java.util.List;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -1498,16 +1498,16 @@ public class TestCachingExecChain {
 
         // Set up the mock response chain
         Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
-        Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any())).thenReturn(true);
-        Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any())).thenReturn(true);
-        Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
+        Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any(), Mockito.any())).thenReturn(true);
+        Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any(), Mockito.any())).thenReturn(true);
+        Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
 
         // Assuming validityPolicy is a Mockito mock
         Mockito.when(validityPolicy.getCurrentAge(Mockito.any(), Mockito.any()))
                 .thenReturn(TimeValue.ofMilliseconds(0));
 
         // Assuming validityPolicy is a Mockito mock
-        Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any()))
+        Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any(), Mockito.any()))
                 .thenReturn(TimeValue.ofMilliseconds(0));
 
         final SimpleHttpResponse response = SimpleHttpResponse.create(HttpStatus.SC_OK);
@@ -1599,16 +1599,16 @@ public class TestCachingExecChain {
 
         // Set up the mock response chain
         Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
-        Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any())).thenReturn(true);
-        Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any())).thenReturn(true);
-        Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
+        Mockito.when(responseCachingPolicy.isStaleIfErrorEnabled(Mockito.any(), Mockito.any())).thenReturn(true);
+        Mockito.when(cacheableRequestPolicy.isServableFromCache(Mockito.any(), Mockito.any())).thenReturn(true);
+        Mockito.when(validityPolicy.getStaleness(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(TimeValue.MAX_VALUE);
 
         // Assuming validityPolicy is a Mockito mock
         Mockito.when(validityPolicy.getCurrentAge(Mockito.any(), Mockito.any()))
                 .thenReturn(TimeValue.ofDays(2));
 
         // Assuming validityPolicy is a Mockito mock
-        Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any()))
+        Mockito.when(validityPolicy.getFreshnessLifetime(Mockito.any(), Mockito.any()))
                 .thenReturn(TimeValue.ofDays(2));
 
         final SimpleHttpResponse response = SimpleHttpResponse.create(HttpStatus.SC_OK);
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestConditionalRequestBuilder.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestConditionalRequestBuilder.java
index ffff6e0fe..3ec083065 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestConditionalRequestBuilder.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestConditionalRequestBuilder.java
@@ -70,7 +70,8 @@ public class TestConditionalRequestBuilder {
                 new BasicHeader("Last-Modified", lastModified) };
 
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
-        final HttpRequest newRequest = impl.buildConditionalRequest(basicRequest, cacheEntry);
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
+        final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
 
         Assertions.assertEquals(theMethod, newRequest.getMethod());
         Assertions.assertEquals(theUri, newRequest.getRequestUri());
@@ -98,7 +99,8 @@ public class TestConditionalRequestBuilder {
         };
         final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
-        final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
+        final HttpRequest result = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
         Assertions.assertEquals(lmDate,
                 result.getFirstHeader("If-Modified-Since").getValue());
         Assertions.assertEquals(etag,
@@ -121,7 +123,8 @@ public class TestConditionalRequestBuilder {
 
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
 
-        final HttpRequest newRequest = impl.buildConditionalRequest(basicRequest, cacheEntry);
+        final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
+        final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
 
         Assertions.assertEquals(theMethod, newRequest.getMethod());
         Assertions.assertEquals(theUri, newRequest.getRequestUri());
@@ -145,14 +148,18 @@ public class TestConditionalRequestBuilder {
 
         final Header[] cacheEntryHeaders = new Header[] {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("ETag", "\"etag\""),
-                new BasicHeader("Cache-Control","max-age=5, must-revalidate") };
+                new BasicHeader("ETag", "\"etag\"")
+        };
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
 
-        final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setMustRevalidate(true)
+                .build();
+        final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
 
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
-        Assertions.assertEquals(0, cacheControl.getMaxAge());
+        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
+        Assertions.assertEquals(0, requestCacheControl.getMaxAge());
     }
 
     @Test
@@ -165,14 +172,18 @@ public class TestConditionalRequestBuilder {
 
         final Header[] cacheEntryHeaders = new Header[] {
                 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
-                new BasicHeader("ETag", "\"etag\""),
-                new BasicHeader("Cache-Control","max-age=5, proxy-revalidate") };
+                new BasicHeader("ETag", "\"etag\"")
+        };
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
 
-        final HttpRequest result = impl.buildConditionalRequest(basicRequest, cacheEntry);
+        final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(5)
+                .setProxyRevalidate(true)
+                .build();
+        final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
 
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
-        Assertions.assertEquals(0, cacheControl.getMaxAge());
+        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
+        Assertions.assertEquals(0, requestCacheControl.getMaxAge());
     }
 
     @Test
@@ -195,8 +206,8 @@ public class TestConditionalRequestBuilder {
     public void testBuildUnconditionalRequestAddsCacheControlNoCache()
         throws Exception {
         final HttpRequest result = impl.buildUnconditionalRequest(request);
-        final RequestCacheControl cacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
-        Assertions.assertTrue(cacheControl.isNoCache());
+        final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
+        Assertions.assertTrue(requestCacheControl.isNoCache());
     }
 
     @Test
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseCachingPolicy.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseCachingPolicy.java
index 00d45b9e5..74de5c73a 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseCachingPolicy.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseCachingPolicy.java
@@ -26,6 +26,9 @@
  */
 package org.apache.hc.client5.http.impl.cache;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.time.Duration;
 import java.time.Instant;
 import java.util.Random;
@@ -38,19 +41,14 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 public class TestResponseCachingPolicy {
 
-    private static final ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1);
     private ResponseCachingPolicy policy;
     private HttpResponse response;
     private HttpRequest request;
@@ -60,6 +58,7 @@ public class TestResponseCachingPolicy {
     private Instant now;
     private Instant tenSecondsFromNow;
     private Instant sixSecondsAgo;
+    private ResponseCacheControl responseCacheControl;
 
     @BeforeEach
     public void setUp() throws Exception {
@@ -72,24 +71,25 @@ public class TestResponseCachingPolicy {
         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
         response.setHeader("Content-Length", "0");
+        responseCacheControl = ResponseCacheControl.builder().build();
     }
 
     @Test
     public void testIsGetCacheable() {
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadCacheable() {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testResponsesToRequestsWithAuthorizationHeadersAreNotCacheableBySharedCache() {
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -97,51 +97,60 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, false, false, false, true);
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testAuthorizedResponsesWithSMaxAgeAreCacheable() {
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        response.setHeader("Cache-Control","s-maxage=3600");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setSharedMaxAge(3600)
+                .build();
+
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testAuthorizedResponsesWithMustRevalidateAreCacheable() {
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        response.setHeader("Cache-Control","must-revalidate");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMustRevalidate(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testAuthorizedResponsesWithCacheControlPublicAreCacheable() {
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        response.setHeader("Cache-Control","public");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testAuthorizedResponsesWithCacheControlMaxAgeAreNotCacheable() {
         request = new BasicHttpRequest("GET","/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
-        response.setHeader("Cache-Control","max-age=3600");
-        Assertions.assertFalse(policy.isResponseCacheable(request,response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(3600)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void test203ResponseCodeIsCacheable() {
         response.setCode(HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION);
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void test206ResponseCodeIsNotCacheable() {
         response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -150,42 +159,42 @@ public class TestResponseCachingPolicy {
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
         response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
-        response.setHeader("Cache-Control", "public");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void test300ResponseCodeIsCacheable() {
         response.setCode(HttpStatus.SC_MULTIPLE_CHOICES);
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void test301ResponseCodeIsCacheable() {
         response.setCode(HttpStatus.SC_MOVED_PERMANENTLY);
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void test410ResponseCodeIsCacheable() {
         response.setCode(HttpStatus.SC_GONE);
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testPlain302ResponseCodeIsNotCacheable() {
         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
         response.removeHeaders("Expires");
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testPlain303ResponseCodeIsNotCacheableUnderDefaultBehavior() {
         response.setCode(HttpStatus.SC_SEE_OTHER);
         response.removeHeaders("Expires");
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -193,8 +202,7 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, true, true);
         response.setCode(HttpStatus.SC_SEE_OTHER);
         response.removeHeaders("Expires");
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
 
@@ -202,8 +210,7 @@ public class TestResponseCachingPolicy {
     public void testPlain307ResponseCodeIsNotCacheable() {
         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
         response.removeHeaders("Expires");
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -211,40 +218,17 @@ public class TestResponseCachingPolicy {
         final int status = getRandomStatus();
         response.setCode(status);
         response.setHeader("Expires", DateUtils.formatStandardDate(Instant.now()));
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithMaxAgeIsCacheable() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "max-age=0");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
-    }
-
-    @Test
-    public void testMalformedHeaderValue() {
-        final int status = getRandomStatus();
-         response.setCode(status);
-        response.setHeader("Cache-Control", "max-age=boom");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
-    }
-
-
-    @Test
-    public void testNullHeaderValue() {
-        final int status = getRandomStatus();
-        response.setCode(status);
-        response.setHeader("Cache-Control", null);
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
-    }
-
-    @Test
-    public void testMultipleHeaderValue() {
-        final int status = getRandomStatus();
-        response.setCode(status);
-        response.setHeader("Cache-Control", "s-maxage=12,must-revalidate=true,max-age=23");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(0)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -252,201 +236,250 @@ public class TestResponseCachingPolicy {
         final int status = getRandomStatus();
         response.setCode(status);
         response.removeHeaders(HttpHeaders.CACHE_CONTROL);
-        final boolean isCacheable = policy.isResponseCacheable("GET", response);
-        Assertions.assertTrue(isCacheable);
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithSMaxAgeIsCacheable() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "s-maxage=0");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setSharedMaxAge(1)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithMustRevalidateIsCacheable() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "must-revalidate");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMustRevalidate(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithProxyRevalidateIsCacheable() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "proxy-revalidate");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setProxyRevalidate(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithPublicCacheControlIsCacheable() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "public");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testNon206WithPrivateCacheControlIsNotCacheableBySharedCache() {
         final int status = getRandomStatus();
         response.setCode(status);
-        response.setHeader("Cache-Control", "private");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePrivate(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void test200ResponseWithPrivateCacheControlIsCacheableByNonSharedCache() {
         policy = new ResponseCachingPolicy(0, false, false, false, true);
         response.setCode(HttpStatus.SC_OK);
-        response.setHeader("Cache-Control", "private");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePrivate(true)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsGetWithNoCacheCacheable() {
-        response.addHeader("Cache-Control", "no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoCacheCacheable() {
-        response.addHeader("Cache-Control", "no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithNoStoreCacheable() {
-        response.addHeader("Cache-Control", "no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoStoreCacheable() {
-        response.addHeader("Cache-Control", "no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithNoStoreEmbeddedInListCacheable() {
-        response.addHeader("Cache-Control", "public, no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoStoreEmbeddedInListCacheable() {
-        response.addHeader("Cache-Control", "public, no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithNoCacheEmbeddedInListCacheable() {
-        response.addHeader("Cache-Control", "public, no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoCacheEmbeddedInListCacheable() {
-        response.addHeader("Cache-Control", "public, no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
-        response.addHeader("Cache-Control", "max-age=20");
-        response.addHeader("Cache-Control", "public, no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(20)
+                .setCachePublic(true)
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
-        response.addHeader("Cache-Control", "max-age=20");
-        response.addHeader("Cache-Control", "public, no-cache");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(20)
+                .setCachePublic(true)
+                .setNoCache(true)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
-        response.addHeader("Cache-Control", "max-age=20");
-        response.addHeader("Cache-Control", "public, no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(20)
+                .setCachePublic(true)
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
-        response.addHeader("Cache-Control", "max-age=20");
-        response.addHeader("Cache-Control", "public, no-store");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(20)
+                .setCachePublic(true)
+                .setNoStore(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithAnyCacheControlCacheable() {
-        response.addHeader("Cache-Control", "max=10");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(10)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
 
         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
-        response.addHeader("Cache-Control", "no-transform");
         response.setHeader("Content-Length", "0");
+        responseCacheControl = ResponseCacheControl.builder()
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithAnyCacheControlCacheable() {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
-        response.addHeader("Cache-Control", "max=10");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(10)
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
 
         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
-        response.addHeader("Cache-Control", "no-transform");
         response.setHeader("Content-Length", "0");
+        responseCacheControl = ResponseCacheControl.builder()
+                .build();
 
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsGetWithout200Cacheable() {
         HttpResponse response404 = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "");
 
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response404));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response404));
 
         response404 = new BasicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "");
 
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response404));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response404));
     }
 
     @Test
     public void testIsHeadWithout200Cacheable() {
         HttpResponse response404 = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "");
 
-        Assertions.assertFalse(policy.isResponseCacheable("HEAD", response404));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "HEAD", response404));
 
         response404 = new BasicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "");
 
-        Assertions.assertFalse(policy.isResponseCacheable("HEAD", response404));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "HEAD", response404));
     }
 
     @Test
     public void testVaryStarIsNotCacheable() {
         response.setHeader("Vary", "*");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -454,30 +487,32 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.setHeader("Vary", "*");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testIsGetWithVaryHeaderCacheable() {
         response.addHeader("Vary", "Accept-Encoding");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testIsHeadWithVaryHeaderCacheable() {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
         response.addHeader("Vary", "Accept-Encoding");
-        Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "HEAD", response));
     }
 
     @Test
     public void testIsArbitraryMethodCacheable() {
 
-        Assertions.assertFalse(policy.isResponseCacheable("PUT", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "PUT", response));
 
-        Assertions.assertFalse(policy.isResponseCacheable("get", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "get", response));
     }
 
     @Test
@@ -487,23 +522,18 @@ public class TestResponseCachingPolicy {
         request = new HttpOptions("http://foo.example.com/");
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
         response.setCode(HttpStatus.SC_NO_CONTENT);
-        response.setHeader("Cache-Control", "public");
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
 
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
-    }
-
-    @Test
-    public void testResponsesToRequestsWithNoStoreAreNotCacheable() {
-        request.setHeader("Cache-Control","no-store");
-        response.setHeader("Cache-Control","public");
-        Assertions.assertTrue(policy.isResponseCacheable(request,response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesWithMultipleAgeHeadersAreNotCacheable() {
         response.addHeader("Age", "3");
         response.addHeader("Age", "5");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -511,17 +541,19 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.addHeader("Age", "3");
         response.addHeader("Age", "5");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesWithMultipleDateHeadersAreNotCacheable() {
         response.addHeader("Date", DateUtils.formatStandardDate(now));
         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -529,16 +561,18 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.addHeader("Date", DateUtils.formatStandardDate(now));
         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesWithMalformedDateHeadersAreNotCacheable() {
         response.addHeader("Date", "garbage");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -546,16 +580,18 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.addHeader("Date", "garbage");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesWithMultipleExpiresHeadersAreNotCacheable() {
         response.addHeader("Expires", DateUtils.formatStandardDate(now));
         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -563,22 +599,24 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.addHeader("Expires", DateUtils.formatStandardDate(now));
         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesWithoutDateHeadersAreNotCacheable() {
         response.removeHeaders("Date");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testResponseThatHasTooMuchContentIsNotCacheable() {
         response.setHeader("Content-Length", "9000");
-        Assertions.assertFalse(policy.isResponseCacheable("GET", response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
@@ -586,41 +624,43 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
 
         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
-        response.setHeader("Cache-Control", "public");
         response.setHeader("Content-Length", "9000");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setCachePublic(true)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesThatAreSmallEnoughAreCacheable() {
         response.setHeader("Content-Length", "0");
-        Assertions.assertTrue(policy.isResponseCacheable("GET", response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, "GET", response));
     }
 
     @Test
     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
         policy = new ResponseCachingPolicy(0, true, true, false, false);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
         policy = new ResponseCachingPolicy(0, true, true, false, false);
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -628,7 +668,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -637,7 +677,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -646,7 +686,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -655,7 +695,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -663,7 +703,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
         response.setVersion(HttpVersion.HTTP_1_0);
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -671,7 +711,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
         response.setVersion(HttpVersion.HTTP_1_0);
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -680,7 +720,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
         response.setVersion(HttpVersion.HTTP_1_0);
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -689,7 +729,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
         response.setVersion(HttpVersion.HTTP_1_0);
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -699,7 +739,7 @@ public class TestResponseCachingPolicy {
         response.setVersion(HttpVersion.HTTP_1_0);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -710,7 +750,7 @@ public class TestResponseCachingPolicy {
         response.setVersion(HttpVersion.HTTP_1_0);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -721,7 +761,7 @@ public class TestResponseCachingPolicy {
         response.setVersion(HttpVersion.HTTP_1_0);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -732,21 +772,21 @@ public class TestResponseCachingPolicy {
         response.setVersion(HttpVersion.HTTP_1_0);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -755,7 +795,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -765,7 +805,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -775,7 +815,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -785,7 +825,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -794,7 +834,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -804,7 +844,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -814,7 +854,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -824,7 +864,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -835,7 +875,7 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.1 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -847,31 +887,32 @@ public class TestResponseCachingPolicy {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
         response.setHeader(HttpHeaders.VIA, "1.1 someproxy");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(now));
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void notCacheableIfExpiresPrecedesDateAndNoCacheControl() {
         response.setHeader("Date", DateUtils.formatStandardDate(now));
         response.setHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
-        response.removeHeaders("Cache-Control");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void test302WithExplicitCachingHeaders() {
         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        response.setHeader("Cache-Control","max-age=300");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(300)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -879,8 +920,10 @@ public class TestResponseCachingPolicy {
         // RFC 2616 says: 303 should not be cached
         response.setCode(HttpStatus.SC_SEE_OTHER);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        response.setHeader("Cache-Control","max-age=300");
-        Assertions.assertFalse(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(300)
+                .build();
+        Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -890,24 +933,30 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, true, true);
         response.setCode(HttpStatus.SC_SEE_OTHER);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        response.setHeader("Cache-Control","max-age=300");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(300)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void test307WithExplicitCachingHeaders() {
         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        response.setHeader("Cache-Control","max-age=300");
-        Assertions.assertTrue(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(300)
+                .build();
+        Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
     public void otherStatusCodesAreCacheableWithExplicitCachingHeaders() {
         response.setCode(HttpStatus.SC_NOT_FOUND);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        response.setHeader("Cache-Control","max-age=300");
-        assertTrue(policy.isResponseCacheable(request, response));
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(300)
+                .build();
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -918,16 +967,13 @@ public class TestResponseCachingPolicy {
 
         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
-       response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
+        response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
 
 
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false, false);
         request = new BasicHttpRequest("POST", "/foo");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertTrue(isCacheable);
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
 
@@ -945,11 +991,10 @@ public class TestResponseCachingPolicy {
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false, false);
         request = new BasicHttpRequest("POST", "/foo");
-        response.addHeader(HttpHeaders.CACHE_CONTROL, "s-maxage=60");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertTrue(isCacheable);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(60)
+                .build();
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -966,11 +1011,10 @@ public class TestResponseCachingPolicy {
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false,false);
         request = new BasicHttpRequest("POST", "/foo");
-        response.addHeader(HttpHeaders.CACHE_CONTROL, "max-age=60");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertTrue(isCacheable);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setMaxAge(60)
+                .build();
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -987,15 +1031,9 @@ public class TestResponseCachingPolicy {
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false,false);
         request = new BasicHttpRequest("POST", "/foo");
-        response.addHeader(HttpHeaders.CACHE_CONTROL, "something");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertTrue(isCacheable);
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
-
-
     private int getRandomStatus() {
         final int rnd = new Random().nextInt(acceptableCodes.length);
 
@@ -1010,7 +1048,7 @@ public class TestResponseCachingPolicy {
         policy = new ResponseCachingPolicy(0, true, false, false, true);
         response.setCode(HttpStatus.SC_OK);
         response.setHeader("Date", DateUtils.formatStandardDate(now));
-        assertTrue(policy.isResponseCacheable(request, response));
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -1022,11 +1060,10 @@ public class TestResponseCachingPolicy {
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false, false);
         request = new BasicHttpRequest("GET", "/foo");
-        response.addHeader(HttpHeaders.CACHE_CONTROL, "no-cache");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertTrue(isCacheable);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoCache(true)
+                .build();
+        assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 
     @Test
@@ -1038,10 +1075,9 @@ public class TestResponseCachingPolicy {
         // Create ResponseCachingPolicy instance and test the method
         policy = new ResponseCachingPolicy(0, true, false, false, false);
         request = new BasicHttpRequest("GET", "/foo");
-        response.addHeader(HttpHeaders.CACHE_CONTROL, "no-store");
-        final boolean isCacheable = policy.isResponseCacheable(request, response);
-
-        // Verify the result
-        assertFalse(isCacheable);
+        responseCacheControl = ResponseCacheControl.builder()
+                .setNoStore(true)
+                .build();
+        assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
     }
 }
\ No newline at end of file