Title: [286764] trunk
Revision
286764
Author
beid...@apple.com
Date
2021-12-08 22:37:26 -0800 (Wed, 08 Dec 2021)

Log Message

Add ability to inject messages into webpushd
https://bugs.webkit.org/show_bug.cgi?id=233988

Reviewed by Alex Christensen.

Source/WebKit:

Covered by API tests.

This patch:
 - Adds WKWebsiteDataStore SPI to fetch pending push messages for the embedding application
 - Gives webpushd code to inject a push message for a given bundle identifier
 - Gives webpushtool the ability to send one of these fake messages
 - Gives webpushtool the ability to reconnect to the next daemon instance after the current connection is dropped
 - Tests the injection and fetching of push messages via TestWebKitAPI

* Configurations/webpushtool.xcconfig:
* WebKit.xcodeproj/project.pbxproj:
* Resources/webpushtool.entitlements:

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::getPendingPushMessages):
(WebKit::NetworkProcess::processPushMessage):
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:

* NetworkProcess/Notifications/NetworkNotificationManager.cpp:
(WebKit::NetworkNotificationManager::getPendingPushMessages):
(WebKit::ReplyCaller<Vector<WebPushMessage>::callReply):
* NetworkProcess/Notifications/NetworkNotificationManager.h:

* Shared/Cocoa/WebPushMessageCocoa.mm: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
(WebKit::WebPushMessage::fromDictionary):
(WebKit::WebPushMessage::toDictionary const):

* Shared/PushMessageForTesting.h: Copied from Source/WebKit/Shared/WebPushDaemonConstants.h.
(WebKit::WebPushD::PushMessageForTesting::encode const):
(WebKit::WebPushD::PushMessageForTesting::decode):

* Shared/WebPushDaemonConstants.h:
(WebKit::WebPushD::messageTypeSendsReply):

* Shared/WebPushMessage.h: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
(WebKit::WebPushMessage::encode const):
(WebKit::WebPushMessage::decode):

* UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
(-[WKWebsiteDataStore _getPendingPushMessages:]):
(-[WKWebsiteDataStore _processPushMessage:completionHandler:]):
(-[WKWebsiteDataStore _processPushMessage:registration:completionHandler:]): Deleted.
* UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:

* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::getPendingPushMessages):
(WebKit::NetworkProcessProxy::processPushMessage):
* UIProcess/Network/NetworkProcessProxy.h:

Tools:

* TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements:
* TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements:
* TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements:

* TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm:
(messageDictionary):

* TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm:
(TestWebKitAPI::createMessageDictionary):
(TestWebKitAPI::sendMessageToDaemon):
(TestWebKitAPI::sendMessageToDaemonWaitingForReply):
(TestWebKitAPI::sendConfigurationWithAuditToken):
(TestWebKitAPI::createAndConfigureConnectionToService):
(TestWebKitAPI::encodeString):
(TestWebKitAPI::TEST):
(TestWebKitAPI::function):
* TestWebKitAPI/cocoa/TestWKWebView.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (286763 => 286764)


--- trunk/Source/WebKit/ChangeLog	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/ChangeLog	2021-12-09 06:37:26 UTC (rev 286764)
@@ -1,3 +1,87 @@
+2021-12-08  Brady Eidson  <beid...@apple.com>
+
+        Add ability to inject messages into webpushd
+        https://bugs.webkit.org/show_bug.cgi?id=233988
+
+        Reviewed by Alex Christensen.
+
+        Covered by API tests.
+
+        This patch:
+         - Adds WKWebsiteDataStore SPI to fetch pending push messages for the embedding application
+         - Gives webpushd code to inject a push message for a given bundle identifier
+         - Gives webpushtool the ability to send one of these fake messages
+         - Gives webpushtool the ability to reconnect to the next daemon instance after the current connection is dropped
+         - Tests the injection and fetching of push messages via TestWebKitAPI
+
+        * Configurations/webpushtool.xcconfig:
+        * WebKit.xcodeproj/project.pbxproj:
+        * Resources/webpushtool.entitlements:
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::getPendingPushMessages):
+        (WebKit::NetworkProcess::processPushMessage):
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+
+        * NetworkProcess/Notifications/NetworkNotificationManager.cpp:
+        (WebKit::NetworkNotificationManager::getPendingPushMessages):
+        (WebKit::ReplyCaller<Vector<WebPushMessage>::callReply):
+        * NetworkProcess/Notifications/NetworkNotificationManager.h:
+
+        * Shared/Cocoa/WebPushMessageCocoa.mm: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
+        (WebKit::WebPushMessage::fromDictionary):
+        (WebKit::WebPushMessage::toDictionary const):
+
+        * Shared/PushMessageForTesting.h: Copied from Source/WebKit/Shared/WebPushDaemonConstants.h.
+        (WebKit::WebPushD::PushMessageForTesting::encode const):
+        (WebKit::WebPushD::PushMessageForTesting::decode):
+
+        * Shared/WebPushDaemonConstants.h:
+        (WebKit::WebPushD::messageTypeSendsReply):
+
+        * Shared/WebPushMessage.h: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
+        (WebKit::WebPushMessage::encode const):
+        (WebKit::WebPushMessage::decode):
+
+        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+        (-[WKWebsiteDataStore _getPendingPushMessages:]):
+        (-[WKWebsiteDataStore _processPushMessage:completionHandler:]):
+        (-[WKWebsiteDataStore _processPushMessage:registration:completionHandler:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
+
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::getPendingPushMessages):
+        (WebKit::NetworkProcessProxy::processPushMessage):
+        * UIProcess/Network/NetworkProcessProxy.h:
+\
+        * webpushd/PushClientConnection.h:
+        * webpushd/PushClientConnection.mm:
+        (WebPushD::ClientConnection::hostAppHasPushEntitlement):
+        (WebPushD::ClientConnection::hostAppHasPushInjectEntitlement):
+        (WebPushD::ClientConnection::hostHasEntitlement):
+        (WebPushD::ClientConnection::broadcastDebugMessage):
+
+        * webpushd/WebPushDaemon.h:
+        * webpushd/WebPushDaemon.mm:
+        (WebPushD::MessageInfo::injectPushMessageForTesting::encodeReply):
+        (WebPushD::MessageInfo::getPendingPushMessages::encodeReply):
+        (WebPushD::Daemon::decodeAndHandleMessage):
+        (WebPushD::Daemon::injectPushMessageForTesting):
+        (WebPushD::Daemon::getPendingPushMessages):
+
+        * webpushd/webpushtool/WebPushToolConnection.h:
+        (WebPushTool::Connection::setPushMessage):
+
+        * webpushd/webpushtool/WebPushToolConnection.mm:
+        (WebPushTool::Connection::startAction):
+        (WebPushTool::Connection::sendPushMessage):
+
+        * webpushd/webpushtool/WebPushToolMain.mm:
+        (printUsageAndTerminate):
+        (pushMessageFromArguments):
+        (main):
+
 2021-12-08  Megan Gardner  <megan_gard...@apple.com>
 
         Show correct content menu for images services chevron.

Modified: trunk/Source/WebKit/Configurations/webpushtool.xcconfig (286763 => 286764)


--- trunk/Source/WebKit/Configurations/webpushtool.xcconfig	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/Configurations/webpushtool.xcconfig	2021-12-09 06:37:26 UTC (rev 286764)
@@ -29,7 +29,7 @@
 EXCLUDED_SOURCE_FILE_NAMES[sdk=appletv*] = *;
 EXCLUDED_SOURCE_FILE_NAMES[sdk=watch*] = *;
 
-OTHER_LDFLAGS = -l WTF -framework Foundation -framework CoreFoundation;
+OTHER_LDFLAGS = -framework WebKit -framework _javascript_Core
 LIBRARY_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR);
 
 CODE_SIGN_ENTITLEMENTS = Resources/webpushtool.entitlements;

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (286763 => 286764)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2021-12-09 06:37:26 UTC (rev 286764)
@@ -58,6 +58,7 @@
 #include "WebCookieManager.h"
 #include "WebPageProxyMessages.h"
 #include "WebProcessPoolMessages.h"
+#include "WebPushMessage.h"
 #include "WebResourceLoadStatisticsStore.h"
 #include "WebSWOriginStore.h"
 #include "WebSWServerConnection.h"
