// 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/child/service_worker/service_worker_dispatcher.h" #include <stddef.h> #include <utility> #include "base/lazy_instance.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/thread_task_runner_handle.h" #include "base/threading/thread_local.h" #include "base/trace_event/trace_event.h" #include "content/child/service_worker/service_worker_handle_reference.h" #include "content/child/service_worker/service_worker_provider_context.h" #include "content/child/service_worker/service_worker_registration_handle_reference.h" #include "content/child/service_worker/web_service_worker_impl.h" #include "content/child/service_worker/web_service_worker_registration_impl.h" #include "content/child/thread_safe_sender.h" #include "content/child/webmessageportchannel_impl.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/common/service_worker/service_worker_types.h" #include "content/public/common/content_constants.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h" using blink::WebServiceWorkerError; using blink::WebServiceWorkerProvider; using base::ThreadLocalPointer; namespace content { namespace { base::LazyInstance<ThreadLocalPointer<void>>::Leaky g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER; void* const kHasBeenDeleted = reinterpret_cast<void*>(0x1); int CurrentWorkerId() { return WorkerThread::GetCurrentId(); } } // namespace ServiceWorkerDispatcher::ServiceWorkerDispatcher( ThreadSafeSender* thread_safe_sender, base::SingleThreadTaskRunner* main_thread_task_runner) : thread_safe_sender_(thread_safe_sender), main_thread_task_runner_(main_thread_task_runner) { g_dispatcher_tls.Pointer()->Set(static_cast<void*>(this)); } ServiceWorkerDispatcher::~ServiceWorkerDispatcher() { g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); } void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) { bool handled = true; // When you add a new message handler, you should consider adding a similar // handler in ServiceWorkerMessageFilter to release references passed from // the browser process in case we fail to post task to the thread. IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration, OnAssociateRegistration) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DisassociateRegistration, OnDisassociateRegistration) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered, OnRegistered) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUpdated, OnUpdated) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistered, OnUnregistered) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration, OnDidGetRegistration) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrations, OnDidGetRegistrations) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrationForReady, OnDidGetRegistrationForReady) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError, OnRegistrationError) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUpdateError, OnUpdateError) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistrationError, OnUnregistrationError) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationError, OnGetRegistrationError) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationsError, OnGetRegistrationsError) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged, OnServiceWorkerStateChanged) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes, OnSetVersionAttributes) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_UpdateFound, OnUpdateFound) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetControllerServiceWorker, OnSetControllerServiceWorker) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument, OnPostMessage) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() DCHECK(handled) << "Unhandled message:" << msg.type(); } void ServiceWorkerDispatcher::RegisterServiceWorker( int provider_id, const GURL& pattern, const GURL& script_url, WebServiceWorkerRegistrationCallbacks* callbacks) { DCHECK(callbacks); if (pattern.possibly_invalid_spec().size() > kMaxURLChars || script_url.possibly_invalid_spec().size() > kMaxURLChars) { scoped_ptr<WebServiceWorkerRegistrationCallbacks> owned_callbacks(callbacks); std::string error_message(kServiceWorkerRegisterErrorPrefix); error_message += "The provided scriptURL or scope is too long."; callbacks->onError( WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity, blink::WebString::fromUTF8(error_message))); return; } int request_id = pending_registration_callbacks_.Add(callbacks); TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerDispatcher::RegisterServiceWorker", request_id, "Scope", pattern.spec(), "Script URL", script_url.spec()); thread_safe_sender_->Send(new ServiceWorkerHostMsg_RegisterServiceWorker( CurrentWorkerId(), request_id, provider_id, pattern, script_url)); } void ServiceWorkerDispatcher::UpdateServiceWorker( int provider_id, int64_t registration_id, WebServiceWorkerUpdateCallbacks* callbacks) { DCHECK(callbacks); int request_id = pending_update_callbacks_.Add(callbacks); thread_safe_sender_->Send(new ServiceWorkerHostMsg_UpdateServiceWorker( CurrentWorkerId(), request_id, provider_id, registration_id)); } void ServiceWorkerDispatcher::UnregisterServiceWorker( int provider_id, int64_t registration_id, WebServiceWorkerUnregistrationCallbacks* callbacks) { DCHECK(callbacks); int request_id = pending_unregistration_callbacks_.Add(callbacks); TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "ServiceWorkerDispatcher::UnregisterServiceWorker", request_id, "Registration ID", registration_id); thread_safe_sender_->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker( CurrentWorkerId(), request_id, provider_id, registration_id)); } void ServiceWorkerDispatcher::GetRegistration( int provider_id, const GURL& document_url, WebServiceWorkerGetRegistrationCallbacks* callbacks) { DCHECK(callbacks); if (document_url.possibly_invalid_spec().size() > kMaxURLChars) { scoped_ptr<WebServiceWorkerGetRegistrationCallbacks> owned_callbacks( callbacks); std::string error_message(kServiceWorkerGetRegistrationErrorPrefix); error_message += "The provided documentURL is too long."; callbacks->onError( WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity, blink::WebString::fromUTF8(error_message))); return; } int request_id = pending_get_registration_callbacks_.Add(callbacks); TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "ServiceWorkerDispatcher::GetRegistration", request_id, "Document URL", document_url.spec()); thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistration( CurrentWorkerId(), request_id, provider_id, document_url)); } void ServiceWorkerDispatcher::GetRegistrations( int provider_id, WebServiceWorkerGetRegistrationsCallbacks* callbacks) { DCHECK(callbacks); int request_id = pending_get_registrations_callbacks_.Add(callbacks); TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistrations", request_id); thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistrations( CurrentWorkerId(), request_id, provider_id)); } void ServiceWorkerDispatcher::GetRegistrationForReady( int provider_id, WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks) { int request_id = get_for_ready_callbacks_.Add(callbacks); TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistrationForReady", request_id); thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistrationForReady( CurrentWorkerId(), request_id, provider_id)); } void ServiceWorkerDispatcher::AddProviderContext( ServiceWorkerProviderContext* provider_context) { DCHECK(provider_context); int provider_id = provider_context->provider_id(); DCHECK(!ContainsKey(provider_contexts_, provider_id)); provider_contexts_[provider_id] = provider_context; } void ServiceWorkerDispatcher::RemoveProviderContext( ServiceWorkerProviderContext* provider_context) { DCHECK(provider_context); DCHECK(ContainsKey(provider_contexts_, provider_context->provider_id())); provider_contexts_.erase(provider_context->provider_id()); } void ServiceWorkerDispatcher::AddProviderClient( int provider_id, blink::WebServiceWorkerProviderClient* client) { DCHECK(client); DCHECK(!ContainsKey(provider_clients_, provider_id)); provider_clients_[provider_id] = client; } void ServiceWorkerDispatcher::RemoveProviderClient(int provider_id) { // This could be possibly called multiple times to ensure termination. if (ContainsKey(provider_clients_, provider_id)) provider_clients_.erase(provider_id); } ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( ThreadSafeSender* thread_safe_sender, base::SingleThreadTaskRunner* main_thread_task_runner) { if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) { NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher."; g_dispatcher_tls.Pointer()->Set(NULL); } if (g_dispatcher_tls.Pointer()->Get()) return static_cast<ServiceWorkerDispatcher*>( g_dispatcher_tls.Pointer()->Get()); ServiceWorkerDispatcher* dispatcher = new ServiceWorkerDispatcher(thread_safe_sender, main_thread_task_runner); if (WorkerThread::GetCurrentId()) WorkerThread::AddObserver(dispatcher); return dispatcher; } ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetThreadSpecificInstance() { if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) return NULL; return static_cast<ServiceWorkerDispatcher*>( g_dispatcher_tls.Pointer()->Get()); } void ServiceWorkerDispatcher::WillStopCurrentWorkerThread() { delete this; } scoped_refptr<WebServiceWorkerImpl> ServiceWorkerDispatcher::GetOrCreateServiceWorker( scoped_ptr<ServiceWorkerHandleReference> handle_ref) { if (!handle_ref) return nullptr; WorkerObjectMap::iterator found = service_workers_.find(handle_ref->handle_id()); if (found != service_workers_.end()) return found->second; // WebServiceWorkerImpl constructor calls AddServiceWorker. return new WebServiceWorkerImpl(std::move(handle_ref), thread_safe_sender_.get()); } scoped_refptr<WebServiceWorkerRegistrationImpl> ServiceWorkerDispatcher::GetOrCreateRegistration( const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { RegistrationObjectMap::iterator found = registrations_.find(info.handle_id); if (found != registrations_.end()) return found->second; // WebServiceWorkerRegistrationImpl constructor calls // AddServiceWorkerRegistration. scoped_refptr<WebServiceWorkerRegistrationImpl> registration( new WebServiceWorkerRegistrationImpl( ServiceWorkerRegistrationHandleReference::Create( info, thread_safe_sender_.get()))); registration->SetInstalling( GetOrCreateServiceWorker(ServiceWorkerHandleReference::Create( attrs.installing, thread_safe_sender_.get()))); registration->SetWaiting( GetOrCreateServiceWorker(ServiceWorkerHandleReference::Create( attrs.waiting, thread_safe_sender_.get()))); registration->SetActive( GetOrCreateServiceWorker(ServiceWorkerHandleReference::Create( attrs.active, thread_safe_sender_.get()))); return registration; } scoped_refptr<WebServiceWorkerRegistrationImpl> ServiceWorkerDispatcher::GetOrAdoptRegistration( const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { scoped_ptr<ServiceWorkerRegistrationHandleReference> registration_ref = Adopt(info); scoped_ptr<ServiceWorkerHandleReference> installing_ref = Adopt(attrs.installing); scoped_ptr<ServiceWorkerHandleReference> waiting_ref = Adopt(attrs.waiting); scoped_ptr<ServiceWorkerHandleReference> active_ref = Adopt(attrs.active); RegistrationObjectMap::iterator found = registrations_.find(info.handle_id); if (found != registrations_.end()) return found->second; // WebServiceWorkerRegistrationImpl constructor calls // AddServiceWorkerRegistration. scoped_refptr<WebServiceWorkerRegistrationImpl> registration( new WebServiceWorkerRegistrationImpl(std::move(registration_ref))); registration->SetInstalling( GetOrCreateServiceWorker(std::move(installing_ref))); registration->SetWaiting(GetOrCreateServiceWorker(std::move(waiting_ref))); registration->SetActive(GetOrCreateServiceWorker(std::move(active_ref))); return registration; } void ServiceWorkerDispatcher::OnAssociateRegistration( int thread_id, int provider_id, const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { // Adopt the references sent from the browser process and pass them to the // provider context if it exists. scoped_ptr<ServiceWorkerRegistrationHandleReference> registration = Adopt(info); scoped_ptr<ServiceWorkerHandleReference> installing = Adopt(attrs.installing); scoped_ptr<ServiceWorkerHandleReference> waiting = Adopt(attrs.waiting); scoped_ptr<ServiceWorkerHandleReference> active = Adopt(attrs.active); ProviderContextMap::iterator context = provider_contexts_.find(provider_id); if (context != provider_contexts_.end()) { context->second->OnAssociateRegistration( std::move(registration), std::move(installing), std::move(waiting), std::move(active)); } } void ServiceWorkerDispatcher::OnDisassociateRegistration( int thread_id, int provider_id) { ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); if (provider == provider_contexts_.end()) return; provider->second->OnDisassociateRegistration(); } void ServiceWorkerDispatcher::OnRegistered( int thread_id, int request_id, const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", "ServiceWorkerDispatcher::RegisterServiceWorker", request_id, "OnRegistered"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::RegisterServiceWorker", request_id); WebServiceWorkerRegistrationCallbacks* callbacks = pending_registration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onSuccess(WebServiceWorkerRegistrationImpl::CreateHandle( GetOrAdoptRegistration(info, attrs))); pending_registration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnUpdated(int thread_id, int request_id) { TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", "ServiceWorkerDispatcher::UpdateServiceWorker", request_id, "OnUpdated"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::UpdateServiceWorker", request_id); WebServiceWorkerUpdateCallbacks* callbacks = pending_update_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onSuccess(); pending_update_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnUnregistered(int thread_id, int request_id, bool is_success) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::UnregisterServiceWorker", request_id, "OnUnregistered"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::UnregisterServiceWorker", request_id); WebServiceWorkerUnregistrationCallbacks* callbacks = pending_unregistration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onSuccess(is_success); pending_unregistration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnDidGetRegistration( int thread_id, int request_id, const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::GetRegistration", request_id, "OnDidGetRegistration"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistration", request_id); WebServiceWorkerGetRegistrationCallbacks* callbacks = pending_get_registration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; scoped_refptr<WebServiceWorkerRegistrationImpl> registration; if (info.handle_id != kInvalidServiceWorkerRegistrationHandleId) registration = GetOrAdoptRegistration(info, attrs); callbacks->onSuccess( WebServiceWorkerRegistrationImpl::CreateHandle(registration)); pending_get_registration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnDidGetRegistrations( int thread_id, int request_id, const std::vector<ServiceWorkerRegistrationObjectInfo>& infos, const std::vector<ServiceWorkerVersionAttributes>& attrs) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::GetRegistrations", request_id, "OnDidGetRegistrations"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistrations", request_id); WebServiceWorkerGetRegistrationsCallbacks* callbacks = pending_get_registrations_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; typedef blink::WebVector<blink::WebServiceWorkerRegistration::Handle*> WebServiceWorkerRegistrationArray; scoped_ptr<WebServiceWorkerRegistrationArray> registrations( new WebServiceWorkerRegistrationArray(infos.size())); for (size_t i = 0; i < infos.size(); ++i) { if (infos[i].handle_id != kInvalidServiceWorkerHandleId) { ServiceWorkerRegistrationObjectInfo info(infos[i]); ServiceWorkerVersionAttributes attr(attrs[i]); // WebServiceWorkerGetRegistrationsCallbacks cannot receive an array of // WebPassOwnPtr<WebServiceWorkerRegistration::Handle>, so create leaky // handles instead. (*registrations)[i] = WebServiceWorkerRegistrationImpl::CreateLeakyHandle( GetOrAdoptRegistration(info, attr)); } } callbacks->onSuccess(blink::adoptWebPtr(registrations.release())); pending_get_registrations_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnDidGetRegistrationForReady( int thread_id, int request_id, const ServiceWorkerRegistrationObjectInfo& info, const ServiceWorkerVersionAttributes& attrs) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::GetRegistrationForReady", request_id, "OnDidGetRegistrationForReady"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistrationForReady", request_id); WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks = get_for_ready_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onSuccess(WebServiceWorkerRegistrationImpl::CreateHandle( GetOrAdoptRegistration(info, attrs))); get_for_ready_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnRegistrationError( int thread_id, int request_id, WebServiceWorkerError::ErrorType error_type, const base::string16& message) { TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", "ServiceWorkerDispatcher::RegisterServiceWorker", request_id, "OnRegistrationError"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::RegisterServiceWorker", request_id); WebServiceWorkerRegistrationCallbacks* callbacks = pending_registration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onError(WebServiceWorkerError(error_type, message)); pending_registration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnUpdateError( int thread_id, int request_id, WebServiceWorkerError::ErrorType error_type, const base::string16& message) { TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", "ServiceWorkerDispatcher::UpdateServiceWorker", request_id, "OnUpdateError"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::UpdateServiceWorker", request_id); WebServiceWorkerUpdateCallbacks* callbacks = pending_update_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onError(WebServiceWorkerError(error_type, message)); pending_update_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnUnregistrationError( int thread_id, int request_id, WebServiceWorkerError::ErrorType error_type, const base::string16& message) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::UnregisterServiceWorker", request_id, "OnUnregistrationError"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::UnregisterServiceWorker", request_id); WebServiceWorkerUnregistrationCallbacks* callbacks = pending_unregistration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onError(WebServiceWorkerError(error_type, message)); pending_unregistration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnGetRegistrationError( int thread_id, int request_id, WebServiceWorkerError::ErrorType error_type, const base::string16& message) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::GetRegistration", request_id, "OnGetRegistrationError"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistration", request_id); WebServiceWorkerGetRegistrationCallbacks* callbacks = pending_get_registration_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onError(WebServiceWorkerError(error_type, message)); pending_get_registration_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnGetRegistrationsError( int thread_id, int request_id, WebServiceWorkerError::ErrorType error_type, const base::string16& message) { TRACE_EVENT_ASYNC_STEP_INTO0( "ServiceWorker", "ServiceWorkerDispatcher::GetRegistrations", request_id, "OnGetRegistrationsError"); TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerDispatcher::GetRegistrations", request_id); WebServiceWorkerGetRegistrationsCallbacks* callbacks = pending_get_registrations_callbacks_.Lookup(request_id); DCHECK(callbacks); if (!callbacks) return; callbacks->onError(WebServiceWorkerError(error_type, message)); pending_get_registrations_callbacks_.Remove(request_id); } void ServiceWorkerDispatcher::OnServiceWorkerStateChanged( int thread_id, int handle_id, blink::WebServiceWorkerState state) { TRACE_EVENT2("ServiceWorker", "ServiceWorkerDispatcher::OnServiceWorkerStateChanged", "Thread ID", thread_id, "State", state); WorkerObjectMap::iterator worker = service_workers_.find(handle_id); if (worker != service_workers_.end()) worker->second->OnStateChanged(state); } void ServiceWorkerDispatcher::OnSetVersionAttributes( int thread_id, int registration_handle_id, int changed_mask, const ServiceWorkerVersionAttributes& attrs) { TRACE_EVENT1("ServiceWorker", "ServiceWorkerDispatcher::OnSetVersionAttributes", "Thread ID", thread_id); // Adopt the references sent from the browser process and pass it to the // registration if it exists. scoped_ptr<ServiceWorkerHandleReference> installing = Adopt(attrs.installing); scoped_ptr<ServiceWorkerHandleReference> waiting = Adopt(attrs.waiting); scoped_ptr<ServiceWorkerHandleReference> active = Adopt(attrs.active); RegistrationObjectMap::iterator found = registrations_.find(registration_handle_id); if (found != registrations_.end()) { // Populate the version fields (eg. .installing) with worker objects. ChangedVersionAttributesMask mask(changed_mask); if (mask.installing_changed()) found->second->SetInstalling( GetOrCreateServiceWorker(std::move(installing))); if (mask.waiting_changed()) found->second->SetWaiting(GetOrCreateServiceWorker(std::move(waiting))); if (mask.active_changed()) found->second->SetActive(GetOrCreateServiceWorker(std::move(active))); } } void ServiceWorkerDispatcher::OnUpdateFound( int thread_id, int registration_handle_id) { TRACE_EVENT0("ServiceWorker", "ServiceWorkerDispatcher::OnUpdateFound"); RegistrationObjectMap::iterator found = registrations_.find(registration_handle_id); if (found != registrations_.end()) found->second->OnUpdateFound(); } void ServiceWorkerDispatcher::OnSetControllerServiceWorker( int thread_id, int provider_id, const ServiceWorkerObjectInfo& info, bool should_notify_controllerchange) { TRACE_EVENT2("ServiceWorker", "ServiceWorkerDispatcher::OnSetControllerServiceWorker", "Thread ID", thread_id, "Provider ID", provider_id); // Adopt the reference sent from the browser process and pass it to the // provider context if it exists. scoped_ptr<ServiceWorkerHandleReference> handle_ref = Adopt(info); ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); if (provider != provider_contexts_.end()) provider->second->OnSetControllerServiceWorker(std::move(handle_ref)); ProviderClientMap::iterator found = provider_clients_.find(provider_id); if (found != provider_clients_.end()) { // Get the existing worker object or create a new one with a new reference // to populate the .controller field. scoped_refptr<WebServiceWorkerImpl> worker = GetOrCreateServiceWorker( ServiceWorkerHandleReference::Create(info, thread_safe_sender_.get())); found->second->setController(WebServiceWorkerImpl::CreateHandle(worker), should_notify_controllerchange); } } void ServiceWorkerDispatcher::OnPostMessage( const ServiceWorkerMsg_MessageToDocument_Params& params) { // Make sure we're on the main document thread. (That must be the only // thread we get this message) DCHECK_EQ(kDocumentMainThreadId, params.thread_id); TRACE_EVENT1("ServiceWorker", "ServiceWorkerDispatcher::OnPostMessage", "Thread ID", params.thread_id); // Adopt the reference sent from the browser process and get the corresponding // worker object. scoped_refptr<WebServiceWorkerImpl> worker = GetOrCreateServiceWorker(Adopt(params.service_worker_info)); ProviderClientMap::iterator found = provider_clients_.find(params.provider_id); if (found == provider_clients_.end()) { // For now we do no queueing for messages sent to nonexistent / unattached // client. return; } blink::WebMessagePortChannelArray ports = WebMessagePortChannelImpl::CreatePorts( params.message_ports, params.new_routing_ids, base::ThreadTaskRunnerHandle::Get()); found->second->dispatchMessageEvent( WebServiceWorkerImpl::CreateHandle(worker), params.message, ports); } void ServiceWorkerDispatcher::AddServiceWorker( int handle_id, WebServiceWorkerImpl* worker) { DCHECK(!ContainsKey(service_workers_, handle_id)); service_workers_[handle_id] = worker; } void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id) { DCHECK(ContainsKey(service_workers_, handle_id)); service_workers_.erase(handle_id); } void ServiceWorkerDispatcher::AddServiceWorkerRegistration( int registration_handle_id, WebServiceWorkerRegistrationImpl* registration) { DCHECK(!ContainsKey(registrations_, registration_handle_id)); registrations_[registration_handle_id] = registration; } void ServiceWorkerDispatcher::RemoveServiceWorkerRegistration( int registration_handle_id) { DCHECK(ContainsKey(registrations_, registration_handle_id)); registrations_.erase(registration_handle_id); } scoped_ptr<ServiceWorkerRegistrationHandleReference> ServiceWorkerDispatcher::Adopt( const ServiceWorkerRegistrationObjectInfo& info) { return ServiceWorkerRegistrationHandleReference::Adopt( info, thread_safe_sender_.get()); } scoped_ptr<ServiceWorkerHandleReference> ServiceWorkerDispatcher::Adopt( const ServiceWorkerObjectInfo& info) { return ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); } } // namespace content