Resource Load Statistics: Add optional cap on partitioned cache max age
authorwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 19:19:56 +0000 (19:19 +0000)
committerwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 19:19:56 +0000 (19:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189711
<rdar://problem/39246837>

Reviewed by Antti Koivisto and Chris Dumez.

Source/WebCore:

Test: http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html

* platform/network/NetworkStorageSession.h:
* platform/network/cf/NetworkStorageSessionCFNet.cpp:
(WebCore::NetworkStorageSession::maxAgeCacheCap):
    Checks if a max age cap is set and returns it if the request
    represents a prevalent resource.
(WebCore::NetworkStorageSession::setCacheMaxAgeCapForPrevalentResources):
(WebCore::NetworkStorageSession::resetCacheMaxAgeCapForPrevalentResources):
    New functionality to receive a max age cap setting in the session.

Source/WebKit:

These changes add the capability to set a max age cap for prevalent resources
and consults it when retrieving cache entries. If an entry is capped and found
to be too old, it will not be used but instead removed from the cache.

This functionality is off by default because no cap is set by default.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::setCacheMaxAgeCapForPrevalentResources):
(WebKit::NetworkProcess::resetCacheMaxAgeCapForPrevalentResources):
    Infrastructure for testing.
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::retrieveCacheEntry):
    Now sends in the session ID in the retrieve call.
* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::hasReachedPrevalentResourceAgeCap):
    Static convenience function.
(WebKit::NetworkCache::makeUseDecision):
    Now receives an optional maxAge parameter and checks
    hasReachedPrevalentResourceAgeCap() first.
(WebKit::NetworkCache::Cache::retrieve):
    Now takes a session ID.
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheStatistics.cpp:
(WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
    Added UseDecision::NoDueToPrevalentResourceAgeCap which causes a
    return of WebCore::DiagnosticLoggingKeys::otherKey().
* UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
(WKWebsiteDataStoreSetStatisticsCacheMaxAgeCap):
(WKWebsiteDataStoreStatisticsResetToConsistentState):
    Infrastructure for testing.
* UIProcess/API/C/WKWebsiteDataStoreRef.h:
* UIProcess/Cocoa/ResourceLoadStatisticsMemoryStoreCocoa.mm:
(WebKit::ResourceLoadStatisticsMemoryStore::registerUserDefaultsIfNeeded):
    Now supports a user default ResourceLoadStatisticsCacheMaxAgeCap.
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::hasStorageAccessForFrame):
(WebKit::NetworkProcessProxy::grantStorageAccess):
(WebKit::NetworkProcessProxy::removeAllStorageAccess):
(WebKit::NetworkProcessProxy::getAllStorageAccessEntries):
(WebKit::NetworkProcessProxy::setCacheMaxAgeCapForPrevalentResources):
(WebKit::NetworkProcessProxy::didSetCacheMaxAgeCapForPrevalentResources):
(WebKit::NetworkProcessProxy::resetCacheMaxAgeCapForPrevalentResources):
(WebKit::NetworkProcessProxy::didResetCacheMaxAgeCapForPrevalentResources):
(WebKit::nextRequestStorageAccessContextId): Deleted.
    Deleted this to make all code use the generic generateCallbackID().
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
    Used to transfer the setting from the UI process to the network process.
* UIProcess/ResourceLoadStatisticsMemoryStore.cpp:
(WebKit::ResourceLoadStatisticsMemoryStore::setCacheMaxAgeCap):
* UIProcess/ResourceLoadStatisticsMemoryStore.h:
* UIProcess/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::setCacheMaxAgeCap):
* UIProcess/WebResourceLoadStatisticsStore.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources):
(WebKit::WebsiteDataStore::resetCacheMaxAgeCapForPrevalentResources):
* UIProcess/WebsiteData/WebsiteDataStore.h:

Tools:

This change adds infrastructure for layout tests of capped cache max age.

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setStatisticsCacheMaxAgeCap):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::setStatisticsCacheMaxAgeCap):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):

LayoutTests:

* http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt: Added.
* http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html: Added.
* http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php: Added.
* http/tests/resourceLoadStatistics/resources/echo-query.php: Added.
* platform/ios/TestExpectations:
    New test marked as [ Pass ].
* platform/mac-wk2/TestExpectations:
    New test marked as [ Pass ].