@@ -2555,13 +2556,21 @@
         SandboxExtension::consumePermanently(handle);
 }
 
-void NetworkProcess::processPushMessage(PAL::SessionID sessionID, const std::optional<IPC::DataReference>& ipcData, URL&& registrationURL, CompletionHandler<void(bool)>&& callback)
+void NetworkProcess::getPendingPushMessages(PAL::SessionID sessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&& callback)
 {
-    std::optional<Vector<uint8_t>> data;
-    if (ipcData)
-        data = "" { ipcData->data(), ipcData->size() };
-    swServerForSession(sessionID).processPushMessage(WTFMove(data), WTFMove(registrationURL), WTFMove(callback));
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+    if (auto* session = networkSession(sessionID)) {
+        session->notificationManager().getPendingPushMessages(WTFMove(callback));
+        return;
+    }
+#endif
+    callback({ });
 }
+
+void NetworkProcess::processPushMessage(PAL::SessionID sessionID, WebPushMessage&& pushMessage, CompletionHandler<void(bool)>&& callback)
+{
+    swServerForSession(sessionID).processPushMessage(WTFMove(pushMessage.pushData), WTFMove(pushMessage.registrationURL), WTFMove(callback));
+}
 #endif // ENABLE(SERVICE_WORKER)
 
 void NetworkProcess::deletePushAndNotificationRegistration(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& callback)

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (286763 => 286764)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -117,6 +117,7 @@
 enum class WebsiteDataFetchOption : uint8_t;
 enum class WebsiteDataType : uint32_t;
 struct NetworkProcessCreationParameters;
+struct WebPushMessage;
 struct WebsiteDataStoreParameters;
 
 #if ENABLE(SERVICE_WORKER)
@@ -396,7 +397,8 @@
     bool ftpEnabled() const { return m_ftpEnabled; }
 
 #if ENABLE(SERVICE_WORKER)
