Title: [277376] trunk
Revision
277376
Author
[email protected]
Date
2021-05-12 10:52:38 -0700 (Wed, 12 May 2021)

Log Message

Queue notification permission requests for the same origin on WebKit side
https://bugs.webkit.org/show_bug.cgi?id=225701
<rdar://76804977>

Reviewed by Geoffrey Garen.

Source/WebCore:

Remove some dead code.

* Modules/notifications/NotificationClient.h:

Source/WebKit:

If there are parallel notification permission requests for the same origin, we now queue them on WebKit
side and only ask the client once for the origin. Once we've received the permission from the client,
we respond to all JS requests at this point.

This patch also removes some dead code to facilitate refactoring the code to support this.
In a follow-up I am planning to use sendWithAsyncReply() and refactor this code further.

* WebProcess/Notifications/NotificationPermissionRequestManager.cpp:
(WebKit::NotificationPermissionRequestManager::startRequest):
(WebKit::NotificationPermissionRequestManager::permissionLevel):
(WebKit::NotificationPermissionRequestManager::didReceiveNotificationPermissionDecision):
* WebProcess/Notifications/NotificationPermissionRequestManager.h:
* WebProcess/Notifications/WebNotificationManager.cpp:
(WebKit::WebNotificationManager::policyForOrigin const):
* WebProcess/Notifications/WebNotificationManager.h:
* WebProcess/WebCoreSupport/WebNotificationClient.cpp:
(WebKit::WebNotificationClient::requestPermission):
(WebKit::WebNotificationClient::checkPermission):
* WebProcess/WebCoreSupport/WebNotificationClient.h:

Source/WebKitLegacy/mac:

Remove some dead code.

* WebCoreSupport/WebNotificationClient.h:
* WebCoreSupport/WebNotificationClient.mm:

Source/WebKitLegacy/win:

Remove some dead code.

* WebCoreSupport/WebDesktopNotificationsDelegate.cpp:
* WebCoreSupport/WebDesktopNotificationsDelegate.h:

Tools:

Add API test coverage.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm: Added.
(-[NotificationPermissionMessageHandler userContentController:didReceiveScriptMessage:]):
(-[NotificationPermissionUIDelegate initWithHandler:]):
(-[NotificationPermissionUIDelegate _webView:requestNotificationPermissionForSecurityOrigin:decisionHandler:]):
(TestWebKitAPI::runRequestPermissionTest):
(TestWebKitAPI::TEST):
(TestWebKitAPI::runParallelPermissionRequestsTest):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (277375 => 277376)


--- trunk/Source/WebCore/ChangeLog	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebCore/ChangeLog	2021-05-12 17:52:38 UTC (rev 277376)
@@ -1,3 +1,15 @@
+2021-05-12  Chris Dumez  <[email protected]>
+
+        Queue notification permission requests for the same origin on WebKit side
+        https://bugs.webkit.org/show_bug.cgi?id=225701
+        <rdar://76804977>
+
+        Reviewed by Geoffrey Garen.
+
+        Remove some dead code.
+
+        * Modules/notifications/NotificationClient.h:
+
 2021-05-12  Ryosuke Niwa  <[email protected]>
 
         REGRESSION: Release assert in SlotAssignment::assignedNodesForSlot via ComposedTreeIterator::traverseNextInShadowTree

Modified: trunk/Source/WebCore/Modules/notifications/NotificationClient.h (277375 => 277376)


--- trunk/Source/WebCore/Modules/notifications/NotificationClient.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebCore/Modules/notifications/NotificationClient.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -68,11 +68,6 @@
     // made a decision.
     virtual void requestPermission(ScriptExecutionContext*, RefPtr<NotificationPermissionCallback>&&) = 0;
 
-    virtual bool hasPendingPermissionRequests(ScriptExecutionContext*) const = 0;
-
-    // Cancel all outstanding requests for the ScriptExecutionContext
-    virtual void cancelRequestsForPermission(ScriptExecutionContext*) = 0;
-
     // Checks the current level of permission.
     virtual Permission checkPermission(ScriptExecutionContext*) = 0;
 

Modified: trunk/Source/WebKit/ChangeLog (277375 => 277376)