* platform/wk2/TestExpectations:
    New test marked as [ Skip ] because it's not supported on non-Cocoa platforms.

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [new file with mode: 0644]
LayoutTests/http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php [new file with mode: 0644]
LayoutTests/http/tests/resourceLoadStatistics/resources/echo-query.php [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
LayoutTests/platform/mac-wk2/TestExpectations
LayoutTests/platform/wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/platform/network/NetworkStorageSession.h
Source/WebCore/platform/network/cf/NetworkStorageSessionCFNet.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit/NetworkProcess/cache/NetworkCache.h
Source/WebKit/NetworkProcess/cache/NetworkCacheStatistics.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp
Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h
Source/WebKit/UIProcess/Cocoa/ResourceLoadStatisticsMemoryStoreCocoa.mm
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in
Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp
Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.h
Source/WebKit/UIProcess/WebResourceLoadStatisticsStore.cpp
Source/WebKit/UIProcess/WebResourceLoadStatisticsStore.h
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Tools/ChangeLog
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp

index 05c0aa2..5060e19 100644 (file)
@@ -1,3 +1,22 @@
+2018-09-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Add optional cap on partitioned cache max age
+        https://bugs.webkit.org/show_bug.cgi?id=189711
+        <rdar://problem/39246837>
+
+        Reviewed by Antti Koivisto and Chris Dumez.
+
+        * http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt: Added.
+        * http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html: Added.
+        * http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php: Added.
+        * http/tests/resourceLoadStatistics/resources/echo-query.php: Added.
+        * platform/ios/TestExpectations:
+            New test marked as [ Pass ].
+        * platform/mac-wk2/TestExpectations:
+            New test marked as [ Pass ].
+        * platform/wk2/TestExpectations:
+            New test marked as [ Skip ] because it's not supported on non-Cocoa platforms.
+
 2018-09-19  Youenn Fablet  <youenn@apple.com>
 
         Layout Test webrtc/video-mute.html is flaky.
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt b/LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource-expected.txt
new file mode 100644 (file)
index 0000000..63c6069
--- /dev/null
@@ -0,0 +1,11 @@
+Tests that cache max-age is capped for prevalent resources.
+
+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="
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html b/LayoutTests/http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html
new file mode 100644 (file)
index 0000000..08b82bb
--- /dev/null
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="resources/util.js"></script>
+    <title>Tests for Capped Cache Max-Age</title>
+</head>
+<body>
+<script>
+    description("Tests that cache max-age is capped for prevalent resources.");
+    jsTestIsAsync = true;
+
+    var loadedUrl;
+    function firstFetch() {
+        // This should create a capped cache entry.
+        fetch("http://localhost:8000/resourceLoadStatistics/resources/cached-permanent-redirect.php",
+            {
+                cache: "reload",
+                headers: {
+                    "X-WebKit": "1234",
+                }
+            }
+        ).then(function(response) {
+            loadedUrl = response.url;
+            shouldBeEqualToString("loadedUrl", "http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=1234");
+            secondFetch();
+        }).catch(function(error) {
+            testFailed(error.message);
+            setEnableFeature(false, finishJSTest);
+        });
+    }
+
+    function secondFetch() {
+        // This should not trigger a successful cache hit.
+        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=");
+            setEnableFeature(false, finishJSTest);
+        }).catch(function(error) {
+            testFailed(error.message);
+            setEnableFeature(false, finishJSTest);
+        });
+    }
+
+    setEnableFeature(true, function() {
+        if (testRunner.isStatisticsPrevalentResource("http://localhost"))
+            testFailed("Localhost was classified as prevalent resource before the test started.");
+
+        testRunner.setStatisticsCacheMaxAgeCap(0);
+        testRunner.setStatisticsPrevalentResource("http://localhost", true, function() {
+            testRunner.statisticsUpdateCookieBlocking(firstFetch);
+        });
+    });
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php b/LayoutTests/http/tests/resourceLoadStatistics/resources/cached-permanent-redirect.php
new file mode 100644 (file)
index 0000000..947ed3b
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+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;
+}
+$headerStringValue = $_SERVER["HTTP_X_WEBKIT"];
+header("HTTP/1.1 301 Moved Permanently");
+header("Cache-Control: private, max-age=31536000", true);
+header('ETag: "WebKitTest"', true);
+header("Location: http://localhost:8000/resourceLoadStatistics/resources/echo-query.php?value=" . $headerStringValue);
+?>
\ No newline at end of file
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/resources/echo-query.php b/LayoutTests/http/tests/resourceLoadStatistics/resources/echo-query.php
new file mode 100644 (file)
index 0000000..6f0a573
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+header("Access-Control-Allow-Origin: http://127.0.0.1:8000");
+header("Access-Control-Allow-Headers: X-WebKit");
+if(isset($_GET["value"])) {
+  echo $_GET["value"];
+} else {
+  echo "No query parameter named 'value.'";
+}
+?>
\ No newline at end of file
index d106777..2ece794 100644 (file)
@@ -2830,6 +2830,7 @@ http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subreso
 http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subresource-requests.html [ Pass ]
 http/tests/storageAccess/deny-storage-access-under-opener.html [ Pass ]
 http/tests/storageAccess/grant-storage-access-under-opener.html [ Pass ]
+http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Pass ]
 
 # Skipped in general expectations since they only work on iOS and Mac, WK2.
 http/tests/security/strip-referrer-to-origin-for-third-party-redirects-in-private-mode.html [ Pass ]
index cf048f4..59fa0dd 100644 (file)
@@ -763,6 +763,7 @@ webkit.org/b/185994 [ Debug ] fast/text/user-installed-fonts/shadow-postscript-f
 [ HighSierra+ ] http/tests/resourceLoadStatistics/grandfathering.html [ Pass ]
 [ HighSierra+ ] http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subresource-redirects.html [ Pass ]
 [ HighSierra+ ] http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subresource-requests.html [ Pass ]
+[ HighSierra+ ] http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Pass ]
 
 # Skipped in general expectations since they only work on iOS and Mac, WK2.
 http/tests/security/strip-referrer-to-origin-for-third-party-redirects-in-private-mode.html [ Pass ]
index 89270a1..40bf537 100644 (file)
@@ -730,6 +730,7 @@ http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subreso
 http/tests/resourceLoadStatistics/add-blocking-to-redirect.html [ Skip ]
 http/tests/resourceLoadStatistics/remove-blocking-in-redirect.html [ Skip ]
 http/tests/resourceLoadStatistics/non-prevalent-resources-can-access-cookies-in-a-third-party-context.html [ Skip ]
