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/child/service_worker/service_worker_dispatcher.h" 6 7 #include "base/debug/trace_event.h" 8 #include "base/lazy_instance.h" 9 #include "base/stl_util.h" 10 #include "base/threading/thread_local.h" 11 #include "content/child/child_thread.h" 12 #include "content/child/service_worker/service_worker_handle_reference.h" 13 #include "content/child/service_worker/service_worker_provider_context.h" 14 #include "content/child/service_worker/service_worker_registration_handle_reference.h" 15 #include "content/child/service_worker/web_service_worker_impl.h" 16 #include "content/child/service_worker/web_service_worker_registration_impl.h" 17 #include "content/child/thread_safe_sender.h" 18 #include "content/child/webmessageportchannel_impl.h" 19 #include "content/common/service_worker/service_worker_messages.h" 20 #include "content/public/common/url_utils.h" 21 #include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h" 22 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 23 24 using blink::WebServiceWorkerError; 25 using blink::WebServiceWorkerProvider; 26 using base::ThreadLocalPointer; 27 28 namespace content { 29 30 namespace { 31 32 base::LazyInstance<ThreadLocalPointer<ServiceWorkerDispatcher> >::Leaky 33 g_dispatcher_tls = LAZY_INSTANCE_INITIALIZER; 34 35 ServiceWorkerDispatcher* const kHasBeenDeleted = 36 reinterpret_cast<ServiceWorkerDispatcher*>(0x1); 37 38 int CurrentWorkerId() { 39 return WorkerTaskRunner::Instance()->CurrentWorkerId(); 40 } 41 42 } // namespace 43 44 ServiceWorkerDispatcher::ServiceWorkerDispatcher( 45 ThreadSafeSender* thread_safe_sender) 46 : thread_safe_sender_(thread_safe_sender) { 47 g_dispatcher_tls.Pointer()->Set(this); 48 } 49 50 ServiceWorkerDispatcher::~ServiceWorkerDispatcher() { 51 g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); 52 } 53 54 void ServiceWorkerDispatcher::OnMessageReceived(const IPC::Message& msg) { 55 bool handled = true; 56 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcher, msg) 57 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_AssociateRegistration, 58 OnAssociateRegistration) 59 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DisassociateRegistration, 60 OnDisassociateRegistration) 61 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistered, OnRegistered) 62 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistered, 63 OnUnregistered) 64 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration, 65 OnDidGetRegistration) 66 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError, 67 OnRegistrationError) 68 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerUnregistrationError, 69 OnUnregistrationError) 70 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationError, 71 OnGetRegistrationError) 72 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged, 73 OnServiceWorkerStateChanged) 74 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes, 75 OnSetVersionAttributes) 76 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_UpdateFound, 77 OnUpdateFound) 78 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetControllerServiceWorker, 79 OnSetControllerServiceWorker) 80 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument, 81 OnPostMessage) 82 IPC_MESSAGE_UNHANDLED(handled = false) 83 IPC_END_MESSAGE_MAP() 84 DCHECK(handled) << "Unhandled message:" << msg.type(); 85 } 86 87 bool ServiceWorkerDispatcher::Send(IPC::Message* msg) { 88 return thread_safe_sender_->Send(msg); 89 } 90 91 void ServiceWorkerDispatcher::RegisterServiceWorker( 92 int provider_id, 93 const GURL& pattern, 94 const GURL& script_url, 95 WebServiceWorkerRegistrationCallbacks* callbacks) { 96 DCHECK(callbacks); 97 98 if (pattern.possibly_invalid_spec().size() > GetMaxURLChars() || 99 script_url.possibly_invalid_spec().size() > GetMaxURLChars()) { 100 scoped_ptr<WebServiceWorkerRegistrationCallbacks> 101 owned_callbacks(callbacks); 102 scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError( 103 WebServiceWorkerError::ErrorTypeSecurity, "URL too long")); 104 callbacks->onError(error.release()); 105 return; 106 } 107 108 int request_id = pending_registration_callbacks_.Add(callbacks); 109 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", 110 "ServiceWorkerDispatcher::RegisterServiceWorker", 111 request_id, 112 "Scope", pattern.spec(), 113 "Script URL", script_url.spec()); 114 thread_safe_sender_->Send(new ServiceWorkerHostMsg_RegisterServiceWorker( 115 CurrentWorkerId(), request_id, provider_id, pattern, script_url)); 116 } 117 118 void ServiceWorkerDispatcher::UnregisterServiceWorker( 119 int provider_id, 120 const GURL& pattern, 121 WebServiceWorkerUnregistrationCallbacks* callbacks) { 122 DCHECK(callbacks); 123 124 if (pattern.possibly_invalid_spec().size() > GetMaxURLChars()) { 125 scoped_ptr<WebServiceWorkerUnregistrationCallbacks> 126 owned_callbacks(callbacks); 127 scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError( 128 WebServiceWorkerError::ErrorTypeSecurity, "URL too long")); 129 callbacks->onError(error.release()); 130 return; 131 } 132 133 int request_id = pending_unregistration_callbacks_.Add(callbacks); 134 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", 135 "ServiceWorkerDispatcher::UnregisterServiceWorker", 136 request_id, 137 "Scope", pattern.spec()); 138 thread_safe_sender_->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker( 139 CurrentWorkerId(), request_id, provider_id, pattern)); 140 } 141 142 void ServiceWorkerDispatcher::GetRegistration( 143 int provider_id, 144 const GURL& document_url, 145 WebServiceWorkerRegistrationCallbacks* callbacks) { 146 DCHECK(callbacks); 147 148 if (document_url.possibly_invalid_spec().size() > GetMaxURLChars()) { 149 scoped_ptr<WebServiceWorkerRegistrationCallbacks> 150 owned_callbacks(callbacks); 151 scoped_ptr<WebServiceWorkerError> error(new WebServiceWorkerError( 152 WebServiceWorkerError::ErrorTypeSecurity, "URL too long")); 153 callbacks->onError(error.release()); 154 return; 155 } 156 157 int request_id = pending_get_registration_callbacks_.Add(callbacks); 158 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", 159 "ServiceWorkerDispatcher::GetRegistration", 160 request_id, 161 "Document URL", document_url.spec()); 162 thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistration( 163 CurrentWorkerId(), request_id, provider_id, document_url)); 164 } 165 166 void ServiceWorkerDispatcher::AddProviderContext( 167 ServiceWorkerProviderContext* provider_context) { 168 DCHECK(provider_context); 169 int provider_id = provider_context->provider_id(); 170 DCHECK(!ContainsKey(provider_contexts_, provider_id)); 171 provider_contexts_[provider_id] = provider_context; 172 } 173 174 void ServiceWorkerDispatcher::RemoveProviderContext( 175 ServiceWorkerProviderContext* provider_context) { 176 DCHECK(provider_context); 177 DCHECK(ContainsKey(provider_contexts_, provider_context->provider_id())); 178 provider_contexts_.erase(provider_context->provider_id()); 179 worker_to_provider_.erase(provider_context->installing_handle_id()); 180 worker_to_provider_.erase(provider_context->waiting_handle_id()); 181 worker_to_provider_.erase(provider_context->active_handle_id()); 182 worker_to_provider_.erase(provider_context->controller_handle_id()); 183 } 184 185 void ServiceWorkerDispatcher::AddScriptClient( 186 int provider_id, 187 blink::WebServiceWorkerProviderClient* client) { 188 DCHECK(client); 189 DCHECK(!ContainsKey(script_clients_, provider_id)); 190 script_clients_[provider_id] = client; 191 } 192 193 void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id) { 194 // This could be possibly called multiple times to ensure termination. 195 if (ContainsKey(script_clients_, provider_id)) 196 script_clients_.erase(provider_id); 197 } 198 199 ServiceWorkerDispatcher* 200 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( 201 ThreadSafeSender* thread_safe_sender) { 202 if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) { 203 NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher."; 204 g_dispatcher_tls.Pointer()->Set(NULL); 205 } 206 if (g_dispatcher_tls.Pointer()->Get()) 207 return g_dispatcher_tls.Pointer()->Get(); 208 209 ServiceWorkerDispatcher* dispatcher = 210 new ServiceWorkerDispatcher(thread_safe_sender); 211 if (WorkerTaskRunner::Instance()->CurrentWorkerId()) 212 WorkerTaskRunner::Instance()->AddStopObserver(dispatcher); 213 return dispatcher; 214 } 215 216 ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetThreadSpecificInstance() { 217 if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) 218 return NULL; 219 return g_dispatcher_tls.Pointer()->Get(); 220 } 221 222 void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() { 223 delete this; 224 } 225 226 WebServiceWorkerImpl* ServiceWorkerDispatcher::GetServiceWorker( 227 const ServiceWorkerObjectInfo& info, 228 bool adopt_handle) { 229 if (info.handle_id == kInvalidServiceWorkerHandleId) 230 return NULL; 231 232 WorkerObjectMap::iterator existing_worker = 233 service_workers_.find(info.handle_id); 234 235 if (existing_worker != service_workers_.end()) { 236 if (adopt_handle) { 237 // We are instructed to adopt a handle but we already have one, so 238 // adopt and destroy a handle ref. 239 ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); 240 } 241 return existing_worker->second; 242 } 243 244 scoped_ptr<ServiceWorkerHandleReference> handle_ref = 245 adopt_handle 246 ? ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()) 247 : ServiceWorkerHandleReference::Create(info, 248 thread_safe_sender_.get()); 249 // WebServiceWorkerImpl constructor calls AddServiceWorker. 250 return new WebServiceWorkerImpl(handle_ref.Pass(), thread_safe_sender_.get()); 251 } 252 253 WebServiceWorkerRegistrationImpl* 254 ServiceWorkerDispatcher::FindServiceWorkerRegistration( 255 const ServiceWorkerRegistrationObjectInfo& info, 256 bool adopt_handle) { 257 RegistrationObjectMap::iterator registration = 258 registrations_.find(info.handle_id); 259 if (registration == registrations_.end()) 260 return NULL; 261 if (adopt_handle) { 262 // We are instructed to adopt a handle but we already have one, so 263 // adopt and destroy a handle ref. 264 ServiceWorkerRegistrationHandleReference::Adopt( 265 info, thread_safe_sender_.get()); 266 } 267 return registration->second; 268 } 269 270 WebServiceWorkerRegistrationImpl* 271 ServiceWorkerDispatcher::CreateServiceWorkerRegistration( 272 const ServiceWorkerRegistrationObjectInfo& info, 273 bool adopt_handle) { 274 DCHECK(!FindServiceWorkerRegistration(info, adopt_handle)); 275 if (info.handle_id == kInvalidServiceWorkerRegistrationHandleId) 276 return NULL; 277 278 scoped_ptr<ServiceWorkerRegistrationHandleReference> handle_ref = 279 adopt_handle ? ServiceWorkerRegistrationHandleReference::Adopt( 280 info, thread_safe_sender_.get()) 281 : ServiceWorkerRegistrationHandleReference::Create( 282 info, thread_safe_sender_.get()); 283 284 // WebServiceWorkerRegistrationImpl constructor calls 285 // AddServiceWorkerRegistration. 286 return new WebServiceWorkerRegistrationImpl(handle_ref.Pass()); 287 } 288 289 void ServiceWorkerDispatcher::OnAssociateRegistration( 290 int thread_id, 291 int provider_id, 292 const ServiceWorkerRegistrationObjectInfo& info, 293 const ServiceWorkerVersionAttributes& attrs) { 294 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 295 if (provider == provider_contexts_.end()) 296 return; 297 provider->second->OnAssociateRegistration(info, attrs); 298 if (attrs.installing.handle_id != kInvalidServiceWorkerHandleId) 299 worker_to_provider_[attrs.installing.handle_id] = provider->second; 300 if (attrs.waiting.handle_id != kInvalidServiceWorkerHandleId) 301 worker_to_provider_[attrs.waiting.handle_id] = provider->second; 302 if (attrs.active.handle_id != kInvalidServiceWorkerHandleId) 303 worker_to_provider_[attrs.active.handle_id] = provider->second; 304 } 305 306 void ServiceWorkerDispatcher::OnDisassociateRegistration( 307 int thread_id, 308 int provider_id) { 309 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 310 if (provider == provider_contexts_.end()) 311 return; 312 provider->second->OnDisassociateRegistration(); 313 worker_to_provider_.erase(provider->second->installing_handle_id()); 314 worker_to_provider_.erase(provider->second->waiting_handle_id()); 315 worker_to_provider_.erase(provider->second->active_handle_id()); 316 worker_to_provider_.erase(provider->second->controller_handle_id()); 317 } 318 319 void ServiceWorkerDispatcher::OnRegistered( 320 int thread_id, 321 int request_id, 322 const ServiceWorkerRegistrationObjectInfo& info, 323 const ServiceWorkerVersionAttributes& attrs) { 324 TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", 325 "ServiceWorkerDispatcher::RegisterServiceWorker", 326 request_id, 327 "OnRegistered"); 328 TRACE_EVENT_ASYNC_END0("ServiceWorker", 329 "ServiceWorkerDispatcher::RegisterServiceWorker", 330 request_id); 331 WebServiceWorkerRegistrationCallbacks* callbacks = 332 pending_registration_callbacks_.Lookup(request_id); 333 DCHECK(callbacks); 334 if (!callbacks) 335 return; 336 337 callbacks->onSuccess(FindOrCreateRegistration(info, attrs)); 338 pending_registration_callbacks_.Remove(request_id); 339 } 340 341 void ServiceWorkerDispatcher::OnUnregistered(int thread_id, 342 int request_id, 343 bool is_success) { 344 TRACE_EVENT_ASYNC_STEP_INTO0( 345 "ServiceWorker", 346 "ServiceWorkerDispatcher::UnregisterServiceWorker", 347 request_id, 348 "OnUnregistered"); 349 TRACE_EVENT_ASYNC_END0("ServiceWorker", 350 "ServiceWorkerDispatcher::UnregisterServiceWorker", 351 request_id); 352 WebServiceWorkerUnregistrationCallbacks* callbacks = 353 pending_unregistration_callbacks_.Lookup(request_id); 354 DCHECK(callbacks); 355 if (!callbacks) 356 return; 357 callbacks->onSuccess(&is_success); 358 pending_unregistration_callbacks_.Remove(request_id); 359 } 360 361 void ServiceWorkerDispatcher::OnDidGetRegistration( 362 int thread_id, 363 int request_id, 364 const ServiceWorkerRegistrationObjectInfo& info, 365 const ServiceWorkerVersionAttributes& attrs) { 366 TRACE_EVENT_ASYNC_STEP_INTO0( 367 "ServiceWorker", 368 "ServiceWorkerDispatcher::GetRegistration", 369 request_id, 370 "OnDidGetRegistration"); 371 TRACE_EVENT_ASYNC_END0("ServiceWorker", 372 "ServiceWorkerDispatcher::GetRegistration", 373 request_id); 374 WebServiceWorkerRegistrationCallbacks* callbacks = 375 pending_get_registration_callbacks_.Lookup(request_id); 376 DCHECK(callbacks); 377 if (!callbacks) 378 return; 379 380 WebServiceWorkerRegistrationImpl* registration = NULL; 381 if (info.handle_id != kInvalidServiceWorkerHandleId) 382 registration = FindOrCreateRegistration(info, attrs); 383 384 callbacks->onSuccess(registration); 385 pending_get_registration_callbacks_.Remove(request_id); 386 } 387 388 void ServiceWorkerDispatcher::OnRegistrationError( 389 int thread_id, 390 int request_id, 391 WebServiceWorkerError::ErrorType error_type, 392 const base::string16& message) { 393 TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker", 394 "ServiceWorkerDispatcher::RegisterServiceWorker", 395 request_id, 396 "OnRegistrationError"); 397 TRACE_EVENT_ASYNC_END0("ServiceWorker", 398 "ServiceWorkerDispatcher::RegisterServiceWorker", 399 request_id); 400 WebServiceWorkerRegistrationCallbacks* callbacks = 401 pending_registration_callbacks_.Lookup(request_id); 402 DCHECK(callbacks); 403 if (!callbacks) 404 return; 405 406 scoped_ptr<WebServiceWorkerError> error( 407 new WebServiceWorkerError(error_type, message)); 408 callbacks->onError(error.release()); 409 pending_registration_callbacks_.Remove(request_id); 410 } 411 412 void ServiceWorkerDispatcher::OnUnregistrationError( 413 int thread_id, 414 int request_id, 415 WebServiceWorkerError::ErrorType error_type, 416 const base::string16& message) { 417 TRACE_EVENT_ASYNC_STEP_INTO0( 418 "ServiceWorker", 419 "ServiceWorkerDispatcher::UnregisterServiceWorker", 420 request_id, 421 "OnUnregistrationError"); 422 TRACE_EVENT_ASYNC_END0("ServiceWorker", 423 "ServiceWorkerDispatcher::UnregisterServiceWorker", 424 request_id); 425 WebServiceWorkerUnregistrationCallbacks* callbacks = 426 pending_unregistration_callbacks_.Lookup(request_id); 427 DCHECK(callbacks); 428 if (!callbacks) 429 return; 430 431 scoped_ptr<WebServiceWorkerError> error( 432 new WebServiceWorkerError(error_type, message)); 433 callbacks->onError(error.release()); 434 pending_unregistration_callbacks_.Remove(request_id); 435 } 436 437 void ServiceWorkerDispatcher::OnGetRegistrationError( 438 int thread_id, 439 int request_id, 440 WebServiceWorkerError::ErrorType error_type, 441 const base::string16& message) { 442 TRACE_EVENT_ASYNC_STEP_INTO0( 443 "ServiceWorker", 444 "ServiceWorkerDispatcher::GetRegistration", 445 request_id, 446 "OnGetRegistrationError"); 447 TRACE_EVENT_ASYNC_END0("ServiceWorker", 448 "ServiceWorkerDispatcher::GetRegistration", 449 request_id); 450 WebServiceWorkerGetRegistrationCallbacks* callbacks = 451 pending_get_registration_callbacks_.Lookup(request_id); 452 DCHECK(callbacks); 453 if (!callbacks) 454 return; 455 456 scoped_ptr<WebServiceWorkerError> error( 457 new WebServiceWorkerError(error_type, message)); 458 callbacks->onError(error.release()); 459 pending_get_registration_callbacks_.Remove(request_id); 460 } 461 462 void ServiceWorkerDispatcher::OnServiceWorkerStateChanged( 463 int thread_id, 464 int handle_id, 465 blink::WebServiceWorkerState state) { 466 TRACE_EVENT2("ServiceWorker", 467 "ServiceWorkerDispatcher::OnServiceWorkerStateChanged", 468 "Thread ID", thread_id, 469 "State", state); 470 WorkerObjectMap::iterator worker = service_workers_.find(handle_id); 471 if (worker != service_workers_.end()) 472 worker->second->OnStateChanged(state); 473 474 WorkerToProviderMap::iterator provider = worker_to_provider_.find(handle_id); 475 if (provider != worker_to_provider_.end()) 476 provider->second->OnServiceWorkerStateChanged(handle_id, state); 477 } 478 479 void ServiceWorkerDispatcher::OnSetVersionAttributes( 480 int thread_id, 481 int provider_id, 482 int registration_handle_id, 483 int changed_mask, 484 const ServiceWorkerVersionAttributes& attributes) { 485 TRACE_EVENT1("ServiceWorker", 486 "ServiceWorkerDispatcher::OnSetVersionAttributes", 487 "Thread ID", thread_id); 488 ChangedVersionAttributesMask mask(changed_mask); 489 if (mask.installing_changed()) { 490 SetInstallingServiceWorker(provider_id, 491 registration_handle_id, 492 attributes.installing); 493 } 494 if (mask.waiting_changed()) { 495 SetWaitingServiceWorker(provider_id, 496 registration_handle_id, 497 attributes.waiting); 498 } 499 if (mask.active_changed()) { 500 SetActiveServiceWorker(provider_id, 501 registration_handle_id, 502 attributes.active); 503 SetReadyRegistration(provider_id, registration_handle_id); 504 } 505 } 506 507 void ServiceWorkerDispatcher::OnUpdateFound( 508 int thread_id, 509 const ServiceWorkerRegistrationObjectInfo& info) { 510 TRACE_EVENT0("ServiceWorker", 511 "ServiceWorkerDispatcher::OnUpdateFound"); 512 RegistrationObjectMap::iterator found = registrations_.find(info.handle_id); 513 if (found != registrations_.end()) 514 found->second->OnUpdateFound(); 515 } 516 517 void ServiceWorkerDispatcher::SetInstallingServiceWorker( 518 int provider_id, 519 int registration_handle_id, 520 const ServiceWorkerObjectInfo& info) { 521 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 522 if (provider != provider_contexts_.end() && 523 provider->second->registration_handle_id() == registration_handle_id) { 524 int existing_installing_id = provider->second->installing_handle_id(); 525 if (existing_installing_id != info.handle_id && 526 existing_installing_id != kInvalidServiceWorkerHandleId) { 527 WorkerToProviderMap::iterator associated_provider = 528 worker_to_provider_.find(existing_installing_id); 529 DCHECK(associated_provider != worker_to_provider_.end()); 530 DCHECK(associated_provider->second->provider_id() == provider_id); 531 worker_to_provider_.erase(associated_provider); 532 } 533 provider->second->OnSetInstallingServiceWorker( 534 registration_handle_id, info); 535 if (info.handle_id != kInvalidServiceWorkerHandleId) 536 worker_to_provider_[info.handle_id] = provider->second; 537 } 538 539 RegistrationObjectMap::iterator found = 540 registrations_.find(registration_handle_id); 541 if (found != registrations_.end()) { 542 // Populate the .installing field with the new worker object. 543 found->second->SetInstalling(GetServiceWorker(info, false)); 544 } 545 } 546 547 void ServiceWorkerDispatcher::SetWaitingServiceWorker( 548 int provider_id, 549 int registration_handle_id, 550 const ServiceWorkerObjectInfo& info) { 551 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 552 if (provider != provider_contexts_.end() && 553 provider->second->registration_handle_id() == registration_handle_id) { 554 int existing_waiting_id = provider->second->waiting_handle_id(); 555 if (existing_waiting_id != info.handle_id && 556 existing_waiting_id != kInvalidServiceWorkerHandleId) { 557 WorkerToProviderMap::iterator associated_provider = 558 worker_to_provider_.find(existing_waiting_id); 559 DCHECK(associated_provider != worker_to_provider_.end()); 560 DCHECK(associated_provider->second->provider_id() == provider_id); 561 worker_to_provider_.erase(associated_provider); 562 } 563 provider->second->OnSetWaitingServiceWorker(registration_handle_id, info); 564 if (info.handle_id != kInvalidServiceWorkerHandleId) 565 worker_to_provider_[info.handle_id] = provider->second; 566 } 567 568 RegistrationObjectMap::iterator found = 569 registrations_.find(registration_handle_id); 570 if (found != registrations_.end()) { 571 // Populate the .waiting field with the new worker object. 572 found->second->SetWaiting(GetServiceWorker(info, false)); 573 } 574 } 575 576 void ServiceWorkerDispatcher::SetActiveServiceWorker( 577 int provider_id, 578 int registration_handle_id, 579 const ServiceWorkerObjectInfo& info) { 580 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 581 if (provider != provider_contexts_.end() && 582 provider->second->registration_handle_id() == registration_handle_id) { 583 int existing_active_id = provider->second->active_handle_id(); 584 if (existing_active_id != info.handle_id && 585 existing_active_id != kInvalidServiceWorkerHandleId) { 586 WorkerToProviderMap::iterator associated_provider = 587 worker_to_provider_.find(existing_active_id); 588 DCHECK(associated_provider != worker_to_provider_.end()); 589 DCHECK(associated_provider->second->provider_id() == provider_id); 590 worker_to_provider_.erase(associated_provider); 591 } 592 provider->second->OnSetActiveServiceWorker(registration_handle_id, info); 593 if (info.handle_id != kInvalidServiceWorkerHandleId) 594 worker_to_provider_[info.handle_id] = provider->second; 595 } 596 597 RegistrationObjectMap::iterator found = 598 registrations_.find(registration_handle_id); 599 if (found != registrations_.end()) { 600 // Populate the .active field with the new worker object. 601 found->second->SetActive(GetServiceWorker(info, false)); 602 } 603 } 604 605 void ServiceWorkerDispatcher::SetReadyRegistration( 606 int provider_id, 607 int registration_handle_id) { 608 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 609 if (provider == provider_contexts_.end() || 610 provider->second->registration_handle_id() != registration_handle_id || 611 provider->second->active_handle_id() == kInvalidServiceWorkerHandleId) { 612 return; 613 } 614 615 ScriptClientMap::iterator client = script_clients_.find(provider_id); 616 if (client == script_clients_.end()) 617 return; 618 619 ServiceWorkerRegistrationObjectInfo info = 620 provider->second->registration()->info(); 621 WebServiceWorkerRegistrationImpl* registration = 622 FindServiceWorkerRegistration(info, false); 623 if (!registration) { 624 registration = CreateServiceWorkerRegistration(info, false); 625 ServiceWorkerVersionAttributes attrs = 626 provider->second->GetVersionAttributes(); 627 registration->SetInstalling(GetServiceWorker(attrs.installing, false)); 628 registration->SetWaiting(GetServiceWorker(attrs.waiting, false)); 629 registration->SetActive(GetServiceWorker(attrs.active, false)); 630 } 631 632 // Resolve the .ready promise with the registration object. 633 client->second->setReadyRegistration(registration); 634 } 635 636 void ServiceWorkerDispatcher::OnSetControllerServiceWorker( 637 int thread_id, 638 int provider_id, 639 const ServiceWorkerObjectInfo& info) { 640 TRACE_EVENT2("ServiceWorker", 641 "ServiceWorkerDispatcher::OnSetControllerServiceWorker", 642 "Thread ID", thread_id, 643 "Provider ID", provider_id); 644 ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); 645 if (provider != provider_contexts_.end()) { 646 provider->second->OnSetControllerServiceWorker( 647 provider->second->registration_handle_id(), info); 648 worker_to_provider_[info.handle_id] = provider->second; 649 } 650 651 ScriptClientMap::iterator found = script_clients_.find(provider_id); 652 if (found != script_clients_.end()) { 653 // Populate the .controller field with the new worker object. 654 found->second->setController(GetServiceWorker(info, false)); 655 } 656 } 657 658 void ServiceWorkerDispatcher::OnPostMessage( 659 int thread_id, 660 int provider_id, 661 const base::string16& message, 662 const std::vector<int>& sent_message_port_ids, 663 const std::vector<int>& new_routing_ids) { 664 // Make sure we're on the main document thread. (That must be the only 665 // thread we get this message) 666 DCHECK(ChildThread::current()); 667 TRACE_EVENT1("ServiceWorker", 668 "ServiceWorkerDispatcher::OnPostMessage", 669 "Thread ID", thread_id); 670 671 ScriptClientMap::iterator found = script_clients_.find(provider_id); 672 if (found == script_clients_.end()) { 673 // For now we do no queueing for messages sent to nonexistent / unattached 674 // client. 675 return; 676 } 677 678 std::vector<WebMessagePortChannelImpl*> ports; 679 if (!sent_message_port_ids.empty()) { 680 ports.resize(sent_message_port_ids.size()); 681 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) { 682 ports[i] = new WebMessagePortChannelImpl( 683 new_routing_ids[i], sent_message_port_ids[i], 684 base::MessageLoopProxy::current()); 685 } 686 } 687 688 found->second->dispatchMessageEvent(message, ports); 689 } 690 691 void ServiceWorkerDispatcher::AddServiceWorker( 692 int handle_id, WebServiceWorkerImpl* worker) { 693 DCHECK(!ContainsKey(service_workers_, handle_id)); 694 service_workers_[handle_id] = worker; 695 } 696 697 void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id) { 698 DCHECK(ContainsKey(service_workers_, handle_id)); 699 service_workers_.erase(handle_id); 700 } 701 702 void ServiceWorkerDispatcher::AddServiceWorkerRegistration( 703 int registration_handle_id, 704 WebServiceWorkerRegistrationImpl* registration) { 705 DCHECK(!ContainsKey(registrations_, registration_handle_id)); 706 registrations_[registration_handle_id] = registration; 707 } 708 709 void ServiceWorkerDispatcher::RemoveServiceWorkerRegistration( 710 int registration_handle_id) { 711 DCHECK(ContainsKey(registrations_, registration_handle_id)); 712 registrations_.erase(registration_handle_id); 713 } 714 715 WebServiceWorkerRegistrationImpl* 716 ServiceWorkerDispatcher::FindOrCreateRegistration( 717 const ServiceWorkerRegistrationObjectInfo& info, 718 const ServiceWorkerVersionAttributes& attrs) { 719 WebServiceWorkerRegistrationImpl* registration = 720 FindServiceWorkerRegistration(info, true); 721 if (!registration) { 722 registration = CreateServiceWorkerRegistration(info, true); 723 registration->SetInstalling(GetServiceWorker(attrs.installing, true)); 724 registration->SetWaiting(GetServiceWorker(attrs.waiting, true)); 725 registration->SetActive(GetServiceWorker(attrs.active, true)); 726 } else { 727 // |registration| must already have version attributes, so adopt and destroy 728 // handle refs for them. 729 ServiceWorkerHandleReference::Adopt( 730 attrs.installing, thread_safe_sender_.get()); 731 ServiceWorkerHandleReference::Adopt( 732 attrs.waiting, thread_safe_sender_.get()); 733 ServiceWorkerHandleReference::Adopt( 734 attrs.active, thread_safe_sender_.get()); 735 } 736 return registration; 737 } 738 739 } // namespace content 740