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

Last change on this file was 295131, checked in by Ben Nham, 3 years ago

Reset WebKitTestRunner notification policies as part of test cleanup
https://bugs.webkit.org/show_bug.cgi?id=239300

Reviewed by Geoffrey Garen.

Some notification layout tests that check permissions (e.g. http/tests/push-api/subscribe) seem to
be flaky. I can't reproduce this flakiness locally, but from code inspection, this flakiness is
possible if a prewarmed or cached WebContent process is used for one of these tests.

The reason for this is that when a test finishes, WebNotificationProvider (in WebKitTestRunner)
tries to reset the notification permissions. However, it doesn't tell cached WebContent processes
about this reset via WKNotificationManagerProviderDidRemoveNotificationPolicies. To fix this, make
WebNotificationProvider::reset call that function.

  • LayoutTests/platform/mac-wk2/TestExpectations:
  • Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp:

(WebKit::NetworkNotificationManager::deletePushAndNotificationRegistration):

  • Tools/WebKitTestRunner/WebNotificationProvider.cpp:

(WTR::securityOriginsFromStrings):
(WTR::WebNotificationProvider::reset):

Canonical link: https://commits.webkit.org/251222@main

File size: 13.7 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 "Logging.h"
34#include "NetworkSession.h"
35#include "WebPushDaemonConnectionConfiguration.h"
36#include "WebPushMessage.h"
37#include <WebCore/SecurityOriginData.h>
38
39namespace WebKit {
40using namespace WebCore;
41
42NetworkNotificationManager::NetworkNotificationManager(NetworkSession& networkSession, const String& webPushMachServiceName, WebPushD::WebPushDaemonConnectionConfiguration&& configuration)
43 : m_networkSession(networkSession)
44{
45 if (!m_networkSession.sessionID().isEphemeral() && !webPushMachServiceName.isEmpty()) {
46#if PLATFORM(COCOA)
47 auto token = m_networkSession.networkProcess().parentProcessConnection()->getAuditToken();
48 if (token) {
49 Vector<uint8_t> auditTokenData;
50 auditTokenData.resize(sizeof(*token));
51 memcpy(auditTokenData.data(), &(*token), sizeof(*token));
52 configuration.hostAppAuditTokenData = WTFMove(auditTokenData);
53 }
54#endif
55
56 m_connection = makeUnique<WebPushD::Connection>(webPushMachServiceName.utf8(), *this, WTFMove(configuration));
57 }
58}
59
60void NetworkNotificationManager::requestSystemNotificationPermission(const String& originString, CompletionHandler<void(bool)>&& completionHandler)
61{
62 LOG(Push, "Network process passing permission request to webpushd");
63 sendMessageWithReply<WebPushD::MessageType::RequestSystemNotificationPermission>(WTFMove(completionHandler), originString);
64}
65
66void NetworkNotificationManager::deletePushAndNotificationRegistration(const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& completionHandler)
67{
68 if (!m_connection) {
69 completionHandler("No connection to push daemon"_s);
70 return;
71 }
72
73 sendMessageWithReply<WebPushD::MessageType::DeletePushAndNotificationRegistration>(WTFMove(completionHandler), origin.toString());
74}
75
76void NetworkNotificationManager::getOriginsWithPushAndNotificationPermissions(CompletionHandler<void(const Vector<SecurityOriginData>&)>&& completionHandler)
77{
78 CompletionHandler<void(Vector<String>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<String> originStrings) mutable {
79 auto origins = originStrings.map([](auto& originString) {
80 return SecurityOriginData::fromURL({ { }, originString });
81 });
82 completionHandler(WTFMove(origins));
83 };
84
85 sendMessageWithReply<WebPushD::MessageType::GetOriginsWithPushAndNotificationPermissions>(WTFMove(replyHandler));
86}
87
88void NetworkNotificationManager::getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
89{
90 CompletionHandler<void(Vector<WebPushMessage>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<WebPushMessage>&& messages) mutable {
91 LOG(Push, "Done getting push messages");
92 completionHandler(WTFMove(messages));
93 };
94
95 sendMessageWithReply<WebPushD::MessageType::GetPendingPushMessages>(WTFMove(replyHandler));
96}
97
98void NetworkNotificationManager::showNotification(IPC::Connection&, const WebCore::NotificationData&, CompletionHandler<void()>&& callback)
99{
100 callback();
101
102// FIXME: While we don't normally land commented-out code in the tree,
103// this is a nice bookmark for a development milestone; Roundtrip communication with webpushd
104// Will make next development steps obvious.
105//
106// CompletionHandler<void(String)>&& completionHandler = [] (String reply) {
107// printf("Got reply: %s\n", reply.utf8().data());
108// };
109//
110// sendMessageWithReply<WebPushD::MessageType::EchoTwice>(WTFMove(completionHandler), String("FIXME: Do useful work here"));
111}
112
113void NetworkNotificationManager::cancelNotification(const UUID&)
114{
115 if (!m_connection)
116 return;
117}
118
119void NetworkNotificationManager::clearNotifications(const Vector<UUID>&)
120{
121 if (!m_connection)
122 return;
123}
124
125void NetworkNotificationManager::didDestroyNotification(const UUID&)
126{
127 if (!m_connection)
128 return;
129}
130
131void NetworkNotificationManager::subscribeToPushService(URL&& scopeURL, Vector<uint8_t>&& applicationServerKey, CompletionHandler<void(Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&&)>&& completionHandler)
132{
133 if (!m_connection) {
134 completionHandler(makeUnexpected(ExceptionData { AbortError, "No connection to push daemon"_s }));
135 return;
136 }
137
138 sendMessageWithReply<WebPushD::MessageType::SubscribeToPushService>(WTFMove(completionHandler), WTFMove(scopeURL), WTFMove(applicationServerKey));
139}
140
141void NetworkNotificationManager::unsubscribeFromPushService(URL&& scopeURL, std::optional<PushSubscriptionIdentifier> pushSubscriptionIdentifier, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&& completionHandler)
142{
143 if (!m_connection) {
144 completionHandler(makeUnexpected(ExceptionData { AbortError, "No connection to push daemon"_s }));
145 return;
146 }
147
148 sendMessageWithReply<WebPushD::MessageType::UnsubscribeFromPushService>(WTFMove(completionHandler), WTFMove(scopeURL), pushSubscriptionIdentifier);
149}
150
151void NetworkNotificationManager::getPushSubscription(URL&& scopeURL, CompletionHandler<void(Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&&)>&& completionHandler)
152{
153 if (!m_connection) {
154 completionHandler(makeUnexpected(ExceptionData { AbortError, "No connection to push daemon"_s }));
155 return;
156 }
157
158 sendMessageWithReply<WebPushD::MessageType::GetPushSubscription>(WTFMove(completionHandler), WTFMove(scopeURL));
159}
160
161void NetworkNotificationManager::getPushPermissionState(URL&& scopeURL, CompletionHandler<void(Expected<uint8_t, WebCore::ExceptionData>&&)>&& completionHandler)
162{
163 if (!m_connection) {
164 completionHandler(makeUnexpected(ExceptionData { AbortError, "No connection to push daemon"_s }));
165 return;
166 }
167
168 sendMessageWithReply<WebPushD::MessageType::GetPushPermissionState>(WTFMove(completionHandler), WTFMove(scopeURL));
169}
170
171void NetworkNotificationManager::incrementSilentPushCount(WebCore::SecurityOriginData&& origin, CompletionHandler<void(unsigned)>&& completionHandler)
172{
173 if (!m_connection) {
174 completionHandler(0);
175 return;
176 }
177
178 sendMessageWithReply<WebPushD::MessageType::IncrementSilentPushCount>(WTFMove(completionHandler), WTFMove(origin));
179}
180
181void NetworkNotificationManager::removeAllPushSubscriptions(CompletionHandler<void(unsigned)>&& completionHandler)
182{
183 if (!m_connection) {
184 completionHandler(0);
185 return;
186 }
187
188 sendMessageWithReply<WebPushD::MessageType::RemoveAllPushSubscriptions>(WTFMove(completionHandler));
189}
190
191void NetworkNotificationManager::removePushSubscriptionsForOrigin(WebCore::SecurityOriginData&& origin, CompletionHandler<void(unsigned)>&& completionHandler)
192{
193 if (!m_connection) {
194 completionHandler(0);
195 return;
196 }
197
198 sendMessageWithReply<WebPushD::MessageType::RemovePushSubscriptionsForOrigin>(WTFMove(completionHandler), WTFMove(origin));
199}
200
201template<WebPushD::MessageType messageType, typename... Args>
202void NetworkNotificationManager::sendMessage(Args&&... args) const
203{
204 RELEASE_ASSERT(m_connection);
205
206 Daemon::Encoder encoder;
207 encoder.encode(std::forward<Args>(args)...);
208 m_connection->send(messageType, encoder.takeBuffer());
209}
210
211template<typename... Args> struct ReplyCaller;
212template<> struct ReplyCaller<> {
213 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void()>&& completionHandler)
214 {
215 completionHandler();
216 }
217};
218
219template<> struct ReplyCaller<String> {
220 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(String&&)>&& completionHandler)
221 {
222 std::optional<String> string;
223 decoder >> string;
224 if (!string)
225 return completionHandler({ });
226 completionHandler(WTFMove(*string));
227 }
228};
229
230template<> struct ReplyCaller<const String&> {
231 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(const String&)>&& completionHandler)
232 {
233 std::optional<String> string;
234 decoder >> string;
235 if (!string)
236 return completionHandler({ });
237 completionHandler(WTFMove(*string));
238 }
239};
240
241template<> struct ReplyCaller<bool> {
242 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(bool)>&& completionHandler)
243 {
244 std::optional<bool> boolean;
245 decoder >> boolean;
246 if (!boolean)
247 return completionHandler(false);
248 completionHandler(*boolean);
249 }
250};
251
252template<> struct ReplyCaller<unsigned> {
253 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(bool)>&& completionHandler)
254 {
255 std::optional<int> value;
256 decoder >> value;
257 if (!value)
258 return completionHandler(0);
259 completionHandler(*value);
260 }
261};
262
263template<> struct ReplyCaller<Vector<String>&&> {
264 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
265 {
266 std::optional<Vector<String>> strings;
267 decoder >> strings;
268 if (!strings)
269 return completionHandler({ });
270 completionHandler(WTFMove(*strings));
271 }
272};
273
274template<> struct ReplyCaller<Vector<WebPushMessage>&&> {
275 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<WebPushMessage>&&)>&& completionHandler)
276 {
277 std::optional<Vector<WebPushMessage>> messages;
278 decoder >> messages;
279 if (!messages)
280 return completionHandler({ });
281 completionHandler(WTFMove(*messages));
282 }
283};
284
285template<> struct ReplyCaller<Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&&> {
286 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&&)>&& completionHandler)
287 {
288 std::optional<Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>> data;
289 decoder >> data;
290
291 if (!data)
292 completionHandler(makeUnexpected(ExceptionData { AbortError, "Couldn't decode message"_s }));
293 else
294 completionHandler(WTFMove(*data));
295 }
296};
297
298template<> struct ReplyCaller<Expected<bool, WebCore::ExceptionData>&&> {
299 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&& completionHandler)
300 {
301 std::optional<Expected<bool, WebCore::ExceptionData>> data;
302 decoder >> data;
303
304 if (!data)
305 completionHandler(makeUnexpected(ExceptionData { AbortError, "Couldn't decode message"_s }));
306 else
307 completionHandler(WTFMove(*data));
308 }
309};
310
311template<> struct ReplyCaller<Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&&> {
312 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&&)>&& completionHandler)
313 {
314 std::optional<Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>> data;
315 decoder >> data;
316
317 if (!data)
318 completionHandler(makeUnexpected(ExceptionData { AbortError, "Couldn't decode message"_s }));
319 else
320 completionHandler(WTFMove(*data));
321 }
322};
323
324template<> struct ReplyCaller<Expected<uint8_t, WebCore::ExceptionData>&&> {
325 static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Expected<uint8_t, WebCore::ExceptionData>&&)>&& completionHandler)
326 {
327 std::optional<Expected<uint8_t, WebCore::ExceptionData>> data;
328 decoder >> data;
329
330 if (!data)
331 completionHandler(makeUnexpected(ExceptionData { AbortError, "Couldn't decode message"_s }));
332 else
333 completionHandler(WTFMove(*data));
334 }
335};
336
337template<WebPushD::MessageType messageType, typename... Args, typename... ReplyArgs>
338void NetworkNotificationManager::sendMessageWithReply(CompletionHandler<void(ReplyArgs...)>&& completionHandler, Args&&... args) const
339{
340 RELEASE_ASSERT(m_connection);
341
342 Daemon::Encoder encoder;
343 encoder.encode(std::forward<Args>(args)...);
344 m_connection->sendWithReply(messageType, encoder.takeBuffer(), [completionHandler = WTFMove(completionHandler)] (auto replyBuffer) mutable {
345 Daemon::Decoder decoder(WTFMove(replyBuffer));
346 ReplyCaller<ReplyArgs...>::callReply(WTFMove(decoder), WTFMove(completionHandler));
347 });
348}
349
350} // namespace WebKit
351#endif // ENABLE(BUILT_IN_NOTIFICATIONS)
Note: See TracBrowser for help on using the repository browser.