Home | History | Annotate | Download | only in service_worker
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/child/service_worker/service_worker_dispatcher.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/stl_util.h"
     10 #include "base/threading/thread_local.h"
     11 #include "content/child/child_thread.h"
     12 #include "content/child/service_worker/service_worker_handle_reference.h"
     13 #include "content/child/service_worker/service_worker_provider_context.h"
     14 #include "content/child/service_worker/service_worker_registration_handle_reference.h"
     15 #include "content/child/service_worker/web_service_worker_impl.h"
     16 #include "content/child/service_worker/web_service_worker_registration_impl.h"
     17 #include "content/child/thread_safe_sender.h"
     18 #include "content/child/webmessageportchannel_impl.h"
     19 #include "content/common/service_worker/service_worker_messages.h"
     20 #include "content/public/common/url_utils.h"
     21 #include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
     22 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
     23 
     24 using blink::WebServiceWorkerError;
     25 using blink::WebServiceWorkerProvider;
     26 using base::ThreadLocalPointer;
     27 
     28 namespace content {
     29 
     30 namespace {
     31 
     32 base::LazyInstance<ThreadLocalPointer<ServiceWorkerDispatcher> >::Leaky
     33     g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
     34 
     35 ServiceWorkerDispatcher* const kHasBeenDeleted =
     36     reinterpret_cast<ServiceWorkerDispatcher*>(0x1);
     37 
     38 int CurrentWorkerId() {
     39   return WorkerTaskRunner::Instance()->CurrentWorkerId();
     40 }
     41 
     42 }  // namespace
     43 
     44 ServiceWorkerDispatcher::ServiceWorkerDispatcher(
     45     ThreadSafeSender* thread_safe_sender)
     46     : thread_safe_sender_(thread_safe_sender) {
     47   g_dispatcher_tls.Pointer()->Set(this);
     48 }
     49 
     50 ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
     51   g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
     52 }
     53 
     54 void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) {
     55   bool handled = true;
     56   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg)
     57     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration,
     58                         OnAssociateRegistration)
     59     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DisassociateRegistration,
     60                         OnDisassociateRegistration)
     61     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered, OnRegistered)
     62     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistered,
     63                         OnUnregistered)
     64     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration,
     65                         OnDidGetRegistration)
     66     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError,
     67                         OnRegistrationError)
     68     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistrationError,
     69                         OnUnregistrationError)
     70     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationError,
     71                         OnGetRegistrationError)
     72     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged,
     73                         OnServiceWorkerStateChanged)
     74     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes,
     75                         OnSetVersionAttributes)
     76     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_UpdateFound,
     77                         OnUpdateFound)
     78     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetControllerServiceWorker,
     79                         OnSetControllerServiceWorker)
     80     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument,
     81                         OnPostMessage)
     82     IPC_MESSAGE_UNHANDLED(handled = false)
     83   IPC_END_MESSAGE_MAP()
     84   DCHECK(handled) << "Unhandled message:" << msg.type();
     85 }
     86 
     87 bool ServiceWorkerDispatcher::Send(IPC::Message* msg) {
     88   return thread_safe_sender_->Send(msg);
     89 }
     90 
     91 void ServiceWorkerDispatcher::RegisterServiceWorker(
     92     int provider_id,
     93     const GURL& pattern,
     94     const GURL& script_url,
     95     WebServiceWorkerRegistrationCallbacks* callbacks) {
     96   DCHECK(callbacks);
     97 
     98   if (pattern.possibly_invalid_spec().size() > GetMaxURLChars() ||
     99       script_url.possibly_invalid_spec().size() > GetMaxURLChars()) {
    100     scoped_ptr<WebServiceWorkerRegistrationCallbacks>
    101         owned_callbacks(callbacks);
    102     scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
    103         WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
    104     callbacks->onError(error.release());
    105     return;
    106   }
    107 
    108   int request_id = pending_registration_callbacks_.Add(callbacks);
    109   TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
    110                            "ServiceWorkerDispatcher::RegisterServiceWorker",
    111                            request_id,
    112                            "Scope", pattern.spec(),
    113                            "Script URL", script_url.spec());
    114   thread_safe_sender_->Send(new ServiceWorkerHostMsg_RegisterServiceWorker(
    115       CurrentWorkerId(), request_id, provider_id, pattern, script_url));
    116 }
    117 
    118 void ServiceWorkerDispatcher::UnregisterServiceWorker(
    119     int provider_id,
    120     const GURL& pattern,
    121     WebServiceWorkerUnregistrationCallbacks* callbacks) {
    122   DCHECK(callbacks);
    123 
    124   if (pattern.possibly_invalid_spec().size() > GetMaxURLChars()) {
    125     scoped_ptr<WebServiceWorkerUnregistrationCallbacks>
    126         owned_callbacks(callbacks);
    127     scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
    128         WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
    129     callbacks->onError(error.release());
    130     return;
    131   }
    132 
    133   int request_id = pending_unregistration_callbacks_.Add(callbacks);
    134   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
    135                            "ServiceWorkerDispatcher::UnregisterServiceWorker",
    136                            request_id,
    137                            "Scope", pattern.spec());
    138   thread_safe_sender_->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker(
    139       CurrentWorkerId(), request_id, provider_id, pattern));
    140 }
    141 
    142 void ServiceWorkerDispatcher::GetRegistration(
    143     int provider_id,
    144     const GURL& document_url,
    145     WebServiceWorkerRegistrationCallbacks* callbacks) {
    146   DCHECK(callbacks);
    147 
    148   if (document_url.possibly_invalid_spec().size() > GetMaxURLChars()) {
    149     scoped_ptr<WebServiceWorkerRegistrationCallbacks>
    150         owned_callbacks(callbacks);
    151     scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError(
    152         WebServiceWorkerError::ErrorTypeSecurity, "URL too long"));
    153     callbacks->onError(error.release());
    154     return;
    155   }
    156 
    157   int request_id = pending_get_registration_callbacks_.Add(callbacks);
    158   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
    159                            "ServiceWorkerDispatcher::GetRegistration",
    160                            request_id,
    161                            "Document URL", document_url.spec());
    162   thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistration(
    163       CurrentWorkerId(), request_id, provider_id, document_url));
    164 }
    165 
    166 void ServiceWorkerDispatcher::AddProviderContext(
    167     ServiceWorkerProviderContext* provider_context) {
    168   DCHECK(provider_context);
    169   int provider_id = provider_context->provider_id();
    170   DCHECK(!ContainsKey(provider_contexts_, provider_id));
    171   provider_contexts_[provider_id] = provider_context;
    172 }
    173 
    174 void ServiceWorkerDispatcher::RemoveProviderContext(
    175     ServiceWorkerProviderContext* provider_context) {
    176   DCHECK(provider_context);
    177   DCHECK(ContainsKey(provider_contexts_, provider_context->provider_id()));
    178   provider_contexts_.erase(provider_context->provider_id());
    179   worker_to_provider_.erase(provider_context->installing_handle_id());
    180   worker_to_provider_.erase(provider_context->waiting_handle_id());
    181   worker_to_provider_.erase(provider_context->active_handle_id());
    182   worker_to_provider_.erase(provider_context->controller_handle_id());
    183 }
    184 
    185 void ServiceWorkerDispatcher::AddScriptClient(
    186     int provider_id,
    187     blink::WebServiceWorkerProviderClient* client) {
    188   DCHECK(client);
    189   DCHECK(!ContainsKey(script_clients_, provider_id));
    190   script_clients_[provider_id] = client;
    191 }
    192 
    193 void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id) {
    194   // This could be possibly called multiple times to ensure termination.
    195   if (ContainsKey(script_clients_, provider_id))
    196     script_clients_.erase(provider_id);
    197 }
    198 
    199 ServiceWorkerDispatcher*
    200 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
    201     ThreadSafeSender* thread_safe_sender) {
    202   if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
    203     NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher.";
    204     g_dispatcher_tls.Pointer()->Set(NULL);
    205   }
    206   if (g_dispatcher_tls.Pointer()->Get())
    207     return g_dispatcher_tls.Pointer()->Get();
    208 
    209   ServiceWorkerDispatcher* dispatcher =
    210       new ServiceWorkerDispatcher(thread_safe_sender);
    211   if (WorkerTaskRunner::Instance()->CurrentWorkerId())
    212     WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
    213   return dispatcher;
    214 }
    215 
    216 ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetThreadSpecificInstance() {
    217   if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted)
    218     return NULL;
    219   return g_dispatcher_tls.Pointer()->Get();
    220 }
    221 
    222 void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() {
    223   delete this;
    224 }
    225 
    226 WebServiceWorkerImpl* ServiceWorkerDispatcher::GetServiceWorker(
    227     const ServiceWorkerObjectInfo& info,
    228     bool adopt_handle) {
    229   if (info.handle_id == kInvalidServiceWorkerHandleId)
    230     return NULL;
    231 
    232   WorkerObjectMap::iterator existing_worker =
    233       service_workers_.find(info.handle_id);
    234 
    235   if (existing_worker != service_workers_.end()) {
    236     if (adopt_handle) {
    237       // We are instructed to adopt a handle but we already have one, so
    238       // adopt and destroy a handle ref.
    239       ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
    240     }
    241     return existing_worker->second;
    242   }
    243 
    244   scoped_ptr<ServiceWorkerHandleReference> handle_ref =
    245       adopt_handle
    246           ? ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get())
    247           : ServiceWorkerHandleReference::Create(info,
    248                                                  thread_safe_sender_.get());
    249   // WebServiceWorkerImpl constructor calls AddServiceWorker.
    250   return new WebServiceWorkerImpl(handle_ref.Pass(), thread_safe_sender_.get());
    251 }
    252 
    253 WebServiceWorkerRegistrationImpl*
    254 ServiceWorkerDispatcher::FindServiceWorkerRegistration(
    255     const ServiceWorkerRegistrationObjectInfo& info,
    256     bool adopt_handle) {
    257   RegistrationObjectMap::iterator registration =
    258       registrations_.find(info.handle_id);
    259   if (registration == registrations_.end())
    260     return NULL;
    261   if (adopt_handle) {
    262     // We are instructed to adopt a handle but we already have one, so
    263     // adopt and destroy a handle ref.
    264     ServiceWorkerRegistrationHandleReference::Adopt(
    265         info, thread_safe_sender_.get());
    266   }
    267   return registration->second;
    268 }
    269 
    270 WebServiceWorkerRegistrationImpl*
    271 ServiceWorkerDispatcher::CreateServiceWorkerRegistration(
    272     const ServiceWorkerRegistrationObjectInfo& info,
    273     bool adopt_handle) {
    274   DCHECK(!FindServiceWorkerRegistration(info, adopt_handle));
    275   if (info.handle_id == kInvalidServiceWorkerRegistrationHandleId)
    276     return NULL;
    277 
    278   scoped_ptr<ServiceWorkerRegistrationHandleReference> handle_ref =
    279       adopt_handle ? ServiceWorkerRegistrationHandleReference::Adopt(
    280                          info, thread_safe_sender_.get())
    281                    : ServiceWorkerRegistrationHandleReference::Create(
    282                          info, thread_safe_sender_.get());
    283 
    284   // WebServiceWorkerRegistrationImpl constructor calls
    285   // AddServiceWorkerRegistration.
    286   return new WebServiceWorkerRegistrationImpl(handle_ref.Pass());
    287 }
    288 
    289 void ServiceWorkerDispatcher::OnAssociateRegistration(
    290     int thread_id,
    291     int provider_id,
    292     const ServiceWorkerRegistrationObjectInfo& info,
    293     const ServiceWorkerVersionAttributes& attrs) {
    294   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    295   if (provider == provider_contexts_.end())
    296     return;
    297   provider->second->OnAssociateRegistration(info, attrs);
    298   if (attrs.installing.handle_id != kInvalidServiceWorkerHandleId)
    299     worker_to_provider_[attrs.installing.handle_id] = provider->second;
    300   if (attrs.waiting.handle_id != kInvalidServiceWorkerHandleId)
    301     worker_to_provider_[attrs.waiting.handle_id] = provider->second;
    302   if (attrs.active.handle_id != kInvalidServiceWorkerHandleId)
    303     worker_to_provider_[attrs.active.handle_id] = provider->second;
    304 }
    305 
    306 void ServiceWorkerDispatcher::OnDisassociateRegistration(
    307     int thread_id,
    308     int provider_id) {
    309   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    310   if (provider == provider_contexts_.end())
    311     return;
    312   provider->second->OnDisassociateRegistration();
    313   worker_to_provider_.erase(provider->second->installing_handle_id());
    314   worker_to_provider_.erase(provider->second->waiting_handle_id());
    315   worker_to_provider_.erase(provider->second->active_handle_id());
    316   worker_to_provider_.erase(provider->second->controller_handle_id());
    317 }
    318 
    319 void ServiceWorkerDispatcher::OnRegistered(
    320     int thread_id,
    321     int request_id,
    322     const ServiceWorkerRegistrationObjectInfo& info,
    323     const ServiceWorkerVersionAttributes& attrs) {
    324   TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
    325                                "ServiceWorkerDispatcher::RegisterServiceWorker",
    326                                request_id,
    327                                "OnRegistered");
    328   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    329                          "ServiceWorkerDispatcher::RegisterServiceWorker",
    330                          request_id);
    331   WebServiceWorkerRegistrationCallbacks* callbacks =
    332       pending_registration_callbacks_.Lookup(request_id);
    333   DCHECK(callbacks);
    334   if (!callbacks)
    335     return;
    336 
    337   callbacks->onSuccess(FindOrCreateRegistration(info, attrs));
    338   pending_registration_callbacks_.Remove(request_id);
    339 }
    340 
    341 void ServiceWorkerDispatcher::OnUnregistered(int thread_id,
    342                                              int request_id,
    343                                              bool is_success) {
    344   TRACE_EVENT_ASYNC_STEP_INTO0(
    345       "ServiceWorker",
    346       "ServiceWorkerDispatcher::UnregisterServiceWorker",
    347       request_id,
    348       "OnUnregistered");
    349   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    350                          "ServiceWorkerDispatcher::UnregisterServiceWorker",
    351                          request_id);
    352   WebServiceWorkerUnregistrationCallbacks* callbacks =
    353       pending_unregistration_callbacks_.Lookup(request_id);
    354   DCHECK(callbacks);
    355   if (!callbacks)
    356     return;
    357   callbacks->onSuccess(&is_success);
    358   pending_unregistration_callbacks_.Remove(request_id);
    359 }
    360 
    361 void ServiceWorkerDispatcher::OnDidGetRegistration(
    362     int thread_id,
    363     int request_id,
    364     const ServiceWorkerRegistrationObjectInfo& info,
    365     const ServiceWorkerVersionAttributes& attrs) {
    366   TRACE_EVENT_ASYNC_STEP_INTO0(
    367       "ServiceWorker",
    368       "ServiceWorkerDispatcher::GetRegistration",
    369       request_id,
    370       "OnDidGetRegistration");
    371   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    372                          "ServiceWorkerDispatcher::GetRegistration",
    373                          request_id);
    374   WebServiceWorkerRegistrationCallbacks* callbacks =
    375       pending_get_registration_callbacks_.Lookup(request_id);
    376   DCHECK(callbacks);
    377   if (!callbacks)
    378     return;
    379 
    380   WebServiceWorkerRegistrationImpl* registration = NULL;
    381   if (info.handle_id != kInvalidServiceWorkerHandleId)
    382     registration = FindOrCreateRegistration(info, attrs);
    383 
    384   callbacks->onSuccess(registration);
    385   pending_get_registration_callbacks_.Remove(request_id);
    386 }
    387 
    388 void ServiceWorkerDispatcher::OnRegistrationError(
    389     int thread_id,
    390     int request_id,
    391     WebServiceWorkerError::ErrorType error_type,
    392     const base::string16& message) {
    393   TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
    394                                "ServiceWorkerDispatcher::RegisterServiceWorker",
    395                                request_id,
    396                                "OnRegistrationError");
    397   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    398                          "ServiceWorkerDispatcher::RegisterServiceWorker",
    399                          request_id);
    400   WebServiceWorkerRegistrationCallbacks* callbacks =
    401       pending_registration_callbacks_.Lookup(request_id);
    402   DCHECK(callbacks);
    403   if (!callbacks)
    404     return;
    405 
    406   scoped_ptr<WebServiceWorkerError> error(
    407       new WebServiceWorkerError(error_type, message));
    408   callbacks->onError(error.release());
    409   pending_registration_callbacks_.Remove(request_id);
    410 }
    411 
    412 void ServiceWorkerDispatcher::OnUnregistrationError(
    413     int thread_id,
    414     int request_id,
    415     WebServiceWorkerError::ErrorType error_type,
    416     const base::string16& message) {
    417   TRACE_EVENT_ASYNC_STEP_INTO0(
    418       "ServiceWorker",
    419       "ServiceWorkerDispatcher::UnregisterServiceWorker",
    420       request_id,
    421       "OnUnregistrationError");
    422   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    423                          "ServiceWorkerDispatcher::UnregisterServiceWorker",
    424                          request_id);
    425   WebServiceWorkerUnregistrationCallbacks* callbacks =
    426       pending_unregistration_callbacks_.Lookup(request_id);
    427   DCHECK(callbacks);
    428   if (!callbacks)
    429     return;
    430 
    431   scoped_ptr<WebServiceWorkerError> error(
    432       new WebServiceWorkerError(error_type, message));
    433   callbacks->onError(error.release());
    434   pending_unregistration_callbacks_.Remove(request_id);
    435 }
    436 
    437 void ServiceWorkerDispatcher::OnGetRegistrationError(
    438     int thread_id,
    439     int request_id,
    440     WebServiceWorkerError::ErrorType error_type,
    441     const base::string16& message) {
    442   TRACE_EVENT_ASYNC_STEP_INTO0(
    443       "ServiceWorker",
    444       "ServiceWorkerDispatcher::GetRegistration",
    445       request_id,
    446       "OnGetRegistrationError");
    447   TRACE_EVENT_ASYNC_END0("ServiceWorker",
    448                          "ServiceWorkerDispatcher::GetRegistration",
    449                          request_id);
    450   WebServiceWorkerGetRegistrationCallbacks* callbacks =
    451       pending_get_registration_callbacks_.Lookup(request_id);
    452   DCHECK(callbacks);
    453   if (!callbacks)
    454     return;
    455 
    456   scoped_ptr<WebServiceWorkerError> error(
    457       new WebServiceWorkerError(error_type, message));
    458   callbacks->onError(error.release());
    459   pending_get_registration_callbacks_.Remove(request_id);
    460 }
    461 
    462 void ServiceWorkerDispatcher::OnServiceWorkerStateChanged(
    463     int thread_id,
    464     int handle_id,
    465     blink::WebServiceWorkerState state) {
    466   TRACE_EVENT2("ServiceWorker",
    467                "ServiceWorkerDispatcher::OnServiceWorkerStateChanged",
    468                "Thread ID", thread_id,
    469                "State", state);
    470   WorkerObjectMap::iterator worker = service_workers_.find(handle_id);
    471   if (worker != service_workers_.end())
    472     worker->second->OnStateChanged(state);
    473 
    474   WorkerToProviderMap::iterator provider = worker_to_provider_.find(handle_id);
    475   if (provider != worker_to_provider_.end())
    476     provider->second->OnServiceWorkerStateChanged(handle_id, state);
    477 }
    478 
    479 void ServiceWorkerDispatcher::OnSetVersionAttributes(
    480     int thread_id,
    481     int provider_id,
    482     int registration_handle_id,
    483     int changed_mask,
    484     const ServiceWorkerVersionAttributes& attributes) {
    485   TRACE_EVENT1("ServiceWorker",
    486                "ServiceWorkerDispatcher::OnSetVersionAttributes",
    487                "Thread ID", thread_id);
    488   ChangedVersionAttributesMask mask(changed_mask);
    489   if (mask.installing_changed()) {
    490     SetInstallingServiceWorker(provider_id,
    491                                registration_handle_id,
    492                                attributes.installing);
    493   }
    494   if (mask.waiting_changed()) {
    495     SetWaitingServiceWorker(provider_id,
    496                             registration_handle_id,
    497                             attributes.waiting);
    498   }
    499   if (mask.active_changed()) {
    500     SetActiveServiceWorker(provider_id,
    501                            registration_handle_id,
    502                            attributes.active);
    503     SetReadyRegistration(provider_id, registration_handle_id);
    504   }
    505 }
    506 
    507 void ServiceWorkerDispatcher::OnUpdateFound(
    508     int thread_id,
    509     const ServiceWorkerRegistrationObjectInfo& info) {
    510   TRACE_EVENT0("ServiceWorker",
    511                "ServiceWorkerDispatcher::OnUpdateFound");
    512   RegistrationObjectMap::iterator found = registrations_.find(info.handle_id);
    513   if (found != registrations_.end())
    514     found->second->OnUpdateFound();
    515 }
    516 
    517 void ServiceWorkerDispatcher::SetInstallingServiceWorker(
    518     int provider_id,
    519     int registration_handle_id,
    520     const ServiceWorkerObjectInfo& info) {
    521   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    522   if (provider != provider_contexts_.end() &&
    523       provider->second->registration_handle_id() == registration_handle_id) {
    524     int existing_installing_id = provider->second->installing_handle_id();
    525     if (existing_installing_id != info.handle_id &&
    526         existing_installing_id != kInvalidServiceWorkerHandleId) {
    527       WorkerToProviderMap::iterator associated_provider =
    528           worker_to_provider_.find(existing_installing_id);
    529       DCHECK(associated_provider != worker_to_provider_.end());
    530       DCHECK(associated_provider->second->provider_id() == provider_id);
    531       worker_to_provider_.erase(associated_provider);
    532     }
    533     provider->second->OnSetInstallingServiceWorker(
    534         registration_handle_id, info);
    535     if (info.handle_id != kInvalidServiceWorkerHandleId)
    536       worker_to_provider_[info.handle_id] = provider->second;
    537   }
    538 
    539   RegistrationObjectMap::iterator found =
    540       registrations_.find(registration_handle_id);
    541   if (found != registrations_.end()) {
    542     // Populate the .installing field with the new worker object.
    543     found->second->SetInstalling(GetServiceWorker(info, false));
    544   }
    545 }
    546 
    547 void ServiceWorkerDispatcher::SetWaitingServiceWorker(
    548     int provider_id,
    549     int registration_handle_id,
    550     const ServiceWorkerObjectInfo& info) {
    551   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    552   if (provider != provider_contexts_.end() &&
    553       provider->second->registration_handle_id() == registration_handle_id) {
    554     int existing_waiting_id = provider->second->waiting_handle_id();
    555     if (existing_waiting_id != info.handle_id &&
    556         existing_waiting_id != kInvalidServiceWorkerHandleId) {
    557       WorkerToProviderMap::iterator associated_provider =
    558           worker_to_provider_.find(existing_waiting_id);
    559       DCHECK(associated_provider != worker_to_provider_.end());
    560       DCHECK(associated_provider->second->provider_id() == provider_id);
    561       worker_to_provider_.erase(associated_provider);
    562     }
    563     provider->second->OnSetWaitingServiceWorker(registration_handle_id, info);
    564     if (info.handle_id != kInvalidServiceWorkerHandleId)
    565       worker_to_provider_[info.handle_id] = provider->second;
    566   }
    567 
    568   RegistrationObjectMap::iterator found =
    569       registrations_.find(registration_handle_id);
    570   if (found != registrations_.end()) {
    571     // Populate the .waiting field with the new worker object.
    572     found->second->SetWaiting(GetServiceWorker(info, false));
    573   }
    574 }
    575 
    576 void ServiceWorkerDispatcher::SetActiveServiceWorker(
    577     int provider_id,
    578     int registration_handle_id,
    579     const ServiceWorkerObjectInfo& info) {
    580   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    581   if (provider != provider_contexts_.end() &&
    582       provider->second->registration_handle_id() == registration_handle_id) {
    583     int existing_active_id = provider->second->active_handle_id();
    584     if (existing_active_id != info.handle_id &&
    585         existing_active_id != kInvalidServiceWorkerHandleId) {
    586       WorkerToProviderMap::iterator associated_provider =
    587           worker_to_provider_.find(existing_active_id);
    588       DCHECK(associated_provider != worker_to_provider_.end());
    589       DCHECK(associated_provider->second->provider_id() == provider_id);
    590       worker_to_provider_.erase(associated_provider);
    591     }
    592     provider->second->OnSetActiveServiceWorker(registration_handle_id, info);
    593     if (info.handle_id != kInvalidServiceWorkerHandleId)
    594       worker_to_provider_[info.handle_id] = provider->second;
    595   }
    596 
    597   RegistrationObjectMap::iterator found =
    598       registrations_.find(registration_handle_id);
    599   if (found != registrations_.end()) {
    600     // Populate the .active field with the new worker object.
    601     found->second->SetActive(GetServiceWorker(info, false));
    602   }
    603 }
    604 
    605 void ServiceWorkerDispatcher::SetReadyRegistration(
    606     int provider_id,
    607     int registration_handle_id) {
    608   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    609   if (provider == provider_contexts_.end() ||
    610       provider->second->registration_handle_id() != registration_handle_id ||
    611       provider->second->active_handle_id() == kInvalidServiceWorkerHandleId) {
    612     return;
    613   }
    614 
    615   ScriptClientMap::iterator client = script_clients_.find(provider_id);
    616   if (client == script_clients_.end())
    617     return;
    618 
    619   ServiceWorkerRegistrationObjectInfo info =
    620       provider->second->registration()->info();
    621   WebServiceWorkerRegistrationImpl* registration =
    622       FindServiceWorkerRegistration(info, false);
    623   if (!registration) {
    624     registration = CreateServiceWorkerRegistration(info, false);
    625     ServiceWorkerVersionAttributes attrs =
    626         provider->second->GetVersionAttributes();
    627     registration->SetInstalling(GetServiceWorker(attrs.installing, false));
    628     registration->SetWaiting(GetServiceWorker(attrs.waiting, false));
    629     registration->SetActive(GetServiceWorker(attrs.active, false));
    630   }
    631 
    632   // Resolve the .ready promise with the registration object.
    633   client->second->setReadyRegistration(registration);
    634 }
    635 
    636 void ServiceWorkerDispatcher::OnSetControllerServiceWorker(
    637     int thread_id,
    638     int provider_id,
    639     const ServiceWorkerObjectInfo& info) {
    640   TRACE_EVENT2("ServiceWorker",
    641                "ServiceWorkerDispatcher::OnSetControllerServiceWorker",
    642                "Thread ID", thread_id,
    643                "Provider ID", provider_id);
    644   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
    645   if (provider != provider_contexts_.end()) {
    646     provider->second->OnSetControllerServiceWorker(
    647         provider->second->registration_handle_id(), info);
    648     worker_to_provider_[info.handle_id] = provider->second;
    649   }
    650 
    651   ScriptClientMap::iterator found = script_clients_.find(provider_id);
    652   if (found != script_clients_.end()) {
    653     // Populate the .controller field with the new worker object.
    654     found->second->setController(GetServiceWorker(info, false));
    655   }
    656 }
    657 
    658 void ServiceWorkerDispatcher::OnPostMessage(
    659     int thread_id,
    660     int provider_id,
    661     const base::string16& message,
    662     const std::vector<int>& sent_message_port_ids,
    663     const std::vector<int>& new_routing_ids) {
    664   // Make sure we're on the main document thread. (That must be the only
    665   // thread we get this message)
    666   DCHECK(ChildThread::current());
    667   TRACE_EVENT1("ServiceWorker",
    668                "ServiceWorkerDispatcher::OnPostMessage",
    669                "Thread ID", thread_id);
    670 
    671   ScriptClientMap::iterator found = script_clients_.find(provider_id);
    672   if (found == script_clients_.end()) {
    673     // For now we do no queueing for messages sent to nonexistent / unattached
    674     // client.
    675     return;
    676   }
    677 
    678   std::vector<WebMessagePortChannelImpl*> ports;
    679   if (!sent_message_port_ids.empty()) {
    680     ports.resize(sent_message_port_ids.size());
    681     for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
    682       ports[i] = new WebMessagePortChannelImpl(
    683           new_routing_ids[i], sent_message_port_ids[i],
    684           base::MessageLoopProxy::current());
    685     }
    686   }
    687 
    688   found->second->dispatchMessageEvent(message, ports);
    689 }
    690 
    691 void ServiceWorkerDispatcher::AddServiceWorker(
    692     int handle_id, WebServiceWorkerImpl* worker) {
    693   DCHECK(!ContainsKey(service_workers_, handle_id));
    694   service_workers_[handle_id] = worker;
    695 }
    696 
    697 void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id) {
    698   DCHECK(ContainsKey(service_workers_, handle_id));
    699   service_workers_.erase(handle_id);
    700 }
    701 
    702 void ServiceWorkerDispatcher::AddServiceWorkerRegistration(
    703     int registration_handle_id,
    704     WebServiceWorkerRegistrationImpl* registration) {
    705   DCHECK(!ContainsKey(registrations_, registration_handle_id));
    706   registrations_[registration_handle_id] = registration;
    707 }
    708 
    709 void ServiceWorkerDispatcher::RemoveServiceWorkerRegistration(
    710     int registration_handle_id) {
    711   DCHECK(ContainsKey(registrations_, registration_handle_id));
    712   registrations_.erase(registration_handle_id);
    713 }
    714 
    715 WebServiceWorkerRegistrationImpl*
    716 ServiceWorkerDispatcher::FindOrCreateRegistration(
    717     const ServiceWorkerRegistrationObjectInfo& info,
    718     const ServiceWorkerVersionAttributes& attrs) {
    719   WebServiceWorkerRegistrationImpl* registration =
    720       FindServiceWorkerRegistration(info, true);
    721   if (!registration) {
    722     registration = CreateServiceWorkerRegistration(info, true);
    723     registration->SetInstalling(GetServiceWorker(attrs.installing, true));
    724     registration->SetWaiting(GetServiceWorker(attrs.waiting, true));
    725     registration->SetActive(GetServiceWorker(attrs.active, true));
    726   } else {
    727     // |registration| must already have version attributes, so adopt and destroy
    728     // handle refs for them.
    729     ServiceWorkerHandleReference::Adopt(
    730         attrs.installing, thread_safe_sender_.get());
    731     ServiceWorkerHandleReference::Adopt(
    732         attrs.waiting, thread_safe_sender_.get());
    733     ServiceWorkerHandleReference::Adopt(
    734         attrs.active, thread_safe_sender_.get());
    735   }
    736   return registration;
    737 }
    738 
    739 }  // namespace content
    740