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()) {
                LOG.debug("Protocol version {} is non-cacheable", version);
            }
            return false;
        }

        // Presently only GET and HEAD methods are supported
        final String httpMethod = request.getMethod();
        if (!Method.GET.isSame(httpMethod) && !Method.HEAD.isSame(httpMethod)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} method response is not cacheable", httpMethod);
            }
            return false;
        }

        final int code = response.getCode();

        // Should never happen but better be defensive
        if (code <= HttpStatus.SC_INFORMATIONAL) {
            return false;
        }

        if (isKnownNonCacheableStatusCode(code)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} response is not cacheable", code);
            }
            return false;
        }

        if (request.getPath().contains("?")) {
            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(cacheControl, response)) {
                LOG.debug("Response is not cacheable as it is missing explicit caching headers");
                return false;
            }
        }

        if (cacheControl.isMustUnderstand() && !understoodStatusCode(code)) {
            // must-understand cache directive overrides no-store
            LOG.debug("Response contains a status code that the cache does not understand, so it's not cacheable");
            return false;
        }

        if (isExplicitlyNonCacheable(cacheControl)) {
            LOG.debug("Response is explicitly non-cacheable per cache control directive");
            return false;
        }

        if (sharedCache) {
            if (request.containsHeader(HttpHeaders.AUTHORIZATION) &&
                    cacheControl.getSharedMaxAge() == -1 &&
                    !(cacheControl.isPublic() || cacheControl.isMustRevalidate())) {
                LOG.debug("Request contains private credentials");
                return false;
            }
        }

        // See if the response is tainted
        if (response.countHeaders(HttpHeaders.EXPIRES) > 1) {
            LOG.debug("Multiple Expires headers");
            return false;
        }

        if (response.countHeaders(HttpHeaders.DATE) > 1) {
            LOG.debug("Multiple Date headers");
            return false;
        }

        final Instant responseDate = DateUtils.parseStandardDate(response, HttpHeaders.DATE);
        final Instant responseExpires = DateUtils.parseStandardDate(response, HttpHeaders.EXPIRES);

        if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(cacheControl, responseDate, responseExpires)) {
            LOG.debug("Expires header less or equal to Date header and no cache control directives");
            return false;
        }

        // Treat responses with `Vary: *` as essentially non-cacheable.
        final Iterator<String> it = MessageSupport.iterateTokens(response, HttpHeaders.VARY);
        while (it.hasNext()) {
            final String token = it.next();
            if ("*".equals(token)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Vary: * found");
                }
                return false;
            }
        }

        return isExplicitlyCacheable(cacheControl, response) || isHeuristicallyCacheable(cacheControl, code, responseDate, responseExpires);
    }
Determine if the {@link HttpResponse} gotten from the origin is a
cacheable response.

@return {@code true} if response is cacheable
httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java