Resource Load Statistics: Remove cap on partitioned cache max age if it matches a...
authorwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Nov 2018 23:10:36 +0000 (23:10 +0000)
committerwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Nov 2018 23:10:36 +0000 (23:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189760
<rdar://problem/44612242>

Reviewed by Youenn Fablet and Antti Koivisto.

Source/WebCore:

No new tests. Existing test fleshed out.

* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::isRedirection const):
* platform/network/ResourceResponseBase.h:
(WebCore::ResourceResponseBase::isRedirection const): Deleted.
    Moved to the implementation file so that I can export it without warning.

Source/WebKit:

When a redirect cache entry for a prevalent resource reaches its max
age cap, it is loaded again from the network and the network response
is compared with what's in the cache. If it's a match, the cache entry
is fully accepted. If not, a new capped cache entry is created.

This feature is still off by default.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::canUseCachedRedirect const):
    Now checks the new member m_cacheEntryForMaxAgeCapValidation.
(WebKit::NetworkResourceLoader::retrieveCacheEntry):
    New case handled for entry->hasReachedPrevalentResourceAgeCap().
(WebKit::NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation):
    This is where the new logic compares the incoming redirect with the
    cached one. If they match, an uncapped entry is allowed to be stored.
    If they don't match, a new capped entry will be stored.
(WebKit::NetworkResourceLoader::willSendRedirectedRequest):
    Now calls the new
    NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation()
    function.
* NetworkProcess/NetworkResourceLoader.h:
    Added the m_cacheEntryForMaxAgeCapValidation member.
* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::makeUseDecision):
    Restored to previous behavior which means
    UseDecision::NoDueToPrevalentResourceAgeCap was removed.
(WebKit::NetworkCache::Cache::retrieve):
    Restored to previous behavior.
(WebKit::NetworkCache::Cache::storeRedirect):
    Now takes the optional maxAgeCap and caps the entry's max age if it's set.
(WebKit::NetworkCache::hasReachedPrevalentResourceAgeCap): Deleted.
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheEntry.cpp:
(WebKit::NetworkCache::Entry::encodeAsStorageRecord const):
    Now encodes m_maxAgeCap.
(WebKit::NetworkCache::Entry::decodeStorageRecord):
    Now decodes m_maxAgeCap.
(WebKit::NetworkCache::Entry::hasReachedPrevalentResourceAgeCap const):
    Added.
(WebKit::NetworkCache::Entry::capMaxAge):
    Added.
* NetworkProcess/cache/NetworkCacheEntry.h:
    Added the optional m_maxAgeCap.
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:
(WebKit::NetworkCache::SpeculativeLoad::willSendRedirectedRequest):
    Now gets the optional max age cap from the NetworkStorageSession and sends it
    to Cache::storeRedirect().
