OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/services/gcm/push_messaging_service_impl.h" | 5 #include "chrome/browser/services/gcm/push_messaging_service_impl.h" |
6 | 6 |
7 #include <bitset> | 7 #include <bitset> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 } | 173 } |
174 | 174 |
175 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { | 175 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const { |
176 return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); | 176 return PushMessagingApplicationId::Get(profile_, app_id).IsValid(); |
177 } | 177 } |
178 | 178 |
179 void PushMessagingServiceImpl::ShutdownHandler() { | 179 void PushMessagingServiceImpl::ShutdownHandler() { |
180 // TODO(johnme): Do any necessary cleanup. | 180 // TODO(johnme): Do any necessary cleanup. |
181 } | 181 } |
182 | 182 |
| 183 // OnMessage methods ----------------------------------------------------------- |
| 184 |
183 void PushMessagingServiceImpl::OnMessage( | 185 void PushMessagingServiceImpl::OnMessage( |
184 const std::string& app_id, | 186 const std::string& app_id, |
185 const GCMClient::IncomingMessage& message) { | 187 const GCMClient::IncomingMessage& message) { |
186 PushMessagingApplicationId application_id = | 188 PushMessagingApplicationId application_id = |
187 PushMessagingApplicationId::Get(profile_, app_id); | 189 PushMessagingApplicationId::Get(profile_, app_id); |
188 // Drop message and unregister if app id was unknown (maybe recently deleted). | 190 // Drop message and unregister if app id was unknown (maybe recently deleted). |
189 if (!application_id.IsValid()) { | 191 if (!application_id.IsValid()) { |
190 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, | 192 DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1, message, |
191 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); | 193 content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); |
192 return; | 194 return; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 profile_, | 230 profile_, |
229 application_id.origin(), | 231 application_id.origin(), |
230 application_id.service_worker_registration_id(), | 232 application_id.service_worker_registration_id(), |
231 data, | 233 data, |
232 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, | 234 base::Bind(&PushMessagingServiceImpl::DeliverMessageCallback, |
233 weak_factory_.GetWeakPtr(), | 235 weak_factory_.GetWeakPtr(), |
234 application_id.app_id_guid(), application_id.origin(), | 236 application_id.app_id_guid(), application_id.origin(), |
235 application_id.service_worker_registration_id(), message)); | 237 application_id.service_worker_registration_id(), message)); |
236 } | 238 } |
237 | 239 |
238 void PushMessagingServiceImpl::OnContentSettingChanged( | |
239 const ContentSettingsPattern& primary_pattern, | |
240 const ContentSettingsPattern& secondary_pattern, | |
241 ContentSettingsType content_type, | |
242 std::string resource_identifier) { | |
243 if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING && | |
244 content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { | |
245 return; | |
246 } | |
247 | |
248 for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) { | |
249 // If |primary_pattern| is not valid, we should always check for a | |
250 // permission change because it can happen for example when the entire | |
251 // Push or Notifications permissions are cleared. | |
252 // Otherwise, the permission should be checked if the pattern matches the | |
253 // origin. | |
254 if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin())) | |
255 continue; | |
256 | |
257 if (HasPermission(id.origin())) | |
258 continue; | |
259 | |
260 // Unregister the PushMessagingApplicationId with the push service. | |
261 Unregister(id.app_id_guid(), true /* retry */, UnregisterCallback()); | |
262 | |
263 // Clear the associated service worker push registration id. | |
264 PushMessagingService::ClearPushRegistrationID( | |
265 profile_, id.origin(), id.service_worker_registration_id()); | |
266 } | |
267 } | |
268 | |
269 void PushMessagingServiceImpl::SetProfileForTesting(Profile* profile) { | |
270 profile_ = profile; | |
271 profile_->GetHostContentSettingsMap()->AddObserver(this); | |
272 } | |
273 | |
274 void PushMessagingServiceImpl::DeliverMessageCallback( | 240 void PushMessagingServiceImpl::DeliverMessageCallback( |
275 const std::string& app_id_guid, | 241 const std::string& app_id_guid, |
276 const GURL& requesting_origin, | 242 const GURL& requesting_origin, |
277 int64 service_worker_registration_id, | 243 int64 service_worker_registration_id, |
278 const GCMClient::IncomingMessage& message, | 244 const GCMClient::IncomingMessage& message, |
279 content::PushDeliveryStatus status) { | 245 content::PushDeliveryStatus status) { |
280 // TODO(mvanouwerkerk): UMA logging. | 246 // TODO(mvanouwerkerk): UMA logging. |
281 // TODO(mvanouwerkerk): Show a warning in the developer console of the | 247 // TODO(mvanouwerkerk): Show a warning in the developer console of the |
282 // Service Worker corresponding to app_id (and/or on an internals page). | 248 // Service Worker corresponding to app_id (and/or on an internals page). |
283 // TODO(mvanouwerkerk): Is there a way to recover from failure? | 249 // TODO(mvanouwerkerk): Is there a way to recover from failure? |
284 switch (status) { | 250 switch (status) { |
285 // Call RequireUserVisibleUX if the message was delivered to the Service | 251 // Call RequireUserVisibleUX if the message was delivered to the Service |
286 // Worker JS, even if the website's event handler failed (to prevent sites | 252 // Worker JS, even if the website's event handler failed (to prevent sites |
287 // deliberately failing in order to avoid having to show notifications). | 253 // deliberately failing in order to avoid having to show notifications). |
288 case content::PUSH_DELIVERY_STATUS_SUCCESS: | 254 case content::PUSH_DELIVERY_STATUS_SUCCESS: |
289 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: | 255 case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: |
290 RequireUserVisibleUX(requesting_origin, service_worker_registration_id); | 256 RequireUserVisibleUX(requesting_origin, service_worker_registration_id); |
291 break; | 257 break; |
292 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: | 258 case content::PUSH_DELIVERY_STATUS_INVALID_MESSAGE: |
293 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: | 259 case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: |
294 break; | 260 break; |
295 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: | 261 case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: |
296 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: | 262 case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: |
297 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: | 263 case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: |
298 Unregister(app_id_guid, true /*retry_on_failure*/, UnregisterCallback()); | 264 Unregister(app_id_guid, message.sender_id, true /* retry_on_failure */, |
| 265 UnregisterCallback()); |
299 break; | 266 break; |
300 } | 267 } |
301 } | 268 } |
302 | 269 |
303 void PushMessagingServiceImpl::RequireUserVisibleUX( | 270 void PushMessagingServiceImpl::RequireUserVisibleUX( |
304 const GURL& requesting_origin, int64 service_worker_registration_id) { | 271 const GURL& requesting_origin, int64 service_worker_registration_id) { |
305 #if defined(ENABLE_NOTIFICATIONS) | 272 #if defined(ENABLE_NOTIFICATIONS) |
306 // TODO(johnme): Relax this heuristic slightly. | 273 // TODO(johnme): Relax this heuristic slightly. |
307 PlatformNotificationServiceImpl* notification_service = | 274 PlatformNotificationServiceImpl* notification_service = |
308 PlatformNotificationServiceImpl::GetInstance(); | 275 PlatformNotificationServiceImpl::GetInstance(); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 PlatformNotificationServiceImpl::GetInstance(); | 422 PlatformNotificationServiceImpl::GetInstance(); |
456 notification_service->DisplayPersistentNotification( | 423 notification_service->DisplayPersistentNotification( |
457 profile_, | 424 profile_, |
458 service_worker_registration_id, | 425 service_worker_registration_id, |
459 requesting_origin, | 426 requesting_origin, |
460 SkBitmap() /* icon */, | 427 SkBitmap() /* icon */, |
461 notification_data); | 428 notification_data); |
462 } | 429 } |
463 } | 430 } |
464 | 431 |
| 432 // Other GCMAppHandler methods ------------------------------------------------- |
| 433 |
465 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { | 434 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { |
466 // TODO(mvanouwerkerk): Fire push error event on the Service Worker | 435 // TODO(mvanouwerkerk): Fire push error event on the Service Worker |
467 // corresponding to app_id. | 436 // corresponding to app_id. |
468 } | 437 } |
469 | 438 |
470 void PushMessagingServiceImpl::OnSendError( | 439 void PushMessagingServiceImpl::OnSendError( |
471 const std::string& app_id, | 440 const std::string& app_id, |
472 const GCMClient::SendErrorDetails& send_error_details) { | 441 const GCMClient::SendErrorDetails& send_error_details) { |
473 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; | 442 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; |
474 } | 443 } |
475 | 444 |
476 void PushMessagingServiceImpl::OnSendAcknowledged( | 445 void PushMessagingServiceImpl::OnSendAcknowledged( |
477 const std::string& app_id, | 446 const std::string& app_id, |
478 const std::string& message_id) { | 447 const std::string& message_id) { |
479 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; | 448 NOTREACHED() << "The Push API shouldn't have sent messages upstream"; |
480 } | 449 } |
481 | 450 |
| 451 // GetPushEndpoint method ------------------------------------------------------ |
| 452 |
482 GURL PushMessagingServiceImpl::GetPushEndpoint() { | 453 GURL PushMessagingServiceImpl::GetPushEndpoint() { |
483 return GURL(std::string(kPushMessagingEndpoint)); | 454 return GURL(std::string(kPushMessagingEndpoint)); |
484 } | 455 } |
485 | 456 |
| 457 // Register and GetPermissionStatus methods ------------------------------------ |
| 458 |
486 void PushMessagingServiceImpl::RegisterFromDocument( | 459 void PushMessagingServiceImpl::RegisterFromDocument( |
487 const GURL& requesting_origin, | 460 const GURL& requesting_origin, |
488 int64 service_worker_registration_id, | 461 int64 service_worker_registration_id, |
489 const std::string& sender_id, | 462 const std::string& sender_id, |
490 int renderer_id, | 463 int renderer_id, |
491 int render_frame_id, | 464 int render_frame_id, |
492 bool user_visible_only, | 465 bool user_visible_only, |
493 const content::PushMessagingService::RegisterCallback& callback) { | 466 const content::PushMessagingService::RegisterCallback& callback) { |
494 if (!gcm_profile_service_->driver()) { | 467 if (!gcm_profile_service_->driver()) { |
495 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; | 468 NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 IncreasePushRegistrationCount(1, true /* is_pending */); | 613 IncreasePushRegistrationCount(1, true /* is_pending */); |
641 std::vector<std::string> sender_ids(1, sender_id); | 614 std::vector<std::string> sender_ids(1, sender_id); |
642 gcm_profile_service_->driver()->Register( | 615 gcm_profile_service_->driver()->Register( |
643 application_id.app_id_guid(), | 616 application_id.app_id_guid(), |
644 sender_ids, | 617 sender_ids, |
645 base::Bind(&PushMessagingServiceImpl::DidRegister, | 618 base::Bind(&PushMessagingServiceImpl::DidRegister, |
646 weak_factory_.GetWeakPtr(), | 619 weak_factory_.GetWeakPtr(), |
647 application_id, register_callback)); | 620 application_id, register_callback)); |
648 } | 621 } |
649 | 622 |
| 623 // Unregister methods ---------------------------------------------------------- |
| 624 |
650 void PushMessagingServiceImpl::Unregister( | 625 void PushMessagingServiceImpl::Unregister( |
651 const GURL& requesting_origin, | 626 const GURL& requesting_origin, |
652 int64 service_worker_registration_id, | 627 int64 service_worker_registration_id, |
| 628 const std::string& sender_id, |
653 bool retry_on_failure, | 629 bool retry_on_failure, |
654 const content::PushMessagingService::UnregisterCallback& callback) { | 630 const content::PushMessagingService::UnregisterCallback& callback) { |
655 DCHECK(gcm_profile_service_->driver()); | 631 DCHECK(gcm_profile_service_->driver()); |
656 | 632 |
657 PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( | 633 PushMessagingApplicationId application_id = PushMessagingApplicationId::Get( |
658 profile_, requesting_origin, service_worker_registration_id); | 634 profile_, requesting_origin, service_worker_registration_id); |
659 if (!application_id.IsValid()) { | 635 if (!application_id.IsValid()) { |
660 if (!callback.is_null()) { | 636 if (!callback.is_null()) { |
661 callback.Run( | 637 callback.Run( |
662 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); | 638 content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); |
663 } | 639 } |
664 return; | 640 return; |
665 } | 641 } |
666 | 642 |
667 Unregister(application_id.app_id_guid(), retry_on_failure, callback); | 643 Unregister(application_id.app_id_guid(), sender_id, retry_on_failure, |
| 644 callback); |
668 } | 645 } |
669 | 646 |
670 void PushMessagingServiceImpl::Unregister( | 647 void PushMessagingServiceImpl::Unregister( |
671 const std::string& app_id_guid, | 648 const std::string& app_id_guid, |
| 649 const std::string& sender_id, |
672 bool retry_on_failure, | 650 bool retry_on_failure, |
673 const content::PushMessagingService::UnregisterCallback& callback) { | 651 const content::PushMessagingService::UnregisterCallback& callback) { |
674 DCHECK(gcm_profile_service_->driver()); | 652 DCHECK(gcm_profile_service_->driver()); |
675 | 653 |
676 if (retry_on_failure) { | 654 if (retry_on_failure) { |
677 // Delete the mapping for this app id, to guarantee that no messages get | 655 // Delete the mapping for this app id, to guarantee that no messages get |
678 // delivered in future (even if unregistration fails). | 656 // delivered in future (even if unregistration fails). |
679 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, | 657 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, |
680 // and retry unregistration if it fails due to network errors. | 658 // and retry unregistration if it fails due to network errors. |
681 PushMessagingApplicationId application_id = | 659 PushMessagingApplicationId application_id = |
682 PushMessagingApplicationId::Get(profile_, app_id_guid); | 660 PushMessagingApplicationId::Get(profile_, app_id_guid); |
683 if (application_id.IsValid()) | 661 if (application_id.IsValid()) |
684 application_id.DeleteFromDisk(profile_); | 662 application_id.DeleteFromDisk(profile_); |
685 } | 663 } |
686 | 664 |
687 gcm_profile_service_->driver()->Unregister( | 665 const auto& unregister_callback = |
688 app_id_guid, | |
689 base::Bind(&PushMessagingServiceImpl::DidUnregister, | 666 base::Bind(&PushMessagingServiceImpl::DidUnregister, |
690 weak_factory_.GetWeakPtr(), | 667 weak_factory_.GetWeakPtr(), |
691 app_id_guid, retry_on_failure, callback)); | 668 app_id_guid, retry_on_failure, callback); |
| 669 #if defined(OS_ANDROID) |
| 670 // On Android the backend is different, and requires the original sender_id. |
| 671 gcm_profile_service_->driver()->UnregisterWithSenderId(app_id_guid, sender_id, |
| 672 unregister_callback); |
| 673 #else |
| 674 gcm_profile_service_->driver()->Unregister(app_id_guid, unregister_callback); |
| 675 #endif |
692 } | 676 } |
693 | 677 |
694 void PushMessagingServiceImpl::DidUnregister( | 678 void PushMessagingServiceImpl::DidUnregister( |
695 const std::string& app_id_guid, | 679 const std::string& app_id_guid, |
696 bool retry_on_failure, | 680 bool retry_on_failure, |
697 const content::PushMessagingService::UnregisterCallback& callback, | 681 const content::PushMessagingService::UnregisterCallback& callback, |
698 GCMClient::Result result) { | 682 GCMClient::Result result) { |
699 if (result == GCMClient::SUCCESS) { | 683 if (result == GCMClient::SUCCESS) { |
700 PushMessagingApplicationId application_id = | 684 PushMessagingApplicationId application_id = |
701 PushMessagingApplicationId::Get(profile_, app_id_guid); | 685 PushMessagingApplicationId::Get(profile_, app_id_guid); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); | 717 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); |
734 break; | 718 break; |
735 default: | 719 default: |
736 NOTREACHED() << "Unexpected GCMClient::Result value."; | 720 NOTREACHED() << "Unexpected GCMClient::Result value."; |
737 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); | 721 callback.Run(content::PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR); |
738 break; | 722 break; |
739 } | 723 } |
740 } | 724 } |
741 } | 725 } |
742 | 726 |
| 727 // OnContentSettingChanged methods --------------------------------------------- |
| 728 |
| 729 void PushMessagingServiceImpl::OnContentSettingChanged( |
| 730 const ContentSettingsPattern& primary_pattern, |
| 731 const ContentSettingsPattern& secondary_pattern, |
| 732 ContentSettingsType content_type, |
| 733 std::string resource_identifier) { |
| 734 if (content_type != CONTENT_SETTINGS_TYPE_PUSH_MESSAGING && |
| 735 content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { |
| 736 return; |
| 737 } |
| 738 |
| 739 for (const auto& id : PushMessagingApplicationId::GetAll(profile_)) { |
| 740 // If |primary_pattern| is not valid, we should always check for a |
| 741 // permission change because it can happen for example when the entire |
| 742 // Push or Notifications permissions are cleared. |
| 743 // Otherwise, the permission should be checked if the pattern matches the |
| 744 // origin. |
| 745 if (primary_pattern.IsValid() && !primary_pattern.Matches(id.origin())) |
| 746 continue; |
| 747 |
| 748 if (HasPermission(id.origin())) |
| 749 continue; |
| 750 |
| 751 PushMessagingService::GetSenderId( |
| 752 profile_, id.origin(), id.service_worker_registration_id(), |
| 753 base::Bind( |
| 754 &PushMessagingServiceImpl::UnregisterBecausePermissionRevoked, |
| 755 weak_factory_.GetWeakPtr(), id)); |
| 756 } |
| 757 } |
| 758 |
| 759 void PushMessagingServiceImpl::UnregisterBecausePermissionRevoked( |
| 760 const PushMessagingApplicationId& id, |
| 761 const std::string& sender_id, bool success, bool not_found) { |
| 762 // Unregister the PushMessagingApplicationId with the push service. |
| 763 Unregister(id.app_id_guid(), sender_id, true /* retry_on_failure */, |
| 764 UnregisterCallback()); |
| 765 |
| 766 // Clear the associated service worker push registration id. |
| 767 PushMessagingService::ClearPushRegistrationID( |
| 768 profile_, id.origin(), id.service_worker_registration_id()); |
| 769 } |
| 770 |
| 771 // Helper methods -------------------------------------------------------------- |
| 772 |
743 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { | 773 bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { |
744 gcm::PushMessagingPermissionContext* permission_context = | 774 gcm::PushMessagingPermissionContext* permission_context = |
745 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); | 775 gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); |
746 DCHECK(permission_context); | 776 DCHECK(permission_context); |
747 | 777 |
748 return permission_context->GetPermissionStatus(origin, origin) == | 778 return permission_context->GetPermissionStatus(origin, origin) == |
749 CONTENT_SETTING_ALLOW; | 779 CONTENT_SETTING_ALLOW; |
750 } | 780 } |
751 | 781 |
| 782 void PushMessagingServiceImpl::SetProfileForTesting(Profile* profile) { |
| 783 profile_ = profile; |
| 784 profile_->GetHostContentSettingsMap()->AddObserver(this); |
| 785 } |
| 786 |
752 } // namespace gcm | 787 } // namespace gcm |
OLD | NEW |