-    void processPushMessage(PAL::SessionID, const std::optional<IPC::DataReference>&, URL&&, CompletionHandler<void(bool)>&&);
+    void getPendingPushMessages(PAL::SessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
+    void processPushMessage(PAL::SessionID, WebPushMessage&&, CompletionHandler<void(bool)>&&);
 #endif
 
     void deletePushAndNotificationRegistration(PAL::SessionID, const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in (286763 => 286764)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in	2021-12-09 06:37:26 UTC (rev 286764)
@@ -207,7 +207,8 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-    ProcessPushMessage(PAL::SessionID sessionID, std::optional<IPC::DataReference> data, URL registrationURL) -> (bool didSucceed) Async
+    GetPendingPushMessages(PAL::SessionID sessionID) -> (Vector<WebKit::WebPushMessage> messages) Async
+    ProcessPushMessage(PAL::SessionID sessionID, struct WebKit::WebPushMessage pushMessage) -> (bool didSucceed) Async
 #endif
     DeletePushAndNotificationRegistration(PAL::SessionID sessionID, struct WebCore::SecurityOriginData origin) -> (String errorMessage) Async
     GetOriginsWithPushAndNotificationPermissions(PAL::SessionID sessionID) -> (Vector<WebCore::SecurityOriginData> origins) Async

Modified: trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp (286763 => 286764)


--- trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp	2021-12-09 06:37:26 UTC (rev 286764)
@@ -32,6 +32,7 @@
 #include "DaemonEncoder.h"
 #include "NetworkSession.h"
 #include "WebPushDaemonConnectionConfiguration.h"
+#include "WebPushMessage.h"
 #include <WebCore/SecurityOriginData.h>
 
 namespace WebKit {
@@ -88,6 +89,15 @@
     sendMessageWithReply<WebPushD::MessageType::GetOriginsWithPushAndNotificationPermissions>(WTFMove(replyHandler));
 }
 
+void NetworkNotificationManager::getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
+{
+    CompletionHandler<void(Vector<WebPushMessage>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<WebPushMessage>&& messages) mutable {
+        completionHandler(WTFMove(messages));
+    };
+
+    sendMessageWithReply<WebPushD::MessageType::GetPendingPushMessages>(WTFMove(replyHandler));
+}
+
 void NetworkNotificationManager::showNotification(const String&, const String&, const String&, const String&, const String&, WebCore::NotificationDirection, const String&, uint64_t)
 {
     if (!m_connection)
@@ -186,6 +196,17 @@
     }
 };
 
+template<> struct ReplyCaller<Vector<WebPushMessage>&&> {
+    static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<WebPushMessage>&&)>&& completionHandler)
+    {
+        std::optional<Vector<WebPushMessage>> messages;
+        decoder >> messages;
+        if (!messages)
+            return completionHandler({ });
+        completionHandler(WTFMove(*messages));
+    }
+};
+
 template<WebPushD::MessageType messageType, typename... Args, typename... ReplyArgs>
 void NetworkNotificationManager::sendMessageWithReply(CompletionHandler<void(ReplyArgs...)>&& completionHandler, Args&&... args) const
 {

Modified: trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h (286763 => 286764)


--- trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -29,6 +29,7 @@
 
 #include "NotificationManagerMessageHandler.h"
 #include "WebPushDaemonConnection.h"
+#include "WebPushMessage.h"
 #include <WebCore/NotificationDirection.h>
 #include <wtf/text/WTFString.h>
 
@@ -52,6 +53,7 @@
 
     void deletePushAndNotificationRegistration(const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);
     void getOriginsWithPushAndNotificationPermissions(CompletionHandler<void(const Vector<WebCore::SecurityOriginData>&)>&&);
+    void getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
 
 private:
     NetworkNotificationManager(NetworkSession&, const String& webPushMachServiceName);

Modified: trunk/Source/WebKit/Resources/webpushtool.entitlements (286763 => 286764)


--- trunk/Source/WebKit/Resources/webpushtool.entitlements	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/Resources/webpushtool.entitlements	2021-12-09 06:37:26 UTC (rev 286764)
@@ -4,5 +4,7 @@
 <dict>
 	<key>com.apple.private.webkit.webpush</key>
 	<true/>
+	<key>com.apple.private.webkit.webpush.inject</key>
+	<true/>
 </dict>
 </plist>

Copied: trunk/Source/WebKit/Shared/Cocoa/WebPushMessageCocoa.mm (from rev 286763, trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h) (0 => 286764)


--- trunk/Source/WebKit/Shared/Cocoa/WebPushMessageCocoa.mm	                        (rev 0)
+++ trunk/Source/WebKit/Shared/Cocoa/WebPushMessageCocoa.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -0,0 +1,61 @@
+/*
+ * 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 "WebPushMessage.h"
+
+#import <wtf/RetainPtr.h>
+
+namespace WebKit {
+
+#define WebKitPushDataKey @"WebKitPushData"
+#define WebKitPushRegistrationURLKey @"WebKitPushRegistrationURL"
+
+std::optional<WebPushMessage> WebPushMessage::fromDictionary(NSDictionary *dictionary)
+{
+    NSURL *url = "" objectForKey:WebKitPushRegistrationURLKey];
+    if (!url || ![url isKindOfClass:[NSURL class]])
+        return std::nullopt;
+
+    NSData *pushData = [dictionary objectForKey:WebKitPushDataKey];
+    if (!pushData || ![pushData isKindOfClass:[NSData class]])
+        return std::nullopt;
+
+    return { {
+        Vector<uint8_t> { static_cast<const uint8_t*>(pushData.bytes), pushData.length },
+        URL { url }
+    } };
+}
+
+NSDictionary *WebPushMessage::toDictionary() const
+{
+    auto nsData = adoptNS([[NSData alloc] initWithBytes:pushData.data() length:pushData.size()]);
+    return @{
+        WebKitPushDataKey : nsData.get(),
+        WebKitPushRegistrationURLKey : (NSURL *)registrationURL
+    };
+}
+
+} // namespace WebKit

Copied: trunk/Source/WebKit/Shared/PushMessageForTesting.h (from rev 286763, trunk/Source/WebKit/Shared/WebPushDaemonConstants.h) (0 => 286764)


--- trunk/Source/WebKit/Shared/PushMessageForTesting.h	                        (rev 0)
+++ trunk/Source/WebKit/Shared/PushMessageForTesting.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <wtf/URL.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit::WebPushD {
+
+struct PushMessageForTesting {
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static std::optional<PushMessageForTesting> decode(Decoder&);
+
+    String targetAppCodeSigningIdentifier;
+    URL registrationURL;
+    String message;
+};
+
+template<class Encoder>
+void PushMessageForTesting::encode(Encoder& encoder) const
+{
+    encoder << targetAppCodeSigningIdentifier << registrationURL << message;
+}
+
+template<class Decoder>
+std::optional<PushMessageForTesting> PushMessageForTesting::decode(Decoder& decoder)
+{
+    std::optional<String> targetAppCodeSigningIdentifier;
+    decoder >> targetAppCodeSigningIdentifier;
+    if (!targetAppCodeSigningIdentifier)
+        return std::nullopt;
+
+    std::optional<URL> registrationURL;
+    decoder >> registrationURL;
+    if (!registrationURL)
+        return std::nullopt;
+
+    std::optional<String> message;
+    decoder >> message;
+    if (!message)
+        return std::nullopt;
+
+    return { {
+        WTFMove(*targetAppCodeSigningIdentifier),
+        WTFMove(*registrationURL),
+        WTFMove(*message),
+    } };
+}
+
+} // namespace WebKit::WebPushD

Modified: trunk/Source/WebKit/Shared/WebPushDaemonConstants.h (286763 => 286764)


--- trunk/Source/WebKit/Shared/WebPushDaemonConstants.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/Shared/WebPushDaemonConstants.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -42,6 +42,8 @@
     GetOriginsWithPushAndNotificationPermissions,
     SetDebugModeIsEnabled,
     UpdateConnectionConfiguration,
+    InjectPushMessageForTesting,
+    GetPendingPushMessages,
 };
 
 inline bool messageTypeSendsReply(MessageType messageType)
@@ -51,6 +53,8 @@
     case MessageType::GetOriginsWithPushAndNotificationPermissions:
     case MessageType::DeletePushAndNotificationRegistration:
     case MessageType::RequestSystemNotificationPermission:
+    case MessageType::GetPendingPushMessages:
+    case MessageType::InjectPushMessageForTesting:
         return true;
     case MessageType::SetDebugModeIsEnabled:
     case MessageType::UpdateConnectionConfiguration:

Copied: trunk/Source/WebKit/Shared/WebPushMessage.h (from rev 286763, trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h) (0 => 286764)


--- trunk/Source/WebKit/Shared/WebPushMessage.h	                        (rev 0)
+++ trunk/Source/WebKit/Shared/WebPushMessage.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <wtf/URL.h>
+#include <wtf/Vector.h>
+
+OBJC_CLASS NSDictionary;
+
+namespace WebKit {
+
+struct WebPushMessage {
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static std::optional<WebPushMessage> decode(Decoder&);
+
+    Vector<uint8_t> pushData;
+    URL registrationURL;
+
+#if PLATFORM(COCOA)
+    static std::optional<WebPushMessage> fromDictionary(NSDictionary *);
+    NSDictionary *toDictionary() const;
+#endif
+};
+
+template<class Encoder>
+void WebPushMessage::encode(Encoder& encoder) const
+{
+    encoder << pushData << registrationURL;
+}
+
+template<class Decoder>
+std::optional<WebPushMessage> WebPushMessage::decode(Decoder& decoder)
+{
+    std::optional<Vector<uint8_t>> pushData;
+    decoder >> pushData;
+    if (!pushData)
+        return std::nullopt;
+
+    std::optional<URL> registrationURL;
+    decoder >> registrationURL;
+    if (!registrationURL)
+        return std::nullopt;
+
+    return { {
+        WTFMove(*pushData),
+        WTFMove(*registrationURL)
+    } };
+}
+
+} // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm (286763 => 286764)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -39,6 +39,7 @@
 #import "WKWebViewInternal.h"
 #import "WKWebsiteDataRecordInternal.h"
 #import "WebPageProxy.h"
+#import "WebPushMessage.h"
 #import "WebResourceLoadStatisticsStore.h"
 #import "WebsiteDataFetchOption.h"
 #import "_WKResourceLoadStatisticsThirdPartyInternal.h"
@@ -761,13 +762,29 @@
     return _websiteDataStore->hasServiceWorkerBackgroundActivityForTesting();
 }
 
--(void)_processPushMessage:(NSData*) message registration:(NSURL *)registration completionHandler:(void(^)(bool wasProcessed))completionHandler
+-(void)_getPendingPushMessages:(void(^)(NSArray<NSDictionary *> *))completionHandler
 {
 #if ENABLE(SERVICE_WORKER)
-    std::optional<Span<const uint8_t>> data;
-    if (message)
-        data = "" uint8_t> { reinterpret_cast<const uint8_t*>(message.bytes), message.length };
-    _websiteDataStore->networkProcess().processPushMessage(_websiteDataStore->sessionID(), data, registration, [completionHandler = makeBlockPtr(completionHandler)] (bool wasProcessed) {
+    _websiteDataStore->networkProcess().getPendingPushMessages(_websiteDataStore->sessionID(), [completionHandler = makeBlockPtr(completionHandler)] (const Vector<WebKit::WebPushMessage>& messages) {
+        auto result = adoptNS([[NSMutableArray alloc] initWithCapacity:messages.size()]);
+        for (auto& message : messages)
+            [result addObject:message.toDictionary()];
+
+        completionHandler(result.get());
+    });
+#endif
+}
+
+-(void)_processPushMessage:(NSDictionary *)pushMessageDictionary completionHandler:(void(^)(bool wasProcessed))completionHandler
+{
+#if ENABLE(SERVICE_WORKER)
+    auto pushMessage = WebKit::WebPushMessage::fromDictionary(pushMessageDictionary);
+    if (!pushMessage) {
+        completionHandler(false);
+        return;
+    }
+
+    _websiteDataStore->networkProcess().processPushMessage(_websiteDataStore->sessionID(), *pushMessage, [completionHandler = makeBlockPtr(completionHandler)] (bool wasProcessed) {
         completionHandler(wasProcessed);
     });
 #endif

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h (286763 => 286764)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -108,7 +108,8 @@
 - (void)_countNonDefaultSessionSets:(void(^)(size_t))completionHandler;
 
 -(bool)_hasServiceWorkerBackgroundActivityForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
--(void)_processPushMessage:(NSData*)data registration:(NSURL *)registration completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+-(void)_getPendingPushMessages:(void(^)(NSArray<NSDictionary *> *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+-(void)_processPushMessage:(NSDictionary *)pushMessage completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 -(void)_deletePushAndNotificationRegistration:(WKSecurityOrigin *)securityOrigin completionHandler:(void(^)(NSError *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 -(void)_getOriginsWithPushAndNotificationPermissions:(void(^)(NSSet<WKSecurityOrigin *> *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @end

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (286763 => 286764)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2021-12-09 06:37:26 UTC (rev 286764)
@@ -1692,13 +1692,15 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-void NetworkProcessProxy::processPushMessage(PAL::SessionID sessionID, std::optional<Span<const uint8_t>> data, const URL& registrationURL, CompletionHandler<void(bool wasProcessed)>&& callback)
+void NetworkProcessProxy::getPendingPushMessages(PAL::SessionID sessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
 {
-    std::optional<IPC::DataReference> ipcData;
-    if (data)
-        ipcData = IPC::DataReference { data->data(), data->size() };
-    sendWithAsyncReply(Messages::NetworkProcess::ProcessPushMessage { sessionID, ipcData, registrationURL }, WTFMove(callback));
+    sendWithAsyncReply(Messages::NetworkProcess::GetPendingPushMessages { sessionID }, WTFMove(completionHandler));
 }
+
+void NetworkProcessProxy::processPushMessage(PAL::SessionID sessionID, const WebPushMessage& pushMessage, CompletionHandler<void(bool wasProcessed)>&& callback)
+{
+    sendWithAsyncReply(Messages::NetworkProcess::ProcessPushMessage { sessionID, pushMessage }, WTFMove(callback));
+}
 #endif // ENABLE(SERVICE_WORKER)
 
 void NetworkProcessProxy::deletePushAndNotificationRegistration(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& callback)

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (286763 => 286764)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -92,6 +92,7 @@
 struct FrameInfoData;
 struct NetworkProcessCreationParameters;
 struct ResourceLoadInfo;
+struct WebPushMessage;
 struct WebsiteData;
 struct WebsiteDataStoreParameters;
 
@@ -273,7 +274,8 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-    void processPushMessage(PAL::SessionID, std::optional<Span<const uint8_t>>, const URL&, CompletionHandler<void(bool wasProcessed)>&&);
+    void getPendingPushMessages(PAL::SessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
+    void processPushMessage(PAL::SessionID, const WebPushMessage&, CompletionHandler<void(bool wasProcessed)>&&);
 #endif
 
     void deletePushAndNotificationRegistration(PAL::SessionID, const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (286763 => 286764)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2021-12-09 06:37:26 UTC (rev 286764)
@@ -1034,6 +1034,12 @@
 		517B5F84275E97B6002DC22D /* MockAppBundleForTesting.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51F7BB74274498BA00C45A72 /* MockAppBundleForTesting.mm */; };
 		517B5F85275E97B6002DC22D /* AppBundleRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 5160E954274B887100567388 /* AppBundleRequest.h */; };
 		517B5F86275E97B6002DC22D /* MockAppBundleRegistry.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5160E95F274C2A3F00567388 /* MockAppBundleRegistry.mm */; };
