Resource Load Statistics: Communicate to the network process which domains to partition
authorwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 04:02:14 +0000 (04:02 +0000)
committerwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 04:02:14 +0000 (04:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169322
<rdar://problem/30768921>

Reviewed by Alex Christensen.

Source/WebCore:

Test: http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html

* loader/ResourceLoadObserver.cpp:
(WebCore::ResourceLoadObserver::logUserInteractionWithReducedTimeResolution):
    Now calls ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler()
    to tell the network process the domain has got user interaction.
(WebCore::ResourceLoadObserver::logUserInteraction):
    Now calls ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler()
    to tell the network process the domain has got user interaction.
(WebCore::ResourceLoadObserver::fireShouldPartitionCookiesHandler):
    To allow TestRunner to set a domain for which
    partitioning should be applied.
(WebCore::ResourceLoadObserver::primaryDomain):
    New overloaded convenience function.
* loader/ResourceLoadObserver.h:
* loader/ResourceLoadStatisticsStore.cpp:
(WebCore::ResourceLoadStatisticsStore::readDataFromDecoder):
    Now bootstraps the network process' set of known domains to
    partition cookies for.
(WebCore::ResourceLoadStatisticsStore::setShouldPartitionCookiesCallback):
(WebCore::ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler):
(WebCore::ResourceLoadStatisticsStore::hasHadRecentUserInteraction):
    Now tells the network process to start partitioning again
    when user interaction ages out.
* loader/ResourceLoadStatisticsStore.h:
* platform/network/NetworkStorageSession.h:
* platform/network/cf/NetworkStorageSessionCFNet.cpp:
(WebCore::NetworkStorageSession::shouldPartitionCookiesForHost):
(WebCore::NetworkStorageSession::setShouldPartitionCookiesForHosts):

Source/WebKit2:

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
(WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
    Now consults WebCore::NetworkStorageSession::shouldPartitionCookiesForHost()
    to decide whether partitioning should be applied or not.
* UIProcess/API/C/WKCookieManager.cpp:
(WKCookieManagerSetCookieStoragePartitioningEnabled):
    To allow TestRunner to configure cookie partitioning.
* UIProcess/API/C/WKCookieManager.h:
* UIProcess/API/C/WKResourceLoadStatisticsManager.cpp:
(WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler):
    To allow TestRunner to set a domain for which
    partitioning should be applied.
* UIProcess/API/C/WKResourceLoadStatisticsManager.h:
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
* UIProcess/WebCookieManagerProxy.cpp:
(WebKit::WebCookieManagerProxy::setCookieStoragePartitioningEnabled):
    To allow TestRunner to configure cookie partitioning.
* UIProcess/WebCookieManagerProxy.h:
* UIProcess/WebResourceLoadStatisticsManager.cpp:
(WebKit::WebResourceLoadStatisticsManager::fireShouldPartitionCookiesHandler):
    To allow TestRunner to set a domain for which
    partitioning should be applied.
* UIProcess/WebResourceLoadStatisticsManager.h:
* UIProcess/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::classifyResource):
    Now tells the network process as soon as a domain
    has been classified as prevalent.
(WebKit::WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver):
    Overloaded function to allow injection of handlers for communication with the
    network process.
* UIProcess/WebResourceLoadStatisticsStore.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
(WebKit::WebsiteDataStore::registerSharedResourceLoadObserver):
    Now sets two callback handlers for communication with the network process.
* UIProcess/WebsiteData/WebsiteDataStore.h:

Tools:

These changes add support for two new TestRunner functions:
- setCookieStoragePartitioningEnabled()
- statisticsFireShouldPartitionCookiesHandler()

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

LayoutTests:

* http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction-expected.txt: Added.
* http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html: Added.
* http/tests/loading/resourceLoadStatistics/resources: Added.
* http/tests/loading/resourceLoadStatistics/resources/get-cookies.php: Added.
* http/tests/loading/resourceLoadStatistics/resources/set-cookie.php: Added.

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

39 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html [new file with mode: 0644]
LayoutTests/http/tests/loading/resourceLoadStatistics/resources/get-cookies.php [new file with mode: 0644]
LayoutTests/http/tests/loading/resourceLoadStatistics/resources/set-cookie.php [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/loader/ResourceLoadObserver.cpp
Source/WebCore/loader/ResourceLoadObserver.h
Source/WebCore/loader/ResourceLoadStatisticsStore.cpp
Source/WebCore/loader/ResourceLoadStatisticsStore.h
Source/WebCore/platform/network/NetworkStorageSession.h
Source/WebCore/platform/network/cf/NetworkStorageSessionCFNet.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/NetworkProcess.cpp
Source/WebKit2/NetworkProcess/NetworkProcess.h
Source/WebKit2/NetworkProcess/NetworkProcess.messages.in
Source/WebKit2/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
Source/WebKit2/UIProcess/API/C/WKCookieManager.cpp
Source/WebKit2/UIProcess/API/C/WKCookieManager.h
Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.cpp
Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.h
Source/WebKit2/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit2/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit2/UIProcess/Network/NetworkProcessProxy.messages.in
Source/WebKit2/UIProcess/WebCookieManagerProxy.cpp
Source/WebKit2/UIProcess/WebCookieManagerProxy.h
Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.cpp
Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.h
Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.cpp
Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.h
Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit2/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 99cd929..3c3e1ce 100644 (file)
@@ -1,3 +1,17 @@
+2017-03-08  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Communicate to the network process which domains to partition
+        https://bugs.webkit.org/show_bug.cgi?id=169322
+        <rdar://problem/30768921>
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction-expected.txt: Added.
+        * http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html: Added.
+        * http/tests/loading/resourceLoadStatistics/resources: Added.
+        * http/tests/loading/resourceLoadStatistics/resources/get-cookies.php: Added.
+        * http/tests/loading/resourceLoadStatistics/resources/set-cookie.php: Added.
+
 2017-03-08  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Should be able to see where Resources came from (Memory Cache, Disk Cache)
diff --git a/LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction-expected.txt b/LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction-expected.txt
new file mode 100644 (file)
index 0000000..ce9b1b6
--- /dev/null
@@ -0,0 +1,75 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Test for Partitioned Cookies With and Without User Interaction
+main frame - didChangeLocationWithinPageForFrame
+main frame - willPerformClientRedirectToURL: http://localhost:8000/loading/resourceLoadStatistics/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html#step2 
+main frame - didFinishDocumentLoadForFrame
+main frame - didFinishLoadForFrame
+main frame - didStartProvisionalLoadForFrame
+main frame - didCancelClientRedirectForFrame
+main frame - didCommitLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+main frame - willPerformClientRedirectToURL: http://127.0.0.1:8000/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html#step2 
+main frame - didStartProvisionalLoadForFrame
+main frame - didCancelClientRedirectForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Test for Partitioned Cookies With and Without User Interaction
+main frame - didChangeLocationWithinPageForFrame
+frame "<!--framePath //<!--frame0-->-->" - didStartProvisionalLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+frame "<!--framePath //<!--frame0-->-->" - didCommitLoadForFrame
+frame "<!--framePath //<!--frame0-->-->" - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didChangeLocationWithinPageForFrame
+frame "<!--framePath //<!--frame1-->-->" - didStartProvisionalLoadForFrame
+frame "<!--framePath //<!--frame0-->-->" - didHandleOnloadEventsForFrame
+frame "<!--framePath //<!--frame0-->-->" - didFinishLoadForFrame
+frame "<!--framePath //<!--frame1-->-->" - didCommitLoadForFrame
+frame "<!--framePath //<!--frame1-->-->" - didFinishDocumentLoadForFrame
+main frame - didChangeLocationWithinPageForFrame
+frame "<!--framePath //<!--frame2-->-->" - didStartProvisionalLoadForFrame
+frame "<!--framePath //<!--frame1-->-->" - didHandleOnloadEventsForFrame
+frame "<!--framePath //<!--frame1-->-->" - didFinishLoadForFrame
+frame "<!--framePath //<!--frame2-->-->" - didCommitLoadForFrame
+frame "<!--framePath //<!--frame2-->-->" - didFinishDocumentLoadForFrame
+frame "<!--framePath //<!--frame3-->-->" - didStartProvisionalLoadForFrame
+frame "<!--framePath //<!--frame2-->-->" - didHandleOnloadEventsForFrame
+frame "<!--framePath //<!--frame2-->-->" - didFinishLoadForFrame
+frame "<!--framePath //<!--frame3-->-->" - didCommitLoadForFrame
+frame "<!--framePath //<!--frame3-->-->" - didFinishDocumentLoadForFrame
+frame "<!--framePath //<!--frame3-->-->" - didHandleOnloadEventsForFrame
+frame "<!--framePath //<!--frame3-->-->" - didFinishLoadForFrame
+main frame - didFinishLoadForFrame
+  
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+Should receive no cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'thirdPartyCookie'.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+Setting partitioned, third party cookie.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+Should only receive partitioned, third party cookie.
+Did not receive cookie named 'firstPartyCookie'.
+Received cookie named 'thirdPartyCookie'.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+After user interaction, should only receive non-partitioned, first party cookie.
+Received cookie named 'firstPartyCookie'.
+Did not receive cookie named 'thirdPartyCookie'.
+
diff --git a/LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html b/LayoutTests/http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html
new file mode 100644 (file)
index 0000000..ee0fbad
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Test for Partitioned Cookies With and Without User Interaction</title>
+    <script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+    const partitionHost = "127.0.0.1:8000";
+    const thirdPartyOrigin = "http://localhost:8000";
+    const thirdPartyBaseUrl = thirdPartyOrigin + "/loading/resourceLoadStatistics/resources";
+    const firstPartyCookieName = "firstPartyCookie";
+    const subPathToSetFirstPartyCookie = "/set-cookie.php?name=" + firstPartyCookieName + "&value=value";
+    const thirdPartyCookieName = "thirdPartyCookie";
+    const subPathToSetThirdPartyCookie = "/set-cookie.php?name=" + thirdPartyCookieName + "&value=value";
+    const fragmentWithReturnUrl = "http://127.0.0.1:8000/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html";
+    const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName + "&name2=" + thirdPartyCookieName;
+
+    function setEnableFeature(enable) {
+        if (!enable) {
+            testRunner.statisticsResetToConsistentState();
+        }
+        internals.setResourceLoadStatisticsEnabled(enable);
+        testRunner.setCookieStoragePartitioningEnabled(enable);
+    }
+
+    function finishTest() {
+        setEnableFeature(false);
+        testRunner.notifyDone();
+    }
+
+    function openIframe(url, onLoadHandler) {
+        const element = document.createElement("iframe");
+        element.src = url;
+        if (onLoadHandler) {
+            element.onload = onLoadHandler;
+        }
+        document.body.appendChild(element);
+    }
+
+    function setUserInteractionAndContinue() {
+        testRunner.setStatisticsHasHadUserInteraction(thirdPartyOrigin, true);
+        if (!testRunner.isStatisticsHasHadUserInteraction(thirdPartyOrigin))
+            testFailed("Third party did not get logged for user interaction.");
+        runTest();
+    }
+
+    function runTest() {
+        switch (document.location.hash) {
+            case "#step1":
+                document.location.href = thirdPartyBaseUrl + subPathToSetFirstPartyCookie + "#" + fragmentWithReturnUrl + "#step2";
+                break;
+            case "#step2":
+                document.location.hash = "step3";
+                openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should receive no cookies.", runTest);
+                break;
+            case "#step3":
+                document.location.hash = "step4";
+                openIframe(thirdPartyBaseUrl + subPathToSetThirdPartyCookie + "&message=Setting partitioned, third party cookie.", runTest);
+                break;
+            case "#step4":
+                document.location.hash = "step5";
+                openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should only receive partitioned, third party cookie.", setUserInteractionAndContinue);
+                break;
+            case "#step5":
+                openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=After user interaction, should only receive non-partitioned, first party cookie.", finishTest);
+                break;
+        }
+    }
+
+    if (document.location.host === partitionHost && document.location.hash == "" && window.testRunner && window.internals) {
+        setEnableFeature(true);
+
+        testRunner.statisticsFireShouldPartitionCookiesHandler("localhost", true);
+
+        testRunner.waitUntilDone();
+        testRunner.dumpChildFramesAsText();
+        document.location.hash = "step1";
+    }
+
+    runTest();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/http/tests/loading/resourceLoadStatistics/resources/get-cookies.php b/LayoutTests/http/tests/loading/resourceLoadStatistics/resources/get-cookies.php
new file mode 100644 (file)
index 0000000..55487ae
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+echo $_GET["message"] . "<br>";
+if(!isset($_COOKIE[$_GET["name1"]])) {
+    echo "Did not receive cookie named '" . $_GET["name1"] . "'.<br>";
+} else {
+    echo "Received cookie named '" . $_GET["name1"] . "'.<br>";
+}
+if(!isset($_COOKIE[$_GET["name2"]])) {
+    echo "Did not receive cookie named '" . $_GET["name2"] . "'.<br>";
+} else {
+    echo "Received cookie named '" . $_GET["name2"] . "'.<br>";
+}
+?>
diff --git a/LayoutTests/http/tests/loading/resourceLoadStatistics/resources/set-cookie.php b/LayoutTests/http/tests/loading/resourceLoadStatistics/resources/set-cookie.php
new file mode 100644 (file)
index 0000000..0a2d892
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+setcookie($_GET["name"], $_GET["value"], 0, "/");
+echo $_GET["message"] . "<br>";
+?>
+<script>
+if (document.location.hash) {
+    setTimeout("document.location.href = document.location.hash.substring(1)", 10);
+}
+</script>
\ No newline at end of file
index d7275d6..6bc1f45 100644 (file)
@@ -1,3 +1,41 @@
+2017-03-08  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Communicate to the network process which domains to partition
+        https://bugs.webkit.org/show_bug.cgi?id=169322
+        <rdar://problem/30768921>
+
+        Reviewed by Alex Christensen.
+
+        Test: http/tests/loading/resourceLoadStatistics/partitioned-cookies-with-and-without-user-interaction.html
+
+        * loader/ResourceLoadObserver.cpp:
+        (WebCore::ResourceLoadObserver::logUserInteractionWithReducedTimeResolution):
+            Now calls ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler()
+            to tell the network process the domain has got user interaction.
+        (WebCore::ResourceLoadObserver::logUserInteraction):
+            Now calls ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler()
+            to tell the network process the domain has got user interaction.
+        (WebCore::ResourceLoadObserver::fireShouldPartitionCookiesHandler):
+            To allow TestRunner to set a domain for which
+            partitioning should be applied.
+        (WebCore::ResourceLoadObserver::primaryDomain):
+            New overloaded convenience function.
+        * loader/ResourceLoadObserver.h:
+        * loader/ResourceLoadStatisticsStore.cpp:
+        (WebCore::ResourceLoadStatisticsStore::readDataFromDecoder):
+            Now bootstraps the network process' set of known domains to
+            partition cookies for.
+        (WebCore::ResourceLoadStatisticsStore::setShouldPartitionCookiesCallback):
+        (WebCore::ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler):
+        (WebCore::ResourceLoadStatisticsStore::hasHadRecentUserInteraction):
+            Now tells the network process to start partitioning again
+            when user interaction ages out.
+        * loader/ResourceLoadStatisticsStore.h:
+        * platform/network/NetworkStorageSession.h:
+        * platform/network/cf/NetworkStorageSessionCFNet.cpp:
+        (WebCore::NetworkStorageSession::shouldPartitionCookiesForHost):
+        (WebCore::NetworkStorageSession::setShouldPartitionCookiesForHosts):
+
 2017-03-08  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Should be able to see where Resources came from (Memory Cache, Disk Cache)
index 1026dae..9624201 100644 (file)
@@ -304,13 +304,17 @@ void ResourceLoadObserver::logUserInteractionWithReducedTimeResolution(const Doc
     if (url.isBlankURL() || url.isEmpty())
         return;
 
-    auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+    auto primaryDomainStr = primaryDomain(url);
+
+    auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomainStr);
     double newTimestamp = reduceTimeResolutionToOneDay(WTF::currentTime());
     if (newTimestamp == statistics.mostRecentUserInteraction)
         return;
 
     statistics.hadUserInteraction = true;
     statistics.mostRecentUserInteraction = newTimestamp;
+
+    m_store->fireShouldPartitionCookiesHandler(primaryDomainStr, false);
     m_store->fireDataModificationHandler();
 }
 
@@ -319,9 +323,13 @@ void ResourceLoadObserver::logUserInteraction(const URL& url)
     if (url.isBlankURL() || url.isEmpty())
         return;
 
-    auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomain(url));
+    auto primaryDomainStr = primaryDomain(url);
+
+    auto& statistics = m_store->ensureResourceStatisticsForPrimaryDomain(primaryDomainStr);
     statistics.hadUserInteraction = true;
     statistics.mostRecentUserInteraction = WTF::currentTime();