+http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Skip ]
 
 # Process swapping is only implemented on WebKit2.
 http/tests/navigation/process-swap-window-open.html [ Pass ]
index dbfda72..09cb9fb 100644 (file)
@@ -1,3 +1,22 @@
+2018-09-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Add optional cap on partitioned cache max age
+        https://bugs.webkit.org/show_bug.cgi?id=189711
+        <rdar://problem/39246837>
+
+        Reviewed by Antti Koivisto and Chris Dumez.
+
+        Test: http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html
+
+        * platform/network/NetworkStorageSession.h:
+        * platform/network/cf/NetworkStorageSessionCFNet.cpp:
+        (WebCore::NetworkStorageSession::maxAgeCacheCap):
+            Checks if a max age cap is set and returns it if the request
+            represents a prevalent resource.
+        (WebCore::NetworkStorageSession::setCacheMaxAgeCapForPrevalentResources):
+        (WebCore::NetworkStorageSession::resetCacheMaxAgeCapForPrevalentResources):
+            New functionality to receive a max age cap setting in the session.
+
 2018-09-19  Youenn Fablet  <youenn@apple.com>
 
         Layout Test webrtc/video-mute.html is flaky.
index 986f7e4..81dacff 100644 (file)
@@ -110,6 +110,9 @@ public:
     WEBCORE_EXPORT void removeStorageAccessForFrame(uint64_t frameID, uint64_t pageID);
     WEBCORE_EXPORT void removeStorageAccessForAllFramesOnPage(uint64_t pageID);
     WEBCORE_EXPORT void removeAllStorageAccess();
+    WEBCORE_EXPORT void setCacheMaxAgeCapForPrevalentResources(Seconds);
+    WEBCORE_EXPORT void resetCacheMaxAgeCapForPrevalentResources();
+    WEBCORE_EXPORT std::optional<Seconds> maxAgeCacheCap(const ResourceRequest&);
 #endif
 #elif USE(SOUP)
     NetworkStorageSession(PAL::SessionID, std::unique_ptr<SoupNetworkSession>&&);
@@ -187,6 +190,7 @@ private:
     HashSet<String> m_topPrivatelyControlledDomainsToBlock;
     HashMap<uint64_t, HashMap<uint64_t, String, DefaultHash<uint64_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>, DefaultHash<uint64_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> m_framesGrantedStorageAccess;
     HashMap<uint64_t, HashMap<String, String>, DefaultHash<uint64_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> m_pagesGrantedStorageAccess;
+    std::optional<Seconds> m_cacheMaxAgeCapForPrevalentResources { };
 #endif
 
 #if PLATFORM(COCOA)
index c9d2964..33d23bc 100644 (file)
@@ -266,6 +266,13 @@ bool NetworkStorageSession::shouldBlockCookies(const URL& firstPartyForCookies,
     return shouldBlockThirdPartyCookies(resourceDomain);
 }
 
+std::optional<Seconds> NetworkStorageSession::maxAgeCacheCap(const ResourceRequest& request)
+{
+    if (m_cacheMaxAgeCapForPrevalentResources && shouldBlockCookies(request, std::nullopt, std::nullopt))
+        return m_cacheMaxAgeCapForPrevalentResources;
+    return std::nullopt;
+}
+
 void NetworkStorageSession::setPrevalentDomainsToBlockCookiesFor(const Vector<String>& domains, bool clearFirst)
 {
     if (clearFirst) {
@@ -370,6 +377,15 @@ void NetworkStorageSession::removeAllStorageAccess()
     m_framesGrantedStorageAccess.clear();
 }
 
+void NetworkStorageSession::setCacheMaxAgeCapForPrevalentResources(Seconds seconds)
+{
+    m_cacheMaxAgeCapForPrevalentResources = seconds;
+}
+    
+void NetworkStorageSession::resetCacheMaxAgeCapForPrevalentResources()
+{
+    m_cacheMaxAgeCapForPrevalentResources = std::nullopt;
+}
 #endif // HAVE(CFNETWORK_STORAGE_PARTITIONING)
 
 #if !PLATFORM(COCOA)
index b584442..261b3a7 100644 (file)
@@ -1,3 +1,72 @@
+2018-09-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Add optional cap on partitioned cache max age
+        https://bugs.webkit.org/show_bug.cgi?id=189711
+        <rdar://problem/39246837>
+
+        Reviewed by Antti Koivisto and Chris Dumez.
+
+        These changes add the capability to set a max age cap for prevalent resources
+        and consults it when retrieving cache entries. If an entry is capped and found
+        to be too old, it will not be used but instead removed from the cache.
+
+        This functionality is off by default because no cap is set by default.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::setCacheMaxAgeCapForPrevalentResources):
+        (WebKit::NetworkProcess::resetCacheMaxAgeCapForPrevalentResources):
+            Infrastructure for testing.
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::retrieveCacheEntry):
+            Now sends in the session ID in the retrieve call.
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::hasReachedPrevalentResourceAgeCap):
+            Static convenience function.
+        (WebKit::NetworkCache::makeUseDecision):
+            Now receives an optional maxAge parameter and checks
+            hasReachedPrevalentResourceAgeCap() first.
+        (WebKit::NetworkCache::Cache::retrieve):
+            Now takes a session ID.
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheStatistics.cpp:
+        (WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
+            Added UseDecision::NoDueToPrevalentResourceAgeCap which causes a
+            return of WebCore::DiagnosticLoggingKeys::otherKey().
+        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
+        (WKWebsiteDataStoreSetStatisticsCacheMaxAgeCap):
+        (WKWebsiteDataStoreStatisticsResetToConsistentState):
+            Infrastructure for testing.
+        * UIProcess/API/C/WKWebsiteDataStoreRef.h:
+        * UIProcess/Cocoa/ResourceLoadStatisticsMemoryStoreCocoa.mm:
+        (WebKit::ResourceLoadStatisticsMemoryStore::registerUserDefaultsIfNeeded):
+            Now supports a user default ResourceLoadStatisticsCacheMaxAgeCap.
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::hasStorageAccessForFrame):
+        (WebKit::NetworkProcessProxy::grantStorageAccess):
+        (WebKit::NetworkProcessProxy::removeAllStorageAccess):
+        (WebKit::NetworkProcessProxy::getAllStorageAccessEntries):
+        (WebKit::NetworkProcessProxy::setCacheMaxAgeCapForPrevalentResources):
+        (WebKit::NetworkProcessProxy::didSetCacheMaxAgeCapForPrevalentResources):
+        (WebKit::NetworkProcessProxy::resetCacheMaxAgeCapForPrevalentResources):
+        (WebKit::NetworkProcessProxy::didResetCacheMaxAgeCapForPrevalentResources):
+        (WebKit::nextRequestStorageAccessContextId): Deleted.
+            Deleted this to make all code use the generic generateCallbackID().
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+            Used to transfer the setting from the UI process to the network process. 
+        * UIProcess/ResourceLoadStatisticsMemoryStore.cpp:
+        (WebKit::ResourceLoadStatisticsMemoryStore::setCacheMaxAgeCap):
+        * UIProcess/ResourceLoadStatisticsMemoryStore.h:
+        * UIProcess/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::setCacheMaxAgeCap):
+        * UIProcess/WebResourceLoadStatisticsStore.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources):
+        (WebKit::WebsiteDataStore::resetCacheMaxAgeCapForPrevalentResources):
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+
 2018-09-18  Brent Fulgham  <bfulgham@apple.com>
 
         [iOS] Allow WebContent process to check the "Protocol Characteristics" of files to which it has access