+		517B5F95275EBA63002DC22D /* PushMessageForTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = 517B5F94275EBA62002DC22D /* PushMessageForTesting.h */; };
+		517B5F97275EC5E5002DC22D /* WebPushMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 517B5F96275EC5E5002DC22D /* WebPushMessage.h */; };
+		517B5F99275EC601002DC22D /* WebPushMessageCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */; };
+		517B5F9A275F3A86002DC22D /* ArgumentCoders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A3D610413A7F03A00F95D4E /* ArgumentCoders.cpp */; };
+		517B5F9B275F3A98002DC22D /* DaemonUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C1579F92717AF5000ED5280 /* DaemonUtilities.mm */; };
+		517B5F9C275F3C37002DC22D /* DaemonEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C1579E827172A8A00ED5280 /* DaemonEncoder.cpp */; };
 		517CF0E3163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */; };
 		517CF0E3163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */; };
 		517CF0E4163A486C00C2950E /* NetworkProcessConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 517CF0E2163A486C00C2950E /* NetworkProcessConnectionMessages.h */; };
@@ -4409,6 +4415,9 @@
 		517B5F6B275AE50B002DC22D /* webpushtool.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = webpushtool.entitlements; path = Resources/webpushtool.entitlements; sourceTree = "<group>"; };
 		517B5F72275E9609002DC22D /* WebPushDaemonMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPushDaemonMain.h; sourceTree = "<group>"; };
 		517B5F77275E9795002DC22D /* webpushd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = webpushd.cpp; sourceTree = "<group>"; };
+		517B5F94275EBA62002DC22D /* PushMessageForTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushMessageForTesting.h; sourceTree = "<group>"; };
+		517B5F96275EC5E5002DC22D /* WebPushMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPushMessage.h; sourceTree = "<group>"; };
+		517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPushMessageCocoa.mm; sourceTree = "<group>"; };
 		517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkProcessConnectionMessageReceiver.cpp; path = DerivedSources/WebKit/NetworkProcessConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
 		517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheStorageEngineConnectionMessageReceiver.cpp; path = DerivedSources/WebKit/CacheStorageEngineConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
 		517CF0E2163A486C00C2950E /* NetworkProcessConnectionMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkProcessConnectionMessages.h; path = DerivedSources/WebKit/NetworkProcessConnectionMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -6475,6 +6484,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				517B5F9E275F3F54002DC22D /* libicucore.tbd in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -7136,6 +7146,7 @@
 				E18C92F312DB9E7100CF2AEB /* PrintInfo.cpp */,
 				E1CC1B8E12D7EADF00625838 /* PrintInfo.h */,
 				463FD4811EB94EAD00A2982C /* ProcessTerminationReason.h */,
+				517B5F94275EBA62002DC22D /* PushMessageForTesting.h */,
 				9B1229D023FF2A5E008CA751 /* RemoteAudioDestinationIdentifier.h */,
 				7203449B26A6C476000A5F54 /* RenderingUpdateID.h */,
 				5CB7AFE623C681B000E49CF3 /* ResourceLoadInfo.h */,
@@ -7242,6 +7253,7 @@
 				467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */,
 				517B5F2D2757382A002DC22D /* WebPushDaemonConnectionConfiguration.h */,
 				512CD6992721F04900F7F8EC /* WebPushDaemonConstants.h */,
+				517B5F96275EC5E5002DC22D /* WebPushMessage.h */,
 				5C8DD37F1FE4519200F2A556 /* WebsiteAutoplayPolicy.h */,
 				5C8DD3811FE455CA00F2A556 /* WebsiteAutoplayQuirk.h */,
 				511F7D3F1EB1BCEE00E47B83 /* WebsiteDataStoreParameters.cpp */,
@@ -8938,6 +8950,7 @@
 				7AF236221E79A43100438A05 /* WebErrorsCocoa.mm */,
 				465250E51ECF52CD002025CB /* WebKit2InitializeCocoa.mm */,
 				1DE076D92460CCBD00B211E8 /* WebPreferencesDefaultValuesCocoa.mm */,
+				517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */,
 				37C4C0921814B3AF003688B9 /* WKNSArray.h */,
 				37C4C0911814B3AF003688B9 /* WKNSArray.mm */,
 				373CEAD4185417AE008C363D /* WKNSData.h */,
@@ -9700,6 +9713,7 @@
 		5750F3292032D4E300389347 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				517B5F9D275F3F54002DC22D /* libicucore.tbd */,
 				57A9FF15252C6AEF006A2040 /* libWTF.a */,
 				5750F32A2032D4E500389347 /* LocalAuthentication.framework */,
 				570DAAB0230273D200E8FC04 /* NearField.framework */,
@@ -13013,6 +13027,7 @@
 				532159561DBAE72D0054AA3C /* NetworkDataTaskCocoa.h in Headers */,
 				839902031BE9A02B000F3653 /* NetworkLoad.h in Headers */,
 				83D454D71BE9D3C4006C93BD /* NetworkLoadClient.h in Headers */,
+				517B5F97275EC5E5002DC22D /* WebPushMessage.h in Headers */,
 				839149651BEA838500D2D953 /* NetworkLoadParameters.h in Headers */,
 				E47FC8A025B8331C005495FC /* NetworkLoadScheduler.h in Headers */,
 				514526ED271E1647000467B6 /* NetworkNotificationManager.h in Headers */,
@@ -13520,6 +13535,7 @@
 				9356F2DC2152B6B500E6D5DF /* WebSWClientConnection.h in Headers */,
 				517A53101F47A86200DCDC0A /* WebSWClientConnectionMessages.h in Headers */,
 				466BC03C1FA266DA002FA9C1 /* WebSWContextManagerConnection.h in Headers */,
+				517B5F95275EBA63002DC22D /* PushMessageForTesting.h in Headers */,
 				460F48901F996F7100CF4B87 /* WebSWContextManagerConnectionMessages.h in Headers */,
 				C11A9ECC214035F800CFB20A /* WebSwitchingGPUClient.h in Headers */,
 				9356F2DE2152B71000E6D5DF /* WebSWOriginStore.h in Headers */,
@@ -15085,7 +15101,10 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				517B5F9A275F3A86002DC22D /* ArgumentCoders.cpp in Sources */,
 				517B5F68275A9A78002DC22D /* WebPushToolConnection.mm in Sources */,
+				517B5F9B275F3A98002DC22D /* DaemonUtilities.mm in Sources */,
+				517B5F9C275F3C37002DC22D /* DaemonEncoder.cpp in Sources */,
 				517B5F65275A8D7F002DC22D /* WebPushToolMain.mm in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -15181,6 +15200,7 @@
 				CDA93DB122F8BCF400490A69 /* FullscreenTouchSecheuristicParameters.cpp in Sources */,
 				C1A152D724E5A29A00978C8B /* HandleXPCEndpointMessages.mm in Sources */,
 				2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */,
