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
~ProviderHostIterator()30 ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {}
31
32 ServiceWorkerProviderHost*
GetProviderHost()33 ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() {
34 DCHECK(!IsAtEnd());
35 return provider_host_iterator_->GetCurrentValue();
36 }
37
Advance()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
IsAtEnd()60 bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() {
61 return process_iterator_->IsAtEnd() &&
62 (!provider_host_iterator_ || provider_host_iterator_->IsAtEnd());
63 }
64
ProviderHostIterator(ProcessToProviderMap * map)65 ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator(
66 ProcessToProviderMap* map)
67 : map_(map) {
68 DCHECK(map);
69 Initialize();
70 }
71
Initialize()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
ServiceWorkerContextCore(const base::FilePath & path,const scoped_refptr<base::SequencedTaskRunner> & cache_task_runner,const scoped_refptr<base::SequencedTaskRunner> & database_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & disk_cache_thread,storage::QuotaManagerProxy * quota_manager_proxy,ObserverListThreadSafe<ServiceWorkerContextObserver> * observer_list,ServiceWorkerContextWrapper * wrapper)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
ServiceWorkerContextCore(ServiceWorkerContextCore * old_context,ServiceWorkerContextWrapper * wrapper)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
~ServiceWorkerContextCore()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
GetProviderHost(int process_id,int provider_id)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
AddProviderHost(scoped_ptr<ServiceWorkerProviderHost> host)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
RemoveProviderHost(int process_id,int provider_id)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
RemoveAllProviderHostsForProcess(int process_id)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>
GetProviderHostIterator()171 ServiceWorkerContextCore::GetProviderHostIterator() {
172 return make_scoped_ptr(new ProviderHostIterator(providers_.get()));
173 }
174
RegisterServiceWorker(const GURL & pattern,const GURL & script_url,ServiceWorkerProviderHost * provider_host,const RegistrationCallback & callback)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
UnregisterServiceWorker(const GURL & pattern,const UnregistrationCallback & callback)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
UpdateServiceWorker(ServiceWorkerRegistration * registration)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
RegistrationComplete(const GURL & pattern,const ServiceWorkerContextCore::RegistrationCallback & callback,ServiceWorkerStatusCode status,ServiceWorkerRegistration * registration,ServiceWorkerVersion * version)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
UnregistrationComplete(const GURL & pattern,const ServiceWorkerContextCore::UnregistrationCallback & callback,ServiceWorkerStatusCode status)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
GetLiveRegistration(int64 id)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
AddLiveRegistration(ServiceWorkerRegistration * registration)265 void ServiceWorkerContextCore::AddLiveRegistration(
266 ServiceWorkerRegistration* registration) {
267 DCHECK(!GetLiveRegistration(registration->id()));
268 live_registrations_[registration->id()] = registration;
269 }
270
RemoveLiveRegistration(int64 id)271 void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) {
272 live_registrations_.erase(id);
273 }
274
GetLiveVersion(int64 id)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
AddLiveVersion(ServiceWorkerVersion * version)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
RemoveLiveVersion(int64 id)287 void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) {
288 live_versions_.erase(id);
289 }
290
291 std::vector<ServiceWorkerRegistrationInfo>
GetAllLiveRegistrationInfo()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>
GetAllLiveVersionInfo()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
GetNewServiceWorkerHandleId()315 int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() {
316 return next_handle_id_++;
317 }
318
GetNewRegistrationHandleId()319 int ServiceWorkerContextCore::GetNewRegistrationHandleId() {
320 return next_registration_handle_id_++;
321 }
322
ScheduleDeleteAndStartOver() const323 void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const {
324 storage_->Disable();
325 base::MessageLoop::current()->PostTask(
326 FROM_HERE,
327 base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_));
328 }
329
DeleteAndStartOver(const StatusCallback & callback)330 void ServiceWorkerContextCore::DeleteAndStartOver(
331 const StatusCallback& callback) {
332 job_coordinator_->AbortAll();
333 storage_->DeleteAndStartOver(callback);
334 }
335
SetBlobParametersForCache(net::URLRequestContext * request_context,base::WeakPtr<storage::BlobStorageContext> blob_storage_context)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
OnWorkerStarted(ServiceWorkerVersion * version)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
OnWorkerStopped(ServiceWorkerVersion * version)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
OnVersionStateChanged(ServiceWorkerVersion * version)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
OnErrorReported(ServiceWorkerVersion * version,const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)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
OnReportConsoleMessage(ServiceWorkerVersion * version,int source_identifier,int message_level,const base::string16 & message,int line_number,const GURL & source_url)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
process_manager()406 ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
407 if (wrapper_)
408 return wrapper_->process_manager();
409 return NULL;
410 }
411
412 } // namespace content
413