Upstream version 9.38.198.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_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"
22 #include "url/gurl.h"
23
24 using blink::WebServiceWorkerError;
25
26 namespace content {
27
28 namespace {
29
30 const char kShutdownErrorMessage[] =
31     "The Service Worker system has shutdown.";
32
33 const uint32 kFilteredMessageClasses[] = {
34   ServiceWorkerMsgStart,
35   EmbeddedWorkerMsgStart,
36 };
37
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,
42                               const GURL& pattern,
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();
48 }
49
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();
55 }
56
57 }  // namespace
58
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) {
67 }
68
69 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
70   if (GetContext()) {
71     GetContext()->RemoveAllProviderHostsForProcess(render_process_id_);
72     GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
73         render_process_id_);
74   }
75 }
76
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)));
84     return;
85   }
86   context_wrapper_ = context_wrapper;
87   GetContext()->embedded_worker_registry()->AddChildProcessSender(
88       render_process_id_, this);
89 }
90
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]);
98   }
99 }
100
101 void ServiceWorkerDispatcherHost::OnDestruct() const {
102   BrowserThread::DeleteOnIOThread::Destruct(this);
103 }
104
105 bool ServiceWorkerDispatcherHost::OnMessageReceived(
106     const IPC::Message& message) {
107   bool handled = true;
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,
114                         OnProviderCreated)
115     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
116                         OnProviderDestroyed)
117     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId,
118                         OnSetHostedVersionId)
119     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
120                         OnPostMessageToWorker)
121     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
122                         OnWorkerScriptLoaded)
123     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed,
124                         OnWorkerScriptLoadFailed)
125     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
126                         OnWorkerStarted)
127     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
128                         OnWorkerStopped)
129     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_DidPauseAfterDownload,
130                         OnPausedAfterDownload)
131     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
132                         OnReportException)
133     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
134                         OnReportConsoleMessage)
135     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
136                         OnIncrementServiceWorkerRefCount)
137     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
138                         OnDecrementServiceWorkerRefCount)
139     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount,
140                         OnIncrementRegistrationRefCount)
141     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount,
142                         OnDecrementRegistrationRefCount)
143     IPC_MESSAGE_UNHANDLED(handled = false)
144   IPC_END_MESSAGE_MAP()
145
146   if (!handled && GetContext()) {
147     handled =
148         GetContext()->embedded_worker_registry()->OnMessageReceived(message);
149     if (!handled)
150       BadMessageReceived();
151   }
152
153   return handled;
154 }
155
156 bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
157   if (channel_ready_) {
158     BrowserMessageFilter::Send(message);
159     // Don't bother passing through Send()'s result: it's not reliable.
160     return true;
161   }
162
163   pending_messages_.push_back(message);
164   return true;
165 }
166
167 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
168     scoped_ptr<ServiceWorkerHandle> handle) {
169   int handle_id = handle->handle_id();
170   handles_.AddWithID(handle.release(), handle_id);
171 }
172
173 void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
174     scoped_ptr<ServiceWorkerRegistrationHandle> handle) {
175   int handle_id = handle->handle_id();
176   registration_handles_.AddWithID(handle.release(), handle_id);
177 }
178
179 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
180     int thread_id,
181     int request_id,
182     int provider_id,
183     const GURL& pattern,
184     const GURL& script_url) {
185   if (!GetContext()) {
186     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
187         thread_id,
188         request_id,
189         WebServiceWorkerError::ErrorTypeAbort,
190         base::ASCIIToUTF16(kShutdownErrorMessage)));
191     return;
192   }
193
194   ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
195       render_process_id_, provider_id);
196   if (!provider_host) {
197     BadMessageReceived();
198     return;
199   }
200   if (!provider_host->IsContextAlive()) {
201     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
202         thread_id,
203         request_id,
204         WebServiceWorkerError::ErrorTypeAbort,
205         base::ASCIIToUTF16(kShutdownErrorMessage)));
206     return;
207   }
208
209   if (!CanRegisterServiceWorker(
210       provider_host->document_url(), pattern, script_url)) {
211     BadMessageReceived();
212     return;
213   }
214   GetContext()->RegisterServiceWorker(
215       pattern,
216       script_url,
217       render_process_id_,
218       provider_host,
219       base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
220                  this,
221                  thread_id,
222                  provider_id,
223                  request_id));
224 }
225
226 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
227     int thread_id,
228     int request_id,
229     int provider_id,
230     const GURL& pattern) {
231   if (!GetContext()) {
232     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
233         thread_id,
234         request_id,
235         blink::WebServiceWorkerError::ErrorTypeAbort,
236         base::ASCIIToUTF16(kShutdownErrorMessage)));
237     return;
238   }
239
240   ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
241       render_process_id_, provider_id);
242   if (!provider_host) {
243     BadMessageReceived();
244     return;
245   }
246   if (!provider_host->IsContextAlive()) {
247     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
248         thread_id,
249         request_id,
250         blink::WebServiceWorkerError::ErrorTypeAbort,
251         base::ASCIIToUTF16(kShutdownErrorMessage)));
252     return;
253   }
254
255   if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) {
256     BadMessageReceived();
257     return;
258   }
259
260   GetContext()->UnregisterServiceWorker(
261       pattern,
262       base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
263                  this,
264                  thread_id,
265                  request_id));
266 }
267
268 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
269     int handle_id,
270     const base::string16& message,
271     const std::vector<int>& sent_message_port_ids) {
272   if (!GetContext())
273     return;
274
275   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
276   if (!handle) {
277     BadMessageReceived();
278     return;
279   }
280
281   std::vector<int> new_routing_ids;
282   message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
283       sent_message_port_ids, &new_routing_ids);
284   handle->version()->SendMessage(
285       ServiceWorkerMsg_MessageToWorker(message,
286                                        sent_message_port_ids,
287                                        new_routing_ids),
288       base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
289 }
290
291 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
292   if (!GetContext())
293     return;
294   if (GetContext()->GetProviderHost(render_process_id_, provider_id)) {
295     BadMessageReceived();
296     return;
297   }
298   scoped_ptr<ServiceWorkerProviderHost> provider_host(
299       new ServiceWorkerProviderHost(
300           render_process_id_, provider_id, GetContext()->AsWeakPtr(), this));
301   GetContext()->AddProviderHost(provider_host.Pass());
302 }
303
304 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
305   if (!GetContext())
306     return;
307   if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
308     BadMessageReceived();
309     return;
310   }
311   GetContext()->RemoveProviderHost(render_process_id_, provider_id);
312 }
313
314 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
315     int provider_id, int64 version_id) {
316   if (!GetContext())
317     return;
318   ServiceWorkerProviderHost* provider_host =
319       GetContext()->GetProviderHost(render_process_id_, provider_id);
320   if (!provider_host) {
321     BadMessageReceived();
322     return;
323   }
324   if (!provider_host->IsContextAlive())
325     return;
326   if (!provider_host->SetHostedVersionId(version_id))
327     BadMessageReceived();
328 }
329
330 ServiceWorkerHandle* ServiceWorkerDispatcherHost::FindHandle(int provider_id,
331                                                              int64 version_id) {
332   for (IDMap<ServiceWorkerHandle, IDMapOwnPointer>::iterator iter(&handles_);
333        !iter.IsAtEnd();
334        iter.Advance()) {
335     ServiceWorkerHandle* handle = iter.GetCurrentValue();
336     DCHECK(handle);
337     if (handle->provider_id() == provider_id && handle->version() &&
338         handle->version()->version_id() == version_id) {
339       return handle;
340     }
341   }
342   return NULL;
343 }
344
345 ServiceWorkerRegistrationHandle*
346 ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
347                                                     int64 registration_id) {
348   for (IDMap<ServiceWorkerRegistrationHandle, IDMapOwnPointer>::iterator
349            iter(&registration_handles_);
350        !iter.IsAtEnd();
351        iter.Advance()) {
352     ServiceWorkerRegistrationHandle* handle = iter.GetCurrentValue();
353     DCHECK(handle);
354     if (handle->provider_id() == provider_id && handle->registration() &&
355         handle->registration()->id() == registration_id) {
356       return handle;
357     }
358   }
359   return NULL;
360 }
361
362 void ServiceWorkerDispatcherHost::RegistrationComplete(
363     int thread_id,
364     int provider_id,
365     int request_id,
366     ServiceWorkerStatusCode status,
367     int64 registration_id,
368     int64 version_id) {
369   if (!GetContext())
370     return;
371
372   if (status != SERVICE_WORKER_OK) {
373     SendRegistrationError(thread_id, request_id, status);
374     return;
375   }
376
377   ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
378   DCHECK(version);
379   DCHECK_EQ(registration_id, version->registration_id());
380   ServiceWorkerObjectInfo info;
381
382   ServiceWorkerHandle* handle = FindHandle(provider_id, version_id);
383   if (handle) {
384     DCHECK_EQ(thread_id, handle->thread_id());
385     info = handle->GetObjectInfo();
386     handle->IncrementRefCount();
387   } else {
388     scoped_ptr<ServiceWorkerHandle> new_handle = ServiceWorkerHandle::Create(
389         GetContext()->AsWeakPtr(), this, thread_id, provider_id, version);
390     info = new_handle->GetObjectInfo();
391     RegisterServiceWorkerHandle(new_handle.Pass());
392   }
393
394   ServiceWorkerRegistration* registration =
395       GetContext()->GetLiveRegistration(registration_id);
396   DCHECK(registration);
397
398   ServiceWorkerRegistrationHandle* registration_handle =
399       FindRegistrationHandle(provider_id, registration_id);
400   int registration_handle_id = kInvalidServiceWorkerRegistrationHandleId;
401   if (registration_handle) {
402     registration_handle->IncrementRefCount();
403     registration_handle_id = registration_handle->handle_id();
404   } else {
405     scoped_ptr<ServiceWorkerRegistrationHandle> new_handle(
406         new ServiceWorkerRegistrationHandle(
407             GetContext()->AsWeakPtr(), this, provider_id, registration));
408     registration_handle_id = new_handle->handle_id();
409     RegisterServiceWorkerRegistrationHandle(new_handle.Pass());
410   }
411
412   Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
413       thread_id, request_id, registration_handle_id, info));
414 }
415
416 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
417   if (!GetContext())
418     return;
419   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
420   if (!registry->CanHandle(embedded_worker_id))
421     return;
422   registry->OnWorkerScriptLoaded(render_process_id_, embedded_worker_id);
423 }
424
425 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
426     int embedded_worker_id) {
427   if (!GetContext())
428     return;
429   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
430   if (!registry->CanHandle(embedded_worker_id))
431     return;
432   registry->OnWorkerScriptLoadFailed(render_process_id_, embedded_worker_id);
433 }
434
435 void ServiceWorkerDispatcherHost::OnWorkerStarted(
436     int thread_id, int embedded_worker_id) {
437   if (!GetContext())
438     return;
439   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
440   if (!registry->CanHandle(embedded_worker_id))
441     return;
442   registry->OnWorkerStarted(render_process_id_, thread_id, embedded_worker_id);
443 }
444
445 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
446   if (!GetContext())
447     return;
448   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
449   if (!registry->CanHandle(embedded_worker_id))
450     return;
451   registry->OnWorkerStopped(render_process_id_, embedded_worker_id);
452 }
453
454 void ServiceWorkerDispatcherHost::OnPausedAfterDownload(
455     int embedded_worker_id) {
456   if (!GetContext())
457     return;
458   GetContext()->embedded_worker_registry()->OnPausedAfterDownload(
459       render_process_id_, embedded_worker_id);
460 }
461
462 void ServiceWorkerDispatcherHost::OnReportException(
463     int embedded_worker_id,
464     const base::string16& error_message,
465     int line_number,
466     int column_number,
467     const GURL& source_url) {
468   if (!GetContext())
469     return;
470   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
471   if (!registry->CanHandle(embedded_worker_id))
472     return;
473   registry->OnReportException(embedded_worker_id,
474                               error_message,
475                               line_number,
476                               column_number,
477                               source_url);
478 }
479
480 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
481     int embedded_worker_id,
482     const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
483   if (!GetContext())
484     return;
485   EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
486   if (!registry->CanHandle(embedded_worker_id))
487     return;
488   registry->OnReportConsoleMessage(embedded_worker_id,
489                                    params.source_identifier,
490                                    params.message_level,
491                                    params.message,
492                                    params.line_number,
493                                    params.source_url);
494 }
495
496 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
497     int handle_id) {
498   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
499   if (!handle) {
500     BadMessageReceived();
501     return;
502   }
503   handle->IncrementRefCount();
504 }
505
506 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
507     int handle_id) {
508   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
509   if (!handle) {
510     BadMessageReceived();
511     return;
512   }
513   handle->DecrementRefCount();
514   if (handle->HasNoRefCount())
515     handles_.Remove(handle_id);
516 }
517
518 void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
519     int registration_handle_id) {
520   ServiceWorkerRegistrationHandle* handle =
521       registration_handles_.Lookup(registration_handle_id);
522   if (!handle) {
523     BadMessageReceived();
524     return;
525   }
526   handle->IncrementRefCount();
527 }
528
529 void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
530     int registration_handle_id) {
531   ServiceWorkerRegistrationHandle* handle =
532       registration_handles_.Lookup(registration_handle_id);
533   if (!handle) {
534     BadMessageReceived();
535     return;
536   }
537   handle->DecrementRefCount();
538   if (handle->HasNoRefCount())
539     registration_handles_.Remove(registration_handle_id);
540 }
541
542 void ServiceWorkerDispatcherHost::UnregistrationComplete(
543     int thread_id,
544     int request_id,
545     ServiceWorkerStatusCode status) {
546   if (status != SERVICE_WORKER_OK) {
547     SendRegistrationError(thread_id, request_id, status);
548     return;
549   }
550
551   Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
552 }
553
554 void ServiceWorkerDispatcherHost::SendRegistrationError(
555     int thread_id,
556     int request_id,
557     ServiceWorkerStatusCode status) {
558   base::string16 error_message;
559   blink::WebServiceWorkerError::ErrorType error_type;
560   GetServiceWorkerRegistrationStatusResponse(
561       status, &error_type, &error_message);
562   Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
563       thread_id, request_id, error_type, error_message));
564 }
565
566 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
567   return context_wrapper_->context();
568 }
569
570 }  // namespace content