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/browser/service_worker/service_worker_dispatcher_host.h"
7 #include "base/logging.h"
8 #include "base/profiler/scoped_tracker.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/trace_event/trace_event.h"
11 #include "content/browser/bad_message.h"
12 #include "content/browser/message_port_message_filter.h"
13 #include "content/browser/message_port_service.h"
14 #include "content/browser/service_worker/embedded_worker_registry.h"
15 #include "content/browser/service_worker/service_worker_context_core.h"
16 #include "content/browser/service_worker/service_worker_context_wrapper.h"
17 #include "content/browser/service_worker/service_worker_handle.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_registration_handle.h"
20 #include "content/browser/service_worker/service_worker_utils.h"
21 #include "content/common/service_worker/embedded_worker_messages.h"
22 #include "content/common/service_worker/service_worker_messages.h"
23 #include "content/common/service_worker/service_worker_types.h"
24 #include "content/public/browser/content_browser_client.h"
25 #include "content/public/common/content_client.h"
26 #include "content/public/common/origin_util.h"
27 #include "ipc/ipc_message_macros.h"
28 #include "net/base/net_util.h"
29 #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
32 using blink::WebServiceWorkerError
;
38 const char kNoDocumentURLErrorMessage
[] =
39 "No URL is associated with the caller's document.";
40 const char kShutdownErrorMessage
[] =
41 "The Service Worker system has shutdown.";
42 const char kUserDeniedPermissionMessage
[] =
43 "The user denied permission to use Service Worker.";
45 const uint32 kFilteredMessageClasses
[] = {
46 ServiceWorkerMsgStart
,
47 EmbeddedWorkerMsgStart
,
50 bool AllOriginsMatch(const GURL
& url_a
, const GURL
& url_b
, const GURL
& url_c
) {
51 return url_a
.GetOrigin() == url_b
.GetOrigin() &&
52 url_a
.GetOrigin() == url_c
.GetOrigin();
55 bool CanRegisterServiceWorker(const GURL
& document_url
,
57 const GURL
& script_url
) {
58 DCHECK(document_url
.is_valid());
59 DCHECK(pattern
.is_valid());
60 DCHECK(script_url
.is_valid());
61 return AllOriginsMatch(document_url
, pattern
, script_url
) &&
62 OriginCanAccessServiceWorkers(document_url
) &&
63 OriginCanAccessServiceWorkers(pattern
) &&
64 OriginCanAccessServiceWorkers(script_url
);
67 bool CanUnregisterServiceWorker(const GURL
& document_url
,
68 const GURL
& pattern
) {
69 DCHECK(document_url
.is_valid());
70 DCHECK(pattern
.is_valid());
71 return document_url
.GetOrigin() == pattern
.GetOrigin() &&
72 OriginCanAccessServiceWorkers(document_url
) &&
73 OriginCanAccessServiceWorkers(pattern
);
76 bool CanUpdateServiceWorker(const GURL
& document_url
, const GURL
& pattern
) {
77 DCHECK(document_url
.is_valid());
78 DCHECK(pattern
.is_valid());
79 DCHECK(OriginCanAccessServiceWorkers(document_url
));
80 DCHECK(OriginCanAccessServiceWorkers(pattern
));
81 return document_url
.GetOrigin() == pattern
.GetOrigin();
84 bool CanGetRegistration(const GURL
& document_url
,
85 const GURL
& given_document_url
) {
86 DCHECK(document_url
.is_valid());
87 DCHECK(given_document_url
.is_valid());
88 return document_url
.GetOrigin() == given_document_url
.GetOrigin() &&
89 OriginCanAccessServiceWorkers(document_url
) &&
90 OriginCanAccessServiceWorkers(given_document_url
);
95 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
96 int render_process_id
,
97 MessagePortMessageFilter
* message_port_message_filter
,
98 ResourceContext
* resource_context
)
99 : BrowserMessageFilter(kFilteredMessageClasses
,
100 arraysize(kFilteredMessageClasses
)),
101 render_process_id_(render_process_id
),
102 message_port_message_filter_(message_port_message_filter
),
103 resource_context_(resource_context
),
104 channel_ready_(false) {
107 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
109 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_
);
110 GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
115 void ServiceWorkerDispatcherHost::Init(
116 ServiceWorkerContextWrapper
* context_wrapper
) {
117 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
118 BrowserThread::PostTask(
119 BrowserThread::IO
, FROM_HERE
,
120 base::Bind(&ServiceWorkerDispatcherHost::Init
,
121 this, make_scoped_refptr(context_wrapper
)));
125 context_wrapper_
= context_wrapper
;
128 GetContext()->embedded_worker_registry()->AddChildProcessSender(
129 render_process_id_
, this, message_port_message_filter_
);
132 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender
* sender
) {
133 TRACE_EVENT0("ServiceWorker",
134 "ServiceWorkerDispatcherHost::OnFilterAdded");
135 channel_ready_
= true;
136 std::vector
<IPC::Message
*> messages
;
137 pending_messages_
.release(&messages
);
138 for (size_t i
= 0; i
< messages
.size(); ++i
) {
139 BrowserMessageFilter::Send(messages
[i
]);
143 void ServiceWorkerDispatcherHost::OnFilterRemoved() {
144 // Don't wait until the destructor to teardown since a new dispatcher host
145 // for this process might be created before then.
147 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_
);
148 GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
151 context_wrapper_
= nullptr;
152 channel_ready_
= false;
155 void ServiceWorkerDispatcherHost::OnDestruct() const {
156 BrowserThread::DeleteOnIOThread::Destruct(this);
159 bool ServiceWorkerDispatcherHost::OnMessageReceived(
160 const IPC::Message
& message
) {
162 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost
, message
)
163 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker
,
164 OnRegisterServiceWorker
)
165 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UpdateServiceWorker
,
166 OnUpdateServiceWorker
)
167 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker
,
168 OnUnregisterServiceWorker
)
169 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration
,
171 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrations
,
173 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrationForReady
,
174 OnGetRegistrationForReady
)
175 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated
,
177 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed
,
179 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId
,
180 OnSetHostedVersionId
)
181 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker
,
182 OnPostMessageToWorker
)
183 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection
,
184 OnWorkerReadyForInspection
)
185 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded
,
186 OnWorkerScriptLoaded
)
187 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed
,
188 OnWorkerScriptLoadFailed
)
189 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptEvaluated
,
190 OnWorkerScriptEvaluated
)
191 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted
,
193 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped
,
195 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException
,
197 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage
,
198 OnReportConsoleMessage
)
199 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount
,
200 OnIncrementServiceWorkerRefCount
)
201 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount
,
202 OnDecrementServiceWorkerRefCount
)
203 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount
,
204 OnIncrementRegistrationRefCount
)
205 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount
,
206 OnDecrementRegistrationRefCount
)
207 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_TerminateWorker
, OnTerminateWorker
)
208 IPC_MESSAGE_UNHANDLED(handled
= false)
209 IPC_END_MESSAGE_MAP()
211 if (!handled
&& GetContext()) {
212 handled
= GetContext()->embedded_worker_registry()->OnMessageReceived(
213 message
, render_process_id_
);
215 bad_message::ReceivedBadMessage(this, bad_message::SWDH_NOT_HANDLED
);
221 bool ServiceWorkerDispatcherHost::Send(IPC::Message
* message
) {
222 if (channel_ready_
) {
223 BrowserMessageFilter::Send(message
);
224 // Don't bother passing through Send()'s result: it's not reliable.
228 pending_messages_
.push_back(message
);
232 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
233 scoped_ptr
<ServiceWorkerHandle
> handle
) {
234 int handle_id
= handle
->handle_id();
235 handles_
.AddWithID(handle
.release(), handle_id
);
238 void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
239 scoped_ptr
<ServiceWorkerRegistrationHandle
> handle
) {
240 int handle_id
= handle
->handle_id();
241 registration_handles_
.AddWithID(handle
.release(), handle_id
);
244 ServiceWorkerHandle
* ServiceWorkerDispatcherHost::FindServiceWorkerHandle(
247 for (IDMap
<ServiceWorkerHandle
, IDMapOwnPointer
>::iterator
iter(&handles_
);
248 !iter
.IsAtEnd(); iter
.Advance()) {
249 ServiceWorkerHandle
* handle
= iter
.GetCurrentValue();
251 DCHECK(handle
->version());
252 if (handle
->provider_id() == provider_id
&&
253 handle
->version()->version_id() == version_id
) {
260 ServiceWorkerRegistrationHandle
*
261 ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
262 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
263 ServiceWorkerRegistration
* registration
) {
264 DCHECK(provider_host
);
265 ServiceWorkerRegistrationHandle
* handle
=
266 FindRegistrationHandle(provider_host
->provider_id(), registration
->id());
268 handle
->IncrementRefCount();
272 scoped_ptr
<ServiceWorkerRegistrationHandle
> new_handle(
273 new ServiceWorkerRegistrationHandle(
274 GetContext()->AsWeakPtr(), provider_host
, registration
));
275 handle
= new_handle
.get();
276 RegisterServiceWorkerRegistrationHandle(new_handle
.Pass());
280 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
285 const GURL
& script_url
) {
286 TRACE_EVENT0("ServiceWorker",
287 "ServiceWorkerDispatcherHost::OnRegisterServiceWorker");
289 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
290 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeAbort
,
291 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
292 base::ASCIIToUTF16(kShutdownErrorMessage
)));
295 if (!pattern
.is_valid() || !script_url
.is_valid()) {
296 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_BAD_URL
);
300 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
301 render_process_id_
, provider_id
);
302 if (!provider_host
) {
303 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_NO_HOST
);
306 if (!provider_host
->IsContextAlive()) {
307 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
308 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeAbort
,
309 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
310 base::ASCIIToUTF16(kShutdownErrorMessage
)));
314 // TODO(ksakamoto): Currently, document_url is empty if the document is in an
315 // IFRAME using frame.contentDocument.write(...). We can remove this check
316 // once crbug.com/439697 is fixed.
317 if (provider_host
->document_url().is_empty()) {
318 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
319 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
320 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
321 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
325 if (!CanRegisterServiceWorker(
326 provider_host
->document_url(), pattern
, script_url
)) {
327 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_CANNOT
);
331 std::string error_message
;
332 if (ServiceWorkerUtils::ContainsDisallowedCharacter(pattern
, script_url
,
334 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
335 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
336 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
337 base::UTF8ToUTF16(error_message
)));
341 if (!GetContentClient()->browser()->AllowServiceWorker(
342 pattern
, provider_host
->topmost_frame_url(), resource_context_
,
343 render_process_id_
, provider_host
->frame_id())) {
344 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
345 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
346 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
347 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
351 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
352 "ServiceWorkerDispatcherHost::RegisterServiceWorker",
354 "Pattern", pattern
.spec(),
355 "Script URL", script_url
.spec());
356 GetContext()->RegisterServiceWorker(
360 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete
,
367 void ServiceWorkerDispatcherHost::OnUpdateServiceWorker(int provider_id
,
368 int64 registration_id
) {
369 TRACE_EVENT0("ServiceWorker",
370 "ServiceWorkerDispatcherHost::OnUpdateServiceWorker");
374 ServiceWorkerProviderHost
* provider_host
=
375 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
376 if (!provider_host
) {
377 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_NO_HOST
);
380 if (!provider_host
->IsContextAlive())
383 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
384 if (provider_host
->document_url().is_empty())
387 ServiceWorkerRegistration
* registration
=
388 GetContext()->GetLiveRegistration(registration_id
);
390 // |registration| must be alive because a renderer retains a registration
391 // reference at this point.
392 bad_message::ReceivedBadMessage(
393 this, bad_message::SWDH_UPDATE_BAD_REGISTRATION_ID
);
397 if (!CanUpdateServiceWorker(provider_host
->document_url(),
398 registration
->pattern())) {
399 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_CANNOT
);
403 if (!GetContentClient()->browser()->AllowServiceWorker(
404 registration
->pattern(), provider_host
->topmost_frame_url(),
405 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
409 if (!registration
->GetNewestVersion()) {
410 // This can happen if update() is called during initial script evaluation.
411 // Abort the following steps according to the spec.
415 // The spec says, "update() pings the server for an updated version of this
416 // script without consulting caches", so set |force_bypass_cache| to true.
417 GetContext()->UpdateServiceWorker(registration
,
418 true /* force_bypass_cache */);
421 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
425 int64 registration_id
) {
426 TRACE_EVENT0("ServiceWorker",
427 "ServiceWorkerDispatcherHost::OnUnregisterServiceWorker");
429 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
430 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
431 base::ASCIIToUTF16(kShutdownErrorMessage
)));
435 ServiceWorkerProviderHost
* provider_host
=
436 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
437 if (!provider_host
) {
438 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_NO_HOST
);
441 if (!provider_host
->IsContextAlive()) {
442 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
443 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
444 base::ASCIIToUTF16(kShutdownErrorMessage
)));
448 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
449 if (provider_host
->document_url().is_empty()) {
450 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
451 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
452 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
456 ServiceWorkerRegistration
* registration
=
457 GetContext()->GetLiveRegistration(registration_id
);
459 // |registration| must be alive because a renderer retains a registration
460 // reference at this point.
461 bad_message::ReceivedBadMessage(
462 this, bad_message::SWDH_UNREGISTER_BAD_REGISTRATION_ID
);
466 if (!CanUnregisterServiceWorker(provider_host
->document_url(),
467 registration
->pattern())) {
468 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_CANNOT
);
472 if (!GetContentClient()->browser()->AllowServiceWorker(
473 registration
->pattern(), provider_host
->topmost_frame_url(),
474 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
475 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
476 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
477 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
481 TRACE_EVENT_ASYNC_BEGIN1(
482 "ServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
483 request_id
, "Pattern", registration
->pattern().spec());
484 GetContext()->UnregisterServiceWorker(
485 registration
->pattern(),
486 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete
, this,
487 thread_id
, request_id
));
490 void ServiceWorkerDispatcherHost::OnGetRegistration(
494 const GURL
& document_url
) {
495 TRACE_EVENT0("ServiceWorker",
496 "ServiceWorkerDispatcherHost::OnGetRegistration");
498 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
501 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
502 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
503 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
504 base::ASCIIToUTF16(kShutdownErrorMessage
)));
507 if (!document_url
.is_valid()) {
508 bad_message::ReceivedBadMessage(this,
509 bad_message::SWDH_GET_REGISTRATION_BAD_URL
);
513 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
514 render_process_id_
, provider_id
);
515 if (!provider_host
) {
516 bad_message::ReceivedBadMessage(this,
517 bad_message::SWDH_GET_REGISTRATION_NO_HOST
);
520 if (!provider_host
->IsContextAlive()) {
521 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
522 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
523 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
524 base::ASCIIToUTF16(kShutdownErrorMessage
)));
528 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
529 if (provider_host
->document_url().is_empty()) {
530 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
531 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
532 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
533 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
537 if (!CanGetRegistration(provider_host
->document_url(), document_url
)) {
538 bad_message::ReceivedBadMessage(this,
539 bad_message::SWDH_GET_REGISTRATION_CANNOT
);
543 if (!GetContentClient()->browser()->AllowServiceWorker(
544 provider_host
->document_url(), provider_host
->topmost_frame_url(),
545 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
546 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
547 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
548 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
549 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
553 if (GetContext()->storage()->IsDisabled()) {
554 SendGetRegistrationError(thread_id
, request_id
, SERVICE_WORKER_ERROR_ABORT
);
558 TRACE_EVENT_ASYNC_BEGIN1(
560 "ServiceWorkerDispatcherHost::GetRegistration",
562 "Document URL", document_url
.spec());
564 GetContext()->storage()->FindRegistrationForDocument(
566 base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete
,
573 void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id
,
576 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
579 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
580 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
581 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
582 base::ASCIIToUTF16(kShutdownErrorMessage
)));
586 ServiceWorkerProviderHost
* provider_host
=
587 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
588 if (!provider_host
) {
589 bad_message::ReceivedBadMessage(
590 this, bad_message::SWDH_GET_REGISTRATIONS_NO_HOST
);
593 if (!provider_host
->IsContextAlive()) {
594 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
595 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
596 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
597 base::ASCIIToUTF16(kShutdownErrorMessage
)));
601 // TODO(jungkees): This check can be removed once crbug.com/439697 is fixed.
602 if (provider_host
->document_url().is_empty()) {
603 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
604 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
605 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
606 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
610 if (!OriginCanAccessServiceWorkers(provider_host
->document_url())) {
611 bad_message::ReceivedBadMessage(
612 this, bad_message::SWDH_GET_REGISTRATIONS_INVALID_ORIGIN
);
616 if (!GetContentClient()->browser()->AllowServiceWorker(
617 provider_host
->document_url(), provider_host
->topmost_frame_url(),
618 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
619 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
620 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
621 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
622 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
626 if (GetContext()->storage()->IsDisabled()) {
627 SendGetRegistrationsError(thread_id
, request_id
,
628 SERVICE_WORKER_ERROR_ABORT
);
632 TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
633 "ServiceWorkerDispatcherHost::GetRegistrations",
636 GetContext()->storage()->GetRegistrationsForOrigin(
637 provider_host
->document_url().GetOrigin(),
638 base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete
, this,
639 thread_id
, provider_id
, request_id
));
642 void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
646 TRACE_EVENT0("ServiceWorker",
647 "ServiceWorkerDispatcherHost::OnGetRegistrationForReady");
650 ServiceWorkerProviderHost
* provider_host
=
651 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
652 if (!provider_host
) {
653 bad_message::ReceivedBadMessage(
654 this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_NO_HOST
);
657 if (!provider_host
->IsContextAlive())
660 TRACE_EVENT_ASYNC_BEGIN0(
662 "ServiceWorkerDispatcherHost::GetRegistrationForReady",
665 if (!provider_host
->GetRegistrationForReady(base::Bind(
666 &ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete
,
667 this, thread_id
, request_id
, provider_host
->AsWeakPtr()))) {
668 bad_message::ReceivedBadMessage(
669 this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_ALREADY_IN_PROGRESS
);
673 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
675 const base::string16
& message
,
676 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
677 TRACE_EVENT0("ServiceWorker",
678 "ServiceWorkerDispatcherHost::OnPostMessageToWorker");
682 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
684 bad_message::ReceivedBadMessage(this, bad_message::SWDH_POST_MESSAGE
);
688 handle
->version()->DispatchMessageEvent(
689 message
, sent_message_ports
,
690 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
693 void ServiceWorkerDispatcherHost::OnProviderCreated(
696 ServiceWorkerProviderType provider_type
) {
697 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
698 tracked_objects::ScopedTracker
tracking_profile(
699 FROM_HERE_WITH_EXPLICIT_FUNCTION(
700 "477117 ServiceWorkerDispatcherHost::OnProviderCreated"));
701 TRACE_EVENT0("ServiceWorker",
702 "ServiceWorkerDispatcherHost::OnProviderCreated");
705 if (GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
706 bad_message::ReceivedBadMessage(this,
707 bad_message::SWDH_PROVIDER_CREATED_NO_HOST
);
710 scoped_ptr
<ServiceWorkerProviderHost
> provider_host(
711 new ServiceWorkerProviderHost(render_process_id_
, route_id
, provider_id
,
712 provider_type
, GetContext()->AsWeakPtr(),
714 GetContext()->AddProviderHost(provider_host
.Pass());
717 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id
) {
718 TRACE_EVENT0("ServiceWorker",
719 "ServiceWorkerDispatcherHost::OnProviderDestroyed");
722 if (!GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
723 bad_message::ReceivedBadMessage(
724 this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST
);
727 GetContext()->RemoveProviderHost(render_process_id_
, provider_id
);
730 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
731 int provider_id
, int64 version_id
) {
732 TRACE_EVENT0("ServiceWorker",
733 "ServiceWorkerDispatcherHost::OnSetHostedVersionId");
736 ServiceWorkerProviderHost
* provider_host
=
737 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
738 if (!provider_host
) {
739 bad_message::ReceivedBadMessage(
740 this, bad_message::SWDH_SET_HOSTED_VERSION_NO_HOST
);
743 if (!provider_host
->IsContextAlive())
745 if (!provider_host
->SetHostedVersionId(version_id
))
746 bad_message::ReceivedBadMessage(this, bad_message::SWDH_SET_HOSTED_VERSION
);
748 ServiceWorkerVersion
* version
= GetContext()->GetLiveVersion(version_id
);
752 // Retrieve the registration associated with |version|. The registration
753 // must be alive because the version keeps it during starting worker.
754 ServiceWorkerRegistration
* registration
=
755 GetContext()->GetLiveRegistration(version
->registration_id());
756 DCHECK(registration
);
757 // TODO(ksakamoto): This is a quick fix for crbug.com/459916.
761 // Set the document URL to the script url in order to allow
762 // register/unregister/getRegistration on ServiceWorkerGlobalScope.
763 provider_host
->SetDocumentUrl(version
->script_url());
765 ServiceWorkerRegistrationObjectInfo info
;
766 ServiceWorkerVersionAttributes attrs
;
767 GetRegistrationObjectInfoAndVersionAttributes(
768 provider_host
->AsWeakPtr(), registration
, &info
, &attrs
);
770 Send(new ServiceWorkerMsg_AssociateRegistrationWithServiceWorker(
771 kDocumentMainThreadId
, provider_id
, info
, attrs
));
774 ServiceWorkerRegistrationHandle
*
775 ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id
,
776 int64 registration_id
) {
777 for (IDMap
<ServiceWorkerRegistrationHandle
, IDMapOwnPointer
>::iterator
778 iter(®istration_handles_
);
781 ServiceWorkerRegistrationHandle
* handle
= iter
.GetCurrentValue();
783 DCHECK(handle
->registration());
784 if (handle
->provider_id() == provider_id
&&
785 handle
->registration()->id() == registration_id
) {
792 void ServiceWorkerDispatcherHost::GetRegistrationObjectInfoAndVersionAttributes(
793 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
794 ServiceWorkerRegistration
* registration
,
795 ServiceWorkerRegistrationObjectInfo
* info
,
796 ServiceWorkerVersionAttributes
* attrs
) {
797 ServiceWorkerRegistrationHandle
* handle
=
798 GetOrCreateRegistrationHandle(provider_host
, registration
);
799 *info
= handle
->GetObjectInfo();
801 attrs
->installing
= provider_host
->GetOrCreateServiceWorkerHandle(
802 registration
->installing_version());
803 attrs
->waiting
= provider_host
->GetOrCreateServiceWorkerHandle(
804 registration
->waiting_version());
805 attrs
->active
= provider_host
->GetOrCreateServiceWorkerHandle(
806 registration
->active_version());
809 void ServiceWorkerDispatcherHost::RegistrationComplete(
813 ServiceWorkerStatusCode status
,
814 const std::string
& status_message
,
815 int64 registration_id
) {
819 ServiceWorkerProviderHost
* provider_host
=
820 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
822 return; // The provider has already been destroyed.
824 if (status
!= SERVICE_WORKER_OK
) {
825 SendRegistrationError(thread_id
, request_id
, status
, status_message
);
829 ServiceWorkerRegistration
* registration
=
830 GetContext()->GetLiveRegistration(registration_id
);
831 DCHECK(registration
);
833 ServiceWorkerRegistrationObjectInfo info
;
834 ServiceWorkerVersionAttributes attrs
;
835 GetRegistrationObjectInfoAndVersionAttributes(
836 provider_host
->AsWeakPtr(), registration
, &info
, &attrs
);
838 Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
839 thread_id
, request_id
, info
, attrs
));
840 TRACE_EVENT_ASYNC_END1("ServiceWorker",
841 "ServiceWorkerDispatcherHost::RegisterServiceWorker",
847 void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
848 int embedded_worker_id
) {
849 TRACE_EVENT0("ServiceWorker",
850 "ServiceWorkerDispatcherHost::OnWorkerReadyForInspection");
853 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
854 if (!registry
->CanHandle(embedded_worker_id
))
856 registry
->OnWorkerReadyForInspection(render_process_id_
, embedded_worker_id
);
859 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(
860 int embedded_worker_id
,
863 TRACE_EVENT0("ServiceWorker",
864 "ServiceWorkerDispatcherHost::OnWorkerScriptLoaded");
868 ServiceWorkerProviderHost
* provider_host
=
869 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
870 if (!provider_host
) {
871 bad_message::ReceivedBadMessage(
872 this, bad_message::SWDH_WORKER_SCRIPT_LOAD_NO_HOST
);
876 provider_host
->SetReadyToSendMessagesToWorker(thread_id
);
878 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
879 if (!registry
->CanHandle(embedded_worker_id
))
881 registry
->OnWorkerScriptLoaded(
882 render_process_id_
, thread_id
, embedded_worker_id
);
885 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
886 int embedded_worker_id
) {
887 TRACE_EVENT0("ServiceWorker",
888 "ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed");
891 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
892 if (!registry
->CanHandle(embedded_worker_id
))
894 registry
->OnWorkerScriptLoadFailed(render_process_id_
, embedded_worker_id
);
897 void ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated(
898 int embedded_worker_id
,
900 TRACE_EVENT0("ServiceWorker",
901 "ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated");
904 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
905 if (!registry
->CanHandle(embedded_worker_id
))
907 registry
->OnWorkerScriptEvaluated(
908 render_process_id_
, embedded_worker_id
, success
);
911 void ServiceWorkerDispatcherHost::OnWorkerStarted(int embedded_worker_id
) {
912 TRACE_EVENT0("ServiceWorker",
913 "ServiceWorkerDispatcherHost::OnWorkerStarted");
916 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
917 if (!registry
->CanHandle(embedded_worker_id
))
919 registry
->OnWorkerStarted(render_process_id_
, embedded_worker_id
);
922 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id
) {
923 TRACE_EVENT0("ServiceWorker",
924 "ServiceWorkerDispatcherHost::OnWorkerStopped");
927 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
928 if (!registry
->CanHandle(embedded_worker_id
))
930 registry
->OnWorkerStopped(render_process_id_
, embedded_worker_id
);
933 void ServiceWorkerDispatcherHost::OnReportException(
934 int embedded_worker_id
,
935 const base::string16
& error_message
,
938 const GURL
& source_url
) {
939 TRACE_EVENT0("ServiceWorker",
940 "ServiceWorkerDispatcherHost::OnReportException");
943 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
944 if (!registry
->CanHandle(embedded_worker_id
))
946 registry
->OnReportException(embedded_worker_id
,
953 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
954 int embedded_worker_id
,
955 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params
& params
) {
956 TRACE_EVENT0("ServiceWorker",
957 "ServiceWorkerDispatcherHost::OnReportConsoleMessage");
960 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
961 if (!registry
->CanHandle(embedded_worker_id
))
963 registry
->OnReportConsoleMessage(embedded_worker_id
,
964 params
.source_identifier
,
965 params
.message_level
,
971 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
973 TRACE_EVENT0("ServiceWorker",
974 "ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount");
975 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
977 bad_message::ReceivedBadMessage(
978 this, bad_message::SWDH_INCREMENT_WORKER_BAD_HANDLE
);
981 handle
->IncrementRefCount();
984 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
986 TRACE_EVENT0("ServiceWorker",
987 "ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount");
988 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
990 bad_message::ReceivedBadMessage(
991 this, bad_message::SWDH_DECREMENT_WORKER_BAD_HANDLE
);
994 handle
->DecrementRefCount();
995 if (handle
->HasNoRefCount())
996 handles_
.Remove(handle_id
);
999 void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
1000 int registration_handle_id
) {
1001 TRACE_EVENT0("ServiceWorker",
1002 "ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount");
1003 ServiceWorkerRegistrationHandle
* handle
=
1004 registration_handles_
.Lookup(registration_handle_id
);
1006 bad_message::ReceivedBadMessage(
1007 this, bad_message::SWDH_INCREMENT_REGISTRATION_BAD_HANDLE
);
1010 handle
->IncrementRefCount();
1013 void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
1014 int registration_handle_id
) {
1015 TRACE_EVENT0("ServiceWorker",
1016 "ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount");
1017 ServiceWorkerRegistrationHandle
* handle
=
1018 registration_handles_
.Lookup(registration_handle_id
);
1020 bad_message::ReceivedBadMessage(
1021 this, bad_message::SWDH_DECREMENT_REGISTRATION_BAD_HANDLE
);
1024 handle
->DecrementRefCount();
1025 if (handle
->HasNoRefCount())
1026 registration_handles_
.Remove(registration_handle_id
);
1029 void ServiceWorkerDispatcherHost::UnregistrationComplete(
1032 ServiceWorkerStatusCode status
) {
1033 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
) {
1034 SendUnregistrationError(thread_id
, request_id
, status
);
1037 const bool is_success
= (status
== SERVICE_WORKER_OK
);
1038 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id
,
1041 TRACE_EVENT_ASYNC_END1(
1043 "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
1048 void ServiceWorkerDispatcherHost::GetRegistrationComplete(
1052 ServiceWorkerStatusCode status
,
1053 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
1054 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1055 "ServiceWorkerDispatcherHost::GetRegistration",
1058 registration
.get() ? registration
->id()
1059 : kInvalidServiceWorkerRegistrationId
);
1064 ServiceWorkerProviderHost
* provider_host
=
1065 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
1067 return; // The provider has already been destroyed.
1069 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
) {
1070 SendGetRegistrationError(thread_id
, request_id
, status
);
1074 ServiceWorkerRegistrationObjectInfo info
;
1075 ServiceWorkerVersionAttributes attrs
;
1076 if (status
== SERVICE_WORKER_OK
) {
1077 DCHECK(registration
.get());
1078 if (!registration
->is_uninstalling()) {
1079 GetRegistrationObjectInfoAndVersionAttributes(
1080 provider_host
->AsWeakPtr(), registration
.get(), &info
, &attrs
);
1084 Send(new ServiceWorkerMsg_DidGetRegistration(
1085 thread_id
, request_id
, info
, attrs
));
1088 void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
1092 const std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>&
1094 TRACE_EVENT_ASYNC_END0("ServiceWorker",
1095 "ServiceWorkerDispatcherHost::GetRegistrations",
1100 ServiceWorkerProviderHost
* provider_host
=
1101 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
1103 return; // The provider has already been destroyed.
1105 std::vector
<ServiceWorkerRegistrationObjectInfo
> object_infos
;
1106 std::vector
<ServiceWorkerVersionAttributes
> version_attrs
;
1108 for (const auto& registration
: registrations
) {
1109 DCHECK(registration
.get());
1110 if (!registration
->is_uninstalling()) {
1111 ServiceWorkerRegistrationObjectInfo object_info
;
1112 ServiceWorkerVersionAttributes version_attr
;
1113 GetRegistrationObjectInfoAndVersionAttributes(
1114 provider_host
->AsWeakPtr(), registration
.get(), &object_info
,
1116 object_infos
.push_back(object_info
);
1117 version_attrs
.push_back(version_attr
);
1121 Send(new ServiceWorkerMsg_DidGetRegistrations(thread_id
, request_id
,
1122 object_infos
, version_attrs
));
1125 void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
1128 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
1129 ServiceWorkerRegistration
* registration
) {
1130 DCHECK(registration
);
1131 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1132 "ServiceWorkerDispatcherHost::GetRegistrationForReady",
1135 registration
? registration
->id()
1136 : kInvalidServiceWorkerRegistrationId
);
1141 ServiceWorkerRegistrationObjectInfo info
;
1142 ServiceWorkerVersionAttributes attrs
;
1143 GetRegistrationObjectInfoAndVersionAttributes(
1144 provider_host
, registration
, &info
, &attrs
);
1145 Send(new ServiceWorkerMsg_DidGetRegistrationForReady(
1146 thread_id
, request_id
, info
, attrs
));
1149 void ServiceWorkerDispatcherHost::SendRegistrationError(
1152 ServiceWorkerStatusCode status
,
1153 const std::string
& status_message
) {
1154 base::string16 error_message
;
1155 blink::WebServiceWorkerError::ErrorType error_type
;
1156 GetServiceWorkerRegistrationStatusResponse(status
, status_message
,
1157 &error_type
, &error_message
);
1158 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
1159 thread_id
, request_id
, error_type
,
1160 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) + error_message
));
1163 void ServiceWorkerDispatcherHost::SendUnregistrationError(
1166 ServiceWorkerStatusCode status
) {
1167 base::string16 error_message
;
1168 blink::WebServiceWorkerError::ErrorType error_type
;
1169 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1171 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
1172 thread_id
, request_id
, error_type
,
1173 base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix
) + error_message
));
1176 void ServiceWorkerDispatcherHost::SendGetRegistrationError(
1179 ServiceWorkerStatusCode status
) {
1180 base::string16 error_message
;
1181 blink::WebServiceWorkerError::ErrorType error_type
;
1182 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1184 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
1185 thread_id
, request_id
, error_type
,
1186 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
1190 void ServiceWorkerDispatcherHost::SendGetRegistrationsError(
1193 ServiceWorkerStatusCode status
) {
1194 base::string16 error_message
;
1195 blink::WebServiceWorkerError::ErrorType error_type
;
1196 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1198 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
1199 thread_id
, request_id
, error_type
,
1200 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
1204 ServiceWorkerContextCore
* ServiceWorkerDispatcherHost::GetContext() {
1205 if (!context_wrapper_
.get())
1207 return context_wrapper_
->context();
1210 void ServiceWorkerDispatcherHost::OnTerminateWorker(int handle_id
) {
1211 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
1213 bad_message::ReceivedBadMessage(this,
1214 bad_message::SWDH_TERMINATE_BAD_HANDLE
);
1217 handle
->version()->StopWorker(
1218 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
1221 } // namespace content