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/strings/utf_string_conversions.h"
9 #include "content/browser/message_port_message_filter.h"
10 #include "content/browser/message_port_service.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
14 #include "content/browser/service_worker/service_worker_handle.h"
15 #include "content/browser/service_worker/service_worker_registration.h"
16 #include "content/browser/service_worker/service_worker_registration_handle.h"
17 #include "content/browser/service_worker/service_worker_utils.h"
18 #include "content/common/service_worker/embedded_worker_messages.h"
19 #include "content/common/service_worker/service_worker_messages.h"
20 #include "ipc/ipc_message_macros.h"
21 #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
24 using blink::WebServiceWorkerError
;
30 const char kShutdownErrorMessage
[] =
31 "The Service Worker system has shutdown.";
33 const uint32 kFilteredMessageClasses
[] = {
34 ServiceWorkerMsgStart
,
35 EmbeddedWorkerMsgStart
,
38 // TODO(dominicc): When crbug.com/362214 is fixed, make
39 // Can(R|Unr)egisterServiceWorker also check that these are secure
40 // origins to defend against compromised renderers.
41 bool CanRegisterServiceWorker(const GURL
& document_url
,
43 const GURL
& script_url
) {
44 // TODO: Respect Chrome's content settings, if we add a setting for
45 // controlling whether Service Worker is allowed.
46 return document_url
.GetOrigin() == pattern
.GetOrigin() &&
47 document_url
.GetOrigin() == script_url
.GetOrigin();
50 bool CanUnregisterServiceWorker(const GURL
& document_url
,
51 const GURL
& pattern
) {
52 // TODO: Respect Chrome's content settings, if we add a setting for
53 // controlling whether Service Worker is allowed.
54 return document_url
.GetOrigin() == pattern
.GetOrigin();
59 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
60 int render_process_id
,
61 MessagePortMessageFilter
* message_port_message_filter
)
62 : BrowserMessageFilter(kFilteredMessageClasses
,
63 arraysize(kFilteredMessageClasses
)),
64 render_process_id_(render_process_id
),
65 message_port_message_filter_(message_port_message_filter
),
66 channel_ready_(false) {
69 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
71 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_
);
72 GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
77 void ServiceWorkerDispatcherHost::Init(
78 ServiceWorkerContextWrapper
* context_wrapper
) {
79 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
80 BrowserThread::PostTask(
81 BrowserThread::IO
, FROM_HERE
,
82 base::Bind(&ServiceWorkerDispatcherHost::Init
,
83 this, make_scoped_refptr(context_wrapper
)));
86 context_wrapper_
= context_wrapper
;
87 GetContext()->embedded_worker_registry()->AddChildProcessSender(
88 render_process_id_
, this);
91 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender
* sender
) {
92 BrowserMessageFilter::OnFilterAdded(sender
);
93 channel_ready_
= true;
94 std::vector
<IPC::Message
*> messages
;
95 pending_messages_
.release(&messages
);
96 for (size_t i
= 0; i
< messages
.size(); ++i
) {
97 BrowserMessageFilter::Send(messages
[i
]);
101 void ServiceWorkerDispatcherHost::OnDestruct() const {
102 BrowserThread::DeleteOnIOThread::Destruct(this);
105 bool ServiceWorkerDispatcherHost::OnMessageReceived(
106 const IPC::Message
& message
) {
108 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost
, message
)
109 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker
,
110 OnRegisterServiceWorker
)
111 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker
,
112 OnUnregisterServiceWorker
)
113 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated
,
115 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed
,
117 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId
,
118 OnSetHostedVersionId
)
119 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker
,
120 OnPostMessageToWorker
)
121 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection
,
122 OnWorkerReadyForInspection
)
123 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded
,
124 OnWorkerScriptLoaded
)
125 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed
,
126 OnWorkerScriptLoadFailed
)
127 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted
,
129 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped
,
131 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_DidPauseAfterDownload
,
132 OnPausedAfterDownload
)
133 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException
,
135 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage
,
136 OnReportConsoleMessage
)
137 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount
,
138 OnIncrementServiceWorkerRefCount
)
139 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount
,
140 OnDecrementServiceWorkerRefCount
)
141 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount
,
142 OnIncrementRegistrationRefCount
)
143 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount
,
144 OnDecrementRegistrationRefCount
)
145 IPC_MESSAGE_UNHANDLED(handled
= false)
146 IPC_END_MESSAGE_MAP()
148 if (!handled
&& GetContext()) {
150 GetContext()->embedded_worker_registry()->OnMessageReceived(message
);
152 BadMessageReceived();
158 bool ServiceWorkerDispatcherHost::Send(IPC::Message
* message
) {
159 if (channel_ready_
) {
160 BrowserMessageFilter::Send(message
);
161 // Don't bother passing through Send()'s result: it's not reliable.
165 pending_messages_
.push_back(message
);
169 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
170 scoped_ptr
<ServiceWorkerHandle
> handle
) {
171 int handle_id
= handle
->handle_id();
172 handles_
.AddWithID(handle
.release(), handle_id
);
175 void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
176 scoped_ptr
<ServiceWorkerRegistrationHandle
> handle
) {
177 int handle_id
= handle
->handle_id();
178 registration_handles_
.AddWithID(handle
.release(), handle_id
);
181 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
186 const GURL
& script_url
) {
188 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
191 WebServiceWorkerError::ErrorTypeAbort
,
192 base::ASCIIToUTF16(kShutdownErrorMessage
)));
196 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
197 render_process_id_
, provider_id
);
198 if (!provider_host
) {
199 BadMessageReceived();
202 if (!provider_host
->IsContextAlive()) {
203 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
206 WebServiceWorkerError::ErrorTypeAbort
,
207 base::ASCIIToUTF16(kShutdownErrorMessage
)));
211 if (!CanRegisterServiceWorker(
212 provider_host
->document_url(), pattern
, script_url
)) {
213 BadMessageReceived();
216 GetContext()->RegisterServiceWorker(
221 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete
,
228 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
232 const GURL
& pattern
) {
234 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
237 blink::WebServiceWorkerError::ErrorTypeAbort
,
238 base::ASCIIToUTF16(kShutdownErrorMessage
)));
242 ServiceWorkerProviderHost
* provider_host
= GetContext()->GetProviderHost(
243 render_process_id_
, provider_id
);
244 if (!provider_host
) {
245 BadMessageReceived();
248 if (!provider_host
->IsContextAlive()) {
249 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
252 blink::WebServiceWorkerError::ErrorTypeAbort
,
253 base::ASCIIToUTF16(kShutdownErrorMessage
)));
257 if (!CanUnregisterServiceWorker(provider_host
->document_url(), pattern
)) {
258 BadMessageReceived();
262 GetContext()->UnregisterServiceWorker(
264 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete
,
270 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
272 const base::string16
& message
,
273 const std::vector
<int>& sent_message_port_ids
) {
277 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
279 BadMessageReceived();
283 std::vector
<int> new_routing_ids
;
284 message_port_message_filter_
->UpdateMessagePortsWithNewRoutes(
285 sent_message_port_ids
, &new_routing_ids
);
286 handle
->version()->SendMessage(
287 ServiceWorkerMsg_MessageToWorker(message
,
288 sent_message_port_ids
,
290 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
293 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id
) {
296 if (GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
297 BadMessageReceived();
300 scoped_ptr
<ServiceWorkerProviderHost
> provider_host(
301 new ServiceWorkerProviderHost(
302 render_process_id_
, provider_id
, GetContext()->AsWeakPtr(), this));
303 GetContext()->AddProviderHost(provider_host
.Pass());
306 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id
) {
309 if (!GetContext()->GetProviderHost(render_process_id_
, provider_id
)) {
310 BadMessageReceived();
313 GetContext()->RemoveProviderHost(render_process_id_
, provider_id
);
316 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
317 int provider_id
, int64 version_id
) {
320 ServiceWorkerProviderHost
* provider_host
=
321 GetContext()->GetProviderHost(render_process_id_
, provider_id
);
322 if (!provider_host
) {
323 BadMessageReceived();
326 if (!provider_host
->IsContextAlive())
328 if (!provider_host
->SetHostedVersionId(version_id
))
329 BadMessageReceived();
332 ServiceWorkerRegistrationHandle
*
333 ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id
,
334 int64 registration_id
) {
335 for (IDMap
<ServiceWorkerRegistrationHandle
, IDMapOwnPointer
>::iterator
336 iter(®istration_handles_
);
339 ServiceWorkerRegistrationHandle
* handle
= iter
.GetCurrentValue();
341 if (handle
->provider_id() == provider_id
&& handle
->registration() &&
342 handle
->registration()->id() == registration_id
) {
349 void ServiceWorkerDispatcherHost::RegistrationComplete(
353 ServiceWorkerStatusCode status
,
354 int64 registration_id
,
359 if (status
!= SERVICE_WORKER_OK
) {
360 SendRegistrationError(thread_id
, request_id
, status
);
364 ServiceWorkerRegistration
* registration
=
365 GetContext()->GetLiveRegistration(registration_id
);
366 DCHECK(registration
);
368 ServiceWorkerRegistrationHandle
* handle
=
369 FindRegistrationHandle(provider_id
, registration_id
);
370 ServiceWorkerRegistrationObjectInfo info
;
372 handle
->IncrementRefCount();
373 info
= handle
->GetObjectInfo();
375 scoped_ptr
<ServiceWorkerRegistrationHandle
> new_handle(
376 new ServiceWorkerRegistrationHandle(
377 GetContext()->AsWeakPtr(), this, provider_id
, registration
));
378 info
= new_handle
->GetObjectInfo();
379 RegisterServiceWorkerRegistrationHandle(new_handle
.Pass());
382 Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
383 thread_id
, request_id
, info
));
386 void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
387 int embedded_worker_id
) {
390 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
391 if (!registry
->CanHandle(embedded_worker_id
))
393 registry
->OnWorkerReadyForInspection(render_process_id_
, embedded_worker_id
);
396 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(
397 int embedded_worker_id
,
401 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
402 if (!registry
->CanHandle(embedded_worker_id
))
404 registry
->OnWorkerScriptLoaded(
405 render_process_id_
, thread_id
, embedded_worker_id
);
408 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
409 int embedded_worker_id
) {
412 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
413 if (!registry
->CanHandle(embedded_worker_id
))
415 registry
->OnWorkerScriptLoadFailed(render_process_id_
, embedded_worker_id
);
418 void ServiceWorkerDispatcherHost::OnWorkerStarted(int embedded_worker_id
) {
421 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
422 if (!registry
->CanHandle(embedded_worker_id
))
424 registry
->OnWorkerStarted(render_process_id_
, embedded_worker_id
);
427 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id
) {
430 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
431 if (!registry
->CanHandle(embedded_worker_id
))
433 registry
->OnWorkerStopped(render_process_id_
, embedded_worker_id
);
436 void ServiceWorkerDispatcherHost::OnPausedAfterDownload(
437 int embedded_worker_id
) {
440 GetContext()->embedded_worker_registry()->OnPausedAfterDownload(
441 render_process_id_
, embedded_worker_id
);
444 void ServiceWorkerDispatcherHost::OnReportException(
445 int embedded_worker_id
,
446 const base::string16
& error_message
,
449 const GURL
& source_url
) {
452 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
453 if (!registry
->CanHandle(embedded_worker_id
))
455 registry
->OnReportException(embedded_worker_id
,
462 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
463 int embedded_worker_id
,
464 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params
& params
) {
467 EmbeddedWorkerRegistry
* registry
= GetContext()->embedded_worker_registry();
468 if (!registry
->CanHandle(embedded_worker_id
))
470 registry
->OnReportConsoleMessage(embedded_worker_id
,
471 params
.source_identifier
,
472 params
.message_level
,
478 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
480 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
482 BadMessageReceived();
485 handle
->IncrementRefCount();
488 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
490 ServiceWorkerHandle
* handle
= handles_
.Lookup(handle_id
);
492 BadMessageReceived();
495 handle
->DecrementRefCount();
496 if (handle
->HasNoRefCount())
497 handles_
.Remove(handle_id
);
500 void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
501 int registration_handle_id
) {
502 ServiceWorkerRegistrationHandle
* handle
=
503 registration_handles_
.Lookup(registration_handle_id
);
505 BadMessageReceived();
508 handle
->IncrementRefCount();
511 void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
512 int registration_handle_id
) {
513 ServiceWorkerRegistrationHandle
* handle
=
514 registration_handles_
.Lookup(registration_handle_id
);
516 BadMessageReceived();
519 handle
->DecrementRefCount();
520 if (handle
->HasNoRefCount())
521 registration_handles_
.Remove(registration_handle_id
);
524 void ServiceWorkerDispatcherHost::UnregistrationComplete(
527 ServiceWorkerStatusCode status
) {
528 if (status
!= SERVICE_WORKER_OK
) {
529 SendRegistrationError(thread_id
, request_id
, status
);
533 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id
, request_id
));
536 void ServiceWorkerDispatcherHost::SendRegistrationError(
539 ServiceWorkerStatusCode status
) {
540 base::string16 error_message
;
541 blink::WebServiceWorkerError::ErrorType error_type
;
542 GetServiceWorkerRegistrationStatusResponse(
543 status
, &error_type
, &error_message
);
544 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
545 thread_id
, request_id
, error_type
, error_message
));
548 ServiceWorkerContextCore
* ServiceWorkerDispatcherHost::GetContext() {
549 return context_wrapper_
->context();
552 } // namespace content