+
+    m_store->fireShouldPartitionCookiesHandler(primaryDomainStr, false);
 }
 
 void ResourceLoadObserver::clearUserInteraction(const URL& url)
@@ -412,10 +420,19 @@ void ResourceLoadObserver::fireDataModificationHandler()
     m_store->fireDataModificationHandler();
 }
 
+void ResourceLoadObserver::fireShouldPartitionCookiesHandler(const String& hostName, bool value)
+{
+    m_store->fireShouldPartitionCookiesHandler(primaryDomain(hostName), value);
+}
+
 String ResourceLoadObserver::primaryDomain(const URL& url)
 {
+    return primaryDomain(url.host());
+}
+
+String ResourceLoadObserver::primaryDomain(const String& host)
+{
     String primaryDomain;
-    String host = url.host();
     if (host.isNull() || host.isEmpty())
         primaryDomain = "nullOrigin";
 #if ENABLE(PUBLIC_SUFFIX_LIST)
index 78449a7..278cea5 100644 (file)
@@ -66,6 +66,7 @@ public:
     WEBCORE_EXPORT void setReducedTimestampResolution(double seconds);
 
     WEBCORE_EXPORT void fireDataModificationHandler();
+    WEBCORE_EXPORT void fireShouldPartitionCookiesHandler(const String& primaryDomain, bool value);
 
     WEBCORE_EXPORT RefPtr<ResourceLoadStatisticsStore> statisticsStore();
     WEBCORE_EXPORT void setStatisticsStore(Ref<ResourceLoadStatisticsStore>&&);
@@ -75,6 +76,7 @@ public:
 private:
     bool shouldLog(Page*);
     static String primaryDomain(const URL&);
+    static String primaryDomain(const String& host);
 
     RefPtr<ResourceLoadStatisticsStore> m_store;
     HashMap<String, size_t> m_originsVisitedMap;
index 16f4567..660fe15 100644 (file)
@@ -100,8 +100,15 @@ void ResourceLoadStatisticsStore::readDataFromDecoder(KeyedDecoder& decoder)
     if (!succeeded)
         return;
 
-    for (auto& statistics : loadedStatistics)
+    Vector<String> prevalentResourceDomainsWithoutUserInteraction;
+    prevalentResourceDomainsWithoutUserInteraction.reserveInitialCapacity(loadedStatistics.size());
+    for (auto& statistics : loadedStatistics) {
         m_resourceStatisticsMap.set(statistics.highLevelDomain, statistics);
+        if (statistics.isPrevalentResource && !statistics.hadUserInteraction)
+            prevalentResourceDomainsWithoutUserInteraction.uncheckedAppend(statistics.highLevelDomain);
+    }
+    
+    fireShouldPartitionCookiesHandler(prevalentResourceDomainsWithoutUserInteraction, true);
 }
 
 String ResourceLoadStatisticsStore::statisticsForOrigin(const String& origin)