--- trunk/Source/WebKit/ChangeLog	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/ChangeLog	2021-05-12 17:52:38 UTC (rev 277376)
@@ -1,3 +1,31 @@
+2021-05-12  Chris Dumez  <[email protected]>
+
+        Queue notification permission requests for the same origin on WebKit side
+        https://bugs.webkit.org/show_bug.cgi?id=225701
+        <rdar://76804977>
+
+        Reviewed by Geoffrey Garen.
+
+        If there are parallel notification permission requests for the same origin, we now queue them on WebKit
+        side and only ask the client once for the origin. Once we've received the permission from the client,
+        we respond to all JS requests at this point.
+
+        This patch also removes some dead code to facilitate refactoring the code to support this.
+        In a follow-up I am planning to use sendWithAsyncReply() and refactor this code further.
+
+        * WebProcess/Notifications/NotificationPermissionRequestManager.cpp:
+        (WebKit::NotificationPermissionRequestManager::startRequest):
+        (WebKit::NotificationPermissionRequestManager::permissionLevel):
+        (WebKit::NotificationPermissionRequestManager::didReceiveNotificationPermissionDecision):
+        * WebProcess/Notifications/NotificationPermissionRequestManager.h:
+        * WebProcess/Notifications/WebNotificationManager.cpp:
+        (WebKit::WebNotificationManager::policyForOrigin const):
+        * WebProcess/Notifications/WebNotificationManager.h:
+        * WebProcess/WebCoreSupport/WebNotificationClient.cpp:
+        (WebKit::WebNotificationClient::requestPermission):
+        (WebKit::WebNotificationClient::checkPermission):
+        * WebProcess/WebCoreSupport/WebNotificationClient.h:
+
 2021-05-12  Julian Gonzalez  <[email protected]>
 
         Crash in WebPageProxy::endColorPicker()

Modified: trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp	2021-05-12 17:52:38 UTC (rev 277376)
@@ -68,9 +68,9 @@
 #endif
 
 #if ENABLE(NOTIFICATIONS)
-void NotificationPermissionRequestManager::startRequest(SecurityOrigin* origin, RefPtr<NotificationPermissionCallback>&& callback)
+void NotificationPermissionRequestManager::startRequest(const SecurityOriginData& securityOrigin, RefPtr<NotificationPermissionCallback>&& callback)
 {
-    auto permission = permissionLevel(origin);
+    auto permission = permissionLevel(securityOrigin);
     if (permission != NotificationClient::Permission::Default) {
         if (callback)
             callback->handleEvent(permission);
@@ -77,45 +77,26 @@
         return;
     }
 
+    auto addResult = m_requestsPerOrigin.add(securityOrigin, Vector<RefPtr<WebCore::NotificationPermissionCallback>> { });
+    addResult.iterator->value.append(WTFMove(callback));
+    if (!addResult.isNewEntry)
+        return;
+
     uint64_t requestID = generateRequestID();
-    m_originToIDMap.set(origin, requestID);
-    m_idToOriginMap.set(requestID, origin);
-    m_idToCallbackMap.set(requestID, WTFMove(callback));
-    m_page->send(Messages::WebPageProxy::RequestNotificationPermission(requestID, origin->toString()));
-}
-#endif
+    m_idToOriginMap.set(requestID, securityOrigin);
 
-void NotificationPermissionRequestManager::cancelRequest(SecurityOrigin* origin)
-{
-#if ENABLE(NOTIFICATIONS)
-    uint64_t id = m_originToIDMap.take(origin);
-    if (!id)
-        return;
-    
-    m_idToOriginMap.remove(id);
-    m_idToCallbackMap.remove(id);
-#else
-    UNUSED_PARAM(origin);
-#endif
+    // FIXME: This should use sendWithAsyncReply().
+    m_page->send(Messages::WebPageProxy::RequestNotificationPermission(requestID, securityOrigin.toString()));
 }
-
-bool NotificationPermissionRequestManager::hasPendingPermissionRequests(SecurityOrigin* origin) const
-{
-#if ENABLE(NOTIFICATIONS)
-    return m_originToIDMap.contains(origin);
-#else
-    UNUSED_PARAM(origin);
-    return false;
 #endif
-}
 