* NetworkProcess/cache/NetworkCacheStatistics.cpp:
(WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
    Removed handling of UseDecision::NoDueToPrevalentResourceAgeCap.

LayoutTests:

* http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt:
* http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html:
    The test now performs:
    - an initial Fetch request with a permanent redirect to ID 1234. Capped max age.
    - a second Fetch request with a permanent redirect to ID 4321. Capped max age.
    - a third Fetch request with a permanent redirect to and empty ID. Capped max age.
    - a fourth Fetch request with a permanent redirect to and empty ID. Max age cap removed.
    - a fifth Fetch request with a permanent redirect to and empty ID. Regular cache hit.
* http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php:
    Now returns an HTTP 500 if the request contains validation headers.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237895 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt
LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html
LayoutTests/http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php
Source/WebCore/ChangeLog
Source/WebCore/platform/network/ResourceResponseBase.cpp
Source/WebCore/platform/network/ResourceResponseBase.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoader.h
Source/WebKit/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit/NetworkProcess/cache/NetworkCache.h
Source/WebKit/NetworkProcess/cache/NetworkCacheEntry.cpp
Source/WebKit/NetworkProcess/cache/NetworkCacheEntry.h
Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp
Source/WebKit/NetworkProcess/cache/NetworkCacheStatistics.cpp

index 10d52f9..b8ae216 100644 (file)
@@ -1,3 +1,22 @@
+2018-11-06  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Remove cap on partitioned cache max age if it matches a network reload (redirect-only)
+        https://bugs.webkit.org/show_bug.cgi?id=189760
+        <rdar://problem/44612242>
+
+        Reviewed by Youenn Fablet and Antti Koivisto.
+
+        * http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt:
+        * http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html:
+            The test now performs:
+            - an initial Fetch request with a permanent redirect to ID 1234. Capped max age.
+            - a second Fetch request with a permanent redirect to ID 4321. Capped max age.
+            - a third Fetch request with a permanent redirect to and empty ID. Capped max age.
+            - a fourth Fetch request with a permanent redirect to and empty ID. Max age cap removed.
+            - a fifth Fetch request with a permanent redirect to and empty ID. Regular cache hit.
+        * http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php:
+            Now returns an HTTP 500 if the request contains validation headers.
+
 2018-11-06  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Spelling dots are drawn in the wrong place
index 63c6069..0cce5aa 100644 (file)
@@ -4,6 +4,9 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS loadedUrl is "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=1234"
+PASS loadedUrl is "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=4321"
+PASS loadedUrl is "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value="
+PASS loadedUrl is "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value="
 PASS loadedUrl is "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value="
 PASS successfullyParsed is true
 
index 08b82bb..178004b 100644 (file)
     }
 
     function secondFetch() {
-        // This should not trigger a successful cache hit.
+        // This should not trigger a successful cache hit and instead create another capped cache entry.
         fetch("http://localhost:8000/resourceLoadStatistics/resources/cached-permanent-redirect.php",
             {
                 cache: "force-cache",
+                headers: {
+                    "X-WebKit": "4321",
+                }
+            }
+        ).then(function(response) {
+            loadedUrl = response.url;
+            shouldBeEqualToString("loadedUrl", "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=4321");
+            thirdFetch();
+        }).catch(function(error) {
+            testFailed(error.message);
+            setEnableFeature(false, finishJSTest);
+        });
+    }
+
+    function thirdFetch() {
+        // This should not trigger a successful cache hit and instead create another capped cache entry.
+        fetch("http://localhost:8000/resourceLoadStatistics/resources/cached-permanent-redirect.php",
+            {
+                cache: "force-cache",
+            }
+        ).then(function(response) {
+            loadedUrl = response.url;
+            shouldBeEqualToString("loadedUrl", "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=");
+            fourthFetch();
+        }).catch(function(error) {
+            testFailed(error.message);
+            setEnableFeature(false, finishJSTest);
+        });
+    }
+
+    function fourthFetch() {
+        // This should not trigger a successful cache hit but clear capping.
+        fetch("http://localhost:8000/resourceLoadStatistics/resources/cached-permanent-redirect.php",
+            {
+                cache: "force-cache",
+            }
+        ).then(function(response) {
+            loadedUrl = response.url;
+            shouldBeEqualToString("loadedUrl", "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=");
+            fifthFetch();
+        }).catch(function(error) {
+            testFailed(error.message);
+            setEnableFeature(false, finishJSTest);
+        });
+    }
+
+    function fifthFetch() {
+        // This should trigger a regular, successful cache hit.
+        fetch("http://localhost:8000/resourceLoadStatistics/resources/cached-permanent-redirect.php",
+            {
+                headers: {
+                    "X-WebKit": "1234",
+                }
             }
         ).then(function(response) {
             loadedUrl = response.url;
index 947ed3b..7d2d04a 100644 (file)
@@ -1,11 +1,15 @@
 <?php
+if (isset($_SERVER["HTTP_IF_NONE_MATCH"]) || isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
+    header($_SERVER["SERVER_PROTOCOL"] . " 500 Internal Server Error", true, 500);
+    exit;
+}
 header("Access-Control-Allow-Origin: http://127.0.0.1:8000");
 header("Access-Control-Allow-Headers: X-WebKit");
 if ($_SERVER["REQUEST_METHOD"] == "OPTIONS" && isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]) && $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] == "GET") {
-  exit;
+    exit;
 }
 $headerStringValue = $_SERVER["HTTP_X_WEBKIT"];