@@ -141,12 +148,30 @@ void ResourceLoadStatisticsStore::setNotificationCallback(std::function<void()>
     m_dataAddedHandler = WTFMove(handler);
 }
 
+void ResourceLoadStatisticsStore::setShouldPartitionCookiesCallback(std::function<void(const Vector<String>& primaryDomains, bool value)>&& handler)
+{
+    m_shouldPartitionCookiesForDomainsHandler = WTFMove(handler);
+}
+    
 void ResourceLoadStatisticsStore::fireDataModificationHandler()
 {
     if (m_dataAddedHandler)
         m_dataAddedHandler();
 }
 
+void ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler(const String& primaryDomain, bool value)
+{
+    Vector<String> domainVector;
+    domainVector.append(primaryDomain);
+    fireShouldPartitionCookiesHandler(domainVector, value);
+}
+
+void ResourceLoadStatisticsStore::fireShouldPartitionCookiesHandler(const Vector<String>& primaryDomains, bool value)
+{
+    if (m_shouldPartitionCookiesForDomainsHandler)
+        m_shouldPartitionCookiesForDomainsHandler(primaryDomains, value);
+}
+
 void ResourceLoadStatisticsStore::setTimeToLiveUserInteraction(double seconds)
 {
     if (seconds >= 0)
@@ -170,6 +195,10 @@ bool ResourceLoadStatisticsStore::hasHadRecentUserInteraction(ResourceLoadStatis
         // it has been reset as opposed to its default -1.
         resourceStatistic.mostRecentUserInteraction = 0;
         resourceStatistic.hadUserInteraction = false;
+
+        if (resourceStatistic.isPrevalentResource)
+            fireShouldPartitionCookiesHandler(resourceStatistic.highLevelDomain, true);
+
         return false;
     }
 
index fcebdf5..cacc2b2 100644 (file)
@@ -56,10 +56,13 @@ public:
     WEBCORE_EXPORT void mergeStatistics(const Vector<ResourceLoadStatistics>&);
     WEBCORE_EXPORT Vector<ResourceLoadStatistics> takeStatistics();
 
-    WEBCORE_EXPORT void setNotificationCallback(std::function<void()> handler);
+    WEBCORE_EXPORT void setNotificationCallback(std::function<void()>);
+    WEBCORE_EXPORT void setShouldPartitionCookiesCallback(std::function<void(const Vector<String>& primaryDomains, bool value)>&&);
 
     void fireDataModificationHandler();
     void setTimeToLiveUserInteraction(double seconds);
+    WEBCORE_EXPORT void fireShouldPartitionCookiesHandler(const String& primaryDomain, bool value);
+    WEBCORE_EXPORT void fireShouldPartitionCookiesHandler(const Vector<String>& primaryDomain, bool value);
 
     WEBCORE_EXPORT void processStatistics(std::function<void(ResourceLoadStatistics&)>&&);
 
@@ -71,6 +74,7 @@ private:
 
     HashMap<String, ResourceLoadStatistics> m_resourceStatisticsMap;
     std::function<void()> m_dataAddedHandler;
+    std::function<void(const Vector<String>& primaryDomains, bool value)> m_shouldPartitionCookiesForDomainsHandler;
 };
     
 } // namespace WebCore
