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
24using blink::WebServiceWorkerError;
25using blink::WebServiceWorkerProvider;
26using base::ThreadLocalPointer;
27
28namespace content {
29
30namespace {
31
32base::LazyInstance<ThreadLocalPointer<ServiceWorkerDispatcher> >::Leaky
33    g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
34
35ServiceWorkerDispatcher* const kHasBeenDeleted =
36    reinterpret_cast<ServiceWorkerDispatcher*>(0x1);
37
38int CurrentWorkerId() {
39  return WorkerTaskRunner::Instance()->CurrentWorkerId();
40}
41
42}  // namespace
43
44ServiceWorkerDispatcher::ServiceWorkerDispatcher(
45    ThreadSafeSender* thread_safe_sender)
46    : thread_safe_sender_(thread_safe_sender) {
47  g_dispatcher_tls.Pointer()->Set(this);
48}
49
50ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
51  g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
52}
53
54void 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
87bool ServiceWorkerDispatcher::Send(IPC::Message* msg) {
88  return thread_safe_sender_->Send(msg);
89}
90
91void 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
118void 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
142void 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
166void 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
174void 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
185void 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
193void 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
199ServiceWorkerDispatcher*
200ServiceWorkerDispatcher::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
216ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetThreadSpecificInstance() {
217  if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted)
218    return NULL;
219  return g_dispatcher_tls.Pointer()->Get();
220}
221
222void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() {
223  delete this;
224}
225
226WebServiceWorkerImpl* 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
253WebServiceWorkerRegistrationImpl*
254ServiceWorkerDispatcher::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
270WebServiceWorkerRegistrationImpl*
271ServiceWorkerDispatcher::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
289void 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
306void 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
319void 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
341void 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
361void 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
388void 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
412void 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
437void 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
462void 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
479void 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
507void 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
517void 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
547void 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
576void 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
605void 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
636void 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
658void 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
691void ServiceWorkerDispatcher::AddServiceWorker(
692    int handle_id, WebServiceWorkerImpl* worker) {
693  DCHECK(!ContainsKey(service_workers_, handle_id));
694  service_workers_[handle_id] = worker;
695}
696
697void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id) {
698  DCHECK(ContainsKey(service_workers_, handle_id));
699  service_workers_.erase(handle_id);
700}
701
702void 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
709void ServiceWorkerDispatcher::RemoveServiceWorkerRegistration(
710    int registration_handle_id) {
711  DCHECK(ContainsKey(registrations_, registration_handle_id));
712  registrations_.erase(registration_handle_id);
713}
714
715WebServiceWorkerRegistrationImpl*
716ServiceWorkerDispatcher::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