Resource Load Statistics: Update cookie blocking in NetworkStorageSession after first user interaction
https://bugs.webkit.org/show_bug.cgi?id=203195
<rdar://problem/56464567>

Reviewed by Alex Christensen and Chris Dumez.

Source/WebKit:

This change makes sure that the state of cookie blocking in
WebCore:: NetworkStorageSession is immediately updated if the logged
user interaction was new for this domain. It adds a completion
handler to WebResourceLoadStatisticsStore::logUserInteraction() so
that the call properly waits for everything to be updated.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::CompletionHandler<void):
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
(WebKit::ResourceLoadStatisticsMemoryStore::logUserInteraction):
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::logUserInteraction):

LayoutTests:

This patch removes the explicit calls to testRunner.statisticsUpdateCookieBlocking() since
they are no longer needed. This makes sure the changed code is tested.

* http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html:
* http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251391 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 00fc9f3..bfdf6a0 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,17 @@
+2019-10-21  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Update cookie blocking in NetworkStorageSession after first user interaction
+        https://bugs.webkit.org/show_bug.cgi?id=203195
+        <rdar://problem/56464567>
+
+        Reviewed by Alex Christensen and Chris Dumez.
+
+        This patch removes the explicit calls to testRunner.statisticsUpdateCookieBlocking() since
+        they are no longer needed. This makes sure the changed code is tested.
+
+        * http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html:
+        * http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html:
+
 2019-10-21  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Unreviewed, re-enable a couple of passing layout tests
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html b/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html
index fc9233c..a3e0735 100644
--- a/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html
+++ b/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction-database.html
@@ -46,10 +46,8 @@
                 document.location.hash = "step4";
                 // Produce user interaction for the first-party to allow third-party cookie access.
                 testRunner.setStatisticsHasHadUserInteraction(partitionOrigin, true, function() {
-                    testRunner.statisticsUpdateCookieBlocking(function() {
-                        // Check that the cookie is no longer blocked for localhost under 127.0.0.1.
-                        openIframe(thirdPartyBaseUrl + subPathToGetCookies +  "&message=After user interaction, should receive first-party cookie.", runTest);
-                    });
+                    // Check that the cookie is no longer blocked for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies +  "&message=After user interaction, should receive first-party cookie.", runTest);
                 });
                 break;
             case "#step4":
diff --git a/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html b/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html
index cdf7323..e66ea36 100644
--- a/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html
+++ b/LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-on-sites-without-user-interaction.html
@@ -46,10 +46,8 @@
                 document.location.hash = "step4";
                 // Produce user interaction for the first-party to allow third-party cookie access.
                 testRunner.setStatisticsHasHadUserInteraction(partitionOrigin, true, function() {
-                    testRunner.statisticsUpdateCookieBlocking(function() {
-                        // Check that the cookie is no longer blocked for localhost under 127.0.0.1.
-                        openIframe(thirdPartyBaseUrl + subPathToGetCookies +  "&message=After user interaction, should receive first-party cookie.", runTest);
-                    });
+                    // Check that the cookie is no longer blocked for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies +  "&message=After user interaction, should receive first-party cookie.", runTest);
                 });
                 break;
             case "#step4":
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 323b237..d478525 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,27 @@
+2019-10-21  John Wilander  <wilander@apple.com>
+
+        Resource Load Statistics: Update cookie blocking in NetworkStorageSession after first user interaction
+        https://bugs.webkit.org/show_bug.cgi?id=203195
+        <rdar://problem/56464567>
+
+        Reviewed by Alex Christensen and Chris Dumez.
+
+        This change makes sure that the state of cookie blocking in
+        WebCore:: NetworkStorageSession is immediately updated if the logged
+        user interaction was new for this domain. It adds a completion
+        handler to WebResourceLoadStatisticsStore::logUserInteraction() so
+        that the call properly waits for everything to be updated.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::CompletionHandler<void):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
+        (WebKit::ResourceLoadStatisticsMemoryStore::logUserInteraction):
+        * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::logUserInteraction):
+
 2019-10-21  Dean Jackson  <dino@apple.com>
 
         Dispatch AR event on the originating anchor element
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
index eb94abb..8b61842 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
@@ -1350,12 +1350,18 @@
     ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