-NotificationClient::Permission NotificationPermissionRequestManager::permissionLevel(SecurityOrigin* securityOrigin)
+NotificationClient::Permission NotificationPermissionRequestManager::permissionLevel(const SecurityOriginData& securityOrigin)
 {
 #if ENABLE(NOTIFICATIONS)
     if (!m_page->corePage()->settings().notificationsEnabled())
         return NotificationClient::Permission::Denied;
     
-    return WebProcess::singleton().supplement<WebNotificationManager>()->policyForOrigin(securityOrigin);
+    return WebProcess::singleton().supplement<WebNotificationManager>()->policyForOrigin(securityOrigin.toString());
 #else
     UNUSED_PARAM(securityOrigin);
     return NotificationClient::Permission::Denied;
@@ -145,19 +126,18 @@
     if (!isRequestIDValid(requestID))
         return;
 
-    RefPtr<WebCore::SecurityOrigin> origin = m_idToOriginMap.take(requestID);
-    if (!origin)
+    auto origin = m_idToOriginMap.take(requestID);
+    if (origin.isEmpty())
         return;
 
-    m_originToIDMap.remove(origin);
+    WebProcess::singleton().supplement<WebNotificationManager>()->didUpdateNotificationDecision(origin.toString(), allowed);
 
-    WebProcess::singleton().supplement<WebNotificationManager>()->didUpdateNotificationDecision(origin->toString(), allowed);
-
-    RefPtr<NotificationPermissionCallback> callback = m_idToCallbackMap.take(requestID);
-    if (!callback)
-        return;
-    
-    callback->handleEvent(allowed ? NotificationClient::Permission::Granted : NotificationClient::Permission::Denied);
+    auto callbacks = m_requestsPerOrigin.take(origin);
+    for (auto& callback : callbacks) {
+        if (!callback)
+            return;
+        callback->handleEvent(allowed ? NotificationClient::Permission::Granted : NotificationClient::Permission::Denied);
+    }
 #else
     UNUSED_PARAM(requestID);
     UNUSED_PARAM(allowed);

Modified: trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.h (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -28,7 +28,7 @@
 
 #include <WebCore/NotificationClient.h>
 #include <WebCore/NotificationPermissionCallback.h>
-#include <WebCore/SecurityOriginHash.h>
+#include <WebCore/SecurityOriginData.h>
 #include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -35,8 +35,7 @@
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
-class Notification;    
-class SecurityOrigin;
+class Notification;
 }
 
 namespace WebKit {
@@ -49,12 +48,10 @@
     static Ref<NotificationPermissionRequestManager> create(WebPage*);
 
 #if ENABLE(NOTIFICATIONS)
-    void startRequest(WebCore::SecurityOrigin*, RefPtr<WebCore::NotificationPermissionCallback>&&);
+    void startRequest(const WebCore::SecurityOriginData&, RefPtr<WebCore::NotificationPermissionCallback>&&);
 #endif
-    void cancelRequest(WebCore::SecurityOrigin*);
-    bool hasPendingPermissionRequests(WebCore::SecurityOrigin*) const;
     
-    WebCore::NotificationClient::Permission permissionLevel(WebCore::SecurityOrigin*);
+    WebCore::NotificationClient::Permission permissionLevel(const WebCore::SecurityOriginData&);
 
     // For testing purposes only.
     void setPermissionLevelForTesting(const String& originString, bool allowed);
@@ -66,12 +63,8 @@
     NotificationPermissionRequestManager(WebPage*);
 
 #if ENABLE(NOTIFICATIONS)
-    HashMap<uint64_t, RefPtr<WebCore::NotificationPermissionCallback>> m_idToCallbackMap;
-#endif
-    HashMap<RefPtr<WebCore::SecurityOrigin>, uint64_t> m_originToIDMap;
-    HashMap<uint64_t, RefPtr<WebCore::SecurityOrigin>> m_idToOriginMap;
-
-#if ENABLE(NOTIFICATIONS)
+    HashMap<WebCore::SecurityOriginData, Vector<RefPtr<WebCore::NotificationPermissionCallback>>> m_requestsPerOrigin;
+    HashMap<uint64_t, WebCore::SecurityOriginData> m_idToOriginMap;
     WebPage* m_page;
 #endif
 };

Modified: trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp	2021-05-12 17:52:38 UTC (rev 277376)
@@ -101,23 +101,17 @@
 #endif
 }
 
