1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/child/push_messaging/push_provider.h"
7 #include "base/lazy_instance.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/stl_util.h"
10 #include "base/threading/thread_local.h"
11 #include "content/child/push_messaging/push_dispatcher.h"
12 #include "content/child/service_worker/web_service_worker_registration_impl.h"
13 #include "content/child/thread_safe_sender.h"
14 #include "content/common/push_messaging_messages.h"
15 #include "third_party/WebKit/public/platform/WebString.h"
16 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscription.h"
17 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h"
22 int CurrentWorkerId() {
23 return WorkerThread::GetCurrentId();
26 // Returns the id of the given |service_worker_registration|, which
27 // is only available on the implementation of the interface.
28 int64_t GetServiceWorkerRegistrationId(
29 blink::WebServiceWorkerRegistration
* service_worker_registration
) {
30 return static_cast<WebServiceWorkerRegistrationImpl
*>(
31 service_worker_registration
)->registration_id();
36 static base::LazyInstance
<base::ThreadLocalPointer
<PushProvider
>>::Leaky
37 g_push_provider_tls
= LAZY_INSTANCE_INITIALIZER
;
39 PushProvider::PushProvider(ThreadSafeSender
* thread_safe_sender
,
40 PushDispatcher
* push_dispatcher
)
41 : thread_safe_sender_(thread_safe_sender
),
42 push_dispatcher_(push_dispatcher
) {
43 g_push_provider_tls
.Pointer()->Set(this);
46 PushProvider::~PushProvider() {
47 g_push_provider_tls
.Pointer()->Set(nullptr);
50 PushProvider
* PushProvider::ThreadSpecificInstance(
51 ThreadSafeSender
* thread_safe_sender
,
52 PushDispatcher
* push_dispatcher
) {
53 if (g_push_provider_tls
.Pointer()->Get())
54 return g_push_provider_tls
.Pointer()->Get();
56 PushProvider
* provider
=
57 new PushProvider(thread_safe_sender
, push_dispatcher
);
58 if (CurrentWorkerId())
59 WorkerThread::AddObserver(provider
);
63 void PushProvider::WillStopCurrentWorkerThread() {
67 void PushProvider::subscribe(
68 blink::WebServiceWorkerRegistration
* service_worker_registration
,
69 const blink::WebPushSubscriptionOptions
& options
,
70 blink::WebPushSubscriptionCallbacks
* callbacks
) {
71 DCHECK(service_worker_registration
);
73 int request_id
= push_dispatcher_
->GenerateRequestId(CurrentWorkerId());
74 subscription_callbacks_
.AddWithID(callbacks
, request_id
);
75 int64_t service_worker_registration_id
=
76 GetServiceWorkerRegistrationId(service_worker_registration
);
77 thread_safe_sender_
->Send(new PushMessagingHostMsg_SubscribeFromWorker(
78 request_id
, service_worker_registration_id
, options
.userVisibleOnly
));
81 void PushProvider::unsubscribe(
82 blink::WebServiceWorkerRegistration
* service_worker_registration
,
83 blink::WebPushUnsubscribeCallbacks
* callbacks
) {
84 DCHECK(service_worker_registration
);
87 int request_id
= push_dispatcher_
->GenerateRequestId(CurrentWorkerId());
88 unsubscribe_callbacks_
.AddWithID(callbacks
, request_id
);
90 int64_t service_worker_registration_id
=
91 GetServiceWorkerRegistrationId(service_worker_registration
);
92 thread_safe_sender_
->Send(new PushMessagingHostMsg_Unsubscribe(
93 request_id
, service_worker_registration_id
));
96 void PushProvider::getSubscription(
97 blink::WebServiceWorkerRegistration
* service_worker_registration
,
98 blink::WebPushSubscriptionCallbacks
* callbacks
) {
99 DCHECK(service_worker_registration
);
101 int request_id
= push_dispatcher_
->GenerateRequestId(CurrentWorkerId());
102 subscription_callbacks_
.AddWithID(callbacks
, request_id
);
103 int64_t service_worker_registration_id
=
104 GetServiceWorkerRegistrationId(service_worker_registration
);
105 thread_safe_sender_
->Send(new PushMessagingHostMsg_GetRegistration(
106 request_id
, service_worker_registration_id
));
109 void PushProvider::getPermissionStatus(
110 blink::WebServiceWorkerRegistration
* service_worker_registration
,
111 const blink::WebPushSubscriptionOptions
& options
,
112 blink::WebPushPermissionStatusCallbacks
* callbacks
) {
113 DCHECK(service_worker_registration
);
115 int request_id
= push_dispatcher_
->GenerateRequestId(CurrentWorkerId());
116 permission_status_callbacks_
.AddWithID(callbacks
, request_id
);
117 int64_t service_worker_registration_id
=
118 GetServiceWorkerRegistrationId(service_worker_registration
);
119 thread_safe_sender_
->Send(new PushMessagingHostMsg_GetPermissionStatus(
120 request_id
, service_worker_registration_id
, options
.userVisibleOnly
));
123 bool PushProvider::OnMessageReceived(const IPC::Message
& message
) {
125 IPC_BEGIN_MESSAGE_MAP(PushProvider
, message
)
126 IPC_MESSAGE_HANDLER(PushMessagingMsg_SubscribeFromWorkerSuccess
,
127 OnSubscribeFromWorkerSuccess
);
128 IPC_MESSAGE_HANDLER(PushMessagingMsg_SubscribeFromWorkerError
,
129 OnSubscribeFromWorkerError
);
130 IPC_MESSAGE_HANDLER(PushMessagingMsg_UnsubscribeSuccess
,
131 OnUnsubscribeSuccess
);
132 IPC_MESSAGE_HANDLER(PushMessagingMsg_UnsubscribeError
,
134 IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationSuccess
,
135 OnGetRegistrationSuccess
);
136 IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationError
,
137 OnGetRegistrationError
);
138 IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusSuccess
,
139 OnGetPermissionStatusSuccess
);
140 IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusError
,
141 OnGetPermissionStatusError
);
142 IPC_MESSAGE_UNHANDLED(handled
= false)
143 IPC_END_MESSAGE_MAP()
148 void PushProvider::OnSubscribeFromWorkerSuccess(
150 const GURL
& endpoint
,
151 const std::vector
<uint8_t>& curve25519dh
) {
152 blink::WebPushSubscriptionCallbacks
* callbacks
=
153 subscription_callbacks_
.Lookup(request_id
);
157 callbacks
->onSuccess(blink::adoptWebPtr(
158 new blink::WebPushSubscription(endpoint
, curve25519dh
)));
160 subscription_callbacks_
.Remove(request_id
);
163 void PushProvider::OnSubscribeFromWorkerError(int request_id
,
164 PushRegistrationStatus status
) {
165 blink::WebPushSubscriptionCallbacks
* callbacks
=
166 subscription_callbacks_
.Lookup(request_id
);
170 blink::WebPushError::ErrorType error_type
=
171 status
== PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
172 ? blink::WebPushError::ErrorTypePermissionDenied
173 : blink::WebPushError::ErrorTypeAbort
;
175 callbacks
->onError(blink::WebPushError(
177 blink::WebString::fromUTF8(PushRegistrationStatusToString(status
))));
179 subscription_callbacks_
.Remove(request_id
);
182 void PushProvider::OnUnsubscribeSuccess(int request_id
, bool did_unsubscribe
) {
183 blink::WebPushUnsubscribeCallbacks
* callbacks
=
184 unsubscribe_callbacks_
.Lookup(request_id
);
188 callbacks
->onSuccess(did_unsubscribe
);
190 unsubscribe_callbacks_
.Remove(request_id
);
193 void PushProvider::OnUnsubscribeError(
195 blink::WebPushError::ErrorType error_type
,
196 const std::string
& error_message
) {
197 blink::WebPushUnsubscribeCallbacks
* callbacks
=
198 unsubscribe_callbacks_
.Lookup(request_id
);
202 callbacks
->onError(blink::WebPushError(
203 error_type
, blink::WebString::fromUTF8(error_message
)));
205 unsubscribe_callbacks_
.Remove(request_id
);
208 void PushProvider::OnGetRegistrationSuccess(
210 const GURL
& endpoint
,
211 const std::vector
<uint8_t>& curve25519dh
) {
212 blink::WebPushSubscriptionCallbacks
* callbacks
=
213 subscription_callbacks_
.Lookup(request_id
);
217 callbacks
->onSuccess(blink::adoptWebPtr(
218 new blink::WebPushSubscription(endpoint
, curve25519dh
)));
220 subscription_callbacks_
.Remove(request_id
);
223 void PushProvider::OnGetRegistrationError(
225 PushGetRegistrationStatus status
) {
226 blink::WebPushSubscriptionCallbacks
* callbacks
=
227 subscription_callbacks_
.Lookup(request_id
);
231 // We are only expecting an error if we can't find a registration.
232 callbacks
->onSuccess(nullptr);
234 subscription_callbacks_
.Remove(request_id
);
237 void PushProvider::OnGetPermissionStatusSuccess(
239 blink::WebPushPermissionStatus status
) {
240 blink::WebPushPermissionStatusCallbacks
* callbacks
=
241 permission_status_callbacks_
.Lookup(request_id
);
245 callbacks
->onSuccess(status
);
247 permission_status_callbacks_
.Remove(request_id
);
250 void PushProvider::OnGetPermissionStatusError(
252 blink::WebPushError::ErrorType error
) {
253 blink::WebPushPermissionStatusCallbacks
* callbacks
=
254 permission_status_callbacks_
.Lookup(request_id
);
258 std::string error_message
;
259 if (error
== blink::WebPushError::ErrorTypeNotSupported
) {
261 "Push subscriptions that don't enable userVisibleOnly are not "
265 callbacks
->onError(blink::WebPushError(
266 error
, blink::WebString::fromUTF8(error_message
)));
268 permission_status_callbacks_
.Remove(request_id
);
271 } // namespace content