⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286788 in webkit


Ignore:
Timestamp:
Dec 9, 2021, 10:58:34 AM (5 years ago)
Author:
beidson@apple.com
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:
  • 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):

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:
Location:
trunk
Files:
28 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r286785 r286788  
     12021-12-09  Brady Eidson  <beidson@apple.com>
     2
     3        Add ability to inject messages into webpushd
     4        https://bugs.webkit.org/show_bug.cgi?id=233988
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by API tests.
     9
     10        This patch:
     11         - Adds WKWebsiteDataStore SPI to fetch pending push messages for the embedding application
     12         - Gives webpushd code to inject a push message for a given bundle identifier
     13         - Gives webpushtool the ability to send one of these fake messages
     14         - Gives webpushtool the ability to reconnect to the next daemon instance after the current connection is dropped
     15         - Tests the injection and fetching of push messages via TestWebKitAPI
     16
     17        * Configurations/webpushtool.xcconfig:
     18        * WebKit.xcodeproj/project.pbxproj:
     19        * Resources/webpushtool.entitlements:
     20
     21        * NetworkProcess/NetworkProcess.cpp:
     22        (WebKit::NetworkProcess::getPendingPushMessages):
     23        (WebKit::NetworkProcess::processPushMessage):
     24        * NetworkProcess/NetworkProcess.h:
     25        * NetworkProcess/NetworkProcess.messages.in:
     26
     27        * NetworkProcess/Notifications/NetworkNotificationManager.cpp:
     28        (WebKit::NetworkNotificationManager::getPendingPushMessages):
     29        (WebKit::ReplyCaller<Vector<WebPushMessage>::callReply):
     30        * NetworkProcess/Notifications/NetworkNotificationManager.h:
     31
     32        * Shared/Cocoa/WebPushMessageCocoa.mm: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
     33        (WebKit::WebPushMessage::fromDictionary):
     34        (WebKit::WebPushMessage::toDictionary const):
     35
     36        * Shared/PushMessageForTesting.h: Copied from Source/WebKit/Shared/WebPushDaemonConstants.h.
     37        (WebKit::WebPushD::PushMessageForTesting::encode const):
     38        (WebKit::WebPushD::PushMessageForTesting::decode):
     39
     40        * Shared/WebPushDaemonConstants.h:
     41        (WebKit::WebPushD::messageTypeSendsReply):
     42
     43        * Shared/WebPushMessage.h: Copied from Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h.
     44        (WebKit::WebPushMessage::encode const):
     45        (WebKit::WebPushMessage::decode):
     46
     47        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
     48        (-[WKWebsiteDataStore _getPendingPushMessages:]):
     49        (-[WKWebsiteDataStore _processPushMessage:completionHandler:]):
     50        (-[WKWebsiteDataStore _processPushMessage:registration:completionHandler:]): Deleted.
     51        * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
     52
     53        * UIProcess/Network/NetworkProcessProxy.cpp:
     54        (WebKit::NetworkProcessProxy::getPendingPushMessages):
     55        (WebKit::NetworkProcessProxy::processPushMessage):
     56        * UIProcess/Network/NetworkProcessProxy.h:
     57
     58        * webpushd/PushClientConnection.h:
     59        * webpushd/PushClientConnection.mm:
     60        (WebPushD::ClientConnection::hostAppHasPushEntitlement):
     61        (WebPushD::ClientConnection::hostAppHasPushInjectEntitlement):
     62        (WebPushD::ClientConnection::hostHasEntitlement):
     63        (WebPushD::ClientConnection::broadcastDebugMessage):
     64
     65        * webpushd/WebPushDaemon.h:
     66        * webpushd/WebPushDaemon.mm:
     67        (WebPushD::MessageInfo::injectPushMessageForTesting::encodeReply):
     68        (WebPushD::MessageInfo::getPendingPushMessages::encodeReply):
     69        (WebPushD::Daemon::decodeAndHandleMessage):
     70        (WebPushD::Daemon::injectPushMessageForTesting):
     71        (WebPushD::Daemon::getPendingPushMessages):
     72
     73        * webpushd/webpushtool/WebPushToolConnection.h:
     74        (WebPushTool::Connection::setPushMessage):
     75
     76        * webpushd/webpushtool/WebPushToolConnection.mm:
     77        (WebPushTool::Connection::startAction):
     78        (WebPushTool::Connection::sendPushMessage):
     79
     80        * webpushd/webpushtool/WebPushToolMain.mm:
     81        (printUsageAndTerminate):
     82        (pushMessageFromArguments):
     83        (main):
     84
    1852021-12-09  J Pascoe  <j_pascoe@apple.com>
    286
  • trunk/Source/WebKit/Configurations/webpushtool.xcconfig

    r286777 r286788  
    3030EXCLUDED_SOURCE_FILE_NAMES[sdk=watch*] = *;
    3131
    32 OTHER_LDFLAGS = -l WTF -framework Foundation -framework CoreFoundation;
     32OTHER_LDFLAGS = -framework WebKit -framework JavaScriptCore
    3333LIBRARY_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR);
    3434
  • trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp

    r286777 r286788  
    5959#include "WebPageProxyMessages.h"
    6060#include "WebProcessPoolMessages.h"
     61#include "WebPushMessage.h"
    6162#include "WebResourceLoadStatisticsStore.h"
    6263#include "WebSWOriginStore.h"
     
    25562557}
    25572558
    2558 void NetworkProcess::processPushMessage(PAL::SessionID sessionID, const std::optional<IPC::DataReference>& ipcData, URL&& registrationURL, CompletionHandler<void(bool)>&& callback)
    2559 {
    2560     std::optional<Vector<uint8_t>> data;
    2561     if (ipcData)
    2562         data = Vector<uint8_t> { ipcData->data(), ipcData->size() };
    2563     swServerForSession(sessionID).processPushMessage(WTFMove(data), WTFMove(registrationURL), WTFMove(callback));
     2559void NetworkProcess::getPendingPushMessages(PAL::SessionID sessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&& callback)
     2560{
     2561#if ENABLE(BUILT_IN_NOTIFICATIONS)
     2562    if (auto* session = networkSession(sessionID)) {
     2563        session->notificationManager().getPendingPushMessages(WTFMove(callback));
     2564        return;
     2565    }
     2566#endif
     2567    callback({ });
     2568}
     2569
     2570void NetworkProcess::processPushMessage(PAL::SessionID sessionID, WebPushMessage&& pushMessage, CompletionHandler<void(bool)>&& callback)
     2571{
     2572    swServerForSession(sessionID).processPushMessage(WTFMove(pushMessage.pushData), WTFMove(pushMessage.registrationURL), WTFMove(callback));
    25642573}
    25652574#endif // ENABLE(SERVICE_WORKER)
  • trunk/Source/WebKit/NetworkProcess/NetworkProcess.h

    r286777 r286788  
    118118enum class WebsiteDataType : uint32_t;
    119119struct NetworkProcessCreationParameters;
     120struct WebPushMessage;
    120121struct WebsiteDataStoreParameters;
    121122
     
    397398
    398399#if ENABLE(SERVICE_WORKER)
    399     void processPushMessage(PAL::SessionID, const std::optional<IPC::DataReference>&, URL&&, CompletionHandler<void(bool)>&&);
     400    void getPendingPushMessages(PAL::SessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
     401    void processPushMessage(PAL::SessionID, WebPushMessage&&, CompletionHandler<void(bool)>&&);
    400402#endif
    401403
  • trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in

    r286777 r286788  
    208208
    209209#if ENABLE(SERVICE_WORKER)
    210     ProcessPushMessage(PAL::SessionID sessionID, std::optional<IPC::DataReference> data, URL registrationURL) -> (bool didSucceed) Async
     210    GetPendingPushMessages(PAL::SessionID sessionID) -> (Vector<WebKit::WebPushMessage> messages) Async
     211    ProcessPushMessage(PAL::SessionID sessionID, struct WebKit::WebPushMessage pushMessage) -> (bool didSucceed) Async
    211212#endif
    212213    DeletePushAndNotificationRegistration(PAL::SessionID sessionID, struct WebCore::SecurityOriginData origin) -> (String errorMessage) Async
  • trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp

    r286777 r286788  
    3333#include "NetworkSession.h"
    3434#include "WebPushDaemonConnectionConfiguration.h"
     35#include "WebPushMessage.h"
    3536#include <WebCore/SecurityOriginData.h>
    3637
     
    8788
    8889    sendMessageWithReply<WebPushD::MessageType::GetOriginsWithPushAndNotificationPermissions>(WTFMove(replyHandler));
     90}
     91
     92void NetworkNotificationManager::getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
     93{
     94    CompletionHandler<void(Vector<WebPushMessage>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<WebPushMessage>&& messages) mutable {
     95        completionHandler(WTFMove(messages));
     96    };
     97
     98    sendMessageWithReply<WebPushD::MessageType::GetPendingPushMessages>(WTFMove(replyHandler));
    8999}
    90100
     
    187197};
    188198
     199template<> struct ReplyCaller<Vector<WebPushMessage>&&> {
     200    static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<WebPushMessage>&&)>&& completionHandler)
     201    {
     202        std::optional<Vector<WebPushMessage>> messages;
     203        decoder >> messages;
     204        if (!messages)
     205            return completionHandler({ });
     206        completionHandler(WTFMove(*messages));
     207    }
     208};
     209
    189210template<WebPushD::MessageType messageType, typename... Args, typename... ReplyArgs>
    190211void NetworkNotificationManager::sendMessageWithReply(CompletionHandler<void(ReplyArgs...)>&& completionHandler, Args&&... args) const
  • trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h

    r286777 r286788  
    3030#include "NotificationManagerMessageHandler.h"
    3131#include "WebPushDaemonConnection.h"
     32#include "WebPushMessage.h"
    3233#include <WebCore/NotificationDirection.h>
    3334#include <wtf/text/WTFString.h>
     
    5354    void deletePushAndNotificationRegistration(const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);
    5455    void getOriginsWithPushAndNotificationPermissions(CompletionHandler<void(const Vector<WebCore::SecurityOriginData>&)>&&);
     56    void getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
    5557
    5658private:
  • trunk/Source/WebKit/Resources/webpushtool.entitlements

    r286777 r286788  
    55        <key>com.apple.private.webkit.webpush</key>
    66        <true/>
     7        <key>com.apple.private.webkit.webpush.inject</key>
     8        <true/>
    79</dict>
    810</plist>
  • trunk/Source/WebKit/Shared/Cocoa/WebPushMessageCocoa.mm

    r286787 r286788  
    2424 */
    2525
    26 #pragma once
     26#import "config.h"
     27#import "WebPushMessage.h"
    2728
    28 #include <memory>
    29 #include <wtf/RetainPtr.h>
    30 #include <wtf/WeakPtr.h>
    31 #include <wtf/spi/darwin/XPCSPI.h>
     29#import <wtf/RetainPtr.h>
    3230
    33 namespace WebPushTool {
     31namespace WebKit {
    3432
    35 enum class Action {
    36     StreamDebugMessages,
    37 };
     33#define WebKitPushDataKey @"WebKitPushData"
     34#define WebKitPushRegistrationURLKey @"WebKitPushRegistrationURL"
    3835
    39 enum class PreferTestService : bool {
    40     Yes,
    41     No,
    42 };
     36std::optional<WebPushMessage> WebPushMessage::fromDictionary(NSDictionary *dictionary)
     37{
     38    NSURL *url = [dictionary objectForKey:WebKitPushRegistrationURLKey];
     39    if (!url || ![url isKindOfClass:[NSURL class]])
     40        return std::nullopt;
    4341
    44 enum class Reconnect : bool {
    45     Yes,
    46     No,
    47 };
     42    NSData *pushData = [dictionary objectForKey:WebKitPushDataKey];
     43    if (!pushData || ![pushData isKindOfClass:[NSData class]])
     44        return std::nullopt;
    4845
    49 class Connection : public CanMakeWeakPtr<Connection> {
    50     WTF_MAKE_FAST_ALLOCATED;
    51 public:
    52     static std::unique_ptr<Connection> create(Action, PreferTestService, Reconnect);
    53     Connection(Action, PreferTestService, Reconnect);
     46    return { {
     47        Vector<uint8_t> { static_cast<const uint8_t*>(pushData.bytes), pushData.length },
     48        URL { url }
     49    } };
     50}
    5451
    55     void connectToService();
     52NSDictionary *WebPushMessage::toDictionary() const
     53{
     54    auto nsData = adoptNS([[NSData alloc] initWithBytes:pushData.data() length:pushData.size()]);
     55    return @{
     56        WebKitPushDataKey : nsData.get(),
     57        WebKitPushRegistrationURLKey : (NSURL *)registrationURL
     58    };
     59}
    5660
    57 private:
    58     void messageReceived(xpc_object_t);
    59     void connectionDropped();
    60 
    61     void startAction();
    62     void startDebugStreamAction();
    63 
    64     void sendAuditToken();
    65    
    66     Action m_action;
    67     bool m_reconnect { false };
    68     RetainPtr<xpc_connection_t> m_connection;
    69     const char* m_serviceName;
    70 };
    71 
    72 } // namespace WebPushTool
     61} // namespace WebKit
  • trunk/Source/WebKit/Shared/PushMessageForTesting.h

    r286787 r286788  
    2626#pragma once
    2727
     28#include <wtf/URL.h>
     29#include <wtf/text/WTFString.h>
     30
    2831namespace WebKit::WebPushD {
    2932
    30 constexpr const char* protocolVersionKey = "protocol version";
    31 constexpr uint64_t protocolVersionValue = 1;
    32 constexpr const char* protocolEncodedMessageKey = "encoded message";
     33struct PushMessageForTesting {
     34    template<class Encoder> void encode(Encoder&) const;
     35    template<class Decoder> static std::optional<PushMessageForTesting> decode(Decoder&);
    3336
    34 constexpr const char* protocolDebugMessageKey { "debug message" };
    35 constexpr const char* protocolDebugMessageLevelKey { "debug message level" };
    36 
    37 constexpr const char* protocolMessageTypeKey { "message type" };
    38 enum class MessageType : uint8_t {
    39     EchoTwice = 1,
    40     RequestSystemNotificationPermission,
    41     DeletePushAndNotificationRegistration,
    42     GetOriginsWithPushAndNotificationPermissions,
    43     SetDebugModeIsEnabled,
    44     UpdateConnectionConfiguration,
     37    String targetAppCodeSigningIdentifier;
     38    URL registrationURL;
     39    String message;
    4540};
    4641
    47 inline bool messageTypeSendsReply(MessageType messageType)
     42template<class Encoder>
     43void PushMessageForTesting::encode(Encoder& encoder) const
    4844{
    49     switch (messageType) {
    50     case MessageType::EchoTwice:
    51     case MessageType::GetOriginsWithPushAndNotificationPermissions:
    52     case MessageType::DeletePushAndNotificationRegistration:
    53     case MessageType::RequestSystemNotificationPermission:
    54         return true;
    55     case MessageType::SetDebugModeIsEnabled:
    56     case MessageType::UpdateConnectionConfiguration:
    57         return false;
    58     }
    59     ASSERT_NOT_REACHED();
    60     return false;
     45    encoder << targetAppCodeSigningIdentifier << registrationURL << message;
     46}
     47
     48template<class Decoder>
     49std::optional<PushMessageForTesting> PushMessageForTesting::decode(Decoder& decoder)
     50{
     51    std::optional<String> targetAppCodeSigningIdentifier;
     52    decoder >> targetAppCodeSigningIdentifier;
     53    if (!targetAppCodeSigningIdentifier)
     54        return std::nullopt;
     55
     56    std::optional<URL> registrationURL;
     57    decoder >> registrationURL;
     58    if (!registrationURL)
     59        return std::nullopt;
     60
     61    std::optional<String> message;
     62    decoder >> message;
     63    if (!message)
     64        return std::nullopt;
     65
     66    return { {
     67        WTFMove(*targetAppCodeSigningIdentifier),
     68        WTFMove(*registrationURL),
     69        WTFMove(*message),
     70    } };
    6171}
    6272
  • trunk/Source/WebKit/Shared/WebPushDaemonConstants.h

    r286777 r286788  
    4343    SetDebugModeIsEnabled,
    4444    UpdateConnectionConfiguration,
     45    InjectPushMessageForTesting,
     46    GetPendingPushMessages,
    4547};
    4648
     
    5254    case MessageType::DeletePushAndNotificationRegistration:
    5355    case MessageType::RequestSystemNotificationPermission:
     56    case MessageType::GetPendingPushMessages:
     57    case MessageType::InjectPushMessageForTesting:
    5458        return true;
    5559    case MessageType::SetDebugModeIsEnabled:
  • trunk/Source/WebKit/Shared/WebPushMessage.h

    r286787 r286788  
    2626#pragma once
    2727
    28 #include <memory>
    29 #include <wtf/RetainPtr.h>
    30 #include <wtf/WeakPtr.h>
    31 #include <wtf/spi/darwin/XPCSPI.h>
     28#include <optional>
     29#include <wtf/URL.h>
     30#include <wtf/Vector.h>
    3231
    33 namespace WebPushTool {
     32OBJC_CLASS NSDictionary;
    3433
    35 enum class Action {
    36     StreamDebugMessages,
     34namespace WebKit {
     35
     36struct WebPushMessage {
     37    template<class Encoder> void encode(Encoder&) const;
     38    template<class Decoder> static std::optional<WebPushMessage> decode(Decoder&);
     39
     40    Vector<uint8_t> pushData;
     41    URL registrationURL;
     42
     43#if PLATFORM(COCOA)
     44    static std::optional<WebPushMessage> fromDictionary(NSDictionary *);
     45    NSDictionary *toDictionary() const;
     46#endif
    3747};
    3848
    39 enum class PreferTestService : bool {
    40     Yes,
    41     No,
    42 };
     49template<class Encoder>
     50void WebPushMessage::encode(Encoder& encoder) const
     51{
     52    encoder << pushData << registrationURL;
     53}
    4354
    44 enum class Reconnect : bool {
    45     Yes,
    46     No,
    47 };
     55template<class Decoder>
     56std::optional<WebPushMessage> WebPushMessage::decode(Decoder& decoder)
     57{
     58    std::optional<Vector<uint8_t>> pushData;
     59    decoder >> pushData;
     60    if (!pushData)
     61        return std::nullopt;
    4862
    49 class Connection : public CanMakeWeakPtr<Connection> {
    50     WTF_MAKE_FAST_ALLOCATED;
    51 public:
    52     static std::unique_ptr<Connection> create(Action, PreferTestService, Reconnect);
    53     Connection(Action, PreferTestService, Reconnect);
     63    std::optional<URL> registrationURL;
     64    decoder >> registrationURL;
     65    if (!registrationURL)
     66        return std::nullopt;
    5467
    55     void connectToService();
     68    return { {
     69        WTFMove(*pushData),
     70        WTFMove(*registrationURL)
     71    } };
     72}
    5673
    57 private:
    58     void messageReceived(xpc_object_t);
    59     void connectionDropped();
    60 
    61     void startAction();
    62     void startDebugStreamAction();
    63 
    64     void sendAuditToken();
    65    
    66     Action m_action;
    67     bool m_reconnect { false };
    68     RetainPtr<xpc_connection_t> m_connection;
    69     const char* m_serviceName;
    70 };
    71 
    72 } // namespace WebPushTool
     74} // namespace WebKit
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm

    r286777 r286788  
    4040#import "WKWebsiteDataRecordInternal.h"
    4141#import "WebPageProxy.h"
     42#import "WebPushMessage.h"
    4243#import "WebResourceLoadStatisticsStore.h"
    4344#import "WebsiteDataFetchOption.h"
     
    762763}
    763764
    764 -(void)_processPushMessage:(NSData*) message registration:(NSURL *)registration completionHandler:(void(^)(bool wasProcessed))completionHandler
     765-(void)_getPendingPushMessages:(void(^)(NSArray<NSDictionary *> *))completionHandler
    765766{
    766767#if ENABLE(SERVICE_WORKER)
    767     std::optional<Span<const uint8_t>> data;
    768     if (message)
    769         data = Span<const uint8_t> { reinterpret_cast<const uint8_t*>(message.bytes), message.length };
    770     _websiteDataStore->networkProcess().processPushMessage(_websiteDataStore->sessionID(), data, registration, [completionHandler = makeBlockPtr(completionHandler)] (bool wasProcessed) {
     768    _websiteDataStore->networkProcess().getPendingPushMessages(_websiteDataStore->sessionID(), [completionHandler = makeBlockPtr(completionHandler)] (const Vector<WebKit::WebPushMessage>& messages) {
     769        auto result = adoptNS([[NSMutableArray alloc] initWithCapacity:messages.size()]);
     770        for (auto& message : messages)
     771            [result addObject:message.toDictionary()];
     772
     773        completionHandler(result.get());
     774    });
     775#endif
     776}
     777
     778-(void)_processPushMessage:(NSDictionary *)pushMessageDictionary completionHandler:(void(^)(bool wasProcessed))completionHandler
     779{
     780#if ENABLE(SERVICE_WORKER)
     781    auto pushMessage = WebKit::WebPushMessage::fromDictionary(pushMessageDictionary);
     782    if (!pushMessage) {
     783        completionHandler(false);
     784        return;
     785    }
     786
     787    _websiteDataStore->networkProcess().processPushMessage(_websiteDataStore->sessionID(), *pushMessage, [completionHandler = makeBlockPtr(completionHandler)] (bool wasProcessed) {
    771788        completionHandler(wasProcessed);
    772789    });
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h

    r286777 r286788  
    109109
    110110-(bool)_hasServiceWorkerBackgroundActivityForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    111 -(void)_processPushMessage:(NSData*)data registration:(NSURL *)registration completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
     111-(void)_getPendingPushMessages:(void(^)(NSArray<NSDictionary *> *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
     112-(void)_processPushMessage:(NSDictionary *)pushMessage completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    112113-(void)_deletePushAndNotificationRegistration:(WKSecurityOrigin *)securityOrigin completionHandler:(void(^)(NSError *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    113114-(void)_getOriginsWithPushAndNotificationPermissions:(void(^)(NSSet<WKSecurityOrigin *> *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp

    r286777 r286788  
    16931693
    16941694#if ENABLE(SERVICE_WORKER)
    1695 void NetworkProcessProxy::processPushMessage(PAL::SessionID sessionID, std::optional<Span<const uint8_t>> data, const URL& registrationURL, CompletionHandler<void(bool wasProcessed)>&& callback)
    1696 {
    1697     std::optional<IPC::DataReference> ipcData;
    1698     if (data)
    1699         ipcData = IPC::DataReference { data->data(), data->size() };
    1700     sendWithAsyncReply(Messages::NetworkProcess::ProcessPushMessage { sessionID, ipcData, registrationURL }, WTFMove(callback));
     1695void NetworkProcessProxy::getPendingPushMessages(PAL::SessionID sessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
     1696{
     1697    sendWithAsyncReply(Messages::NetworkProcess::GetPendingPushMessages { sessionID }, WTFMove(completionHandler));
     1698}
     1699
     1700void NetworkProcessProxy::processPushMessage(PAL::SessionID sessionID, const WebPushMessage& pushMessage, CompletionHandler<void(bool wasProcessed)>&& callback)
     1701{
     1702    sendWithAsyncReply(Messages::NetworkProcess::ProcessPushMessage { sessionID, pushMessage }, WTFMove(callback));
    17011703}
    17021704#endif // ENABLE(SERVICE_WORKER)
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h

    r286777 r286788  
    9393struct NetworkProcessCreationParameters;
    9494struct ResourceLoadInfo;
     95struct WebPushMessage;
    9596struct WebsiteData;
    9697struct WebsiteDataStoreParameters;
     
    274275
    275276#if ENABLE(SERVICE_WORKER)
    276     void processPushMessage(PAL::SessionID, std::optional<Span<const uint8_t>>, const URL&, CompletionHandler<void(bool wasProcessed)>&&);
     277    void getPendingPushMessages(PAL::SessionID, CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
     278    void processPushMessage(PAL::SessionID, const WebPushMessage&, CompletionHandler<void(bool wasProcessed)>&&);
    277279#endif
    278280
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r286777 r286788  
    10351035                517B5F85275E97B6002DC22D /* AppBundleRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 5160E954274B887100567388 /* AppBundleRequest.h */; };
    10361036                517B5F86275E97B6002DC22D /* MockAppBundleRegistry.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5160E95F274C2A3F00567388 /* MockAppBundleRegistry.mm */; };
     1037                517B5F95275EBA63002DC22D /* PushMessageForTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = 517B5F94275EBA62002DC22D /* PushMessageForTesting.h */; };
     1038                517B5F97275EC5E5002DC22D /* WebPushMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 517B5F96275EC5E5002DC22D /* WebPushMessage.h */; };
     1039                517B5F99275EC601002DC22D /* WebPushMessageCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */; };
     1040                517B5F9A275F3A86002DC22D /* ArgumentCoders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A3D610413A7F03A00F95D4E /* ArgumentCoders.cpp */; };
     1041                517B5F9B275F3A98002DC22D /* DaemonUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C1579F92717AF5000ED5280 /* DaemonUtilities.mm */; };
     1042                517B5F9C275F3C37002DC22D /* DaemonEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C1579E827172A8A00ED5280 /* DaemonEncoder.cpp */; };
    10371043                517CF0E3163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */; };
    10381044                517CF0E3163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */; };
     
    21402146                        remoteGlobalIDString = 517B5F5A275A8D3E002DC22D;
    21412147                        remoteInfo = webpushtool;
     2148                };
     2149                519797C627627B1D00BE0F83 /* PBXContainerItemProxy */ = {
     2150                        isa = PBXContainerItemProxy;
     2151                        containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
     2152                        proxyType = 1;
     2153                        remoteGlobalIDString = E1AC2E2720F7B94C00B0897D;
     2154                        remoteInfo = "Unlock Keychain";
     2155                };
     2156                519797C827627B2300BE0F83 /* PBXContainerItemProxy */ = {
     2157                        isa = PBXContainerItemProxy;
     2158                        containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
     2159                        proxyType = 1;
     2160                        remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
     2161                        remoteInfo = WebKit;
    21422162                };
    21432163                5742A2E72535613F00B7BA14 /* PBXContainerItemProxy */ = {
     
    44104430                517B5F72275E9609002DC22D /* WebPushDaemonMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPushDaemonMain.h; sourceTree = "<group>"; };
    44114431                517B5F77275E9795002DC22D /* webpushd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = webpushd.cpp; sourceTree = "<group>"; };
     4432                517B5F94275EBA62002DC22D /* PushMessageForTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushMessageForTesting.h; sourceTree = "<group>"; };
     4433                517B5F96275EC5E5002DC22D /* WebPushMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPushMessage.h; sourceTree = "<group>"; };
     4434                517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPushMessageCocoa.mm; sourceTree = "<group>"; };
    44124435                517CF0E1163A486C00C2950E /* NetworkProcessConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkProcessConnectionMessageReceiver.cpp; path = DerivedSources/WebKit/NetworkProcessConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
    44134436                517CF0E1163A486C00C2950F /* CacheStorageEngineConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheStorageEngineConnectionMessageReceiver.cpp; path = DerivedSources/WebKit/CacheStorageEngineConnectionMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
     
    71377160                                E1CC1B8E12D7EADF00625838 /* PrintInfo.h */,
    71387161                                463FD4811EB94EAD00A2982C /* ProcessTerminationReason.h */,
     7162                                517B5F94275EBA62002DC22D /* PushMessageForTesting.h */,
    71397163                                9B1229D023FF2A5E008CA751 /* RemoteAudioDestinationIdentifier.h */,
    71407164                                7203449B26A6C476000A5F54 /* RenderingUpdateID.h */,
     
    72437267                                517B5F2D2757382A002DC22D /* WebPushDaemonConnectionConfiguration.h */,
    72447268                                512CD6992721F04900F7F8EC /* WebPushDaemonConstants.h */,
     7269                                517B5F96275EC5E5002DC22D /* WebPushMessage.h */,
    72457270                                5C8DD37F1FE4519200F2A556 /* WebsiteAutoplayPolicy.h */,
    72467271                                5C8DD3811FE455CA00F2A556 /* WebsiteAutoplayQuirk.h */,
     
    89398964                                465250E51ECF52CD002025CB /* WebKit2InitializeCocoa.mm */,
    89408965                                1DE076D92460CCBD00B211E8 /* WebPreferencesDefaultValuesCocoa.mm */,
     8966                                517B5F98275EC600002DC22D /* WebPushMessageCocoa.mm */,
    89418967                                37C4C0921814B3AF003688B9 /* WKNSArray.h */,
    89428968                                37C4C0911814B3AF003688B9 /* WKNSArray.mm */,
     
    1301413040                                839902031BE9A02B000F3653 /* NetworkLoad.h in Headers */,
    1301513041                                83D454D71BE9D3C4006C93BD /* NetworkLoadClient.h in Headers */,
     13042                                517B5F97275EC5E5002DC22D /* WebPushMessage.h in Headers */,
    1301613043                                839149651BEA838500D2D953 /* NetworkLoadParameters.h in Headers */,
    1301713044                                E47FC8A025B8331C005495FC /* NetworkLoadScheduler.h in Headers */,
     
    1352113548                                517A53101F47A86200DCDC0A /* WebSWClientConnectionMessages.h in Headers */,
    1352213549                                466BC03C1FA266DA002FA9C1 /* WebSWContextManagerConnection.h in Headers */,
     13550                                517B5F95275EBA63002DC22D /* PushMessageForTesting.h in Headers */,
    1352313551                                460F48901F996F7100CF4B87 /* WebSWContextManagerConnectionMessages.h in Headers */,
    1352413552                                C11A9ECC214035F800CFB20A /* WebSwitchingGPUClient.h in Headers */,
     
    1404214070                        );
    1404314071                        dependencies = (
     14072                                519797C927627B2300BE0F83 /* PBXTargetDependency */,
     14073                                519797C727627B1D00BE0F83 /* PBXTargetDependency */,
    1404414074                        );
    1404514075                        name = webpushtool;
     
    1508615116                        buildActionMask = 2147483647;
    1508715117                        files = (
     15118                                517B5F9A275F3A86002DC22D /* ArgumentCoders.cpp in Sources */,
    1508815119                                517B5F68275A9A78002DC22D /* WebPushToolConnection.mm in Sources */,
     15120                                517B5F9B275F3A98002DC22D /* DaemonUtilities.mm in Sources */,
     15121                                517B5F9C275F3C37002DC22D /* DaemonEncoder.cpp in Sources */,
    1508915122                                517B5F65275A8D7F002DC22D /* WebPushToolMain.mm in Sources */,
    1509015123                        );
     
    1518215215                                C1A152D724E5A29A00978C8B /* HandleXPCEndpointMessages.mm in Sources */,
    1518315216                                2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */,
     15217                                517B5F99275EC601002DC22D /* WebPushMessageCocoa.mm in Sources */,
    1518415218                                2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */,
    1518515219                                9BF5EC642541145600984E77 /* JSIPCBinding.cpp in Sources */,
     
    1566215696                        targetProxy = 517B5F6C275B07C3002DC22D /* PBXContainerItemProxy */;
    1566315697                };
     15698                519797C727627B1D00BE0F83 /* PBXTargetDependency */ = {
     15699                        isa = PBXTargetDependency;
     15700                        target = E1AC2E2720F7B94C00B0897D /* Unlock Keychain */;
     15701                        targetProxy = 519797C627627B1D00BE0F83 /* PBXContainerItemProxy */;
     15702                };
     15703                519797C927627B2300BE0F83 /* PBXTargetDependency */ = {
     15704                        isa = PBXTargetDependency;
     15705                        target = 8DC2EF4F0486A6940098B216 /* WebKit */;
     15706                        targetProxy = 519797C827627B2300BE0F83 /* PBXContainerItemProxy */;
     15707                };
    1566415708                5742A2E62535613F00B7BA14 /* PBXTargetDependency */ = {
    1566515709                        isa = PBXTargetDependency;
  • trunk/Source/WebKit/webpushd/PushClientConnection.h

    r286777 r286788  
    5757    const String& hostAppCodeSigningIdentifier();
    5858    bool hostAppHasPushEntitlement();
     59    bool hostAppHasPushInjectEntitlement();
    5960
    6061    bool debugModeIsEnabled() const { return m_debugModeEnabled; }
     
    7677    void setHostAppAuditTokenData(const Vector<uint8_t>&);
    7778
     79    bool hostHasEntitlement(const char*);
     80
    7881    OSObjectPtr<xpc_connection_t> m_xpcConnection;
    7982
  • trunk/Source/WebKit/webpushd/PushClientConnection.mm

    r286777 r286788  
    9090bool ClientConnection::hostAppHasPushEntitlement()
    9191{
    92     if (!m_hostAppHasPushEntitlement) {
    93         if (!m_hostAppAuditToken)
    94             return false;
    95         m_hostAppHasPushEntitlement = WTF::hasEntitlement(*m_hostAppAuditToken, "com.apple.private.webkit.webpush");
    96     }
     92    if (!m_hostAppHasPushEntitlement)
     93        m_hostAppHasPushEntitlement = hostHasEntitlement("com.apple.private.webkit.webpush"_s);
    9794
    9895    return *m_hostAppHasPushEntitlement;
     96}
     97
     98bool ClientConnection::hostAppHasPushInjectEntitlement()
     99{
     100    return hostHasEntitlement("com.apple.private.webkit.webpush.inject"_s);
     101}
     102
     103bool ClientConnection::hostHasEntitlement(const char* entitlement)
     104{
     105    if (!m_hostAppAuditToken)
     106        return false;
     107    return WTF::hasEntitlement(*m_hostAppAuditToken, entitlement);
    99108}
    100109
     
    113122    auto signingIdentifer = hostAppCodeSigningIdentifier();
    114123    if (signingIdentifer.isEmpty())
    115         messageIdentifier = makeString ("[(0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
     124        messageIdentifier = makeString("[(0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
    116125    else
    117         messageIdentifier = makeString ("[", signingIdentifer, " (0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
     126        messageIdentifier = makeString("[", signingIdentifer, " (0x", hex(reinterpret_cast<uint64_t>(m_xpcConnection.get()), WTF::HexConversionMode::Lowercase), ")] ");
    118127
    119128    Daemon::singleton().broadcastDebugMessage(JSC::MessageLevel::Info, makeString(messageIdentifier, message));
  • trunk/Source/WebKit/webpushd/WebPushDaemon.h

    r286777 r286788  
    2727
    2828#include "PushClientConnection.h"
     29#include "PushMessageForTesting.h"
    2930#include "WebPushDaemonConnectionConfiguration.h"
    3031#include "WebPushDaemonConstants.h"
     32#include "WebPushMessage.h"
     33#include <wtf/Deque.h>
    3134#include <wtf/Forward.h>
    3235#include <wtf/HashMap.h>
     
    4144}
    4245
     46using WebKit::WebPushD::PushMessageForTesting;
    4347using WebKit::WebPushD::WebPushDaemonConnectionConfiguration;
    4448
     
    6367    void setDebugModeIsEnabled(ClientConnection*, bool);
    6468    void updateConnectionConfiguration(ClientConnection*, const WebPushDaemonConnectionConfiguration&);
     69    void injectPushMessageForTesting(ClientConnection*, const PushMessageForTesting&, CompletionHandler<void(bool)>&&);
     70    void getPendingPushMessages(ClientConnection*, CompletionHandler<void(const Vector<WebKit::WebPushMessage>&)>&& replySender);
    6571
    6672    void broadcastDebugMessage(JSC::MessageLevel, const String&);
     
    7682    ClientConnection* toClientConnection(xpc_connection_t);
    7783    HashMap<xpc_connection_t, Ref<ClientConnection>> m_connectionMap;
     84
     85    HashMap<String, Deque<PushMessageForTesting>> m_testingPushMessages;
    7886};
    7987
  • trunk/Source/WebKit/webpushd/WebPushDaemon.mm

    r286777 r286788  
    7171END
    7272
     73FUNCTION(getPendingPushMessages)
     74ARGUMENTS()
     75REPLY(const Vector<WebKit::WebPushMessage>&)
     76END
     77
    7378FUNCTION(setDebugModeIsEnabled)
    7479ARGUMENTS(bool)
     
    7782FUNCTION(updateConnectionConfiguration)
    7883ARGUMENTS(WebPushDaemonConnectionConfiguration)
     84END
     85
     86FUNCTION(injectPushMessageForTesting)
     87ARGUMENTS(PushMessageForTesting)
     88REPLY(bool)
    7989END
    8090
     
    106116
    107117WebPushD::EncodedMessage requestSystemNotificationPermission::encodeReply(bool reply)
     118{
     119    WebKit::Daemon::Encoder encoder;
     120    encoder << reply;
     121    return encoder.takeBuffer();
     122}
     123
     124WebPushD::EncodedMessage injectPushMessageForTesting::encodeReply(bool reply)
     125{
     126    WebKit::Daemon::Encoder encoder;
     127    encoder << reply;
     128    return encoder.takeBuffer();
     129}
     130
     131WebPushD::EncodedMessage getPendingPushMessages::encodeReply(const Vector<WebKit::WebPushMessage>& reply)
    108132{
    109133    WebKit::Daemon::Encoder encoder;
     
    234258        handleWebPushDMessage<MessageInfo::updateConnectionConfiguration>(clientConnection, encodedMessage);
    235259        break;
     260    case MessageType::InjectPushMessageForTesting:
     261        handleWebPushDMessageWithReply<MessageInfo::injectPushMessageForTesting>(clientConnection, encodedMessage, WTFMove(replySender));
     262        break;
     263    case MessageType::GetPendingPushMessages:
     264        handleWebPushDMessageWithReply<MessageInfo::getPendingPushMessages>(clientConnection, encodedMessage, WTFMove(replySender));
     265        break;
    236266    }
    237267}
     
    298328}
    299329
     330void Daemon::injectPushMessageForTesting(ClientConnection* connection, const PushMessageForTesting& message, CompletionHandler<void(bool)>&& replySender)
     331{
     332    if (!connection->hostAppHasPushInjectEntitlement()) {
     333        connection->broadcastDebugMessage("Attempting to inject a push message from an unentitled process");
     334        replySender(false);
     335        return;
     336    }
     337
     338    if (message.targetAppCodeSigningIdentifier.isEmpty() || !message.registrationURL.isValid()) {
     339        connection->broadcastDebugMessage("Attempting to inject an invalid push message");
     340        replySender(false);
     341        return;
     342    }
     343
     344    connection->broadcastDebugMessage(makeString("Injected a test push messasge for ", message.targetAppCodeSigningIdentifier, " at ", message.registrationURL.string()));
     345    connection->broadcastDebugMessage(message.message);
     346
     347    auto addResult = m_testingPushMessages.ensure(message.targetAppCodeSigningIdentifier, [] {
     348        return Deque<PushMessageForTesting> { };
     349    });
     350    addResult.iterator->value.append(message);
     351
     352    replySender(true);
     353}
     354
     355void Daemon::getPendingPushMessages(ClientConnection* connection, CompletionHandler<void(const Vector<WebKit::WebPushMessage>&)>&& replySender)
     356{
     357    auto hostAppCodeSigningIdentifier = connection->hostAppCodeSigningIdentifier();
     358    if (hostAppCodeSigningIdentifier.isEmpty()) {
     359        replySender({ });
     360        return;
     361    }
     362
     363    Vector<WebKit::WebPushMessage> resultMessages;
     364
     365    auto iterator = m_testingPushMessages.find(hostAppCodeSigningIdentifier);
     366    if (iterator != m_testingPushMessages.end()) {
     367        for (auto& message : iterator->value) {
     368            auto data = message.message.utf8();
     369            resultMessages.append(WebKit::WebPushMessage { Vector<uint8_t> { reinterpret_cast<const uint8_t*>(data.data()), data.length() }, message.registrationURL });
     370        }
     371        m_testingPushMessages.remove(iterator);
     372    }
     373
     374    connection->broadcastDebugMessage(makeString("Fetching ", String::number(resultMessages.size()), " pending push messages"));
     375
     376    replySender(WTFMove(resultMessages));
     377}
     378
    300379ClientConnection* Daemon::toClientConnection(xpc_connection_t connection)
    301380{
  • trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.h

    r286777 r286788  
    2626#pragma once
    2727
     28#include "PushMessageForTesting.h"
    2829#include <memory>
    2930#include <wtf/RetainPtr.h>
     31#include <wtf/URL.h>
    3032#include <wtf/WeakPtr.h>
    3133#include <wtf/spi/darwin/XPCSPI.h>
     34
     35using WebKit::WebPushD::PushMessageForTesting;
    3236
    3337namespace WebPushTool {
     
    5559    void connectToService();
    5660
     61    void setPushMessage(std::unique_ptr<PushMessageForTesting>&& message) { m_pushMessage = WTFMove(message); }
     62
    5763private:
    5864    void messageReceived(xpc_object_t);
     
    6167    void startAction();
    6268    void startDebugStreamAction();
     69    void sendPushMessage();
    6370
    6471    void sendAuditToken();
    65    
     72
    6673    Action m_action;
    6774    bool m_reconnect { false };
    6875    RetainPtr<xpc_connection_t> m_connection;
    6976    const char* m_serviceName;
     77
     78    std::unique_ptr<PushMessageForTesting> m_pushMessage;
    7079};
    7180
  • trunk/Source/WebKit/webpushd/webpushtool/WebPushToolConnection.mm

    r286777 r286788  
    2727#import "WebPushToolConnection.h"
    2828
     29#import "DaemonEncoder.h"
     30#import "DaemonUtilities.h"
     31#import "WebPushDaemonConstants.h"
    2932#import <mach/mach_init.h>
    3033#import <mach/task.h>
     
    119122        break;
    120123    };
     124
     125    if (m_pushMessage)
     126        sendPushMessage();
     127}
     128
     129void Connection::sendPushMessage()
     130{
     131    ASSERT(m_pushMessage);
     132
     133    WebKit::Daemon::Encoder encoder;
     134    encoder << *m_pushMessage;
     135
     136    auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
     137    xpc_dictionary_set_uint64(dictionary.get(), WebKit::WebPushD::protocolVersionKey, WebKit::WebPushD::protocolVersionValue);
     138    xpc_dictionary_set_value(dictionary.get(), WebKit::WebPushD::protocolEncodedMessageKey, WebKit::vectorToXPCData(encoder.takeBuffer()).get());
     139    xpc_dictionary_set_uint64(dictionary.get(), WebKit::WebPushD::protocolMessageTypeKey, static_cast<uint64_t>(WebKit::WebPushD::MessageType::InjectPushMessageForTesting));
     140
     141    xpc_connection_send_message_with_reply(m_connection.get(), dictionary.get(), dispatch_get_main_queue(), ^(xpc_object_t resultMessage) {
     142        // This reply handler intentionally left blank
     143    });
    121144}
    122145
  • trunk/Source/WebKit/webpushd/webpushtool/WebPushToolMain.mm

    r286777 r286788  
    2525
    2626#import "config.h"
     27#import "PushMessageForTesting.h"
    2728#import "WebPushToolConnection.h"
    2829#import <Foundation/Foundation.h>
    2930#import <optional>
    3031#import <wtf/MainThread.h>
     32
     33using WebKit::WebPushD::PushMessageForTesting;
    3134
    3235__attribute__((__noreturn__))
     
    3740    fprintf(stderr, "Usage: webpushtool [options]\n");
    3841    fprintf(stderr, "\n");
    39     fprintf(stderr, "  --development              Connects to mach service \"org.webkit.webpushtestdaemon.service\" (Default)\n");
    40     fprintf(stderr, "  --production               Connects to mach service \"com.apple.webkit.webpushd.service\"\n");
    41     fprintf(stderr, "  --streamDebugMessages      Stream debug messages from webpushd\n");
    42     fprintf(stderr, "  --reconnect                Reconnect after connection is lost\n");
     42    fprintf(stderr, "  --development\n");
     43    fprintf(stderr, "    Connects to mach service \"org.webkit.webpushtestdaemon.service\" (Default)\n");
     44    fprintf(stderr, "  --production\n");
     45    fprintf(stderr, "    Connects to mach service \"com.apple.webkit.webpushd.service\"\n");
     46    fprintf(stderr, "  --streamDebugMessages\n");
     47    fprintf(stderr, "    Stream debug messages from webpushd\n");
     48    fprintf(stderr, "  --reconnect\n");
     49    fprintf(stderr, "    Reconnect after connection is lost\n");
     50    fprintf(stderr, "  --push <target app identifier> <registration URL> <message>\n");
     51    fprintf(stderr, "    Inject a test push messasge to the target app and registration URL\n");
    4352    fprintf(stderr, "\n");
    4453
    4554    exit(-1);
     55}
     56
     57static std::unique_ptr<PushMessageForTesting> pushMessageFromArguments(NSEnumerator<NSString *> *enumerator)
     58{
     59    NSString *appIdentifier = [enumerator nextObject];
     60    if (!appIdentifier)
     61        return nullptr;
     62
     63    NSString *registrationString = [enumerator nextObject];
     64    if (!registrationString)
     65        return nullptr;
     66
     67    NSURL *registrationURL = [NSURL URLWithString:registrationString];
     68    if (!registrationURL)
     69        return nullptr;
     70
     71    NSString *message = [enumerator nextObject];
     72    if (!message)
     73        return nullptr;
     74
     75    PushMessageForTesting pushMessage = { appIdentifier, registrationURL, message };
     76    return makeUniqueWithoutFastMallocCheck<PushMessageForTesting>(WTFMove(pushMessage));
    4677}
    4778
     
    5384    auto reconnect = WebPushTool::Reconnect::No;
    5485    std::optional<WebPushTool::Action> action;
     86    std::unique_ptr<PushMessageForTesting> pushMessage;
    5587
    5688    @autoreleasepool {
     
    5991            printUsageAndTerminate(@"No arguments provided");
    6092
    61         for (NSString *argument in [arguments subarrayWithRange:NSMakeRange(1, arguments.count - 1)]) {
     93        NSEnumerator<NSString *> *enumerator = [[arguments subarrayWithRange:NSMakeRange(1, arguments.count - 1)] objectEnumerator];
     94        NSString *argument = [enumerator nextObject];
     95        while (argument) {
    6296            if ([argument isEqualToString:@"--production"])
    6397                preferTestService = WebPushTool::PreferTestService::No;
     
    68102            else if ([argument isEqualToString:@"--reconnect"])
    69103                reconnect = WebPushTool::Reconnect::Yes;
    70             else
     104            else if ([argument isEqualToString:@"--push"]) {
     105                pushMessage = pushMessageFromArguments(enumerator);
     106                if (!pushMessage)
     107                    printUsageAndTerminate([NSString stringWithFormat:@"Invalid push arguments specified"]);
     108            } else
    71109                printUsageAndTerminate([NSString stringWithFormat:@"Invalid option provided: %@", argument]);
     110
     111            argument = [enumerator nextObject];
    72112        }
    73113    }
    74114
    75     if (!action)
     115    if (!action && !pushMessage)
    76116        printUsageAndTerminate(@"No action provided");
    77117
    78118    auto connection = WebPushTool::Connection::create(*action, preferTestService, reconnect);
     119    if (pushMessage)
     120        connection->setPushMessage(WTFMove(pushMessage));
     121
    79122    connection->connectToService();
    80123
  • trunk/Tools/ChangeLog

    r286785 r286788  
     12021-12-09  Brady Eidson  <beidson@apple.com>
     2
     3        Add ability to inject messages into webpushd
     4        https://bugs.webkit.org/show_bug.cgi?id=233988
     5
     6        Reviewed by Alex Christensen.
     7
     8        * TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements:
     9        * TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements:
     10        * TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements:
     11
     12        * TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm:
     13        (messageDictionary):
     14
     15        * TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm:
     16        (TestWebKitAPI::createMessageDictionary):
     17        (TestWebKitAPI::sendMessageToDaemon):
     18        (TestWebKitAPI::sendMessageToDaemonWaitingForReply):
     19        (TestWebKitAPI::sendConfigurationWithAuditToken):
     20        (TestWebKitAPI::createAndConfigureConnectionToService):
     21        (TestWebKitAPI::encodeString):
     22        (TestWebKitAPI::TEST):
     23        (TestWebKitAPI::function):
     24        * TestWebKitAPI/cocoa/TestWKWebView.h:
     25
    1262021-12-09  J Pascoe  <j_pascoe@apple.com>
    227
  • trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements

    r286777 r286788  
    1313        <key>com.apple.private.webkit.webpush</key>
    1414        <true/>
     15        <key>com.apple.private.webkit.webpush.inject</key>
     16        <true/>
    1517        <key>com.apple.private.xpc.launchd.job-manager</key>
    1618        <string>TestWebKitAPI</string>
  • trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS-internal.entitlements

    r286777 r286788  
    66        <string>TestWebKitAPI</string>
    77        <key>com.apple.private.webkit.webpush</key>
     8        <true/>
     9        <key>com.apple.private.webkit.webpush.inject</key>
    810        <true/>
    911        <key>com.apple.hid.manager.user-access-device</key>
  • trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-macOS.entitlements

    r286777 r286788  
    1111        <key>com.apple.private.webkit.webpush</key>
    1212        <true/>
     13        <key>com.apple.private.webkit.webpush.inject</key>
     14        <true/>
    1315        <key>com.apple.security.temporary-exception.sbpl</key>
    1416        <array>
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm

    r286777 r286788  
    3535#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
    3636
     37static NSDictionary *messageDictionary(NSData *data, NSURL *registration)
     38{
     39    return @{
     40        @"WebKitPushData" : data,
     41        @"WebKitPushRegistrationURL" : registration
     42    };
     43}
     44
    3745static String expectedMessage;
    3846
     
    147155    NSString *message = @"Sweet Potatoes";
    148156    expectedMessage = "Received: Sweet Potatoes";
    149     [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
     157
     158    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
    150159        pushMessageSuccessful = result;
    151160        pushMessageProcessed = true;
     
    161170    message = @"Rotten Potatoes";
    162171    expectedMessage = "Received: Rotten Potatoes";
    163     [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
     172    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
    164173        pushMessageSuccessful = result;
    165174        pushMessageProcessed = true;
     
    235244    pushMessageSuccessful = false;
    236245    NSString *message = @"Sweet Potatoes";
    237     [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
     246    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
    238247        pushMessageSuccessful = result;
    239248        pushMessageProcessed = true;
     
    280289    pushMessageSuccessful = false;
    281290    NSString *message = @"Rotten Potatoes";
    282     [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
     291    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
    283292        pushMessageSuccessful = result;
    284293        pushMessageProcessed = true;
     
    333342    pushMessageSuccessful = false;
    334343    NSString *message = @"Timeless Potatoes";
    335     [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
     344    [[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
    336345        pushMessageSuccessful = result;
    337346        pushMessageProcessed = true;
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm

    r286777 r286788  
    2727
    2828#import "DaemonTestUtilities.h"
     29#import "HTTPServer.h"
    2930#import "Test.h"
    3031#import "TestURLSchemeHandler.h"
     
    3637#import <WebKit/_WKExperimentalFeature.h>
    3738#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
    38 #import <array>
    3939#import <mach/mach_init.h>
    4040#import <mach/task.h>
     
    163163}
    164164
     165static RetainPtr<xpc_object_t> createMessageDictionary(uint8_t messageType, const Vector<uint8_t>& message)
     166{
     167    auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
     168    xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
     169    xpc_dictionary_set_uint64(dictionary.get(), "message type", messageType);
     170    xpc_dictionary_set_data(dictionary.get(), "encoded message", message.data(), message.size());
     171    return WTFMove(dictionary);
     172}
     173
     174// Uses an existing connection to the daemon for a one-off message
     175void sendMessageToDaemon(xpc_connection_t connection, uint8_t messageType, const Vector<uint8_t>& message)
     176{
     177    auto dictionary = createMessageDictionary(messageType, message);
     178    xpc_connection_send_message(connection, dictionary.get());
     179}
     180
     181// Uses an existing connection to the daemon for a one-off message, waiting for the reply
     182void sendMessageToDaemonWaitingForReply(xpc_connection_t connection, uint8_t messageType, const Vector<uint8_t>& message)
     183{
     184    auto dictionary = createMessageDictionary(messageType, message);
     185
     186    __block bool done = false;
     187    xpc_connection_send_message_with_reply(connection, dictionary.get(), dispatch_get_main_queue(), ^(xpc_object_t request) {
     188        done = true;
     189    });
     190
     191    TestWebKitAPI::Util::run(&done);
     192}
     193
     194static void sendConfigurationWithAuditToken(xpc_connection_t connection)
     195{
     196    audit_token_t token = { 0, 0, 0, 0, 0, 0, 0, 0 };
     197    mach_msg_type_number_t auditTokenCount = TASK_AUDIT_TOKEN_COUNT;
     198    kern_return_t result = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)(&token), &auditTokenCount);
     199    if (result != KERN_SUCCESS) {
     200        EXPECT_TRUE(false);
     201        return;
     202    }
     203
     204    // Send configuration with audit token
     205    {
     206        Vector<uint8_t> encodedMessage(42);
     207        encodedMessage.fill(0);
     208        encodedMessage[1] = 1;
     209        encodedMessage[2] = 32;
     210        memcpy(&encodedMessage[10], &token, sizeof(token));
     211        sendMessageToDaemon(connection, 6, encodedMessage);
     212    }
     213}
     214
     215RetainPtr<xpc_connection_t> createAndConfigureConnectionToService(const char* serviceName)
     216{
     217    auto connection = adoptNS(xpc_connection_create_mach_service(serviceName, dispatch_get_main_queue(), 0));
     218    xpc_connection_set_event_handler(connection.get(), ^(xpc_object_t) { });
     219    xpc_connection_activate(connection.get());
     220    sendConfigurationWithAuditToken(connection.get());
     221
     222    return WTFMove(connection);
     223}
     224
     225static Vector<uint8_t> encodeString(const String& message)
     226{
     227    ASSERT(message.is8Bit());
     228    auto utf8 = message.utf8();
     229
     230    Vector<uint8_t> result(utf8.length() + 5);
     231    result[0] = static_cast<uint8_t>(utf8.length());
     232    result[1] = static_cast<uint8_t>(utf8.length() >> 8);
     233    result[2] = static_cast<uint8_t>(utf8.length() >> 16);
     234    result[3] = static_cast<uint8_t>(utf8.length() >> 24);
     235    result[4] = 0x01;
     236
     237    auto data = utf8.data();
     238    for (size_t i = 0; i < utf8.length(); ++i)
     239        result[5 + i] = data[i];
     240
     241    return result;
     242}
     243
    165244// FIXME: Re-enable this test on Mac once webkit.org/232857 is resolved.
    166245#if PLATFORM(MAC)
     
    197276
    198277    xpc_connection_activate(connection.get());
    199 
    200     audit_token_t token = { 0, 0, 0, 0, 0, 0, 0, 0 };
    201     mach_msg_type_number_t auditTokenCount = TASK_AUDIT_TOKEN_COUNT;
    202     kern_return_t result = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)(&token), &auditTokenCount);
    203     if (result != KERN_SUCCESS) {
    204         EXPECT_TRUE(false);
    205         return;
    206     }
    207 
    208     // Send configuration with audit token
    209     {
    210         std::array<uint8_t, 42> encodedMessage;
    211         encodedMessage.fill(0);
    212         encodedMessage[1] = 1;
    213         encodedMessage[2] = 32;
    214         memcpy(&encodedMessage[10], &token, sizeof(token));
    215         auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
    216         xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
    217         xpc_dictionary_set_uint64(dictionary.get(), "message type", 6);
    218         xpc_dictionary_set_data(dictionary.get(), "encoded message", encodedMessage.data(), encodedMessage.size());
    219         xpc_connection_send_message(connection.get(), dictionary.get());
    220     }
     278    sendConfigurationWithAuditToken(connection.get());
    221279
    222280    // Enable debug messages, and wait for the resulting debug message
    223281    {
    224282        auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
    225         std::array<uint8_t, 1> encodedMessage { 1 };
    226         xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
    227         xpc_dictionary_set_uint64(dictionary.get(), "message type", 5);
    228         xpc_dictionary_set_data(dictionary.get(), "encoded message", encodedMessage.data(), encodedMessage.size());
    229 
    230         xpc_connection_send_message(connection.get(), dictionary.get());
     283        Vector<uint8_t> encodedMessage(1);
     284        encodedMessage[0] = 1;
     285        sendMessageToDaemon(connection.get(), 5, encodedMessage);
    231286        TestWebKitAPI::Util::run(&done);
    232287    }
     
    234289    // Echo and wait for a reply
    235290    auto dictionary = adoptNS(xpc_dictionary_create(nullptr, nullptr, 0));
    236     std::array<uint8_t, 10> encodedString { 5, 0, 0, 0, 1, 'h', 'e', 'l', 'l', 'o' };
     291    auto encodedString = encodeString("hello");
    237292    xpc_dictionary_set_uint64(dictionary.get(), "protocol version", 1);
    238293    xpc_dictionary_set_uint64(dictionary.get(), "message type", 1);
     
    342397}
    343398
     399static const char* mainSWBytes = R"SWRESOURCE(
     400<script>
     401function log(msg)
     402{
     403    window.webkit.messageHandlers.sw.postMessage(msg);
     404}
     405
     406const channel = new MessageChannel();
     407channel.port1.onmessage = (event) => log(event.data);
     408
     409navigator.serviceWorker.register('/sw.js').then((registration) => {
     410    if (registration.active) {
     411        registration.active.postMessage({port: channel.port2}, [channel.port2]);
     412        return;
     413    }
     414    worker = registration.installing;
     415    worker.addEventListener('statechange', function() {
     416        if (worker.state == 'activated')
     417            worker.postMessage({port: channel.port2}, [channel.port2]);
     418    });
     419}).catch(function(error) {
     420    log("Registration failed with: " + error);
     421});
     422</script>
     423)SWRESOURCE";
     424
     425static const char* scriptBytes = R"SWRESOURCE(
     426let port;
     427self.addEventListener("message", (event) => {
     428    port = event.data.port;
     429    port.postMessage("Ready");
     430});
     431self.addEventListener("push", (event) => {
     432    try {
     433        if (!event.data) {
     434            port.postMessage("Received: null data");
     435            return;
     436        }
     437        const value = event.data.text();
     438        port.postMessage("Received: " + value);
     439        if (value != 'Sweet Potatoes')
     440            event.waitUntil(Promise.reject('I want sweet potatoes'));
     441    } catch (e) {
     442        port.postMessage("Got exception " + e);
     443    }
     444});
     445)SWRESOURCE";
     446
     447static void clearWebsiteDataStore(WKWebsiteDataStore *store)
     448{
     449    __block bool clearedStore = false;
     450    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
     451        clearedStore = true;
     452    }];
     453    TestWebKitAPI::Util::run(&clearedStore);
     454}
     455
     456// FIXME: Re-enable this test on Mac once webkit.org/232857 is resolved.
     457#if PLATFORM(MAC)
     458TEST(WebPushD, DISABLED_HandleInjectedPush)
     459#else
     460TEST(WebPushD, HandleInjectedPush)
     461#endif
     462{
     463    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
     464
     465    NSURL *tempDirectory = setUpTestWebPushD();
     466
     467    auto dataStoreConfiguration = adoptNS([_WKWebsiteDataStoreConfiguration new]);
     468    dataStoreConfiguration.get().webPushMachServiceName = @"org.webkit.webpushtestdaemon.service";
     469    dataStoreConfiguration.get().webPushDaemonUsesMockBundlesForTesting = YES;
     470    auto dataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration.get()]);
     471
     472    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     473    configuration.get().websiteDataStore = dataStore.get();
     474    clearWebsiteDataStore([configuration websiteDataStore]);
     475
     476    [configuration.get().preferences _setNotificationsEnabled:YES];
     477    for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) {
     478        if ([feature.key isEqualToString:@"BuiltInNotificationsEnabled"])
     479            [[configuration preferences] _setEnabled:YES forFeature:feature];
     480    }
     481
     482    auto messageHandler = adoptNS([[TestMessageHandler alloc] init]);
     483    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
     484    __block bool done = false;
     485    [messageHandler addMessage:@"Ready" withHandler:^{
     486        done = true;
     487    }];
     488    [messageHandler addMessage:@"Received: Hello World" withHandler:^{
     489        done = true;
     490    }];
     491
     492    TestWebKitAPI::HTTPServer server({
     493        { "/", { mainSWBytes } },
     494        { "/sw.js", { { { "Content-Type", "application/javascript" } }, scriptBytes } }
     495    }, TestWebKitAPI::HTTPServer::Protocol::Http);
     496
     497    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
     498    [webView loadRequest:server.request()];
     499
     500    TestWebKitAPI::Util::run(&done);
     501    done = false;
     502
     503    // Inject push message
     504    auto encodedMessage = encodeString("com.apple.WebKit.TestWebKitAPI");
     505    encodedMessage.appendVector(encodeString(server.request().URL.absoluteString));
     506    encodedMessage.appendVector(encodeString("Hello World"));
     507
     508    auto utilityConnection = createAndConfigureConnectionToService("org.webkit.webpushtestdaemon.service");
     509    sendMessageToDaemonWaitingForReply(utilityConnection.get(), 7, encodedMessage);
     510
     511    // Fetch push messages
     512    __block RetainPtr<NSArray<NSDictionary *>> messages;
     513    [dataStore _getPendingPushMessages:^(NSArray<NSDictionary *> *rawMessages) {
     514        messages = rawMessages;
     515        done = true;
     516    }];
     517    TestWebKitAPI::Util::run(&done);
     518    done = false;
     519
     520    EXPECT_EQ([messages count], 1u);
     521
     522    // Handle push message
     523    __block bool pushMessageProcessed = false;
     524    [dataStore _processPushMessage:[messages firstObject] completionHandler:^(bool result) {
     525        pushMessageProcessed = true;
     526    }];
     527    TestWebKitAPI::Util::run(&done);
     528    TestWebKitAPI::Util::run(&pushMessageProcessed);
     529
     530    cleanUpTestWebPushD(tempDirectory);
     531}
     532
    344533} // namespace TestWebKitAPI
    345534
  • trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h

    r286777 r286788  
    7979@interface TestMessageHandler : NSObject <WKScriptMessageHandler>
    8080- (void)addMessage:(NSString *)message withHandler:(dispatch_block_t)handler;
     81- (void)setWildcardMessageHandler:(void (^)(NSString *))handler;
    8182@end
    8283
Note: See TracChangeset for help on using the changeset viewer.