-header("HTTP/1.1 301 Moved Permanently");
+header($_SERVER["SERVER_PROTOCOL"] . " 301 Moved Permanently", true, 301);
 header("Cache-Control: private, max-age=31536000", true);
 header('ETag: "WebKitTest"', true);
 header("Location: http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=" . $headerStringValue);
index 9fcd6e3..c484b88 100644 (file)
@@ -1,3 +1,19 @@
+2018-11-06  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Remove cap on partitioned cache max age if it matches a network reload (redirect-only)
+        https://bugs.webkit.org/show_bug.cgi?id=189760
+        <rdar://problem/44612242>
+
+        Reviewed by Youenn Fablet and Antti Koivisto.
+
+        No new tests. Existing test fleshed out.
+
+        * platform/network/ResourceResponseBase.cpp:
+        (WebCore::ResourceResponseBase::isRedirection const):
+        * platform/network/ResourceResponseBase.h:
+        (WebCore::ResourceResponseBase::isRedirection const): Deleted.
+            Moved to the implementation file so that I can export it without warning.
+
 2018-11-06  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Spelling dots are drawn in the wrong place
index ab7b2e1..7667219 100644 (file)
@@ -296,6 +296,11 @@ void ResourceResponseBase::setHTTPStatusCode(int statusCode)
     // FIXME: Should invalidate or update platform response if present.
 }
 
