Storage Access API: Add the capability to call the Storage Access API as a quirk...
authorwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 23 Jun 2020 04:13:24 +0000 (04:13 +0000)
committerwilander@apple.com <wilander@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 23 Jun 2020 04:13:24 +0000 (04:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=213418
<rdar://problem/64549429>

Reviewed by Alex Christensen.

Source/WebCore:

No new tests. This patch adds quirks for specific websites.
The general functionality that's touched has tests under
LayoutTests/http/tests/storageAccess/.

* dom/Document.h:
(WebCore::Document::isTopDocument const):
    New convenience function.
(WebCore::Document::setUserDidInteractWithPage):
    Use of the new convenience function.
(WebCore::Document::userDidInteractWithPage const):
    Use of the new convenience function.
* dom/DocumentStorageAccess.cpp:
(WebCore::DocumentStorageAccess::hasStorageAccessQuickCheck):
(WebCore::DocumentStorageAccess::hasStorageAccess):
(WebCore::DocumentStorageAccess::hasStorageAccessForDocumentQuirk):
(WebCore::DocumentStorageAccess::requestStorageAccess):
(WebCore::DocumentStorageAccess::requestStorageAccessQuickCheck):
(WebCore::DocumentStorageAccess::requestStorageAccessForDocumentQuirk):
(WebCore::DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk):
(WebCore::DocumentStorageAccess::requestStorageAccessQuirk):
    These functions are split up to allow quirks to call directly into the
    implementation of the Storage Access API without the JavaScript
    promise that goes with the web API. It also allows for quirks to call
    the API without an iframe document.
* dom/DocumentStorageAccess.h:
* dom/Element.cpp:
(WebCore::Element::dispatchMouseEvent):
    The two existing quirks are for click events.
* loader/ResourceLoadObserver.h:
(WebCore::ResourceLoadObserver::setDomainsWithUserInteraction):
(WebCore::ResourceLoadObserver::hasHadUserInteraction const):
    These two new functions allow the Storage Access API quirks
    to synchronously check if it's worth calling the API or not.
    If there has been no user interaction for the requesting
    domain, there is no need to call the API.
* page/Quirks.cpp:
(WebCore::Quirks::triggerOptionalStorageAccessQuirk const):
    This is the new quirks function, hiding the specifics of
    certain elements clicked and for which websites. It also
    calls the Storage Access API.
* page/Quirks.h:

Source/WebKit:

These changes are for forwarding ITP's knowledge of user interaction
for specific quirks domains to the WebKit::WebProcessPool where it in
turn can be distributed to all existing and new Web Content processes.

* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::needsUserInteractionQuirk const):
(WebKit::WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToBlockCookiesForHandler):
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
* Shared/WebProcessDataStoreParameters.h:
(WebKit::WebProcessDataStoreParameters::encode const):
(WebKit::WebProcessDataStoreParameters::decode):
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::setDomainsWithUserInteraction):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::webProcessDataStoreParameters):
(WebKit::WebProcessPool::setDomainsWithUserInteraction):
* UIProcess/WebProcessPool.h:
* WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp:
(WebKit::WebResourceLoadObserver::hasHadUserInteraction const):
* WebProcess/WebCoreSupport/WebResourceLoadObserver.h:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::setWebsiteDataStoreParameters):
(WebKit::WebProcess::setDomainsWithUserInteraction):
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

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

22 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.h
Source/WebCore/dom/DocumentStorageAccess.cpp
Source/WebCore/dom/DocumentStorageAccess.h
Source/WebCore/dom/Element.cpp
Source/WebCore/loader/ResourceLoadObserver.h
Source/WebCore/page/Quirks.cpp
Source/WebCore/page/Quirks.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp
Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h
Source/WebKit/Shared/WebProcessDataStoreParameters.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebResourceLoadObserver.h
Source/WebKit/WebProcess/WebProcess.cpp
Source/WebKit/WebProcess/WebProcess.h
Source/WebKit/WebProcess/WebProcess.messages.in

index ffa1101..e2a1402 100644 (file)
@@ -1,3 +1,53 @@
+2020-06-22  John Wilander  <wilander@apple.com>
+
+        Storage Access API: Add the capability to call the Storage Access API as a quirk, on behalf of websites that should be doing it themselves
+        https://bugs.webkit.org/show_bug.cgi?id=213418
+        <rdar://problem/64549429>
+
+        Reviewed by Alex Christensen.
+
+        No new tests. This patch adds quirks for specific websites.
+        The general functionality that's touched has tests under
+        LayoutTests/http/tests/storageAccess/.
+
+        * dom/Document.h:
+        (WebCore::Document::isTopDocument const):
+            New convenience function.
+        (WebCore::Document::setUserDidInteractWithPage):
+            Use of the new convenience function.
+        (WebCore::Document::userDidInteractWithPage const):
+            Use of the new convenience function.
+        * dom/DocumentStorageAccess.cpp:
+        (WebCore::DocumentStorageAccess::hasStorageAccessQuickCheck):
+        (WebCore::DocumentStorageAccess::hasStorageAccess):
+        (WebCore::DocumentStorageAccess::hasStorageAccessForDocumentQuirk):
+        (WebCore::DocumentStorageAccess::requestStorageAccess):
+        (WebCore::DocumentStorageAccess::requestStorageAccessQuickCheck):
+        (WebCore::DocumentStorageAccess::requestStorageAccessForDocumentQuirk):
+        (WebCore::DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk):
+        (WebCore::DocumentStorageAccess::requestStorageAccessQuirk):
+            These functions are split up to allow quirks to call directly into the
+            implementation of the Storage Access API without the JavaScript
+            promise that goes with the web API. It also allows for quirks to call
+            the API without an iframe document.
+        * dom/DocumentStorageAccess.h:
+        * dom/Element.cpp:
+        (WebCore::Element::dispatchMouseEvent):
+            The two existing quirks are for click events.
+        * loader/ResourceLoadObserver.h:
+        (WebCore::ResourceLoadObserver::setDomainsWithUserInteraction):
+        (WebCore::ResourceLoadObserver::hasHadUserInteraction const):
+            These two new functions allow the Storage Access API quirks
+            to synchronously check if it's worth calling the API or not.
+            If there has been no user interaction for the requesting
+            domain, there is no need to call the API.
+        * page/Quirks.cpp:
+        (WebCore::Quirks::triggerOptionalStorageAccessQuirk const):
+            This is the new quirks function, hiding the specifics of
+            certain elements clicked and for which websites. It also
+            calls the Storage Access API.
+        * page/Quirks.h:
+
 2020-06-22  Chris Dumez  <cdumez@apple.com>
 
         Introduce BaseAudioContext interface
