<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[243181] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/243181">243181</a></dd>
<dt>Author</dt> <dd>wilander@apple.com</dd>
<dt>Date</dt> <dd>2019-03-19 17:22:09 -0700 (Tue, 19 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Resource Load Statistics (experimental): Clear non-cookie website data for sites that have been navigated to, with link decoration, by a prevalent resource
https://bugs.webkit.org/show_bug.cgi?id=195923
<rdar://problem/49001272>

Reviewed by Alex Christensen.

Source/WebCore:

Adds a new experimental feature.

Test: http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html

* page/RuntimeEnabledFeatures.h:
(WebCore::RuntimeEnabledFeatures::setIsITPFirstPartyWebsiteDataRemovalEnabled):
(WebCore::RuntimeEnabledFeatures::isITPFirstPartyWebsiteDataRemovalEnabled const):

Source/WebKit:

Cross-site trackers abuse link query parameters to transport user identifiers and then store
them in first-party storage space. To address this, we've done three things:
- <a href="http://trac.webkit.org/projects/webkit/changeset/236448">r236448</a> capped all persistent client-side cookies to seven days of storage.
- <a href="http://trac.webkit.org/projects/webkit/changeset/242288">r242288</a> further capped persistent client-side cookies for navigations with link decoration from prevalent resources.
- <a href="http://trac.webkit.org/projects/webkit/changeset/242603">r242603</a> added logging of navigations with link decoration from prevalent resources.

This patch introduces an experimental feature that removes non-cookie website data for sites
that have been navigated to, with link decoration, by a prevalent resource.

To achieve this, resource domains to remove website data for are now marked with an enum called
WebsiteDataToRemove with values All, AllButHttpOnlyCookies, AllButCookies. As resources are
iterated, they are marked for either of these values and the new function
ResourceLoadStatisticsMemoryStore::shouldRemoveAllButCookiesFor() leads to the marking with
WebsiteDataToRemove::AllButCookies.

Then NetworkProcess::deleteWebsiteDataForRegistrableDomains() looks at this setting and removes
website data accordingly.

The thinking behind this is that the lifetime cap applied in <a href="http://trac.webkit.org/projects/webkit/changeset/236448">r236448</a> and <a href="http://trac.webkit.org/projects/webkit/changeset/242288">r242288</a> take care of
script writable cookies, and this patch takes care of all other script writable storage.

The infrastructure to handle user interaction expiration is now parameterized so that multiple
expiries can be applied. In this particular case, seven days of browser use.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal):
(WebKit::ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction):
(WebKit::ResourceLoadStatisticsDatabaseStore::shouldRemoveAllWebsiteDataFor const):
(WebKit::ResourceLoadStatisticsDatabaseStore::shouldRemoveAllButCookiesFor const):
(WebKit::ResourceLoadStatisticsDatabaseStore::registrableDomainsToRemoveWebsiteDataFor):
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
(WebKit::ResourceLoadStatisticsMemoryStore::hasHadUserInteraction):
(WebKit::ResourceLoadStatisticsMemoryStore::hasHadUnexpiredRecentUserInteraction const):
(WebKit::ResourceLoadStatisticsMemoryStore::shouldRemoveAllWebsiteDataFor const):
(WebKit::ResourceLoadStatisticsMemoryStore::shouldRemoveAllButCookiesFor const):
(WebKit::ResourceLoadStatisticsMemoryStore::registrableDomainsToRemoveWebsiteDataFor):
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp:
(WebKit::domainsToString):
(WebKit::ResourceLoadStatisticsStore::removeDataRecords):
(WebKit::ResourceLoadStatisticsStore::statisticsEpirationTime const):
(WebKit::ResourceLoadStatisticsStore::mergeOperatingDates):
(WebKit::ResourceLoadStatisticsStore::includeTodayAsOperatingDateIfNecessary):
(WebKit::ResourceLoadStatisticsStore::hasStatisticsExpired const):
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::hasHadUserInteraction):
(WebKit::WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomains):
(WebKit::WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
   Renamed to reflect that it actually takes a parameter for which types of data to remove.
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::initializeNetworkProcess):
(WebKit::NetworkProcess::setCrossSiteLoadWithLinkDecorationForTesting):
(WebKit::NetworkProcess::deleteWebsiteDataForRegistrableDomains):
(WebKit::NetworkProcess::deleteCookiesForTesting):
(WebKit::NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
   Renamed to reflect that it actually takes a parameter for which types of data to remove.
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/NetworkProcessCreationParameters.cpp:
(WebKit::NetworkProcessCreationParameters::encode const):
(WebKit::NetworkProcessCreationParameters::decode):
* NetworkProcess/NetworkProcessCreationParameters.h:
* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::deleteWebsiteDataForRegistrableDomains):
(WebKit::NetworkSession::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
   Renamed to reflect that it actually takes a parameter for which types of data to remove.
* NetworkProcess/NetworkSession.h:
* Shared/WebPreferences.yaml:
* UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
(WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration):
(WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction):
(WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords):
* UIProcess/API/C/WKWebsiteDataStoreRef.h:
* UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::WebProcessPool::platformInitializeNetworkProcess):
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::setCrossSiteLoadWithLinkDecorationForTesting):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::setCrossSiteLoadWithLinkDecorationForTesting):
* UIProcess/WebsiteData/WebsiteDataStore.h:

Tools:

This patch does the following to the TestRunner:
- Adds setStatisticsCrossSiteLoadWithLinkDecoration().
- Makes setStatisticsTimeToLiveUserInteraction() wait for completion.
- Makes statisticsProcessStatisticsAndDataRecords() wait for completion.

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

LayoutTests:

* http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt: Added.
* http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorepageRuntimeEnabledFeaturesh">trunk/Source/WebCore/page/RuntimeEnabledFeatures.h</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStoreh">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsMemoryStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsMemoryStoreh">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsStoreh">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStoreh">trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcesscpp">trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcessh">trunk/Source/WebKit/NetworkProcess/NetworkProcess.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcessmessagesin">trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcessCreationParameterscpp">trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcessCreationParametersh">trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkSessioncpp">trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkSessionh">trunk/Source/WebKit/NetworkProcess/NetworkSession.h</a></li>
<li><a href="#trunkSourceWebKitSharedWebPreferencesyaml">trunk/Source/WebKit/Shared/WebPreferences.yaml</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKWebsiteDataStoreRefcpp">trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKWebsiteDataStoreRefh">trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaWebProcessPoolCocoamm">trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessNetworkNetworkProcessProxycpp">trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessNetworkNetworkProcessProxyh">trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebsiteDataWebsiteDataStorecpp">trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebsiteDataWebsiteDataStoreh">trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleBindingsTestRunneridl">trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleTestRunnercpp">trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleTestRunnerh">trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestControllercpp">trunk/Tools/WebKitTestRunner/TestController.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestControllerh">trunk/Tools/WebKitTestRunner/TestController.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestInvocationcpp">trunk/Tools/WebKitTestRunner/TestInvocation.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestsresourceLoadStatisticswebsitedataremovalforsitenavigatedtowithlinkdecorationexpectedtxt">trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsresourceLoadStatisticswebsitedataremovalforsitenavigatedtowithlinkdecorationhtml">trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/LayoutTests/ChangeLog 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2019-03-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics (experimental): Clear non-cookie website data for sites that have been navigated to, with link decoration, by a prevalent resource
+        https://bugs.webkit.org/show_bug.cgi?id=195923
+        <rdar://problem/49001272>
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt: Added.
+        * http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html: Added.
+
</ins><span class="cx"> 2019-03-19  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Reparenting during a mutation event inside appendChild could result in a circular DOM tree
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsresourceLoadStatisticswebsitedataremovalforsitenavigatedtowithlinkdecorationexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt (0 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt                         (rev 0)
+++ trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration-expected.txt    2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+Check that non-cookie website data gets removed after a navigation with link decoration from a prevalent resource.
+
+Before deletion: Client-side cookie exists.
+Before deletion: HttpOnly cookie exists.
+Before deletion: Regular server-side cookie exists.
+
+Before deletion: IDB entry does exist.
+
+After deletion: HttpOnly cookie exists.
+After deletion: Client-side cookie exists.
+After deletion: Regular server-side cookie exists.
+
+After deletion: IDB entry does not exist.
+
+
+Resource load statistics:
+
+Registrable domain: localhost
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    gotLinkDecorationFromPrevalentResource: No    isPrevalentResource: Yes
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 0
+Registrable domain: 127.0.0.1
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    topFrameLinkDecorationsFrom:
+        localhost
+    gotLinkDecorationFromPrevalentResource: No    isPrevalentResource: No
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 1
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestsresourceLoadStatisticswebsitedataremovalforsitenavigatedtowithlinkdecorationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html (0 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html                         (rev 0)
+++ trunk/LayoutTests/http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html    2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/cookies/resources/cookie-utilities.js"></script>
+    <script src="resources/util.js"></script>
+</head>
+<body onload="setTimeout('runTest()', 0)">
+<div id="description">Check that non-cookie website data gets removed after a navigation with link decoration from a prevalent resource.</div>
+<br>
+<div id="output"></div>
+<br>
+<script>
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+
+    const httpOnlyCookieName = "http-only-cookie";
+    const serverSideCookieName = "server-side-cookie";
+    const clientSideCookieName = "client-side-cookie";
+
+    function sortStringArray(a, b) {
+        a = a.toLowerCase();
+        b = b.toLowerCase();
+
+        return a > b ? 1 : b > a ? -1 : 0;
+    }
+
+    function addLinebreakToOutput() {
+        let element = document.createElement("br");
+        output.appendChild(element);
+    }
+
+    function addOutput(message) {
+        let element = document.createElement("div");
+        element.innerText = message;
+        output.appendChild(element);
+    }
+
+    function checkCookies(isAfterDeletion) {
+        let unsortedTestPassedMessages = [];
+        let cookies = internals.getCookies();
+        if (!cookies.length)
+            testFailed((isAfterDeletion ? "After" : "Before") + " script-accessible deletion: No cookies found.");
+        for (let cookie of cookies) {
+            switch (cookie.name) {
+                case httpOnlyCookieName:
+                    unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: " + (isAfterDeletion ? " " : "") + "HttpOnly cookie exists.");
+                    break;
+                case serverSideCookieName:
+                    unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: Regular server-side cookie exists.");
+                    break;
+                case clientSideCookieName:
+                    unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: Client-side cookie exists.");
+                    break;
+            }
+        }
+        let sortedTestPassedMessages = unsortedTestPassedMessages.sort(sortStringArray);
+        for (let testPassedMessage of sortedTestPassedMessages) {
+            addOutput(testPassedMessage);
+        }
+    }
+
+    const dbName = "TestDatabase";
+
+    function createIDBDataStore(callback) {
+        let request = indexedDB.open(dbName);
+        request.onerror = function() {
+            addOutput("Couldn't create indexedDB.");
+            finishTest();
+        };
+        request.onupgradeneeded = function(event) {
+            let db = event.target.result;
+            let objStore = db.createObjectStore("test", {autoIncrement: true});
+            objStore.add("value");
+            callback();
+        }
+    }
+
+    function checkIDBDataStoreExists(isAfterDeletion, callback) {
+        let request = indexedDB.open(dbName);
+        request.onerror = function() {
+            addOutput("Couldn't open indexedDB.");
+            finishTest();
+        };
+        request.onupgradeneeded = function () {
+            addOutput((isAfterDeletion ? "After" : "Before") + " deletion: IDB entry does not exist.");
+            callback();
+        };
+        request.onsuccess = function() {
+            addOutput((isAfterDeletion ? "After" : "Before") + " deletion: IDB entry does exist.");
+            callback();
+        };
+    }
+
+    async function writeWebsiteDataAndContinue() {
+        // Write cookies.
+        await fetch("/cookies/resources/set-http-only-cookie.php?cookieName=" + httpOnlyCookieName, { credentials: "same-origin" });
+        await fetch("/cookies/resources/setCookies.cgi", { headers: { "Set-Cookie": serverSideCookieName + "=1; path=/;" }, credentials: "same-origin" });
+        document.cookie = clientSideCookieName + "=1";
+
+        checkCookies(false);
+        addLinebreakToOutput();
+
+        // Write IndexedDB.
+        createIDBDataStore(function () {
+            checkIDBDataStoreExists(false, processWebsiteDataAndContinue);
+        });
+    }
+
+    function processWebsiteDataAndContinue() {
+        testRunner.statisticsProcessStatisticsAndDataRecords();
+
+        addLinebreakToOutput();
+        checkCookies(true);
+        addLinebreakToOutput();
+        checkIDBDataStoreExists(true, finishTest);
+    }
+
+    function finishTest() {
+        resetCookies();
+        testRunner.dumpResourceLoadStatistics();
+        setEnableFeature(false, function() {
+            testRunner.notifyDone();
+        });
+    }
+
+    const prevalentResourceOrigin = "http://localhost:8000";
+    const destinationOrigin  = "http://127.0.0.1:8000";
+    function runTest() {
+        setEnableFeature(true, function () {
+            testRunner.setStatisticsPrevalentResource(prevalentResourceOrigin, true, function() {
+                testRunner.setStatisticsCrossSiteLoadWithLinkDecoration(prevalentResourceOrigin, destinationOrigin);
+                writeWebsiteDataAndContinue();
+            });
+        });
+    }
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebCore/ChangeLog      2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2019-03-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics (experimental): Clear non-cookie website data for sites that have been navigated to, with link decoration, by a prevalent resource
+        https://bugs.webkit.org/show_bug.cgi?id=195923
+        <rdar://problem/49001272>
+
+        Reviewed by Alex Christensen.
+
+        Adds a new experimental feature.
+
+        Test: http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html
+
+        * page/RuntimeEnabledFeatures.h:
+        (WebCore::RuntimeEnabledFeatures::setIsITPFirstPartyWebsiteDataRemovalEnabled):
+        (WebCore::RuntimeEnabledFeatures::isITPFirstPartyWebsiteDataRemovalEnabled const):
+
</ins><span class="cx"> 2019-03-19  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Reparenting during a mutation event inside appendChild could result in a circular DOM tree
</span></span></pre></div>
<a id="trunkSourceWebCorepageRuntimeEnabledFeaturesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/RuntimeEnabledFeatures.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/RuntimeEnabledFeatures.h       2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebCore/page/RuntimeEnabledFeatures.h  2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -150,6 +150,9 @@
</span><span class="cx"> 
</span><span class="cx">     void setIsITPDatabaseEnabled(bool isEnabled) { m_isITPDatabaseEnabled = isEnabled; }
</span><span class="cx">     bool isITPDatabaseEnabled() const { return m_isITPDatabaseEnabled; }
</span><ins>+    
+    void setIsITPFirstPartyWebsiteDataRemovalEnabled(bool isEnabled) { m_isITPFirstPartyWebsiteDataRemovalEnabled = isEnabled; }
+    bool isITPFirstPartyWebsiteDataRemovalEnabled() const { return m_isITPFirstPartyWebsiteDataRemovalEnabled; }
</ins><span class="cx"> 
</span><span class="cx">     void setRestrictedHTTPResponseAccess(bool isEnabled) { m_isRestrictedHTTPResponseAccess = isEnabled; }
</span><span class="cx">     bool restrictedHTTPResponseAccess() const { return m_isRestrictedHTTPResponseAccess; }
</span><span class="lines">@@ -537,6 +540,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     bool m_isITPDatabaseEnabled { false };
</span><ins>+    bool m_isITPFirstPartyWebsiteDataRemovalEnabled { false };
</ins><span class="cx"> 
</span><span class="cx">     bool m_referrerPolicyAttributeEnabled { false };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/ChangeLog       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1,3 +1,97 @@
</span><ins>+2019-03-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics (experimental): Clear non-cookie website data for sites that have been navigated to, with link decoration, by a prevalent resource
+        https://bugs.webkit.org/show_bug.cgi?id=195923
+        <rdar://problem/49001272>
+
+        Reviewed by Alex Christensen.
+
+        Cross-site trackers abuse link query parameters to transport user identifiers and then store
+        them in first-party storage space. To address this, we've done three things:
+        - r236448 capped all persistent client-side cookies to seven days of storage.
+        - r242288 further capped persistent client-side cookies for navigations with link decoration from prevalent resources.
+        - r242603 added logging of navigations with link decoration from prevalent resources.
+
+        This patch introduces an experimental feature that removes non-cookie website data for sites
+        that have been navigated to, with link decoration, by a prevalent resource.
+
+        To achieve this, resource domains to remove website data for are now marked with an enum called
+        WebsiteDataToRemove with values All, AllButHttpOnlyCookies, AllButCookies. As resources are
+        iterated, they are marked for either of these values and the new function
+        ResourceLoadStatisticsMemoryStore::shouldRemoveAllButCookiesFor() leads to the marking with
+        WebsiteDataToRemove::AllButCookies.
+
+        Then NetworkProcess::deleteWebsiteDataForRegistrableDomains() looks at this setting and removes
+        website data accordingly.
+
+        The thinking behind this is that the lifetime cap applied in r236448 and r242288 take care of
+        script writable cookies, and this patch takes care of all other script writable storage.
+
+        The infrastructure to handle user interaction expiration is now parameterized so that multiple
+        expiries can be applied. In this particular case, seven days of browser use.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::shouldRemoveAllWebsiteDataFor const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::shouldRemoveAllButCookiesFor const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::registrableDomainsToRemoveWebsiteDataFor):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
+        (WebKit::ResourceLoadStatisticsMemoryStore::hasHadUserInteraction):
+        (WebKit::ResourceLoadStatisticsMemoryStore::hasHadUnexpiredRecentUserInteraction const):
+        (WebKit::ResourceLoadStatisticsMemoryStore::shouldRemoveAllWebsiteDataFor const):
+        (WebKit::ResourceLoadStatisticsMemoryStore::shouldRemoveAllButCookiesFor const):
+        (WebKit::ResourceLoadStatisticsMemoryStore::registrableDomainsToRemoveWebsiteDataFor):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp:
+        (WebKit::domainsToString):
+        (WebKit::ResourceLoadStatisticsStore::removeDataRecords):
+        (WebKit::ResourceLoadStatisticsStore::statisticsEpirationTime const):
+        (WebKit::ResourceLoadStatisticsStore::mergeOperatingDates):
+        (WebKit::ResourceLoadStatisticsStore::includeTodayAsOperatingDateIfNecessary):
+        (WebKit::ResourceLoadStatisticsStore::hasStatisticsExpired const):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::hasHadUserInteraction):
+        (WebKit::WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomains):
+        (WebKit::WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
+           Renamed to reflect that it actually takes a parameter for which types of data to remove.
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::initializeNetworkProcess):
+        (WebKit::NetworkProcess::setCrossSiteLoadWithLinkDecorationForTesting):
+        (WebKit::NetworkProcess::deleteWebsiteDataForRegistrableDomains):
+        (WebKit::NetworkProcess::deleteCookiesForTesting):
+        (WebKit::NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
+           Renamed to reflect that it actually takes a parameter for which types of data to remove.
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/NetworkProcessCreationParameters.cpp:
+        (WebKit::NetworkProcessCreationParameters::encode const):
+        (WebKit::NetworkProcessCreationParameters::decode):
+        * NetworkProcess/NetworkProcessCreationParameters.h:
+        * NetworkProcess/NetworkSession.cpp:
+        (WebKit::NetworkSession::deleteWebsiteDataForRegistrableDomains):
+        (WebKit::NetworkSession::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores): Deleted.
+           Renamed to reflect that it actually takes a parameter for which types of data to remove.
+        * NetworkProcess/NetworkSession.h:
+        * Shared/WebPreferences.yaml:
+        * UIProcess/API/C/WKWebsiteDataStoreRef.cpp:
+        (WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration):
+        (WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction):
+        (WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords):
+        * UIProcess/API/C/WKWebsiteDataStoreRef.h:
+        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
+        (WebKit::WebProcessPool::platformInitializeNetworkProcess):
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::setCrossSiteLoadWithLinkDecorationForTesting):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::setCrossSiteLoadWithLinkDecorationForTesting):
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+
</ins><span class="cx"> 2019-03-19  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed build fix after r243173.
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -819,7 +819,7 @@
</span><span class="cx">     if (userWasPromptedNow) {
</span><span class="cx">         auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
</span><span class="cx">         ASSERT(subFrameStatus.first == AddedRecord::No);
</span><del>-        ASSERT(hasHadUserInteraction(subFrameDomain));
</del><ins>+        ASSERT(hasHadUserInteraction(subFrameDomain, OperatingDatesWindow::Long));
</ins><span class="cx">         insertDomainRelationship(m_storageAccessUnderTopFrameDomainsStatement, subFrameStatus.second, topFrameDomain);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -839,7 +839,7 @@
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">         auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
</span><span class="cx">         ASSERT(subFrameStatus.first == AddedRecord::No);
</span><del>-        ASSERT(hasHadUserInteraction(subFrameDomain));
</del><ins>+        ASSERT(hasHadUserInteraction(subFrameDomain, OperatingDatesWindow::Long));
</ins><span class="cx">         ASSERT(hasUserGrantedStorageAccessThroughPrompt(subFrameStatus.second, topFrameDomain));
</span><span class="cx"> #endif
</span><span class="cx">         setUserInteraction(subFrameDomain, true, WallTime::now());
</span><span class="lines">@@ -1033,7 +1033,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction(const RegistrableDomain& domain)
</del><ins>+bool ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction(const RegistrableDomain& domain, OperatingDatesWindow operatingDatesWindow)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="lines">@@ -1050,7 +1050,7 @@
</span><span class="cx">     
</span><span class="cx">     WallTime mostRecentUserInteractionTime = WallTime::fromRawSeconds(m_hadUserInteractionStatement.getColumnDouble(1));
</span><span class="cx"> 
</span><del>-    if (hasStatisticsExpired(mostRecentUserInteractionTime)) {
</del><ins>+    if (hasStatisticsExpired(mostRecentUserInteractionTime, operatingDatesWindow)) {
</ins><span class="cx">         // Drop privacy sensitive data because we no longer need it.
</span><span class="cx">         // Set timestamp to 0 so that statistics merge will know
</span><span class="cx">         // it has been reset as opposed to its default -1.
</span><span class="lines">@@ -1492,8 +1492,20 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Vector<RegistrableDomain> ResourceLoadStatisticsDatabaseStore::registrableDomainsToRemoveWebsiteDataFor()
</del><ins>+bool ResourceLoadStatisticsDatabaseStore::shouldRemoveAllWebsiteDataFor(const PrevalentDomainData& resourceStatistic, bool shouldCheckForGrandfathering) const
</ins><span class="cx"> {
</span><ins>+    return !resourceStatistic.hadUserInteraction && (!shouldCheckForGrandfathering || !resourceStatistic.grandfathered);
+}
+
+bool ResourceLoadStatisticsDatabaseStore::shouldRemoveAllButCookiesFor(const PrevalentDomainData& resourceStatistic, bool shouldCheckForGrandfathering) const
+{
+    UNUSED_PARAM(resourceStatistic);
+    UNUSED_PARAM(shouldCheckForGrandfathering);
+    return false;
+}
+
+HashMap<RegistrableDomain, WebsiteDataToRemove> ResourceLoadStatisticsDatabaseStore::registrableDomainsToRemoveWebsiteDataFor()
+{
</ins><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     bool shouldCheckForGrandfathering = endOfGrandfatheringTimestamp() > WallTime::now();
</span><span class="lines">@@ -1504,13 +1516,15 @@
</span><span class="cx"> 
</span><span class="cx">     clearExpiredUserInteractions();
</span><span class="cx">     
</span><del>-    Vector<RegistrableDomain> prevalentResources;
</del><ins>+    HashMap<RegistrableDomain, WebsiteDataToRemove> domainsToRemoveWebsiteDataFor;
</ins><span class="cx"> 
</span><span class="cx">     Vector<PrevalentDomainData> prevalentDomains = this->prevalentDomains();
</span><span class="cx">     Vector<unsigned> domainIDsToClearGrandfathering;
</span><span class="cx">     for (auto& statistic : prevalentDomains) {
</span><del>-        if (!statistic.hadUserInteraction && (!shouldCheckForGrandfathering || !statistic.grandfathered))
-            prevalentResources.append(statistic.registerableDomain);
</del><ins>+        if (shouldRemoveAllWebsiteDataFor(statistic, shouldCheckForGrandfathering))
+            domainsToRemoveWebsiteDataFor.add(statistic.registerableDomain, WebsiteDataToRemove::All);
+        else if (shouldRemoveAllButCookiesFor(statistic, shouldCheckForGrandfathering))
+            domainsToRemoveWebsiteDataFor.add(statistic.registerableDomain, WebsiteDataToRemove::AllButCookies);
</ins><span class="cx"> 
</span><span class="cx">         if (shouldClearGrandfathering && statistic.grandfathered)
</span><span class="cx">             domainIDsToClearGrandfathering.append(statistic.domainID);
</span><span class="lines">@@ -1518,7 +1532,7 @@
</span><span class="cx"> 
</span><span class="cx">     clearGrandfathering(WTFMove(domainIDsToClearGrandfathering));
</span><span class="cx">     
</span><del>-    return prevalentResources;
</del><ins>+    return domainsToRemoveWebsiteDataFor;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsDatabaseStore::pruneStatisticsIfNeeded()
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -101,7 +101,7 @@
</span><span class="cx">     void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
</span><span class="cx"> 
</span><span class="cx">     void clearUserInteraction(const RegistrableDomain&) override;
</span><del>-    bool hasHadUserInteraction(const RegistrableDomain&) override;
</del><ins>+    bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) override;
</ins><span class="cx"> 
</span><span class="cx">     void setLastSeen(const RegistrableDomain&, Seconds) override;
</span><span class="cx"> 
</span><span class="lines">@@ -158,7 +158,9 @@
</span><span class="cx">     void pruneStatisticsIfNeeded() override;
</span><span class="cx">     enum class AddedRecord { No, Yes };
</span><span class="cx">     std::pair<AddedRecord, unsigned> ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain&);
</span><del>-    Vector<RegistrableDomain> registrableDomainsToRemoveWebsiteDataFor() override;
</del><ins>+    bool shouldRemoveAllWebsiteDataFor(const PrevalentDomainData&, bool shouldCheckForGrandfathering) const;
+    bool shouldRemoveAllButCookiesFor(const PrevalentDomainData&, bool shouldCheckForGrandfathering) const;
+    HashMap<RegistrableDomain, WebsiteDataToRemove> registrableDomainsToRemoveWebsiteDataFor() override;
</ins><span class="cx">     bool isDatabaseStore() const final { return true; }
</span><span class="cx"> 
</span><span class="cx">     bool createSchema();
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsMemoryStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> #include <WebCore/KeyedCoding.h>
</span><span class="cx"> #include <WebCore/NetworkStorageSession.h>
</span><span class="cx"> #include <WebCore/ResourceLoadStatistics.h>
</span><ins>+#include <WebCore/RuntimeEnabledFeatures.h>
</ins><span class="cx"> #include <wtf/CallbackAggregator.h>
</span><span class="cx"> #include <wtf/DateMath.h>
</span><span class="cx"> #include <wtf/MathExtras.h>
</span><span class="lines">@@ -444,12 +445,12 @@
</span><span class="cx">     statistics.mostRecentUserInteractionTime = { };
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ResourceLoadStatisticsMemoryStore::hasHadUserInteraction(const RegistrableDomain& domain)
</del><ins>+bool ResourceLoadStatisticsMemoryStore::hasHadUserInteraction(const RegistrableDomain& domain, OperatingDatesWindow operatingDatesWindow)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     auto mapEntry = m_resourceStatisticsMap.find(domain);
</span><del>-    return mapEntry == m_resourceStatisticsMap.end() ? false: hasHadUnexpiredRecentUserInteraction(mapEntry->value);
</del><ins>+    return mapEntry == m_resourceStatisticsMap.end() ? false: hasHadUnexpiredRecentUserInteraction(mapEntry->value, operatingDatesWindow);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsMemoryStore::setPrevalentResource(ResourceLoadStatistics& resourceStatistic, ResourceLoadPrevalence newPrevalence)
</span><span class="lines">@@ -785,11 +786,11 @@
</span><span class="cx">         processFunction(resourceStatistic);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ResourceLoadStatisticsMemoryStore::hasHadUnexpiredRecentUserInteraction(ResourceLoadStatistics& resourceStatistic) const
</del><ins>+bool ResourceLoadStatisticsMemoryStore::hasHadUnexpiredRecentUserInteraction(ResourceLoadStatistics& resourceStatistic, OperatingDatesWindow operatingDatesWindow) const
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><del>-    if (resourceStatistic.hadUserInteraction && hasStatisticsExpired(resourceStatistic)) {
</del><ins>+    if (resourceStatistic.hadUserInteraction && hasStatisticsExpired(resourceStatistic, operatingDatesWindow)) {
</ins><span class="cx">         // Drop privacy sensitive data because we no longer need it.
</span><span class="cx">         // Set timestamp to 0 so that statistics merge will know
</span><span class="cx">         // it has been reset as opposed to its default -1.
</span><span class="lines">@@ -801,8 +802,18 @@
</span><span class="cx">     return resourceStatistic.hadUserInteraction;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Vector<RegistrableDomain> ResourceLoadStatisticsMemoryStore::registrableDomainsToRemoveWebsiteDataFor()
</del><ins>+bool ResourceLoadStatisticsMemoryStore::shouldRemoveAllWebsiteDataFor(ResourceLoadStatistics& resourceStatistic, bool shouldCheckForGrandfathering) const
</ins><span class="cx"> {
</span><ins>+    return resourceStatistic.isPrevalentResource && !hasHadUnexpiredRecentUserInteraction(resourceStatistic, OperatingDatesWindow::Long) && (!shouldCheckForGrandfathering || !resourceStatistic.grandfathered);
+}
+
+bool ResourceLoadStatisticsMemoryStore::shouldRemoveAllButCookiesFor(ResourceLoadStatistics& resourceStatistic, bool shouldCheckForGrandfathering) const
+{
+    return RuntimeEnabledFeatures::sharedFeatures().isITPFirstPartyWebsiteDataRemovalEnabled() && resourceStatistic.gotLinkDecorationFromPrevalentResource && !hasHadUnexpiredRecentUserInteraction(resourceStatistic, OperatingDatesWindow::Short) && (!shouldCheckForGrandfathering || !resourceStatistic.grandfathered);
+}
+
+HashMap<RegistrableDomain, WebsiteDataToRemove> ResourceLoadStatisticsMemoryStore::registrableDomainsToRemoveWebsiteDataFor()
+{
</ins><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     bool shouldCheckForGrandfathering = endOfGrandfatheringTimestamp() > WallTime::now();
</span><span class="lines">@@ -811,16 +822,20 @@
</span><span class="cx">     if (shouldClearGrandfathering)
</span><span class="cx">         clearEndOfGrandfatheringTimeStamp();
</span><span class="cx"> 
</span><del>-    Vector<RegistrableDomain> prevalentResources;
</del><ins>+    HashMap<RegistrableDomain, WebsiteDataToRemove> domainsToRemoveWebsiteDataFor;
</ins><span class="cx">     for (auto& statistic : m_resourceStatisticsMap.values()) {
</span><del>-        if (statistic.isPrevalentResource && !hasHadUnexpiredRecentUserInteraction(statistic) && (!shouldCheckForGrandfathering || !statistic.grandfathered))
-            prevalentResources.append(statistic.registrableDomain);
</del><ins>+        if (shouldRemoveAllWebsiteDataFor(statistic, shouldCheckForGrandfathering))
+            domainsToRemoveWebsiteDataFor.add(statistic.registrableDomain, WebsiteDataToRemove::All);
+        else if (shouldRemoveAllButCookiesFor(statistic, shouldCheckForGrandfathering)) {
+            domainsToRemoveWebsiteDataFor.add(statistic.registrableDomain, WebsiteDataToRemove::AllButCookies);
+            statistic.gotLinkDecorationFromPrevalentResource = false;
+        }
</ins><span class="cx"> 
</span><span class="cx">         if (shouldClearGrandfathering && statistic.grandfathered)
</span><span class="cx">             statistic.grandfathered = false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return prevalentResources;
</del><ins>+    return domainsToRemoveWebsiteDataFor;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsMemoryStore::pruneStatisticsIfNeeded()
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsMemoryStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h        2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h   2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx">     void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
</span><span class="cx"> 
</span><span class="cx">     void clearUserInteraction(const RegistrableDomain&) override;
</span><del>-    bool hasHadUserInteraction(const RegistrableDomain&) override;
</del><ins>+    bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) override;
</ins><span class="cx"> 
</span><span class="cx">     void setLastSeen(const RegistrableDomain&, Seconds) override;
</span><span class="cx"> 
</span><span class="lines">@@ -114,7 +114,9 @@
</span><span class="cx">     static bool shouldBlockAndKeepCookies(const ResourceLoadStatistics&);
</span><span class="cx">     static bool shouldBlockAndPurgeCookies(const ResourceLoadStatistics&);
</span><span class="cx">     static bool hasUserGrantedStorageAccessThroughPrompt(const ResourceLoadStatistics&, const RegistrableDomain&);
</span><del>-    bool hasHadUnexpiredRecentUserInteraction(ResourceLoadStatistics&) const;
</del><ins>+    bool hasHadUnexpiredRecentUserInteraction(ResourceLoadStatistics&, OperatingDatesWindow) const;
+    bool shouldRemoveAllWebsiteDataFor(ResourceLoadStatistics&, bool shouldCheckForGrandfathering) const;
+    bool shouldRemoveAllButCookiesFor(ResourceLoadStatistics&, bool shouldCheckForGrandfathering) const;
</ins><span class="cx">     bool wasAccessedAsFirstPartyDueToUserInteraction(const ResourceLoadStatistics& current, const ResourceLoadStatistics& updated) const;
</span><span class="cx">     void incrementRecordsDeletedCountForDomains(HashSet<RegistrableDomain>&&) override;
</span><span class="cx">     void setPrevalentResource(ResourceLoadStatistics&, ResourceLoadPrevalence);
</span><span class="lines">@@ -126,10 +128,9 @@
</span><span class="cx">     void removeDataRecords(CompletionHandler<void()>&&);
</span><span class="cx">     void pruneStatisticsIfNeeded() override;
</span><span class="cx">     ResourceLoadStatistics& ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain&);
</span><del>-    Vector<RegistrableDomain> registrableDomainsToRemoveWebsiteDataFor() override;
</del><ins>+    HashMap<RegistrableDomain, WebsiteDataToRemove> registrableDomainsToRemoveWebsiteDataFor() override;
</ins><span class="cx">     bool isMemoryStore() const final { return true; }
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     WeakPtr<ResourceLoadStatisticsPersistentStorage> m_persistentStorage;
</span><span class="cx">     HashMap<RegistrableDomain, ResourceLoadStatistics> m_resourceStatisticsMap;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -50,7 +50,8 @@
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><span class="cx"> constexpr Seconds minimumStatisticsProcessingInterval { 5_s };
</span><del>-constexpr unsigned operatingDatesWindow { 30 };
</del><ins>+constexpr unsigned operatingDatesWindowLong { 30 };
+constexpr unsigned operatingDatesWindowShort { 7 };
</ins><span class="cx"> 
</span><span class="cx"> #if !RELEASE_LOG_DISABLED
</span><span class="cx"> static String domainsToString(const Vector<RegistrableDomain>& domains)
</span><span class="lines">@@ -63,6 +64,28 @@
</span><span class="cx">     }
</span><span class="cx">     return builder.toString();
</span><span class="cx"> }
</span><ins>+
+static String domainsToString(const HashMap<RegistrableDomain, WebsiteDataToRemove>& domainsToRemoveWebsiteDataFor)
+{
+    StringBuilder builder;
+    for (auto& domain : domainsToRemoveWebsiteDataFor.keys()) {
+        if (!builder.isEmpty())
+            builder.appendLiteral(", ");
+        builder.append(domain.string());
+        switch (domainsToRemoveWebsiteDataFor.get(domain)) {
+        case WebsiteDataToRemove::All:
+            builder.appendLiteral("(all data)");
+            break;
+        case WebsiteDataToRemove::AllButHttpOnlyCookies:
+            builder.appendLiteral("(all but HttpOnly cookies)");
+            break;
+        case WebsiteDataToRemove::AllButCookies:
+            builder.appendLiteral("(all but cookies)");
+            break;
+        }
+    }
+    return builder.toString();
+}
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> OperatingDate OperatingDate::fromWallTime(WallTime time)
</span><span class="lines">@@ -157,12 +180,12 @@
</span><span class="cx">     m_parameters.shouldSubmitTelemetry = value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ResourceLoadStatisticsStore::removeDataRecords(CompletionHandler<void()>&& callback)
</del><ins>+void ResourceLoadStatisticsStore::removeDataRecords(CompletionHandler<void()>&& completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     if (!shouldRemoveDataRecords()) {
</span><del>-        callback();
</del><ins>+        completionHandler();
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -172,33 +195,33 @@
</span><span class="cx">         m_activePluginTokens.add(plugin->pluginProcessToken());
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    auto prevalentResourceDomains = registrableDomainsToRemoveWebsiteDataFor();
-    if (prevalentResourceDomains.isEmpty()) {
-        callback();
</del><ins>+    auto domainsToRemoveWebsiteDataFor = registrableDomainsToRemoveWebsiteDataFor();
+    if (domainsToRemoveWebsiteDataFor.isEmpty()) {
+        completionHandler();
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if !RELEASE_LOG_DISABLED
</span><del>-    RELEASE_LOG_INFO_IF(m_debugLoggingEnabled, ResourceLoadStatisticsDebug, "About to remove data records for %{public}s.", domainsToString(prevalentResourceDomains).utf8().data());
</del><ins>+    RELEASE_LOG_INFO_IF(m_debugLoggingEnabled, ResourceLoadStatisticsDebug, "About to remove data records for %{public}s.", domainsToString(domainsToRemoveWebsiteDataFor).utf8().data());
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     setDataRecordsBeingRemoved(true);
</span><span class="cx"> 
</span><del>-    RunLoop::main().dispatch([prevalentResourceDomains = crossThreadCopy(prevalentResourceDomains), callback = WTFMove(callback), weakThis = makeWeakPtr(*this), shouldNotifyPagesWhenDataRecordsWereScanned = m_parameters.shouldNotifyPagesWhenDataRecordsWereScanned, workQueue = m_workQueue.copyRef()] () mutable {
</del><ins>+    RunLoop::main().dispatch([domainsToRemoveWebsiteDataFor = crossThreadCopy(domainsToRemoveWebsiteDataFor), completionHandler = WTFMove(completionHandler), weakThis = makeWeakPtr(*this), shouldNotifyPagesWhenDataRecordsWereScanned = m_parameters.shouldNotifyPagesWhenDataRecordsWereScanned, workQueue = m_workQueue.copyRef()] () mutable {
</ins><span class="cx">         if (!weakThis) {
</span><del>-            callback();
</del><ins>+            completionHandler();
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        weakThis->m_store.deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(WebResourceLoadStatisticsStore::monitoredDataTypes(), WTFMove(prevalentResourceDomains), shouldNotifyPagesWhenDataRecordsWereScanned, IncludeHttpOnlyCookies::Yes, [callback = WTFMove(callback), weakThis = WTFMove(weakThis), workQueue = workQueue.copyRef()](const HashSet<RegistrableDomain>& domainsWithDeletedWebsiteData) mutable {
-            workQueue->dispatch([domainsWithDeletedWebsiteData = crossThreadCopy(domainsWithDeletedWebsiteData), callback = WTFMove(callback), weakThis = WTFMove(weakThis)] () mutable {
</del><ins>+        weakThis->m_store.deleteWebsiteDataForRegistrableDomains(WebResourceLoadStatisticsStore::monitoredDataTypes(), WTFMove(domainsToRemoveWebsiteDataFor), shouldNotifyPagesWhenDataRecordsWereScanned, [completionHandler = WTFMove(completionHandler), weakThis = WTFMove(weakThis), workQueue = workQueue.copyRef()](const HashSet<RegistrableDomain>& domainsWithDeletedWebsiteData) mutable {
+            workQueue->dispatch([domainsWithDeletedWebsiteData = crossThreadCopy(domainsWithDeletedWebsiteData), completionHandler = WTFMove(completionHandler), weakThis = WTFMove(weakThis)] () mutable {
</ins><span class="cx">                 if (!weakThis) {
</span><del>-                    callback();
</del><ins>+                    completionHandler();
</ins><span class="cx">                     return;
</span><span class="cx">                 }
</span><span class="cx">                 weakThis->incrementRecordsDeletedCountForDomains(WTFMove(domainsWithDeletedWebsiteData));
</span><span class="cx">                 weakThis->setDataRecordsBeingRemoved(false);
</span><del>-                callback();
</del><ins>+                completionHandler();
</ins><span class="cx"> #if !RELEASE_LOG_DISABLED
</span><span class="cx">                 RELEASE_LOG_INFO_IF(weakThis->m_debugLoggingEnabled, ResourceLoadStatisticsDebug, "Done removing data records.");
</span><span class="cx"> #endif
</span><span class="lines">@@ -430,7 +453,7 @@
</span><span class="cx">     if (m_parameters.timeToLiveUserInteraction)
</span><span class="cx">         return WallTime::now().secondsSinceEpoch() - m_parameters.timeToLiveUserInteraction.value();
</span><span class="cx">     
</span><del>-    if (m_operatingDates.size() >= operatingDatesWindow)
</del><ins>+    if (m_operatingDates.size() >= operatingDatesWindowLong)
</ins><span class="cx">         return m_operatingDates.first().secondsSinceEpoch();
</span><span class="cx">     
</span><span class="cx">     return WTF::nullopt;
</span><span class="lines">@@ -448,8 +471,8 @@
</span><span class="cx">     // Remove duplicate dates.
</span><span class="cx">     removeRepeatedElements(mergedDates);
</span><span class="cx">     
</span><del>-    // Drop old dates until the Vector size reaches operatingDatesWindow.
-    while (mergedDates.size() > operatingDatesWindow)
</del><ins>+    // Drop old dates until the Vector size reaches operatingDatesWindowLong.
+    while (mergedDates.size() > operatingDatesWindowLong)
</ins><span class="cx">         mergedDates.remove(0);
</span><span class="cx">     
</span><span class="cx">     return mergedDates;
</span><span class="lines">@@ -468,17 +491,18 @@
</span><span class="cx">     if (!m_operatingDates.isEmpty() && today <= m_operatingDates.last())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    while (m_operatingDates.size() >= operatingDatesWindow)
</del><ins>+    while (m_operatingDates.size() >= operatingDatesWindowLong)
</ins><span class="cx">         m_operatingDates.remove(0);
</span><span class="cx"> 
</span><span class="cx">     m_operatingDates.append(today);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ResourceLoadStatisticsStore::hasStatisticsExpired(WallTime mostRecentUserInteractionTime) const
</del><ins>+bool ResourceLoadStatisticsStore::hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow operatingDatesWindow) const
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><del>-    
-    if (m_operatingDates.size() >= operatingDatesWindow) {
</del><ins>+
+    unsigned operatingDatesWindowInDays = (operatingDatesWindow == OperatingDatesWindow::Long ? operatingDatesWindowLong : operatingDatesWindowShort);
+    if (m_operatingDates.size() >= operatingDatesWindowInDays) {
</ins><span class="cx">         if (OperatingDate::fromWallTime(mostRecentUserInteractionTime) < m_operatingDates.first())
</span><span class="cx">             return true;
</span><span class="cx">     }
</span><span class="lines">@@ -492,9 +516,9 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ResourceLoadStatisticsStore::hasStatisticsExpired(const ResourceLoadStatistics& resourceStatistic) const
</del><ins>+bool ResourceLoadStatisticsStore::hasStatisticsExpired(const ResourceLoadStatistics& resourceStatistic, OperatingDatesWindow operatingDatesWindow) const
</ins><span class="cx"> {
</span><del>-    return hasStatisticsExpired(resourceStatistic.mostRecentUserInteractionTime);
</del><ins>+    return hasStatisticsExpired(resourceStatistic.mostRecentUserInteractionTime, operatingDatesWindow);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsStore::setMaxStatisticsEntries(size_t maximumEntryCount)
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -71,6 +71,8 @@
</span><span class="cx">     int m_monthDay { 0 }; // [1, 31].
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+enum class OperatingDatesWindow : bool { Long, Short };
+
</ins><span class="cx"> // This is always constructed / used / destroyed on the WebResourceLoadStatisticsStore's statistics queue.
</span><span class="cx"> class ResourceLoadStatisticsStore : public CanMakeWeakPtr<ResourceLoadStatisticsStore> {
</span><span class="cx"> public:
</span><span class="lines">@@ -168,7 +170,7 @@
</span><span class="cx">     virtual void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) = 0;
</span><span class="cx"> 
</span><span class="cx">     virtual void clearUserInteraction(const RegistrableDomain&) = 0;
</span><del>-    virtual bool hasHadUserInteraction(const RegistrableDomain&) = 0;
</del><ins>+    virtual bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) = 0;
</ins><span class="cx"> 
</span><span class="cx">     virtual void setLastSeen(const RegistrableDomain& primaryDomain, Seconds) = 0;
</span><span class="cx"> 
</span><span class="lines">@@ -188,12 +190,12 @@
</span><span class="cx"> 
</span><span class="cx">     ResourceLoadStatisticsStore(WebResourceLoadStatisticsStore&, WorkQueue&, ShouldIncludeLocalhost);
</span><span class="cx"> 
</span><del>-    bool hasStatisticsExpired(const ResourceLoadStatistics&) const;
-    bool hasStatisticsExpired(WallTime mostRecentUserInteractionTime) const;
</del><ins>+    bool hasStatisticsExpired(const ResourceLoadStatistics&, OperatingDatesWindow) const;
+    bool hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow) const;
</ins><span class="cx">     void scheduleStatisticsProcessingRequestIfNecessary();
</span><span class="cx">     void mergeOperatingDates(Vector<OperatingDate>&&);
</span><span class="cx">     virtual Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() = 0;
</span><del>-    virtual Vector<RegistrableDomain> registrableDomainsToRemoveWebsiteDataFor() = 0;
</del><ins>+    virtual HashMap<RegistrableDomain, WebsiteDataToRemove> registrableDomainsToRemoveWebsiteDataFor() = 0;
</ins><span class="cx">     virtual void pruneStatisticsIfNeeded() = 0;
</span><span class="cx"> 
</span><span class="cx">     WebResourceLoadStatisticsStore& store() { return m_store; }
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp 2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp    2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -580,7 +580,7 @@
</span><span class="cx"> void WebResourceLoadStatisticsStore::hasHadUserInteraction(const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     postTask([this, domain, completionHandler = WTFMove(completionHandler)]() mutable {
</span><del>-        bool hadUserInteraction = m_statisticsStore ? m_statisticsStore->hasHadUserInteraction(domain) : false;
</del><ins>+        bool hadUserInteraction = m_statisticsStore ? m_statisticsStore->hasHadUserInteraction(domain, OperatingDatesWindow::Long) : false;
</ins><span class="cx">         postTaskReply([hadUserInteraction, completionHandler = WTFMove(completionHandler)]() mutable {
</span><span class="cx">             completionHandler(hadUserInteraction);
</span><span class="cx">         });
</span><span class="lines">@@ -1012,12 +1012,12 @@
</span><span class="cx">         m_networkSession->notifyResourceLoadStatisticsProcessed();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType> dataTypes, Vector<RegistrableDomain>&& domains, bool shouldNotifyPage, IncludeHttpOnlyCookies includeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</del><ins>+void WebResourceLoadStatisticsStore::deleteWebsiteDataForRegistrableDomains(OptionSet<WebsiteDataType> dataTypes, HashMap<RegistrableDomain, WebsiteDataToRemove>&& domainsToRemoveWebsiteDataFor, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="cx">     
</span><span class="cx">     if (m_networkSession) {
</span><del>-        m_networkSession->deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(dataTypes, WTFMove(domains), shouldNotifyPage, includeHttpOnlyCookies, WTFMove(completionHandler));
</del><ins>+        m_networkSession->deleteWebsiteDataForRegistrableDomains(dataTypes, WTFMove(domainsToRemoveWebsiteDataFor), shouldNotifyPage, WTFMove(completionHandler));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h   2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h      2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -60,6 +60,11 @@
</span><span class="cx"> enum class ShouldGrandfatherStatistics : bool;
</span><span class="cx"> enum class ShouldIncludeLocalhost : bool { No, Yes };
</span><span class="cx"> enum class EnableResourceLoadStatisticsDebugMode : bool { No, Yes };
</span><ins>+enum class WebsiteDataToRemove : uint8_t {
+    All,
+    AllButHttpOnlyCookies,
+    AllButCookies
+};
</ins><span class="cx"> 
</span><span class="cx"> class WebResourceLoadStatisticsStore final : public ThreadSafeRefCounted<WebResourceLoadStatisticsStore, WTF::DestructionThread::Main>, public IPC::MessageReceiver {
</span><span class="cx"> public:
</span><span class="lines">@@ -107,7 +112,7 @@
</span><span class="cx">     void logSubresourceRedirect(const RedirectedFromDomain&, const RedirectedToDomain&, CompletionHandler<void()>&&);
</span><span class="cx">     void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&, CompletionHandler<void()>&&);
</span><span class="cx">     void clearUserInteraction(const TopFrameDomain&, CompletionHandler<void()>&&);
</span><del>-    void deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType>, Vector<RegistrableDomain>&&, bool shouldNotifyPage, WebCore::IncludeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&&);
</del><ins>+    void deleteWebsiteDataForRegistrableDomains(OptionSet<WebsiteDataType>, HashMap<RegistrableDomain, WebsiteDataToRemove>&&, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&&);
</ins><span class="cx">     void registrableDomainsWithWebsiteData(OptionSet<WebsiteDataType>, bool shouldNotifyPage, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&&);
</span><span class="cx">     bool grantStorageAccess(const SubFrameDomain&, const TopFrameDomain&, Optional<FrameID>, PageID);
</span><span class="cx">     void hasHadUserInteraction(const RegistrableDomain&, CompletionHandler<void(bool)>&&);
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -313,6 +313,7 @@
</span><span class="cx">         switchToNewTestingSession();
</span><span class="cx"> 
</span><span class="cx">     WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPDatabaseEnabled(parameters.shouldEnableITPDatabase);
</span><ins>+    WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPFirstPartyWebsiteDataRemovalEnabled(parameters.isITPFirstPartyWebsiteDataRemovalEnabled);
</ins><span class="cx"> 
</span><span class="cx">     SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectoryExtensionHandle);
</span><span class="cx"> 
</span><span class="lines">@@ -1220,6 +1221,19 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void NetworkProcess::setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, CompletionHandler<void()>&& completionHandler)
+{
+    if (auto* networkSession = this->networkSession(sessionID)) {
+        if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
+            resourceLoadStatistics->logCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, WTFMove(completionHandler));
+        else
+            completionHandler();
+    } else {
+        ASSERT_NOT_REACHED();
+        completionHandler();
+    }
+}
+
</ins><span class="cx"> void NetworkProcess::resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     if (auto* networkStorageSession = storageSession(sessionID))
</span><span class="lines">@@ -1510,7 +1524,7 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, Vector<RegistrableDomain>&& domains, bool shouldNotifyPage, IncludeHttpOnlyCookies includeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</del><ins>+void NetworkProcess::deleteWebsiteDataForRegistrableDomains(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, HashMap<RegistrableDomain, WebsiteDataToRemove>&& domains, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses;
</span><span class="cx"> 
</span><span class="lines">@@ -1552,13 +1566,37 @@
</span><span class="cx"> 
</span><span class="cx">     auto& websiteDataStore = callbackAggregator->m_websiteData;
</span><span class="cx"> 
</span><ins>+    Vector<RegistrableDomain> domainsToDeleteCookiesFor;
+    Vector<RegistrableDomain> domainsToDeleteAllButHttpOnlyCookiesFor;
+    Vector<RegistrableDomain> domainsToDeleteAllButCookiesFor;
</ins><span class="cx">     Vector<String> hostnamesWithCookiesToDelete;
</span><span class="cx">     if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
</span><ins>+        for (auto& domain : domains.keys()) {
+            domainsToDeleteAllButCookiesFor.append(domain);
+            switch (domains.get(domain)) {
+            case WebsiteDataToRemove::All:
+                domainsToDeleteCookiesFor.append(domain);
+                break;
+            case WebsiteDataToRemove::AllButHttpOnlyCookies:
+                domainsToDeleteAllButHttpOnlyCookiesFor.append(domain);
+                break;
+            case WebsiteDataToRemove::AllButCookies:
+                // Already added.
+                break;
+            }
+        }
</ins><span class="cx">         if (auto* networkStorageSession = storageSession(sessionID)) {
</span><span class="cx">             networkStorageSession->getHostnamesWithCookies(websiteDataStore.hostNamesWithCookies);
</span><del>-            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domains, websiteDataStore.hostNamesWithCookies);
-            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, includeHttpOnlyCookies);
</del><ins>+
+            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteCookiesFor, websiteDataStore.hostNamesWithCookies);
+            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::Yes);
+
+            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteAllButHttpOnlyCookiesFor, websiteDataStore.hostNamesWithCookies);
+            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::No);
</ins><span class="cx">         }
</span><ins>+    } else {
+        for (auto& domain : domains.keys())
+            domainsToDeleteAllButCookiesFor.append(domain);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Vector<String> hostnamesWithHSTSToDelete;
</span><span class="lines">@@ -1566,7 +1604,7 @@
</span><span class="cx">     if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
</span><span class="cx">         if (auto* networkStorageSession = storageSession(sessionID)) {
</span><span class="cx">             getHostNamesWithHSTSCache(*networkStorageSession, websiteDataStore.hostNamesWithHSTSCache);
</span><del>-            hostnamesWithHSTSToDelete = filterForRegistrableDomains(domains, websiteDataStore.hostNamesWithHSTSCache);
</del><ins>+            hostnamesWithHSTSToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, websiteDataStore.hostNamesWithHSTSCache);
</ins><span class="cx">             deleteHSTSCacheForHostNames(*networkStorageSession, hostnamesWithHSTSToDelete);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1581,9 +1619,9 @@
</span><span class="cx">     */
</span><span class="cx">     
</span><span class="cx">     if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
</span><del>-        CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domains, sessionID, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
</del><ins>+        CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domainsToDeleteAllButCookiesFor, sessionID, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
</ins><span class="cx">             
</span><del>-            auto entriesToDelete = filterForRegistrableDomains(domains, entries);
</del><ins>+            auto entriesToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, entries);
</ins><span class="cx"> 
</span><span class="cx">             callbackAggregator->m_websiteData.entries.appendVector(entriesToDelete);
</span><span class="cx">             
</span><span class="lines">@@ -1596,11 +1634,11 @@
</span><span class="cx">     auto path = m_idbDatabasePaths.get(sessionID);
</span><span class="cx">     if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
</span><span class="cx">         // FIXME: Pick the right database store based on the session ID.
</span><del>-        postStorageTask(CrossThreadTask([this, sessionID, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path), domains]() mutable {
-            RunLoop::main().dispatch([this, sessionID, domains = crossThreadCopy(domains), callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
</del><ins>+        postStorageTask(CrossThreadTask([this, sessionID, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path), domainsToDeleteAllButCookiesFor]() mutable {
+            RunLoop::main().dispatch([this, sessionID, domainsToDeleteAllButCookiesFor = crossThreadCopy(domainsToDeleteAllButCookiesFor), callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
</ins><span class="cx">                 Vector<SecurityOriginData> entriesToDelete;
</span><span class="cx">                 for (const auto& securityOrigin : securityOrigins) {
</span><del>-                    if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
</del><ins>+                    if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
</ins><span class="cx">                         continue;
</span><span class="cx"> 
</span><span class="cx">                     entriesToDelete.append(securityOrigin);
</span><span class="lines">@@ -1616,9 +1654,9 @@
</span><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="cx">     path = m_swDatabasePaths.get(sessionID);
</span><span class="cx">     if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
</span><del>-        swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domains, callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
</del><ins>+        swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
</ins><span class="cx">             for (auto& securityOrigin : securityOrigins) {
</span><del>-                if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
</del><ins>+                if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
</ins><span class="cx">                     continue;
</span><span class="cx">                 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::ServiceWorkerRegistrations, 0 });
</span><span class="cx">                 swServerForSession(sessionID).clear(securityOrigin, [callbackAggregator = callbackAggregator.copyRef()] { });
</span><span class="lines">@@ -1628,11 +1666,11 @@
</span><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx">     if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) {
</span><del>-        fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [this, domains, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
</del><ins>+        fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [this, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
</ins><span class="cx"> 
</span><span class="cx">             Vector<SecurityOriginData> entriesToDelete;
</span><span class="cx">             for (auto& entry : entries) {
</span><del>-                if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)))
</del><ins>+                if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)))
</ins><span class="cx">                     continue;
</span><span class="cx">                 entriesToDelete.append(entry.origin);
</span><span class="cx">                 callbackAggregator->m_websiteData.entries.append(entry);
</span><span class="lines">@@ -1645,8 +1683,9 @@
</span><span class="cx"> void NetworkProcess::deleteCookiesForTesting(PAL::SessionID sessionID, RegistrableDomain domain, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     OptionSet<WebsiteDataType> cookieType = WebsiteDataType::Cookies;
</span><del>-
-    deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(sessionID, cookieType, { domain }, true, includeHttpOnlyCookies ? IncludeHttpOnlyCookies::Yes : IncludeHttpOnlyCookies::No, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable {
</del><ins>+    HashMap<RegistrableDomain, WebsiteDataToRemove> toDeleteFor;
+    toDeleteFor.add(domain, includeHttpOnlyCookies ? WebsiteDataToRemove::All : WebsiteDataToRemove::AllButHttpOnlyCookies);
+    deleteWebsiteDataForRegistrableDomains(sessionID, cookieType, WTFMove(toDeleteFor), true, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable {
</ins><span class="cx">         UNUSED_PARAM(domainsDeletedFor);
</span><span class="cx">         completionHandler();
</span><span class="cx">     });
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include "NetworkContentRuleListManager.h"
</span><span class="cx"> #include "NetworkHTTPSUpgradeChecker.h"
</span><span class="cx"> #include "SandboxExtension.h"
</span><ins>+#include "WebResourceLoadStatisticsStore.h"
</ins><span class="cx"> #include <WebCore/AdClickAttribution.h>
</span><span class="cx"> #include <WebCore/ClientOrigin.h>
</span><span class="cx"> #include <WebCore/DiagnosticLoggingClient.h>
</span><span class="lines">@@ -205,7 +206,7 @@
</span><span class="cx"> #if ENABLE(RESOURCE_LOAD_STATISTICS)
</span><span class="cx">     void clearPrevalentResource(PAL::SessionID, const RegistrableDomain&, CompletionHandler<void()>&&);
</span><span class="cx">     void clearUserInteraction(PAL::SessionID, const RegistrableDomain&, CompletionHandler<void()>&&);
</span><del>-    void deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(PAL::SessionID, OptionSet<WebsiteDataType>, Vector<RegistrableDomain>&&, bool shouldNotifyPage, WebCore::IncludeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&&);
</del><ins>+    void deleteWebsiteDataForRegistrableDomains(PAL::SessionID, OptionSet<WebsiteDataType>, HashMap<RegistrableDomain, WebsiteDataToRemove>&&, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&&);
</ins><span class="cx">     void deleteCookiesForTesting(PAL::SessionID, RegistrableDomain, bool includeHttpOnlyCookies, CompletionHandler<void()>&&);
</span><span class="cx">     void dumpResourceLoadStatistics(PAL::SessionID, CompletionHandler<void(String)>&&);
</span><span class="cx">     void updatePrevalentDomainsToBlockCookiesFor(PAL::SessionID, const Vector<RegistrableDomain>& domainsToBlock, CompletionHandler<void()>&&);
</span><span class="lines">@@ -258,6 +259,7 @@
</span><span class="cx">     void setTopFrameUniqueRedirectFrom(PAL::SessionID, const TopFrameDomain&, const RedirectedFromDomain&, CompletionHandler<void()>&&);
</span><span class="cx">     void registrableDomainsWithWebsiteData(PAL::SessionID, OptionSet<WebsiteDataType>, bool shouldNotifyPage, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&&);
</span><span class="cx">     void committedCrossSiteLoadWithLinkDecoration(PAL::SessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, uint64_t pageID, CompletionHandler<void()>&&);
</span><ins>+    void setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, CompletionHandler<void()>&&);
</ins><span class="cx">     void resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID, CompletionHandler<void()>&&);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcessmessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -136,6 +136,7 @@
</span><span class="cx">     SetTopFrameUniqueRedirectFrom(PAL::SessionID sessionID, WebCore::RegistrableDomain topFrameDomain, WebCore::RegistrableDomain redirectedFromDomain) -> () Async
</span><span class="cx">     ResetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID) -> () Async
</span><span class="cx">     CommittedCrossSiteLoadWithLinkDecoration(PAL::SessionID sessionID, WebCore::RegistrableDomain fromDomain, WebCore::RegistrableDomain toDomain, uint64_t pageID) -> () Async
</span><ins>+    SetCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID sessionID, WebCore::RegistrableDomain fromDomain, WebCore::RegistrableDomain toDomain) -> () Async
</ins><span class="cx">     ResetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID sessionID) -> () Async
</span><span class="cx">     DeleteCookiesForTesting(PAL::SessionID sessionID, WebCore::RegistrableDomain domain, bool includeHttpOnlyCookies) -> () Async
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcessCreationParameterscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp  2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.cpp     2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     encoder << shouldEnableITPDatabase;
</span><span class="cx">     encoder << downloadMonitorSpeedMultiplier;
</span><ins>+    encoder << isITPFirstPartyWebsiteDataRemovalEnabled;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool NetworkProcessCreationParameters::decode(IPC::Decoder& decoder, NetworkProcessCreationParameters& result)
</span><span class="lines">@@ -224,7 +225,10 @@
</span><span class="cx">     if (!downloadMonitorSpeedMultiplier)
</span><span class="cx">         return false;
</span><span class="cx">     result.downloadMonitorSpeedMultiplier = *downloadMonitorSpeedMultiplier;
</span><del>-    
</del><ins>+
+    if (!decoder.decode(result.isITPFirstPartyWebsiteDataRemovalEnabled))
+        return false;
+
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcessCreationParametersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -111,6 +111,7 @@
</span><span class="cx">     bool shouldDisableServiceWorkerProcessTerminationDelay { false };
</span><span class="cx"> #endif
</span><span class="cx">     bool shouldEnableITPDatabase { false };
</span><ins>+    bool isITPFirstPartyWebsiteDataRemovalEnabled { true };
</ins><span class="cx">     uint32_t downloadMonitorSpeedMultiplier { 1 };
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -125,9 +125,9 @@
</span><span class="cx">     m_networkProcess->parentProcessConnection()->send(Messages::NetworkProcessProxy::NotifyResourceLoadStatisticsTelemetryFinished(totalPrevalentResources, totalPrevalentResourcesWithUserInteraction, top3SubframeUnderTopFrameOrigins), 0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkSession::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType> dataTypes, Vector<RegistrableDomain>&& domains, bool shouldNotifyPage, IncludeHttpOnlyCookies includeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</del><ins>+void NetworkSession::deleteWebsiteDataForRegistrableDomains(OptionSet<WebsiteDataType> dataTypes, HashMap<RegistrableDomain, WebsiteDataToRemove>&& domains, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
</ins><span class="cx"> {
</span><del>-    m_networkProcess->deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(m_sessionID, dataTypes, WTFMove(domains), shouldNotifyPage, includeHttpOnlyCookies, WTFMove(completionHandler));
</del><ins>+    m_networkProcess->deleteWebsiteDataForRegistrableDomains(m_sessionID, dataTypes, WTFMove(domains), shouldNotifyPage, WTFMove(completionHandler));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkSession::registrableDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, bool shouldNotifyPage, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&& completionHandler)
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkSessionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkSession.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     WebResourceLoadStatisticsStore* resourceLoadStatistics() const { return m_resourceLoadStatistics.get(); }
</span><span class="cx">     void setResourceLoadStatisticsEnabled(bool);
</span><span class="cx">     void notifyResourceLoadStatisticsProcessed();
</span><del>-    void deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType>, Vector<WebCore::RegistrableDomain>&&, bool shouldNotifyPage, WebCore::IncludeHttpOnlyCookies, CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&&);
</del><ins>+    void deleteWebsiteDataForRegistrableDomains(OptionSet<WebsiteDataType>, HashMap<WebCore::RegistrableDomain, WebsiteDataToRemove>&&, bool shouldNotifyPage, CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&&);
</ins><span class="cx">     void registrableDomainsWithWebsiteData(OptionSet<WebsiteDataType>, bool shouldNotifyPage, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&&);
</span><span class="cx">     void logDiagnosticMessageWithValue(const String& message, const String& description, unsigned value, unsigned significantFigures, WebCore::ShouldSample);
</span><span class="cx">     void notifyPageStatisticsTelemetryFinished(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins);
</span></span></pre></div>
<a id="trunkSourceWebKitSharedWebPreferencesyaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/WebPreferences.yaml (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Shared/WebPreferences.yaml   2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/Shared/WebPreferences.yaml      2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1381,6 +1381,14 @@
</span><span class="cx">   humanReadableDescription: "Media Capabilities Extensions"
</span><span class="cx">   category: experimental
</span><span class="cx"> 
</span><ins>+IsITPFirstPartyWebsiteDataRemovalEnabled:
+    type: bool
+    defaultValue: DEFAULT_EXPERIMENTAL_FEATURES_ENABLED
+    humanReadableName: "ITP First Party Website Data Removal"
+    humanReadableDescription: "Enable Intelligent Tracking Prevention First Party Website Data Removal"
+    webcoreBinding: RuntimeEnabledFeatures
+    category: experimental
+
</ins><span class="cx"> # For internal features:
</span><span class="cx"> # The type should be boolean.
</span><span class="cx"> # You must provide a humanReadableName and humanReadableDescription for all debug features. They
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKWebsiteDataStoreRefcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -297,20 +297,39 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(WKWebsiteDataStoreRef dataStoreRef, double seconds)
</del><ins>+void WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration(WKWebsiteDataStoreRef dataStoreRef, WKStringRef fromHost, WKStringRef toHost, void* context, WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecorationFunction callback)
</ins><span class="cx"> {
</span><span class="cx"> #if ENABLE(RESOURCE_LOAD_STATISTICS)
</span><del>-    WebKit::toImpl(dataStoreRef)->websiteDataStore().setTimeToLiveUserInteraction(Seconds { seconds }, [] { });
</del><ins>+    WebKit::toImpl(dataStoreRef)->websiteDataStore().setCrossSiteLoadWithLinkDecorationForTesting(URL(URL(), WebKit::toImpl(fromHost)->string()), URL(URL(), WebKit::toImpl(toHost)->string()), [context, callback] {
+        callback(context);
+    });
+#else
+    callback(context);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(WKWebsiteDataStoreRef dataStoreRef)
</del><ins>+void WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(WKWebsiteDataStoreRef dataStoreRef, double seconds, void* context, WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteractionFunction callback)
</ins><span class="cx"> {
</span><span class="cx"> #if ENABLE(RESOURCE_LOAD_STATISTICS)
</span><del>-    WebKit::toImpl(dataStoreRef)->websiteDataStore().scheduleStatisticsAndDataRecordsProcessing([] { });
</del><ins>+    WebKit::toImpl(dataStoreRef)->websiteDataStore().setTimeToLiveUserInteraction(Seconds { seconds }, [context, callback] {
+        callback(context);
+    });
+#else
+    callback(context);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecordsFunction callback)
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    WebKit::toImpl(dataStoreRef)->websiteDataStore().scheduleStatisticsAndDataRecordsProcessing([context, callback] {
+        callback(context);
+    });
+#else
+    callback(context);
+#endif
+}
+
</ins><span class="cx"> void WKWebsiteDataStoreStatisticsUpdateCookieBlocking(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsUpdateCookieBlockingFunction completionHandler)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(RESOURCE_LOAD_STATISTICS)
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKWebsiteDataStoreRefh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/API/C/WKWebsiteDataStoreRef.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -73,8 +73,12 @@
</span><span class="cx"> WK_EXPORT void WKWebsiteDataStoreSetStatisticsSubresourceUniqueRedirectFrom(WKWebsiteDataStoreRef dataStoreRef, WKStringRef host, WKStringRef hostRedirectedFrom);
</span><span class="cx"> WK_EXPORT void WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectTo(WKWebsiteDataStoreRef dataStoreRef, WKStringRef host, WKStringRef hostRedirectedTo);
</span><span class="cx"> WK_EXPORT void WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectFrom(WKWebsiteDataStoreRef dataStoreRef, WKStringRef host, WKStringRef hostRedirectedFrom);
</span><del>-WK_EXPORT void WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(WKWebsiteDataStoreRef dataStoreRef, double seconds);
-WK_EXPORT void WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(WKWebsiteDataStoreRef dataStoreRef);
</del><ins>+typedef void (*WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecorationFunction)(void* functionContext);
+WK_EXPORT void WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration(WKWebsiteDataStoreRef dataStoreRef, WKStringRef fromHost, WKStringRef toHost, void* context, WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecorationFunction callback);
+typedef void (*WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteractionFunction)(void* functionContext);
+WK_EXPORT void WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(WKWebsiteDataStoreRef dataStoreRef, double seconds, void* context, WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteractionFunction callback);
+typedef void (*WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecordsFunction)(void* functionContext);
+WK_EXPORT void WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecordsFunction callback);
</ins><span class="cx"> typedef void (*WKWebsiteDataStoreStatisticsUpdateCookieBlockingFunction)(void* functionContext);
</span><span class="cx"> WK_EXPORT void WKWebsiteDataStoreStatisticsUpdateCookieBlocking(WKWebsiteDataStoreRef dataStoreRef, void* context, WKWebsiteDataStoreStatisticsUpdateCookieBlockingFunction completionHandler);
</span><span class="cx"> WK_EXPORT void WKWebsiteDataStoreStatisticsSubmitTelemetry(WKWebsiteDataStoreRef dataStoreRef);
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaWebProcessPoolCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm       2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm  2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -307,6 +307,12 @@
</span><span class="cx"> 
</span><span class="cx">     parameters.shouldEnableITPDatabase = [defaults boolForKey:[NSString stringWithFormat:@"InternalDebug%@", WebPreferencesKey::isITPDatabaseEnabledKey().createCFString().get()]];
</span><span class="cx">     parameters.downloadMonitorSpeedMultiplier = m_configuration->downloadMonitorSpeedMultiplier();
</span><ins>+
+    // Check if the feature has been turned off explicitly. This avoids interpreting
+    // a non-existing default as a false value.
+    auto isITPFirstPartyWebsiteDataRemovalEnabledStr = [defaults stringForKey:[NSString stringWithFormat:@"Experimental%@", WebPreferencesKey::isITPFirstPartyWebsiteDataRemovalEnabledKey().createCFString().get()]];
+    if ([isITPFirstPartyWebsiteDataRemovalEnabledStr isEqual:@"0"])
+        parameters.isITPFirstPartyWebsiteDataRemovalEnabled = false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebProcessPool::platformInvalidateContext()
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessNetworkNetworkProcessProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -962,6 +962,16 @@
</span><span class="cx">     sendWithAsyncReply(Messages::NetworkProcess::CommittedCrossSiteLoadWithLinkDecoration(sessionID, fromDomain, toDomain, pageID), WTFMove(completionHandler));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void NetworkProcessProxy::setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, CompletionHandler<void()>&& completionHandler)
+{
+    if (!canSendMessage()) {
+        completionHandler();
+        return;
+    }
+    
+    sendWithAsyncReply(Messages::NetworkProcess::SetCrossSiteLoadWithLinkDecorationForTesting(sessionID, fromDomain, toDomain), WTFMove(completionHandler));
+}
+
</ins><span class="cx"> void NetworkProcessProxy::resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     if (!canSendMessage()) {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessNetworkNetworkProcessProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -146,6 +146,7 @@
</span><span class="cx">     void setShouldClassifyResourcesBeforeDataRecordsRemoval(PAL::SessionID, bool, CompletionHandler<void()>&&);
</span><span class="cx">     void resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID, CompletionHandler<void()>&&);
</span><span class="cx">     void committedCrossSiteLoadWithLinkDecoration(PAL::SessionID, const NavigatedFromDomain&, const NavigatedToDomain&, PageID, CompletionHandler<void()>&&);
</span><ins>+    void setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID, const NavigatedFromDomain&, const NavigatedToDomain&, CompletionHandler<void()>&&);
</ins><span class="cx">     void resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID, CompletionHandler<void()>&&);
</span><span class="cx">     void deleteCookiesForTesting(PAL::SessionID, const RegistrableDomain&, bool includeHttpOnlyCookies, CompletionHandler<void()>&&);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebsiteDataWebsiteDataStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp   2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp      2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1764,6 +1764,18 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebsiteDataStore::setCrossSiteLoadWithLinkDecorationForTesting(const URL& fromURL, const URL& toURL, CompletionHandler<void()>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
+    
+    for (auto& processPool : processPools()) {
+        if (auto* process = processPool->networkProcess())
+            process->setCrossSiteLoadWithLinkDecorationForTesting(m_sessionID, RegistrableDomain { fromURL }, RegistrableDomain { toURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
+    }
+}
+
</ins><span class="cx"> void WebsiteDataStore::resetCrossSiteLoadsWithLinkDecorationForTesting(CompletionHandler<void()>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebsiteDataWebsiteDataStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h     2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h        2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -168,6 +168,7 @@
</span><span class="cx">     void requestStorageAccess(const String& subFrameHost, const String& topFrameHost, uint64_t frameID, uint64_t pageID, CompletionHandler<void(StorageAccessStatus)>&&);
</span><span class="cx">     void grantStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool userWasPrompted, CompletionHandler<void(bool)>&&);
</span><span class="cx">     void setSubframeUnderTopFrameDomain(const URL& subframe, const URL& topFrame);
</span><ins>+    void setCrossSiteLoadWithLinkDecorationForTesting(const URL& fromURL, const URL& toURL, CompletionHandler<void()>&&);
</ins><span class="cx">     void resetCrossSiteLoadsWithLinkDecorationForTesting(CompletionHandler<void()>&&);
</span><span class="cx">     void deleteCookiesForTesting(const URL&, bool includeHttpOnlyCookies, CompletionHandler<void()>&&);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/ChangeLog       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2019-03-19  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics (experimental): Clear non-cookie website data for sites that have been navigated to, with link decoration, by a prevalent resource
+        https://bugs.webkit.org/show_bug.cgi?id=195923
+        <rdar://problem/49001272>
+
+        Reviewed by Alex Christensen.
+
+        This patch does the following to the TestRunner:
+        - Adds setStatisticsCrossSiteLoadWithLinkDecoration().
+        - Makes setStatisticsTimeToLiveUserInteraction() wait for completion.
+        - Makes statisticsProcessStatisticsAndDataRecords() wait for completion.
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setStatisticsCrossSiteLoadWithLinkDecoration):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::setStatisticsCrossSiteLoadWithLinkDecoration):
+        (WTR::TestController::setStatisticsTimeToLiveUserInteraction):
+        (WTR::TestController::statisticsProcessStatisticsAndDataRecords):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
</ins><span class="cx"> 2019-03-19  Christopher Reid  <chris.reid@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [CMake] Support more clang and gcc sanitizers
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleBindingsTestRunneridl"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl      2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl 2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -303,6 +303,7 @@
</span><span class="cx">     void setStatisticsSubresourceUniqueRedirectFrom(DOMString hostName, DOMString hostNameRedirectedTo);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectTo(DOMString hostName, DOMString hostNameRedirectedTo);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectFrom(DOMString hostName, DOMString hostNameRedirectedTo);
</span><ins>+    void setStatisticsCrossSiteLoadWithLinkDecoration(DOMString fromHost, DOMString toHost);
</ins><span class="cx">     void setStatisticsTimeToLiveUserInteraction(double seconds);
</span><span class="cx">     void statisticsNotifyObserver();
</span><span class="cx">     void statisticsProcessStatisticsAndDataRecords();
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleTestRunnercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp       2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp  2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1851,6 +1851,29 @@
</span><span class="cx">     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void TestRunner::setStatisticsCrossSiteLoadWithLinkDecoration(JSStringRef fromHost, JSStringRef toHost)
+{
+    Vector<WKRetainPtr<WKStringRef>> keys;
+    Vector<WKRetainPtr<WKTypeRef>> values;
+    
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("FromHost") });
+    values.append({ AdoptWK, WKStringCreateWithJSString(fromHost) });
+    
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ToHost") });
+    values.append({ AdoptWK, WKStringCreateWithJSString(toHost) });
+    
+    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("SetStatisticsCrossSiteLoadWithLinkDecoration"));
+    WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
</ins><span class="cx"> 
</span><span class="cx"> void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleTestRunnerh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h 2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h    2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -416,6 +416,7 @@
</span><span class="cx">     void setStatisticsSubresourceUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectTo(JSStringRef hostName, JSStringRef hostNameRedirectedTo);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectFrom(JSStringRef hostName, JSStringRef hostNameRedirectedFrom);
</span><ins>+    void setStatisticsCrossSiteLoadWithLinkDecoration(JSStringRef fromHost, JSStringRef toHost);
</ins><span class="cx">     void setStatisticsTimeToLiveUserInteraction(double seconds);
</span><span class="cx">     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
</span><span class="cx">     void setStatisticsIsRunningTest(bool);
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.cpp  2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp     2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -3255,16 +3255,28 @@
</span><span class="cx">     WKWebsiteDataStoreSetStatisticsTopFrameUniqueRedirectFrom(dataStore, host, hostRedirectedFrom);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void TestController::setStatisticsCrossSiteLoadWithLinkDecoration(WKStringRef fromHost, WKStringRef toHost)
+{
+    auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsCrossSiteLoadWithLinkDecoration(dataStore, fromHost, toHost, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
+}
+
</ins><span class="cx"> void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
</span><span class="cx"> {
</span><span class="cx">     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
</span><del>-    WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(dataStore, seconds);
</del><ins>+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreSetStatisticsTimeToLiveUserInteraction(dataStore, seconds, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void TestController::statisticsProcessStatisticsAndDataRecords()
</span><span class="cx"> {
</span><span class="cx">     auto* dataStore = WKContextGetWebsiteDataStore(platformContext());
</span><del>-    WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(dataStore);
</del><ins>+    ResourceStatisticsCallbackContext context(*this);
+    WKWebsiteDataStoreStatisticsProcessStatisticsAndDataRecords(dataStore, &context, resourceStatisticsVoidResultCallback);
+    runUntil(context.done, noTimeout);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void TestController::statisticsUpdateCookieBlocking()
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestController.h (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.h    2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/TestController.h       2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -225,6 +225,7 @@
</span><span class="cx">     void setStatisticsSubresourceUniqueRedirectFrom(WKStringRef host, WKStringRef hostRedirectedFrom);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectTo(WKStringRef host, WKStringRef hostRedirectedTo);
</span><span class="cx">     void setStatisticsTopFrameUniqueRedirectFrom(WKStringRef host, WKStringRef hostRedirectedFrom);
</span><ins>+    void setStatisticsCrossSiteLoadWithLinkDecoration(WKStringRef fromHost, WKStringRef toHost);
</ins><span class="cx">     void setStatisticsTimeToLiveUserInteraction(double seconds);
</span><span class="cx">     void statisticsProcessStatisticsAndDataRecords();
</span><span class="cx">     void statisticsUpdateCookieBlocking();
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestInvocationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestInvocation.cpp (243180 => 243181)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestInvocation.cpp  2019-03-19 23:35:20 UTC (rev 243180)
+++ trunk/Tools/WebKitTestRunner/TestInvocation.cpp     2019-03-20 00:22:09 UTC (rev 243181)
</span><span class="lines">@@ -1304,6 +1304,20 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsCrossSiteLoadWithLinkDecoration")) {
+        ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+        
+        WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+        auto fromHostKey = adoptWK(WKStringCreateWithUTF8CString("FromHost"));
+        auto toHostKey = adoptWK(WKStringCreateWithUTF8CString("ToHost"));
+
+        WKStringRef fromHost = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, fromHostKey.get()));
+        WKStringRef toHost = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, toHostKey.get()));
+        
+        TestController::singleton().setStatisticsCrossSiteLoadWithLinkDecoration(fromHost, toHost);
+        return nullptr;
+    }
+
</ins><span class="cx">     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsTimeToLiveUserInteraction")) {
</span><span class="cx">         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
</span><span class="cx">         WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
</span></span></pre>
</div>
</div>

</body>
</html>