index aedb08a..62cf2ad 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "CredentialStorage.h"
 #include "SessionID.h"
+#include <wtf/HashSet.h>
 #include <wtf/text/WTFString.h>
 
 #if PLATFORM(COCOA) || USE(CFURLCONNECTION)
@@ -67,6 +68,10 @@ public:
     CFURLStorageSessionRef platformSession() { return m_platformSession.get(); }
     WEBCORE_EXPORT RetainPtr<CFHTTPCookieStorageRef> cookieStorage() const;
     WEBCORE_EXPORT static void setCookieStoragePartitioningEnabled(bool);
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    WEBCORE_EXPORT bool shouldPartitionCookiesForHost(const String&);
+    WEBCORE_EXPORT void setShouldPartitionCookiesForHosts(const Vector<String>&, bool value);
+#endif
 #elif USE(SOUP)
     NetworkStorageSession(SessionID, std::unique_ptr<SoupNetworkSession>&&);
     ~NetworkStorageSession();
@@ -106,6 +111,10 @@ private:
 #endif
 
     CredentialStorage m_credentialStorage;
+
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    HashSet<String> m_topPrivatelyControlledDomainsForCookiePartitioning;
+#endif
 };
 
 WEBCORE_EXPORT String cookieStoragePartition(const ResourceRequest&);
