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_context_core.h" 6 7 #include "base/files/file_path.h" 8 #include "base/single_thread_task_runner.h" 9 #include "base/strings/string_util.h" 10 #include "content/browser/service_worker/embedded_worker_registry.h" 11 #include "content/browser/service_worker/service_worker_cache_storage_manager.h" 12 #include "content/browser/service_worker/service_worker_context_observer.h" 13 #include "content/browser/service_worker/service_worker_context_wrapper.h" 14 #include "content/browser/service_worker/service_worker_info.h" 15 #include "content/browser/service_worker/service_worker_job_coordinator.h" 16 #include "content/browser/service_worker/service_worker_process_manager.h" 17 #include "content/browser/service_worker/service_worker_provider_host.h" 18 #include "content/browser/service_worker/service_worker_register_job.h" 19 #include "content/browser/service_worker/service_worker_registration.h" 20 #include "content/browser/service_worker/service_worker_storage.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "url/gurl.h" 23 24 namespace content { 25 26 const base::FilePath::CharType 27 ServiceWorkerContextCore::kServiceWorkerDirectory[] = 28 FILE_PATH_LITERAL("Service Worker"); 29 30 ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {} 31 32 ServiceWorkerProviderHost* 33 ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() { 34 DCHECK(!IsAtEnd()); 35 return provider_host_iterator_->GetCurrentValue(); 36 } 37 38 void ServiceWorkerContextCore::ProviderHostIterator::Advance() { 39 DCHECK(!IsAtEnd()); 40 DCHECK(!provider_host_iterator_->IsAtEnd()); 41 DCHECK(!process_iterator_->IsAtEnd()); 42 43 // Advance the inner iterator. If an element is reached, we're done. 44 provider_host_iterator_->Advance(); 45 if (!provider_host_iterator_->IsAtEnd()) 46 return; 47 48 // Advance the outer iterator until an element is reached, or end is hit. 49 while (true) { 50 process_iterator_->Advance(); 51 if (process_iterator_->IsAtEnd()) 52 return; 53 ProviderMap* provider_map = process_iterator_->GetCurrentValue(); 54 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map)); 55 if (!provider_host_iterator_->IsAtEnd()) 56 return; 57 } 58 } 59 60 bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() { 61 return process_iterator_->IsAtEnd() && 62 (!provider_host_iterator_ || provider_host_iterator_->IsAtEnd()); 63 } 64 65 ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator( 66 ProcessToProviderMap* map) 67 : map_(map) { 68 DCHECK(map); 69 Initialize(); 70 } 71 72 void ServiceWorkerContextCore::ProviderHostIterator::Initialize() { 73 process_iterator_.reset(new ProcessToProviderMap::iterator(map_)); 74 // Advance to the first element. 75 while (!process_iterator_->IsAtEnd()) { 76 ProviderMap* provider_map = process_iterator_->GetCurrentValue(); 77 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map)); 78 if (!provider_host_iterator_->IsAtEnd()) 79 return; 80 process_iterator_->Advance(); 81 } 82 } 83 84 ServiceWorkerContextCore::ServiceWorkerContextCore( 85 const base::FilePath& path, 86 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner, 87 const scoped_refptr<base::SequencedTaskRunner>& database_task_runner, 88 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread, 89 storage::QuotaManagerProxy* quota_manager_proxy, 90 ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list, 91 ServiceWorkerContextWrapper* wrapper) 92 : weak_factory_(this), 93 wrapper_(wrapper), 94 providers_(new ProcessToProviderMap), 95 storage_(ServiceWorkerStorage::Create(path, 96 AsWeakPtr(), 97 database_task_runner, 98 disk_cache_thread, 99 quota_manager_proxy)), 100 cache_manager_( 101 ServiceWorkerCacheStorageManager::Create(path, 102 cache_task_runner.get())), 103 embedded_worker_registry_(EmbeddedWorkerRegistry::Create(AsWeakPtr())), 104 job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())), 105 next_handle_id_(0), 106 next_registration_handle_id_(0), 107 observer_list_(observer_list) { 108 } 109 110 ServiceWorkerContextCore::ServiceWorkerContextCore( 111 ServiceWorkerContextCore* old_context, 112 ServiceWorkerContextWrapper* wrapper) 113 : weak_factory_(this), 114 wrapper_(wrapper), 115 providers_(old_context->providers_.release()), 116 storage_( 117 ServiceWorkerStorage::Create(AsWeakPtr(), old_context->storage())), 118 cache_manager_(ServiceWorkerCacheStorageManager::Create( 119 old_context->cache_manager())), 120 embedded_worker_registry_(EmbeddedWorkerRegistry::Create( 121 AsWeakPtr(), 122 old_context->embedded_worker_registry())), 123 job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())), 124 next_handle_id_(0), 125 next_registration_handle_id_(0), 126 observer_list_(old_context->observer_list_) { 127 } 128 129 ServiceWorkerContextCore::~ServiceWorkerContextCore() { 130 for (VersionMap::iterator it = live_versions_.begin(); 131 it != live_versions_.end(); 132 ++it) { 133 it->second->RemoveListener(this); 134 } 135 weak_factory_.InvalidateWeakPtrs(); 136 } 137 138 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost( 139 int process_id, int provider_id) { 140 ProviderMap* map = GetProviderMapForProcess(process_id); 141 if (!map) 142 return NULL; 143 return map->Lookup(provider_id); 144 } 145 146 void ServiceWorkerContextCore::AddProviderHost( 147 scoped_ptr<ServiceWorkerProviderHost> host) { 148 ServiceWorkerProviderHost* host_ptr = host.release(); // we take ownership 149 ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id()); 150 if (!map) { 151 map = new ProviderMap; 152 providers_->AddWithID(map, host_ptr->process_id()); 153 } 154 map->AddWithID(host_ptr, host_ptr->provider_id()); 155 } 156 157 void ServiceWorkerContextCore::RemoveProviderHost( 158 int process_id, int provider_id) { 159 ProviderMap* map = GetProviderMapForProcess(process_id); 160 DCHECK(map); 161 map->Remove(provider_id); 162 } 163 164 void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess( 165 int process_id) { 166 if (providers_->Lookup(process_id)) 167 providers_->Remove(process_id); 168 } 169 170 scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> 171 ServiceWorkerContextCore::GetProviderHostIterator() { 172 return make_scoped_ptr(new ProviderHostIterator(providers_.get())); 173 } 174 175 void ServiceWorkerContextCore::RegisterServiceWorker( 176 const GURL& pattern, 177 const GURL& script_url, 178 ServiceWorkerProviderHost* provider_host, 179 const RegistrationCallback& callback) { 180 DCHECK_CURRENTLY_ON(BrowserThread::IO); 181 if (storage()->IsDisabled()) { 182 callback.Run(SERVICE_WORKER_ERROR_ABORT, 183 kInvalidServiceWorkerRegistrationId, 184 kInvalidServiceWorkerVersionId); 185 return; 186 } 187 188 job_coordinator_->Register( 189 pattern, 190 script_url, 191 provider_host, 192 base::Bind(&ServiceWorkerContextCore::RegistrationComplete, 193 AsWeakPtr(), 194 pattern, 195 callback)); 196 } 197 198 void ServiceWorkerContextCore::UnregisterServiceWorker( 199 const GURL& pattern, 200 const UnregistrationCallback& callback) { 201 DCHECK_CURRENTLY_ON(BrowserThread::IO); 202 if (storage()->IsDisabled()) { 203 callback.Run(SERVICE_WORKER_ERROR_ABORT); 204 return; 205 } 206 207 job_coordinator_->Unregister( 208 pattern, 209 base::Bind(&ServiceWorkerContextCore::UnregistrationComplete, 210 AsWeakPtr(), 211 pattern, 212 callback)); 213 } 214 215 void ServiceWorkerContextCore::UpdateServiceWorker( 216 ServiceWorkerRegistration* registration) { 217 DCHECK_CURRENTLY_ON(BrowserThread::IO); 218 if (storage()->IsDisabled()) 219 return; 220 job_coordinator_->Update(registration); 221 } 222 223 void ServiceWorkerContextCore::RegistrationComplete( 224 const GURL& pattern, 225 const ServiceWorkerContextCore::RegistrationCallback& callback, 226 ServiceWorkerStatusCode status, 227 ServiceWorkerRegistration* registration, 228 ServiceWorkerVersion* version) { 229 if (status != SERVICE_WORKER_OK) { 230 DCHECK(!version); 231 callback.Run(status, 232 kInvalidServiceWorkerRegistrationId, 233 kInvalidServiceWorkerVersionId); 234 return; 235 } 236 237 DCHECK(version); 238 DCHECK_EQ(version->registration_id(), registration->id()); 239 callback.Run(status, 240 registration->id(), 241 version->version_id()); 242 if (observer_list_.get()) { 243 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored, 244 pattern); 245 } 246 } 247 248 void ServiceWorkerContextCore::UnregistrationComplete( 249 const GURL& pattern, 250 const ServiceWorkerContextCore::UnregistrationCallback& callback, 251 ServiceWorkerStatusCode status) { 252 callback.Run(status); 253 if (observer_list_.get()) { 254 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted, 255 pattern); 256 } 257 } 258 259 ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration( 260 int64 id) { 261 RegistrationsMap::iterator it = live_registrations_.find(id); 262 return (it != live_registrations_.end()) ? it->second : NULL; 263 } 264 265 void ServiceWorkerContextCore::AddLiveRegistration( 266 ServiceWorkerRegistration* registration) { 267 DCHECK(!GetLiveRegistration(registration->id())); 268 live_registrations_[registration->id()] = registration; 269 } 270 271 void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) { 272 live_registrations_.erase(id); 273 } 274 275 ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion( 276 int64 id) { 277 VersionMap::iterator it = live_versions_.find(id); 278 return (it != live_versions_.end()) ? it->second : NULL; 279 } 280 281 void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) { 282 DCHECK(!GetLiveVersion(version->version_id())); 283 live_versions_[version->version_id()] = version; 284 version->AddListener(this); 285 } 286 287 void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) { 288 live_versions_.erase(id); 289 } 290 291 std::vector<ServiceWorkerRegistrationInfo> 292 ServiceWorkerContextCore::GetAllLiveRegistrationInfo() { 293 std::vector<ServiceWorkerRegistrationInfo> infos; 294 for (std::map<int64, ServiceWorkerRegistration*>::const_iterator iter = 295 live_registrations_.begin(); 296 iter != live_registrations_.end(); 297 ++iter) { 298 infos.push_back(iter->second->GetInfo()); 299 } 300 return infos; 301 } 302 303 std::vector<ServiceWorkerVersionInfo> 304 ServiceWorkerContextCore::GetAllLiveVersionInfo() { 305 std::vector<ServiceWorkerVersionInfo> infos; 306 for (std::map<int64, ServiceWorkerVersion*>::const_iterator iter = 307 live_versions_.begin(); 308 iter != live_versions_.end(); 309 ++iter) { 310 infos.push_back(iter->second->GetInfo()); 311 } 312 return infos; 313 } 314 315 int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() { 316 return next_handle_id_++; 317 } 318 319 int ServiceWorkerContextCore::GetNewRegistrationHandleId() { 320 return next_registration_handle_id_++; 321 } 322 323 void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const { 324 storage_->Disable(); 325 base::MessageLoop::current()->PostTask( 326 FROM_HERE, 327 base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_)); 328 } 329 330 void ServiceWorkerContextCore::DeleteAndStartOver( 331 const StatusCallback& callback) { 332 job_coordinator_->AbortAll(); 333 storage_->DeleteAndStartOver(callback); 334 } 335 336 void ServiceWorkerContextCore::SetBlobParametersForCache( 337 net::URLRequestContext* request_context, 338 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) { 339 DCHECK_CURRENTLY_ON(BrowserThread::IO); 340 341 cache_manager_->SetBlobParametersForCache(request_context, 342 blob_storage_context); 343 } 344 345 void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) { 346 if (!observer_list_.get()) 347 return; 348 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted, 349 version->version_id(), 350 version->embedded_worker()->process_id(), 351 version->embedded_worker()->thread_id()); 352 } 353 354 void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) { 355 if (!observer_list_.get()) 356 return; 357 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped, 358 version->version_id(), 359 version->embedded_worker()->process_id(), 360 version->embedded_worker()->thread_id()); 361 } 362 363 void ServiceWorkerContextCore::OnVersionStateChanged( 364 ServiceWorkerVersion* version) { 365 if (!observer_list_.get()) 366 return; 367 observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged, 368 version->version_id()); 369 } 370 371 void ServiceWorkerContextCore::OnErrorReported( 372 ServiceWorkerVersion* version, 373 const base::string16& error_message, 374 int line_number, 375 int column_number, 376 const GURL& source_url) { 377 if (!observer_list_.get()) 378 return; 379 observer_list_->Notify( 380 &ServiceWorkerContextObserver::OnErrorReported, 381 version->version_id(), 382 version->embedded_worker()->process_id(), 383 version->embedded_worker()->thread_id(), 384 ServiceWorkerContextObserver::ErrorInfo( 385 error_message, line_number, column_number, source_url)); 386 } 387 388 void ServiceWorkerContextCore::OnReportConsoleMessage( 389 ServiceWorkerVersion* version, 390 int source_identifier, 391 int message_level, 392 const base::string16& message, 393 int line_number, 394 const GURL& source_url) { 395 if (!observer_list_.get()) 396 return; 397 observer_list_->Notify( 398 &ServiceWorkerContextObserver::OnReportConsoleMessage, 399 version->version_id(), 400 version->embedded_worker()->process_id(), 401 version->embedded_worker()->thread_id(), 402 ServiceWorkerContextObserver::ConsoleMessage( 403 source_identifier, message_level, message, line_number, source_url)); 404 } 405 406 ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() { 407 if (wrapper_) 408 return wrapper_->process_manager(); 409 return NULL; 410 } 411 412 } // namespace content 413