-NotificationClient::Permission WebNotificationManager::policyForOrigin(WebCore::SecurityOrigin* origin) const
+NotificationClient::Permission WebNotificationManager::policyForOrigin(const String& originString) const
 {
 #if ENABLE(NOTIFICATIONS)
-    if (!origin)
+    if (!originString)
         return NotificationClient::Permission::Default;
 
-    ASSERT(!origin->isUnique());
-
-    auto originString = origin->toRawString();
-    if (!decltype(m_permissionsMap)::isValidKey(originString))
-        return NotificationClient::Permission::Default;
-
     auto it = m_permissionsMap.find(originString);
     if (it != m_permissionsMap.end())
         return it->value ? NotificationClient::Permission::Granted : NotificationClient::Permission::Denied;
 #else
-    UNUSED_PARAM(origin);
+    UNUSED_PARAM(originString);
 #endif
     
     return NotificationClient::Permission::Default;

Modified: trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.h (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -62,7 +62,7 @@
     void didUpdateNotificationDecision(const String& originString, bool allowed);
 
     // Looks in local cache for permission. If not found, returns DefaultDenied.
-    WebCore::NotificationClient::Permission policyForOrigin(WebCore::SecurityOrigin*) const;
+    WebCore::NotificationClient::Permission policyForOrigin(const String& originString) const;
 
     void removeAllPermissionsForTesting();
     uint64_t notificationIDForTesting(WebCore::Notification*);

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.cpp (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.cpp	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.cpp	2021-05-12 17:52:38 UTC (rev 277376)
@@ -73,24 +73,20 @@
 
 void WebNotificationClient::requestPermission(ScriptExecutionContext* context, RefPtr<NotificationPermissionCallback>&& callback)
 {
-    m_page->notificationPermissionRequestManager()->startRequest(context->securityOrigin(), WTFMove(callback));
+    auto* securityOrigin = context->securityOrigin();
+    if (!securityOrigin) {
+        if (callback)
+            callback->handleEvent(NotificationClient::Permission::Denied);
+        return;
+    }
+    m_page->notificationPermissionRequestManager()->startRequest(securityOrigin->data(), WTFMove(callback));
 }
 
-bool WebNotificationClient::hasPendingPermissionRequests(ScriptExecutionContext* context) const
-{
-    return m_page->notificationPermissionRequestManager()->hasPendingPermissionRequests(context->securityOrigin());
-}
-
-void WebNotificationClient::cancelRequestsForPermission(ScriptExecutionContext* context)
-{
-    m_page->notificationPermissionRequestManager()->cancelRequest(context->securityOrigin());
-}
-
 NotificationClient::Permission WebNotificationClient::checkPermission(ScriptExecutionContext* context)
 {
-    if (!context || !context->isDocument())
+    if (!context || !context->isDocument() || !context->securityOrigin())
         return NotificationClient::Permission::Denied;
-    return m_page->notificationPermissionRequestManager()->permissionLevel(context->securityOrigin());
+    return m_page->notificationPermissionRequestManager()->permissionLevel(context->securityOrigin()->data());
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.h (277375 => 277376)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebNotificationClient.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -52,8 +52,6 @@
     void notificationObjectDestroyed(WebCore::Notification*) override;
     void notificationControllerDestroyed() override;
     void requestPermission(WebCore::ScriptExecutionContext*, RefPtr<WebCore::NotificationPermissionCallback>&&) override;
-    void cancelRequestsForPermission(WebCore::ScriptExecutionContext*) override;
-    bool hasPendingPermissionRequests(WebCore::ScriptExecutionContext*) const override;
     WebCore::NotificationClient::Permission checkPermission(WebCore::ScriptExecutionContext*) override;
     
     WebPage* m_page;

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (277375 => 277376)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2021-05-12 17:52:38 UTC (rev 277376)
@@ -1,3 +1,16 @@
+2021-05-12  Chris Dumez  <[email protected]>
+
+        Queue notification permission requests for the same origin on WebKit side
+        https://bugs.webkit.org/show_bug.cgi?id=225701
+        <rdar://76804977>
+
+        Reviewed by Geoffrey Garen.
+
+        Remove some dead code.
+
+        * WebCoreSupport/WebNotificationClient.h:
+        * WebCoreSupport/WebNotificationClient.mm:
+
 2021-05-10  Wenson Hsieh  <[email protected]>
 
         Make WebCore::HitTestRequest::RequestType an enum class

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.h (277375 => 277376)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -51,8 +51,6 @@
     void notificationObjectDestroyed(WebCore::Notification*) override;
     void notificationControllerDestroyed() override;
     void requestPermission(WebCore::ScriptExecutionContext*, RefPtr<WebCore::NotificationPermissionCallback>&&) override;
-    void cancelRequestsForPermission(WebCore::ScriptExecutionContext*) override { }
-    bool hasPendingPermissionRequests(WebCore::ScriptExecutionContext*) const override;
     WebCore::NotificationClient::Permission checkPermission(WebCore::ScriptExecutionContext*) override;
 
     void requestPermission(WebCore::ScriptExecutionContext*, WebNotificationPolicyListener *);

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.mm (277375 => 277376)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.mm	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebNotificationClient.mm	2021-05-12 17:52:38 UTC (rev 277376)
@@ -135,13 +135,6 @@
     CallUIDelegate(m_webView, selector, webOrigin.get(), listener);
 }
 
-bool WebNotificationClient::hasPendingPermissionRequests(ScriptExecutionContext*) const
-{
-    // We know permission was requested but we don't know if the client responded. In this case, we play it
-    // safe and presume there is one pending so that ActiveDOMObjects don't get suspended.
-    return m_everRequestedPermission;
-}
-
 void WebNotificationClient::requestPermission(ScriptExecutionContext* context, RefPtr<NotificationPermissionCallback>&& callback)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS

Modified: trunk/Source/WebKitLegacy/win/ChangeLog (277375 => 277376)


--- trunk/Source/WebKitLegacy/win/ChangeLog	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/win/ChangeLog	2021-05-12 17:52:38 UTC (rev 277376)
@@ -1,3 +1,16 @@
+2021-05-12  Chris Dumez  <[email protected]>
+
+        Queue notification permission requests for the same origin on WebKit side
+        https://bugs.webkit.org/show_bug.cgi?id=225701
+        <rdar://76804977>
+
+        Reviewed by Geoffrey Garen.
+
+        Remove some dead code.
+
+        * WebCoreSupport/WebDesktopNotificationsDelegate.cpp:
+        * WebCoreSupport/WebDesktopNotificationsDelegate.h:
+
 2021-05-11  Chris Dumez  <[email protected]>
 
         Port WTF::FileSystem::listDirectory to std::filesystem

Modified: trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.cpp (277375 => 277376)


--- trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.cpp	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.cpp	2021-05-12 17:52:38 UTC (rev 277376)
@@ -181,17 +181,6 @@
 {
 }
 
-void WebDesktopNotificationsDelegate::cancelRequestsForPermission(ScriptExecutionContext* context)
-{
-}
-
-bool hasPendingPermissionRequests(ScriptExecutionContext*) const
-{
-    // We can safely return false here because our implementation for requestPermission() never calls
-    // the completion callback.
-    return false;
-}
-
 NotificationClient::Permission WebDesktopNotificationsDelegate::checkPermission(const URL& url)
 {
     int out = 0;

Modified: trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.h (277375 => 277376)


--- trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.h	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Source/WebKitLegacy/win/WebCoreSupport/WebDesktopNotificationsDelegate.h	2021-05-12 17:52:38 UTC (rev 277376)
@@ -54,8 +54,6 @@
     virtual void notificationObjectDestroyed(WebCore::Notification* object);
     virtual void notificationControllerDestroyed();
     virtual void requestPermission(WebCore::SecurityOrigin*, RefPtr<WebCore::NotificationPermissionCallback>&&);
-    bool hasPendingPermissionRequests(WebCore::ScriptExecutionContext*) const override;
-    virtual void cancelRequestsForPermission(WebCore::ScriptExecutionContext*);
     virtual WebCore::NotificationClient::Permission checkPermission(const URL&);
 
 private:

Modified: trunk/Tools/ChangeLog (277375 => 277376)


--- trunk/Tools/ChangeLog	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Tools/ChangeLog	2021-05-12 17:52:38 UTC (rev 277376)
@@ -1,3 +1,22 @@
+2021-05-12  Chris Dumez  <[email protected]>
+
+        Queue notification permission requests for the same origin on WebKit side
+        https://bugs.webkit.org/show_bug.cgi?id=225701
+        <rdar://76804977>
+
+        Reviewed by Geoffrey Garen.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm: Added.
+        (-[NotificationPermissionMessageHandler userContentController:didReceiveScriptMessage:]):
+        (-[NotificationPermissionUIDelegate initWithHandler:]):
+        (-[NotificationPermissionUIDelegate _webView:requestNotificationPermissionForSecurityOrigin:decisionHandler:]):
+        (TestWebKitAPI::runRequestPermissionTest):
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::runParallelPermissionRequestsTest):
+
 2021-05-11  Chris Dumez  <[email protected]>
 
         Port WTF::FileSystem::listDirectory to std::filesystem

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (277375 => 277376)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-05-12 17:46:26 UTC (rev 277375)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-05-12 17:52:38 UTC (rev 277376)
@@ -272,6 +272,7 @@
 		46918EFC2237283C00468DFE /* DeviceOrientation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46918EFB2237283500468DFE /* DeviceOrientation.mm */; };
 		46A44A5425A7830300F61E16 /* webaudio-createMediaElementSource.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */; };
 		46A46A1A2575645600A1B118 /* SessionStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A46A192575645600A1B118 /* SessionStorage.mm */; };