index 2117db5..ba06a5b 100644 (file)
@@ -140,4 +140,30 @@ String cookieStoragePartition(const URL& firstPartyForCookies, const URL& resour
 
 #endif
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+
+bool NetworkStorageSession::shouldPartitionCookiesForHost(const String& host)
+{
+    if (host.isEmpty())
+        return false;
+
+    auto domain = topPrivatelyControlledDomain(host);
+    if (domain.isEmpty())
+        domain = host;
+
+    return m_topPrivatelyControlledDomainsForCookiePartitioning.contains(domain);
+}
+
+void NetworkStorageSession::setShouldPartitionCookiesForHosts(const Vector<String>& hosts, bool value)
+{
+    if (value)
+        m_topPrivatelyControlledDomainsForCookiePartitioning.add(hosts.begin(), hosts.end());
+    else {
+        for (auto& host : hosts)
+            m_topPrivatelyControlledDomainsForCookiePartitioning.remove(host);
+    }
+}
+
+#endif // HAVE(CFNETWORK_STORAGE_PARTITIONING)
+
 }
index dddd2ac..00a7b06 100644 (file)
@@ -1,3 +1,55 @@
+2017-03-08  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Communicate to the network process which domains to partition
+        https://bugs.webkit.org/show_bug.cgi?id=169322
+        <rdar://problem/30768921>
+
+        Reviewed by Alex Christensen.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
+        (WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
+            Now consults WebCore::NetworkStorageSession::shouldPartitionCookiesForHost()
+            to decide whether partitioning should be applied or not.
+        * UIProcess/API/C/WKCookieManager.cpp:
+        (WKCookieManagerSetCookieStoragePartitioningEnabled):
+            To allow TestRunner to configure cookie partitioning.
+        * UIProcess/API/C/WKCookieManager.h:
+        * UIProcess/API/C/WKResourceLoadStatisticsManager.cpp:
+        (WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler):
+            To allow TestRunner to set a domain for which
+            partitioning should be applied.
+        * UIProcess/API/C/WKResourceLoadStatisticsManager.h:
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+        * UIProcess/WebCookieManagerProxy.cpp:
+        (WebKit::WebCookieManagerProxy::setCookieStoragePartitioningEnabled):
+            To allow TestRunner to configure cookie partitioning.
+        * UIProcess/WebCookieManagerProxy.h:
+        * UIProcess/WebResourceLoadStatisticsManager.cpp:
+        (WebKit::WebResourceLoadStatisticsManager::fireShouldPartitionCookiesHandler):
+            To allow TestRunner to set a domain for which
+            partitioning should be applied.
+        * UIProcess/WebResourceLoadStatisticsManager.h:
+        * UIProcess/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::classifyResource):
+            Now tells the network process as soon as a domain
+            has been classified as prevalent.
+        (WebKit::WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver):
+            Overloaded function to allow injection of handlers for communication with the
+            network process.
+        * UIProcess/WebResourceLoadStatisticsStore.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::shouldPartitionCookiesForTopPrivatelyOwnedDomains):
+        (WebKit::WebsiteDataStore::registerSharedResourceLoadObserver):
+            Now sets two callback handlers for communication with the network process.
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+
 2017-03-08  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         Fix -Wattributes warning spam
index 6836da6..79f68e1 100644 (file)
@@ -310,6 +310,13 @@ void NetworkProcess::didGrantSandboxExtensionsToDatabaseProcessForBlobs(uint64_t
         handler();
 }
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+void NetworkProcess::shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>& domains, bool value)
+{
+    NetworkStorageSession::defaultStorageSession().setShouldPartitionCookiesForHosts(domains, value);
+}
+#endif
+
 static void fetchDiskCacheEntries(SessionID sessionID, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void (Vector<WebsiteData::Entry>)>&& completionHandler)
 {
 #if ENABLE(NETWORK_CACHE)
index b94feb5..9188eac 100644 (file)
@@ -116,6 +116,10 @@ public:
 
     void grantSandboxExtensionsToDatabaseProcessForBlobs(const Vector<String>& filenames, Function<void ()>&& completionHandler);
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    void shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>&, bool value);
+#endif
+
     std::chrono::milliseconds loadThrottleLatency() const { return m_loadThrottleLatency; }
 
 private:
index 0a99169..598158f 100644 (file)
@@ -77,4 +77,8 @@ messages -> NetworkProcess LegacyReceiver {
     ProcessDidResume()
 
     DidGrantSandboxExtensionsToDatabaseProcessForBlobs(uint64_t requestID)
+
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    ShouldPartitionCookiesForTopPrivatelyOwnedDomains(Vector<String> topPrivatelyOwnedDomains, bool value)
+#endif
 }