+				517B5F99275EC601002DC22D /* WebPushMessageCocoa.mm in Sources */,
 				2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */,
 				9BF5EC642541145600984E77 /* JSIPCBinding.cpp in Sources */,
 				C14D37FE24ACE086007FF014 /* LaunchServicesDatabaseManager.mm in Sources */,

Modified: trunk/Source/WebKit/webpushd/PushClientConnection.h (286763 => 286764)


--- trunk/Source/WebKit/webpushd/PushClientConnection.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/PushClientConnection.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -56,6 +56,7 @@
 
     const String& hostAppCodeSigningIdentifier();
     bool hostAppHasPushEntitlement();
+    bool hostAppHasPushInjectEntitlement();
 
     bool debugModeIsEnabled() const { return m_debugModeEnabled; }
     void setDebugModeIsEnabled(bool);
@@ -75,6 +76,8 @@
     void maybeStartNextAppBundleRequest();
     void setHostAppAuditTokenData(const Vector<uint8_t>&);
 
+    bool hostHasEntitlement(const char*);
+
     OSObjectPtr<xpc_connection_t> m_xpcConnection;
 
     std::optional<audit_token_t> m_hostAppAuditToken;

Modified: trunk/Source/WebKit/webpushd/PushClientConnection.mm (286763 => 286764)


--- trunk/Source/WebKit/webpushd/PushClientConnection.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/PushClientConnection.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -89,15 +89,24 @@
 
 bool ClientConnection::hostAppHasPushEntitlement()
 {
-    if (!m_hostAppHasPushEntitlement) {
-        if (!m_hostAppAuditToken)
-            return false;
-        m_hostAppHasPushEntitlement = WTF::hasEntitlement(*m_hostAppAuditToken, "com.apple.private.webkit.webpush");
-    }
+    if (!m_hostAppHasPushEntitlement)
+        m_hostAppHasPushEntitlement = hostHasEntitlement("com.apple.private.webkit.webpush"_s);
 
     return *m_hostAppHasPushEntitlement;
 }
 
+bool ClientConnection::hostAppHasPushInjectEntitlement()
+{
+    return hostHasEntitlement("com.apple.private.webkit.webpush.inject"_s);
+}
+
+bool ClientConnection::hostHasEntitlement(const char* entitlement)
+{
+    if (!m_hostAppAuditToken)
+        return false;
+    return WTF::hasEntitlement(*m_hostAppAuditToken, entitlement);
+}
+
 void ClientConnection::setDebugModeIsEnabled(bool enabled)
 {
     if (enabled == m_debugModeEnabled)
@@ -112,9 +121,9 @@
     String messageIdentifier;
     auto signingIdentifer = hostAppCodeSigningIdentifier();
     if (signingIdentifer.isEmpty())
-        messageIdentifier = makeString ("[(0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
+        messageIdentifier = makeString("[(0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
     else
-        messageIdentifier = makeString ("[", signingIdentifer, " (0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
+        messageIdentifier = makeString("[", signingIdentifer, " (0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
 
     Daemon::singleton().broadcastDebugMessage(JSC::MessageLevel::Info, makeString(messageIdentifier, message));
 }

Modified: trunk/Source/WebKit/webpushd/WebPushDaemon.h (286763 => 286764)


--- trunk/Source/WebKit/webpushd/WebPushDaemon.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/WebPushDaemon.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -26,8 +26,11 @@
 #pragma once
 
 #include "PushClientConnection.h"
+#include "PushMessageForTesting.h"
 #include "WebPushDaemonConnectionConfiguration.h"
 #include "WebPushDaemonConstants.h"
+#include "WebPushMessage.h"
+#include <wtf/Deque.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -40,6 +43,7 @@
 enum class MessageLevel : uint8_t;
 }
 
+using WebKit::WebPushD::PushMessageForTesting;
 using WebKit::WebPushD::WebPushDaemonConnectionConfiguration;
 
 namespace WebPushD {
@@ -62,6 +66,8 @@
     void deletePushAndNotificationRegistration(ClientConnection*, const String& originString, CompletionHandler<void(const String&)>&& replySender);
     void setDebugModeIsEnabled(ClientConnection*, bool);
     void updateConnectionConfiguration(ClientConnection*, const WebPushDaemonConnectionConfiguration&);
+    void injectPushMessageForTesting(ClientConnection*, const PushMessageForTesting&, CompletionHandler<void(bool)>&&);
+    void getPendingPushMessages(ClientConnection*, CompletionHandler<void(const Vector<WebKit::WebPushMessage>&)>&& replySender);
 
     void broadcastDebugMessage(JSC::MessageLevel, const String&);
 
@@ -75,6 +81,8 @@
 
     ClientConnection* toClientConnection(xpc_connection_t);
     HashMap<xpc_connection_t, Ref<ClientConnection>> m_connectionMap;
+
+    HashMap<String, Deque<PushMessageForTesting>> m_testingPushMessages;
 };
 
 } // namespace WebPushD

Modified: trunk/Source/WebKit/webpushd/WebPushDaemon.mm (286763 => 286764)


--- trunk/Source/WebKit/webpushd/WebPushDaemon.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/WebPushDaemon.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -70,6 +70,11 @@
 REPLY(bool)
 END
 
+FUNCTION(getPendingPushMessages)
+ARGUMENTS()
+REPLY(const Vector<WebKit::WebPushMessage>&)
+END
+
 FUNCTION(setDebugModeIsEnabled)
 ARGUMENTS(bool)
 END
@@ -78,6 +83,11 @@
 ARGUMENTS(WebPushDaemonConnectionConfiguration)
 END
 
+FUNCTION(injectPushMessageForTesting)
+ARGUMENTS(PushMessageForTesting)
+REPLY(bool)
+END
+
 #undef FUNCTION
 #undef ARGUMENTS
 #undef REPLY
@@ -111,6 +121,20 @@
     return encoder.takeBuffer();
 }
 
+WebPushD::EncodedMessage injectPushMessageForTesting::encodeReply(bool reply)
+{
+    WebKit::Daemon::Encoder encoder;
+    encoder << reply;
+    return encoder.takeBuffer();
+}
+
+WebPushD::EncodedMessage getPendingPushMessages::encodeReply(const Vector<WebKit::WebPushMessage>& reply)
+{
+    WebKit::Daemon::Encoder encoder;
+    encoder << reply;
+    return encoder.takeBuffer();
+}
+
 } // namespace MessageInfo
 
 template<typename Info>
@@ -233,6 +257,12 @@
     case MessageType::UpdateConnectionConfiguration:
         handleWebPushDMessage<MessageInfo::updateConnectionConfiguration>(clientConnection, encodedMessage);
         break;
+    case MessageType::InjectPushMessageForTesting:
+        handleWebPushDMessageWithReply<MessageInfo::injectPushMessageForTesting>(clientConnection, encodedMessage, WTFMove(replySender));
+        break;
+    case MessageType::GetPendingPushMessages:
+        handleWebPushDMessageWithReply<MessageInfo::getPendingPushMessages>(clientConnection, encodedMessage, WTFMove(replySender));
+        break;
     }
 }
 
@@ -297,6 +327,55 @@
     clientConnection->updateConnectionConfiguration(configuration);
 }
 