+bool ResourceResponseBase::isRedirection() const
+{
+    return isRedirectionStatusCode(m_httpStatusCode);
+}
+
 const String& ResourceResponseBase::httpStatusText() const 
 {
     lazyInit(AllFields);
index d8fcc14..6fca6b7 100644 (file)
@@ -91,7 +91,7 @@ public:
 
     WEBCORE_EXPORT int httpStatusCode() const;
     WEBCORE_EXPORT void setHTTPStatusCode(int);
-    bool isRedirection() const { return isRedirectionStatusCode(m_httpStatusCode); }
+    WEBCORE_EXPORT bool isRedirection() const;
 
     WEBCORE_EXPORT const String& httpStatusText() const;
     WEBCORE_EXPORT void setHTTPStatusText(const String&);
index 8d2f494..4b7e770 100644 (file)
@@ -1,3 +1,62 @@
+2018-11-06  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Remove cap on partitioned cache max age if it matches a network reload (redirect-only)
+        https://bugs.webkit.org/show_bug.cgi?id=189760
+        <rdar://problem/44612242>
+
+        Reviewed by Youenn Fablet and Antti Koivisto.
+
+        When a redirect cache entry for a prevalent resource reaches its max
+        age cap, it is loaded again from the network and the network response
+        is compared with what's in the cache. If it's a match, the cache entry
+        is fully accepted. If not, a new capped cache entry is created.
+
+        This feature is still off by default.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::canUseCachedRedirect const):
+            Now checks the new member m_cacheEntryForMaxAgeCapValidation.
+        (WebKit::NetworkResourceLoader::retrieveCacheEntry):
+            New case handled for entry->hasReachedPrevalentResourceAgeCap().
+        (WebKit::NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation):
+            This is where the new logic compares the incoming redirect with the
+            cached one. If they match, an uncapped entry is allowed to be stored.
+            If they don't match, a new capped entry will be stored.
+        (WebKit::NetworkResourceLoader::willSendRedirectedRequest):
+            Now calls the new
+            NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation()
+            function.
+        * NetworkProcess/NetworkResourceLoader.h:
+            Added the m_cacheEntryForMaxAgeCapValidation member.
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::makeUseDecision):
+            Restored to previous behavior which means
+            UseDecision::NoDueToPrevalentResourceAgeCap was removed.
+        (WebKit::NetworkCache::Cache::retrieve):
+            Restored to previous behavior.
+        (WebKit::NetworkCache::Cache::storeRedirect):
+            Now takes the optional maxAgeCap and caps the entry's max age if it's set.
+        (WebKit::NetworkCache::hasReachedPrevalentResourceAgeCap): Deleted.
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheEntry.cpp:
+        (WebKit::NetworkCache::Entry::encodeAsStorageRecord const):
+            Now encodes m_maxAgeCap.
+        (WebKit::NetworkCache::Entry::decodeStorageRecord):
+            Now decodes m_maxAgeCap.
+        (WebKit::NetworkCache::Entry::hasReachedPrevalentResourceAgeCap const):
+            Added.
+        (WebKit::NetworkCache::Entry::capMaxAge):
+            Added.
+        * NetworkProcess/cache/NetworkCacheEntry.h:
+            Added the optional m_maxAgeCap.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:
+        (WebKit::NetworkCache::SpeculativeLoad::willSendRedirectedRequest):
+            Now gets the optional max age cap from the NetworkStorageSession and sends it
+            to Cache::storeRedirect().
+        * NetworkProcess/cache/NetworkCacheStatistics.cpp:
+        (WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
+            Removed handling of UseDecision::NoDueToPrevalentResourceAgeCap.
+
 2018-11-06  Per Arne Vollan  <pvollan@apple.com>
 
         REGRESSION (r230523): Caps lock indicator not shown in password field
index ecc047f..55bbdce 100644 (file)
@@ -51,6 +51,7 @@
 #include <WebCore/HTTPHeaderNames.h>
 #include <WebCore/HTTPParsers.h>
 #include <WebCore/NetworkLoadMetrics.h>
+#include <WebCore/NetworkStorageSession.h>
 #include <WebCore/ProtectionSpace.h>
 #include <WebCore/SameSiteInfo.h>
 #include <WebCore/SecurityOrigin.h>
@@ -154,7 +155,7 @@ bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
 
 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
 {
-    if (!canUseCache(request))
+    if (!canUseCache(request) || m_cacheEntryForMaxAgeCapValidation)
         return false;
     // Limit cached redirects to avoid cycles and other trouble.
     // Networking layer follows over 30 redirects but caching that many seems unnecessary.
@@ -216,7 +217,7 @@ void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
     ASSERT(canUseCache(request));
 
     RefPtr<NetworkResourceLoader> loader(this);
-    m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, sessionID(), [this, loader = WTFMove(loader), request = ResourceRequest { request }](auto entry, auto info) mutable {
+    m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [this, loader = WTFMove(loader), request = ResourceRequest { request }](auto entry, auto info) mutable {
         if (loader->hasOneRef()) {
             // The loader has been aborted and is only held alive by this lambda.
             return;
@@ -229,6 +230,15 @@ void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
             loader->startNetworkLoad(WTFMove(request), FirstLoad::Yes);
             return;
         }
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+        if (entry->hasReachedPrevalentResourceAgeCap()) {
+            RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource has reached prevalent resource age cap (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
+            m_cacheEntryForMaxAgeCapValidation = WTFMove(entry);
+            ResourceRequest revalidationRequest = originalRequest();
+            loader->startNetworkLoad(WTFMove(revalidationRequest), FirstLoad::Yes);
+            return;
+        }
+#endif
         if (entry->redirectRequest()) {
             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Handling redirect (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
             loader->dispatchWillSendRequestForCacheEntry(WTFMove(request), WTFMove(entry));
@@ -584,12 +594,35 @@ void NetworkResourceLoader::didBlockAuthenticationChallenge()
     send(Messages::WebResourceLoader::DidBlockAuthenticationChallenge());
 }
 
+std::optional<Seconds> NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation(const ResourceRequest& request, const ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    bool existingCacheEntryMatchesNewResponse = false;
+    if (m_cacheEntryForMaxAgeCapValidation) {
+        ASSERT(redirectResponse.source() == ResourceResponse::Source::Network);
+        ASSERT(redirectResponse.isRedirection());
+        if (redirectResponse.httpHeaderField(WebCore::HTTPHeaderName::Location) == m_cacheEntryForMaxAgeCapValidation->response().httpHeaderField(WebCore::HTTPHeaderName::Location))
+            existingCacheEntryMatchesNewResponse = true;
+
+        m_cache->remove(m_cacheEntryForMaxAgeCapValidation->key());
+        m_cacheEntryForMaxAgeCapValidation = nullptr;
+    }
+    
+    if (!existingCacheEntryMatchesNewResponse) {
+        if (auto networkStorageSession = WebCore::NetworkStorageSession::storageSession(sessionID()))
+            return networkStorageSession->maxAgeCacheCap(request);
+    }
+#endif
+    return std::nullopt;
+}
+
 void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
 {
     ++m_redirectCount;
 
+    auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, redirectRequest, redirectResponse);
     if (redirectResponse.source() == ResourceResponse::Source::Network && canUseCachedRedirect(request))
-        m_cache->storeRedirect(request, redirectResponse, redirectRequest);
+        m_cache->storeRedirect(request, redirectResponse, redirectRequest, maxAgeCap);
 
     if (m_networkLoadChecker) {
         m_networkLoadChecker->storeRedirectionIfNeeded(request, redirectResponse);
index afb0e9c..2f67eae 100644 (file)
@@ -174,6 +174,8 @@ private:
 
     void logSlowCacheRetrieveIfNeeded(const NetworkCache::Cache::RetrieveInfo&);
 
+    std::optional<Seconds> validateCacheEntryForMaxAgeCapValidation(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse&);
+
     const NetworkResourceLoadParameters m_parameters;
 
     Ref<NetworkConnectionToWebProcess> m_connection;
@@ -202,6 +204,7 @@ private:
     RefPtr<NetworkCache::Cache> m_cache;
     RefPtr<WebCore::SharedBuffer> m_bufferedDataForCache;
     std::unique_ptr<NetworkCache::Entry> m_cacheEntryForValidation;
+    std::unique_ptr<NetworkCache::Entry> m_cacheEntryForMaxAgeCapValidation;
     bool m_isWaitingContinueWillSendRequestForCachedRedirect { false };
     std::unique_ptr<NetworkCache::Entry> m_cacheEntryWaitingForContinueDidReceiveResponse;
     std::unique_ptr<NetworkLoadChecker> m_networkLoadChecker;
index ac5edf7..abe98ef 100644 (file)
@@ -152,11 +152,6 @@ static bool cachePolicyAllowsExpired(WebCore::ResourceRequestCachePolicy policy)
     return false;
 }
 
-static bool hasReachedPrevalentResourceAgeCap(const WebCore::ResourceResponse& response, WallTime timestamp, const Seconds maxAge)
-{
-    return WebCore::computeCurrentAge(response, timestamp) > maxAge;
-}
-
 static bool responseHasExpired(const WebCore::ResourceResponse& response, WallTime timestamp, std::optional<Seconds> maxStale)
 {
     if (response.cacheControlContainsNoCache())
@@ -188,11 +183,8 @@ static bool responseNeedsRevalidation(const WebCore::ResourceResponse& response,
     return responseHasExpired(response, timestamp, requestDirectives.maxStale);
 }
 
-static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request, std::optional<Seconds> maxAge)
+static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request)
 {
-    if (maxAge && hasReachedPrevalentResourceAgeCap(entry.response(), entry.timeStamp(), maxAge.value()))
-        return UseDecision::NoDueToPrevalentResourceAgeCap;
-    
     // The request is conditional so we force revalidation from the network. We merely check the disk cache
     // so we can update the cache entry.
     if (request.isConditional() && !entry.redirectRequest())
@@ -279,7 +271,7 @@ static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalR
     return StoreDecision::Yes;
 }
 
-void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, PAL::SessionID sessionID, RetrieveCompletionHandler&& completionHandler)
+void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, RetrieveCompletionHandler&& completionHandler)
 {
     ASSERT(request.url().protocolIsInHTTPFamily());
 
@@ -323,7 +315,7 @@ void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameI
     }
 #endif
 
-    m_storage->retrieve(storageKey, priority, [this, protectedThis = makeRef(*this), request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, frameID, sessionID](auto record, auto timings) mutable {
+    m_storage->retrieve(storageKey, priority, [this, protectedThis = makeRef(*this), request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, frameID](auto record, auto timings) mutable {
         info.storageTimings = timings;
 
         if (!record) {
@@ -340,22 +332,13 @@ void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameI
 
         auto entry = Entry::decodeStorageRecord(*record);
 
-        std::optional<Seconds> maxAgeCap;
-#if ENABLE(RESOURCE_LOAD_STATISTICS)
-        if (auto networkStorageSession = WebCore::NetworkStorageSession::storageSession(sessionID))
-            maxAgeCap = networkStorageSession->maxAgeCacheCap(request);
-#endif
-        auto useDecision = entry ? makeUseDecision(*entry, request, maxAgeCap) : UseDecision::NoDueToDecodeFailure;
+        auto useDecision = entry ? makeUseDecision(*entry, request) : UseDecision::NoDueToDecodeFailure;
         switch (useDecision) {
         case UseDecision::Use:
             break;
         case UseDecision::Validate:
             entry->setNeedsValidation(true);
             break;
-        case UseDecision::NoDueToPrevalentResourceAgeCap:
-            entry = nullptr;
-            m_storage->remove(storageKey);
-            break;
         default:
             entry = nullptr;
         };
@@ -430,7 +413,7 @@ std::unique_ptr<Entry> Cache::store(const WebCore::ResourceRequest& request, con
     return cacheEntry;
 }
 
-std::unique_ptr<Entry> Cache::storeRedirect(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& redirectRequest)
+std::unique_ptr<Entry> Cache::storeRedirect(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& redirectRequest, std::optional<Seconds> maxAgeCap)
 {
     LOG(NetworkCache, "(NetworkProcess) storing redirect %s -> %s", request.url().string().latin1().data(), redirectRequest.url().string().latin1().data());
 
@@ -445,6 +428,16 @@ std::unique_ptr<Entry> Cache::storeRedirect(const WebCore::ResourceRequest& requ
     }
 
     auto cacheEntry = makeRedirectEntry(request, response, redirectRequest);
+
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    if (maxAgeCap) {
+        LOG(NetworkCache, "(NetworkProcess) capping max age for redirect %s -> %s", request.url().string().latin1().data(), redirectRequest.url().string().latin1().data());
+        cacheEntry->capMaxAge(maxAgeCap.value());
+    }
+#else
+    UNUSED_PARAM(maxAgeCap);
+#endif
+
     auto record = cacheEntry->encodeAsStorageRecord();
 
     m_storage->store(record, nullptr);
index f15ad6b..b66e32d 100644 (file)
@@ -31,6 +31,7 @@
 #include <WebCore/ResourceResponse.h>
 #include <wtf/Function.h>
 #include <wtf/OptionSet.h>
+#include <wtf/Seconds.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -81,8 +82,7 @@ enum class UseDecision {
     NoDueToVaryingHeaderMismatch,
     NoDueToMissingValidatorFields,
     NoDueToDecodeFailure,
-    NoDueToExpiredRedirect,
-    NoDueToPrevalentResourceAgeCap
+    NoDueToExpiredRedirect
 };
 
 using GlobalFrameID = std::pair<uint64_t /*webPageID*/, uint64_t /*webFrameID*/>;
@@ -113,9 +113,9 @@ public:
         WTF_MAKE_FAST_ALLOCATED;
     };
     using RetrieveCompletionHandler = Function<void (std::unique_ptr<Entry>, const RetrieveInfo&)>;
-    void retrieve(const WebCore::ResourceRequest&, const GlobalFrameID&, PAL::SessionID, RetrieveCompletionHandler&&);
+    void retrieve(const WebCore::ResourceRequest&, const GlobalFrameID&, RetrieveCompletionHandler&&);
     std::unique_ptr<Entry> store(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, Function<void (MappedBody&)>&&);
-    std::unique_ptr<Entry> storeRedirect(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, const WebCore::ResourceRequest& redirectRequest);
+    std::unique_ptr<Entry> storeRedirect(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, const WebCore::ResourceRequest& redirectRequest, std::optional<Seconds> maxAgeCap);
     std::unique_ptr<Entry> update(const WebCore::ResourceRequest&, const GlobalFrameID&, const Entry&, const WebCore::ResourceResponse& validatingResponse);
 
     struct TraversalEntry {
@@ -156,6 +156,8 @@ private:
     String dumpFilePath() const;
     void deleteDumpFile();
 
+    std::optional<Seconds> maxAgeCap(Entry&, const WebCore::ResourceRequest&, PAL::SessionID);
+
     Ref<Storage> m_storage;
 
 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
index ae1188a..226a421 100644 (file)
@@ -95,6 +95,8 @@ Storage::Record Entry::encodeAsStorageRecord() const
     if (isRedirect)
         m_redirectRequest->encodeWithoutPlatformData(encoder);
 
+    encoder << m_maxAgeCap;
+    
     encoder.encodeChecksum();
 
     Data header(encoder.buffer(), encoder.bufferSize());
@@ -133,6 +135,8 @@ std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storage
             return nullptr;
     }
 
+    decoder.decode(entry->m_maxAgeCap);
+    
     if (!decoder.verifyChecksum()) {
         LOG(NetworkCache, "(NetworkProcess) checksum verification failure\n");
         return nullptr;
@@ -141,6 +145,18 @@ std::unique_ptr<Entry> Entry::decodeStorageRecord(const Storage::Record& storage
     return entry;
 }
 
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+bool Entry::hasReachedPrevalentResourceAgeCap() const
+{
+    return m_maxAgeCap && WebCore::computeCurrentAge(response(), timeStamp()) > m_maxAgeCap;
+}
+
+void Entry::capMaxAge(const Seconds seconds)
+{
+    m_maxAgeCap = seconds;
+}
+#endif
+
 #if ENABLE(SHAREABLE_RESOURCE)
 void Entry::initializeShareableResourceHandleFromStorageRecord() const
 {
index 53edef7..deda86a 100644 (file)
@@ -31,6 +31,7 @@
 #include <WebCore/ResourceRequest.h>
 #include <WebCore/ResourceResponse.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/Seconds.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -70,6 +71,11 @@ public:
 
     void asJSON(StringBuilder&, const Storage::RecordInfo&) const;
 
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    bool hasReachedPrevalentResourceAgeCap() const;
+    void capMaxAge(const Seconds);
+#endif
+
 private:
     void initializeBufferFromStorageRecord() const;
 #if ENABLE(SHAREABLE_RESOURCE)
@@ -88,6 +94,8 @@ private:
 #endif
 
     Storage::Record m_sourceStorageRecord { };
+    
+    std::optional<Seconds> m_maxAgeCap;
 };
 
 }
index 7b40ab1..6fad859 100644 (file)
@@ -33,6 +33,7 @@
 #include "NetworkLoad.h"
 #include "NetworkSession.h"
 #include "SessionTracker.h"
+#include <WebCore/NetworkStorageSession.h>
 #include <pal/SessionID.h>
 #include <wtf/RunLoop.h>
 
@@ -71,7 +72,12 @@ void SpeculativeLoad::willSendRedirectedRequest(ResourceRequest&& request, Resou
 {
     LOG(NetworkCacheSpeculativePreloading, "Speculative redirect %s -> %s", request.url().string().utf8().data(), redirectRequest.url().string().utf8().data());
 
-    m_cacheEntry = m_cache->storeRedirect(request, redirectResponse, redirectRequest);
+    std::optional<Seconds> maxAgeCap;
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    if (auto networkStorageSession = WebCore::NetworkStorageSession::storageSession(PAL::SessionID::defaultSessionID()))
+        maxAgeCap = networkStorageSession->maxAgeCacheCap(request);
+#endif
+    m_cacheEntry = m_cache->storeRedirect(request, redirectResponse, redirectRequest, maxAgeCap);
     // Create a synthetic cache entry if we can't store.
     if (!m_cacheEntry)
         m_cacheEntry = m_cache->makeRedirectEntry(request, redirectResponse, redirectRequest);
index a155e9f..a3780c5 100644 (file)
@@ -282,8 +282,6 @@ static String cachedEntryReuseFailureToDiagnosticKey(UseDecision decision)
         return WebCore::DiagnosticLoggingKeys::missingValidatorFieldsKey();
     case UseDecision::NoDueToDecodeFailure:
     case UseDecision::NoDueToExpiredRedirect:
-    case UseDecision::NoDueToPrevalentResourceAgeCap:
-        return WebCore::DiagnosticLoggingKeys::otherKey();
     case UseDecision::Use:
     case UseDecision::Validate:
         ASSERT_NOT_REACHED();