+		46A80F26264C29D400EEF20D /* NotificationAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A80F25264C29D400EEF20D /* NotificationAPI.mm */; };
 		46A911592108E6780078D40D /* CustomUserAgent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A911582108E66B0078D40D /* CustomUserAgent.mm */; };
 		46BBEA1B25F9835700D4987A /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA6A1511AAC0B31002B2ED3 /* WorkQueue.cpp */; };
 		46C1EA9825758820005E409E /* alert.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 46C1EA9725758805005E409E /* alert.html */; };
@@ -2080,6 +2081,7 @@
 		46918EFB2237283500468DFE /* DeviceOrientation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeviceOrientation.mm; sourceTree = "<group>"; };
 		46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "webaudio-createMediaElementSource.html"; sourceTree = "<group>"; };
 		46A46A192575645600A1B118 /* SessionStorage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SessionStorage.mm; sourceTree = "<group>"; };
+		46A80F25264C29D400EEF20D /* NotificationAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NotificationAPI.mm; sourceTree = "<group>"; };
 		46A911582108E66B0078D40D /* CustomUserAgent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CustomUserAgent.mm; sourceTree = "<group>"; };
 		46C1EA9725758805005E409E /* alert.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = alert.html; sourceTree = "<group>"; };
 		46C3AEB223D0E50F001B0680 /* beforeunload.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = beforeunload.html; sourceTree = "<group>"; };
@@ -3481,6 +3483,7 @@
 				6351992722275C6A00890AD3 /* NavigationAction.mm */,
 				5C8BC798218CF3E900813886 /* NetworkProcess.mm */,
 				5CAE4637201937CD0051610F /* NetworkProcessCrashNonPersistentDataStore.mm */,
