Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / child / service_worker / service_worker_dispatcher.cc
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