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