source: webkit/trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp@ 286788

Last change on this file since 286788 was 286788, checked in by beidson@apple.com, 3 years ago

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:
File size: 8.5 KB
Line 
1/*
2 * Copyright (C) 2021 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "NetworkNotificationManager.h"
28
29#if ENABLE(BUILT_IN_NOTIFICATIONS)
30
31#include "DaemonDecoder.h"
32#include "DaemonEncoder.h"
33#include "NetworkSession.h"
34#include "WebPushDaemonConnectionConfiguration.h"
35#include "WebPushMessage.h"
36#include <WebCore/SecurityOriginData.h>
37
38namespace WebKit {
39using namespace WebCore;
40
41NetworkNotificationManager::NetworkNotificationManager(NetworkSession& networkSession, const String& webPushMachServiceName)
42 : m_networkSession(networkSession)
43{
44 if (!m_networkSession.sessionID().isEphemeral() && !webPushMachServiceName.isEmpty())
45 m_connection = makeUnique<WebPushD::Connection>(webPushMachServiceName.utf8(), *this);
46}
47
48void NetworkNotificationManager::maybeSendConnectionConfiguration() const
49{
50 if (m_sentConnectionConfiguration)
51 return;
52 m_sentConnectionConfiguration = true;
53
54 WebPushD::WebPushDaemonConnectionConfiguration configuration;
55 configuration.useMockBundlesForTesting = m_networkSession.webPushDaemonUsesMockBundlesForTesting();
56
57#if PLATFORM(COCOA)
58 auto token = m_networkSession.networkProcess().parentProcessConnection()->getAuditToken();
59 if (token) {
60 Vector<uint8_t> auditTokenData;
61 auditTokenData.resize(sizeof(*token));
62 memcpy(auditTokenData.data(), &(*token), sizeof(*token));
63 configuration.hostAppAuditTokenData = WTFMove(auditTokenData);
64 }
65#endif
66
67 sendMessage<WebPushD::MessageType::UpdateConnectionConfiguration>(configuration);
68}
69
70void NetworkNotificationManager::requestSystemNotificationPermission(const String& originString, CompletionHandler<void(bool)>&& completionHandler)
71{
72 sendMessageWithReply<WebPushD::MessageType::RequestSystemNotificationPermission>(WTFMove(completionHandler), originString);
73}
74
75void NetworkNotificationManager::deletePushAndNotificationRegistration(const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& completionHandler)
76{
77 sendMessageWithReply<WebPushD::MessageType::DeletePushAndNotificationRegistration>(WTFMove(completionHandler), origin.toString());
78}
79
80void NetworkNotificationManager::getOriginsWithPushAndNotificationPermissions(CompletionHandler<void(const Vector<SecurityOriginData>&)>&& completionHandler)
81{
82 CompletionHandler<void(Vector<String>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<String> originStrings) mutable {
83 Vector<SecurityOriginData> origins;
84 for (auto& originString : originStrings)
85 origins.append(SecurityOriginData::fromURL({ { }, originString }));
86 completionHandler(WTFMove(origins));
87 };
88
89 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));
99}
100
101void NetworkNotificationManager::showNotification(const String&, const String&, const String&, const String&, const String&, WebCore::NotificationDirection, const String&, uint64_t)
102{
103 if (!m_connection)
104 return;
105
106// FIXME: While we don't normally land commented-out code in the tree,
107// this is a nice bookmark for a development milestone; Roundtrip communication with webpushd
108// Will make next development steps obvious.
109//
110// CompletionHandler<void(String)>&& completionHandler = [] (String reply) {
111// printf("Got reply: %s\n", reply.utf8().data());
112// };
113//
114// sendMessageWithReply<WebPushD::MessageType::EchoTwice>(WTFMove(completionHandler), String("FIXME: Do useful work here"));
115}
116
117void NetworkNotificationManager::cancelNotification(uint64_t)
118{
119 if (!m_connection)
120 return;
121}
122
123void NetworkNotificationManager::clearNotifications(const Vector<uint64_t>&)
124{
125 if (!m_connection)
126 return;
127}
128
129void NetworkNotificationManager::didDestroyNotification(uint64_t)
130{
131 if (!m_connection)
132 return;
133}
134
135template<WebPushD::MessageType messageType, typename... Args>
136void NetworkNotificationManager::sendMessage(Args&&... args) const
137{
138 RELEASE_ASSERT(m_connection);
139
140 maybeSendConnectionConfiguration();
141
142 Daemon::Encoder encoder;
143 encoder.encode(std::forward<Args>(args)...);
144 m_connection->send(messageType, encoder.takeBuffer());
145}
146
147template<typename... Args> struct ReplyCaller;
148template<> struct ReplyCaller<> {
149 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void()>&& completionHandler)
150 {
151 completionHandler();
152 }
153};
154
155template<> struct ReplyCaller<String> {
156 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(String&&)>&& completionHandler)
157 {
158 std::optional<String> string;
159 decoder >> string;
160 if (!string)
161 return completionHandler({ });
162 completionHandler(WTFMove(*string));
163 }
164};
165
166template<> struct ReplyCaller<const String&> {
167 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(const String&)>&& completionHandler)
168 {
169 std::optional<String> string;
170 decoder >> string;
171 if (!string)
172 return completionHandler({ });
173 completionHandler(WTFMove(*string));
174 }
175};
176
177template<> struct ReplyCaller<bool> {
178 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(bool)>&& completionHandler)
179 {
180 std::optional<bool> boolean;
181 decoder >> boolean;
182 if (!boolean)
183 return completionHandler(false);
184 completionHandler(*boolean);
185 }
186};
187
188template<> struct ReplyCaller<Vector<String>&&> {
189 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
190 {
191 std::optional<Vector<String>> strings;
192 decoder >> strings;
193 if (!strings)
194 return completionHandler({ });
195 completionHandler(WTFMove(*strings));
196 }
197};
198
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
210template<WebPushD::MessageType messageType, typename... Args, typename... ReplyArgs>
211void NetworkNotificationManager::sendMessageWithReply(CompletionHandler<void(ReplyArgs...)>&& completionHandler, Args&&... args) const
212{
213 RELEASE_ASSERT(m_connection);
214
215 maybeSendConnectionConfiguration();
216
217 Daemon::Encoder encoder;
218 encoder.encode(std::forward<Args>(args)...);
219 m_connection->sendWithReply(messageType, encoder.takeBuffer(), [completionHandler = WTFMove(completionHandler)] (auto replyBuffer) mutable {
220 Daemon::Decoder decoder(WTFMove(replyBuffer));
221 ReplyCaller<ReplyArgs...>::callReply(WTFMove(decoder), WTFMove(completionHandler));
222 });
223}
224
225} // namespace WebKit
226#endif // ENABLE(BUILT_IN_NOTIFICATIONS)
Note: See TracBrowser for help on using the repository browser.