blob: 927da07baa35fd30984f680cc51c482e0198c973 [file] [log] [blame]
// 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/child/push_messaging/push_provider.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/threading/thread_local.h"
#include "content/child/push_messaging/push_dispatcher.h"
#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/worker_task_runner.h"
#include "content/common/push_messaging_messages.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscription.h"
#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h"
namespace content {
namespace {
int CurrentWorkerId() {
return WorkerTaskRunner::Instance()->CurrentWorkerId();
}
// Returns the id of the given |service_worker_registration|, which
// is only available on the implementation of the interface.
int64 GetServiceWorkerRegistrationId(
blink::WebServiceWorkerRegistration* service_worker_registration) {
return static_cast<WebServiceWorkerRegistrationImpl*>(
service_worker_registration)->registration_id();
}
} // namespace
static base::LazyInstance<base::ThreadLocalPointer<PushProvider>>::Leaky
g_push_provider_tls = LAZY_INSTANCE_INITIALIZER;
PushProvider::PushProvider(ThreadSafeSender* thread_safe_sender,
PushDispatcher* push_dispatcher)
: thread_safe_sender_(thread_safe_sender),
push_dispatcher_(push_dispatcher) {
g_push_provider_tls.Pointer()->Set(this);
}
PushProvider::~PushProvider() {
g_push_provider_tls.Pointer()->Set(nullptr);
}
PushProvider* PushProvider::ThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender,
PushDispatcher* push_dispatcher) {
if (g_push_provider_tls.Pointer()->Get())
return g_push_provider_tls.Pointer()->Get();
PushProvider* provider =
new PushProvider(thread_safe_sender, push_dispatcher);
if (CurrentWorkerId())
WorkerTaskRunner::Instance()->AddStopObserver(provider);
return provider;
}
void PushProvider::OnWorkerRunLoopStopped() {
delete this;
}
void PushProvider::subscribe(
blink::WebServiceWorkerRegistration* service_worker_registration,
const blink::WebPushSubscriptionOptions& options,
blink::WebPushSubscriptionCallbacks* callbacks) {
DCHECK(service_worker_registration);
DCHECK(callbacks);
int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
subscription_callbacks_.AddWithID(callbacks, request_id);
int64 service_worker_registration_id =
GetServiceWorkerRegistrationId(service_worker_registration);
thread_safe_sender_->Send(new PushMessagingHostMsg_SubscribeFromWorker(
request_id, service_worker_registration_id, options.userVisibleOnly));
}
void PushProvider::unsubscribe(
blink::WebServiceWorkerRegistration* service_worker_registration,
blink::WebPushUnsubscribeCallbacks* callbacks) {
DCHECK(service_worker_registration);
DCHECK(callbacks);
int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
unsubscribe_callbacks_.AddWithID(callbacks, request_id);
int64 service_worker_registration_id =
GetServiceWorkerRegistrationId(service_worker_registration);
thread_safe_sender_->Send(new PushMessagingHostMsg_Unsubscribe(
request_id, service_worker_registration_id));
}
void PushProvider::getSubscription(
blink::WebServiceWorkerRegistration* service_worker_registration,
blink::WebPushSubscriptionCallbacks* callbacks) {
DCHECK(service_worker_registration);
DCHECK(callbacks);
int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
subscription_callbacks_.AddWithID(callbacks, request_id);
int64 service_worker_registration_id =
GetServiceWorkerRegistrationId(service_worker_registration);
thread_safe_sender_->Send(new PushMessagingHostMsg_GetRegistration(
request_id, service_worker_registration_id));
}
void PushProvider::getPermissionStatus(
blink::WebServiceWorkerRegistration* service_worker_registration,
const blink::WebPushSubscriptionOptions& options,
blink::WebPushPermissionStatusCallbacks* callbacks) {
DCHECK(service_worker_registration);
DCHECK(callbacks);
int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId());
permission_status_callbacks_.AddWithID(callbacks, request_id);
int64 service_worker_registration_id =
GetServiceWorkerRegistrationId(service_worker_registration);
thread_safe_sender_->Send(new PushMessagingHostMsg_GetPermissionStatus(
request_id, service_worker_registration_id, options.userVisibleOnly));
}
bool PushProvider::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PushProvider, message)
IPC_MESSAGE_HANDLER(PushMessagingMsg_SubscribeFromWorkerSuccess,
OnSubscribeFromWorkerSuccess);
IPC_MESSAGE_HANDLER(PushMessagingMsg_SubscribeFromWorkerError,
OnSubscribeFromWorkerError);
IPC_MESSAGE_HANDLER(PushMessagingMsg_UnsubscribeSuccess,
OnUnsubscribeSuccess);
IPC_MESSAGE_HANDLER(PushMessagingMsg_UnsubscribeError,
OnUnsubscribeError);
IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationSuccess,
OnGetRegistrationSuccess);
IPC_MESSAGE_HANDLER(PushMessagingMsg_GetRegistrationError,
OnGetRegistrationError);
IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusSuccess,
OnGetPermissionStatusSuccess);
IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusError,
OnGetPermissionStatusError);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PushProvider::OnSubscribeFromWorkerSuccess(
int request_id,
const GURL& endpoint) {
blink::WebPushSubscriptionCallbacks* callbacks =
subscription_callbacks_.Lookup(request_id);
if (!callbacks)
return;
scoped_ptr<blink::WebPushSubscription> subscription(
new blink::WebPushSubscription(endpoint));
callbacks->onSuccess(subscription.release());
subscription_callbacks_.Remove(request_id);
}
void PushProvider::OnSubscribeFromWorkerError(int request_id,
PushRegistrationStatus status) {
blink::WebPushSubscriptionCallbacks* callbacks =
subscription_callbacks_.Lookup(request_id);
if (!callbacks)
return;
scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
blink::WebPushError::ErrorTypeAbort,
blink::WebString::fromUTF8(PushRegistrationStatusToString(status))));
callbacks->onError(error.release());
subscription_callbacks_.Remove(request_id);
}
void PushProvider::OnUnsubscribeSuccess(int request_id, bool did_unsubscribe) {
blink::WebPushUnsubscribeCallbacks* callbacks =
unsubscribe_callbacks_.Lookup(request_id);
if (!callbacks)
return;
callbacks->onSuccess(&did_unsubscribe);
unsubscribe_callbacks_.Remove(request_id);
}
void PushProvider::OnUnsubscribeError(
int request_id,
blink::WebPushError::ErrorType error_type,
const std::string& error_message) {
blink::WebPushUnsubscribeCallbacks* callbacks =
unsubscribe_callbacks_.Lookup(request_id);
if (!callbacks)
return;
scoped_ptr<blink::WebPushError> error(new blink::WebPushError(
error_type, blink::WebString::fromUTF8(error_message)));
callbacks->onError(error.release());
unsubscribe_callbacks_.Remove(request_id);
}
void PushProvider::OnGetRegistrationSuccess(
int request_id,
const GURL& endpoint) {
blink::WebPushSubscriptionCallbacks* callbacks =
subscription_callbacks_.Lookup(request_id);
if (!callbacks)
return;
scoped_ptr<blink::WebPushSubscription> subscription(
new blink::WebPushSubscription(endpoint));
callbacks->onSuccess(subscription.release());
subscription_callbacks_.Remove(request_id);
}
void PushProvider::OnGetRegistrationError(
int request_id,
PushGetRegistrationStatus status) {
blink::WebPushSubscriptionCallbacks* callbacks =
subscription_callbacks_.Lookup(request_id);
if (!callbacks)
return;
// We are only expecting an error if we can't find a registration.
callbacks->onSuccess(nullptr);
subscription_callbacks_.Remove(request_id);
}
void PushProvider::OnGetPermissionStatusSuccess(
int request_id,
blink::WebPushPermissionStatus status) {
blink::WebPushPermissionStatusCallbacks* callbacks =
permission_status_callbacks_.Lookup(request_id);
if (!callbacks)
return;
callbacks->onSuccess(&status);
permission_status_callbacks_.Remove(request_id);
}
void PushProvider::OnGetPermissionStatusError(
int request_id,
blink::WebPushError::ErrorType error) {
blink::WebPushPermissionStatusCallbacks* callbacks =
permission_status_callbacks_.Lookup(request_id);
if (!callbacks)
return;
std::string error_message;
if (error == blink::WebPushError::ErrorTypeNotSupported) {
error_message =
"Push subscriptions that don't enable userVisibleOnly are not "
"supported.";
}
scoped_ptr<blink::WebPushError> web_error(new blink::WebPushError(
error, blink::WebString::fromUTF8(error_message)));
callbacks->onError(web_error.release());
permission_status_callbacks_.Remove(request_id);
}
} // namespace content