+void Daemon::injectPushMessageForTesting(ClientConnection* connection, const PushMessageForTesting& message, CompletionHandler<void(bool)>&& replySender)
+{
+    if (!connection->hostAppHasPushInjectEntitlement()) {
+        connection->broadcastDebugMessage("Attempting to inject a push message from an unentitled process");
+        replySender(false);
+        return;
+    }
+
+    if (message.targetAppCodeSigningIdentifier.isEmpty() || !message.registrationURL.isValid()) {
+        connection->broadcastDebugMessage("Attempting to inject an invalid push message");
+        replySender(false);
+        return;
+    }
+
+    connection->broadcastDebugMessage(makeString("Injected a test push messasge for ", message.targetAppCodeSigningIdentifier, " at ", message.registrationURL.string()));
+    connection->broadcastDebugMessage(message.message);
+
+    auto addResult = m_testingPushMessages.ensure(message.targetAppCodeSigningIdentifier, [] {
+        return Deque<PushMessageForTesting> { };
+    });
+    addResult.iterator->value.append(message);
+
+    replySender(true);
+}
+
+void Daemon::getPendingPushMessages(ClientConnection* connection, CompletionHandler<void(const Vector<WebKit::WebPushMessage>&)>&& replySender)
+{
+    auto hostAppCodeSigningIdentifier = connection->hostAppCodeSigningIdentifier();
+    if (hostAppCodeSigningIdentifier.isEmpty()) {
+        replySender({ });
+        return;
+    }
+
+    Vector<WebKit::WebPushMessage> resultMessages;
+
+    auto iterator = m_testingPushMessages.find(hostAppCodeSigningIdentifier);
+    if (iterator != m_testingPushMessages.end()) {
+        for (auto& message : iterator->value) {
+            auto data = ""
+            resultMessages.append(WebKit::WebPushMessage { Vector<uint8_t> { reinterpret_cast<const uint8_t*>(data.data()), data.length() }, message.registrationURL });
+        }
+        m_testingPushMessages.remove(iterator);
+    }
+
+    connection->broadcastDebugMessage(makeString("Fetching ", String::number(resultMessages.size()), " pending push messages"));
+
+    replySender(WTFMove(resultMessages));
+}
+
 ClientConnection* Daemon::toClientConnection(xpc_connection_t connection)
 {
     auto clientConnection = m_connectionMap.get(connection);

Modified: trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h (286763 => 286764)


--- trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -25,11 +25,15 @@
 
 #pragma once
 
+#include "PushMessageForTesting.h"
 #include <memory>
 #include <wtf/RetainPtr.h>
+#include <wtf/URL.h>
 #include <wtf/WeakPtr.h>
 #include <wtf/spi/darwin/XPCSPI.h>
 
+using WebKit::WebPushD::PushMessageForTesting;
+
 namespace WebPushTool {
 
 enum class Action {
@@ -54,6 +58,8 @@
 
     void connectToService();
 
+    void setPushMessage(std::unique_ptr<PushMessageForTesting>&& message) { m_pushMessage = WTFMove(message); }
+
 private:
     void messageReceived(xpc_object_t);
     void connectionDropped();
@@ -60,13 +66,16 @@
 
     void startAction();
     void startDebugStreamAction();
+    void sendPushMessage();
 
     void sendAuditToken();
-    
+
     Action m_action;
     bool m_reconnect { false };
     RetainPtr<xpc_connection_t> m_connection;
     const char* m_serviceName;
+
+    std::unique_ptr<PushMessageForTesting> m_pushMessage;
 };
 
 } // namespace WebPushTool

Modified: trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.mm (286763 => 286764)


--- trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -26,6 +26,9 @@
 #import "config.h"
 #import "WebPushToolConnection.h"
 
+#import "DaemonEncoder.h"
+#import "DaemonUtilities.h"
+#import "WebPushDaemonConstants.h"
 #import <mach/mach_init.h>
 #import <mach/task.h>
 #import <pal/spi/cocoa/ServersSPI.h>
@@ -118,8 +121,28 @@
         startDebugStreamAction();
         break;
     };
+
+    if (m_pushMessage)
+        sendPushMessage();
 }
 
+void Connection::sendPushMessage()
+{
+    ASSERT(m_pushMessage);
+
+    WebKit::Daemon::Encoder encoder;
+    encoder << *m_pushMessage;
+
+    auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
+    xpc_dictionary_set_uint64(dictionary.get(), WebKit::WebPushD::protocolVersionKey, WebKit::WebPushD::protocolVersionValue);
+    xpc_dictionary_set_value(dictionary.get(), WebKit::WebPushD::protocolEncodedMessageKey, WebKit::vectorToXPCData(encoder.takeBuffer()).get());
+    xpc_dictionary_set_uint64(dictionary.get(), WebKit::WebPushD::protocolMessageTypeKey, static_cast<uint64_t>(WebKit::WebPushD::MessageType::InjectPushMessageForTesting));
+
+    xpc_connection_send_message_with_reply(m_connection.get(), dictionary.get(), dispatch_get_main_queue(), ^(xpc_object_t resultMessage) {
+        // This reply handler intentionally left blank
+    });
+}
+
 void Connection::startDebugStreamAction()
 {
     auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));

Modified: trunk/Source/WebKit/webpushd/webpushtool/WebPushToolMain.mm (286763 => 286764)


--- trunk/Source/WebKit/webpushd/webpushtool/WebPushToolMain.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Source/WebKit/webpushd/webpushtool/WebPushToolMain.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -24,11 +24,14 @@
  */
 
 #import "config.h"
+#import "PushMessageForTesting.h"
 #import "WebPushToolConnection.h"
 #import <Foundation/Foundation.h>
 #import <optional>
 #import <wtf/MainThread.h>
 
+using WebKit::WebPushD::PushMessageForTesting;
+
 __attribute__((__noreturn__))
 static void printUsageAndTerminate(NSString *message)
 {
@@ -36,15 +39,43 @@
 
     fprintf(stderr, "Usage: webpushtool [options]\n");
     fprintf(stderr, "\n");
-    fprintf(stderr, "  --development              Connects to mach service \"org.webkit.webpushtestdaemon.service\" (Default)\n");
-    fprintf(stderr, "  --production               Connects to mach service \"com.apple.webkit.webpushd.service\"\n");
-    fprintf(stderr, "  --streamDebugMessages      Stream debug messages from webpushd\n");
-    fprintf(stderr, "  --reconnect                Reconnect after connection is lost\n");
+    fprintf(stderr, "  --development\n");
+    fprintf(stderr, "    Connects to mach service \"org.webkit.webpushtestdaemon.service\" (Default)\n");
+    fprintf(stderr, "  --production\n");
+    fprintf(stderr, "    Connects to mach service \"com.apple.webkit.webpushd.service\"\n");
+    fprintf(stderr, "  --streamDebugMessages\n");
+    fprintf(stderr, "    Stream debug messages from webpushd\n");
+    fprintf(stderr, "  --reconnect\n");
+    fprintf(stderr, "    Reconnect after connection is lost\n");
+    fprintf(stderr, "  --push <target app identifier> <registration URL> <message>\n");
+    fprintf(stderr, "    Inject a test push messasge to the target app and registration URL\n");
     fprintf(stderr, "\n");
 
     exit(-1);
 }
 
