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.
5 #include "content/child/service_worker/service_worker_dispatcher.h"
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/WebServiceWorkerClientsInfo.h"
22 #include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
23 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
25 using blink::WebServiceWorkerError
;
26 using blink::WebServiceWorkerProvider
;
27 using base::ThreadLocalPointer
;
33 base::LazyInstance
<ThreadLocalPointer
<ServiceWorkerDispatcher
> >::Leaky
34 g_dispatcher_tls
= LAZY_INSTANCE_INITIALIZER
;
36 ServiceWorkerDispatcher
* const kHasBeenDeleted
=
37 reinterpret_cast<ServiceWorkerDispatcher
*>(0x1);
39 int CurrentWorkerId() {
40 return WorkerTaskRunner::Instance()->CurrentWorkerId();
45 ServiceWorkerDispatcher::ServiceWorkerDispatcher(
46 ThreadSafeSender
* thread_safe_sender
)
47 : thread_safe_sender_(thread_safe_sender
) {
48 g_dispatcher_tls
.Pointer()->Set(this);
51 ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
52 g_dispatcher_tls
.Pointer()->Set(kHasBeenDeleted
);
55 void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message
& msg
) {
57 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher
, msg
)
58 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration
,
59 OnAssociateRegistration
)
60 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DisassociateRegistration
,
61 OnDisassociateRegistration
)
62 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered
, OnRegistered
)
63 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistered
,
65 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration
,
67 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError
,
69 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistrationError
,
70 OnUnregistrationError
)
71 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationError
,
72 OnGetRegistrationError
)
73 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged
,
74 OnServiceWorkerStateChanged
)
75 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes
,
76 OnSetVersionAttributes
)
77 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_UpdateFound
,
79 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetControllerServiceWorker
,
80 OnSetControllerServiceWorker
)
81 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument
,
83 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_GetClientInfo
,
85 IPC_MESSAGE_UNHANDLED(handled
= false)
87 DCHECK(handled
) << "Unhandled message:" << msg
.type();
90 bool ServiceWorkerDispatcher::Send(IPC::Message
* msg
) {
91 return thread_safe_sender_
->Send(msg
);
94 void ServiceWorkerDispatcher::RegisterServiceWorker(
97 const GURL
& script_url
,
98 WebServiceWorkerRegistrationCallbacks
* callbacks
) {
101 if (pattern
.possibly_invalid_spec().size() > GetMaxURLChars() ||
102 script_url
.possibly_invalid_spec().size() > GetMaxURLChars()) {
103 scoped_ptr
<WebServiceWorkerRegistrationCallbacks
>
104 owned_callbacks(callbacks
);
105 scoped_ptr
<WebServiceWorkerError
> error(new WebServiceWorkerError(
106 WebServiceWorkerError::ErrorTypeSecurity
, "URL too long"));
107 callbacks
->onError(error
.release());
111 int request_id
= pending_registration_callbacks_
.Add(callbacks
);
112 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
113 "ServiceWorkerDispatcher::RegisterServiceWorker",
115 "Scope", pattern
.spec(),
116 "Script URL", script_url
.spec());
117 thread_safe_sender_
->Send(new ServiceWorkerHostMsg_RegisterServiceWorker(
118 CurrentWorkerId(), request_id
, provider_id
, pattern
, script_url
));
121 void ServiceWorkerDispatcher::UnregisterServiceWorker(
124 WebServiceWorkerUnregistrationCallbacks
* callbacks
) {
127 if (pattern
.possibly_invalid_spec().size() > GetMaxURLChars()) {
128 scoped_ptr
<WebServiceWorkerUnregistrationCallbacks
>
129 owned_callbacks(callbacks
);
130 scoped_ptr
<WebServiceWorkerError
> error(new WebServiceWorkerError(
131 WebServiceWorkerError::ErrorTypeSecurity
, "URL too long"));
132 callbacks
->onError(error
.release());
136 int request_id
= pending_unregistration_callbacks_
.Add(callbacks
);
137 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
138 "ServiceWorkerDispatcher::UnregisterServiceWorker",
140 "Scope", pattern
.spec());
141 thread_safe_sender_
->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker(
142 CurrentWorkerId(), request_id
, provider_id
, pattern
));
145 void ServiceWorkerDispatcher::GetRegistration(
147 const GURL
& document_url
,
148 WebServiceWorkerRegistrationCallbacks
* callbacks
) {
151 if (document_url
.possibly_invalid_spec().size() > GetMaxURLChars()) {
152 scoped_ptr
<WebServiceWorkerRegistrationCallbacks
>
153 owned_callbacks(callbacks
);
154 scoped_ptr
<WebServiceWorkerError
> error(new WebServiceWorkerError(
155 WebServiceWorkerError::ErrorTypeSecurity
, "URL too long"));
156 callbacks
->onError(error
.release());
160 int request_id
= pending_get_registration_callbacks_
.Add(callbacks
);
161 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
162 "ServiceWorkerDispatcher::GetRegistration",
164 "Document URL", document_url
.spec());
165 thread_safe_sender_
->Send(new ServiceWorkerHostMsg_GetRegistration(
166 CurrentWorkerId(), request_id
, provider_id
, document_url
));
169 void ServiceWorkerDispatcher::AddProviderContext(
170 ServiceWorkerProviderContext
* provider_context
) {
171 DCHECK(provider_context
);
172 int provider_id
= provider_context
->provider_id();
173 DCHECK(!ContainsKey(provider_contexts_
, provider_id
));
174 provider_contexts_
[provider_id
] = provider_context
;
177 void ServiceWorkerDispatcher::RemoveProviderContext(
178 ServiceWorkerProviderContext
* provider_context
) {
179 DCHECK(provider_context
);
180 DCHECK(ContainsKey(provider_contexts_
, provider_context
->provider_id()));
181 provider_contexts_
.erase(provider_context
->provider_id());
182 worker_to_provider_
.erase(provider_context
->installing_handle_id());
183 worker_to_provider_
.erase(provider_context
->waiting_handle_id());
184 worker_to_provider_
.erase(provider_context
->active_handle_id());
185 worker_to_provider_
.erase(provider_context
->controller_handle_id());
188 void ServiceWorkerDispatcher::AddScriptClient(
190 blink::WebServiceWorkerProviderClient
* client
) {
192 DCHECK(!ContainsKey(script_clients_
, provider_id
));
193 script_clients_
[provider_id
] = client
;
196 void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id
) {
197 // This could be possibly called multiple times to ensure termination.
198 if (ContainsKey(script_clients_
, provider_id
))
199 script_clients_
.erase(provider_id
);
202 ServiceWorkerDispatcher
*
203 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
204 ThreadSafeSender
* thread_safe_sender
) {
205 if (g_dispatcher_tls
.Pointer()->Get() == kHasBeenDeleted
) {
206 NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher.";
207 g_dispatcher_tls
.Pointer()->Set(NULL
);
209 if (g_dispatcher_tls
.Pointer()->Get())
210 return g_dispatcher_tls
.Pointer()->Get();
212 ServiceWorkerDispatcher
* dispatcher
=
213 new ServiceWorkerDispatcher(thread_safe_sender
);
214 if (WorkerTaskRunner::Instance()->CurrentWorkerId())
215 WorkerTaskRunner::Instance()->AddStopObserver(dispatcher
);
219 ServiceWorkerDispatcher
* ServiceWorkerDispatcher::GetThreadSpecificInstance() {
220 if (g_dispatcher_tls
.Pointer()->Get() == kHasBeenDeleted
)
222 return g_dispatcher_tls
.Pointer()->Get();
225 void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() {
229 WebServiceWorkerImpl
* ServiceWorkerDispatcher::GetServiceWorker(
230 const ServiceWorkerObjectInfo
& info
,
232 if (info
.handle_id
== kInvalidServiceWorkerHandleId
)
235 WorkerObjectMap::iterator existing_worker
=
236 service_workers_
.find(info
.handle_id
);
238 if (existing_worker
!= service_workers_
.end()) {
240 // We are instructed to adopt a handle but we already have one, so
241 // adopt and destroy a handle ref.
242 ServiceWorkerHandleReference::Adopt(info
, thread_safe_sender_
.get());
244 return existing_worker
->second
;
247 scoped_ptr
<ServiceWorkerHandleReference
> handle_ref
=
249 ? ServiceWorkerHandleReference::Adopt(info
, thread_safe_sender_
.get())
250 : ServiceWorkerHandleReference::Create(info
,
251 thread_safe_sender_
.get());
252 // WebServiceWorkerImpl constructor calls AddServiceWorker.
253 return new WebServiceWorkerImpl(handle_ref
.Pass(), thread_safe_sender_
.get());
256 WebServiceWorkerRegistrationImpl
*
257 ServiceWorkerDispatcher::FindServiceWorkerRegistration(
258 const ServiceWorkerRegistrationObjectInfo
& info
,
260 RegistrationObjectMap::iterator registration
=
261 registrations_
.find(info
.handle_id
);
262 if (registration
== registrations_
.end())
265 // We are instructed to adopt a handle but we already have one, so
266 // adopt and destroy a handle ref.
267 ServiceWorkerRegistrationHandleReference::Adopt(
268 info
, thread_safe_sender_
.get());
270 return registration
->second
;
273 WebServiceWorkerRegistrationImpl
*
274 ServiceWorkerDispatcher::CreateServiceWorkerRegistration(
275 const ServiceWorkerRegistrationObjectInfo
& info
,
277 DCHECK(!FindServiceWorkerRegistration(info
, adopt_handle
));
278 if (info
.handle_id
== kInvalidServiceWorkerRegistrationHandleId
)
281 scoped_ptr
<ServiceWorkerRegistrationHandleReference
> handle_ref
=
282 adopt_handle
? ServiceWorkerRegistrationHandleReference::Adopt(
283 info
, thread_safe_sender_
.get())
284 : ServiceWorkerRegistrationHandleReference::Create(
285 info
, thread_safe_sender_
.get());
287 // WebServiceWorkerRegistrationImpl constructor calls
288 // AddServiceWorkerRegistration.
289 return new WebServiceWorkerRegistrationImpl(handle_ref
.Pass());
292 void ServiceWorkerDispatcher::OnAssociateRegistration(
295 const ServiceWorkerRegistrationObjectInfo
& info
,
296 const ServiceWorkerVersionAttributes
& attrs
) {
297 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
298 if (provider
== provider_contexts_
.end())
300 provider
->second
->OnAssociateRegistration(info
, attrs
);
301 if (attrs
.installing
.handle_id
!= kInvalidServiceWorkerHandleId
)
302 worker_to_provider_
[attrs
.installing
.handle_id
] = provider
->second
;
303 if (attrs
.waiting
.handle_id
!= kInvalidServiceWorkerHandleId
)
304 worker_to_provider_
[attrs
.waiting
.handle_id
] = provider
->second
;
305 if (attrs
.active
.handle_id
!= kInvalidServiceWorkerHandleId
)
306 worker_to_provider_
[attrs
.active
.handle_id
] = provider
->second
;
309 void ServiceWorkerDispatcher::OnDisassociateRegistration(
312 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
313 if (provider
== provider_contexts_
.end())
315 provider
->second
->OnDisassociateRegistration();
316 worker_to_provider_
.erase(provider
->second
->installing_handle_id());
317 worker_to_provider_
.erase(provider
->second
->waiting_handle_id());
318 worker_to_provider_
.erase(provider
->second
->active_handle_id());
319 worker_to_provider_
.erase(provider
->second
->controller_handle_id());
322 void ServiceWorkerDispatcher::OnRegistered(
325 const ServiceWorkerRegistrationObjectInfo
& info
,
326 const ServiceWorkerVersionAttributes
& attrs
) {
327 TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
328 "ServiceWorkerDispatcher::RegisterServiceWorker",
331 TRACE_EVENT_ASYNC_END0("ServiceWorker",
332 "ServiceWorkerDispatcher::RegisterServiceWorker",
334 WebServiceWorkerRegistrationCallbacks
* callbacks
=
335 pending_registration_callbacks_
.Lookup(request_id
);
340 callbacks
->onSuccess(FindOrCreateRegistration(info
, attrs
));
341 pending_registration_callbacks_
.Remove(request_id
);
344 void ServiceWorkerDispatcher::OnUnregistered(int thread_id
,
347 TRACE_EVENT_ASYNC_STEP_INTO0(
349 "ServiceWorkerDispatcher::UnregisterServiceWorker",
352 TRACE_EVENT_ASYNC_END0("ServiceWorker",
353 "ServiceWorkerDispatcher::UnregisterServiceWorker",
355 WebServiceWorkerUnregistrationCallbacks
* callbacks
=
356 pending_unregistration_callbacks_
.Lookup(request_id
);
360 callbacks
->onSuccess(&is_success
);
361 pending_unregistration_callbacks_
.Remove(request_id
);
364 void ServiceWorkerDispatcher::OnDidGetRegistration(
367 const ServiceWorkerRegistrationObjectInfo
& info
,
368 const ServiceWorkerVersionAttributes
& attrs
) {
369 TRACE_EVENT_ASYNC_STEP_INTO0(
371 "ServiceWorkerDispatcher::GetRegistration",
373 "OnDidGetRegistration");
374 TRACE_EVENT_ASYNC_END0("ServiceWorker",
375 "ServiceWorkerDispatcher::GetRegistration",
377 WebServiceWorkerRegistrationCallbacks
* callbacks
=
378 pending_get_registration_callbacks_
.Lookup(request_id
);
383 WebServiceWorkerRegistrationImpl
* registration
= NULL
;
384 if (info
.handle_id
!= kInvalidServiceWorkerHandleId
)
385 registration
= FindOrCreateRegistration(info
, attrs
);
387 callbacks
->onSuccess(registration
);
388 pending_get_registration_callbacks_
.Remove(request_id
);
391 void ServiceWorkerDispatcher::OnRegistrationError(
394 WebServiceWorkerError::ErrorType error_type
,
395 const base::string16
& message
) {
396 TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
397 "ServiceWorkerDispatcher::RegisterServiceWorker",
399 "OnRegistrationError");
400 TRACE_EVENT_ASYNC_END0("ServiceWorker",
401 "ServiceWorkerDispatcher::RegisterServiceWorker",
403 WebServiceWorkerRegistrationCallbacks
* callbacks
=
404 pending_registration_callbacks_
.Lookup(request_id
);
409 scoped_ptr
<WebServiceWorkerError
> error(
410 new WebServiceWorkerError(error_type
, message
));
411 callbacks
->onError(error
.release());
412 pending_registration_callbacks_
.Remove(request_id
);
415 void ServiceWorkerDispatcher::OnUnregistrationError(
418 WebServiceWorkerError::ErrorType error_type
,
419 const base::string16
& message
) {
420 TRACE_EVENT_ASYNC_STEP_INTO0(
422 "ServiceWorkerDispatcher::UnregisterServiceWorker",
424 "OnUnregistrationError");
425 TRACE_EVENT_ASYNC_END0("ServiceWorker",
426 "ServiceWorkerDispatcher::UnregisterServiceWorker",
428 WebServiceWorkerUnregistrationCallbacks
* callbacks
=
429 pending_unregistration_callbacks_
.Lookup(request_id
);
434 scoped_ptr
<WebServiceWorkerError
> error(
435 new WebServiceWorkerError(error_type
, message
));
436 callbacks
->onError(error
.release());
437 pending_unregistration_callbacks_
.Remove(request_id
);
440 void ServiceWorkerDispatcher::OnGetRegistrationError(
443 WebServiceWorkerError::ErrorType error_type
,
444 const base::string16
& message
) {
445 TRACE_EVENT_ASYNC_STEP_INTO0(
447 "ServiceWorkerDispatcher::GetRegistration",
449 "OnGetRegistrationError");
450 TRACE_EVENT_ASYNC_END0("ServiceWorker",
451 "ServiceWorkerDispatcher::GetRegistration",
453 WebServiceWorkerGetRegistrationCallbacks
* callbacks
=
454 pending_get_registration_callbacks_
.Lookup(request_id
);
459 scoped_ptr
<WebServiceWorkerError
> error(
460 new WebServiceWorkerError(error_type
, message
));
461 callbacks
->onError(error
.release());
462 pending_get_registration_callbacks_
.Remove(request_id
);
465 void ServiceWorkerDispatcher::OnServiceWorkerStateChanged(
468 blink::WebServiceWorkerState state
) {
469 TRACE_EVENT2("ServiceWorker",
470 "ServiceWorkerDispatcher::OnServiceWorkerStateChanged",
471 "Thread ID", thread_id
,
473 WorkerObjectMap::iterator worker
= service_workers_
.find(handle_id
);
474 if (worker
!= service_workers_
.end())
475 worker
->second
->OnStateChanged(state
);
477 WorkerToProviderMap::iterator provider
= worker_to_provider_
.find(handle_id
);
478 if (provider
!= worker_to_provider_
.end())
479 provider
->second
->OnServiceWorkerStateChanged(handle_id
, state
);
482 void ServiceWorkerDispatcher::OnSetVersionAttributes(
485 int registration_handle_id
,
487 const ServiceWorkerVersionAttributes
& attributes
) {
488 TRACE_EVENT1("ServiceWorker",
489 "ServiceWorkerDispatcher::OnSetVersionAttributes",
490 "Thread ID", thread_id
);
491 ChangedVersionAttributesMask
mask(changed_mask
);
492 if (mask
.installing_changed()) {
493 SetInstallingServiceWorker(provider_id
,
494 registration_handle_id
,
495 attributes
.installing
);
497 if (mask
.waiting_changed()) {
498 SetWaitingServiceWorker(provider_id
,
499 registration_handle_id
,
502 if (mask
.active_changed()) {
503 SetActiveServiceWorker(provider_id
,
504 registration_handle_id
,
506 SetReadyRegistration(provider_id
, registration_handle_id
);
510 void ServiceWorkerDispatcher::OnUpdateFound(
512 const ServiceWorkerRegistrationObjectInfo
& info
) {
513 TRACE_EVENT0("ServiceWorker",
514 "ServiceWorkerDispatcher::OnUpdateFound");
515 RegistrationObjectMap::iterator found
= registrations_
.find(info
.handle_id
);
516 if (found
!= registrations_
.end())
517 found
->second
->OnUpdateFound();
520 void ServiceWorkerDispatcher::SetInstallingServiceWorker(
522 int registration_handle_id
,
523 const ServiceWorkerObjectInfo
& info
) {
524 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
525 if (provider
!= provider_contexts_
.end() &&
526 provider
->second
->registration_handle_id() == registration_handle_id
) {
527 int existing_installing_id
= provider
->second
->installing_handle_id();
528 if (existing_installing_id
!= info
.handle_id
&&
529 existing_installing_id
!= kInvalidServiceWorkerHandleId
) {
530 WorkerToProviderMap::iterator associated_provider
=
531 worker_to_provider_
.find(existing_installing_id
);
532 DCHECK(associated_provider
!= worker_to_provider_
.end());
533 DCHECK(associated_provider
->second
->provider_id() == provider_id
);
534 worker_to_provider_
.erase(associated_provider
);
536 provider
->second
->OnSetInstallingServiceWorker(
537 registration_handle_id
, info
);
538 if (info
.handle_id
!= kInvalidServiceWorkerHandleId
)
539 worker_to_provider_
[info
.handle_id
] = provider
->second
;
542 RegistrationObjectMap::iterator found
=
543 registrations_
.find(registration_handle_id
);
544 if (found
!= registrations_
.end()) {
545 // Populate the .installing field with the new worker object.
546 found
->second
->SetInstalling(GetServiceWorker(info
, false));
550 void ServiceWorkerDispatcher::SetWaitingServiceWorker(
552 int registration_handle_id
,
553 const ServiceWorkerObjectInfo
& info
) {
554 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
555 if (provider
!= provider_contexts_
.end() &&
556 provider
->second
->registration_handle_id() == registration_handle_id
) {
557 int existing_waiting_id
= provider
->second
->waiting_handle_id();
558 if (existing_waiting_id
!= info
.handle_id
&&
559 existing_waiting_id
!= kInvalidServiceWorkerHandleId
) {
560 WorkerToProviderMap::iterator associated_provider
=
561 worker_to_provider_
.find(existing_waiting_id
);
562 DCHECK(associated_provider
!= worker_to_provider_
.end());
563 DCHECK(associated_provider
->second
->provider_id() == provider_id
);
564 worker_to_provider_
.erase(associated_provider
);
566 provider
->second
->OnSetWaitingServiceWorker(registration_handle_id
, info
);
567 if (info
.handle_id
!= kInvalidServiceWorkerHandleId
)
568 worker_to_provider_
[info
.handle_id
] = provider
->second
;
571 RegistrationObjectMap::iterator found
=
572 registrations_
.find(registration_handle_id
);
573 if (found
!= registrations_
.end()) {
574 // Populate the .waiting field with the new worker object.
575 found
->second
->SetWaiting(GetServiceWorker(info
, false));
579 void ServiceWorkerDispatcher::SetActiveServiceWorker(
581 int registration_handle_id
,
582 const ServiceWorkerObjectInfo
& info
) {
583 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
584 if (provider
!= provider_contexts_
.end() &&
585 provider
->second
->registration_handle_id() == registration_handle_id
) {
586 int existing_active_id
= provider
->second
->active_handle_id();
587 if (existing_active_id
!= info
.handle_id
&&
588 existing_active_id
!= kInvalidServiceWorkerHandleId
) {
589 WorkerToProviderMap::iterator associated_provider
=
590 worker_to_provider_
.find(existing_active_id
);
591 DCHECK(associated_provider
!= worker_to_provider_
.end());
592 DCHECK(associated_provider
->second
->provider_id() == provider_id
);
593 worker_to_provider_
.erase(associated_provider
);
595 provider
->second
->OnSetActiveServiceWorker(registration_handle_id
, info
);
596 if (info
.handle_id
!= kInvalidServiceWorkerHandleId
)
597 worker_to_provider_
[info
.handle_id
] = provider
->second
;
600 RegistrationObjectMap::iterator found
=
601 registrations_
.find(registration_handle_id
);
602 if (found
!= registrations_
.end()) {
603 // Populate the .active field with the new worker object.
604 found
->second
->SetActive(GetServiceWorker(info
, false));
608 void ServiceWorkerDispatcher::SetReadyRegistration(
610 int registration_handle_id
) {
611 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
612 if (provider
== provider_contexts_
.end() ||
613 provider
->second
->registration_handle_id() != registration_handle_id
||
614 provider
->second
->active_handle_id() == kInvalidServiceWorkerHandleId
) {
618 ScriptClientMap::iterator client
= script_clients_
.find(provider_id
);
619 if (client
== script_clients_
.end())
622 ServiceWorkerRegistrationObjectInfo info
=
623 provider
->second
->registration()->info();
624 WebServiceWorkerRegistrationImpl
* registration
=
625 FindServiceWorkerRegistration(info
, false);
627 registration
= CreateServiceWorkerRegistration(info
, false);
628 ServiceWorkerVersionAttributes attrs
=
629 provider
->second
->GetVersionAttributes();
630 registration
->SetInstalling(GetServiceWorker(attrs
.installing
, false));
631 registration
->SetWaiting(GetServiceWorker(attrs
.waiting
, false));
632 registration
->SetActive(GetServiceWorker(attrs
.active
, false));
635 // Resolve the .ready promise with the registration object.
636 client
->second
->setReadyRegistration(registration
);
639 void ServiceWorkerDispatcher::OnSetControllerServiceWorker(
642 const ServiceWorkerObjectInfo
& info
,
643 bool should_notify_controllerchange
) {
644 TRACE_EVENT2("ServiceWorker",
645 "ServiceWorkerDispatcher::OnSetControllerServiceWorker",
646 "Thread ID", thread_id
,
647 "Provider ID", provider_id
);
648 ProviderContextMap::iterator provider
= provider_contexts_
.find(provider_id
);
649 if (provider
!= provider_contexts_
.end()) {
650 provider
->second
->OnSetControllerServiceWorker(
651 provider
->second
->registration_handle_id(), info
);
652 worker_to_provider_
[info
.handle_id
] = provider
->second
;
655 ScriptClientMap::iterator found
= script_clients_
.find(provider_id
);
656 if (found
!= script_clients_
.end()) {
657 // Populate the .controller field with the new worker object.
658 found
->second
->setController(GetServiceWorker(info
, false),
659 should_notify_controllerchange
);
663 void ServiceWorkerDispatcher::OnPostMessage(
666 const base::string16
& message
,
667 const std::vector
<int>& sent_message_port_ids
,
668 const std::vector
<int>& new_routing_ids
) {
669 // Make sure we're on the main document thread. (That must be the only
670 // thread we get this message)
671 DCHECK(ChildThread::current());
672 TRACE_EVENT1("ServiceWorker",
673 "ServiceWorkerDispatcher::OnPostMessage",
674 "Thread ID", thread_id
);
676 ScriptClientMap::iterator found
= script_clients_
.find(provider_id
);
677 if (found
== script_clients_
.end()) {
678 // For now we do no queueing for messages sent to nonexistent / unattached
683 std::vector
<WebMessagePortChannelImpl
*> ports
;
684 if (!sent_message_port_ids
.empty()) {
685 ports
.resize(sent_message_port_ids
.size());
686 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
) {
687 ports
[i
] = new WebMessagePortChannelImpl(
688 new_routing_ids
[i
], sent_message_port_ids
[i
],
689 base::MessageLoopProxy::current());
693 found
->second
->dispatchMessageEvent(message
, ports
);
696 void ServiceWorkerDispatcher::OnGetClientInfo(int thread_id
,
697 int embedded_worker_id
,
700 blink::WebServiceWorkerClientInfo info
;
701 ScriptClientMap::iterator found
= script_clients_
.find(provider_id
);
702 // TODO(ksakamoto): Could we track these values in the browser side? Except
703 // for |isFocused|, it would be pretty easy.
704 if (found
!= script_clients_
.end() && found
->second
->getClientInfo(&info
)) {
705 ServiceWorkerClientInfo result
;
706 result
.client_id
= info
.clientID
;
707 result
.visibility_state
= info
.visibilityState
.utf8();
708 result
.is_focused
= info
.isFocused
;
709 result
.url
= info
.url
;
710 result
.frame_type
= static_cast<RequestContextFrameType
>(info
.frameType
);
712 thread_safe_sender_
->Send(new ServiceWorkerHostMsg_GetClientInfoSuccess(
713 embedded_worker_id
, request_id
, result
));
715 thread_safe_sender_
->Send(new ServiceWorkerHostMsg_GetClientInfoError(
716 embedded_worker_id
, request_id
));
720 void ServiceWorkerDispatcher::AddServiceWorker(
721 int handle_id
, WebServiceWorkerImpl
* worker
) {
722 DCHECK(!ContainsKey(service_workers_
, handle_id
));
723 service_workers_
[handle_id
] = worker
;
726 void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id
) {
727 DCHECK(ContainsKey(service_workers_
, handle_id
));
728 service_workers_
.erase(handle_id
);
731 void ServiceWorkerDispatcher::AddServiceWorkerRegistration(
732 int registration_handle_id
,
733 WebServiceWorkerRegistrationImpl
* registration
) {
734 DCHECK(!ContainsKey(registrations_
, registration_handle_id
));
735 registrations_
[registration_handle_id
] = registration
;
738 void ServiceWorkerDispatcher::RemoveServiceWorkerRegistration(
739 int registration_handle_id
) {
740 DCHECK(ContainsKey(registrations_
, registration_handle_id
));
741 registrations_
.erase(registration_handle_id
);
744 WebServiceWorkerRegistrationImpl
*
745 ServiceWorkerDispatcher::FindOrCreateRegistration(
746 const ServiceWorkerRegistrationObjectInfo
& info
,
747 const ServiceWorkerVersionAttributes
& attrs
) {
748 WebServiceWorkerRegistrationImpl
* registration
=
749 FindServiceWorkerRegistration(info
, true);
751 registration
= CreateServiceWorkerRegistration(info
, true);
752 registration
->SetInstalling(GetServiceWorker(attrs
.installing
, true));
753 registration
->SetWaiting(GetServiceWorker(attrs
.waiting
, true));
754 registration
->SetActive(GetServiceWorker(attrs
.active
, true));
756 // |registration| must already have version attributes, so adopt and destroy
757 // handle refs for them.
758 ServiceWorkerHandleReference::Adopt(
759 attrs
.installing
, thread_safe_sender_
.get());
760 ServiceWorkerHandleReference::Adopt(
761 attrs
.waiting
, thread_safe_sender_
.get());
762 ServiceWorkerHandleReference::Adopt(
763 attrs
.active
, thread_safe_sender_
.get());
768 } // namespace content