index 32cb6cf..52a56f6 100644 (file)
@@ -123,9 +123,12 @@ NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataT
     LOG(NetworkSession, "%llu Creating NetworkDataTask with URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
 
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
-    String storagePartition = WebCore::cookieStoragePartition(request);
-    if (!storagePartition.isEmpty())
-        m_task.get()._storagePartitionIdentifier = storagePartition;
+    if (session.networkStorageSession().shouldPartitionCookiesForHost(url.host())) {
+        LOG(NetworkSession, "%llu Partitioning cookies for URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
+        String storagePartition = WebCore::cookieStoragePartition(request);
+        if (!storagePartition.isEmpty())
+            m_task.get()._storagePartitionIdentifier = storagePartition;
+    }
 #endif
 
     if (WebCore::ResourceRequest::resourcePrioritiesEnabled())
index 7624bee..278e83c 100644 (file)
@@ -74,6 +74,11 @@ void WKCookieManagerGetHTTPCookieAcceptPolicy(WKCookieManagerRef cookieManager,
     toImpl(cookieManager)->getHTTPCookieAcceptPolicy(toGenericCallbackFunction<WKHTTPCookieAcceptPolicy, HTTPCookieAcceptPolicy>(context, callback));
 }
 
+void WKCookieManagerSetCookieStoragePartitioningEnabled(WKCookieManagerRef cookieManager, bool enabled)
+{
+    toImpl(cookieManager)->setCookieStoragePartitioningEnabled(enabled);
+}
+
 void WKCookieManagerStartObservingCookieChanges(WKCookieManagerRef cookieManager)
 {
     toImpl(cookieManager)->startObservingCookieChanges(WebCore::SessionID::defaultSessionID());
index 8f4111c..0e8d721 100644 (file)
@@ -72,6 +72,8 @@ WK_EXPORT void WKCookieManagerSetHTTPCookieAcceptPolicy(WKCookieManagerRef cooki
 typedef void (*WKCookieManagerGetHTTPCookieAcceptPolicyFunction)(WKHTTPCookieAcceptPolicy, WKErrorRef, void*);
 WK_EXPORT void WKCookieManagerGetHTTPCookieAcceptPolicy(WKCookieManagerRef cookieManager, void* context, WKCookieManagerGetHTTPCookieAcceptPolicyFunction callback);
 
+WK_EXPORT void WKCookieManagerSetCookieStoragePartitioningEnabled(WKCookieManagerRef cookieManager, bool enabled);
+
 WK_EXPORT void WKCookieManagerStartObservingCookieChanges(WKCookieManagerRef cookieManager);
 WK_EXPORT void WKCookieManagerStopObservingCookieChanges(WKCookieManagerRef cookieManager);
 
index 9edb84f..458b9c8 100644 (file)
@@ -81,6 +81,11 @@ void WKResourceLoadStatisticsManagerFireDataModificationHandler()
     WebResourceLoadStatisticsManager::fireDataModificationHandler();
 }
 
+void WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler(WKStringRef hostName, bool value)
+{
+    WebResourceLoadStatisticsManager::fireShouldPartitionCookiesHandler(toWTFString(hostName), value);
+}
+
 void WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WebResourceLoadStatisticsManager::setNotifyPagesWhenDataRecordsWereScanned(value);
index 9baf88a..1386563 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
     WK_EXPORT void WKResourceLoadStatisticsManagerSetSubresourceUniqueRedirectTo(WKStringRef hostName, WKStringRef hostNameRedirectedTo);
     WK_EXPORT void WKResourceLoadStatisticsManagerSetTimeToLiveUserInteraction(double seconds);
     WK_EXPORT void WKResourceLoadStatisticsManagerFireDataModificationHandler();
+    WK_EXPORT void WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler(WKStringRef hostName, bool value);
     WK_EXPORT void WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(bool value);
     WK_EXPORT void WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(bool value);
     WK_EXPORT void WKResourceLoadStatisticsManagerSetMinimumTimeBetweeenDataRecordsRemoval(double seconds);
index 2c93e8b..e30b378 100644 (file)
@@ -292,6 +292,13 @@ void NetworkProcessProxy::grantSandboxExtensionsToDatabaseProcessForBlobs(uint64
 #endif
 }
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+void NetworkProcessProxy::shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>& topPrivatelyOwnedDomains, bool value)
+{
+    connection()->send(Messages::NetworkProcess::ShouldPartitionCookiesForTopPrivatelyOwnedDomains(topPrivatelyOwnedDomains, value), 0);
+}
+#endif
+
 void NetworkProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
 {
     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
index 5e9566c..55080bd 100644 (file)
@@ -109,6 +109,9 @@ private:
     void didDeleteWebsiteData(uint64_t callbackID);
     void didDeleteWebsiteDataForOrigins(uint64_t callbackID);
     void grantSandboxExtensionsToDatabaseProcessForBlobs(uint64_t requestID, const Vector<String>& paths);
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    void shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>&, bool value);
+#endif
     void logDiagnosticMessage(uint64_t pageID, const String& message, const String& description, WebCore::ShouldSample);
     void logDiagnosticMessageWithResult(uint64_t pageID, const String& message, const String& description, uint32_t result, WebCore::ShouldSample);
     void logDiagnosticMessageWithValue(uint64_t pageID, const String& message, const String& description, double value, unsigned significantFigures, WebCore::ShouldSample);
index 0c902ed..7b5956a 100644 (file)
@@ -31,6 +31,10 @@ messages -> NetworkProcessProxy LegacyReceiver {
 
     GrantSandboxExtensionsToDatabaseProcessForBlobs(uint64_t requestID, Vector<String> paths)
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    ShouldPartitionCookiesForTopPrivatelyOwnedDomains(Vector<String> topPrivatelyOwnedDomains, bool value)
+#endif
+
     ProcessReadyToSuspend()
     SetIsHoldingLockedFiles(bool isHoldingLockedFiles)
 
index 2a9b0dd..08a7979 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "APIArray.h"
 #include "APISecurityOrigin.h"
+#include "NetworkProcessMessages.h"
 #include "WebCookieManagerMessages.h"
 #include "WebCookieManagerProxyMessages.h"
 #include "WebProcessPool.h"
@@ -196,4 +197,13 @@ void WebCookieManagerProxy::didGetHTTPCookieAcceptPolicy(uint32_t policy, uint64
     callback->performCallbackWithReturnValue(policy);
 }
 
+void WebCookieManagerProxy::setCookieStoragePartitioningEnabled(bool enabled)
+{
+#if PLATFORM(COCOA)
+    processPool()->sendToNetworkingProcess(Messages::NetworkProcess::SetCookieStoragePartitioningEnabled(enabled));
+#else
+    UNUSED_PARAM(enabled);
+#endif
+}
+
 } // namespace WebKit
index 44005bc..65d047c 100644 (file)
@@ -73,6 +73,7 @@ public:
 
     void setHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicy);
     void getHTTPCookieAcceptPolicy(std::function<void (HTTPCookieAcceptPolicy, CallbackBase::Error)>);
+    void setCookieStoragePartitioningEnabled(bool);
 
     void startObservingCookieChanges(WebCore::SessionID);
     void stopObservingCookieChanges(WebCore::SessionID);
index b028d8f..7b3f336 100644 (file)
@@ -86,6 +86,11 @@ void WebResourceLoadStatisticsManager::fireDataModificationHandler()
     WebCore::ResourceLoadObserver::sharedObserver().fireDataModificationHandler();
 }
 
