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 bool CanRegisterServiceWorker(const GURL& document_url, 40 const GURL& pattern, 41 const GURL& script_url) { 42 // TODO: Respect Chrome's content settings, if we add a setting for 43 // controlling whether Service Worker is allowed. 44 return document_url.GetOrigin() == pattern.GetOrigin() && 45 document_url.GetOrigin() == script_url.GetOrigin(); 46 } 47 48 bool CanUnregisterServiceWorker(const GURL& document_url, 49 const GURL& pattern) { 50 // TODO: Respect Chrome's content settings, if we add a setting for 51 // controlling whether Service Worker is allowed. 52 return document_url.GetOrigin() == pattern.GetOrigin(); 53 } 54 55 } // namespace 56 57 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost( 58 int render_process_id, 59 MessagePortMessageFilter* message_port_message_filter) 60 : BrowserMessageFilter(kFilteredMessageClasses, 61 arraysize(kFilteredMessageClasses)), 62 render_process_id_(render_process_id), 63 message_port_message_filter_(message_port_message_filter), 64 channel_ready_(false) { 65 } 66 67 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() { 68 if (GetContext()) { 69 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_); 70 GetContext()->embedded_worker_registry()->RemoveChildProcessSender( 71 render_process_id_); 72 } 73 } 74 75 void ServiceWorkerDispatcherHost::Init( 76 ServiceWorkerContextWrapper* context_wrapper) { 77 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 78 BrowserThread::PostTask( 79 BrowserThread::IO, FROM_HERE, 80 base::Bind(&ServiceWorkerDispatcherHost::Init, 81 this, make_scoped_refptr(context_wrapper))); 82 return; 83 } 84 context_wrapper_ = context_wrapper; 85 GetContext()->embedded_worker_registry()->AddChildProcessSender( 86 render_process_id_, this); 87 } 88 89 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) { 90 BrowserMessageFilter::OnFilterAdded(sender); 91 channel_ready_ = true; 92 std::vector<IPC::Message*> messages; 93 pending_messages_.release(&messages); 94 for (size_t i = 0; i < messages.size(); ++i) { 95 BrowserMessageFilter::Send(messages[i]); 96 } 97 } 98 99 void ServiceWorkerDispatcherHost::OnDestruct() const { 100 BrowserThread::DeleteOnIOThread::Destruct(this); 101 } 102 103 bool ServiceWorkerDispatcherHost::OnMessageReceived( 104 const IPC::Message& message) { 105 bool handled = true; 106 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost, message) 107 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker, 108 OnRegisterServiceWorker) 109 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker, 110 OnUnregisterServiceWorker) 111 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated, 112 OnProviderCreated) 113 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed, 114 OnProviderDestroyed) 115 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId, 116 OnSetHostedVersionId) 117 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker, 118 OnPostMessageToWorker) 119 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded, 120 OnWorkerScriptLoaded) 121 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed, 122 OnWorkerScriptLoadFailed) 123 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted, 124 OnWorkerStarted) 125 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped, 126 OnWorkerStopped) 127 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException, 128 OnReportException) 129 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage, 130 OnReportConsoleMessage) 131 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount, 132 OnIncrementServiceWorkerRefCount) 133 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount, 134 OnDecrementServiceWorkerRefCount) 135 IPC_MESSAGE_UNHANDLED(handled = false) 136 IPC_END_MESSAGE_MAP() 137 138 if (!handled && GetContext()) { 139 handled = 140 GetContext()->embedded_worker_registry()->OnMessageReceived(message); 141 if (!handled) 142 BadMessageReceived(); 143 } 144 145 return handled; 146 } 147 148 bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) { 149 if (channel_ready_) { 150 BrowserMessageFilter::Send(message); 151 // Don't bother passing through Send()'s result: it's not reliable. 152 return true; 153 } 154 155 pending_messages_.push_back(message); 156 return true; 157 } 158 159 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle( 160 scoped_ptr<ServiceWorkerHandle> handle) { 161 int handle_id = handle->handle_id(); 162 handles_.AddWithID(handle.release(), handle_id); 163 } 164 165 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker( 166 int thread_id, 167 int request_id, 168 int provider_id, 169 const GURL& pattern, 170 const GURL& script_url) { 171 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) { 172 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 173 thread_id, 174 request_id, 175 WebServiceWorkerError::ErrorTypeDisabled, 176 base::ASCIIToUTF16(kDisabledErrorMessage))); 177 return; 178 } 179 180 ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost( 181 render_process_id_, provider_id); 182 if (!provider_host) { 183 BadMessageReceived(); 184 return; 185 } 186 if (!provider_host->IsContextAlive()) { 187 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 188 thread_id, 189 request_id, 190 WebServiceWorkerError::ErrorTypeDisabled, 191 base::ASCIIToUTF16(kDisabledErrorMessage))); 192 return; 193 } 194 195 if (!CanRegisterServiceWorker( 196 provider_host->document_url(), pattern, script_url)) { 197 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 198 thread_id, 199 request_id, 200 WebServiceWorkerError::ErrorTypeSecurity, 201 base::ASCIIToUTF16(kDomainMismatchErrorMessage))); 202 return; 203 } 204 GetContext()->RegisterServiceWorker( 205 pattern, 206 script_url, 207 render_process_id_, 208 provider_host, 209 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete, 210 this, 211 thread_id, 212 request_id)); 213 } 214 215 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker( 216 int thread_id, 217 int request_id, 218 int provider_id, 219 const GURL& pattern) { 220 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) { 221 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 222 thread_id, 223 request_id, 224 blink::WebServiceWorkerError::ErrorTypeDisabled, 225 base::ASCIIToUTF16(kDisabledErrorMessage))); 226 return; 227 } 228 229 ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost( 230 render_process_id_, provider_id); 231 if (!provider_host) { 232 BadMessageReceived(); 233 return; 234 } 235 if (!provider_host->IsContextAlive()) { 236 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 237 thread_id, 238 request_id, 239 blink::WebServiceWorkerError::ErrorTypeDisabled, 240 base::ASCIIToUTF16(kDisabledErrorMessage))); 241 return; 242 } 243 244 if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) { 245 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 246 thread_id, 247 request_id, 248 WebServiceWorkerError::ErrorTypeSecurity, 249 base::ASCIIToUTF16(kDomainMismatchErrorMessage))); 250 return; 251 } 252 253 GetContext()->UnregisterServiceWorker( 254 pattern, 255 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete, 256 this, 257 thread_id, 258 request_id)); 259 } 260 261 void ServiceWorkerDispatcherHost::OnPostMessageToWorker( 262 int handle_id, 263 const base::string16& message, 264 const std::vector<int>& sent_message_port_ids) { 265 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) 266 return; 267 268 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 269 if (!handle) { 270 BadMessageReceived(); 271 return; 272 } 273 274 std::vector<int> new_routing_ids; 275 message_port_message_filter_->UpdateMessagePortsWithNewRoutes( 276 sent_message_port_ids, &new_routing_ids); 277 handle->version()->SendMessage( 278 ServiceWorkerMsg_MessageToWorker(message, 279 sent_message_port_ids, 280 new_routing_ids), 281 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)); 282 } 283 284 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) { 285 if (!GetContext()) 286 return; 287 if (GetContext()->GetProviderHost(render_process_id_, provider_id)) { 288 BadMessageReceived(); 289 return; 290 } 291 scoped_ptr<ServiceWorkerProviderHost> provider_host( 292 new ServiceWorkerProviderHost( 293 render_process_id_, provider_id, GetContext()->AsWeakPtr(), this)); 294 GetContext()->AddProviderHost(provider_host.Pass()); 295 } 296 297 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) { 298 if (!GetContext()) 299 return; 300 if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) { 301 BadMessageReceived(); 302 return; 303 } 304 GetContext()->RemoveProviderHost(render_process_id_, provider_id); 305 } 306 307 void ServiceWorkerDispatcherHost::OnSetHostedVersionId( 308 int provider_id, int64 version_id) { 309 if (!GetContext()) 310 return; 311 ServiceWorkerProviderHost* provider_host = 312 GetContext()->GetProviderHost(render_process_id_, provider_id); 313 if (!provider_host) { 314 BadMessageReceived(); 315 return; 316 } 317 if (!provider_host->IsContextAlive()) 318 return; 319 if (!provider_host->SetHostedVersionId(version_id)) 320 BadMessageReceived(); 321 } 322 323 void ServiceWorkerDispatcherHost::RegistrationComplete( 324 int thread_id, 325 int request_id, 326 ServiceWorkerStatusCode status, 327 int64 registration_id, 328 int64 version_id) { 329 if (!GetContext()) 330 return; 331 332 if (status != SERVICE_WORKER_OK) { 333 SendRegistrationError(thread_id, request_id, status); 334 return; 335 } 336 337 ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id); 338 DCHECK(version); 339 DCHECK_EQ(registration_id, version->registration_id()); 340 scoped_ptr<ServiceWorkerHandle> handle = 341 ServiceWorkerHandle::Create(GetContext()->AsWeakPtr(), 342 this, thread_id, version); 343 Send(new ServiceWorkerMsg_ServiceWorkerRegistered( 344 thread_id, request_id, handle->GetObjectInfo())); 345 RegisterServiceWorkerHandle(handle.Pass()); 346 } 347 348 // TODO(nhiroki): These message handlers that take |embedded_worker_id| as an 349 // input should check if the worker refers to the live context. If the context 350 // was deleted, handle the messege gracefully (http://crbug.com/371675). 351 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) { 352 if (!GetContext()) 353 return; 354 GetContext()->embedded_worker_registry()->OnWorkerScriptLoaded( 355 render_process_id_, embedded_worker_id); 356 } 357 358 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed( 359 int embedded_worker_id) { 360 if (!GetContext()) 361 return; 362 GetContext()->embedded_worker_registry()->OnWorkerScriptLoadFailed( 363 render_process_id_, embedded_worker_id); 364 } 365 366 void ServiceWorkerDispatcherHost::OnWorkerStarted( 367 int thread_id, int embedded_worker_id) { 368 if (!GetContext()) 369 return; 370 GetContext()->embedded_worker_registry()->OnWorkerStarted( 371 render_process_id_, thread_id, embedded_worker_id); 372 } 373 374 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) { 375 if (!GetContext()) 376 return; 377 GetContext()->embedded_worker_registry()->OnWorkerStopped( 378 render_process_id_, embedded_worker_id); 379 } 380 381 void ServiceWorkerDispatcherHost::OnReportException( 382 int embedded_worker_id, 383 const base::string16& error_message, 384 int line_number, 385 int column_number, 386 const GURL& source_url) { 387 if (!GetContext()) 388 return; 389 GetContext()->embedded_worker_registry()->OnReportException( 390 embedded_worker_id, 391 error_message, 392 line_number, 393 column_number, 394 source_url); 395 } 396 397 void ServiceWorkerDispatcherHost::OnReportConsoleMessage( 398 int embedded_worker_id, 399 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) { 400 if (!GetContext()) 401 return; 402 GetContext()->embedded_worker_registry()->OnReportConsoleMessage( 403 embedded_worker_id, 404 params.source_identifier, 405 params.message_level, 406 params.message, 407 params.line_number, 408 params.source_url); 409 } 410 411 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount( 412 int handle_id) { 413 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 414 if (!handle) { 415 BadMessageReceived(); 416 return; 417 } 418 handle->IncrementRefCount(); 419 } 420 421 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount( 422 int handle_id) { 423 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 424 if (!handle) { 425 BadMessageReceived(); 426 return; 427 } 428 handle->DecrementRefCount(); 429 if (handle->HasNoRefCount()) 430 handles_.Remove(handle_id); 431 } 432 433 void ServiceWorkerDispatcherHost::UnregistrationComplete( 434 int thread_id, 435 int request_id, 436 ServiceWorkerStatusCode status) { 437 if (status != SERVICE_WORKER_OK) { 438 SendRegistrationError(thread_id, request_id, status); 439 return; 440 } 441 442 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id)); 443 } 444 445 void ServiceWorkerDispatcherHost::SendRegistrationError( 446 int thread_id, 447 int request_id, 448 ServiceWorkerStatusCode status) { 449 base::string16 error_message; 450 blink::WebServiceWorkerError::ErrorType error_type; 451 GetServiceWorkerRegistrationStatusResponse( 452 status, &error_type, &error_message); 453 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 454 thread_id, request_id, error_type, error_message)); 455 } 456 457 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() { 458 return context_wrapper_->context(); 459 } 460 461 } // namespace content 462