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.
4
5 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
6
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/service_worker/embedded_worker_registry.h"
9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_context_wrapper.h"
11 #include "content/browser/service_worker/service_worker_provider_host.h"
12 #include "content/common/service_worker_messages.h"
13 #include "ipc/ipc_message_macros.h"
14 #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
15 #include "url/gurl.h"
16
17 using blink::WebServiceWorkerError;
18
19 namespace {
20
21 const char kDisabledErrorMessage[] =
22 "ServiceWorker is disabled";
23 const char kDomainMismatchErrorMessage[] =
24 "Scope and scripts do not have the same origin";
25
26 } // namespace
27
28 namespace content {
29
ServiceWorkerDispatcherHost(int render_process_id)30 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
31 int render_process_id)
32 : render_process_id_(render_process_id) {
33 }
34
~ServiceWorkerDispatcherHost()35 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
36 if (context_) {
37 context_->RemoveAllProviderHostsForProcess(render_process_id_);
38 context_->embedded_worker_registry()->RemoveChildProcessSender(
39 render_process_id_);
40 }
41 }
42
Init(ServiceWorkerContextWrapper * context_wrapper)43 void ServiceWorkerDispatcherHost::Init(
44 ServiceWorkerContextWrapper* context_wrapper) {
45 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
46 BrowserThread::PostTask(
47 BrowserThread::IO, FROM_HERE,
48 base::Bind(&ServiceWorkerDispatcherHost::Init,
49 this, make_scoped_refptr(context_wrapper)));
50 return;
51 }
52 context_ = context_wrapper->context()->AsWeakPtr();
53 context_->embedded_worker_registry()->AddChildProcessSender(
54 render_process_id_, this);
55 }
56
OnDestruct() const57 void ServiceWorkerDispatcherHost::OnDestruct() const {
58 BrowserThread::DeleteOnIOThread::Destruct(this);
59 }
60
OnMessageReceived(const IPC::Message & message,bool * message_was_ok)61 bool ServiceWorkerDispatcherHost::OnMessageReceived(
62 const IPC::Message& message,
63 bool* message_was_ok) {
64 if (IPC_MESSAGE_CLASS(message) != ServiceWorkerMsgStart)
65 return false;
66
67 bool handled = true;
68 IPC_BEGIN_MESSAGE_MAP_EX(
69 ServiceWorkerDispatcherHost, message, *message_was_ok)
70 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker,
71 OnRegisterServiceWorker)
72 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
73 OnUnregisterServiceWorker)
74 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
75 OnProviderCreated)
76 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
77 OnProviderDestroyed)
78 IPC_MESSAGE_UNHANDLED(handled = false)
79 IPC_END_MESSAGE_MAP()
80
81 return handled;
82 }
83
OnRegisterServiceWorker(int32 thread_id,int32 request_id,const GURL & pattern,const GURL & script_url)84 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
85 int32 thread_id,
86 int32 request_id,
87 const GURL& pattern,
88 const GURL& script_url) {
89 if (!context_ || !context_->IsEnabled()) {
90 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
91 thread_id,
92 request_id,
93 WebServiceWorkerError::DisabledError,
94 ASCIIToUTF16(kDisabledErrorMessage)));
95 return;
96 }
97
98 // TODO(alecflett): This check is insufficient for release. Add a
99 // ServiceWorker-specific policy query in
100 // ChildProcessSecurityImpl. See http://crbug.com/311631.
101 if (pattern.GetOrigin() != script_url.GetOrigin()) {
102 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
103 thread_id,
104 request_id,
105 WebServiceWorkerError::SecurityError,
106 ASCIIToUTF16(kDomainMismatchErrorMessage)));
107 return;
108 }
109
110 context_->RegisterServiceWorker(
111 pattern,
112 script_url,
113 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
114 this,
115 thread_id,
116 request_id));
117 }
118
OnUnregisterServiceWorker(int32 thread_id,int32 request_id,const GURL & pattern)119 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
120 int32 thread_id,
121 int32 request_id,
122 const GURL& pattern) {
123 // TODO(alecflett): This check is insufficient for release. Add a
124 // ServiceWorker-specific policy query in
125 // ChildProcessSecurityImpl. See http://crbug.com/311631.
126 if (!context_ || !context_->IsEnabled()) {
127 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
128 thread_id,
129 request_id,
130 blink::WebServiceWorkerError::DisabledError,
131 ASCIIToUTF16(kDisabledErrorMessage)));
132 return;
133 }
134
135 context_->UnregisterServiceWorker(
136 pattern,
137 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
138 this,
139 thread_id,
140 request_id));
141 }
142
OnProviderCreated(int provider_id)143 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
144 if (!context_)
145 return;
146 if (context_->GetProviderHost(render_process_id_, provider_id)) {
147 BadMessageReceived();
148 return;
149 }
150 scoped_ptr<ServiceWorkerProviderHost> provider_host(
151 new ServiceWorkerProviderHost(render_process_id_, provider_id));
152 context_->AddProviderHost(provider_host.Pass());
153 }
154
OnProviderDestroyed(int provider_id)155 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
156 if (!context_)
157 return;
158 if (!context_->GetProviderHost(render_process_id_, provider_id)) {
159 BadMessageReceived();
160 return;
161 }
162 context_->RemoveProviderHost(render_process_id_, provider_id);
163 }
164
RegistrationComplete(int32 thread_id,int32 request_id,ServiceWorkerRegistrationStatus status,int64 registration_id)165 void ServiceWorkerDispatcherHost::RegistrationComplete(
166 int32 thread_id,
167 int32 request_id,
168 ServiceWorkerRegistrationStatus status,
169 int64 registration_id) {
170 if (status != REGISTRATION_OK) {
171 SendRegistrationError(thread_id, request_id, status);
172 return;
173 }
174
175 Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
176 thread_id, request_id, registration_id));
177 }
178
UnregistrationComplete(int32 thread_id,int32 request_id,ServiceWorkerRegistrationStatus status)179 void ServiceWorkerDispatcherHost::UnregistrationComplete(
180 int32 thread_id,
181 int32 request_id,
182 ServiceWorkerRegistrationStatus status) {
183 if (status != REGISTRATION_OK) {
184 SendRegistrationError(thread_id, request_id, status);
185 return;
186 }
187
188 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
189 }
190
SendRegistrationError(int32 thread_id,int32 request_id,ServiceWorkerRegistrationStatus status)191 void ServiceWorkerDispatcherHost::SendRegistrationError(
192 int32 thread_id,
193 int32 request_id,
194 ServiceWorkerRegistrationStatus status) {
195 base::string16 error_message;
196 blink::WebServiceWorkerError::ErrorType error_type;
197 GetServiceWorkerRegistrationStatusResponse(
198 status, &error_type, &error_message);
199 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
200 thread_id, request_id, error_type, error_message));
201 }
202
203 } // namespace content
204