index 324cace..7e6e990 100644 (file)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- * Copyright (C) 2004-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
  * Copyright (C) 2011 Google Inc. All rights reserved.
@@ -1033,6 +1033,7 @@ public:
 
     Document* parentDocument() const;
     WEBCORE_EXPORT Document& topDocument() const;
+    bool isTopDocument() const { return &topDocument() == this; }
     
     ScriptRunner& scriptRunner() { return *m_scriptRunner; }
     ScriptModuleLoader& moduleLoader() { return *m_moduleLoader; }
@@ -1243,8 +1244,8 @@ public:
     bool processingUserGestureForMedia() const;
     void userActivatedMediaFinishedPlaying() { m_userActivatedMediaFinishedPlayingTimestamp = MonotonicTime::now(); }
 
-    void setUserDidInteractWithPage(bool userDidInteractWithPage) { ASSERT(&topDocument() == this); m_userDidInteractWithPage = userDidInteractWithPage; }
-    bool userDidInteractWithPage() const { ASSERT(&topDocument() == this); return m_userDidInteractWithPage; }
+    void setUserDidInteractWithPage(bool userDidInteractWithPage) { ASSERT(isTopDocument()); m_userDidInteractWithPage = userDidInteractWithPage; }
+    bool userDidInteractWithPage() const { ASSERT(isTopDocument()); return m_userDidInteractWithPage; }
 
     // Used for testing. Count handlers in the main document, and one per frame which contains handlers.
     WEBCORE_EXPORT unsigned wheelEventHandlerCount() const;
index 0f1bf62..915e25e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -72,47 +72,57 @@ void DocumentStorageAccess::hasStorageAccess(Document& document, Ref<DeferredPro
     DocumentStorageAccess::from(document)->hasStorageAccess(WTFMove(promise));
 }
 