+static std::unique_ptr<PushMessageForTesting> pushMessageFromArguments(NSEnumerator<NSString *> *enumerator)
+{
+    NSString *appIdentifier = [enumerator nextObject];
+    if (!appIdentifier)
+        return nullptr;
+
+    NSString *registrationString = [enumerator nextObject];
+    if (!registrationString)
+        return nullptr;
+
+    NSURL *registrationURL = [NSURL URLWithString:registrationString];
+    if (!registrationURL)
+        return nullptr;
+
+    NSString *message = [enumerator nextObject];
+    if (!message)
+        return nullptr;
+
+    PushMessageForTesting pushMessage = { appIdentifier, registrationURL, message };
+    return makeUniqueWithoutFastMallocCheck<PushMessageForTesting>(WTFMove(pushMessage));
+}
+
 int main(int, const char **)
 {
     WTF::initializeMainThread();
@@ -52,6 +83,7 @@
     auto preferTestService = WebPushTool::PreferTestService::Yes;
     auto reconnect = WebPushTool::Reconnect::No;
     std::optional<WebPushTool::Action> action;
+    std::unique_ptr<PushMessageForTesting> pushMessage;
 
     @autoreleasepool {
         NSArray *arguments = [[NSProcessInfo processInfo] arguments];
@@ -58,7 +90,9 @@
         if (arguments.count == 1)
             printUsageAndTerminate(@"No arguments provided");
 
-        for (NSString *argument in [arguments subarrayWithRange:NSMakeRange(1, arguments.count - 1)]) {
+        NSEnumerator<NSString *> *enumerator = [[arguments subarrayWithRange:NSMakeRange(1, arguments.count - 1)] objectEnumerator];
+        NSString *argument = [enumerator nextObject];
+        while (argument) {
             if ([argument isEqualToString:@"--production"])
                 preferTestService = WebPushTool::PreferTestService::No;
             else if ([argument isEqualToString:@"--development"])
@@ -67,15 +101,24 @@
                 action = ""
             else if ([argument isEqualToString:@"--reconnect"])
                 reconnect = WebPushTool::Reconnect::Yes;
-            else
+            else if ([argument isEqualToString:@"--push"]) {
+                pushMessage = pushMessageFromArguments(enumerator);
+                if (!pushMessage)
+                    printUsageAndTerminate([NSString stringWithFormat:@"Invalid push arguments specified"]);
+            } else
                 printUsageAndTerminate([NSString stringWithFormat:@"Invalid option provided: %@", argument]);
+
+            argument = [enumerator nextObject];
         }
     }
 
-    if (!action)
+    if (!action && !pushMessage)
         printUsageAndTerminate(@"No action provided");
 
     auto connection = WebPushTool::Connection::create(*action, preferTestService, reconnect);
+    if (pushMessage)
+        connection->setPushMessage(WTFMove(pushMessage));
+
     connection->connectToService();
 
     CFRunLoopRun();

Modified: trunk/Tools/ChangeLog (286763 => 286764)


--- trunk/Tools/ChangeLog	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/ChangeLog	2021-12-09 06:37:26 UTC (rev 286764)
@@ -1,3 +1,28 @@
+2021-12-08  Brady Eidson  <beid...@apple.com>
+
+        Add ability to inject messages into webpushd
+        https://bugs.webkit.org/show_bug.cgi?id=233988
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements:
+        * TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements:
+        * TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements:
+
+        * TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm:
+        (messageDictionary):
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm:
+        (TestWebKitAPI::createMessageDictionary):
+        (TestWebKitAPI::sendMessageToDaemon):
+        (TestWebKitAPI::sendMessageToDaemonWaitingForReply):
+        (TestWebKitAPI::sendConfigurationWithAuditToken):
+        (TestWebKitAPI::createAndConfigureConnectionToService):
+        (TestWebKitAPI::encodeString):
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::function):
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+
 2021-12-08  Kyle Piddington  <kpidding...@apple.com>
 
         [MacCatalyst] Update header search paths for ANGLE Catalyst

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements	2021-12-09 06:37:26 UTC (rev 286764)
@@ -12,6 +12,8 @@
 	<true/>
 	<key>com.apple.private.webkit.webpush</key>
 	<true/>
+	<key>com.apple.private.webkit.webpush.inject</key>
+	<true/>
 	<key>com.apple.private.xpc.launchd.job-manager</key>
 	<string>TestWebKitAPI</string>
 </dict>

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements	2021-12-09 06:37:26 UTC (rev 286764)
@@ -6,6 +6,8 @@
 	<string>TestWebKitAPI</string>
 	<key>com.apple.private.webkit.webpush</key>
 	<true/>
+	<key>com.apple.private.webkit.webpush.inject</key>
+	<true/>
 	<key>com.apple.hid.manager.user-access-device</key>
 	<true/>
 	<key>com.apple.private.hid.client.event-filter</key>

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements	2021-12-09 06:37:26 UTC (rev 286764)
@@ -10,6 +10,8 @@
 	</array>
 	<key>com.apple.private.webkit.webpush</key>
 	<true/>
+	<key>com.apple.private.webkit.webpush.inject</key>
+	<true/>
 	<key>com.apple.security.temporary-exception.sbpl</key>
 	<array>
 		<string>(allow mach-issue-extension (require-all (extension-class &quot;com.apple.webkit.extension.mach&quot;)))</string>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -34,6 +34,14 @@
 #import <WebKit/WKWebsiteDataStorePrivate.h>
 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
 
+static NSDictionary *messageDictionary(NSData *data, NSURL *registration)
+{
+    return @{
+        @"WebKitPushData" : data,
+        @"WebKitPushRegistrationURL" : registration
+    };
+}
+
 static String expectedMessage;
 
 @interface PushAPIMessageHandlerWithExpectedMessage : NSObject <WKScriptMessageHandler>
@@ -146,7 +154,8 @@
     pushMessageSuccessful = false;
     NSString *message = @"Sweet Potatoes";
     expectedMessage = "Received: Sweet Potatoes";
-    [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+
+    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
         pushMessageSuccessful = result;
         pushMessageProcessed = true;
     }];
@@ -160,7 +169,7 @@
     pushMessageSuccessful = false;
     message = @"Rotten Potatoes";
     expectedMessage = "Received: Rotten Potatoes";
-    [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
         pushMessageSuccessful = result;
         pushMessageProcessed = true;
     }];
@@ -234,7 +243,7 @@
     pushMessageProcessed = false;
     pushMessageSuccessful = false;
     NSString *message = @"Sweet Potatoes";
-    [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
         pushMessageSuccessful = result;
         pushMessageProcessed = true;
     }];
@@ -279,7 +288,7 @@
     pushMessageProcessed = false;
     pushMessageSuccessful = false;
     NSString *message = @"Rotten Potatoes";
-    [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
         pushMessageSuccessful = result;
         pushMessageProcessed = true;
     }];
@@ -332,7 +341,7 @@
     pushMessageProcessed = false;
     pushMessageSuccessful = false;
     NSString *message = @"Timeless Potatoes";
-    [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
         pushMessageSuccessful = result;
         pushMessageProcessed = true;
     }];

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm	2021-12-09 06:37:26 UTC (rev 286764)
@@ -26,6 +26,7 @@
 #import "config.h"
 
 #import "DaemonTestUtilities.h"
+#import "HTTPServer.h"
 #import "Test.h"
 #import "TestURLSchemeHandler.h"
 #import "TestWKWebView.h"
@@ -35,7 +36,6 @@
 #import <WebKit/WKWebsiteDataStorePrivate.h>
 #import <WebKit/_WKExperimentalFeature.h>
 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
-#import <array>
 #import <mach/mach_init.h>
 #import <mach/task.h>
 
@@ -162,6 +162,85 @@
     EXPECT_NULL(error);
 }
 
+static RetainPtr<xpc_object_t> createMessageDictionary(uint8_t messageType, const Vector<uint8_t>& message)
+{
+    auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
+    xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
+    xpc_dictionary_set_uint64(dictionary.get(), "message type", messageType);
+    xpc_dictionary_set_data(dictionary.get(), "encoded message", message.data(), message.size());
+    return WTFMove(dictionary);
+}
+
+// Uses an existing connection to the daemon for a one-off message
+void sendMessageToDaemon(xpc_connection_t connection, uint8_t messageType, const Vector<uint8_t>& message)
+{
+    auto dictionary = createMessageDictionary(messageType, message);
+    xpc_connection_send_message(connection, dictionary.get());
+}
+
+// Uses an existing connection to the daemon for a one-off message, waiting for the reply
+void sendMessageToDaemonWaitingForReply(xpc_connection_t connection, uint8_t messageType, const Vector<uint8_t>& message)
+{
+    auto dictionary = createMessageDictionary(messageType, message);
+
+    __block bool done = false;
+    xpc_connection_send_message_with_reply(connection, dictionary.get(), dispatch_get_main_queue(), ^(xpc_object_t request) {
+        done = true;
+    });
+
+    TestWebKitAPI::Util::run(&done);
+}
+
+static void sendConfigurationWithAuditToken(xpc_connection_t connection)
+{
+    audit_token_t token = { 0, 0, 0, 0, 0, 0, 0, 0 };
+    mach_msg_type_number_t auditTokenCount = TASK_AUDIT_TOKEN_COUNT;
+    kern_return_t result = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)(&token), &auditTokenCount);
+    if (result != KERN_SUCCESS) {
+        EXPECT_TRUE(false);
+        return;
+    }
+
+    // Send configuration with audit token
+    {
+        Vector<uint8_t> encodedMessage(42);
+        encodedMessage.fill(0);
+        encodedMessage[1] = 1;
+        encodedMessage[2] = 32;
+        memcpy(&encodedMessage[10], &token, sizeof(token));
+        sendMessageToDaemon(connection, 6, encodedMessage);
+    }
+}
+
+RetainPtr<xpc_connection_t> createAndConfigureConnectionToService(const char* serviceName)
+{
+    auto connection = adoptNS(xpc_connection_create_mach_service(serviceName, dispatch_get_main_queue(), 0));
+    xpc_connection_set_event_handler(connection.get(), ^(xpc_object_t) { });
+    xpc_connection_activate(connection.get());
+    sendConfigurationWithAuditToken(connection.get());
+
+    return WTFMove(connection);
+}
+
+static Vector<uint8_t> encodeString(const String& message)
+{
+    ASSERT(message.is8Bit());
+    auto utf8 = message.utf8();
+
+    Vector<uint8_t> result(utf8.length() + 5);
+    result[0] = static_cast<uint8_t>(utf8.length());
+    result[1] = static_cast<uint8_t>(utf8.length() >> 8);
+    result[2] = static_cast<uint8_t>(utf8.length() >> 16);
+    result[3] = static_cast<uint8_t>(utf8.length() >> 24);
+    result[4] = 0x01;
+
+    auto data = ""
+    for (size_t i = 0; i < utf8.length(); ++i)
+        result[5 + i] = data[i];
+
+    return result;
+}
+
 // FIXME: Re-enable this test on Mac once webkit.org/232857 is resolved.
 #if PLATFORM(MAC)
 TEST(WebPushD, DISABLED_BasicCommunication)