-void ResourceLoadStatisticsDatabaseStore::logUserInteraction(const TopFrameDomain& domain)
+void ResourceLoadStatisticsDatabaseStore::logUserInteraction(const TopFrameDomain& domain, CompletionHandler<void()>&& completionHandler)
 {
     ASSERT(!RunLoop::isMain());
 
+    bool didHavePreviousUserInteraction = hasHadUserInteraction(domain, OperatingDatesWindow::Long);
     ensureResourceStatisticsForRegistrableDomain(domain);
     setUserInteraction(domain, true, WallTime::now());
+    if (didHavePreviousUserInteraction) {
+        completionHandler();
+        return;
+    }
+    updateCookieBlocking(WTFMove(completionHandler));
 }
 
 void ResourceLoadStatisticsDatabaseStore::clearUserInteraction(const RegistrableDomain& domain)
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h
index 0226325..690d0b0 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h
@@ -123,7 +123,7 @@
     void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) override;
 
     void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame) override;
-    void logUserInteraction(const TopFrameDomain&) override;
+    void logUserInteraction(const TopFrameDomain&, CompletionHandler<void()>&&) override;
     void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
 
     void clearUserInteraction(const RegistrableDomain&) override;
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp
index f92f4fd..500dd21 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp
@@ -403,13 +403,19 @@
         scheduleStatisticsProcessingRequestIfNecessary();
 }
 
-void ResourceLoadStatisticsMemoryStore::logUserInteraction(const TopFrameDomain& domain)
+void ResourceLoadStatisticsMemoryStore::logUserInteraction(const TopFrameDomain& domain, CompletionHandler<void()>&& completionHandler)
 {
     ASSERT(!RunLoop::isMain());
 
     auto& statistics = ensureResourceStatisticsForRegistrableDomain(domain);
+    bool didHavePreviousUserInteraction = statistics.hadUserInteraction;
     statistics.hadUserInteraction = true;
     statistics.mostRecentUserInteractionTime = WallTime::now();
+    if (didHavePreviousUserInteraction) {
+        completionHandler();
+        return;
+    }
+    updateCookieBlocking(WTFMove(completionHandler));
 }
 
 void ResourceLoadStatisticsMemoryStore::logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain& fromDomain, const NavigatedToDomain& toDomain)
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h
index 68054a5..631fc3d 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h
@@ -102,7 +102,7 @@
     void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) override;
 
     void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame) override;
-    void logUserInteraction(const TopFrameDomain&) override;
+    void logUserInteraction(const TopFrameDomain&, CompletionHandler<void()>&&) override;
     void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
 
     void clearUserInteraction(const RegistrableDomain&) override;
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h
index 99a6710..2209ac0 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h
@@ -166,7 +166,7 @@
     virtual void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) = 0;
 
     virtual void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame) = 0;
-    virtual void logUserInteraction(const TopFrameDomain&) = 0;
+    virtual void logUserInteraction(const TopFrameDomain&, CompletionHandler<void()>&&) = 0;
     virtual void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) = 0;
 
     virtual void clearUserInteraction(const RegistrableDomain&) = 0;
diff --git a/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp b/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp
index 7b8adec..1db4ec2 100644
--- a/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp
+++ b/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp
@@ -547,9 +547,14 @@
     ASSERT(RunLoop::isMain());
 
     postTask([this, domain = domain.isolatedCopy(), completionHandler = WTFMove(completionHandler)]() mutable {
-        if (m_statisticsStore)
-            m_statisticsStore->logUserInteraction(domain);
-        postTaskReply(WTFMove(completionHandler));
+        auto innerCompletionHandler = [completionHandler = WTFMove(completionHandler)]() mutable {
+            postTaskReply(WTFMove(completionHandler));
+        };
+        if (m_statisticsStore) {
+            m_statisticsStore->logUserInteraction(domain, WTFMove(innerCompletionHandler));
+            return;
+        }
+        innerCompletionHandler();
     });
 }