-void DocumentStorageAccess::requestStorageAccess(Document& document, Ref<DeferredPromise>&& promise)
+Optional<bool> DocumentStorageAccess::hasStorageAccessQuickCheck()
 {
-    DocumentStorageAccess::from(document)->requestStorageAccess(WTFMove(promise));
+    ASSERT(m_document.settings().storageAccessAPIEnabled());
+
+    auto* frame = m_document.frame();
+    if (frame && hasFrameSpecificStorageAccess())
+        return true;
+
+    if (!frame || m_document.securityOrigin().isUnique())
+        return false;
+
+    if (frame->isMainFrame())
+        return true;
+
+    auto& securityOrigin = m_document.securityOrigin();
+    auto& topSecurityOrigin = m_document.topDocument().securityOrigin();
+    if (securityOrigin.equal(&topSecurityOrigin))
+        return true;
+
+    auto* page = frame->page();
+    if (!page)
+        return false;
+
+    return WTF::nullopt;
 }
 
 void DocumentStorageAccess::hasStorageAccess(Ref<DeferredPromise>&& promise)
 {
     ASSERT(m_document.settings().storageAccessAPIEnabled());
 
-    auto* frame = m_document.frame();
-    if (frame && hasFrameSpecificStorageAccess()) {
-        promise->resolve<IDLBoolean>(true);
+    auto quickCheckResult = hasStorageAccessQuickCheck();
+    if (quickCheckResult) {
+        promise->resolve<IDLBoolean>(*quickCheckResult);
         return;
     }
-    
-    if (!frame || m_document.securityOrigin().isUnique()) {
+
+    // The existence of a frame and page has been checked in requestStorageAccessQuickCheck().
+    auto* frame = m_document.frame();
+    if (!frame) {
+        ASSERT_NOT_REACHED();
         promise->resolve<IDLBoolean>(false);
         return;
     }
-    
-    if (frame->isMainFrame()) {
-        promise->resolve<IDLBoolean>(true);
-        return;
-    }
-    
-    auto& securityOrigin = m_document.securityOrigin();
-    auto& topSecurityOrigin = m_document.topDocument().securityOrigin();
-    if (securityOrigin.equal(&topSecurityOrigin)) {
-        promise->resolve<IDLBoolean>(true);
-        return;
-    }
-    
     auto* page = frame->page();
     if (!page) {
-        promise->reject();
+        ASSERT_NOT_REACHED();
+        promise->resolve<IDLBoolean>(false);
         return;
     }
-    
-    auto subFrameDomain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host());
-    auto topFrameDomain = RegistrableDomain::uncheckedCreateFromHost(topSecurityOrigin.host());
-    page->chrome().client().hasStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, [weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (bool hasAccess) {
+
+    page->chrome().client().hasStorageAccess(RegistrableDomain::uncheckedCreateFromHost(m_document.securityOrigin().host()), RegistrableDomain::uncheckedCreateFromHost(m_document.topDocument().securityOrigin().host()), *frame, [weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (bool hasAccess) {
         if (!weakThis)
             return;
 
@@ -120,53 +130,73 @@ void DocumentStorageAccess::hasStorageAccess(Ref<DeferredPromise>&& promise)
     });
 }
 
-void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
+bool DocumentStorageAccess::hasStorageAccessForDocumentQuirk(Document& document)
+{
+    auto quickCheckResult = DocumentStorageAccess::from(document)->hasStorageAccessQuickCheck();
+    if (quickCheckResult)
+        return *quickCheckResult;
+    return false;
+}
+
+void DocumentStorageAccess::requestStorageAccess(Document& document, Ref<DeferredPromise>&& promise)
+{
+    DocumentStorageAccess::from(document)->requestStorageAccess(WTFMove(promise));
+}
+
+Optional<StorageAccessQuickResult> DocumentStorageAccess::requestStorageAccessQuickCheck()
 {
     ASSERT(m_document.settings().storageAccessAPIEnabled());
-    
+
     auto* frame = m_document.frame();
-    if (frame && hasFrameSpecificStorageAccess()) {
-        promise->resolve();
-        return;
-    }
-    
-    if (!frame || m_document.securityOrigin().isUnique() || !isAllowedToRequestFrameSpecificStorageAccess()) {
-        promise->reject();
-        return;
-    }
-    
-    if (frame->isMainFrame()) {
-        promise->resolve();
-        return;
-    }
-    
+    if (frame && hasFrameSpecificStorageAccess())
+        return StorageAccessQuickResult::Grant;
+
+    if (!frame || m_document.securityOrigin().isUnique() || !isAllowedToRequestFrameSpecificStorageAccess())
+        return StorageAccessQuickResult::Reject;
+
+    if (frame->isMainFrame())
+        return StorageAccessQuickResult::Grant;
+
     auto& topDocument = m_document.topDocument();
     auto& topSecurityOrigin = topDocument.securityOrigin();
     auto& securityOrigin = m_document.securityOrigin();
-    if (securityOrigin.equal(&topSecurityOrigin)) {
-        promise->resolve();
-        return;
-    }
-    
+    if (securityOrigin.equal(&topSecurityOrigin))
+        return StorageAccessQuickResult::Grant;
+
     // If there is a sandbox, it has to allow the storage access API to be called.
-    if (m_document.sandboxFlags() != SandboxNone && m_document.isSandboxed(SandboxStorageAccessByUserActivation)) {
-        promise->reject();
-        return;
-    }
-    
+    if (m_document.sandboxFlags() != SandboxNone && m_document.isSandboxed(SandboxStorageAccessByUserActivation))
+        return StorageAccessQuickResult::Reject;
+
     // The iframe has to be a direct child of the top document.
-    if (&topDocument != m_document.parentDocument()) {
-        promise->reject();
+    if (&topDocument != m_document.parentDocument())
+        return StorageAccessQuickResult::Reject;
+
+    if (!UserGestureIndicator::processingUserGesture())
+        return StorageAccessQuickResult::Reject;
+
+    return WTF::nullopt;
+}
+
+void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
+{
+    ASSERT(m_document.settings().storageAccessAPIEnabled());
+
+    auto quickCheckResult = requestStorageAccessQuickCheck();
+    if (quickCheckResult) {
+        *quickCheckResult == StorageAccessQuickResult::Grant ? promise->resolve() : promise->reject();
         return;
     }
-    
-    if (!UserGestureIndicator::processingUserGesture()) {
+
+    // The existence of a frame and page has been checked in requestStorageAccessQuickCheck().
+    auto* frame = m_document.frame();
+    if (!frame) {
+        ASSERT_NOT_REACHED();
         promise->reject();
         return;
     }
-
     auto* page = frame->page();
     if (!page) {
+        ASSERT_NOT_REACHED();
         promise->reject();
         return;
     }
@@ -174,10 +204,7 @@ void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
     if (page->settings().storageAccessAPIPerPageScopeEnabled())
         m_storageAccessScope = StorageAccessScope::PerPage;
 
-    auto subFrameDomain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host());
-    auto topFrameDomain = RegistrableDomain::uncheckedCreateFromHost(topSecurityOrigin.host());
-    
-    page->chrome().client().requestStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, m_storageAccessScope, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (RequestStorageAccessResult result) mutable {
+    page->chrome().client().requestStorageAccess(RegistrableDomain::uncheckedCreateFromHost(m_document.securityOrigin().host()), RegistrableDomain::uncheckedCreateFromHost(m_document.topDocument().securityOrigin().host()), *frame, m_storageAccessScope, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (RequestStorageAccessResult result) mutable {
         if (!weakThis)
             return;
 
@@ -208,6 +235,71 @@ void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
     });
 }
 
+void DocumentStorageAccess::requestStorageAccessForDocumentQuirk(Document& document, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+{
+    DocumentStorageAccess::from(document)->requestStorageAccessForDocumentQuirk(WTFMove(completionHandler));
+}
+
+void DocumentStorageAccess::requestStorageAccessForDocumentQuirk(CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+{
+    auto quickCheckResult = requestStorageAccessQuickCheck();
+    if (quickCheckResult) {
+        *quickCheckResult == StorageAccessQuickResult::Grant ? completionHandler(StorageAccessWasGranted::Yes) : completionHandler(StorageAccessWasGranted::No);
+        return;
+    }
+    requestStorageAccessQuirk(RegistrableDomain::uncheckedCreateFromHost(m_document.securityOrigin().host()), WTFMove(completionHandler));
+}
+
+void DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(Document& hostingDocument, RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+{
+    DocumentStorageAccess::from(hostingDocument)->requestStorageAccessForNonDocumentQuirk(WTFMove(requestingDomain), WTFMove(completionHandler));
+}
+
+void DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+{
+    if (!m_document.frame() || !m_document.frame()->page()) {
+        completionHandler(StorageAccessWasGranted::No);
+        return;
+    }
+    requestStorageAccessQuirk(WTFMove(requestingDomain), WTFMove(completionHandler));
+}
+
+void DocumentStorageAccess::requestStorageAccessQuirk(RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
+{
+    ASSERT(m_document.settings().storageAccessAPIEnabled());
+    RELEASE_ASSERT(m_document.frame() && m_document.frame()->page());
+
+    m_document.frame()->page()->chrome().client().requestStorageAccess(WTFMove(requestingDomain), RegistrableDomain::uncheckedCreateFromHost(m_document.topDocument().securityOrigin().host()), *m_document.frame(), m_storageAccessScope, [this, weakThis = makeWeakPtr(*this), completionHandler = WTFMove(completionHandler)] (RequestStorageAccessResult result) mutable {
+        if (!weakThis)
+            return;
+
+        // Consume the user gesture only if the user explicitly denied access.
+        bool shouldPreserveUserGesture = result.wasGranted == StorageAccessWasGranted::Yes || result.promptWasShown == StorageAccessPromptWasShown::No;
+
+        if (shouldPreserveUserGesture) {
+            m_document.eventLoop().queueMicrotask([this, weakThis] {
+                if (weakThis)
+                    enableTemporaryTimeUserGesture();
+            });
+        }
+
+        if (result.wasGranted == StorageAccessWasGranted::Yes)
+            completionHandler(StorageAccessWasGranted::Yes);
+        else {
+            if (result.promptWasShown == StorageAccessPromptWasShown::Yes)
+                setWasExplicitlyDeniedFrameSpecificStorageAccess();
+            completionHandler(StorageAccessWasGranted::No);
+        }
+
+        if (shouldPreserveUserGesture) {
+            m_document.eventLoop().queueMicrotask([this, weakThis] {
+                if (weakThis)
+                    consumeTemporaryTimeUserGesture();
+            });
+        }
+    });
+}
+
 void DocumentStorageAccess::enableTemporaryTimeUserGesture()
 {
     m_temporaryUserGesture = makeUnique<UserGestureIndicator>(ProcessingUserGesture, &m_document);
index a7e00a6..066cec7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,7 @@
 
 #include "RegistrableDomain.h"
 #include "Supplementable.h"
+#include <wtf/Optional.h>
 #include <wtf/WeakPtr.h>
 
 namespace WebCore {
@@ -52,6 +53,11 @@ enum class StorageAccessScope : bool {
     PerPage
 };
 
+enum class StorageAccessQuickResult : bool {
+    Grant,
+    Reject
+};
+
 struct RequestStorageAccessResult {
     StorageAccessWasGranted wasGranted;
     StorageAccessPromptWasShown promptWasShown;
@@ -72,11 +78,23 @@ public:
     ~DocumentStorageAccess();
 
     static void hasStorageAccess(Document&, Ref<DeferredPromise>&&);
+    static bool hasStorageAccessForDocumentQuirk(Document&);
+
     static void requestStorageAccess(Document&, Ref<DeferredPromise>&&);
+    static void requestStorageAccessForDocumentQuirk(Document&, CompletionHandler<void(StorageAccessWasGranted)>&&);
+    static void requestStorageAccessForNonDocumentQuirk(Document& hostingDocument, RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&&);
 
 private:
+    Optional<bool> hasStorageAccessQuickCheck();
     void hasStorageAccess(Ref<DeferredPromise>&&);
+    bool hasStorageAccessQuirk();
+
+    Optional<StorageAccessQuickResult> requestStorageAccessQuickCheck();
     void requestStorageAccess(Ref<DeferredPromise>&&);
+    void requestStorageAccessForDocumentQuirk(CompletionHandler<void(StorageAccessWasGranted)>&&);
+    void requestStorageAccessForNonDocumentQuirk(RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&&);
+    void requestStorageAccessQuirk(RegistrableDomain&& requestingDomain, CompletionHandler<void(StorageAccessWasGranted)>&&);
+
     static DocumentStorageAccess* from(Document&);
     static const char* supplementName();
     bool hasFrameSpecificStorageAccess() const;
index b9a66c0..7578d0c 100644 (file)
@@ -87,6 +87,7 @@
 #include "PointerEvent.h"
 #include "PointerLockController.h"
 #include "PseudoClassChangeInvalidation.h"
+#include "Quirks.h"
 #include "RenderFragmentedFlow.h"
 #include "RenderLayer.h"
 #include "RenderLayerBacking.h"
@@ -361,6 +362,9 @@ bool Element::dispatchMouseEvent(const PlatformMouseEvent& platformEvent, const
     if (dispatchPointerEventIfNeeded(*this, mouseEvent.get(), platformEvent, didNotSwallowEvent) == ShouldIgnoreMouseEvent::Yes)
         return false;
 
+    if (hasClass() && Quirks::StorageAccessResult::ShouldCancelEvent == document().quirks().triggerOptionalStorageAccessQuirk(eventType, classNames()))
+        return false;
+
     ASSERT(!mouseEvent->target() || mouseEvent->target() != relatedTarget);
     dispatchEvent(mouseEvent);
     if (mouseEvent->defaultPrevented() || mouseEvent->defaultHandled())
index 129c3c6..67fbffc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2019 Apple Inc.  All rights reserved.
+ * Copyright (C) 2016-2020 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -62,6 +62,9 @@ public:
     virtual void clearState() { }
     
     virtual bool hasStatistics() const { return false; }
+
+    virtual void setDomainsWithUserInteraction(HashSet<RegistrableDomain>&&) { }
+    virtual bool hasHadUserInteraction(const RegistrableDomain&) const { return false; }
 };
     
 } // namespace WebCore
index 9c189e1..8911f9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 #include "DOMWindow.h"
 #include "Document.h"
 #include "DocumentLoader.h"
+#include "DocumentStorageAccess.h"
 #include "EventNames.h"
 #include "FrameLoader.h"
 #include "HTMLBodyElement.h"
 #include "HTMLObjectElement.h"
 #include "JSEventListener.h"
 #include "LayoutUnit.h"
+#include "ResourceLoadObserver.h"
 #include "RuntimeEnabledFeatures.h"
 #include "Settings.h"
+#include "SpaceSplitString.h"
 #include "UserAgent.h"
 
 namespace WebCore {
@@ -839,4 +842,61 @@ bool Quirks::shouldAvoidPastingImagesAsWebContent() const
 #endif
 }
 
+Quirks::StorageAccessResult Quirks::triggerOptionalStorageAccessQuirk(const AtomString& eventType, const SpaceSplitString& classNames) const
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    if (!needsQuirks())
+        return Quirks::StorageAccessResult::ShouldNotCancelEvent;
+
+    RegistrableDomain domain { m_document->url() };
+
+    static NeverDestroyed<HashSet<RegistrableDomain>> kinjaQuirks = [] {
+        HashSet<RegistrableDomain> set;
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("avclub.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("gizmodo.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("deadspin.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("jalopnik.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("jezebel.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("kotaku.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("lifehacker.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("theroot.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("thetakeout.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("theonion.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("theinventory.com"_s));
+        return set;
+    }();
+    static NeverDestroyed<RegistrableDomain> kinjaDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString("kinja.com"_s);
+
+    static NeverDestroyed<RegistrableDomain> youTubeDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString("youtube.com"_s);
+
+    if (eventType == "click") {
+
+        // Embedded YouTube case.
+        if (domain == youTubeDomain && !m_document->isTopDocument() && ResourceLoadObserver::shared().hasHadUserInteraction(youTubeDomain) && (classNames.contains("ytp-watch-later-icon") || classNames.contains("ytp-watch-later-icon"))) {
+            if (ResourceLoadObserver::shared().hasHadUserInteraction(youTubeDomain)) {
+                DocumentStorageAccess::requestStorageAccessForDocumentQuirk(*m_document, [](StorageAccessWasGranted) {
+                    // FIXME: Add appropriate logging.
+                });
+                return Quirks::StorageAccessResult::ShouldNotCancelEvent;
+            }
+        }
+
+        // Kinja burner account login case.
+        if (kinjaQuirks.get().contains(domain) && classNames.contains("js_switch-to-burner-login")) {
+            if (ResourceLoadObserver::shared().hasHadUserInteraction(kinjaDomain)) {
+                DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(*m_document, kinjaDomain.get().isolatedCopy(), [](StorageAccessWasGranted) {
+                    // FIXME: Add appropriate logging.
+                });
+                return Quirks::StorageAccessResult::ShouldNotCancelEvent;
+            }
+            // FIXME: Take the user to kinja.com in the else case.
+        }
+    }
+#else
+    UNUSED_PARAM(eventType);
+    UNUSED_PARAM(classNames);
+#endif
+    return Quirks::StorageAccessResult::ShouldNotCancelEvent;
+}
+
 }
index 6386e74..0560978 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,6 +36,7 @@ class EventListener;
 class EventTarget;
 class HTMLElement;
 class LayoutUnit;
+class SpaceSplitString;
 
 class Quirks {
     WTF_MAKE_NONCOPYABLE(Quirks); WTF_MAKE_FAST_ALLOCATED;
@@ -105,6 +106,9 @@ public:
 
     bool shouldAvoidPastingImagesAsWebContent() const;
 
+    enum StorageAccessResult : bool { ShouldNotCancelEvent, ShouldCancelEvent };
+    StorageAccessResult triggerOptionalStorageAccessQuirk(const AtomString& eventType, const SpaceSplitString& classNames) const;
+
 private:
     bool needsQuirks() const;
 
index 4f6e9a5..2c18950 100644 (file)
@@ -1,3 +1,39 @@
+2020-06-22  John Wilander  <wilander@apple.com>
+
+        Storage Access API: Add the capability to call the Storage Access API as a quirk, on behalf of websites that should be doing it themselves
+        https://bugs.webkit.org/show_bug.cgi?id=213418
+        <rdar://problem/64549429>
+
+        Reviewed by Alex Christensen.
+
+        These changes are for forwarding ITP's knowledge of user interaction
+        for specific quirks domains to the WebKit::WebProcessPool where it in
+        turn can be distributed to all existing and new Web Content processes.
+
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::needsUserInteractionQuirk const):
+        (WebKit::WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToBlockCookiesForHandler):
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
+        * Shared/WebProcessDataStoreParameters.h:
+        (WebKit::WebProcessDataStoreParameters::encode const):
+        (WebKit::WebProcessDataStoreParameters::decode):
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::setDomainsWithUserInteraction):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::webProcessDataStoreParameters):
+        (WebKit::WebProcessPool::setDomainsWithUserInteraction):
+        * UIProcess/WebProcessPool.h:
+        * WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp:
+        (WebKit::WebResourceLoadObserver::hasHadUserInteraction const):
+        * WebProcess/WebCoreSupport/WebResourceLoadObserver.h:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::setWebsiteDataStoreParameters):
+        (WebKit::WebProcess::setDomainsWithUserInteraction):
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+
 2020-06-22  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [macOS] WebPageProxy::setPromisedDataForImage should sanitize its filename
index dfebcb1..e3f434d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1281,6 +1281,18 @@ void WebResourceLoadStatisticsStore::setCacheMaxAgeCap(Seconds seconds, Completi
     completionHandler();
 }
 
+bool WebResourceLoadStatisticsStore::needsUserInteractionQuirk(const RegistrableDomain& domain) const
+{
+    static NeverDestroyed<HashSet<RegistrableDomain>> quirks = [] {
+        HashSet<RegistrableDomain> set;
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("kinja.com"_s));
+        set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("youtube.com"_s));
+        return set;
+    }();
+
+    return quirks.get().contains(domain);
+}
+
 void WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToBlockCookiesForHandler(const RegistrableDomainsToBlockCookiesFor& domainsToBlock, CompletionHandler<void()>&& completionHandler)
 {
     ASSERT(RunLoop::isMain());
@@ -1291,6 +1303,17 @@ void WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToBlockCookiesFor
             storageSession->setPrevalentDomainsToBlockButKeepCookiesFor(domainsToBlock.domainsToBlockButKeepCookiesFor);
             storageSession->setDomainsWithUserInteractionAsFirstParty(domainsToBlock.domainsWithUserInteractionAsFirstParty);
         }
+
+        HashSet<RegistrableDomain> domainsWithUserInteractionQuirk;
+        for (auto& domain : domainsToBlock.domainsWithUserInteractionAsFirstParty) {
+            if (needsUserInteractionQuirk(domain))
+                domainsWithUserInteractionQuirk.add(domain);
+        }
+
+        if (m_domainsWithUserInteractionQuirk != domainsWithUserInteractionQuirk) {
+            m_domainsWithUserInteractionQuirk = domainsWithUserInteractionQuirk;
+            m_networkSession->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::SetDomainsWithUserInteraction(domainsWithUserInteractionQuirk), 0);
+        }
     }
 
     completionHandler();
index 5b51d11..f3c3f75 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -273,6 +273,7 @@ struct ThirdPartyData {
     void logTestingEvent(const String&);
     void callGrantStorageAccessHandler(const SubFrameDomain&, const TopFrameDomain&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, StorageAccessScope, CompletionHandler<void(StorageAccessWasGranted)>&&);
     void removeAllStorageAccess(CompletionHandler<void()>&&);
+    bool needsUserInteractionQuirk(const RegistrableDomain&) const;
     void callUpdatePrevalentDomainsToBlockCookiesForHandler(const RegistrableDomainsToBlockCookiesFor&, CompletionHandler<void()>&&);
     void callHasStorageAccessForFrameHandler(const SubFrameDomain&, const TopFrameDomain&, WebCore::FrameIdentifier, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&);
 
@@ -333,6 +334,8 @@ private:
     WebCore::ResourceLoadStatistics::IsEphemeral m_isEphemeral { WebCore::ResourceLoadStatistics::IsEphemeral::No };
     HashSet<RegistrableDomain> m_domainsWithEphemeralUserInteraction;
 
+    HashSet<RegistrableDomain> m_domainsWithUserInteractionQuirk;
+
     bool m_hasScheduledProcessStats { false };
 
     bool m_firstNetworkProcessCreated { false };
index 30db4c9..e626342 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,6 +48,7 @@ struct WebProcessDataStoreParameters {
     HashMap<unsigned, WallTime> plugInAutoStartOriginHashes;
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     WebCore::ThirdPartyCookieBlockingMode thirdPartyCookieBlockingMode { WebCore::ThirdPartyCookieBlockingMode::All };
+    HashSet<WebCore::RegistrableDomain> domainsWithUserInteraction;
 #endif
     bool resourceLoadStatisticsEnabled { false };
 
@@ -73,6 +74,7 @@ void WebProcessDataStoreParameters::encode(Encoder& encoder) const
     encoder << plugInAutoStartOriginHashes;
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     encoder << thirdPartyCookieBlockingMode;
+    encoder << domainsWithUserInteraction;
 #endif
     encoder << resourceLoadStatisticsEnabled;
 }
@@ -144,6 +146,11 @@ Optional<WebProcessDataStoreParameters> WebProcessDataStoreParameters::decode(De
     decoder >> thirdPartyCookieBlockingMode;
     if (!thirdPartyCookieBlockingMode)
         return WTF::nullopt;
+
+    Optional<HashSet<WebCore::RegistrableDomain>> domainsWithUserInteraction;
+    decoder >> domainsWithUserInteraction;
+    if (!domainsWithUserInteraction)
+        return WTF::nullopt;
 #endif
 
     bool resourceLoadStatisticsEnabled = false;
@@ -166,6 +173,7 @@ Optional<WebProcessDataStoreParameters> WebProcessDataStoreParameters::decode(De
         WTFMove(*plugInAutoStartOriginHashes),
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
         *thirdPartyCookieBlockingMode,
+        WTFMove(*domainsWithUserInteraction),
 #endif
         resourceLoadStatisticsEnabled
     };
index 9c06b00..60e1362 100644 (file)
@@ -1199,6 +1199,11 @@ void NetworkProcessProxy::setToSameSiteStrictCookiesForTesting(PAL::SessionID se
 
     sendWithAsyncReply(Messages::NetworkProcess::SetToSameSiteStrictCookiesForTesting(sessionID, domain), WTFMove(completionHandler));
 }
+
+void NetworkProcessProxy::setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&& domains)
+{
+    processPool().setDomainsWithUserInteraction(WTFMove(domains));
+}
 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
 
 void NetworkProcessProxy::setAdClickAttributionDebugMode(bool debugMode)
index 303889c..d6ecb56 100644 (file)
@@ -182,6 +182,7 @@ public:
     void setShouldEnbleSameSiteStrictEnforcementForTesting(PAL::SessionID, WebCore::SameSiteStrictEnforcementEnabled, CompletionHandler<void()>&&);
     void setFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionID, WebCore::FirstPartyWebsiteDataRemovalMode, CompletionHandler<void()>&&);
     void setToSameSiteStrictCookiesForTesting(PAL::SessionID, const RegistrableDomain&, CompletionHandler<void()>&&);
+    void setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&&);
 #endif
 
     void setAdClickAttributionDebugMode(bool);
index 8379d9f..15f9a80 100644 (file)
@@ -50,6 +50,7 @@ messages -> NetworkProcessProxy LegacyReceiver NotRefCounted {
     RequestStorageAccessConfirm(WebKit::WebPageProxyIdentifier pageID, WebCore::FrameIdentifier frameID, WebCore::RegistrableDomain subFrameDomain, WebCore::RegistrableDomain topFrameDomain) -> (bool userDidGrantAccess) Async
     DeleteWebsiteDataInUIProcessForRegistrableDomains(PAL::SessionID sessionID, OptionSet<WebKit::WebsiteDataType> dataTypes, OptionSet<WebKit::WebsiteDataFetchOption> fetchOptions, Vector<WebCore::RegistrableDomain> domains) -> (HashSet<WebCore::RegistrableDomain> domainsWithMatchingDataRecords) Async
     DidCommitCrossSiteLoadWithDataTransferFromPrevalentResource(WebKit::WebPageProxyIdentifier pageID)
+    SetDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain> domains)
 #endif
 #if ENABLE(CONTENT_EXTENSIONS)
     ContentExtensionRules(WebKit::UserContentControllerIdentifier identifier)
index dbfd994..e292e0e 100644 (file)
@@ -997,6 +997,7 @@ WebProcessDataStoreParameters WebProcessPool::webProcessDataStoreParameters(WebP
         WTFMove(plugInAutoStartOriginHashes),
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
         websiteDataStore.thirdPartyCookieBlockingMode(),
+        m_domainsWithUserInteraction,
 #endif
         websiteDataStore.resourceLoadStatisticsEnabled()
     };
@@ -2350,6 +2351,12 @@ void WebProcessPool::didCommitCrossSiteLoadWithDataTransfer(PAL::SessionID sessi
     m_networkProcess->didCommitCrossSiteLoadWithDataTransfer(sessionID, fromDomain, toDomain, navigationDataTransfer, webPageProxyID, webPageID);
 }
 
+void WebProcessPool::setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&& domains)
+{
+    sendToAllProcesses(Messages::WebProcess::SetDomainsWithUserInteraction(domains));
+    m_domainsWithUserInteraction = WTFMove(domains);
+}
+
 void WebProcessPool::seedResourceLoadStatisticsForTesting(const RegistrableDomain& firstPartyDomain, const RegistrableDomain& thirdPartyDomain, bool shouldScheduleNotification, CompletionHandler<void()>&& completionHandler)
 {
     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
index 5c60a32..bf2d8c7 100644 (file)
@@ -504,6 +504,7 @@ public:
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     void didCommitCrossSiteLoadWithDataTransfer(PAL::SessionID, const WebCore::RegistrableDomain& fromDomain, const WebCore::RegistrableDomain& toDomain, OptionSet<WebCore::CrossSiteNavigationDataTransfer::Flag>, WebPageProxyIdentifier, WebCore::PageIdentifier);
+    void setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&&);
     void seedResourceLoadStatisticsForTesting(const WebCore::RegistrableDomain& firstPartyDomain, const WebCore::RegistrableDomain& thirdPartyDomain, bool shouldScheduleNotification, CompletionHandler<void()>&&);
 #endif
 
@@ -821,6 +822,10 @@ private:
     bool m_isDelayedWebProcessLaunchDisabled { false };
 #endif
     bool m_useSeparateServiceWorkerProcess { false };
+
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    HashSet<WebCore::RegistrableDomain> m_domainsWithUserInteraction;
+#endif
 };
 
 template<typename T>
index 5b3b683..7247a4e 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 2019 Apple Inc. All rights reserved.
+* Copyright (C) 2019-2020 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -141,6 +141,11 @@ void WebResourceLoadObserver::clearState()
     m_lastReportedUserInteractionMap.clear();
 }
 
+bool WebResourceLoadObserver::hasHadUserInteraction(const RegistrableDomain& domain) const
+{
+    return m_domainsWithUserInteraction.contains(domain);
+}
+
 void WebResourceLoadObserver::logFontLoad(const Document& document, const String& familyName, bool loadStatus)
 {
     if (isEphemeral())
index e62aa2a..186faa1 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 2019 Apple Inc. All rights reserved.
+* Copyright (C) 2019-2020 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -62,6 +62,8 @@ public:
     
     bool hasStatistics() const final { return !m_resourceStatisticsMap.isEmpty(); }
 
+    void setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&& domains) final { m_domainsWithUserInteraction = WTFMove(domains); }
+    bool hasHadUserInteraction(const WebCore::RegistrableDomain&) const final;
 private:
     WebCore::ResourceLoadStatistics& ensureResourceStatisticsForRegistrableDomain(const WebCore::RegistrableDomain&);
     void scheduleNotificationIfNeeded();
@@ -78,6 +80,7 @@ private:
 
     WebCore::Timer m_notificationTimer;
 
+    HashSet<WebCore::RegistrableDomain> m_domainsWithUserInteraction;
 #if !RELEASE_LOG_DISABLED
     uint64_t m_loggingCounter { 0 };
     static bool shouldLogUserInteraction;
index 692e231..e9136c4 100644 (file)
@@ -508,8 +508,12 @@ void WebProcess::setWebsiteDataStoreParameters(WebProcessDataStoreParameters&& p
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     m_thirdPartyCookieBlockingMode = parameters.thirdPartyCookieBlockingMode;
-    if (parameters.resourceLoadStatisticsEnabled && !ResourceLoadObserver::sharedIfExists())
-        ResourceLoadObserver::setShared(*new WebResourceLoadObserver(parameters.sessionID.isEphemeral() ? WebCore::ResourceLoadStatistics::IsEphemeral::Yes : WebCore::ResourceLoadStatistics::IsEphemeral::No));
+    if (parameters.resourceLoadStatisticsEnabled) {
+        if (!ResourceLoadObserver::sharedIfExists())
+            ResourceLoadObserver::setShared(*new WebResourceLoadObserver(parameters.sessionID.isEphemeral() ? WebCore::ResourceLoadStatistics::IsEphemeral::Yes : WebCore::ResourceLoadStatistics::IsEphemeral::No));
+        ResourceLoadObserver::shared().setDomainsWithUserInteraction(WTFMove(parameters.domainsWithUserInteraction));
+    }
+    
 #endif
 
     resetPlugInAutoStartOriginHashes(WTFMove(parameters.plugInAutoStartOriginHashes));
@@ -1895,6 +1899,11 @@ void WebProcess::setThirdPartyCookieBlockingMode(ThirdPartyCookieBlockingMode th
     m_thirdPartyCookieBlockingMode = thirdPartyCookieBlockingMode;
     completionHandler();
 }
+
+void WebProcess::setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&& domains)
+{
+    ResourceLoadObserver::shared().setDomainsWithUserInteraction(WTFMove(domains));
+}
 #endif
 
 #if ENABLE(GPU_PROCESS)
index 14c0228..a953c8a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -461,6 +461,7 @@ private:
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     void setThirdPartyCookieBlockingMode(WebCore::ThirdPartyCookieBlockingMode, CompletionHandler<void()>&&);
+    void setDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain>&&);
 #endif
 
     void platformInitializeProcess(const AuxiliaryProcessInitializationParameters&);
index cfa3e4d..f5bcc06 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+# Copyright (C) 2010-2020 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -158,6 +158,7 @@ messages -> WebProcess LegacyReceiver NotRefCounted {
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     SeedResourceLoadStatisticsForTesting(WebCore::RegistrableDomain firstPartyDomain, WebCore::RegistrableDomain thirdPartyDomain, bool shouldScheduleNotification) -> () Async
     SetThirdPartyCookieBlockingMode(enum:uint8_t WebCore::ThirdPartyCookieBlockingMode blockingMode) -> () Async
+    SetDomainsWithUserInteraction(HashSet<WebCore::RegistrableDomain> domains)
 #endif
 
 #if PLATFORM(IOS)