index deaed32..b450a88 100644 (file)
@@ -473,6 +473,24 @@ void NetworkProcess::removePrevalentDomains(PAL::SessionID sessionID, const Vect
     if (auto* networkStorageSession = NetworkStorageSession::storageSession(sessionID))
         networkStorageSession->removePrevalentDomains(domains);
 }
+
+void NetworkProcess::setCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, Seconds seconds, uint64_t contextId)
+{
+    if (auto* networkStorageSession = NetworkStorageSession::storageSession(sessionID))
+        networkStorageSession->setCacheMaxAgeCapForPrevalentResources(Seconds { seconds });
+    else
+        ASSERT_NOT_REACHED();
+    parentProcessConnection()->send(Messages::NetworkProcessProxy::DidSetCacheMaxAgeCapForPrevalentResources(contextId), 0);
+}
+
+void NetworkProcess::resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, uint64_t contextId)
+{
+    if (auto* networkStorageSession = NetworkStorageSession::storageSession(sessionID))
+        networkStorageSession->resetCacheMaxAgeCapForPrevalentResources();
+    else
+        ASSERT_NOT_REACHED();
+    parentProcessConnection()->send(Messages::NetworkProcessProxy::DidResetCacheMaxAgeCapForPrevalentResources(contextId), 0);
+}
 #endif
 
 bool NetworkProcess::sessionIsControlledByAutomation(PAL::SessionID sessionID) const
index 7db3971..92d6d03 100644 (file)
@@ -146,6 +146,8 @@ public:
     void grantStorageAccess(PAL::SessionID, const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, uint64_t contextId);
     void removeAllStorageAccess(PAL::SessionID, uint64_t contextId);
     void removePrevalentDomains(PAL::SessionID, const Vector<String>& domains);
+    void setCacheMaxAgeCapForPrevalentResources(PAL::SessionID, Seconds, uint64_t contextId);
+    void resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID, uint64_t contextId);
 #endif
 
     Seconds loadThrottleLatency() const { return m_loadThrottleLatency; }
index b969766..4d0c8b1 100644 (file)
@@ -87,7 +87,9 @@ messages -> NetworkProcess LegacyReceiver {
     GetAllStorageAccessEntries(PAL::SessionID sessionID, uint64_t contextId)
     GrantStorageAccess(PAL::SessionID sessionID, String resourceDomain, String firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, uint64_t contextId)
     RemoveAllStorageAccess(PAL::SessionID sessionID, uint64_t contextId)
-    RemovePrevalentDomains(PAL::SessionID sessionID, Vector<String> domainsWithInteraction);
+    RemovePrevalentDomains(PAL::SessionID sessionID, Vector<String> domainsWithInteraction)
+    SetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, Seconds seconds, uint64_t contextId)
+    ResetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, uint64_t contextId)
 #endif
 
     SetSessionIsControlledByAutomation(PAL::SessionID sessionID, bool controlled);
index 5c11bab..f1095f4 100644 (file)
@@ -214,7 +214,7 @@ void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
     ASSERT(canUseCache(request));
 
     RefPtr<NetworkResourceLoader> loader(this);
