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_utils.h"
17 #include "content/common/service_worker/embedded_worker_messages.h"
18 #include "content/common/service_worker/service_worker_messages.h"
19 #include "ipc/ipc_message_macros.h"
20 #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
23 using blink::WebServiceWorkerError;
29 const char kDisabledErrorMessage[] =
30 "ServiceWorker is disabled";
31 const char kDomainMismatchErrorMessage[] =
32 "Scope and scripts do not have the same origin";
34 const uint32 kFilteredMessageClasses[] = {
35 ServiceWorkerMsgStart,
36 EmbeddedWorkerMsgStart,
41 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
42 int render_process_id,
43 MessagePortMessageFilter* message_port_message_filter)
44 : BrowserMessageFilter(kFilteredMessageClasses,
45 arraysize(kFilteredMessageClasses)),
46 render_process_id_(render_process_id),
47 message_port_message_filter_(message_port_message_filter),
48 channel_ready_(false) {
51 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
53 context_->RemoveAllProviderHostsForProcess(render_process_id_);
54 context_->embedded_worker_registry()->RemoveChildProcessSender(
59 void ServiceWorkerDispatcherHost::Init(
60 ServiceWorkerContextWrapper* context_wrapper) {
61 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
62 BrowserThread::PostTask(
63 BrowserThread::IO, FROM_HERE,
64 base::Bind(&ServiceWorkerDispatcherHost::Init,
65 this, make_scoped_refptr(context_wrapper)));
68 context_ = context_wrapper->context()->AsWeakPtr();
69 context_->embedded_worker_registry()->AddChildProcessSender(
70 render_process_id_, this);
73 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Channel* channel) {
74 BrowserMessageFilter::OnFilterAdded(channel);
75 channel_ready_ = true;
76 std::vector<IPC::Message*> messages;
77 pending_messages_.release(&messages);
78 for (size_t i = 0; i < messages.size(); ++i) {
79 BrowserMessageFilter::Send(messages[i]);
83 void ServiceWorkerDispatcherHost::OnDestruct() const {
84 BrowserThread::DeleteOnIOThread::Destruct(this);
87 bool ServiceWorkerDispatcherHost::OnMessageReceived(
88 const IPC::Message& message,
89 bool* message_was_ok) {
91 IPC_BEGIN_MESSAGE_MAP_EX(
92 ServiceWorkerDispatcherHost, message, *message_was_ok)
93 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker,
94 OnRegisterServiceWorker)
95 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
96 OnUnregisterServiceWorker)
97 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
99 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
101 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId,
102 OnSetHostedVersionId)
103 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
104 OnPostMessageToWorker)
105 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
106 OnWorkerScriptLoaded)
107 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed,
108 OnWorkerScriptLoadFailed)
109 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
111 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
113 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
115 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
116 OnReportConsoleMessage)
117 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
118 OnIncrementServiceWorkerRefCount)
119 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
120 OnDecrementServiceWorkerRefCount)
121 IPC_MESSAGE_UNHANDLED(handled = false)
122 IPC_END_MESSAGE_MAP()
124 if (!handled && context_) {
125 handled = context_->embedded_worker_registry()->OnMessageReceived(message);
127 BadMessageReceived();
133 bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
134 if (channel_ready_) {
135 BrowserMessageFilter::Send(message);
136 // Don't bother passing through Send()'s result: it's not reliable.
140 pending_messages_.push_back(message);
144 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
145 scoped_ptr<ServiceWorkerHandle> handle) {
146 int handle_id = handle->handle_id();
147 handles_.AddWithID(handle.release(), handle_id);
150 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
155 const GURL& script_url) {
156 if (!context_ || !ServiceWorkerUtils::IsFeatureEnabled()) {
157 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
160 WebServiceWorkerError::DisabledError,
161 base::ASCIIToUTF16(kDisabledErrorMessage)));
165 // TODO(alecflett): This check is insufficient for release. Add a
166 // ServiceWorker-specific policy query in
167 // ChildProcessSecurityImpl. See http://crbug.com/311631.
168 if (pattern.GetOrigin() != script_url.GetOrigin()) {
169 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
172 WebServiceWorkerError::SecurityError,
173 base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
177 ServiceWorkerProviderHost* provider_host = context_->GetProviderHost(
178 render_process_id_, provider_id);
179 if (!provider_host) {
180 BadMessageReceived();
184 context_->RegisterServiceWorker(
189 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
195 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
199 const GURL& pattern) {
200 // TODO(alecflett): This check is insufficient for release. Add a
201 // ServiceWorker-specific policy query in
202 // ChildProcessSecurityImpl. See http://crbug.com/311631.
203 if (!context_ || !ServiceWorkerUtils::IsFeatureEnabled()) {
204 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
207 blink::WebServiceWorkerError::DisabledError,
208 base::ASCIIToUTF16(kDisabledErrorMessage)));
212 ServiceWorkerProviderHost* provider_host = context_->GetProviderHost(
213 render_process_id_, provider_id);
214 if (!provider_host) {
215 BadMessageReceived();
219 context_->UnregisterServiceWorker(
221 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
227 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
229 const base::string16& message,
230 const std::vector<int>& sent_message_port_ids) {
231 if (!context_ || !ServiceWorkerUtils::IsFeatureEnabled())
234 ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
236 BadMessageReceived();
240 std::vector<int> new_routing_ids;
241 message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
242 sent_message_port_ids, &new_routing_ids);
243 handle->version()->SendMessage(
244 ServiceWorkerMsg_MessageToWorker(message,
245 sent_message_port_ids,
247 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
250 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
253 if (context_->GetProviderHost(render_process_id_, provider_id)) {
254 BadMessageReceived();
257 scoped_ptr<ServiceWorkerProviderHost> provider_host(
258 new ServiceWorkerProviderHost(
259 render_process_id_, provider_id, context_, this));
260 context_->AddProviderHost(provider_host.Pass());
263 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
266 if (!context_->GetProviderHost(render_process_id_, provider_id)) {
267 BadMessageReceived();
270 context_->RemoveProviderHost(render_process_id_, provider_id);
273 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
274 int provider_id, int64 version_id) {
277 ServiceWorkerProviderHost* provider_host =
278 context_->GetProviderHost(render_process_id_, provider_id);
279 if (!provider_host || !provider_host->SetHostedVersionId(version_id)) {
280 BadMessageReceived();
285 void ServiceWorkerDispatcherHost::RegistrationComplete(
288 ServiceWorkerStatusCode status,
289 int64 registration_id,
294 if (status != SERVICE_WORKER_OK) {
295 SendRegistrationError(thread_id, request_id, status);
299 ServiceWorkerVersion* version = context_->GetLiveVersion(version_id);
301 DCHECK_EQ(registration_id, version->registration_id());
302 scoped_ptr<ServiceWorkerHandle> handle =
303 ServiceWorkerHandle::Create(context_, this, thread_id, version);
304 Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
305 thread_id, request_id, handle->GetObjectInfo()));
306 RegisterServiceWorkerHandle(handle.Pass());
309 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
312 context_->embedded_worker_registry()->OnWorkerScriptLoaded(
313 render_process_id_, embedded_worker_id);
316 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
317 int embedded_worker_id) {
320 context_->embedded_worker_registry()->OnWorkerScriptLoadFailed(
321 render_process_id_, embedded_worker_id);
324 void ServiceWorkerDispatcherHost::OnWorkerStarted(
325 int thread_id, int embedded_worker_id) {
328 context_->embedded_worker_registry()->OnWorkerStarted(
329 render_process_id_, thread_id, embedded_worker_id);
332 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
335 context_->embedded_worker_registry()->OnWorkerStopped(
336 render_process_id_, embedded_worker_id);
339 void ServiceWorkerDispatcherHost::OnReportException(
340 int embedded_worker_id,
341 const base::string16& error_message,
344 const GURL& source_url) {
347 context_->embedded_worker_registry()->OnReportException(embedded_worker_id,
354 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
355 int embedded_worker_id,
356 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
359 context_->embedded_worker_registry()->OnReportConsoleMessage(
361 params.source_identifier,
362 params.message_level,
368 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
370 ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
372 BadMessageReceived();
375 handle->IncrementRefCount();
378 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
380 ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
382 BadMessageReceived();
385 handle->DecrementRefCount();
386 if (handle->HasNoRefCount())
387 handles_.Remove(handle_id);
390 void ServiceWorkerDispatcherHost::UnregistrationComplete(
393 ServiceWorkerStatusCode status) {
394 if (status != SERVICE_WORKER_OK) {
395 SendRegistrationError(thread_id, request_id, status);
399 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
402 void ServiceWorkerDispatcherHost::SendRegistrationError(
405 ServiceWorkerStatusCode status) {
406 base::string16 error_message;
407 blink::WebServiceWorkerError::ErrorType error_type;
408 GetServiceWorkerRegistrationStatusResponse(
409 status, &error_type, &error_message);
410 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
411 thread_id, request_id, error_type, error_message));
414 } // namespace content