+void WebResourceLoadStatisticsManager::fireShouldPartitionCookiesHandler(const String& hostName, bool value)
+{
+    WebCore::ResourceLoadObserver::sharedObserver().fireShouldPartitionCookiesHandler(hostName, value);
+}
+
 void WebResourceLoadStatisticsManager::setNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(value);
index 7223cda..fa06c2a 100644 (file)
@@ -48,6 +48,7 @@ public:
     static void setTimeToLiveUserInteraction(double seconds);
     static void setReducedTimestampResolution(double seconds);
     static void fireDataModificationHandler();
+    static void fireShouldPartitionCookiesHandler(const String& hostName, bool value);
     static void setNotifyPagesWhenDataRecordsWereScanned(bool);
     static void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value);
     static void setMinimumTimeBetweeenDataRecordsRemoval(double seconds);
index 5846879..0aacbd4 100644 (file)
@@ -85,8 +85,11 @@ void WebResourceLoadStatisticsStore::setMinimumTimeBetweeenDataRecordsRemoval(do
 void WebResourceLoadStatisticsStore::classifyResource(ResourceLoadStatistics& resourceStatistic)
 {
     if (!resourceStatistic.isPrevalentResource
-        && m_resourceLoadStatisticsClassifier.hasPrevalentResourceCharacteristics(resourceStatistic))
+        && m_resourceLoadStatisticsClassifier.hasPrevalentResourceCharacteristics(resourceStatistic)) {
         resourceStatistic.isPrevalentResource = true;
+        if (!resourceStatistic.hadUserInteraction)
+            m_resourceLoadStatisticsStore->fireShouldPartitionCookiesHandler(resourceStatistic.highLevelDomain, true);
+    }
 }
 
 void WebResourceLoadStatisticsStore::removeDataRecords()
@@ -170,7 +173,6 @@ bool WebResourceLoadStatisticsStore::resourceLoadStatisticsEnabled() const
     return m_resourceLoadStatisticsEnabled;
 }
 
-
 void WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver()
 {
     ResourceLoadObserver::sharedObserver().setStatisticsStore(m_resourceLoadStatisticsStore.copyRef());
@@ -180,6 +182,14 @@ void WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver()
         processStatisticsAndDataRecords();
     });
 }
+    
+void WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver(std::function<void(const Vector<String>& primaryDomain, bool value)>&& shouldPartitionCookiesForDomainsHandler)
+{
+    registerSharedResourceLoadObserver();
+    m_resourceLoadStatisticsStore->setShouldPartitionCookiesCallback([this, shouldPartitionCookiesForDomainsHandler = WTFMove(shouldPartitionCookiesForDomainsHandler)] (const Vector<String>& primaryDomains, bool value) {
+        shouldPartitionCookiesForDomainsHandler(primaryDomains, value);
+    });
+}
 
 void WebResourceLoadStatisticsStore::readDataFromDiskIfNeeded()
 {
index 7f94c0c..6c822e9 100644 (file)
@@ -63,6 +63,7 @@ public:
     void setResourceLoadStatisticsEnabled(bool);
     bool resourceLoadStatisticsEnabled() const;
     void registerSharedResourceLoadObserver();
+    void registerSharedResourceLoadObserver(std::function<void(const Vector<String>& primaryDomain, bool value)>&& shouldPartitionCookiesForDomainsHandler);
     
     void resourceLoadStatisticsUpdated(const Vector<WebCore::ResourceLoadStatistics>& origins);
 
index 4bad738..994595a 100644 (file)
@@ -1048,6 +1048,14 @@ void WebsiteDataStore::removeDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDa
     });
 }
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+void WebsiteDataStore::shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>& topPrivatelyOwnedDomains, bool value)
+{
+    for (auto& processPool : processPools())
+        processPool->sendToNetworkingProcess(Messages::NetworkProcess::ShouldPartitionCookiesForTopPrivatelyOwnedDomains(topPrivatelyOwnedDomains, value));
+}
+#endif
+
 void WebsiteDataStore::webPageWasAdded(WebPageProxy& webPageProxy)
 {
     if (m_storageManager)
@@ -1212,8 +1220,15 @@ void WebsiteDataStore::registerSharedResourceLoadObserver()
 {
     if (!m_resourceLoadStatistics)
         return;
-
+    
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    m_resourceLoadStatistics->registerSharedResourceLoadObserver(
+        [this] (const Vector<String>& topPrivatelyOwnedDomains, bool value) {
+            this->shouldPartitionCookiesForTopPrivatelyOwnedDomains(topPrivatelyOwnedDomains, value);
+        });
+#else
     m_resourceLoadStatistics->registerSharedResourceLoadObserver();
+#endif
 }
 
 }
index 94e343e..46eac2d 100644 (file)
@@ -90,6 +90,9 @@ public:
     void removeData(OptionSet<WebsiteDataType>, const Vector<WebsiteDataRecord>&, std::function<void ()> completionHandler);
     void removeDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, const Vector<String>& topPrivatelyOwnedDomains, std::function<void(Vector<String>)> completionHandler);
 