-    m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [this, loader = WTFMove(loader), request = ResourceRequest { request }](auto entry, auto info) mutable {
+    m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, sessionID(), [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;
index da07e82..0d80bf7 100644 (file)
@@ -152,6 +152,11 @@ 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())
@@ -183,8 +188,11 @@ static bool responseNeedsRevalidation(const WebCore::ResourceResponse& response,
     return responseHasExpired(response, timestamp, requestDirectives.maxStale);
 }
 
-static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request)
+static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request, std::optional<Seconds> maxAge)
 {
+    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())
@@ -271,7 +279,7 @@ static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalR
     return StoreDecision::Yes;
 }
 
-void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, RetrieveCompletionHandler&& completionHandler)
+void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameID& frameID, PAL::SessionID sessionID, RetrieveCompletionHandler&& completionHandler)
 {
     ASSERT(request.url().protocolIsInHTTPFamily());
 
@@ -315,7 +323,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](auto record, auto timings) mutable {
+    m_storage->retrieve(storageKey, priority, [this, protectedThis = makeRef(*this), request, completionHandler = WTFMove(completionHandler), info = WTFMove(info), storageKey, frameID, sessionID](auto record, auto timings) mutable {
         info.storageTimings = timings;
 
         if (!record) {
@@ -332,13 +340,22 @@ void Cache::retrieve(const WebCore::ResourceRequest& request, const GlobalFrameI
 
         auto entry = Entry::decodeStorageRecord(*record);
 
-        auto useDecision = entry ? makeUseDecision(*entry, request) : UseDecision::NoDueToDecodeFailure;
+        std::optional<Seconds> maxAgeCap;
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+        if (auto networkStorageSession = WebCore::NetworkStorageSession::storageSession(sessionID))
+            maxAgeCap = networkStorageSession->maxAgeCacheCap(request);
+#endif
+        auto useDecision = entry ? makeUseDecision(*entry, request, maxAgeCap) : 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;
         };
index cf5b7bb..f15ad6b 100644 (file)
@@ -82,6 +82,7 @@ enum class UseDecision {
     NoDueToMissingValidatorFields,
     NoDueToDecodeFailure,
     NoDueToExpiredRedirect,
+    NoDueToPrevalentResourceAgeCap
 };
 
 using GlobalFrameID = std::pair<uint64_t /*webPageID*/, uint64_t /*webFrameID*/>;
@@ -112,7 +113,7 @@ public:
         WTF_MAKE_FAST_ALLOCATED;
     };
     using RetrieveCompletionHandler = Function<void (std::unique_ptr<Entry>, const RetrieveInfo&)>;
-    void retrieve(const WebCore::ResourceRequest&, const GlobalFrameID&, RetrieveCompletionHandler&&);
+    void retrieve(const WebCore::ResourceRequest&, const GlobalFrameID&, PAL::SessionID, 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> update(const WebCore::ResourceRequest&, const GlobalFrameID&, const Entry&, const WebCore::ResourceResponse& validatingResponse);
index 8ee7453..a155e9f 100644 (file)
@@ -282,6 +282,7 @@ 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:
index 7f23e90..2464b0b 100644 (file)
@@ -462,6 +462,13 @@ void WKWebsiteDataStoreStatisticsClearThroughWebsiteDataRemoval(WKWebsiteDataSto
     });
 }
 
+void WKWebsiteDataStoreSetStatisticsCacheMaxAgeCap(WKWebsiteDataStoreRef dataStoreRef, double seconds, void* context, WKWebsiteDataStoreSetStatisticsCacheMaxAgeCapFunction callback)
+{
+    WebKit::toImpl(dataStoreRef)->websiteDataStore().setCacheMaxAgeCapForPrevalentResources(Seconds { seconds }, [context, callback] {
+        callback(context);
+    });
+}
+
 void WKWebsiteDataStoreStatisticsResetToConsistentState(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsResetToConsistentStateFunction completionHandler)
 {
     auto callbackAggregator = CallbackAggregator::create([context, completionHandler]() {
@@ -470,6 +477,7 @@ void WKWebsiteDataStoreStatisticsResetToConsistentState(WKWebsiteDataStoreRef da
 
     auto& store = WebKit::toImpl(dataStoreRef)->websiteDataStore();
     store.clearResourceLoadStatisticsInWebProcesses([callbackAggregator = callbackAggregator.copyRef()] { });
+    store.resetCacheMaxAgeCapForPrevalentResources([callbackAggregator = callbackAggregator.copyRef()] { });
 
     auto* statisticsStore = store.resourceLoadStatistics();
     if (!statisticsStore)
index 02e7bce..d7d899e 100644 (file)
@@ -91,6 +91,8 @@ typedef void (*WKWebsiteDataStoreStatisticsClearInMemoryAndPersistentStoreModifi
 WK_EXPORT void WKWebsiteDataStoreStatisticsClearInMemoryAndPersistentStoreModifiedSinceHours(WKWebsiteDataStoreRef dataStoreRef, unsigned hours, void* context, WKWebsiteDataStoreStatisticsClearInMemoryAndPersistentStoreModifiedSinceHoursFunction callback);
 typedef void (*WKWebsiteDataStoreStatisticsClearThroughWebsiteDataRemovalFunction)(void* functionContext);
 WK_EXPORT void WKWebsiteDataStoreStatisticsClearThroughWebsiteDataRemoval(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsClearThroughWebsiteDataRemovalFunction callback);
+typedef void (*WKWebsiteDataStoreSetStatisticsCacheMaxAgeCapFunction)(void* functionContext);
+WK_EXPORT void WKWebsiteDataStoreSetStatisticsCacheMaxAgeCap(WKWebsiteDataStoreRef dataStoreRef, double seconds, void* context, WKWebsiteDataStoreSetStatisticsCacheMaxAgeCapFunction);
 typedef void (*WKWebsiteDataStoreStatisticsResetToConsistentStateFunction)(void* functionContext);
 WK_EXPORT void WKWebsiteDataStoreStatisticsResetToConsistentState(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsResetToConsistentStateFunction completionHandler);
 
index bfeedf9..8d9d1bb 100644 (file)
@@ -52,6 +52,10 @@ void ResourceLoadStatisticsMemoryStore::registerUserDefaultsIfNeeded()
         if (debugManualPrevalentResource)
             setPrevalentResourceForDebugMode(debugManualPrevalentResource);
         setStorageAccessPromptsEnabled([[NSUserDefaults standardUserDefaults] boolForKey:@"ExperimentalStorageAccessPromptsEnabled"]);
+
+        Seconds cacheMaxAgeCapForPrevalentResources([[NSUserDefaults standardUserDefaults] doubleForKey:@"ResourceLoadStatisticsCacheMaxAgeCap"]);
+        if (cacheMaxAgeCapForPrevalentResources > 0_s && cacheMaxAgeCapForPrevalentResources <= 24_h * 365)
+            setCacheMaxAgeCap(cacheMaxAgeCapForPrevalentResources);
     });
 }
 
index 8988987..4e99193 100644 (file)
@@ -404,15 +404,9 @@ void NetworkProcessProxy::didUpdateBlockCookies(uint64_t callbackId)
     m_updateBlockCookiesCallbackMap.take(callbackId)();
 }
 
-static uint64_t nextRequestStorageAccessContextId()
-{
-    static uint64_t nextContextId = 0;
-    return ++nextContextId;
-}
-
 void NetworkProcessProxy::hasStorageAccessForFrame(PAL::SessionID sessionID, const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void(bool)>&& callback)
 {
-    auto contextId = nextRequestStorageAccessContextId();
+    auto contextId = generateCallbackID();
     auto addResult = m_storageAccessResponseCallbackMap.add(contextId, WTFMove(callback));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     send(Messages::NetworkProcess::HasStorageAccessForFrame(sessionID, resourceDomain, firstPartyDomain, frameID, pageID, contextId), 0);
@@ -420,7 +414,7 @@ void NetworkProcessProxy::hasStorageAccessForFrame(PAL::SessionID sessionID, con
 
 void NetworkProcessProxy::grantStorageAccess(PAL::SessionID sessionID, const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, WTF::CompletionHandler<void(bool)>&& callback)
 {
-    auto contextId = nextRequestStorageAccessContextId();
+    auto contextId = generateCallbackID();
     auto addResult = m_storageAccessResponseCallbackMap.add(contextId, WTFMove(callback));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     send(Messages::NetworkProcess::GrantStorageAccess(sessionID, resourceDomain, firstPartyDomain, frameID, pageID, contextId), 0);
@@ -439,7 +433,7 @@ void NetworkProcessProxy::removeAllStorageAccess(PAL::SessionID sessionID, Compl
         return;
     }
 
-    auto contextId = nextRequestStorageAccessContextId();
+    auto contextId = generateCallbackID();
     auto addResult = m_removeAllStorageAccessCallbackMap.add(contextId, WTFMove(completionHandler));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     send(Messages::NetworkProcess::RemoveAllStorageAccess(sessionID, contextId), 0);
@@ -453,7 +447,7 @@ void NetworkProcessProxy::didRemoveAllStorageAccess(uint64_t contextId)
 
 void NetworkProcessProxy::getAllStorageAccessEntries(PAL::SessionID sessionID, CompletionHandler<void(Vector<String>&& domains)>&& callback)
 {
-    auto contextId = nextRequestStorageAccessContextId();
+    auto contextId = generateCallbackID();
     auto addResult = m_allStorageAccessEntriesCallbackMap.add(contextId, WTFMove(callback));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     send(Messages::NetworkProcess::GetAllStorageAccessEntries(sessionID, contextId), 0);
@@ -464,6 +458,44 @@ void NetworkProcessProxy::allStorageAccessEntriesResult(Vector<String>&& domains
     auto callback = m_allStorageAccessEntriesCallbackMap.take(contextId);
     callback(WTFMove(domains));
 }
+
+void NetworkProcessProxy::setCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler)
+{
+    if (!canSendMessage()) {
+        completionHandler();
+        return;
+    }
+    
+    auto contextId = generateCallbackID();
+    auto addResult = m_updateRuntimeSettingsCallbackMap.add(contextId, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    send(Messages::NetworkProcess::SetCacheMaxAgeCapForPrevalentResources(sessionID, seconds, contextId), 0);
+}
+
+void NetworkProcessProxy::didSetCacheMaxAgeCapForPrevalentResources(uint64_t contextId)
+{
+    auto completionHandler = m_updateRuntimeSettingsCallbackMap.take(contextId);
+    completionHandler();
+}
+
+void NetworkProcessProxy::resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
+{
+    if (!canSendMessage()) {
+        completionHandler();
+        return;
+    }
+    
+    auto contextId = generateCallbackID();
+    auto addResult = m_updateRuntimeSettingsCallbackMap.add(contextId, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    send(Messages::NetworkProcess::ResetCacheMaxAgeCapForPrevalentResources(sessionID, contextId), 0);
+}
+
+void NetworkProcessProxy::didResetCacheMaxAgeCapForPrevalentResources(uint64_t contextId)
+{
+    auto completionHandler = m_updateRuntimeSettingsCallbackMap.take(contextId);
+    completionHandler();
+}
 #endif
 
 void NetworkProcessProxy::sendProcessWillSuspendImminently()
index 8354026..6f9648d 100644 (file)
@@ -83,6 +83,8 @@ public:
     void getAllStorageAccessEntries(PAL::SessionID, CompletionHandler<void(Vector<String>&& domains)>&&);
     void grantStorageAccess(PAL::SessionID, const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, CompletionHandler<void(bool)>&& callback);
     void removeAllStorageAccess(PAL::SessionID, CompletionHandler<void()>&&);
+    void setCacheMaxAgeCapForPrevalentResources(PAL::SessionID, Seconds, CompletionHandler<void()>&&);
+    void resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID, CompletionHandler<void()>&&);
 #endif
 
     void writeBlobToFilePath(const WebCore::URL&, const String& path, CompletionHandler<void(bool)>&& callback);
@@ -147,6 +149,8 @@ private:
     void storageAccessRequestResult(bool wasGranted, uint64_t contextId);
     void allStorageAccessEntriesResult(Vector<String>&& domains, uint64_t contextId);
     void didRemoveAllStorageAccess(uint64_t contextId);
+    void didSetCacheMaxAgeCapForPrevalentResources(uint64_t contextId);
+    void didResetCacheMaxAgeCapForPrevalentResources(uint64_t contextId);
 #endif
     void retrieveCacheStorageParameters(PAL::SessionID);
 
@@ -186,6 +190,8 @@ private:
     HashMap<uint64_t, CompletionHandler<void()>> m_removeAllStorageAccessCallbackMap;
     HashMap<uint64_t, CompletionHandler<void(Vector<String>&& domains)>> m_allStorageAccessEntriesCallbackMap;
 
+    HashMap<uint64_t, CompletionHandler<void()>> m_updateRuntimeSettingsCallbackMap;
+
 #if ENABLE(CONTENT_EXTENSIONS)
     HashSet<WebUserContentControllerProxy*> m_webUserContentControllerProxies;
 #endif
index 512dff2..ae7f56e 100644 (file)
@@ -46,6 +46,8 @@ messages -> NetworkProcessProxy LegacyReceiver {
     StorageAccessRequestResult(bool wasGranted, uint64_t contextId)
     AllStorageAccessEntriesResult(Vector<String> domains, uint64_t contextId)
     DidRemoveAllStorageAccess(uint64_t contextId)
+    DidSetCacheMaxAgeCapForPrevalentResources(uint64_t contextId)
+    DidResetCacheMaxAgeCapForPrevalentResources(uint64_t contextId)
 #endif
 #if ENABLE(CONTENT_EXTENSIONS)
     ContentExtensionRules(WebKit::UserContentControllerIdentifier identifier)
index 14c837a..4774eb1 100644 (file)
@@ -832,6 +832,16 @@ void ResourceLoadStatisticsMemoryStore::setGrandfatheringTime(Seconds seconds)
     m_parameters.grandfatheringTime = seconds;
 }
 
+void ResourceLoadStatisticsMemoryStore::setCacheMaxAgeCap(Seconds seconds)
+{
+    ASSERT(!RunLoop::isMain());
+    ASSERT(seconds >= 0_s);
+
+    RunLoop::main().dispatch([store = makeRef(m_store), seconds] () {
+        store->setCacheMaxAgeCap(seconds, [] { });
+    });
+}
+
 bool ResourceLoadStatisticsMemoryStore::shouldRemoveDataRecords() const
 {
     ASSERT(!RunLoop::isMain());
index 634b82d..b708207 100644 (file)
@@ -113,6 +113,7 @@ public:
     void setTimeToLiveUserInteraction(Seconds);
     void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
     void setGrandfatheringTime(Seconds);
+    void setCacheMaxAgeCap(Seconds);
     void setResourceLoadStatisticsDebugMode(bool);
     bool isDebugModeEnabled() const { return m_debugModeEnabled; };
     void setPrevalentResourceForDebugMode(const String& domain);
index c7db69b..11be045 100644 (file)
@@ -833,6 +833,20 @@ void WebResourceLoadStatisticsStore::setGrandfatheringTime(Seconds seconds)
     });
 }
 
+void WebResourceLoadStatisticsStore::setCacheMaxAgeCap(Seconds seconds, CompletionHandler<void()>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(seconds >= 0_s);
+    
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    if (m_websiteDataStore) {
+        m_websiteDataStore->setCacheMaxAgeCapForPrevalentResources(seconds, WTFMove(completionHandler));
+        return;
+    }
+#endif
+    completionHandler();
+}
+
 void WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToBlockCookiesForHandler(const Vector<String>& domainsToBlock, ShouldClearFirst shouldClearFirst, CompletionHandler<void()>&& completionHandler)
 {
     ASSERT(RunLoop::isMain());
index f0f50a8..8bd1685 100644 (file)
@@ -125,6 +125,7 @@ public:
     void setTimeToLiveUserInteraction(Seconds);
     void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
     void setGrandfatheringTime(Seconds);
+    void setCacheMaxAgeCap(Seconds, CompletionHandler<void()>&&);
     void setMaxStatisticsEntries(size_t);
     void setPruneEntriesDownTo(size_t);
 
index df21776..308718a 100644 (file)
@@ -1342,6 +1342,35 @@ void WebsiteDataStore::grantStorageAccess(String&& subFrameHost, String&& topFra
 }
 #endif
 
+void WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources(Seconds seconds, CompletionHandler<void()>&& completionHandler)
+{
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
+    
+    for (auto& processPool : processPools()) {
+        if (auto* networkProcess = processPool->networkProcess())
+            networkProcess->setCacheMaxAgeCapForPrevalentResources(m_sessionID, seconds, [callbackAggregator = callbackAggregator.copyRef()] { });
+    }
+#else
+    UNUSED_PARAM(seconds);
+    completionHandler();
+#endif
+}
+
+void WebsiteDataStore::resetCacheMaxAgeCapForPrevalentResources(CompletionHandler<void()>&& completionHandler)
+{
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
+    
+    for (auto& processPool : processPools()) {
+        if (auto* networkProcess = processPool->networkProcess())
+            networkProcess->resetCacheMaxAgeCapForPrevalentResources(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
+    }
+#else
+    completionHandler();
+#endif
+}
+
 void WebsiteDataStore::networkProcessDidCrash()
 {
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
index a80ef16..5569c9c 100644 (file)
@@ -143,6 +143,8 @@ public:
     void requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(StorageAccessStatus)>&&);
     void grantStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool userWasPrompted, CompletionHandler<void(bool)>&&);
 #endif
+    void setCacheMaxAgeCapForPrevalentResources(Seconds, CompletionHandler<void()>&&);
+    void resetCacheMaxAgeCapForPrevalentResources(CompletionHandler<void()>&&);
     void networkProcessDidCrash();
     void resolveDirectoriesIfNecessary();
     const String& resolvedApplicationCacheDirectory() const { return m_resolvedConfiguration.applicationCacheDirectory; }
index 2465a7d..3b66b6f 100644 (file)
@@ -1,3 +1,23 @@
+2018-09-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Add optional cap on partitioned cache max age
+        https://bugs.webkit.org/show_bug.cgi?id=189711
+        <rdar://problem/39246837>
+
+        Reviewed by Antti Koivisto and Chris Dumez.
+
+        This change adds infrastructure for layout tests of capped cache max age.
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setStatisticsCacheMaxAgeCap):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::setStatisticsCacheMaxAgeCap):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
 2018-09-19  Dawei Fenton  <realdawei@apple.com>
 
        Unreviewed. Update my email and alias in list of contributors.
index 227bf10..13de720 100644 (file)
@@ -307,6 +307,7 @@ interface TestRunner {
     void statisticsClearInMemoryAndPersistentStore(object callback);
     void statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned long hours, object callback);
     void statisticsClearThroughWebsiteDataRemoval(object callback);
+    void setStatisticsCacheMaxAgeCap(double seconds);
     void statisticsResetToConsistentState(object completionHandler);
 
     // Injected bundle form client.
index f70ee13..2c6168b 100644 (file)
@@ -1945,6 +1945,13 @@ void TestRunner::statisticsClearThroughWebsiteDataRemoval(JSValueRef callback)
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
 }
 
+void TestRunner::setStatisticsCacheMaxAgeCap(double seconds)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsCacheMaxAgeCap"));
+    WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
 void TestRunner::statisticsCallClearThroughWebsiteDataRemovalCallback()
 {
     callTestRunnerCallback(StatisticsDidClearThroughWebsiteDataRemovalCallbackID);
index 95d596a..110ee85 100644 (file)
@@ -421,6 +421,7 @@ public:
     void statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours, JSValueRef callback);
     void statisticsClearThroughWebsiteDataRemoval(JSValueRef callback);
     void statisticsCallClearThroughWebsiteDataRemovalCallback();
+    void setStatisticsCacheMaxAgeCap(double seconds);
     void statisticsResetToConsistentState(JSValueRef completionHandler);
     void statisticsCallDidResetToConsistentStateCallback();
 
index 3f3ba2a..4764ec8 100644 (file)
@@ -3122,6 +3122,14 @@ void TestController::statisticsClearThroughWebsiteDataRemoval()
     m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
 }
 
+void TestController::setStatisticsCacheMaxAgeCap(double seconds)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsCacheMaxAgeCap(dataStore, seconds, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+}
+
 void TestController::statisticsResetToConsistentState()
 {
     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
index a1fe510..7661f5e 100644 (file)
@@ -221,6 +221,7 @@ public:
     void statisticsClearInMemoryAndPersistentStore();
     void statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned);
     void statisticsClearThroughWebsiteDataRemoval();
+    void setStatisticsCacheMaxAgeCap(double seconds);
     void statisticsResetToConsistentState();
 
     void getAllStorageAccessEntries();
index 550f9d3..ecfd6cc 100644 (file)
@@ -1358,6 +1358,13 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
         return nullptr;
     }
     
+    if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsCacheMaxAgeCap")) {
+        ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
+        WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
+        TestController::singleton().setStatisticsCacheMaxAgeCap(WKDoubleGetValue(seconds));
+        return nullptr;
+    }
+
     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsResetToConsistentState")) {
         if (m_shouldDumpResourceLoadStatistics)
             m_savedResourceLoadStatistics = TestController::singleton().dumpResourceLoadStatistics();