blob: de52af6b8ceccaaded76ea5ce0a97abf706b8901 [file] [log] [blame]
// Copyright 2013 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/service_worker/service_worker_dispatcher_host.h"
#include <utility>
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/bad_message.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_client_utils.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_handle.h"
#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_registration_handle.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/origin_util.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
#include "url/gurl.h"
using blink::WebServiceWorkerError;
namespace content {
namespace {
const char kNoDocumentURLErrorMessage[] =
"No URL is associated with the caller's document.";
const char kShutdownErrorMessage[] =
"The Service Worker system has shutdown.";
const char kUserDeniedPermissionMessage[] =
"The user denied permission to use Service Worker.";
const char kInvalidStateErrorMessage[] = "The object is in an invalid state.";
const uint32_t kFilteredMessageClasses[] = {
ServiceWorkerMsgStart, EmbeddedWorkerMsgStart,
};
void RunSoon(const base::Closure& callback) {
if (!callback.is_null())
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
}
bool CanUnregisterServiceWorker(const GURL& document_url,
const GURL& pattern) {
DCHECK(document_url.is_valid());
DCHECK(pattern.is_valid());
return document_url.GetOrigin() == pattern.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url) &&
OriginCanAccessServiceWorkers(pattern);
}
bool CanUpdateServiceWorker(const GURL& document_url, const GURL& pattern) {
DCHECK(document_url.is_valid());
DCHECK(pattern.is_valid());
DCHECK(OriginCanAccessServiceWorkers(document_url));
DCHECK(OriginCanAccessServiceWorkers(pattern));
return document_url.GetOrigin() == pattern.GetOrigin();
}
bool CanGetRegistration(const GURL& document_url,
const GURL& given_document_url) {
DCHECK(document_url.is_valid());
DCHECK(given_document_url.is_valid());
return document_url.GetOrigin() == given_document_url.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url) &&
OriginCanAccessServiceWorkers(given_document_url);
}
} // namespace
ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
int render_process_id,
MessagePortMessageFilter* message_port_message_filter,
ResourceContext* resource_context)
: BrowserMessageFilter(kFilteredMessageClasses,
arraysize(kFilteredMessageClasses)),
render_process_id_(render_process_id),
message_port_message_filter_(message_port_message_filter),
resource_context_(resource_context),
channel_ready_(false) {
}
ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
if (GetContext()) {
GetContext()->RemoveAllProviderHostsForProcess(render_process_id_);
GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
render_process_id_);
}
}
void ServiceWorkerDispatcherHost::Init(
ServiceWorkerContextWrapper* context_wrapper) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&ServiceWorkerDispatcherHost::Init, this,
base::RetainedRef(context_wrapper)));
return;
}
context_wrapper_ = context_wrapper;
if (!GetContext())
return;
GetContext()->embedded_worker_registry()->AddChildProcessSender(
render_process_id_, this, message_port_message_filter_);
}
void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnFilterAdded");
channel_ready_ = true;
std::vector<std::unique_ptr<IPC::Message>> messages;
messages.swap(pending_messages_);
for (auto& message : messages) {
BrowserMessageFilter::Send(message.release());
}
}
void ServiceWorkerDispatcherHost::OnFilterRemoved() {
// Don't wait until the destructor to teardown since a new dispatcher host
// for this process might be created before then.
if (GetContext()) {
GetContext()->RemoveAllProviderHostsForProcess(render_process_id_);
GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
render_process_id_);
}
context_wrapper_ = nullptr;
channel_ready_ = false;
}
void ServiceWorkerDispatcherHost::OnDestruct() const {
BrowserThread::DeleteOnIOThread::Destruct(this);
}
bool ServiceWorkerDispatcherHost::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost, message)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker,
OnRegisterServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UpdateServiceWorker,
OnUpdateServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
OnUnregisterServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration,
OnGetRegistration)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrations,
OnGetRegistrations)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrationForReady,
OnGetRegistrationForReady)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
OnProviderCreated)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
OnProviderDestroyed)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId,
OnSetHostedVersionId)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
OnPostMessageToWorker)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection,
OnWorkerReadyForInspection)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
OnWorkerScriptLoaded)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerThreadStarted,
OnWorkerThreadStarted)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed,
OnWorkerScriptLoadFailed)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptEvaluated,
OnWorkerScriptEvaluated)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
OnWorkerStarted)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
OnWorkerStopped)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
OnReportException)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
OnReportConsoleMessage)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
OnIncrementServiceWorkerRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
OnDecrementServiceWorkerRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount,
OnIncrementRegistrationRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount,
OnDecrementRegistrationRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_TerminateWorker, OnTerminateWorker)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
if (!handled && GetContext()) {
handled = GetContext()->embedded_worker_registry()->OnMessageReceived(
message, render_process_id_);
if (!handled)
bad_message::ReceivedBadMessage(this, bad_message::SWDH_NOT_HANDLED);
}
return handled;
}
bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
if (channel_ready_) {
BrowserMessageFilter::Send(message);
// Don't bother passing through Send()'s result: it's not reliable.
return true;
}
pending_messages_.push_back(base::WrapUnique(message));
return true;
}
void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
std::unique_ptr<ServiceWorkerHandle> handle) {
int handle_id = handle->handle_id();
handles_.AddWithID(handle.release(), handle_id);
}
void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
std::unique_ptr<ServiceWorkerRegistrationHandle> handle) {
int handle_id = handle->handle_id();
registration_handles_.AddWithID(handle.release(), handle_id);
}
ServiceWorkerHandle* ServiceWorkerDispatcherHost::FindServiceWorkerHandle(
int provider_id,
int64_t version_id) {
for (IDMap<ServiceWorkerHandle, IDMapOwnPointer>::iterator iter(&handles_);
!iter.IsAtEnd(); iter.Advance()) {
ServiceWorkerHandle* handle = iter.GetCurrentValue();
DCHECK(handle);
DCHECK(handle->version());
if (handle->provider_id() == provider_id &&
handle->version()->version_id() == version_id) {
return handle;
}
}
return nullptr;
}
ServiceWorkerRegistrationHandle*
ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration) {
DCHECK(provider_host);
ServiceWorkerRegistrationHandle* existing_handle =
FindRegistrationHandle(provider_host->provider_id(), registration->id());
if (existing_handle) {
existing_handle->IncrementRefCount();
return existing_handle;
}
std::unique_ptr<ServiceWorkerRegistrationHandle> new_handle(
new ServiceWorkerRegistrationHandle(GetContext()->AsWeakPtr(),
provider_host, registration));
ServiceWorkerRegistrationHandle* new_handle_ptr = new_handle.get();
RegisterServiceWorkerRegistrationHandle(std::move(new_handle));
return new_handle_ptr;
}
void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
int thread_id,
int request_id,
int provider_id,
const GURL& pattern,
const GURL& script_url) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnRegisterServiceWorker");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!pattern.is_valid() || !script_url.is_valid()) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_BAD_URL);
return;
}
ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_NO_HOST);
return;
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
// TODO(ksakamoto): Currently, document_url is empty if the document is in an
// IFRAME using frame.contentDocument.write(...). We can remove this check
// once crbug.com/439697 is fixed.
if (provider_host->document_url().is_empty()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
if (!ServiceWorkerUtils::CanRegisterServiceWorker(
provider_host->document_url(), pattern, script_url)) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_CANNOT);
return;
}
std::string error_message;
if (ServiceWorkerUtils::ContainsDisallowedCharacter(pattern, script_url,
&error_message)) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_CANNOT);
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
pattern, provider_host->topmost_frame_url(), resource_context_,
render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) +
base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN2(
"ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
request_id, "Scope", pattern.spec(), "Script URL", script_url.spec());
GetContext()->RegisterServiceWorker(
pattern,
script_url,
provider_host,
base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
this,
thread_id,
provider_id,
request_id));
}
void ServiceWorkerDispatcherHost::OnUpdateServiceWorker(
int thread_id,
int request_id,
int provider_id,
int64_t registration_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnUpdateServiceWorker");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_NO_HOST);
return;
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
// TODO(jungkees): This check can be removed once crbug.com/439697 is fixed.
if (provider_host->document_url().is_empty()) {
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) +
base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
ServiceWorkerRegistration* registration =
GetContext()->GetLiveRegistration(registration_id);
if (!registration) {
// |registration| must be alive because a renderer retains a registration
// reference at this point.
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_UPDATE_BAD_REGISTRATION_ID);
return;
}
if (!CanUpdateServiceWorker(provider_host->document_url(),
registration->pattern())) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_CANNOT);
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
registration->pattern(), provider_host->topmost_frame_url(),
resource_context_, render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) +
base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
if (!registration->GetNewestVersion()) {
// This can happen if update() is called during initial script evaluation.
// Abort the following steps according to the spec.
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeState,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) +
base::ASCIIToUTF16(kInvalidStateErrorMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
"ServiceWorkerDispatcherHost::UpdateServiceWorker",
request_id, "Scope", registration->pattern().spec());
GetContext()->UpdateServiceWorker(
registration, false /* force_bypass_cache */,
false /* skip_script_comparison */, provider_host,
base::Bind(&ServiceWorkerDispatcherHost::UpdateComplete, this, thread_id,
provider_id, request_id));
}
void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
int thread_id,
int request_id,
int provider_id,
int64_t registration_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnUnregisterServiceWorker");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_NO_HOST);
return;
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
// TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
if (provider_host->document_url().is_empty()) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
ServiceWorkerRegistration* registration =
GetContext()->GetLiveRegistration(registration_id);
if (!registration) {
// |registration| must be alive because a renderer retains a registration
// reference at this point.
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_UNREGISTER_BAD_REGISTRATION_ID);
return;
}
if (!CanUnregisterServiceWorker(provider_host->document_url(),
registration->pattern())) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_CANNOT);
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
registration->pattern(), provider_host->topmost_frame_url(),
resource_context_, render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN1(
"ServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
request_id, "Scope", registration->pattern().spec());
GetContext()->UnregisterServiceWorker(
registration->pattern(),
base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete, this,
thread_id, request_id));
}
void ServiceWorkerDispatcherHost::OnGetRegistration(
int thread_id,
int request_id,
int provider_id,
const GURL& document_url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnGetRegistration");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!document_url.is_valid()) {
bad_message::ReceivedBadMessage(this,
bad_message::SWDH_GET_REGISTRATION_BAD_URL);
return;
}
ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(this,
bad_message::SWDH_GET_REGISTRATION_NO_HOST);
return;
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
// TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
if (provider_host->document_url().is_empty()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
if (!CanGetRegistration(provider_host->document_url(), document_url)) {
bad_message::ReceivedBadMessage(this,
bad_message::SWDH_GET_REGISTRATION_CANNOT);
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
provider_host->document_url(), provider_host->topmost_frame_url(),
resource_context_, render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
"ServiceWorkerDispatcherHost::GetRegistration",
request_id, "Document URL", document_url.spec());
GetContext()->storage()->FindRegistrationForDocument(
document_url,
base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete,
this,
thread_id,
provider_id,
request_id));
}
void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id,
int request_id,
int provider_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnGetRegistrations");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_GET_REGISTRATIONS_NO_HOST);
return;
}
if (!provider_host->IsContextAlive()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
// TODO(jungkees): This check can be removed once crbug.com/439697 is fixed.
if (provider_host->document_url().is_empty()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
return;
}
if (!OriginCanAccessServiceWorkers(provider_host->document_url())) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_GET_REGISTRATIONS_INVALID_ORIGIN);
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
provider_host->document_url(), provider_host->topmost_frame_url(),
resource_context_, render_process_id_, provider_host->frame_id())) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
"ServiceWorkerDispatcherHost::GetRegistrations",
request_id);
GetContext()->storage()->GetRegistrationsForOrigin(
provider_host->document_url().GetOrigin(),
base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete, this,
thread_id, provider_id, request_id));
}
void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
int thread_id,
int request_id,
int provider_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnGetRegistrationForReady");
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_NO_HOST);
return;
}
if (!provider_host->IsContextAlive())
return;
TRACE_EVENT_ASYNC_BEGIN0(
"ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
request_id);
if (!provider_host->GetRegistrationForReady(base::Bind(
&ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete,
this, thread_id, request_id, provider_host->AsWeakPtr()))) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_ALREADY_IN_PROGRESS);
}
}
void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
int handle_id,
int provider_id,
const base::string16& message,
const url::Origin& source_origin,
const std::vector<int>& sent_message_ports) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnPostMessageToWorker");
if (!GetContext())
return;
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_POST_MESSAGE);
return;
}
ServiceWorkerProviderHost* sender_provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!sender_provider_host) {
// This may occur when destruction of the sender provider overtakes
// postMessage() because of thread hopping on WebServiceWorkerImpl.
return;
}
DispatchExtendableMessageEvent(
make_scoped_refptr(handle->version()), message, source_origin,
sent_message_ports, sender_provider_host,
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
}
void ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent(
scoped_refptr<ServiceWorkerVersion> worker,
const base::string16& message,
const url::Origin& source_origin,
const std::vector<int>& sent_message_ports,
ServiceWorkerProviderHost* sender_provider_host,
const StatusCallback& callback) {
for (int port : sent_message_ports)
MessagePortService::GetInstance()->HoldMessages(port);
switch (sender_provider_host->provider_type()) {
case SERVICE_WORKER_PROVIDER_FOR_WINDOW:
case SERVICE_WORKER_PROVIDER_FOR_WORKER:
case SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER:
service_worker_client_utils::GetClient(
sender_provider_host,
base::Bind(&ServiceWorkerDispatcherHost::
DispatchExtendableMessageEventInternal<
ServiceWorkerClientInfo>,
this, worker, message, source_origin, sent_message_ports,
callback));
break;
case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER:
RunSoon(base::Bind(
&ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal<
ServiceWorkerObjectInfo>,
this, worker, message, source_origin, sent_message_ports, callback,
sender_provider_host->GetOrCreateServiceWorkerHandle(
sender_provider_host->running_hosted_version())));
break;
case SERVICE_WORKER_PROVIDER_UNKNOWN:
default:
NOTREACHED() << sender_provider_host->provider_type();
break;
}
}
void ServiceWorkerDispatcherHost::OnProviderCreated(
int provider_id,
int route_id,
ServiceWorkerProviderType provider_type,
bool is_parent_frame_secure) {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"477117 ServiceWorkerDispatcherHost::OnProviderCreated"));
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnProviderCreated");
if (!GetContext())
return;
if (GetContext()->GetProviderHost(render_process_id_, provider_id)) {
bad_message::ReceivedBadMessage(this,
bad_message::SWDH_PROVIDER_CREATED_NO_HOST);
return;
}
std::unique_ptr<ServiceWorkerProviderHost> provider_host;
if (IsBrowserSideNavigationEnabled() &&
ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) {
// PlzNavigate
// Retrieve the provider host previously created for navigation requests.
ServiceWorkerNavigationHandleCore* navigation_handle_core =
GetContext()->GetNavigationHandleCore(provider_id);
if (navigation_handle_core != nullptr) {
provider_host = navigation_handle_core->RetrievePreCreatedHost();
provider_host->set_parent_frame_secure(is_parent_frame_secure);
}
// If no host is found, the navigation has been cancelled in the meantime.
// Just return as the navigation will be stopped in the renderer as well.
if (provider_host == nullptr)
return;
DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, provider_type);
provider_host->CompleteNavigationInitialized(render_process_id_, route_id,
this);
} else {
if (ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_PROVIDER_CREATED_NO_HOST);
return;
}
ServiceWorkerProviderHost::FrameSecurityLevel parent_frame_security_level =
is_parent_frame_secure
? ServiceWorkerProviderHost::FrameSecurityLevel::SECURE
: ServiceWorkerProviderHost::FrameSecurityLevel::INSECURE;
provider_host = std::unique_ptr<ServiceWorkerProviderHost>(
new ServiceWorkerProviderHost(
render_process_id_, route_id, provider_id, provider_type,
parent_frame_security_level, GetContext()->AsWeakPtr(), this));
}
GetContext()->AddProviderHost(std::move(provider_host));
}
void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnProviderDestroyed");
if (!GetContext())
return;
if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
// PlzNavigate: in some cancellation of navigation cases, it is possible
// for the pre-created hoist to have been destroyed before being claimed by
// the renderer. The provider is then destroyed in the renderer, and no
// matching host will be found.
if (!IsBrowserSideNavigationEnabled() ||
!ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST);
}
return;
}
GetContext()->RemoveProviderHost(render_process_id_, provider_id);
}
void ServiceWorkerDispatcherHost::OnSetHostedVersionId(int provider_id,
int64_t version_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnSetHostedVersionId");
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_SET_HOSTED_VERSION_NO_HOST);
return;
}
if (!provider_host->IsContextAlive())
return;
// We might not be STARTING if the stop sequence was entered (STOPPING) or
// ended up being detached (STOPPED).
ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
if (!version || version->running_status() != ServiceWorkerVersion::STARTING)
return;
if (!provider_host->SetHostedVersion(version)) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_SET_HOSTED_VERSION);
return;
}
// Retrieve the registration associated with |version|. The registration
// must be alive because the version keeps it during starting worker.
ServiceWorkerRegistration* registration =
GetContext()->GetLiveRegistration(version->registration_id());
DCHECK(registration);
// Set the document URL to the script url in order to allow
// register/unregister/getRegistration on ServiceWorkerGlobalScope.
provider_host->SetDocumentUrl(version->script_url());
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
GetRegistrationObjectInfoAndVersionAttributes(
provider_host->AsWeakPtr(), registration, &info, &attrs);
Send(new ServiceWorkerMsg_AssociateRegistration(kDocumentMainThreadId,
provider_id, info, attrs));
}
template <typename SourceInfo>
void ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal(
scoped_refptr<ServiceWorkerVersion> worker,
const base::string16& message,
const url::Origin& source_origin,
const std::vector<int>& sent_message_ports,
const StatusCallback& callback,
const SourceInfo& source_info) {
if (!source_info.IsValid()) {
DidFailToDispatchExtendableMessageEvent<SourceInfo>(
sent_message_ports, source_info, callback, SERVICE_WORKER_ERROR_FAILED);
return;
}
worker->RunAfterStartWorker(
ServiceWorkerMetrics::EventType::MESSAGE,
base::Bind(&ServiceWorkerDispatcherHost::
DispatchExtendableMessageEventAfterStartWorker,
this, worker, message, source_origin, sent_message_ports,
ExtendableMessageEventSource(source_info), callback),
base::Bind(
&ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent<
SourceInfo>,
this, sent_message_ports, source_info, callback));
}
void ServiceWorkerDispatcherHost::
DispatchExtendableMessageEventAfterStartWorker(
scoped_refptr<ServiceWorkerVersion> worker,
const base::string16& message,
const url::Origin& source_origin,
const std::vector<int>& sent_message_ports,
const ExtendableMessageEventSource& source,
const StatusCallback& callback) {
int request_id =
worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE, callback);
MessagePortMessageFilter* filter =
worker->embedded_worker()->message_port_message_filter();
std::vector<int> new_routing_ids;
filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
ServiceWorkerMsg_ExtendableMessageEvent_Params params;
params.message = message;
params.source_origin = source_origin;
params.message_ports = sent_message_ports;
params.new_routing_ids = new_routing_ids;
params.source = source;
// Hide the client url if the client has a unique origin.
if (source_origin.unique()) {
if (params.source.client_info.IsValid())
params.source.client_info.url = GURL();
else
params.source.service_worker_info.url = GURL();
}
worker->DispatchSimpleEvent<
ServiceWorkerHostMsg_ExtendableMessageEventFinished>(
request_id, ServiceWorkerMsg_ExtendableMessageEvent(request_id, params));
}
template <typename SourceInfo>
void ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent(
const std::vector<int>& sent_message_ports,
const SourceInfo& source_info,
const StatusCallback& callback,
ServiceWorkerStatusCode status) {
// Transfering the message ports failed, so destroy the ports.
for (int port : sent_message_ports)
MessagePortService::GetInstance()->ClosePort(port);
if (source_info.IsValid())
ReleaseSourceInfo(source_info);
callback.Run(status);
}
void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
const ServiceWorkerClientInfo& source_info) {
// ServiceWorkerClientInfo is just a snapshot of the client. There is no need
// to do anything for it.
}
void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
const ServiceWorkerObjectInfo& source_info) {
ServiceWorkerHandle* handle = handles_.Lookup(source_info.handle_id);
DCHECK(handle);
handle->DecrementRefCount();
if (handle->HasNoRefCount())
handles_.Remove(source_info.handle_id);
}
ServiceWorkerRegistrationHandle*
ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
int64_t registration_id) {
for (RegistrationHandleMap::iterator iter(&registration_handles_);
!iter.IsAtEnd(); iter.Advance()) {
ServiceWorkerRegistrationHandle* handle = iter.GetCurrentValue();
if (handle->provider_id() == provider_id &&
handle->registration()->id() == registration_id) {
return handle;
}
}
return nullptr;
}
void ServiceWorkerDispatcherHost::GetRegistrationObjectInfoAndVersionAttributes(
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration,
ServiceWorkerRegistrationObjectInfo* info,
ServiceWorkerVersionAttributes* attrs) {
ServiceWorkerRegistrationHandle* handle =
GetOrCreateRegistrationHandle(provider_host, registration);
*info = handle->GetObjectInfo();
attrs->installing = provider_host->GetOrCreateServiceWorkerHandle(
registration->installing_version());
attrs->waiting = provider_host->GetOrCreateServiceWorkerHandle(
registration->waiting_version());
attrs->active = provider_host->GetOrCreateServiceWorkerHandle(
registration->active_version());
}
void ServiceWorkerDispatcherHost::RegistrationComplete(
int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
TRACE_EVENT_ASYNC_END2(
"ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
request_id, "Status", status, "Registration ID", registration_id);
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host)
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
GetServiceWorkerRegistrationStatusResponse(status, status_message,
&error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id, request_id, error_type,
base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
return;
}
ServiceWorkerRegistration* registration =
GetContext()->GetLiveRegistration(registration_id);
DCHECK(registration);
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
GetRegistrationObjectInfoAndVersionAttributes(
provider_host->AsWeakPtr(), registration, &info, &attrs);
Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
thread_id, request_id, info, attrs));
}
void ServiceWorkerDispatcherHost::UpdateComplete(
int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
TRACE_EVENT_ASYNC_END2(
"ServiceWorker", "ServiceWorkerDispatcherHost::UpdateServiceWorker",
request_id, "Status", status, "Registration ID", registration_id);
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host)
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
GetServiceWorkerRegistrationStatusResponse(status, status_message,
&error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
thread_id, request_id, error_type,
base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) + error_message));
return;
}
ServiceWorkerRegistration* registration =
GetContext()->GetLiveRegistration(registration_id);
DCHECK(registration);
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
GetRegistrationObjectInfoAndVersionAttributes(provider_host->AsWeakPtr(),
registration, &info, &attrs);
Send(new ServiceWorkerMsg_ServiceWorkerUpdated(thread_id, request_id));
}
void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
int embedded_worker_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerReadyForInspection");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerReadyForInspection(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerScriptLoaded");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerScriptLoaded(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerThreadStarted(int embedded_worker_id,
int thread_id,
int provider_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerThreadStarted");
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_WORKER_SCRIPT_LOAD_NO_HOST);
return;
}
provider_host->SetReadyToSendMessagesToWorker(thread_id);
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerThreadStarted(render_process_id_, thread_id,
embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
int embedded_worker_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerScriptLoadFailed(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated(
int embedded_worker_id,
bool success) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerScriptEvaluated(
render_process_id_, embedded_worker_id, success);
}
void ServiceWorkerDispatcherHost::OnWorkerStarted(int embedded_worker_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerStarted");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerStarted(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnWorkerStopped");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnWorkerStopped(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnReportException(
int embedded_worker_id,
const base::string16& error_message,
int line_number,
int column_number,
const GURL& source_url) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnReportException");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnReportException(embedded_worker_id,
error_message,
line_number,
column_number,
source_url);
}
void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
int embedded_worker_id,
const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnReportConsoleMessage");
if (!GetContext())
return;
EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
if (!registry->CanHandle(embedded_worker_id))
return;
registry->OnReportConsoleMessage(embedded_worker_id,
params.source_identifier,
params.message_level,
params.message,
params.line_number,
params.source_url);
}
void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
int handle_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount");
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_INCREMENT_WORKER_BAD_HANDLE);
return;
}
handle->IncrementRefCount();
}
void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
int handle_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount");
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_DECREMENT_WORKER_BAD_HANDLE);
return;
}
handle->DecrementRefCount();
if (handle->HasNoRefCount())
handles_.Remove(handle_id);
}
void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
int registration_handle_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount");
ServiceWorkerRegistrationHandle* handle =
registration_handles_.Lookup(registration_handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_INCREMENT_REGISTRATION_BAD_HANDLE);
return;
}
handle->IncrementRefCount();
}
void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
int registration_handle_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount");
ServiceWorkerRegistrationHandle* handle =
registration_handles_.Lookup(registration_handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(
this, bad_message::SWDH_DECREMENT_REGISTRATION_BAD_HANDLE);
return;
}
handle->DecrementRefCount();
if (handle->HasNoRefCount())
registration_handles_.Remove(registration_handle_id);
}
void ServiceWorkerDispatcherHost::UnregistrationComplete(
int thread_id,
int request_id,
ServiceWorkerStatusCode status) {
TRACE_EVENT_ASYNC_END1("ServiceWorker",
"ServiceWorkerDispatcherHost::UnregisterServiceWorker",
request_id, "Status", status);
if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
GetServiceWorkerRegistrationStatusResponse(status, std::string(),
&error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id, request_id, error_type,
base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) +
error_message));
return;
}
const bool is_success = (status == SERVICE_WORKER_OK);
Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id,
request_id,
is_success));
}
void ServiceWorkerDispatcherHost::GetRegistrationComplete(
int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
TRACE_EVENT_ASYNC_END2(
"ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistration",
request_id, "Status", status, "Registration ID",
registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host)
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
GetServiceWorkerRegistrationStatusResponse(status, std::string(),
&error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, error_type,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
error_message));
return;
}
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
if (status == SERVICE_WORKER_OK) {
DCHECK(registration.get());
if (!registration->is_uninstalling()) {
GetRegistrationObjectInfoAndVersionAttributes(
provider_host->AsWeakPtr(), registration.get(), &info, &attrs);
}
}
Send(new ServiceWorkerMsg_DidGetRegistration(
thread_id, request_id, info, attrs));
}
void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
registrations) {
TRACE_EVENT_ASYNC_END1("ServiceWorker",
"ServiceWorkerDispatcherHost::GetRegistrations",
request_id, "Status", status);
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
GetContext()->GetProviderHost(render_process_id_, provider_id);
if (!provider_host)
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK) {
base::string16 error_message;
blink::WebServiceWorkerError::ErrorType error_type;
GetServiceWorkerRegistrationStatusResponse(status, std::string(),
&error_type, &error_message);
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
thread_id, request_id, error_type,
base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
error_message));
return;
}
std::vector<ServiceWorkerRegistrationObjectInfo> object_infos;
std::vector<ServiceWorkerVersionAttributes> version_attrs;
for (const auto& registration : registrations) {
DCHECK(registration.get());
if (!registration->is_uninstalling()) {
ServiceWorkerRegistrationObjectInfo object_info;
ServiceWorkerVersionAttributes version_attr;
GetRegistrationObjectInfoAndVersionAttributes(
provider_host->AsWeakPtr(), registration.get(), &object_info,
&version_attr);
object_infos.push_back(object_info);
version_attrs.push_back(version_attr);
}
}
Send(new ServiceWorkerMsg_DidGetRegistrations(thread_id, request_id,
object_infos, version_attrs));
}
void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
int thread_id,
int request_id,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration) {
DCHECK(registration);
TRACE_EVENT_ASYNC_END1(
"ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
request_id, "Registration ID",
registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
if (!GetContext())
return;
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
GetRegistrationObjectInfoAndVersionAttributes(
provider_host, registration, &info, &attrs);
Send(new ServiceWorkerMsg_DidGetRegistrationForReady(
thread_id, request_id, info, attrs));
}
ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
if (!context_wrapper_.get())
return nullptr;
return context_wrapper_->context();
}
void ServiceWorkerDispatcherHost::OnTerminateWorker(int handle_id) {
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
bad_message::ReceivedBadMessage(this,
bad_message::SWDH_TERMINATE_BAD_HANDLE);
return;
}
handle->version()->StopWorker(
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
}
} // namespace content