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 OriginCanAccessServiceWorkers(const GURL
& url
) {
56 return url
.SchemeIsHTTPOrHTTPS() && IsOriginSecure(url
);
59 bool CanRegisterServiceWorker(const GURL
& document_url
,
61 const GURL
& script_url
) {
62 DCHECK(document_url
.is_valid());
63 DCHECK(pattern
.is_valid());
64 DCHECK(script_url
.is_valid());
65 return AllOriginsMatch(document_url
, pattern
, script_url
) &&
66 OriginCanAccessServiceWorkers(document_url
) &&
67 OriginCanAccessServiceWorkers(pattern
) &&
68 OriginCanAccessServiceWorkers(script_url
);
71 bool CanUnregisterServiceWorker(const GURL
& document_url
,
72 const GURL
& pattern
) {
73 DCHECK(document_url
.is_valid());
74 DCHECK(pattern
.is_valid());
75 return document_url
.GetOrigin() == pattern
.GetOrigin() &&
76 OriginCanAccessServiceWorkers(document_url
) &&
77 OriginCanAccessServiceWorkers(pattern
);
80 bool CanUpdateServiceWorker(const GURL
& document_url
, const GURL
& pattern
) {
81 DCHECK(document_url
.is_valid());
82 DCHECK(pattern
.is_valid());
83 DCHECK(OriginCanAccessServiceWorkers(document_url
));
84 DCHECK(OriginCanAccessServiceWorkers(pattern
));
85 return document_url
.GetOrigin() == pattern
.GetOrigin();
88 bool CanGetRegistration(const GURL
& document_url
,
89 const GURL
& given_document_url
) {
90 DCHECK(document_url
.is_valid());
91 DCHECK(given_document_url
.is_valid());
92 return document_url
.GetOrigin() == given_document_url
.GetOrigin() &&
93 OriginCanAccessServiceWorkers(document_url
) &&
94 OriginCanAccessServiceWorkers(given_document_url
);
99 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
100 int render_process_id
,
101 MessagePortMessageFilter
* message_port_message_filter
,
102 ResourceContext
* resource_context
)
103 : BrowserMessageFilter(kFilteredMessageClasses
,
104 arraysize(kFilteredMessageClasses
)),
105 render_process_id_(render_process_id
),
106 message_port_message_filter_(message_port_message_filter
),
107 resource_context_(resource_context
),
108 channel_ready_(false) {
111 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
113 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_
);
114 GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
119 void ServiceWorkerDispatcherHost::Init(
120 ServiceWorkerContextWrapper
* context_wrapper
) {
121 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
122 BrowserThread::PostTask(
123 BrowserThread::IO
, FROM_HERE
,
124 base::Bind(&ServiceWorkerDispatcherHost::Init
,
125 this, make_scoped_refptr(context_wrapper
)));
129 context_wrapper_
= context_wrapper
;
132 GetContext()->embedded_worker_registry()->AddChildProcessSender(
133 render_process_id_
, this, message_port_message_filter_
);
136 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender
* sender
) {
137 TRACE_EVENT0("ServiceWorker",
138 "ServiceWorkerDispatcherHost::OnFilterAdded");
139 channel_ready_
= true;
140 std::vector
<IPC::Message
*> messages
;
141 pending_messages_
.release(&messages
);
142 for (size_t i
= 0; i
< messages
.size(); ++i
) {
143 BrowserMessageFilter::Send(messages
[i
]);
147 void ServiceWorkerDispatcherHost::OnFilterRemoved() {
148 // Don't wait until the destructor to teardown since a new dispatcher host
149 // for this process might be created before then.
151 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_
);
152 GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
155 context_wrapper_
= nullptr;
156 channel_ready_
= false;
159 void ServiceWorkerDispatcherHost::OnDestruct() const {
160 BrowserThread::DeleteOnIOThread::Destruct(this);
163 bool ServiceWorkerDispatcherHost::OnMessageReceived(
164 const IPC::Message
& message
) {
166 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost
, message
)
167 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker
,
168 OnRegisterServiceWorker
)
169 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UpdateServiceWorker
,
170 OnUpdateServiceWorker
)
171 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker
,
172 OnUnregisterServiceWorker
)
173 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration
,
175 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrations
,
177 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrationForReady
,
178 OnGetRegistrationForReady
)
179 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated
,
181 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed
,
183 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId
,
184 OnSetHostedVersionId
)
185 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker
,
186 OnPostMessageToWorker
)
187 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection
,
188 OnWorkerReadyForInspection
)
189 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded
,
190 OnWorkerScriptLoaded
)
191 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed
,
192 OnWorkerScriptLoadFailed
)
193 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptEvaluated
,
194 OnWorkerScriptEvaluated
)
195 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted
,
197 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped
,
199 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException
,
201 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage
,
202 OnReportConsoleMessage
)
203 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount
,
204 OnIncrementServiceWorkerRefCount
)
205 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount
,
206 OnDecrementServiceWorkerRefCount
)
207 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount
,
208 OnIncrementRegistrationRefCount
)
209 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount
,
210 OnDecrementRegistrationRefCount
)
211 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_TerminateWorker
, OnTerminateWorker
)
212 IPC_MESSAGE_UNHANDLED(handled
= false)
213 IPC_END_MESSAGE_MAP()
215 if (!handled
&& GetContext()) {
216 handled
= GetContext()->embedded_worker_registry()->OnMessageReceived(
217 message
, render_process_id_
);
219 bad_message::ReceivedBadMessage(this, bad_message::SWDH_NOT_HANDLED
);
225 bool ServiceWorkerDispatcherHost::Send(IPC::Message
* message
) {
226 if (channel_ready_
) {
227 BrowserMessageFilter::Send(message
);
228 // Don't bother passing through Send()'s result: it's not reliable.
232 pending_messages_
.push_back(message
);
236 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
237 scoped_ptr
<ServiceWorkerHandle
> handle
) {
238 int handle_id
= handle
->handle_id();
239 handles_
.AddWithID(handle
.release(), handle_id
);
242 void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
243 scoped_ptr
<ServiceWorkerRegistrationHandle
> handle
) {
244 int handle_id
= handle
->handle_id();
245 registration_handles_
.AddWithID(handle
.release(), handle_id
);
248 ServiceWorkerHandle
* ServiceWorkerDispatcherHost::FindServiceWorkerHandle(
251 for (IDMap
<ServiceWorkerHandle
, IDMapOwnPointer
>::iterator
iter(&handles_
);
252 !iter
.IsAtEnd(); iter
.Advance()) {
253 ServiceWorkerHandle
* handle
= iter
.GetCurrentValue();
255 DCHECK(handle
->version());
256 if (handle
->provider_id() == provider_id
&&
257 handle
->version()->version_id() == version_id
) {
264 ServiceWorkerRegistrationHandle
*
265 ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
266 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
267 ServiceWorkerRegistration
* registration
) {
268 DCHECK(provider_host
);
269 ServiceWorkerRegistrationHandle
* handle
=
270 FindRegistrationHandle(provider_host
->provider_id(), registration
->id());
272 handle
->IncrementRefCount();
276 scoped_ptr
<ServiceWorkerRegistrationHandle
> new_handle(
277 new ServiceWorkerRegistrationHandle(
278 GetContext()->AsWeakPtr(), provider_host
, registration
));
279 handle
= new_handle
.get();
280 RegisterServiceWorkerRegistrationHandle(new_handle
.Pass());
284 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
289 const GURL
& script_url
) {
290 TRACE_EVENT0("ServiceWorker",
291 "ServiceWorkerDispatcherHost::OnRegisterServiceWorker");
293 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
294 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeAbort
,
295 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
296 base::ASCIIToUTF16(kShutdownErrorMessage
)));
299 if (!pattern
.is_valid() || !script_url
.is_valid()) {
300 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_BAD_URL
);
304 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
305 render_process_id_
, provider_id
);
306 if (!provider_host
) {
307 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_NO_HOST
);
310 if (!provider_host
->IsContextAlive()) {
311 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
312 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeAbort
,
313 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
314 base::ASCIIToUTF16(kShutdownErrorMessage
)));
318 // TODO(ksakamoto): Currently, document_url is empty if the document is in an
319 // IFRAME using frame.contentDocument.write(...). We can remove this check
320 // once crbug.com/439697 is fixed.
321 if (provider_host
->document_url().is_empty()) {
322 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
323 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
324 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
325 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
329 if (!CanRegisterServiceWorker(
330 provider_host
->document_url(), pattern
, script_url
)) {
331 bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_CANNOT
);
335 std::string error_message
;
336 if (ServiceWorkerUtils::ContainsDisallowedCharacter(pattern
, script_url
,
338 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
339 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
340 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
341 base::UTF8ToUTF16(error_message
)));
345 if (!GetContentClient()->browser()->AllowServiceWorker(
346 pattern
, provider_host
->topmost_frame_url(), resource_context_
,
347 render_process_id_
, provider_host
->frame_id())) {
348 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
349 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
350 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) +
351 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
355 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
356 "ServiceWorkerDispatcherHost::RegisterServiceWorker",
358 "Pattern", pattern
.spec(),
359 "Script URL", script_url
.spec());
360 GetContext()->RegisterServiceWorker(
364 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete
,
371 void ServiceWorkerDispatcherHost::OnUpdateServiceWorker(int provider_id
,
372 int64 registration_id
) {
373 TRACE_EVENT0("ServiceWorker",
374 "ServiceWorkerDispatcherHost::OnUpdateServiceWorker");
378 ServiceWorkerProviderHost
* provider_host
=
379 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
380 if (!provider_host
) {
381 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_NO_HOST
);
384 if (!provider_host
->IsContextAlive())
387 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
388 if (provider_host
->document_url().is_empty())
391 ServiceWorkerRegistration
* registration
=
392 GetContext()->GetLiveRegistration(registration_id
);
394 // |registration| must be alive because a renderer retains a registration
395 // reference at this point.
396 bad_message::ReceivedBadMessage(
397 this, bad_message::SWDH_UPDATE_BAD_REGISTRATION_ID
);
401 if (!CanUpdateServiceWorker(provider_host
->document_url(),
402 registration
->pattern())) {
403 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UPDATE_CANNOT
);
407 if (!GetContentClient()->browser()->AllowServiceWorker(
408 registration
->pattern(), provider_host
->topmost_frame_url(),
409 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
413 if (!registration
->GetNewestVersion()) {
414 // This can happen if update() is called during initial script evaluation.
415 // Abort the following steps according to the spec.
419 // The spec says, "update() pings the server for an updated version of this
420 // script without consulting caches", so set |force_bypass_cache| to true.
421 GetContext()->UpdateServiceWorker(registration
,
422 true /* force_bypass_cache */);
425 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
429 int64 registration_id
) {
430 TRACE_EVENT0("ServiceWorker",
431 "ServiceWorkerDispatcherHost::OnUnregisterServiceWorker");
433 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
434 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
435 base::ASCIIToUTF16(kShutdownErrorMessage
)));
439 ServiceWorkerProviderHost
* provider_host
=
440 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
441 if (!provider_host
) {
442 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_NO_HOST
);
445 if (!provider_host
->IsContextAlive()) {
446 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
447 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
448 base::ASCIIToUTF16(kShutdownErrorMessage
)));
452 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
453 if (provider_host
->document_url().is_empty()) {
454 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
455 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
456 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
460 ServiceWorkerRegistration
* registration
=
461 GetContext()->GetLiveRegistration(registration_id
);
463 // |registration| must be alive because a renderer retains a registration
464 // reference at this point.
465 bad_message::ReceivedBadMessage(
466 this, bad_message::SWDH_UNREGISTER_BAD_REGISTRATION_ID
);
470 if (!CanUnregisterServiceWorker(provider_host
->document_url(),
471 registration
->pattern())) {
472 bad_message::ReceivedBadMessage(this, bad_message::SWDH_UNREGISTER_CANNOT
);
476 if (!GetContentClient()->browser()->AllowServiceWorker(
477 registration
->pattern(), provider_host
->topmost_frame_url(),
478 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
479 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
480 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
481 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
485 TRACE_EVENT_ASYNC_BEGIN1(
486 "ServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
487 request_id
, "Pattern", registration
->pattern().spec());
488 GetContext()->UnregisterServiceWorker(
489 registration
->pattern(),
490 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete
, this,
491 thread_id
, request_id
));
494 void ServiceWorkerDispatcherHost::OnGetRegistration(
498 const GURL
& document_url
) {
499 TRACE_EVENT0("ServiceWorker",
500 "ServiceWorkerDispatcherHost::OnGetRegistration");
502 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
505 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
506 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
507 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
508 base::ASCIIToUTF16(kShutdownErrorMessage
)));
511 if (!document_url
.is_valid()) {
512 bad_message::ReceivedBadMessage(this,
513 bad_message::SWDH_GET_REGISTRATION_BAD_URL
);
517 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
518 render_process_id_
, provider_id
);
519 if (!provider_host
) {
520 bad_message::ReceivedBadMessage(this,
521 bad_message::SWDH_GET_REGISTRATION_NO_HOST
);
524 if (!provider_host
->IsContextAlive()) {
525 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
526 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
527 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
528 base::ASCIIToUTF16(kShutdownErrorMessage
)));
532 // TODO(ksakamoto): This check can be removed once crbug.com/439697 is fixed.
533 if (provider_host
->document_url().is_empty()) {
534 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
535 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
536 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
537 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
541 if (!CanGetRegistration(provider_host
->document_url(), document_url
)) {
542 bad_message::ReceivedBadMessage(this,
543 bad_message::SWDH_GET_REGISTRATION_CANNOT
);
547 if (!GetContentClient()->browser()->AllowServiceWorker(
548 provider_host
->document_url(), provider_host
->topmost_frame_url(),
549 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
550 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
551 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
552 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
553 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
557 if (GetContext()->storage()->IsDisabled()) {
558 SendGetRegistrationError(thread_id
, request_id
, SERVICE_WORKER_ERROR_ABORT
);
562 TRACE_EVENT_ASYNC_BEGIN1(
564 "ServiceWorkerDispatcherHost::GetRegistration",
566 "Document URL", document_url
.spec());
568 GetContext()->storage()->FindRegistrationForDocument(
570 base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete
,
577 void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id
,
580 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
583 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
584 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
585 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
586 base::ASCIIToUTF16(kShutdownErrorMessage
)));
590 ServiceWorkerProviderHost
* provider_host
=
591 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
592 if (!provider_host
) {
593 bad_message::ReceivedBadMessage(
594 this, bad_message::SWDH_GET_REGISTRATIONS_NO_HOST
);
597 if (!provider_host
->IsContextAlive()) {
598 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
599 thread_id
, request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
600 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
601 base::ASCIIToUTF16(kShutdownErrorMessage
)));
605 // TODO(jungkees): This check can be removed once crbug.com/439697 is fixed.
606 if (provider_host
->document_url().is_empty()) {
607 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
608 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeSecurity
,
609 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
610 base::ASCIIToUTF16(kNoDocumentURLErrorMessage
)));
614 if (!OriginCanAccessServiceWorkers(provider_host
->document_url())) {
615 bad_message::ReceivedBadMessage(
616 this, bad_message::SWDH_GET_REGISTRATIONS_INVALID_ORIGIN
);
620 if (!GetContentClient()->browser()->AllowServiceWorker(
621 provider_host
->document_url(), provider_host
->topmost_frame_url(),
622 resource_context_
, render_process_id_
, provider_host
->frame_id())) {
623 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
624 thread_id
, request_id
, WebServiceWorkerError::ErrorTypeUnknown
,
625 base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix
) +
626 base::ASCIIToUTF16(kUserDeniedPermissionMessage
)));
630 if (GetContext()->storage()->IsDisabled()) {
631 SendGetRegistrationsError(thread_id
, request_id
,
632 SERVICE_WORKER_ERROR_ABORT
);
636 TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
637 "ServiceWorkerDispatcherHost::GetRegistrations",
640 GetContext()->storage()->GetRegistrationsForOrigin(
641 provider_host
->document_url().GetOrigin(),
642 base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete
, this,
643 thread_id
, provider_id
, request_id
));
646 void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
650 TRACE_EVENT0("ServiceWorker",
651 "ServiceWorkerDispatcherHost::OnGetRegistrationForReady");
654 ServiceWorkerProviderHost
* provider_host
=
655 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
656 if (!provider_host
) {
657 bad_message::ReceivedBadMessage(
658 this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_NO_HOST
);
661 if (!provider_host
->IsContextAlive())
664 TRACE_EVENT_ASYNC_BEGIN0(
666 "ServiceWorkerDispatcherHost::GetRegistrationForReady",
669 if (!provider_host
->GetRegistrationForReady(base::Bind(
670 &ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete
,
671 this, thread_id
, request_id
, provider_host
->AsWeakPtr()))) {
672 bad_message::ReceivedBadMessage(
673 this, bad_message::SWDH_GET_REGISTRATION_FOR_READY_ALREADY_IN_PROGRESS
);
677 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
679 const base::string16
& message
,
680 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
681 TRACE_EVENT0("ServiceWorker",
682 "ServiceWorkerDispatcherHost::OnPostMessageToWorker");
686 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
688 bad_message::ReceivedBadMessage(this, bad_message::SWDH_POST_MESSAGE
);
692 handle
->version()->DispatchMessageEvent(
693 message
, sent_message_ports
,
694 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
697 void ServiceWorkerDispatcherHost::OnProviderCreated(
700 ServiceWorkerProviderType provider_type
) {
701 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
702 tracked_objects::ScopedTracker
tracking_profile(
703 FROM_HERE_WITH_EXPLICIT_FUNCTION(
704 "477117 ServiceWorkerDispatcherHost::OnProviderCreated"));
705 TRACE_EVENT0("ServiceWorker",
706 "ServiceWorkerDispatcherHost::OnProviderCreated");
709 if (GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
710 bad_message::ReceivedBadMessage(this,
711 bad_message::SWDH_PROVIDER_CREATED_NO_HOST
);
714 scoped_ptr
<ServiceWorkerProviderHost
> provider_host(
715 new ServiceWorkerProviderHost(render_process_id_
, route_id
, provider_id
,
716 provider_type
, GetContext()->AsWeakPtr(),
718 GetContext()->AddProviderHost(provider_host
.Pass());
721 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id
) {
722 TRACE_EVENT0("ServiceWorker",
723 "ServiceWorkerDispatcherHost::OnProviderDestroyed");
726 if (!GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
727 bad_message::ReceivedBadMessage(
728 this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST
);
731 GetContext()->RemoveProviderHost(render_process_id_
, provider_id
);
734 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
735 int provider_id
, int64 version_id
) {
736 TRACE_EVENT0("ServiceWorker",
737 "ServiceWorkerDispatcherHost::OnSetHostedVersionId");
740 ServiceWorkerProviderHost
* provider_host
=
741 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
742 if (!provider_host
) {
743 bad_message::ReceivedBadMessage(
744 this, bad_message::SWDH_SET_HOSTED_VERSION_NO_HOST
);
747 if (!provider_host
->IsContextAlive())
749 if (!provider_host
->SetHostedVersionId(version_id
))
750 bad_message::ReceivedBadMessage(this, bad_message::SWDH_SET_HOSTED_VERSION
);
752 ServiceWorkerVersion
* version
= GetContext()->GetLiveVersion(version_id
);
756 // Retrieve the registration associated with |version|. The registration
757 // must be alive because the version keeps it during starting worker.
758 ServiceWorkerRegistration
* registration
=
759 GetContext()->GetLiveRegistration(version
->registration_id());
760 DCHECK(registration
);
761 // TODO(ksakamoto): This is a quick fix for crbug.com/459916.
765 // Set the document URL to the script url in order to allow
766 // register/unregister/getRegistration on ServiceWorkerGlobalScope.
767 provider_host
->SetDocumentUrl(version
->script_url());
769 ServiceWorkerRegistrationObjectInfo info
;
770 ServiceWorkerVersionAttributes attrs
;
771 GetRegistrationObjectInfoAndVersionAttributes(
772 provider_host
->AsWeakPtr(), registration
, &info
, &attrs
);
774 Send(new ServiceWorkerMsg_AssociateRegistrationWithServiceWorker(
775 kDocumentMainThreadId
, provider_id
, info
, attrs
));
778 ServiceWorkerRegistrationHandle
*
779 ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id
,
780 int64 registration_id
) {
781 for (IDMap
<ServiceWorkerRegistrationHandle
, IDMapOwnPointer
>::iterator
782 iter(®istration_handles_
);
785 ServiceWorkerRegistrationHandle
* handle
= iter
.GetCurrentValue();
787 DCHECK(handle
->registration());
788 if (handle
->provider_id() == provider_id
&&
789 handle
->registration()->id() == registration_id
) {
796 void ServiceWorkerDispatcherHost::GetRegistrationObjectInfoAndVersionAttributes(
797 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
798 ServiceWorkerRegistration
* registration
,
799 ServiceWorkerRegistrationObjectInfo
* info
,
800 ServiceWorkerVersionAttributes
* attrs
) {
801 ServiceWorkerRegistrationHandle
* handle
=
802 GetOrCreateRegistrationHandle(provider_host
, registration
);
803 *info
= handle
->GetObjectInfo();
805 attrs
->installing
= provider_host
->GetOrCreateServiceWorkerHandle(
806 registration
->installing_version());
807 attrs
->waiting
= provider_host
->GetOrCreateServiceWorkerHandle(
808 registration
->waiting_version());
809 attrs
->active
= provider_host
->GetOrCreateServiceWorkerHandle(
810 registration
->active_version());
813 void ServiceWorkerDispatcherHost::RegistrationComplete(
817 ServiceWorkerStatusCode status
,
818 const std::string
& status_message
,
819 int64 registration_id
) {
823 ServiceWorkerProviderHost
* provider_host
=
824 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
826 return; // The provider has already been destroyed.
828 if (status
!= SERVICE_WORKER_OK
) {
829 SendRegistrationError(thread_id
, request_id
, status
, status_message
);
833 ServiceWorkerRegistration
* registration
=
834 GetContext()->GetLiveRegistration(registration_id
);
835 DCHECK(registration
);
837 ServiceWorkerRegistrationObjectInfo info
;
838 ServiceWorkerVersionAttributes attrs
;
839 GetRegistrationObjectInfoAndVersionAttributes(
840 provider_host
->AsWeakPtr(), registration
, &info
, &attrs
);
842 Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
843 thread_id
, request_id
, info
, attrs
));
844 TRACE_EVENT_ASYNC_END1("ServiceWorker",
845 "ServiceWorkerDispatcherHost::RegisterServiceWorker",
851 void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
852 int embedded_worker_id
) {
853 TRACE_EVENT0("ServiceWorker",
854 "ServiceWorkerDispatcherHost::OnWorkerReadyForInspection");
857 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
858 if (!registry
->CanHandle(embedded_worker_id
))
860 registry
->OnWorkerReadyForInspection(render_process_id_
, embedded_worker_id
);
863 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(
864 int embedded_worker_id
,
867 TRACE_EVENT0("ServiceWorker",
868 "ServiceWorkerDispatcherHost::OnWorkerScriptLoaded");
872 ServiceWorkerProviderHost
* provider_host
=
873 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
874 if (!provider_host
) {
875 bad_message::ReceivedBadMessage(
876 this, bad_message::SWDH_WORKER_SCRIPT_LOAD_NO_HOST
);
880 provider_host
->SetReadyToSendMessagesToWorker(thread_id
);
882 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
883 if (!registry
->CanHandle(embedded_worker_id
))
885 registry
->OnWorkerScriptLoaded(
886 render_process_id_
, thread_id
, embedded_worker_id
);
889 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
890 int embedded_worker_id
) {
891 TRACE_EVENT0("ServiceWorker",
892 "ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed");
895 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
896 if (!registry
->CanHandle(embedded_worker_id
))
898 registry
->OnWorkerScriptLoadFailed(render_process_id_
, embedded_worker_id
);
901 void ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated(
902 int embedded_worker_id
,
904 TRACE_EVENT0("ServiceWorker",
905 "ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated");
908 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
909 if (!registry
->CanHandle(embedded_worker_id
))
911 registry
->OnWorkerScriptEvaluated(
912 render_process_id_
, embedded_worker_id
, success
);
915 void ServiceWorkerDispatcherHost::OnWorkerStarted(int embedded_worker_id
) {
916 TRACE_EVENT0("ServiceWorker",
917 "ServiceWorkerDispatcherHost::OnWorkerStarted");
920 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
921 if (!registry
->CanHandle(embedded_worker_id
))
923 registry
->OnWorkerStarted(render_process_id_
, embedded_worker_id
);
926 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id
) {
927 TRACE_EVENT0("ServiceWorker",
928 "ServiceWorkerDispatcherHost::OnWorkerStopped");
931 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
932 if (!registry
->CanHandle(embedded_worker_id
))
934 registry
->OnWorkerStopped(render_process_id_
, embedded_worker_id
);
937 void ServiceWorkerDispatcherHost::OnReportException(
938 int embedded_worker_id
,
939 const base::string16
& error_message
,
942 const GURL
& source_url
) {
943 TRACE_EVENT0("ServiceWorker",
944 "ServiceWorkerDispatcherHost::OnReportException");
947 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
948 if (!registry
->CanHandle(embedded_worker_id
))
950 registry
->OnReportException(embedded_worker_id
,
957 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
958 int embedded_worker_id
,
959 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params
& params
) {
960 TRACE_EVENT0("ServiceWorker",
961 "ServiceWorkerDispatcherHost::OnReportConsoleMessage");
964 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
965 if (!registry
->CanHandle(embedded_worker_id
))
967 registry
->OnReportConsoleMessage(embedded_worker_id
,
968 params
.source_identifier
,
969 params
.message_level
,
975 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
977 TRACE_EVENT0("ServiceWorker",
978 "ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount");
979 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
981 bad_message::ReceivedBadMessage(
982 this, bad_message::SWDH_INCREMENT_WORKER_BAD_HANDLE
);
985 handle
->IncrementRefCount();
988 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
990 TRACE_EVENT0("ServiceWorker",
991 "ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount");
992 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
994 bad_message::ReceivedBadMessage(
995 this, bad_message::SWDH_DECREMENT_WORKER_BAD_HANDLE
);
998 handle
->DecrementRefCount();
999 if (handle
->HasNoRefCount())
1000 handles_
.Remove(handle_id
);
1003 void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
1004 int registration_handle_id
) {
1005 TRACE_EVENT0("ServiceWorker",
1006 "ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount");
1007 ServiceWorkerRegistrationHandle
* handle
=
1008 registration_handles_
.Lookup(registration_handle_id
);
1010 bad_message::ReceivedBadMessage(
1011 this, bad_message::SWDH_INCREMENT_REGISTRATION_BAD_HANDLE
);
1014 handle
->IncrementRefCount();
1017 void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
1018 int registration_handle_id
) {
1019 TRACE_EVENT0("ServiceWorker",
1020 "ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount");
1021 ServiceWorkerRegistrationHandle
* handle
=
1022 registration_handles_
.Lookup(registration_handle_id
);
1024 bad_message::ReceivedBadMessage(
1025 this, bad_message::SWDH_DECREMENT_REGISTRATION_BAD_HANDLE
);
1028 handle
->DecrementRefCount();
1029 if (handle
->HasNoRefCount())
1030 registration_handles_
.Remove(registration_handle_id
);
1033 void ServiceWorkerDispatcherHost::UnregistrationComplete(
1036 ServiceWorkerStatusCode status
) {
1037 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
) {
1038 SendUnregistrationError(thread_id
, request_id
, status
);
1041 const bool is_success
= (status
== SERVICE_WORKER_OK
);
1042 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id
,
1045 TRACE_EVENT_ASYNC_END1(
1047 "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
1052 void ServiceWorkerDispatcherHost::GetRegistrationComplete(
1056 ServiceWorkerStatusCode status
,
1057 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
1058 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1059 "ServiceWorkerDispatcherHost::GetRegistration",
1062 registration
.get() ? registration
->id()
1063 : kInvalidServiceWorkerRegistrationId
);
1068 ServiceWorkerProviderHost
* provider_host
=
1069 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
1071 return; // The provider has already been destroyed.
1073 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
) {
1074 SendGetRegistrationError(thread_id
, request_id
, status
);
1078 ServiceWorkerRegistrationObjectInfo info
;
1079 ServiceWorkerVersionAttributes attrs
;
1080 if (status
== SERVICE_WORKER_OK
) {
1081 DCHECK(registration
.get());
1082 if (!registration
->is_uninstalling()) {
1083 GetRegistrationObjectInfoAndVersionAttributes(
1084 provider_host
->AsWeakPtr(), registration
.get(), &info
, &attrs
);
1088 Send(new ServiceWorkerMsg_DidGetRegistration(
1089 thread_id
, request_id
, info
, attrs
));
1092 void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
1096 const std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>&
1098 TRACE_EVENT_ASYNC_END0("ServiceWorker",
1099 "ServiceWorkerDispatcherHost::GetRegistrations",
1104 ServiceWorkerProviderHost
* provider_host
=
1105 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
1107 return; // The provider has already been destroyed.
1109 std::vector
<ServiceWorkerRegistrationObjectInfo
> object_infos
;
1110 std::vector
<ServiceWorkerVersionAttributes
> version_attrs
;
1112 for (const auto& registration
: registrations
) {
1113 DCHECK(registration
.get());
1114 if (!registration
->is_uninstalling()) {
1115 ServiceWorkerRegistrationObjectInfo object_info
;
1116 ServiceWorkerVersionAttributes version_attr
;
1117 GetRegistrationObjectInfoAndVersionAttributes(
1118 provider_host
->AsWeakPtr(), registration
.get(), &object_info
,
1120 object_infos
.push_back(object_info
);
1121 version_attrs
.push_back(version_attr
);
1125 Send(new ServiceWorkerMsg_DidGetRegistrations(thread_id
, request_id
,
1126 object_infos
, version_attrs
));
1129 void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
1132 base::WeakPtr
<ServiceWorkerProviderHost
> provider_host
,
1133 ServiceWorkerRegistration
* registration
) {
1134 DCHECK(registration
);
1135 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1136 "ServiceWorkerDispatcherHost::GetRegistrationForReady",
1139 registration
? registration
->id()
1140 : kInvalidServiceWorkerRegistrationId
);
1145 ServiceWorkerRegistrationObjectInfo info
;
1146 ServiceWorkerVersionAttributes attrs
;
1147 GetRegistrationObjectInfoAndVersionAttributes(
1148 provider_host
, registration
, &info
, &attrs
);
1149 Send(new ServiceWorkerMsg_DidGetRegistrationForReady(
1150 thread_id
, request_id
, info
, attrs
));
1153 void ServiceWorkerDispatcherHost::SendRegistrationError(
1156 ServiceWorkerStatusCode status
,
1157 const std::string
& status_message
) {
1158 base::string16 error_message
;
1159 blink::WebServiceWorkerError::ErrorType error_type
;
1160 GetServiceWorkerRegistrationStatusResponse(status
, status_message
,
1161 &error_type
, &error_message
);
1162 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
1163 thread_id
, request_id
, error_type
,
1164 base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix
) + error_message
));
1167 void ServiceWorkerDispatcherHost::SendUnregistrationError(
1170 ServiceWorkerStatusCode status
) {
1171 base::string16 error_message
;
1172 blink::WebServiceWorkerError::ErrorType error_type
;
1173 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1175 Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
1176 thread_id
, request_id
, error_type
,
1177 base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix
) + error_message
));
1180 void ServiceWorkerDispatcherHost::SendGetRegistrationError(
1183 ServiceWorkerStatusCode status
) {
1184 base::string16 error_message
;
1185 blink::WebServiceWorkerError::ErrorType error_type
;
1186 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1188 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
1189 thread_id
, request_id
, error_type
,
1190 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
1194 void ServiceWorkerDispatcherHost::SendGetRegistrationsError(
1197 ServiceWorkerStatusCode status
) {
1198 base::string16 error_message
;
1199 blink::WebServiceWorkerError::ErrorType error_type
;
1200 GetServiceWorkerRegistrationStatusResponse(status
, std::string(), &error_type
,
1202 Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
1203 thread_id
, request_id
, error_type
,
1204 base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix
) +
1208 ServiceWorkerContextCore
* ServiceWorkerDispatcherHost::GetContext() {
1209 if (!context_wrapper_
.get())
1211 return context_wrapper_
->context();
1214 void ServiceWorkerDispatcherHost::OnTerminateWorker(int handle_id
) {
1215 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
1217 bad_message::ReceivedBadMessage(this,
1218 bad_message::SWDH_TERMINATE_BAD_HANDLE
);
1221 handle
->version()->StopWorker(
1222 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
1225 } // namespace content