+#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
+    void shouldPartitionCookiesForTopPrivatelyOwnedDomains(const Vector<String>&, bool value);
+#endif
     void resolveDirectoriesIfNecessary();
     const String& resolvedApplicationCacheDirectory() const { return m_resolvedConfiguration.applicationCacheDirectory; }
     const String& resolvedMediaCacheDirectory() const { return m_resolvedConfiguration.mediaCacheDirectory; }
index da84af1..d47faee 100644 (file)
@@ -1,3 +1,26 @@
+2017-03-08  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Communicate to the network process which domains to partition
+        https://bugs.webkit.org/show_bug.cgi?id=169322
+        <rdar://problem/30768921>
+
+        Reviewed by Alex Christensen.
+
+        These changes add support for two new TestRunner functions:
+        - setCookieStoragePartitioningEnabled()
+        - statisticsFireShouldPartitionCookiesHandler()
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setCookieStoragePartitioningEnabled):
+        (WTR::TestRunner::statisticsFireShouldPartitionCookiesHandler):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::statisticsFireShouldPartitionCookiesHandler):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
 2017-03-08  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Enable async image decoding for large images
index 01ea5a4..e4844ee 100644 (file)
@@ -163,6 +163,7 @@ interface TestRunner {
 
     // Cookies testing
     void setAlwaysAcceptCookies(boolean accept);
+    void setCookieStoragePartitioningEnabled(boolean enabled);
 
     void overridePreference(DOMString preference, DOMString value);
 
@@ -258,6 +259,7 @@ interface TestRunner {
     void setStatisticsSubresourceUniqueRedirectTo(DOMString hostName, DOMString hostNameRedirectedTo);
     void setStatisticsTimeToLiveUserInteraction(double seconds);
     void statisticsFireDataModificationHandler();
+    void statisticsFireShouldPartitionCookiesHandler(DOMString hostName, boolean value);
     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(boolean value);
     void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(boolean value);
     void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds);
index dfa7c56..f15f30a 100644 (file)
@@ -766,6 +766,15 @@ void TestRunner::setAlwaysAcceptCookies(bool accept)
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
 }
 
+void TestRunner::setCookieStoragePartitioningEnabled(bool enabled)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCookieStoragePartitioningEnabled"));
+
+    WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
+
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
 double TestRunner::preciseTime()
 {
     return currentTime();
@@ -1328,6 +1337,31 @@ void TestRunner::statisticsFireDataModificationHandler()
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
 }
 
+void TestRunner::statisticsFireShouldPartitionCookiesHandler(JSStringRef hostName, bool value)
+{
+    Vector<WKRetainPtr<WKStringRef>> keys;
+    Vector<WKRetainPtr<WKTypeRef>> values;
+    
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
+    values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
+    
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
+    values.append({ AdoptWK, WKBooleanCreate(value) });
+    
+    Vector<WKStringRef> rawKeys(keys.size());
+    Vector<WKTypeRef> rawValues(values.size());
+    
+    for (size_t i = 0; i < keys.size(); ++i) {
+        rawKeys[i] = keys[i].get();
+        rawValues[i] = values[i].get();
+    }
+    
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireShouldPartitionCookiesHandler"));
+    WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+    
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
index 228521e..e033716 100644 (file)
@@ -271,6 +271,7 @@ public:
 
     // Cookies testing
     void setAlwaysAcceptCookies(bool);
+    void setCookieStoragePartitioningEnabled(bool);
 
     // Custom full screen behavior.
     void setHasCustomFullScreenBehavior(bool value) { m_customFullScreenBehavior = value; }
@@ -351,6 +352,7 @@ public:
     void installStatisticsDidModifyDataRecordsCallback(JSValueRef callback);
     void statisticsDidModifyDataRecordsCallback();
     void statisticsFireDataModificationHandler();
+    void statisticsFireShouldPartitionCookiesHandler(JSStringRef hostName, bool value);
     void setStatisticsPrevalentResource(JSStringRef hostName, bool value);
     bool isStatisticsPrevalentResource(JSStringRef hostName);
     void setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value);
index 060eac9..fed2efe 100644 (file)
@@ -2270,6 +2270,11 @@ void TestController::statisticsFireDataModificationHandler()
     WKResourceLoadStatisticsManagerFireDataModificationHandler();
 }
     
+void TestController::statisticsFireShouldPartitionCookiesHandler(WKStringRef hostName, bool value)
+{
+    WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler(hostName, value);
+}
+
 void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(value);
index fa44774..253a641 100644 (file)
@@ -157,6 +157,7 @@ public:
     void setStatisticsSubresourceUniqueRedirectTo(WKStringRef hostName, WKStringRef hostNameRedirectedTo);
     void setStatisticsTimeToLiveUserInteraction(double seconds);
     void statisticsFireDataModificationHandler();
+    void statisticsFireShouldPartitionCookiesHandler(WKStringRef hostName, bool value);
     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
     void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
     void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double);
index f429719..2c74b3e 100644 (file)
@@ -793,6 +793,12 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
         return nullptr;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "SetCookieStoragePartitioningEnabled")) {
+        WKBooleanRef accept = static_cast<WKBooleanRef>(messageBody);
+        WKCookieManagerSetCookieStoragePartitioningEnabled(WKContextGetCookieManager(TestController::singleton().context()), WKBooleanGetValue(accept));
+        return nullptr;
+    }
+    
     if (WKStringIsEqualToUTF8CString(messageName, "ImageCountInGeneralPasteboard")) {
         unsigned count = TestController::singleton().imageCountInGeneralPasteboard();
         WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count));
@@ -991,6 +997,20 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
         return nullptr;
     }
     
+    if (WKStringIsEqualToUTF8CString(messageName, "StatisticsFireShouldPartitionCookiesHandler")) {
+        ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+        
+        WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+        WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
+        WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
+        
+        WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
+        WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
+        
+        TestController::singleton().statisticsFireShouldPartitionCookiesHandler(hostName, WKBooleanGetValue(value));
+        return nullptr;
+    }
+    
     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenDataRecordsWereScanned")) {
         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);