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/message_loop/message_loop_proxy.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_context_observer.h" 12 #include "content/browser/service_worker/service_worker_context_wrapper.h" 13 #include "content/browser/service_worker/service_worker_info.h" 14 #include "content/browser/service_worker/service_worker_job_coordinator.h" 15 #include "content/browser/service_worker/service_worker_process_manager.h" 16 #include "content/browser/service_worker/service_worker_provider_host.h" 17 #include "content/browser/service_worker/service_worker_register_job.h" 18 #include "content/browser/service_worker/service_worker_registration.h" 19 #include "content/browser/service_worker/service_worker_storage.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "url/gurl.h" 22 23 namespace content { 24 25 ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {} 26 27 ServiceWorkerProviderHost* 28 ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() { 29 DCHECK(!IsAtEnd()); 30 return provider_host_iterator_->GetCurrentValue(); 31 } 32 33 void ServiceWorkerContextCore::ProviderHostIterator::Advance() { 34 DCHECK(!IsAtEnd()); 35 DCHECK(!provider_host_iterator_->IsAtEnd()); 36 DCHECK(!provider_iterator_->IsAtEnd()); 37 38 // Advance the inner iterator. If an element is reached, we're done. 39 provider_host_iterator_->Advance(); 40 if (!provider_host_iterator_->IsAtEnd()) 41 return; 42 43 // Advance the outer iterator until an element is reached, or end is hit. 44 while (true) { 45 provider_iterator_->Advance(); 46 if (provider_iterator_->IsAtEnd()) 47 return; 48 ProviderMap* provider_map = provider_iterator_->GetCurrentValue(); 49 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map)); 50 if (!provider_host_iterator_->IsAtEnd()) 51 return; 52 } 53 } 54 55 bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() { 56 return provider_iterator_->IsAtEnd() && 57 (!provider_host_iterator_ || provider_host_iterator_->IsAtEnd()); 58 } 59 60 ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator( 61 ProcessToProviderMap* map) 62 : map_(map) { 63 DCHECK(map); 64 Initialize(); 65 } 66 67 void ServiceWorkerContextCore::ProviderHostIterator::Initialize() { 68 provider_iterator_.reset(new ProcessToProviderMap::iterator(map_)); 69 // Advance to the first element. 70 while (!provider_iterator_->IsAtEnd()) { 71 ProviderMap* provider_map = provider_iterator_->GetCurrentValue(); 72 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map)); 73 if (!provider_host_iterator_->IsAtEnd()) 74 return; 75 provider_iterator_->Advance(); 76 } 77 } 78 79 ServiceWorkerContextCore::ServiceWorkerContextCore( 80 const base::FilePath& path, 81 base::SequencedTaskRunner* database_task_runner, 82 base::MessageLoopProxy* disk_cache_thread, 83 quota::QuotaManagerProxy* quota_manager_proxy, 84 ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list, 85 ServiceWorkerContextWrapper* wrapper) 86 : weak_factory_(this), 87 wrapper_(wrapper), 88 storage_(new ServiceWorkerStorage(path, 89 AsWeakPtr(), 90 database_task_runner, 91 disk_cache_thread, 92 quota_manager_proxy)), 93 embedded_worker_registry_(new EmbeddedWorkerRegistry(AsWeakPtr())), 94 job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())), 95 next_handle_id_(0), 96 observer_list_(observer_list) { 97 } 98 99 ServiceWorkerContextCore::~ServiceWorkerContextCore() { 100 for (VersionMap::iterator it = live_versions_.begin(); 101 it != live_versions_.end(); 102 ++it) { 103 it->second->RemoveListener(this); 104 } 105 weak_factory_.InvalidateWeakPtrs(); 106 } 107 108 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost( 109 int process_id, int provider_id) { 110 ProviderMap* map = GetProviderMapForProcess(process_id); 111 if (!map) 112 return NULL; 113 return map->Lookup(provider_id); 114 } 115 116 void ServiceWorkerContextCore::AddProviderHost( 117 scoped_ptr<ServiceWorkerProviderHost> host) { 118 ServiceWorkerProviderHost* host_ptr = host.release(); // we take ownership 119 ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id()); 120 if (!map) { 121 map = new ProviderMap; 122 providers_.AddWithID(map, host_ptr->process_id()); 123 } 124 map->AddWithID(host_ptr, host_ptr->provider_id()); 125 } 126 127 void ServiceWorkerContextCore::RemoveProviderHost( 128 int process_id, int provider_id) { 129 ProviderMap* map = GetProviderMapForProcess(process_id); 130 DCHECK(map); 131 map->Remove(provider_id); 132 } 133 134 void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess( 135 int process_id) { 136 if (providers_.Lookup(process_id)) 137 providers_.Remove(process_id); 138 } 139 140 scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> 141 ServiceWorkerContextCore::GetProviderHostIterator() { 142 return make_scoped_ptr(new ProviderHostIterator(&providers_)); 143 } 144 145 void ServiceWorkerContextCore::RegisterServiceWorker( 146 const GURL& pattern, 147 const GURL& script_url, 148 int source_process_id, 149 ServiceWorkerProviderHost* provider_host, 150 const RegistrationCallback& callback) { 151 DCHECK_CURRENTLY_ON(BrowserThread::IO); 152 153 // TODO(kinuko): Wire the provider_host so that we can tell which document 154 // is calling .register. 155 156 job_coordinator_->Register( 157 pattern, 158 script_url, 159 source_process_id, 160 base::Bind(&ServiceWorkerContextCore::RegistrationComplete, 161 AsWeakPtr(), 162 pattern, 163 callback)); 164 } 165 166 void ServiceWorkerContextCore::UnregisterServiceWorker( 167 const GURL& pattern, 168 const UnregistrationCallback& callback) { 169 DCHECK_CURRENTLY_ON(BrowserThread::IO); 170 171 job_coordinator_->Unregister( 172 pattern, 173 base::Bind(&ServiceWorkerContextCore::UnregistrationComplete, 174 AsWeakPtr(), 175 pattern, 176 callback)); 177 } 178 179 void ServiceWorkerContextCore::RegistrationComplete( 180 const GURL& pattern, 181 const ServiceWorkerContextCore::RegistrationCallback& callback, 182 ServiceWorkerStatusCode status, 183 ServiceWorkerRegistration* registration, 184 ServiceWorkerVersion* version) { 185 if (status != SERVICE_WORKER_OK) { 186 DCHECK(!version); 187 callback.Run(status, 188 kInvalidServiceWorkerRegistrationId, 189 kInvalidServiceWorkerVersionId); 190 return; 191 } 192 193 DCHECK(version); 194 DCHECK_EQ(version->registration_id(), registration->id()); 195 callback.Run(status, 196 registration->id(), 197 version->version_id()); 198 if (observer_list_) { 199 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored, 200 pattern); 201 } 202 } 203 204 void ServiceWorkerContextCore::UnregistrationComplete( 205 const GURL& pattern, 206 const ServiceWorkerContextCore::UnregistrationCallback& callback, 207 ServiceWorkerStatusCode status) { 208 callback.Run(status); 209 if (observer_list_) { 210 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted, 211 pattern); 212 } 213 } 214 215 ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration( 216 int64 id) { 217 RegistrationsMap::iterator it = live_registrations_.find(id); 218 return (it != live_registrations_.end()) ? it->second : NULL; 219 } 220 221 void ServiceWorkerContextCore::AddLiveRegistration( 222 ServiceWorkerRegistration* registration) { 223 DCHECK(!GetLiveRegistration(registration->id())); 224 live_registrations_[registration->id()] = registration; 225 } 226 227 void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) { 228 live_registrations_.erase(id); 229 } 230 231 ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion( 232 int64 id) { 233 VersionMap::iterator it = live_versions_.find(id); 234 return (it != live_versions_.end()) ? it->second : NULL; 235 } 236 237 void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) { 238 DCHECK(!GetLiveVersion(version->version_id())); 239 live_versions_[version->version_id()] = version; 240 version->AddListener(this); 241 } 242 243 void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) { 244 live_versions_.erase(id); 245 } 246 247 std::vector<ServiceWorkerRegistrationInfo> 248 ServiceWorkerContextCore::GetAllLiveRegistrationInfo() { 249 std::vector<ServiceWorkerRegistrationInfo> infos; 250 for (std::map<int64, ServiceWorkerRegistration*>::const_iterator iter = 251 live_registrations_.begin(); 252 iter != live_registrations_.end(); 253 ++iter) { 254 infos.push_back(iter->second->GetInfo()); 255 } 256 return infos; 257 } 258 259 std::vector<ServiceWorkerVersionInfo> 260 ServiceWorkerContextCore::GetAllLiveVersionInfo() { 261 std::vector<ServiceWorkerVersionInfo> infos; 262 for (std::map<int64, ServiceWorkerVersion*>::const_iterator iter = 263 live_versions_.begin(); 264 iter != live_versions_.end(); 265 ++iter) { 266 infos.push_back(iter->second->GetInfo()); 267 } 268 return infos; 269 } 270 271 int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() { 272 return next_handle_id_++; 273 } 274 275 void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) { 276 if (!observer_list_) 277 return; 278 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted, 279 version->version_id(), 280 version->embedded_worker()->process_id(), 281 version->embedded_worker()->thread_id()); 282 } 283 284 void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) { 285 if (!observer_list_) 286 return; 287 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped, 288 version->version_id(), 289 version->embedded_worker()->process_id(), 290 version->embedded_worker()->thread_id()); 291 } 292 293 void ServiceWorkerContextCore::OnVersionStateChanged( 294 ServiceWorkerVersion* version) { 295 if (!observer_list_) 296 return; 297 observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged, 298 version->version_id()); 299 } 300 301 void ServiceWorkerContextCore::OnErrorReported( 302 ServiceWorkerVersion* version, 303 const base::string16& error_message, 304 int line_number, 305 int column_number, 306 const GURL& source_url) { 307 if (!observer_list_) 308 return; 309 observer_list_->Notify( 310 &ServiceWorkerContextObserver::OnErrorReported, 311 version->version_id(), 312 version->embedded_worker()->process_id(), 313 version->embedded_worker()->thread_id(), 314 ServiceWorkerContextObserver::ErrorInfo( 315 error_message, line_number, column_number, source_url)); 316 } 317 318 void ServiceWorkerContextCore::OnReportConsoleMessage( 319 ServiceWorkerVersion* version, 320 int source_identifier, 321 int message_level, 322 const base::string16& message, 323 int line_number, 324 const GURL& source_url) { 325 if (!observer_list_) 326 return; 327 observer_list_->Notify( 328 &ServiceWorkerContextObserver::OnReportConsoleMessage, 329 version->version_id(), 330 version->embedded_worker()->process_id(), 331 version->embedded_worker()->thread_id(), 332 ServiceWorkerContextObserver::ConsoleMessage( 333 source_identifier, message_level, message, line_number, source_url)); 334 } 335 336 ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() { 337 return wrapper_->process_manager(); 338 } 339 340 } // namespace content 341