+				46A80F25264C29D400EEF20D /* NotificationAPI.mm */,
 				CDCFFEC022E268D500DF4223 /* NoPauseWhenSwitchingTabs.mm */,
 				CD2D0D19213465560018C784 /* NowPlaying.mm */,
 				2ECFF5541D9B12F800B55394 /* NowPlayingControlsTests.mm */,
@@ -5449,6 +5452,7 @@
 				CDB213BD24EF522800FDE301 /* FullscreenFocus.mm in Sources */,
 				CDE77D2525A6591C00D4115E /* FullscreenPointerLeave.mm in Sources */,
 				CDDC7C6925FFF6D000224278 /* FullscreenRemoveNodeBeforeEnter.mm in Sources */,
+				46A80F26264C29D400EEF20D /* NotificationAPI.mm in Sources */,
 				CDBFCC451A9FF45300A7B691 /* FullscreenZoomInitialFrame.mm in Sources */,
 				83DB79691EF63B3C00BFA5E5 /* Function.cpp in Sources */,
 				7CCE7EF81A411AE600447C4C /* Geolocation.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm (0 => 277376)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NotificationAPI.mm	2021-05-12 17:52:38 UTC (rev 277376)
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <wtf/Function.h>
+#import <wtf/RetainPtr.h>
+
+static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
+static unsigned clientPermissionRequestCount;
+static bool didReceiveMessage;
+
+@interface NotificationPermissionMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation NotificationPermissionMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    if ([message body])
+        [receivedMessages addObject:[message body]];
+    else
+        [receivedMessages addObject:@""];
+    didReceiveMessage = true;
+}
+@end
+
+@interface NotificationPermissionUIDelegate : NSObject <WKUIDelegatePrivate> {
+}
+- (instancetype)initWithHandler:(Function<bool()>&&)decisionHandler;
+@end
+
+@implementation NotificationPermissionUIDelegate {
+Function<bool()> _decisionHandler;
+}
+
+- (instancetype)initWithHandler:(Function<bool()>&&)decisionHandler
+{
+    self = [super init];
+    _decisionHandler = WTFMove(decisionHandler);
+    return self;
+}
+
+- (void)_webView:(WKWebView *)webView requestNotificationPermissionForSecurityOrigin:(WKSecurityOrigin *)securityOrigin decisionHandler:(void (^)(BOOL))decisionHandler
+{
+    decisionHandler(_decisionHandler());
+    ++clientPermissionRequestCount;
+}
+
+@end
+
+namespace TestWebKitAPI {
+
+enum class ShouldGrantPermission : bool { No, Yes };
+static void runRequestPermissionTest(ShouldGrantPermission shouldGrantPermission)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto messageHandler = adoptNS([[NotificationPermissionMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    auto uiDelegate = adoptNS([[NotificationPermissionUIDelegate alloc] initWithHandler:[shouldGrantPermission] { return shouldGrantPermission == ShouldGrantPermission::Yes; }]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    [webView synchronouslyLoadTestPageNamed:@"simple"];
+
+    didReceiveMessage = false;
+    clientPermissionRequestCount = 0;
+    [receivedMessages removeAllObjects];
+
+    [webView evaluateJavaScript:@"Notification.requestPermission((permission) => { webkit.messageHandlers.testHandler.postMessage(permission) });" completionHandler:nil];
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+
+    EXPECT_EQ(clientPermissionRequestCount, 1U);
+    if (shouldGrantPermission == ShouldGrantPermission::Yes)
+        EXPECT_WK_STREQ(@"granted", receivedMessages.get()[0]);
+    else
+        EXPECT_WK_STREQ(@"denied", receivedMessages.get()[0]);
+
+
+    didReceiveMessage = false;
+    [webView evaluateJavaScript:@"Notification.requestPermission((permission) => { webkit.messageHandlers.testHandler.postMessage(permission) });" completionHandler:nil];
+    TestWebKitAPI::Util::run(&didReceiveMessage);
+
+    EXPECT_EQ(clientPermissionRequestCount, 1U);
+    if (shouldGrantPermission == ShouldGrantPermission::Yes)
+        EXPECT_WK_STREQ(@"granted", receivedMessages.get()[1]);
+    else
+        EXPECT_WK_STREQ(@"denied", receivedMessages.get()[1]);
+}
+
+TEST(Notification, RequestPermissionDenied)
+{
+    runRequestPermissionTest(ShouldGrantPermission::No);
+}
+
+TEST(Notification, RequestPermissionGranted)
+{
+    runRequestPermissionTest(ShouldGrantPermission::Yes);
+}
+
+static void runParallelPermissionRequestsTest(ShouldGrantPermission shouldGrantPermission)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto messageHandler = adoptNS([[NotificationPermissionMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    auto uiDelegate = adoptNS([[NotificationPermissionUIDelegate alloc] initWithHandler:[shouldGrantPermission] { return shouldGrantPermission == ShouldGrantPermission::Yes; }]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    [webView synchronouslyLoadTestPageNamed:@"simple"];
+
+    clientPermissionRequestCount = 0;
+    [receivedMessages removeAllObjects];
+
+    constexpr unsigned permissionRequestsCount = 5;
+    for (unsigned i = 0; i < permissionRequestsCount; ++i)
+        [webView evaluateJavaScript:@"Notification.requestPermission((permission) => { webkit.messageHandlers.testHandler.postMessage(permission) });" completionHandler:nil];
+
+    while ([receivedMessages count] != permissionRequestsCount)
+        TestWebKitAPI::Util::spinRunLoop(10);
+
+    // We should have called out to the client only once.
+    EXPECT_EQ(clientPermissionRequestCount, 1U);
+
+    // All requests should have the same permission.
+    for (id message in receivedMessages.get()) {
+        if (shouldGrantPermission == ShouldGrantPermission::Yes)
+            EXPECT_WK_STREQ(@"granted", message);
+        else
+            EXPECT_WK_STREQ(@"denied", message);
+    }
+}
+
+TEST(Notification, ParallelPermissionRequestsDenied)
+{
+    runParallelPermissionRequestsTest(ShouldGrantPermission::No);
+}
+
+TEST(Notification, ParallelPermissionRequestsGranted)
+{
+    runParallelPermissionRequestsTest(ShouldGrantPermission::Yes);
+}
+
+} // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to