• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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