| Index: content/browser/push_messaging/push_messaging_message_filter.cc
|
| diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc
|
| deleted file mode 100644
|
| index 9820f4f151d95be74ca3f6e4ad5b6fc6a80158dc..0000000000000000000000000000000000000000
|
| --- a/content/browser/push_messaging/push_messaging_message_filter.cc
|
| +++ /dev/null
|
| @@ -1,917 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "content/browser/push_messaging/push_messaging_message_filter.h"
|
| -
|
| -#include <string>
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/metrics/histogram_macros.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "content/browser/renderer_host/render_process_host_impl.h"
|
| -#include "content/browser/service_worker/service_worker_context_core.h"
|
| -#include "content/browser/service_worker/service_worker_context_wrapper.h"
|
| -#include "content/browser/service_worker/service_worker_storage.h"
|
| -#include "content/common/push_messaging_messages.h"
|
| -#include "content/public/browser/browser_context.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/permission_manager.h"
|
| -#include "content/public/browser/permission_type.h"
|
| -#include "content/public/browser/push_messaging_service.h"
|
| -#include "content/public/browser/render_frame_host.h"
|
| -#include "content/public/browser/web_contents.h"
|
| -#include "content/public/common/child_process_host.h"
|
| -#include "content/public/common/console_message_level.h"
|
| -#include "content/public/common/content_switches.h"
|
| -#include "content/public/common/push_messaging_status.h"
|
| -#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
|
| -
|
| -namespace content {
|
| -
|
| -// Service Worker database keys. If a registration ID is stored, the stored
|
| -// sender ID must be the one used to register. Unfortunately, this isn't always
|
| -// true of pre-InstanceID registrations previously stored in the database, but
|
| -// fortunately it's less important for their sender ID to be accurate.
|
| -const char kPushSenderIdServiceWorkerKey[] = "push_sender_id";
|
| -const char kPushRegistrationIdServiceWorkerKey[] = "push_registration_id";
|
| -
|
| -namespace {
|
| -
|
| -// Chrome currently does not support the Push API in incognito.
|
| -const char kIncognitoPushUnsupportedMessage[] =
|
| - "Chrome currently does not support the Push API in incognito mode "
|
| - "(https://crbug.com/401439). There is deliberately no way to "
|
| - "feature-detect this, since incognito mode needs to be undetectable by "
|
| - "websites.";
|
| -
|
| -// These UMA methods are only called from IO thread, but it would be acceptable
|
| -// (even though slightly racy) to call them from UI thread as well, see
|
| -// https://groups.google.com/a/chromium.org/d/msg/chromium-dev/FNzZRJtN2aw/Aw0CWAXJJ1kJ
|
| -void RecordRegistrationStatus(PushRegistrationStatus status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - UMA_HISTOGRAM_ENUMERATION("PushMessaging.RegistrationStatus", status,
|
| - PUSH_REGISTRATION_STATUS_LAST + 1);
|
| -}
|
| -
|
| -void RecordUnregistrationStatus(PushUnregistrationStatus status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationStatus", status,
|
| - PUSH_UNREGISTRATION_STATUS_LAST + 1);
|
| -}
|
| -
|
| -void RecordGetRegistrationStatus(PushGetRegistrationStatus status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - UMA_HISTOGRAM_ENUMERATION("PushMessaging.GetRegistrationStatus", status,
|
| - PUSH_GETREGISTRATION_STATUS_LAST + 1);
|
| -}
|
| -
|
| -// Curries the |success| and |p256dh| parameters over to |callback| and
|
| -// posts a task to invoke |callback| on the IO thread.
|
| -void ForwardEncryptionInfoToIOThreadProxy(
|
| - const PushMessagingService::EncryptionInfoCallback& callback,
|
| - bool success,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| - base::Bind(callback, success, p256dh, auth));
|
| -}
|
| -
|
| -// Returns whether |sender_info| contains a valid application server key, that
|
| -// is, a NIST P-256 public key in uncompressed format.
|
| -bool IsApplicationServerKey(const std::string& sender_info) {
|
| - return sender_info.size() == 65 && sender_info[0] == 0x04;
|
| -}
|
| -
|
| -// Returns sender_info if non-empty, otherwise checks if stored_sender_id
|
| -// may be used as a fallback and if so, returns stored_sender_id instead.
|
| -//
|
| -// This is in order to support the legacy way of subscribing from a service
|
| -// worker (first subscribe from the document using a gcm_sender_id set in the
|
| -// manifest, and then subscribe from the service worker with no key).
|
| -//
|
| -// An empty string will be returned if sender_info is empty and the fallback
|
| -// is not a numeric gcm sender id.
|
| -std::string FixSenderInfo(const std::string& sender_info,
|
| - const std::string& stored_sender_id) {
|
| - if (!sender_info.empty())
|
| - return sender_info;
|
| - if (base::ContainsOnlyChars(stored_sender_id, "0123456789"))
|
| - return stored_sender_id;
|
| - return std::string();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -struct PushMessagingMessageFilter::RegisterData {
|
| - RegisterData();
|
| - RegisterData(const RegisterData& other) = default;
|
| - bool FromDocument() const;
|
| - int request_id;
|
| - GURL requesting_origin;
|
| - int64_t service_worker_registration_id;
|
| - PushSubscriptionOptions options;
|
| - // The following member should only be read if FromDocument() is true.
|
| - int render_frame_id;
|
| -};
|
| -
|
| -// Inner core of this message filter which lives on the UI thread.
|
| -class PushMessagingMessageFilter::Core {
|
| - public:
|
| - Core(const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
|
| - int render_process_id);
|
| -
|
| - // Public Register methods on UI thread --------------------------------------
|
| -
|
| - // Called via PostTask from IO thread.
|
| - void RegisterOnUI(const RegisterData& data);
|
| -
|
| - // Public Unregister methods on UI thread ------------------------------------
|
| -
|
| - // Called via PostTask from IO thread.
|
| - void UnregisterFromService(int request_id,
|
| - int64_t service_worker_registration_id,
|
| - const GURL& requesting_origin,
|
| - const std::string& sender_id);
|
| -
|
| - // Public GetPermission methods on UI thread ---------------------------------
|
| -
|
| - // Called via PostTask from IO thread.
|
| - void GetPermissionStatusOnUI(const GURL& requesting_origin,
|
| - bool user_visible,
|
| - int request_id);
|
| -
|
| - // Public helper methods on UI thread ----------------------------------------
|
| -
|
| - // Called via PostTask from IO thread. The |io_thread_callback| callback
|
| - // will be invoked on the IO thread.
|
| - void GetEncryptionInfoOnUI(
|
| - const GURL& origin,
|
| - int64_t service_worker_registration_id,
|
| - const std::string& sender_id,
|
| - const PushMessagingService::EncryptionInfoCallback& io_thread_callback);
|
| -
|
| - // Called (directly) from both the UI and IO threads.
|
| - bool is_incognito() const { return is_incognito_; }
|
| -
|
| - // Returns a push messaging service. May return null.
|
| - PushMessagingService* service();
|
| -
|
| - private:
|
| - friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
|
| - friend class base::DeleteHelper<Core>;
|
| -
|
| - ~Core();
|
| -
|
| - // Private Register methods on UI thread -------------------------------------
|
| -
|
| - void DidRequestPermissionInIncognito(const RegisterData& data,
|
| - blink::mojom::PermissionStatus status);
|
| -
|
| - void DidRegister(const RegisterData& data,
|
| - const std::string& push_registration_id,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth,
|
| - PushRegistrationStatus status);
|
| -
|
| - // Private Unregister methods on UI thread -----------------------------------
|
| -
|
| - void DidUnregisterFromService(int request_id,
|
| - int64_t service_worker_registration_id,
|
| - PushUnregistrationStatus unregistration_status);
|
| -
|
| - // Private helper methods on UI thread ---------------------------------------
|
| -
|
| - void Send(IPC::Message* message);
|
| -
|
| - // Outer part of this message filter which lives on the IO thread.
|
| - base::WeakPtr<PushMessagingMessageFilter> io_parent_;
|
| -
|
| - int render_process_id_;
|
| -
|
| - bool is_incognito_;
|
| -
|
| - base::WeakPtrFactory<Core> weak_factory_ui_to_ui_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Core);
|
| -};
|
| -
|
| -PushMessagingMessageFilter::RegisterData::RegisterData()
|
| - : request_id(0),
|
| - service_worker_registration_id(0),
|
| - render_frame_id(ChildProcessHost::kInvalidUniqueID) {}
|
| -
|
| -bool PushMessagingMessageFilter::RegisterData::FromDocument() const {
|
| - return render_frame_id != ChildProcessHost::kInvalidUniqueID;
|
| -}
|
| -
|
| -PushMessagingMessageFilter::Core::Core(
|
| - const base::WeakPtr<PushMessagingMessageFilter>& io_parent,
|
| - int render_process_id)
|
| - : io_parent_(io_parent),
|
| - render_process_id_(render_process_id),
|
| - weak_factory_ui_to_ui_(this) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - RenderProcessHost* process_host =
|
| - RenderProcessHost::FromID(render_process_id_); // Can't be null yet.
|
| - is_incognito_ = process_host->GetBrowserContext()->IsOffTheRecord();
|
| -}
|
| -
|
| -PushMessagingMessageFilter::Core::~Core() {}
|
| -
|
| -PushMessagingMessageFilter::PushMessagingMessageFilter(
|
| - int render_process_id,
|
| - ServiceWorkerContextWrapper* service_worker_context)
|
| - : BrowserMessageFilter(PushMessagingMsgStart),
|
| - service_worker_context_(service_worker_context),
|
| - weak_factory_io_to_io_(this) {
|
| - // Although this class is used only on the IO thread, it is constructed on UI.
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - // Normally, it would be unsafe to obtain a weak pointer from the UI thread,
|
| - // but it's ok in the constructor since we can't be destroyed before our
|
| - // constructor finishes.
|
| - ui_core_.reset(
|
| - new Core(weak_factory_io_to_io_.GetWeakPtr(), render_process_id));
|
| -
|
| - PushMessagingService* service = ui_core_->service();
|
| - service_available_ = !!service;
|
| -
|
| - if (service_available_) {
|
| - default_endpoint_ = service->GetEndpoint(false /* standard_protocol */);
|
| - web_push_protocol_endpoint_ =
|
| - service->GetEndpoint(true /* standard_protocol */);
|
| - }
|
| -}
|
| -
|
| -PushMessagingMessageFilter::~PushMessagingMessageFilter() {}
|
| -
|
| -void PushMessagingMessageFilter::OnDestruct() const {
|
| - BrowserThread::DeleteOnIOThread::Destruct(this);
|
| -}
|
| -
|
| -bool PushMessagingMessageFilter::OnMessageReceived(
|
| - const IPC::Message& message) {
|
| - bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP(PushMessagingMessageFilter, message)
|
| - IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Subscribe, OnSubscribe)
|
| - IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Unsubscribe, OnUnsubscribe)
|
| - IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetSubscription, OnGetSubscription)
|
| - IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetPermissionStatus,
|
| - OnGetPermissionStatus)
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP()
|
| - return handled;
|
| -}
|
| -
|
| -// Subscribe methods on both IO and UI threads, merged in order of use from
|
| -// PushMessagingMessageFilter and Core.
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -void PushMessagingMessageFilter::OnSubscribe(
|
| - int render_frame_id,
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - const PushSubscriptionOptions& options) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - // TODO(mvanouwerkerk): Validate arguments?
|
| - RegisterData data;
|
| -
|
| - // Will be ChildProcessHost::kInvalidUniqueID in requests from Service Worker.
|
| - data.render_frame_id = render_frame_id;
|
| -
|
| - data.request_id = request_id;
|
| - data.service_worker_registration_id = service_worker_registration_id;
|
| - data.options = options;
|
| -
|
| - ServiceWorkerRegistration* service_worker_registration =
|
| - service_worker_context_->GetLiveRegistration(
|
| - data.service_worker_registration_id);
|
| - if (!service_worker_registration ||
|
| - !service_worker_registration->active_version()) {
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER);
|
| - return;
|
| - }
|
| - data.requesting_origin = service_worker_registration->pattern().GetOrigin();
|
| -
|
| - DCHECK(!(data.options.sender_info.empty() && data.FromDocument()));
|
| -
|
| - service_worker_context_->GetRegistrationUserData(
|
| - data.service_worker_registration_id,
|
| - {kPushRegistrationIdServiceWorkerKey, kPushSenderIdServiceWorkerKey},
|
| - base::Bind(&PushMessagingMessageFilter::DidCheckForExistingRegistration,
|
| - weak_factory_io_to_io_.GetWeakPtr(), data));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidCheckForExistingRegistration(
|
| - const RegisterData& data,
|
| - const std::vector<std::string>& push_registration_id_and_sender_id,
|
| - ServiceWorkerStatusCode service_worker_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (service_worker_status == SERVICE_WORKER_OK) {
|
| - DCHECK_EQ(2u, push_registration_id_and_sender_id.size());
|
| - const auto& push_registration_id = push_registration_id_and_sender_id[0];
|
| - const auto& stored_sender_id = push_registration_id_and_sender_id[1];
|
| - std::string fixed_sender_id =
|
| - FixSenderInfo(data.options.sender_info, stored_sender_id);
|
| - if (fixed_sender_id.empty()) {
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
|
| - return;
|
| - }
|
| - if (fixed_sender_id != stored_sender_id) {
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH);
|
| - return;
|
| - }
|
| - auto callback = base::Bind(
|
| - &PushMessagingMessageFilter::DidGetEncryptionKeys,
|
| - weak_factory_io_to_io_.GetWeakPtr(), data, push_registration_id);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::GetEncryptionInfoOnUI,
|
| - base::Unretained(ui_core_.get()), data.requesting_origin,
|
| - data.service_worker_registration_id, fixed_sender_id,
|
| - callback));
|
| - return;
|
| - }
|
| - // TODO(johnme): The spec allows the register algorithm to reject with an
|
| - // AbortError when accessing storage fails. Perhaps we should do that if
|
| - // service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND instead of
|
| - // attempting to do a fresh registration?
|
| - // https://w3c.github.io/push-api/#widl-PushRegistrationManager-register-Promise-PushRegistration
|
| - if (!data.options.sender_info.empty()) {
|
| - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::RegisterOnUI,
|
| - base::Unretained(ui_core_.get()), data));
|
| - } else {
|
| - // There is no existing registration and the sender_info passed in was
|
| - // empty, but perhaps there is a stored sender id we can use.
|
| - service_worker_context_->GetRegistrationUserData(
|
| - data.service_worker_registration_id, {kPushSenderIdServiceWorkerKey},
|
| - base::Bind(&PushMessagingMessageFilter::DidGetSenderIdFromStorage,
|
| - weak_factory_io_to_io_.GetWeakPtr(), data));
|
| - }
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidGetEncryptionKeys(
|
| - const RegisterData& data,
|
| - const std::string& push_registration_id,
|
| - bool success,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (!success) {
|
| - SendSubscriptionError(
|
| - data, PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE);
|
| - return;
|
| - }
|
| -
|
| - SendSubscriptionSuccess(data, PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE,
|
| - push_registration_id, p256dh, auth);
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidGetSenderIdFromStorage(
|
| - const RegisterData& data,
|
| - const std::vector<std::string>& stored_sender_id,
|
| - ServiceWorkerStatusCode service_worker_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (service_worker_status != SERVICE_WORKER_OK) {
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
|
| - return;
|
| - }
|
| - DCHECK_EQ(1u, stored_sender_id.size());
|
| - // We should only be here because no sender info was supplied to subscribe().
|
| - DCHECK(data.options.sender_info.empty());
|
| - std::string fixed_sender_id =
|
| - FixSenderInfo(data.options.sender_info, stored_sender_id[0]);
|
| - if (fixed_sender_id.empty()) {
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
|
| - return;
|
| - }
|
| - RegisterData mutated_data = data;
|
| - mutated_data.options.sender_info = fixed_sender_id;
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()),
|
| - mutated_data));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::RegisterOnUI(
|
| - const PushMessagingMessageFilter::RegisterData& data) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - PushMessagingService* push_service = service();
|
| - if (!push_service) {
|
| - if (!is_incognito()) {
|
| - // This might happen if InstanceIDProfileService::IsInstanceIDEnabled
|
| - // returns false because the Instance ID kill switch was enabled.
|
| - // TODO(johnme): Might be better not to expose the API in this case.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
|
| - io_parent_,
|
| - data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
|
| - } else {
|
| - // Prevent websites from detecting incognito mode, by emulating what would
|
| - // have happened if we had a PushMessagingService available.
|
| - if (!data.FromDocument() || !data.options.user_visible_only) {
|
| - // Throw a permission denied error under the same circumstances.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
|
| - io_parent_, data,
|
| - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
|
| - } else {
|
| - RenderFrameHost* render_frame_host =
|
| - RenderFrameHost::FromID(render_process_id_, data.render_frame_id);
|
| - WebContents* web_contents =
|
| - WebContents::FromRenderFrameHost(render_frame_host);
|
| - if (web_contents) {
|
| - web_contents->GetMainFrame()->AddMessageToConsole(
|
| - CONSOLE_MESSAGE_LEVEL_ERROR, kIncognitoPushUnsupportedMessage);
|
| - // Request push messaging permission (which will fail, since
|
| - // notifications aren't supported in incognito), so the website can't
|
| - // detect whether incognito is active.
|
| - web_contents->GetBrowserContext()
|
| - ->GetPermissionManager()
|
| - ->RequestPermission(
|
| - PermissionType::PUSH_MESSAGING, render_frame_host,
|
| - data.requesting_origin, false /* user_gesture */,
|
| - base::Bind(&PushMessagingMessageFilter::Core::
|
| - DidRequestPermissionInIncognito,
|
| - weak_factory_ui_to_ui_.GetWeakPtr(), data));
|
| - }
|
| - }
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (data.FromDocument()) {
|
| - push_service->SubscribeFromDocument(
|
| - data.requesting_origin, data.service_worker_registration_id,
|
| - render_process_id_, data.render_frame_id, data.options,
|
| - base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
|
| - data));
|
| - } else {
|
| - push_service->SubscribeFromWorker(
|
| - data.requesting_origin, data.service_worker_registration_id,
|
| - data.options, base::Bind(&Core::DidRegister,
|
| - weak_factory_ui_to_ui_.GetWeakPtr(), data));
|
| - }
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::DidRequestPermissionInIncognito(
|
| - const RegisterData& data,
|
| - blink::mojom::PermissionStatus status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - // Notification permission should always be denied in incognito.
|
| - DCHECK_EQ(blink::mojom::PermissionStatus::DENIED, status);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::SendSubscriptionError, io_parent_,
|
| - data, PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::DidRegister(
|
| - const RegisterData& data,
|
| - const std::string& push_registration_id,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth,
|
| - PushRegistrationStatus status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE) {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::PersistRegistrationOnIO,
|
| - io_parent_, data, push_registration_id, p256dh, auth));
|
| - } else {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::SendSubscriptionError,
|
| - io_parent_, data, status));
|
| - }
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::PersistRegistrationOnIO(
|
| - const RegisterData& data,
|
| - const std::string& push_registration_id,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - service_worker_context_->StoreRegistrationUserData(
|
| - data.service_worker_registration_id, data.requesting_origin,
|
| - {{kPushRegistrationIdServiceWorkerKey, push_registration_id},
|
| - {kPushSenderIdServiceWorkerKey, data.options.sender_info}},
|
| - base::Bind(&PushMessagingMessageFilter::DidPersistRegistrationOnIO,
|
| - weak_factory_io_to_io_.GetWeakPtr(), data,
|
| - push_registration_id, p256dh, auth));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidPersistRegistrationOnIO(
|
| - const RegisterData& data,
|
| - const std::string& push_registration_id,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth,
|
| - ServiceWorkerStatusCode service_worker_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (service_worker_status == SERVICE_WORKER_OK) {
|
| - SendSubscriptionSuccess(data,
|
| - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE,
|
| - push_registration_id, p256dh, auth);
|
| - } else {
|
| - // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count.
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
|
| - }
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::SendSubscriptionError(
|
| - const RegisterData& data, PushRegistrationStatus status) {
|
| - // Only called from IO thread, but would be safe to call from UI thread.
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (data.FromDocument()) {
|
| - Send(new PushMessagingMsg_SubscribeFromDocumentError(
|
| - data.render_frame_id, data.request_id, status));
|
| - } else {
|
| - Send(
|
| - new PushMessagingMsg_SubscribeFromWorkerError(data.request_id, status));
|
| - }
|
| - RecordRegistrationStatus(status);
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::SendSubscriptionSuccess(
|
| - const RegisterData& data,
|
| - PushRegistrationStatus status,
|
| - const std::string& push_subscription_id,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth) {
|
| - // Only called from IO thread, but would be safe to call from UI thread.
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (!service_available_) {
|
| - // This shouldn't be possible in incognito mode, since we've already checked
|
| - // that we have an existing registration. Hence it's ok to throw an error.
|
| - DCHECK(!ui_core_->is_incognito());
|
| - SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE);
|
| - return;
|
| - }
|
| -
|
| - const GURL endpoint = CreateEndpoint(
|
| - IsApplicationServerKey(data.options.sender_info), push_subscription_id);
|
| -
|
| - if (data.FromDocument()) {
|
| - Send(new PushMessagingMsg_SubscribeFromDocumentSuccess(
|
| - data.render_frame_id, data.request_id, endpoint, data.options, p256dh,
|
| - auth));
|
| - } else {
|
| - Send(new PushMessagingMsg_SubscribeFromWorkerSuccess(
|
| - data.request_id, endpoint, data.options, p256dh, auth));
|
| - }
|
| - RecordRegistrationStatus(status);
|
| -}
|
| -
|
| -// Unsubscribe methods on both IO and UI threads, merged in order of use from
|
| -// PushMessagingMessageFilter and Core.
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -void PushMessagingMessageFilter::OnUnsubscribe(
|
| - int request_id, int64_t service_worker_registration_id) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - ServiceWorkerRegistration* service_worker_registration =
|
| - service_worker_context_->GetLiveRegistration(
|
| - service_worker_registration_id);
|
| - if (!service_worker_registration) {
|
| - DidUnregister(request_id, PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER);
|
| - return;
|
| - }
|
| -
|
| - service_worker_context_->GetRegistrationUserData(
|
| - service_worker_registration_id, {kPushSenderIdServiceWorkerKey},
|
| - base::Bind(&PushMessagingMessageFilter::UnsubscribeHavingGottenSenderId,
|
| - weak_factory_io_to_io_.GetWeakPtr(), request_id,
|
| - service_worker_registration_id,
|
| - service_worker_registration->pattern().GetOrigin()));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::UnsubscribeHavingGottenSenderId(
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - const GURL& requesting_origin,
|
| - const std::vector<std::string>& sender_ids,
|
| - ServiceWorkerStatusCode service_worker_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| -
|
| - std::string sender_id;
|
| - if (service_worker_status == SERVICE_WORKER_OK) {
|
| - DCHECK_EQ(1u, sender_ids.size());
|
| - sender_id = sender_ids[0];
|
| - }
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::UnregisterFromService, base::Unretained(ui_core_.get()),
|
| - request_id, service_worker_registration_id, requesting_origin,
|
| - sender_id));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::UnregisterFromService(
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - const GURL& requesting_origin,
|
| - const std::string& sender_id) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - PushMessagingService* push_service = service();
|
| - if (!push_service) {
|
| - // This shouldn't be possible in incognito mode, since we've already checked
|
| - // that we have an existing registration. Hence it's ok to throw an error.
|
| - DCHECK(!is_incognito());
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::DidUnregister, io_parent_,
|
| - request_id,
|
| - PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE));
|
| - return;
|
| - }
|
| -
|
| - push_service->Unsubscribe(
|
| - requesting_origin, service_worker_registration_id, sender_id,
|
| - base::Bind(&Core::DidUnregisterFromService,
|
| - weak_factory_ui_to_ui_.GetWeakPtr(), request_id,
|
| - service_worker_registration_id));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::DidUnregisterFromService(
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - PushUnregistrationStatus unregistration_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::DidUnregister, io_parent_,
|
| - request_id, unregistration_status));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidUnregister(
|
| - int request_id,
|
| - PushUnregistrationStatus unregistration_status) {
|
| - // Only called from IO thread, but would be safe to call from UI thread.
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - switch (unregistration_status) {
|
| - case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED:
|
| - case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR:
|
| - case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR:
|
| - Send(new PushMessagingMsg_UnsubscribeSuccess(request_id, true));
|
| - break;
|
| - case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED:
|
| - Send(new PushMessagingMsg_UnsubscribeSuccess(request_id, false));
|
| - break;
|
| - case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER:
|
| - case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE:
|
| - case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR:
|
| - Send(new PushMessagingMsg_UnsubscribeError(
|
| - request_id, blink::WebPushError::ErrorTypeAbort,
|
| - PushUnregistrationStatusToString(unregistration_status)));
|
| - break;
|
| - case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR:
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| - RecordUnregistrationStatus(unregistration_status);
|
| -}
|
| -
|
| -// GetSubscription methods on both IO and UI threads, merged in order of use
|
| -// from PushMessagingMessageFilter and Core.
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -void PushMessagingMessageFilter::OnGetSubscription(
|
| - int request_id,
|
| - int64_t service_worker_registration_id) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - // TODO(johnme): Validate arguments?
|
| - service_worker_context_->GetRegistrationUserData(
|
| - service_worker_registration_id,
|
| - {kPushRegistrationIdServiceWorkerKey, kPushSenderIdServiceWorkerKey},
|
| - base::Bind(&PushMessagingMessageFilter::DidGetSubscription,
|
| - weak_factory_io_to_io_.GetWeakPtr(), request_id,
|
| - service_worker_registration_id));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidGetSubscription(
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - const std::vector<std::string>& push_subscription_id_and_sender_info,
|
| - ServiceWorkerStatusCode service_worker_status) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - PushGetRegistrationStatus get_status =
|
| - PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
|
| - switch (service_worker_status) {
|
| - case SERVICE_WORKER_OK: {
|
| - DCHECK_EQ(2u, push_subscription_id_and_sender_info.size());
|
| -
|
| - if (!service_available_) {
|
| - // Return not found in incognito mode, so websites can't detect it.
|
| - get_status =
|
| - ui_core_->is_incognito()
|
| - ? PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND
|
| - : PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE;
|
| - break;
|
| - }
|
| -
|
| - ServiceWorkerRegistration* registration =
|
| - service_worker_context_->GetLiveRegistration(
|
| - service_worker_registration_id);
|
| - const GURL origin = registration->pattern().GetOrigin();
|
| -
|
| - const bool uses_standard_protocol =
|
| - IsApplicationServerKey(push_subscription_id_and_sender_info[1]);
|
| - const GURL endpoint = CreateEndpoint(
|
| - uses_standard_protocol, push_subscription_id_and_sender_info[0]);
|
| -
|
| - auto callback =
|
| - base::Bind(&PushMessagingMessageFilter::DidGetSubscriptionKeys,
|
| - weak_factory_io_to_io_.GetWeakPtr(), request_id, endpoint,
|
| - push_subscription_id_and_sender_info[1]);
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::GetEncryptionInfoOnUI,
|
| - base::Unretained(ui_core_.get()), origin,
|
| - service_worker_registration_id,
|
| - push_subscription_id_and_sender_info[1], callback));
|
| -
|
| - return;
|
| - }
|
| - case SERVICE_WORKER_ERROR_NOT_FOUND: {
|
| - get_status = PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND;
|
| - break;
|
| - }
|
| - case SERVICE_WORKER_ERROR_FAILED: {
|
| - get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
|
| - break;
|
| - }
|
| - case SERVICE_WORKER_ERROR_ABORT:
|
| - case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
|
| - case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
|
| - case SERVICE_WORKER_ERROR_EXISTS:
|
| - case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
|
| - case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
|
| - case SERVICE_WORKER_ERROR_IPC_FAILED:
|
| - case SERVICE_WORKER_ERROR_NETWORK:
|
| - case SERVICE_WORKER_ERROR_SECURITY:
|
| - case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
|
| - case SERVICE_WORKER_ERROR_STATE:
|
| - case SERVICE_WORKER_ERROR_TIMEOUT:
|
| - case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
|
| - case SERVICE_WORKER_ERROR_DISK_CACHE:
|
| - case SERVICE_WORKER_ERROR_REDUNDANT:
|
| - case SERVICE_WORKER_ERROR_DISALLOWED:
|
| - case SERVICE_WORKER_ERROR_MAX_VALUE: {
|
| - NOTREACHED() << "Got unexpected error code: " << service_worker_status
|
| - << " " << ServiceWorkerStatusToString(service_worker_status);
|
| - get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR;
|
| - break;
|
| - }
|
| - }
|
| - Send(new PushMessagingMsg_GetSubscriptionError(request_id, get_status));
|
| - RecordGetRegistrationStatus(get_status);
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::DidGetSubscriptionKeys(
|
| - int request_id,
|
| - const GURL& endpoint,
|
| - const std::string& sender_info,
|
| - bool success,
|
| - const std::vector<uint8_t>& p256dh,
|
| - const std::vector<uint8_t>& auth) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - if (!success) {
|
| - PushGetRegistrationStatus status =
|
| - PUSH_GETREGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE;
|
| -
|
| - Send(new PushMessagingMsg_GetSubscriptionError(request_id, status));
|
| -
|
| - RecordGetRegistrationStatus(status);
|
| - return;
|
| - }
|
| -
|
| - PushSubscriptionOptions options;
|
| - // Chrome rejects subscription requests with userVisibleOnly false, so it must
|
| - // have been true. TODO(harkness): If Chrome starts accepting silent push
|
| - // subscriptions with userVisibleOnly false, the bool will need to be stored.
|
| - options.user_visible_only = true;
|
| - options.sender_info = sender_info;
|
| -
|
| - Send(new PushMessagingMsg_GetSubscriptionSuccess(request_id, endpoint,
|
| - options, p256dh, auth));
|
| -
|
| - RecordGetRegistrationStatus(PUSH_GETREGISTRATION_STATUS_SUCCESS);
|
| -}
|
| -
|
| -// GetPermission methods on both IO and UI threads, merged in order of use from
|
| -// PushMessagingMessageFilter and Core.
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -void PushMessagingMessageFilter::OnGetPermissionStatus(
|
| - int request_id,
|
| - int64_t service_worker_registration_id,
|
| - bool user_visible) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - ServiceWorkerRegistration* service_worker_registration =
|
| - service_worker_context_->GetLiveRegistration(
|
| - service_worker_registration_id);
|
| - if (!service_worker_registration) {
|
| - Send(new PushMessagingMsg_GetPermissionStatusError(
|
| - request_id, blink::WebPushError::ErrorTypeAbort));
|
| - return;
|
| - }
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Core::GetPermissionStatusOnUI,
|
| - base::Unretained(ui_core_.get()),
|
| - service_worker_registration->pattern().GetOrigin(),
|
| - user_visible, request_id));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::GetPermissionStatusOnUI(
|
| - const GURL& requesting_origin, bool user_visible, int request_id) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - blink::WebPushPermissionStatus permission_status;
|
| - PushMessagingService* push_service = service();
|
| - if (push_service) {
|
| - if (!user_visible && !push_service->SupportNonVisibleMessages()) {
|
| - Send(new PushMessagingMsg_GetPermissionStatusError(
|
| - request_id, blink::WebPushError::ErrorTypeNotSupported));
|
| - return;
|
| - }
|
| - permission_status =
|
| - push_service->GetPermissionStatus(requesting_origin, user_visible);
|
| - } else if (is_incognito()) {
|
| - // Return prompt, so the website can't detect incognito mode.
|
| - permission_status = blink::WebPushPermissionStatusPrompt;
|
| - } else {
|
| - Send(new PushMessagingMsg_GetPermissionStatusError(
|
| - request_id, blink::WebPushError::ErrorTypeAbort));
|
| - return;
|
| - }
|
| - Send(new PushMessagingMsg_GetPermissionStatusSuccess(request_id,
|
| - permission_status));
|
| -}
|
| -
|
| -// Helper methods on both IO and UI threads, merged from
|
| -// PushMessagingMessageFilter and Core.
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -void PushMessagingMessageFilter::Core::GetEncryptionInfoOnUI(
|
| - const GURL& origin,
|
| - int64_t service_worker_registration_id,
|
| - const std::string& sender_id,
|
| - const PushMessagingService::EncryptionInfoCallback& io_thread_callback) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - PushMessagingService* push_service = service();
|
| - if (push_service) {
|
| - push_service->GetEncryptionInfo(
|
| - origin, service_worker_registration_id, sender_id,
|
| - base::Bind(&ForwardEncryptionInfoToIOThreadProxy, io_thread_callback));
|
| - return;
|
| - }
|
| -
|
| - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| - base::Bind(io_thread_callback, false /* success */,
|
| - std::vector<uint8_t>() /* p256dh */,
|
| - std::vector<uint8_t>() /* auth */));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::Core::Send(IPC::Message* message) {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&PushMessagingMessageFilter::SendIPC, io_parent_,
|
| - base::Passed(base::WrapUnique(message))));
|
| -}
|
| -
|
| -void PushMessagingMessageFilter::SendIPC(
|
| - std::unique_ptr<IPC::Message> message) {
|
| - Send(message.release());
|
| -}
|
| -
|
| -GURL PushMessagingMessageFilter::CreateEndpoint(
|
| - bool standard_protocol,
|
| - const std::string& subscription_id) const {
|
| - const GURL& base =
|
| - standard_protocol ? web_push_protocol_endpoint_ : default_endpoint_;
|
| -
|
| - return GURL(base.spec() + subscription_id);
|
| -}
|
| -
|
| -PushMessagingService* PushMessagingMessageFilter::Core::service() {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - RenderProcessHost* process_host =
|
| - RenderProcessHost::FromID(render_process_id_);
|
| - return process_host
|
| - ? process_host->GetBrowserContext()->GetPushMessagingService()
|
| - : nullptr;
|
| -}
|
| -
|
| -} // namespace content
|
|
|