Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: content/browser/push_messaging/push_messaging_message_filter.cc

Issue 2690203003: Convert push_messaging IPC msgs into mojo interfaces (Closed)
Patch Set: code rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "content/browser/push_messaging/push_messaging_message_filter.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "content/browser/renderer_host/render_process_host_impl.h"
19 #include "content/browser/service_worker/service_worker_context_core.h"
20 #include "content/browser/service_worker/service_worker_context_wrapper.h"
21 #include "content/browser/service_worker/service_worker_storage.h"
22 #include "content/common/push_messaging_messages.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/permission_manager.h"
26 #include "content/public/browser/permission_type.h"
27 #include "content/public/browser/push_messaging_service.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/child_process_host.h"
31 #include "content/public/common/console_message_level.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/push_messaging_status.h"
34 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermi ssionStatus.h"
35
36 namespace content {
37
38 // Service Worker database keys. If a registration ID is stored, the stored
39 // sender ID must be the one used to register. Unfortunately, this isn't always
40 // true of pre-InstanceID registrations previously stored in the database, but
41 // fortunately it's less important for their sender ID to be accurate.
42 const char kPushSenderIdServiceWorkerKey[] = "push_sender_id";
43 const char kPushRegistrationIdServiceWorkerKey[] = "push_registration_id";
44
45 namespace {
46
47 // Chrome currently does not support the Push API in incognito.
48 const char kIncognitoPushUnsupportedMessage[] =
49 "Chrome currently does not support the Push API in incognito mode "
50 "(https://crbug.com/401439). There is deliberately no way to "
51 "feature-detect this, since incognito mode needs to be undetectable by "
52 "websites.";
53
54 // These UMA methods are only called from IO thread, but it would be acceptable
55 // (even though slightly racy) to call them from UI thread as well, see
56 // https://groups.google.com/a/chromium.org/d/msg/chromium-dev/FNzZRJtN2aw/Aw0CW AXJJ1kJ
57 void RecordRegistrationStatus(PushRegistrationStatus status) {
58 DCHECK_CURRENTLY_ON(BrowserThread::IO);
59 UMA_HISTOGRAM_ENUMERATION("PushMessaging.RegistrationStatus", status,
60 PUSH_REGISTRATION_STATUS_LAST + 1);
61 }
62
63 void RecordUnregistrationStatus(PushUnregistrationStatus status) {
64 DCHECK_CURRENTLY_ON(BrowserThread::IO);
65 UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationStatus", status,
66 PUSH_UNREGISTRATION_STATUS_LAST + 1);
67 }
68
69 void RecordGetRegistrationStatus(PushGetRegistrationStatus status) {
70 DCHECK_CURRENTLY_ON(BrowserThread::IO);
71 UMA_HISTOGRAM_ENUMERATION("PushMessaging.GetRegistrationStatus", status,
72 PUSH_GETREGISTRATION_STATUS_LAST + 1);
73 }
74
75 // Curries the |success| and |p256dh| parameters over to |callback| and
76 // posts a task to invoke |callback| on the IO thread.
77 void ForwardEncryptionInfoToIOThreadProxy(
78 const PushMessagingService::EncryptionInfoCallback& callback,
79 bool success,
80 const std::vector<uint8_t>& p256dh,
81 const std::vector<uint8_t>& auth) {
82 DCHECK_CURRENTLY_ON(BrowserThread::UI);
83 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
84 base::Bind(callback, success, p256dh, auth));
85 }
86
87 // Returns whether |sender_info| contains a valid application server key, that
88 // is, a NIST P-256 public key in uncompressed format.
89 bool IsApplicationServerKey(const std::string& sender_info) {
90 return sender_info.size() == 65 && sender_info[0] == 0x04;
91 }
92
93 // Returns sender_info if non-empty, otherwise checks if stored_sender_id
94 // may be used as a fallback and if so, returns stored_sender_id instead.
95 //
96 // This is in order to support the legacy way of subscribing from a service
97 // worker (first subscribe from the document using a gcm_sender_id set in the
98 // manifest, and then subscribe from the service worker with no key).
99 //
100 // An empty string will be returned if sender_info is empty and the fallback
101 // is not a numeric gcm sender id.
102 std::string FixSenderInfo(const std::string& sender_info,
103 const std::string& stored_sender_id) {
104 if (!sender_info.empty())
105 return sender_info;
106 if (base::ContainsOnlyChars(stored_sender_id, "0123456789"))
107 return stored_sender_id;
108 return std::string();
109 }
110
111 } // namespace
112
113 struct PushMessagingMessageFilter::RegisterData {
114 RegisterData();
115 RegisterData(const RegisterData& other) = default;
116 bool FromDocument() const;
117 int request_id;
118 GURL requesting_origin;
119 int64_t service_worker_registration_id;
120 PushSubscriptionOptions options;
121 // The following member should only be read if FromDocument() is true.
122 int render_frame_id;
123 };
124
125 // Inner core of this message filter which lives on the UI thread.
126 class PushMessagingMessageFilter::Core {
127 public:
128 Core(const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
129 int render_process_id);
130
131 // Public Register methods on UI thread --------------------------------------
132
133 // Called via PostTask from IO thread.
134 void RegisterOnUI(const RegisterData& data);
135
136 // Public Unregister methods on UI thread ------------------------------------
137
138 // Called via PostTask from IO thread.
139 void UnregisterFromService(int request_id,
140 int64_t service_worker_registration_id,
141 const GURL& requesting_origin,
142 const std::string& sender_id);
143
144 // Public GetPermission methods on UI thread ---------------------------------
145
146 // Called via PostTask from IO thread.
147 void GetPermissionStatusOnUI(const GURL& requesting_origin,
148 bool user_visible,
149 int request_id);
150
151 // Public helper methods on UI thread ----------------------------------------
152
153 // Called via PostTask from IO thread. The |io_thread_callback| callback
154 // will be invoked on the IO thread.
155 void GetEncryptionInfoOnUI(
156 const GURL& origin,
157 int64_t service_worker_registration_id,
158 const std::string& sender_id,
159 const PushMessagingService::EncryptionInfoCallback& io_thread_callback);
160
161 // Called (directly) from both the UI and IO threads.
162 bool is_incognito() const { return is_incognito_; }
163
164 // Returns a push messaging service. May return null.
165 PushMessagingService* service();
166
167 private:
168 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
169 friend class base::DeleteHelper<Core>;
170
171 ~Core();
172
173 // Private Register methods on UI thread -------------------------------------
174
175 void DidRequestPermissionInIncognito(const RegisterData& data,
176 blink::mojom::PermissionStatus status);
177
178 void DidRegister(const RegisterData& data,
179 const std::string& push_registration_id,
180 const std::vector<uint8_t>& p256dh,
181 const std::vector<uint8_t>& auth,
182 PushRegistrationStatus status);
183
184 // Private Unregister methods on UI thread -----------------------------------
185
186 void DidUnregisterFromService(int request_id,
187 int64_t service_worker_registration_id,
188 PushUnregistrationStatus unregistration_status);
189
190 // Private helper methods on UI thread ---------------------------------------
191
192 void Send(IPC::Message* message);
193
194 // Outer part of this message filter which lives on the IO thread.
195 base::WeakPtr<PushMessagingMessageFilter> io_parent_;
196
197 int render_process_id_;
198
199 bool is_incognito_;
200
201 base::WeakPtrFactory<Core> weak_factory_ui_to_ui_;
202
203 DISALLOW_COPY_AND_ASSIGN(Core);
204 };
205
206 PushMessagingMessageFilter::RegisterData::RegisterData()
207 : request_id(0),
208 service_worker_registration_id(0),
209 render_frame_id(ChildProcessHost::kInvalidUniqueID) {}
210
211 bool PushMessagingMessageFilter::RegisterData::FromDocument() const {
212 return render_frame_id != ChildProcessHost::kInvalidUniqueID;
213 }
214
215 PushMessagingMessageFilter::Core::Core(
216 const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
217 int render_process_id)
218 : io_parent_(io_parent),
219 render_process_id_(render_process_id),
220 weak_factory_ui_to_ui_(this) {
221 DCHECK_CURRENTLY_ON(BrowserThread::UI);
222 RenderProcessHost* process_host =
223 RenderProcessHost::FromID(render_process_id_); // Can't be null yet.
224 is_incognito_ = process_host->GetBrowserContext()->IsOffTheRecord();
225 }
226
227 PushMessagingMessageFilter::Core::~Core() {}
228
229 PushMessagingMessageFilter::PushMessagingMessageFilter(
230 int render_process_id,
231 ServiceWorkerContextWrapper* service_worker_context)
232 : BrowserMessageFilter(PushMessagingMsgStart),
233 service_worker_context_(service_worker_context),
234 weak_factory_io_to_io_(this) {
235 // Although this class is used only on the IO thread, it is constructed on UI.
236 DCHECK_CURRENTLY_ON(BrowserThread::UI);
237 // Normally, it would be unsafe to obtain a weak pointer from the UI thread,
238 // but it's ok in the constructor since we can't be destroyed before our
239 // constructor finishes.
240 ui_core_.reset(
241 new Core(weak_factory_io_to_io_.GetWeakPtr(), render_process_id));
242
243 PushMessagingService* service = ui_core_->service();
244 service_available_ = !!service;
245
246 if (service_available_) {
247 default_endpoint_ = service->GetEndpoint(false /* standard_protocol */);
248 web_push_protocol_endpoint_ =
249 service->GetEndpoint(true /* standard_protocol */);
250 }
251 }
252
253 PushMessagingMessageFilter::~PushMessagingMessageFilter() {}
254
255 void PushMessagingMessageFilter::OnDestruct() const {
256 BrowserThread::DeleteOnIOThread::Destruct(this);
257 }
258
259 bool PushMessagingMessageFilter::OnMessageReceived(
260 const IPC::Message& message) {
261 bool handled = true;
262 IPC_BEGIN_MESSAGE_MAP(PushMessagingMessageFilter, message)
263 IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Subscribe, OnSubscribe)
264 IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Unsubscribe, OnUnsubscribe)
265 IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetSubscription, OnGetSubscription)
266 IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetPermissionStatus,
267 OnGetPermissionStatus)
268 IPC_MESSAGE_UNHANDLED(handled = false)
269 IPC_END_MESSAGE_MAP()
270 return handled;
271 }
272
273 // Subscribe methods on both IO and UI threads, merged in order of use from
274 // PushMessagingMessageFilter and Core.
275 // -----------------------------------------------------------------------------
276
277 void PushMessagingMessageFilter::OnSubscribe(
278 int render_frame_id,
279 int request_id,
280 int64_t service_worker_registration_id,
281 const PushSubscriptionOptions& options) {
282 DCHECK_CURRENTLY_ON(BrowserThread::IO);
283 // TODO(mvanouwerkerk): Validate arguments?
284 RegisterData data;
285
286 // Will be ChildProcessHost::kInvalidUniqueID in requests from Service Worker.
287 data.render_frame_id = render_frame_id;
288
289 data.request_id = request_id;
290 data.service_worker_registration_id = service_worker_registration_id;
291 data.options = options;
292
293 ServiceWorkerRegistration* service_worker_registration =
294 service_worker_context_->GetLiveRegistration(
295 data.service_worker_registration_id);
296 if (!service_worker_registration ||
297 !service_worker_registration->active_version()) {
298 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER);
299 return;
300 }
301 data.requesting_origin = service_worker_registration->pattern().GetOrigin();
302
303 DCHECK(!(data.options.sender_info.empty() && data.FromDocument()));
304
305 service_worker_context_->GetRegistrationUserData(
306 data.service_worker_registration_id,
307 {kPushRegistrationIdServiceWorkerKey, kPushSenderIdServiceWorkerKey},
308 base::Bind(&PushMessagingMessageFilter::DidCheckForExistingRegistration,
309 weak_factory_io_to_io_.GetWeakPtr(), data));
310 }
311
312 void PushMessagingMessageFilter::DidCheckForExistingRegistration(
313 const RegisterData& data,
314 const std::vector<std::string>& push_registration_id_and_sender_id,
315 ServiceWorkerStatusCode service_worker_status) {
316 DCHECK_CURRENTLY_ON(BrowserThread::IO);
317 if (service_worker_status == SERVICE_WORKER_OK) {
318 DCHECK_EQ(2u, push_registration_id_and_sender_id.size());
319 const auto& push_registration_id = push_registration_id_and_sender_id[0];
320 const auto& stored_sender_id = push_registration_id_and_sender_id[1];
321 std::string fixed_sender_id =
322 FixSenderInfo(data.options.sender_info, stored_sender_id);
323 if (fixed_sender_id.empty()) {
324 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
325 return;
326 }
327 if (fixed_sender_id != stored_sender_id) {
328 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH);
329 return;
330 }
331 auto callback = base::Bind(
332 &PushMessagingMessageFilter::DidGetEncryptionKeys,
333 weak_factory_io_to_io_.GetWeakPtr(), data, push_registration_id);
334 BrowserThread::PostTask(
335 BrowserThread::UI, FROM_HERE,
336 base::Bind(&Core::GetEncryptionInfoOnUI,
337 base::Unretained(ui_core_.get()), data.requesting_origin,
338 data.service_worker_registration_id, fixed_sender_id,
339 callback));
340 return;
341 }
342 // TODO(johnme): The spec allows the register algorithm to reject with an
343 // AbortError when accessing storage fails. Perhaps we should do that if
344 // service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND instead of
345 // attempting to do a fresh registration?
346 // https://w3c.github.io/push-api/#widl-PushRegistrationManager-register-Promi se-PushRegistration
347 if (!data.options.sender_info.empty()) {
348 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
349 base::Bind(&Core::RegisterOnUI,
350 base::Unretained(ui_core_.get()), data));
351 } else {
352 // There is no existing registration and the sender_info passed in was
353 // empty, but perhaps there is a stored sender id we can use.
354 service_worker_context_->GetRegistrationUserData(
355 data.service_worker_registration_id, {kPushSenderIdServiceWorkerKey},
356 base::Bind(&PushMessagingMessageFilter::DidGetSenderIdFromStorage,
357 weak_factory_io_to_io_.GetWeakPtr(), data));
358 }
359 }
360
361 void PushMessagingMessageFilter::DidGetEncryptionKeys(
362 const RegisterData& data,
363 const std::string& push_registration_id,
364 bool success,
365 const std::vector<uint8_t>& p256dh,
366 const std::vector<uint8_t>& auth) {
367 DCHECK_CURRENTLY_ON(BrowserThread::IO);
368 if (!success) {
369 SendSubscriptionError(
370 data, PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE);
371 return;
372 }
373
374 SendSubscriptionSuccess(data, PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE,
375 push_registration_id, p256dh, auth);
376 }
377
378 void PushMessagingMessageFilter::DidGetSenderIdFromStorage(
379 const RegisterData& data,
380 const std::vector<std::string>& stored_sender_id,
381 ServiceWorkerStatusCode service_worker_status) {
382 DCHECK_CURRENTLY_ON(BrowserThread::IO);
383 if (service_worker_status != SERVICE_WORKER_OK) {
384 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
385 return;
386 }
387 DCHECK_EQ(1u, stored_sender_id.size());
388 // We should only be here because no sender info was supplied to subscribe().
389 DCHECK(data.options.sender_info.empty());
390 std::string fixed_sender_id =
391 FixSenderInfo(data.options.sender_info, stored_sender_id[0]);
392 if (fixed_sender_id.empty()) {
393 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
394 return;
395 }
396 RegisterData mutated_data = data;
397 mutated_data.options.sender_info = fixed_sender_id;
398 BrowserThread::PostTask(
399 BrowserThread::UI, FROM_HERE,
400 base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()),
401 mutated_data));
402 }
403
404 void PushMessagingMessageFilter::Core::RegisterOnUI(
405 const PushMessagingMessageFilter::RegisterData& data) {
406 DCHECK_CURRENTLY_ON(BrowserThread::UI);
407 PushMessagingService* push_service = service();
408 if (!push_service) {
409 if (!is_incognito()) {
410 // This might happen if InstanceIDProfileService::IsInstanceIDEnabled
411 // returns false because the Instance ID kill switch was enabled.
412 // TODO(johnme): Might be better not to expose the API in this case.
413 BrowserThread::PostTask(
414 BrowserThread::IO, FROM_HERE,
415 base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
416 io_parent_,
417 data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
418 } else {
419 // Prevent websites from detecting incognito mode, by emulating what would
420 // have happened if we had a PushMessagingService available.
421 if (!data.FromDocument() || !data.options.user_visible_only) {
422 // Throw a permission denied error under the same circumstances.
423 BrowserThread::PostTask(
424 BrowserThread::IO, FROM_HERE,
425 base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
426 io_parent_, data,
427 PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
428 } else {
429 RenderFrameHost* render_frame_host =
430 RenderFrameHost::FromID(render_process_id_, data.render_frame_id);
431 WebContents* web_contents =
432 WebContents::FromRenderFrameHost(render_frame_host);
433 if (web_contents) {
434 web_contents->GetMainFrame()->AddMessageToConsole(
435 CONSOLE_MESSAGE_LEVEL_ERROR, kIncognitoPushUnsupportedMessage);
436 // Request push messaging permission (which will fail, since
437 // notifications aren't supported in incognito), so the website can't
438 // detect whether incognito is active.
439 web_contents->GetBrowserContext()
440 ->GetPermissionManager()
441 ->RequestPermission(
442 PermissionType::PUSH_MESSAGING, render_frame_host,
443 data.requesting_origin, false /* user_gesture */,
444 base::Bind(&PushMessagingMessageFilter::Core::
445 DidRequestPermissionInIncognito,
446 weak_factory_ui_to_ui_.GetWeakPtr(), data));
447 }
448 }
449 }
450 return;
451 }
452
453 if (data.FromDocument()) {
454 push_service->SubscribeFromDocument(
455 data.requesting_origin, data.service_worker_registration_id,
456 render_process_id_, data.render_frame_id, data.options,
457 base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
458 data));
459 } else {
460 push_service->SubscribeFromWorker(
461 data.requesting_origin, data.service_worker_registration_id,
462 data.options, base::Bind(&Core::DidRegister,
463 weak_factory_ui_to_ui_.GetWeakPtr(), data));
464 }
465 }
466
467 void PushMessagingMessageFilter::Core::DidRequestPermissionInIncognito(
468 const RegisterData& data,
469 blink::mojom::PermissionStatus status) {
470 DCHECK_CURRENTLY_ON(BrowserThread::UI);
471 // Notification permission should always be denied in incognito.
472 DCHECK_EQ(blink::mojom::PermissionStatus::DENIED, status);
473 BrowserThread::PostTask(
474 BrowserThread::IO, FROM_HERE,
475 base::Bind(&PushMessagingMessageFilter::SendSubscriptionError, io_parent_,
476 data, PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
477 }
478
479 void PushMessagingMessageFilter::Core::DidRegister(
480 const RegisterData& data,
481 const std::string& push_registration_id,
482 const std::vector<uint8_t>& p256dh,
483 const std::vector<uint8_t>& auth,
484 PushRegistrationStatus status) {
485 DCHECK_CURRENTLY_ON(BrowserThread::UI);
486 if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE) {
487 BrowserThread::PostTask(
488 BrowserThread::IO, FROM_HERE,
489 base::Bind(&PushMessagingMessageFilter::PersistRegistrationOnIO,
490 io_parent_, data, push_registration_id, p256dh, auth));
491 } else {
492 BrowserThread::PostTask(
493 BrowserThread::IO, FROM_HERE,
494 base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
495 io_parent_, data, status));
496 }
497 }
498
499 void PushMessagingMessageFilter::PersistRegistrationOnIO(
500 const RegisterData& data,
501 const std::string& push_registration_id,
502 const std::vector<uint8_t>& p256dh,
503 const std::vector<uint8_t>& auth) {
504 DCHECK_CURRENTLY_ON(BrowserThread::IO);
505 service_worker_context_->StoreRegistrationUserData(
506 data.service_worker_registration_id, data.requesting_origin,
507 {{kPushRegistrationIdServiceWorkerKey, push_registration_id},
508 {kPushSenderIdServiceWorkerKey, data.options.sender_info}},
509 base::Bind(&PushMessagingMessageFilter::DidPersistRegistrationOnIO,
510 weak_factory_io_to_io_.GetWeakPtr(), data,
511 push_registration_id, p256dh, auth));
512 }
513
514 void PushMessagingMessageFilter::DidPersistRegistrationOnIO(
515 const RegisterData& data,
516 const std::string& push_registration_id,
517 const std::vector<uint8_t>& p256dh,
518 const std::vector<uint8_t>& auth,
519 ServiceWorkerStatusCode service_worker_status) {
520 DCHECK_CURRENTLY_ON(BrowserThread::IO);
521 if (service_worker_status == SERVICE_WORKER_OK) {
522 SendSubscriptionSuccess(data,
523 PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE,
524 push_registration_id, p256dh, auth);
525 } else {
526 // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count.
527 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
528 }
529 }
530
531 void PushMessagingMessageFilter::SendSubscriptionError(
532 const RegisterData& data, PushRegistrationStatus status) {
533 // Only called from IO thread, but would be safe to call from UI thread.
534 DCHECK_CURRENTLY_ON(BrowserThread::IO);
535 if (data.FromDocument()) {
536 Send(new PushMessagingMsg_SubscribeFromDocumentError(
537 data.render_frame_id, data.request_id, status));
538 } else {
539 Send(
540 new PushMessagingMsg_SubscribeFromWorkerError(data.request_id, status));
541 }
542 RecordRegistrationStatus(status);
543 }
544
545 void PushMessagingMessageFilter::SendSubscriptionSuccess(
546 const RegisterData& data,
547 PushRegistrationStatus status,
548 const std::string& push_subscription_id,
549 const std::vector<uint8_t>& p256dh,
550 const std::vector<uint8_t>& auth) {
551 // Only called from IO thread, but would be safe to call from UI thread.
552 DCHECK_CURRENTLY_ON(BrowserThread::IO);
553 if (!service_available_) {
554 // This shouldn't be possible in incognito mode, since we've already checked
555 // that we have an existing registration. Hence it's ok to throw an error.
556 DCHECK(!ui_core_->is_incognito());
557 SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE);
558 return;
559 }
560
561 const GURL endpoint = CreateEndpoint(
562 IsApplicationServerKey(data.options.sender_info), push_subscription_id);
563
564 if (data.FromDocument()) {
565 Send(new PushMessagingMsg_SubscribeFromDocumentSuccess(
566 data.render_frame_id, data.request_id, endpoint, data.options, p256dh,
567 auth));
568 } else {
569 Send(new PushMessagingMsg_SubscribeFromWorkerSuccess(
570 data.request_id, endpoint, data.options, p256dh, auth));
571 }
572 RecordRegistrationStatus(status);
573 }
574
575 // Unsubscribe methods on both IO and UI threads, merged in order of use from
576 // PushMessagingMessageFilter and Core.
577 // -----------------------------------------------------------------------------
578
579 void PushMessagingMessageFilter::OnUnsubscribe(
580 int request_id, int64_t service_worker_registration_id) {
581 DCHECK_CURRENTLY_ON(BrowserThread::IO);
582 ServiceWorkerRegistration* service_worker_registration =
583 service_worker_context_->GetLiveRegistration(
584 service_worker_registration_id);
585 if (!service_worker_registration) {
586 DidUnregister(request_id, PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER);
587 return;
588 }
589
590 service_worker_context_->GetRegistrationUserData(
591 service_worker_registration_id, {kPushSenderIdServiceWorkerKey},
592 base::Bind(&PushMessagingMessageFilter::UnsubscribeHavingGottenSenderId,
593 weak_factory_io_to_io_.GetWeakPtr(), request_id,
594 service_worker_registration_id,
595 service_worker_registration->pattern().GetOrigin()));
596 }
597
598 void PushMessagingMessageFilter::UnsubscribeHavingGottenSenderId(
599 int request_id,
600 int64_t service_worker_registration_id,
601 const GURL& requesting_origin,
602 const std::vector<std::string>& sender_ids,
603 ServiceWorkerStatusCode service_worker_status) {
604 DCHECK_CURRENTLY_ON(BrowserThread::IO);
605
606 std::string sender_id;
607 if (service_worker_status == SERVICE_WORKER_OK) {
608 DCHECK_EQ(1u, sender_ids.size());
609 sender_id = sender_ids[0];
610 }
611 BrowserThread::PostTask(
612 BrowserThread::UI, FROM_HERE,
613 base::Bind(&Core::UnregisterFromService, base::Unretained(ui_core_.get()),
614 request_id, service_worker_registration_id, requesting_origin,
615 sender_id));
616 }
617
618 void PushMessagingMessageFilter::Core::UnregisterFromService(
619 int request_id,
620 int64_t service_worker_registration_id,
621 const GURL& requesting_origin,
622 const std::string& sender_id) {
623 DCHECK_CURRENTLY_ON(BrowserThread::UI);
624 PushMessagingService* push_service = service();
625 if (!push_service) {
626 // This shouldn't be possible in incognito mode, since we've already checked
627 // that we have an existing registration. Hence it's ok to throw an error.
628 DCHECK(!is_incognito());
629 BrowserThread::PostTask(
630 BrowserThread::IO, FROM_HERE,
631 base::Bind(&PushMessagingMessageFilter::DidUnregister, io_parent_,
632 request_id,
633 PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
634 return;
635 }
636
637 push_service->Unsubscribe(
638 requesting_origin, service_worker_registration_id, sender_id,
639 base::Bind(&Core::DidUnregisterFromService,
640 weak_factory_ui_to_ui_.GetWeakPtr(), request_id,
641 service_worker_registration_id));
642 }
643
644 void PushMessagingMessageFilter::Core::DidUnregisterFromService(
645 int request_id,
646 int64_t service_worker_registration_id,
647 PushUnregistrationStatus unregistration_status) {
648 DCHECK_CURRENTLY_ON(BrowserThread::UI);
649
650 BrowserThread::PostTask(
651 BrowserThread::IO, FROM_HERE,
652 base::Bind(&PushMessagingMessageFilter::DidUnregister, io_parent_,
653 request_id, unregistration_status));
654 }
655
656 void PushMessagingMessageFilter::DidUnregister(
657 int request_id,
658 PushUnregistrationStatus unregistration_status) {
659 // Only called from IO thread, but would be safe to call from UI thread.
660 DCHECK_CURRENTLY_ON(BrowserThread::IO);
661 switch (unregistration_status) {
662 case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED:
663 case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR:
664 case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR:
665 Send(new PushMessagingMsg_UnsubscribeSuccess(request_id, true));
666 break;
667 case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED:
668 Send(new PushMessagingMsg_UnsubscribeSuccess(request_id, false));
669 break;
670 case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER:
671 case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE:
672 case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR:
673 Send(new PushMessagingMsg_UnsubscribeError(
674 request_id, blink::WebPushError::ErrorTypeAbort,
675 PushUnregistrationStatusToString(unregistration_status)));
676 break;
677 case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR:
678 NOTREACHED();
679 break;
680 }
681 RecordUnregistrationStatus(unregistration_status);
682 }
683
684 // GetSubscription methods on both IO and UI threads, merged in order of use
685 // from PushMessagingMessageFilter and Core.
686 // -----------------------------------------------------------------------------
687
688 void PushMessagingMessageFilter::OnGetSubscription(
689 int request_id,
690 int64_t service_worker_registration_id) {
691 DCHECK_CURRENTLY_ON(BrowserThread::IO);
692 // TODO(johnme): Validate arguments?
693 service_worker_context_->GetRegistrationUserData(
694 service_worker_registration_id,
695 {kPushRegistrationIdServiceWorkerKey, kPushSenderIdServiceWorkerKey},
696 base::Bind(&PushMessagingMessageFilter::DidGetSubscription,
697 weak_factory_io_to_io_.GetWeakPtr(), request_id,
698 service_worker_registration_id));
699 }
700
701 void PushMessagingMessageFilter::DidGetSubscription(
702 int request_id,
703 int64_t service_worker_registration_id,
704 const std::vector<std::string>& push_subscription_id_and_sender_info,
705 ServiceWorkerStatusCode service_worker_status) {
706 DCHECK_CURRENTLY_ON(BrowserThread::IO);
707 PushGetRegistrationStatus get_status =
708 PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
709 switch (service_worker_status) {
710 case SERVICE_WORKER_OK: {
711 DCHECK_EQ(2u, push_subscription_id_and_sender_info.size());
712
713 if (!service_available_) {
714 // Return not found in incognito mode, so websites can't detect it.
715 get_status =
716 ui_core_->is_incognito()
717 ? PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND
718 : PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE;
719 break;
720 }
721
722 ServiceWorkerRegistration* registration =
723 service_worker_context_->GetLiveRegistration(
724 service_worker_registration_id);
725 const GURL origin = registration->pattern().GetOrigin();
726
727 const bool uses_standard_protocol =
728 IsApplicationServerKey(push_subscription_id_and_sender_info[1]);
729 const GURL endpoint = CreateEndpoint(
730 uses_standard_protocol, push_subscription_id_and_sender_info[0]);
731
732 auto callback =
733 base::Bind(&PushMessagingMessageFilter::DidGetSubscriptionKeys,
734 weak_factory_io_to_io_.GetWeakPtr(), request_id, endpoint,
735 push_subscription_id_and_sender_info[1]);
736
737 BrowserThread::PostTask(
738 BrowserThread::UI, FROM_HERE,
739 base::Bind(&Core::GetEncryptionInfoOnUI,
740 base::Unretained(ui_core_.get()), origin,
741 service_worker_registration_id,
742 push_subscription_id_and_sender_info[1], callback));
743
744 return;
745 }
746 case SERVICE_WORKER_ERROR_NOT_FOUND: {
747 get_status = PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND;
748 break;
749 }
750 case SERVICE_WORKER_ERROR_FAILED: {
751 get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
752 break;
753 }
754 case SERVICE_WORKER_ERROR_ABORT:
755 case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
756 case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
757 case SERVICE_WORKER_ERROR_EXISTS:
758 case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
759 case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
760 case SERVICE_WORKER_ERROR_IPC_FAILED:
761 case SERVICE_WORKER_ERROR_NETWORK:
762 case SERVICE_WORKER_ERROR_SECURITY:
763 case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
764 case SERVICE_WORKER_ERROR_STATE:
765 case SERVICE_WORKER_ERROR_TIMEOUT:
766 case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
767 case SERVICE_WORKER_ERROR_DISK_CACHE:
768 case SERVICE_WORKER_ERROR_REDUNDANT:
769 case SERVICE_WORKER_ERROR_DISALLOWED:
770 case SERVICE_WORKER_ERROR_MAX_VALUE: {
771 NOTREACHED() << "Got unexpected error code: " << service_worker_status
772 << " " << ServiceWorkerStatusToString(service_worker_status);
773 get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
774 break;
775 }
776 }
777 Send(new PushMessagingMsg_GetSubscriptionError(request_id, get_status));
778 RecordGetRegistrationStatus(get_status);
779 }
780
781 void PushMessagingMessageFilter::DidGetSubscriptionKeys(
782 int request_id,
783 const GURL& endpoint,
784 const std::string& sender_info,
785 bool success,
786 const std::vector<uint8_t>& p256dh,
787 const std::vector<uint8_t>& auth) {
788 DCHECK_CURRENTLY_ON(BrowserThread::IO);
789 if (!success) {
790 PushGetRegistrationStatus status =
791 PUSH_GETREGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE;
792
793 Send(new PushMessagingMsg_GetSubscriptionError(request_id, status));
794
795 RecordGetRegistrationStatus(status);
796 return;
797 }
798
799 PushSubscriptionOptions options;
800 // Chrome rejects subscription requests with userVisibleOnly false, so it must
801 // have been true. TODO(harkness): If Chrome starts accepting silent push
802 // subscriptions with userVisibleOnly false, the bool will need to be stored.
803 options.user_visible_only = true;
804 options.sender_info = sender_info;
805
806 Send(new PushMessagingMsg_GetSubscriptionSuccess(request_id, endpoint,
807 options, p256dh, auth));
808
809 RecordGetRegistrationStatus(PUSH_GETREGISTRATION_STATUS_SUCCESS);
810 }
811
812 // GetPermission methods on both IO and UI threads, merged in order of use from
813 // PushMessagingMessageFilter and Core.
814 // -----------------------------------------------------------------------------
815
816 void PushMessagingMessageFilter::OnGetPermissionStatus(
817 int request_id,
818 int64_t service_worker_registration_id,
819 bool user_visible) {
820 DCHECK_CURRENTLY_ON(BrowserThread::IO);
821 ServiceWorkerRegistration* service_worker_registration =
822 service_worker_context_->GetLiveRegistration(
823 service_worker_registration_id);
824 if (!service_worker_registration) {
825 Send(new PushMessagingMsg_GetPermissionStatusError(
826 request_id, blink::WebPushError::ErrorTypeAbort));
827 return;
828 }
829
830 BrowserThread::PostTask(
831 BrowserThread::UI, FROM_HERE,
832 base::Bind(&Core::GetPermissionStatusOnUI,
833 base::Unretained(ui_core_.get()),
834 service_worker_registration->pattern().GetOrigin(),
835 user_visible, request_id));
836 }
837
838 void PushMessagingMessageFilter::Core::GetPermissionStatusOnUI(
839 const GURL& requesting_origin, bool user_visible, int request_id) {
840 DCHECK_CURRENTLY_ON(BrowserThread::UI);
841 blink::WebPushPermissionStatus permission_status;
842 PushMessagingService* push_service = service();
843 if (push_service) {
844 if (!user_visible && !push_service->SupportNonVisibleMessages()) {
845 Send(new PushMessagingMsg_GetPermissionStatusError(
846 request_id, blink::WebPushError::ErrorTypeNotSupported));
847 return;
848 }
849 permission_status =
850 push_service->GetPermissionStatus(requesting_origin, user_visible);
851 } else if (is_incognito()) {
852 // Return prompt, so the website can't detect incognito mode.
853 permission_status = blink::WebPushPermissionStatusPrompt;
854 } else {
855 Send(new PushMessagingMsg_GetPermissionStatusError(
856 request_id, blink::WebPushError::ErrorTypeAbort));
857 return;
858 }
859 Send(new PushMessagingMsg_GetPermissionStatusSuccess(request_id,
860 permission_status));
861 }
862
863 // Helper methods on both IO and UI threads, merged from
864 // PushMessagingMessageFilter and Core.
865 // -----------------------------------------------------------------------------
866
867 void PushMessagingMessageFilter::Core::GetEncryptionInfoOnUI(
868 const GURL& origin,
869 int64_t service_worker_registration_id,
870 const std::string& sender_id,
871 const PushMessagingService::EncryptionInfoCallback& io_thread_callback) {
872 DCHECK_CURRENTLY_ON(BrowserThread::UI);
873 PushMessagingService* push_service = service();
874 if (push_service) {
875 push_service->GetEncryptionInfo(
876 origin, service_worker_registration_id, sender_id,
877 base::Bind(&ForwardEncryptionInfoToIOThreadProxy, io_thread_callback));
878 return;
879 }
880
881 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
882 base::Bind(io_thread_callback, false /* success */,
883 std::vector<uint8_t>() /* p256dh */,
884 std::vector<uint8_t>() /* auth */));
885 }
886
887 void PushMessagingMessageFilter::Core::Send(IPC::Message* message) {
888 BrowserThread::PostTask(
889 BrowserThread::IO, FROM_HERE,
890 base::Bind(&PushMessagingMessageFilter::SendIPC, io_parent_,
891 base::Passed(base::WrapUnique(message))));
892 }
893
894 void PushMessagingMessageFilter::SendIPC(
895 std::unique_ptr<IPC::Message> message) {
896 Send(message.release());
897 }
898
899 GURL PushMessagingMessageFilter::CreateEndpoint(
900 bool standard_protocol,
901 const std::string& subscription_id) const {
902 const GURL& base =
903 standard_protocol ? web_push_protocol_endpoint_ : default_endpoint_;
904
905 return GURL(base.spec() + subscription_id);
906 }
907
908 PushMessagingService* PushMessagingMessageFilter::Core::service() {
909 DCHECK_CURRENTLY_ON(BrowserThread::UI);
910 RenderProcessHost* process_host =
911 RenderProcessHost::FromID(render_process_id_);
912 return process_host
913 ? process_host->GetBrowserContext()->GetPushMessagingService()
914 : nullptr;
915 }
916
917 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698