Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_dispatcher_host.cc
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/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"
21 #include "url/gurl.h"
22
23 using blink::WebServiceWorkerError;
24
25 namespace content {
26
27 namespace {
28
29 const char kDisabledErrorMessage[] =
30     "ServiceWorker is disabled";
31 const char kDomainMismatchErrorMessage[] =
32     "Scope and scripts do not have the same origin";
33
34 const uint32 kFilteredMessageClasses[] = {
35   ServiceWorkerMsgStart,
36   EmbeddedWorkerMsgStart,
37 };
38
39 }  // namespace
40
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) {
49 }
50
51 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
52   if (context_) {
53     context_->RemoveAllProviderHostsForProcess(render_process_id_);
54     context_->embedded_worker_registry()->RemoveChildProcessSender(
55         render_process_id_);
56   }
57 }
58
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)));
66       return;
67   }
68   context_ = context_wrapper->context()->AsWeakPtr();
69   context_->embedded_worker_registry()->AddChildProcessSender(
70       render_process_id_, this);
71 }
72
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]);
80   }
81 }
82
83 void ServiceWorkerDispatcherHost::OnDestruct() const {
84   BrowserThread::DeleteOnIOThread::Destruct(this);
85 }
86
87 bool ServiceWorkerDispatcherHost::OnMessageReceived(
88     const IPC::Message& message,
89     bool* message_was_ok) {
90   bool handled = true;
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,
98                         OnProviderCreated)
99     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
100                         OnProviderDestroyed)
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,
110                         OnWorkerStarted)
111     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
112                         OnWorkerStopped)
113     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
114                         OnReportException)
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()
123
124   if (!handled && context_) {
125     handled = context_->embedded_worker_registry()->OnMessageReceived(message);
126     if (!handled)
127       BadMessageReceived();
128   }
129
130   return handled;
131 }
132
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.
137     return true;
138   }
139
140   pending_messages_.push_back(message);
141   return true;
142 }
143
144 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
145     scoped_ptr<ServiceWorkerHandle> handle) {
146   int handle_id = handle->handle_id();
147   handles_.AddWithID(handle.release(), handle_id);
148 }
149
150 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
151     int thread_id,
152     int request_id,
153     int provider_id,
154     const GURL& pattern,
155     const GURL& script_url) {
156   if (!context_ || !ServiceWorkerUtils::IsFeatureEnabled()) {
157     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
158         thread_id,
159         request_id,
160         WebServiceWorkerError::DisabledError,
161         base::ASCIIToUTF16(kDisabledErrorMessage)));
162     return;
163   }
164
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(
170         thread_id,
171         request_id,
172         WebServiceWorkerError::SecurityError,
173         base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
174     return;
175   }
176
177   ServiceWorkerProviderHost* provider_host = context_->GetProviderHost(
178       render_process_id_, provider_id);
179   if (!provider_host) {
180     BadMessageReceived();
181     return;
182   }
183
184   context_->RegisterServiceWorker(
185       pattern,
186       script_url,
187       render_process_id_,
188       provider_host,
189       base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
190                  this,
191                  thread_id,
192                  request_id));
193 }
194
195 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
196     int thread_id,
197     int request_id,
198     int provider_id,
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(
205         thread_id,
206         request_id,
207         blink::WebServiceWorkerError::DisabledError,
208         base::ASCIIToUTF16(kDisabledErrorMessage)));
209     return;
210   }
211
212   ServiceWorkerProviderHost* provider_host = context_->GetProviderHost(
213       render_process_id_, provider_id);
214   if (!provider_host) {
215     BadMessageReceived();
216     return;
217   }
218
219   context_->UnregisterServiceWorker(
220       pattern,
221       base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
222                  this,
223                  thread_id,
224                  request_id));
225 }
226
227 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
228     int handle_id,
229     const base::string16& message,
230     const std::vector<int>& sent_message_port_ids) {
231   if (!context_ || !ServiceWorkerUtils::IsFeatureEnabled())
232     return;
233
234   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
235   if (!handle) {
236     BadMessageReceived();
237     return;
238   }
239
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,
246                                        new_routing_ids),
247       base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
248 }
249
250 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
251   if (!context_)
252     return;
253   if (context_->GetProviderHost(render_process_id_, provider_id)) {
254     BadMessageReceived();
255     return;
256   }
257   scoped_ptr<ServiceWorkerProviderHost> provider_host(
258       new ServiceWorkerProviderHost(
259           render_process_id_, provider_id, context_, this));
260   context_->AddProviderHost(provider_host.Pass());
261 }
262
263 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
264   if (!context_)
265     return;
266   if (!context_->GetProviderHost(render_process_id_, provider_id)) {
267     BadMessageReceived();
268     return;
269   }
270   context_->RemoveProviderHost(render_process_id_, provider_id);
271 }
272
273 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
274     int provider_id, int64 version_id) {
275   if (!context_)
276     return;
277   ServiceWorkerProviderHost* provider_host =
278       context_->GetProviderHost(render_process_id_, provider_id);
279   if (!provider_host || !provider_host->SetHostedVersionId(version_id)) {
280     BadMessageReceived();
281     return;
282   }
283 }
284
285 void ServiceWorkerDispatcherHost::RegistrationComplete(
286     int thread_id,
287     int request_id,
288     ServiceWorkerStatusCode status,
289     int64 registration_id,
290     int64 version_id) {
291   if (!context_)
292     return;
293
294   if (status != SERVICE_WORKER_OK) {
295     SendRegistrationError(thread_id, request_id, status);
296     return;
297   }
298
299   ServiceWorkerVersion* version = context_->GetLiveVersion(version_id);
300   DCHECK(version);
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());
307 }
308
309 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
310   if (!context_)
311     return;
312   context_->embedded_worker_registry()->OnWorkerScriptLoaded(
313       render_process_id_, embedded_worker_id);
314 }
315
316 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
317     int embedded_worker_id) {
318   if (!context_)
319     return;
320   context_->embedded_worker_registry()->OnWorkerScriptLoadFailed(
321       render_process_id_, embedded_worker_id);
322 }
323
324 void ServiceWorkerDispatcherHost::OnWorkerStarted(
325     int thread_id, int embedded_worker_id) {
326   if (!context_)
327     return;
328   context_->embedded_worker_registry()->OnWorkerStarted(
329       render_process_id_, thread_id, embedded_worker_id);
330 }
331
332 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
333   if (!context_)
334     return;
335   context_->embedded_worker_registry()->OnWorkerStopped(
336       render_process_id_, embedded_worker_id);
337 }
338
339 void ServiceWorkerDispatcherHost::OnReportException(
340     int embedded_worker_id,
341     const base::string16& error_message,
342     int line_number,
343     int column_number,
344     const GURL& source_url) {
345   if (!context_)
346     return;
347   context_->embedded_worker_registry()->OnReportException(embedded_worker_id,
348                                                           error_message,
349                                                           line_number,
350                                                           column_number,
351                                                           source_url);
352 }
353
354 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
355     int embedded_worker_id,
356     const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
357   if (!context_)
358     return;
359   context_->embedded_worker_registry()->OnReportConsoleMessage(
360       embedded_worker_id,
361       params.source_identifier,
362       params.message_level,
363       params.message,
364       params.line_number,
365       params.source_url);
366 }
367
368 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
369     int handle_id) {
370   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
371   if (!handle) {
372     BadMessageReceived();
373     return;
374   }
375   handle->IncrementRefCount();
376 }
377
378 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
379     int handle_id) {
380   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
381   if (!handle) {
382     BadMessageReceived();
383     return;
384   }
385   handle->DecrementRefCount();
386   if (handle->HasNoRefCount())
387     handles_.Remove(handle_id);
388 }
389
390 void ServiceWorkerDispatcherHost::UnregistrationComplete(
391     int thread_id,
392     int request_id,
393     ServiceWorkerStatusCode status) {
394   if (status != SERVICE_WORKER_OK) {
395     SendRegistrationError(thread_id, request_id, status);
396     return;
397   }
398
399   Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
400 }
401
402 void ServiceWorkerDispatcherHost::SendRegistrationError(
403     int thread_id,
404     int request_id,
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));
412 }
413
414 }  // namespace content