@@ -196,44 +275,20 @@
     });
 
     xpc_connection_activate(connection.get());
+    sendConfigurationWithAuditToken(connection.get());
 
-    audit_token_t token = { 0, 0, 0, 0, 0, 0, 0, 0 };
-    mach_msg_type_number_t auditTokenCount = TASK_AUDIT_TOKEN_COUNT;
-    kern_return_t result = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)(&token), &auditTokenCount);
-    if (result != KERN_SUCCESS) {
-        EXPECT_TRUE(false);
-        return;
-    }
-
-    // Send configuration with audit token
-    {
-        std::array<uint8_t, 42> encodedMessage;
-        encodedMessage.fill(0);
-        encodedMessage[1] = 1;
-        encodedMessage[2] = 32;
-        memcpy(&encodedMessage[10], &token, sizeof(token));
-        auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
-        xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
-        xpc_dictionary_set_uint64(dictionary.get(), "message type", 6);
-        xpc_dictionary_set_data(dictionary.get(), "encoded message", encodedMessage.data(), encodedMessage.size());
-        xpc_connection_send_message(connection.get(), dictionary.get());
-    }
-
     // Enable debug messages, and wait for the resulting debug message
     {
         auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
-        std::array<uint8_t, 1> encodedMessage { 1 };
-        xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
-        xpc_dictionary_set_uint64(dictionary.get(), "message type", 5);
-        xpc_dictionary_set_data(dictionary.get(), "encoded message", encodedMessage.data(), encodedMessage.size());
-
-        xpc_connection_send_message(connection.get(), dictionary.get());
+        Vector<uint8_t> encodedMessage(1);
+        encodedMessage[0] = 1;
+        sendMessageToDaemon(connection.get(), 5, encodedMessage);
         TestWebKitAPI::Util::run(&done);
     }
 
     // Echo and wait for a reply
     auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
-    std::array<uint8_t, 10> encodedString { 5, 0, 0, 0, 1, 'h', 'e', 'l', 'l', 'o' };
+    auto encodedString = encodeString("hello");
     xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
     xpc_dictionary_set_uint64(dictionary.get(), "message type", 1);
     xpc_dictionary_set_data(dictionary.get(), "encoded message", encodedString.data(), encodedString.size());
@@ -341,6 +396,140 @@
     cleanUpTestWebPushD(tempDirectory);
 }
 
+static const char* mainSWBytes = R"SWRESOURCE(
+<script>
+function log(msg)
+{
+    window.webkit.messageHandlers.sw.postMessage(msg);
+}
+
+const channel = new MessageChannel();
+channel.port1._onmessage_ = (event) => log(event.data);
+
+navigator.serviceWorker.register('/sw.js').then((registration) => {
+    if (registration.active) {
+        registration.active.postMessage({port: channel.port2}, [channel.port2]);
+        return;
+    }
+    worker = registration.installing;
+    worker.addEventListener('statechange', function() {
+        if (worker.state == 'activated')
+            worker.postMessage({port: channel.port2}, [channel.port2]);
+    });
+}).catch(function(error) {
+    log("Registration failed with: " + error);
+});
+</script>
+)SWRESOURCE";
+
+static const char* scriptBytes = R"SWRESOURCE(
+let port;
+self.addEventListener("message", (event) => {
+    port = event.data.port;
+    port.postMessage("Ready");
+});
+self.addEventListener("push", (event) => {
+    try {
+        if (!event.data) {
+            port.postMessage("Received: null data");
+            return;
+        }
+        const value = event.data.text();
+        port.postMessage("Received: " + value);
+        if (value != 'Sweet Potatoes')
+            event.waitUntil(Promise.reject('I want sweet potatoes'));
+    } catch (e) {
+        port.postMessage("Got exception " + e);
+    }
+});
+)SWRESOURCE";
+
+static void clearWebsiteDataStore(WKWebsiteDataStore *store)
+{
+    __block bool clearedStore = false;
+    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+        clearedStore = true;
+    }];
+    TestWebKitAPI::Util::run(&clearedStore);
+}
+
+// FIXME: Re-enable this test on Mac once webkit.org/232857 is resolved.
+#if PLATFORM(MAC)
+TEST(WebPushD, DISABLED_HandleInjectedPush)
+#else
+TEST(WebPushD, HandleInjectedPush)
+#endif
+{
+    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+    NSURL *tempDirectory = setUpTestWebPushD();
+
+    auto dataStoreConfiguration = adoptNS([_WKWebsiteDataStoreConfiguration new]);
+    dataStoreConfiguration.get().webPushMachServiceName = @"org.webkit.webpushtestdaemon.service";
+    dataStoreConfiguration.get().webPushDaemonUsesMockBundlesForTesting = YES;
+    auto dataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration.get()]);
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    configuration.get().websiteDataStore = dataStore.get();
+    clearWebsiteDataStore([configuration websiteDataStore]);
+
+    [configuration.get().preferences _setNotificationsEnabled:YES];
+    for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) {
+        if ([feature.key isEqualToString:@"BuiltInNotificationsEnabled"])
+            [[configuration preferences] _setEnabled:YES forFeature:feature];
+    }
+
+    auto messageHandler = adoptNS([[TestMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+    __block bool done = false;
+    [messageHandler addMessage:@"Ready" withHandler:^{
+        done = true;
+    }];
+    [messageHandler addMessage:@"Received: Hello World" withHandler:^{
+        done = true;
+    }];
+
+    TestWebKitAPI::HTTPServer server({
+        { "/", { mainSWBytes } },
+        { "/sw.js", { { { "Content-Type", "application/_javascript_" } }, scriptBytes } }
+    }, TestWebKitAPI::HTTPServer::Protocol::Http);
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView loadRequest:server.request()];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Inject push message
+    auto encodedMessage = encodeString("com.apple.WebKit.TestWebKitAPI");
+    encodedMessage.appendVector(encodeString(server.request().URL.absoluteString));
+    encodedMessage.appendVector(encodeString("Hello World"));
+
+    auto utilityConnection = createAndConfigureConnectionToService("org.webkit.webpushtestdaemon.service");
+    sendMessageToDaemonWaitingForReply(utilityConnection.get(), 7, encodedMessage);
+
+    // Fetch push messages
+    __block RetainPtr<NSArray<NSDictionary *>> messages;
+    [dataStore _getPendingPushMessages:^(NSArray<NSDictionary *> *rawMessages) {
+        messages = rawMessages;
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_EQ([messages count], 1u);
+
+    // Handle push message
+    __block bool pushMessageProcessed = false;
+    [dataStore _processPushMessage:[messages firstObject] completionHandler:^(bool result) {
+        pushMessageProcessed = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    TestWebKitAPI::Util::run(&pushMessageProcessed);
+
+    cleanUpTestWebPushD(tempDirectory);
+}
+
 } // namespace TestWebKitAPI
 
 #endif // PLATFORM(MAC) || PLATFORM(IOS)

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (286763 => 286764)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2021-12-09 06:34:52 UTC (rev 286763)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2021-12-09 06:37:26 UTC (rev 286764)
@@ -78,6 +78,7 @@
 
 @interface TestMessageHandler : NSObject <WKScriptMessageHandler>
 - (void)addMessage:(NSString *)message withHandler:(dispatch_block_t)handler;
+- (void)setWildcardMessageHandler:(void (^)(NSString *))handler;
 @end
 
 @interface TestWKWebView : WKWebView
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to