Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_context_core.cc
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_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     base::SequencedTaskRunner* cache_task_runner,
87     base::SequencedTaskRunner* database_task_runner,
88     base::MessageLoopProxy* disk_cache_thread,
89     quota::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, cache_task_runner)),
102       embedded_worker_registry_(EmbeddedWorkerRegistry::Create(AsWeakPtr())),
103       job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
104       next_handle_id_(0),
105       next_registration_handle_id_(0),
106       observer_list_(observer_list) {
107 }
108
109 ServiceWorkerContextCore::ServiceWorkerContextCore(
110     ServiceWorkerContextCore* old_context,
111     ServiceWorkerContextWrapper* wrapper)
112     : weak_factory_(this),
113       wrapper_(wrapper),
114       providers_(old_context->providers_.release()),
115       storage_(
116           ServiceWorkerStorage::Create(AsWeakPtr(), old_context->storage())),
117       cache_manager_(ServiceWorkerCacheStorageManager::Create(
118           old_context->cache_manager())),
119       embedded_worker_registry_(EmbeddedWorkerRegistry::Create(
120           AsWeakPtr(),
121           old_context->embedded_worker_registry())),
122       job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
123       next_handle_id_(0),
124       next_registration_handle_id_(0),
125       observer_list_(old_context->observer_list_) {
126 }
127
128 ServiceWorkerContextCore::~ServiceWorkerContextCore() {
129   for (VersionMap::iterator it = live_versions_.begin();
130        it != live_versions_.end();
131        ++it) {
132     it->second->RemoveListener(this);
133   }
134   weak_factory_.InvalidateWeakPtrs();
135 }
136
137 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost(
138     int process_id, int provider_id) {
139   ProviderMap* map = GetProviderMapForProcess(process_id);
140   if (!map)
141     return NULL;
142   return map->Lookup(provider_id);
143 }
144
145 void ServiceWorkerContextCore::AddProviderHost(
146     scoped_ptr<ServiceWorkerProviderHost> host) {
147   ServiceWorkerProviderHost* host_ptr = host.release();   // we take ownership
148   ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id());
149   if (!map) {
150     map = new ProviderMap;
151     providers_->AddWithID(map, host_ptr->process_id());
152   }
153   map->AddWithID(host_ptr, host_ptr->provider_id());
154 }
155
156 void ServiceWorkerContextCore::RemoveProviderHost(
157     int process_id, int provider_id) {
158   ProviderMap* map = GetProviderMapForProcess(process_id);
159   DCHECK(map);
160   map->Remove(provider_id);
161 }
162
163 void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess(
164     int process_id) {
165   if (providers_->Lookup(process_id))
166     providers_->Remove(process_id);
167 }
168
169 scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator>
170 ServiceWorkerContextCore::GetProviderHostIterator() {
171   return make_scoped_ptr(new ProviderHostIterator(providers_.get()));
172 }
173
174 void ServiceWorkerContextCore::RegisterServiceWorker(
175     const GURL& pattern,
176     const GURL& script_url,
177     int source_process_id,
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   // TODO(kinuko): Wire the provider_host so that we can tell which document
189   // is calling .register.
190
191   job_coordinator_->Register(
192       pattern,
193       script_url,
194       source_process_id,
195       base::Bind(&ServiceWorkerContextCore::RegistrationComplete,
196                  AsWeakPtr(),
197                  pattern,
198                  callback));
199 }
200
201 void ServiceWorkerContextCore::UnregisterServiceWorker(
202     const GURL& pattern,
203     const UnregistrationCallback& callback) {
204   DCHECK_CURRENTLY_ON(BrowserThread::IO);
205   if (storage()->IsDisabled()) {
206     callback.Run(SERVICE_WORKER_ERROR_ABORT);
207     return;
208   }
209
210   job_coordinator_->Unregister(
211       pattern,
212       base::Bind(&ServiceWorkerContextCore::UnregistrationComplete,
213                  AsWeakPtr(),
214                  pattern,
215                  callback));
216 }
217
218 void ServiceWorkerContextCore::UpdateServiceWorker(
219     ServiceWorkerRegistration* registration) {
220   DCHECK_CURRENTLY_ON(BrowserThread::IO);
221   if (storage()->IsDisabled())
222     return;
223   job_coordinator_->Update(registration);
224 }
225
226 void ServiceWorkerContextCore::RegistrationComplete(
227     const GURL& pattern,
228     const ServiceWorkerContextCore::RegistrationCallback& callback,
229     ServiceWorkerStatusCode status,
230     ServiceWorkerRegistration* registration,
231     ServiceWorkerVersion* version) {
232   if (status != SERVICE_WORKER_OK) {
233     DCHECK(!version);
234     callback.Run(status,
235                  kInvalidServiceWorkerRegistrationId,
236                  kInvalidServiceWorkerVersionId);
237     return;
238   }
239
240   DCHECK(version);
241   DCHECK_EQ(version->registration_id(), registration->id());
242   callback.Run(status,
243                registration->id(),
244                version->version_id());
245   if (observer_list_) {
246     observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored,
247                            pattern);
248   }
249 }
250
251 void ServiceWorkerContextCore::UnregistrationComplete(
252     const GURL& pattern,
253     const ServiceWorkerContextCore::UnregistrationCallback& callback,
254     ServiceWorkerStatusCode status) {
255   callback.Run(status);
256   if (observer_list_) {
257     observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted,
258                            pattern);
259   }
260 }
261
262 ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration(
263     int64 id) {
264   RegistrationsMap::iterator it = live_registrations_.find(id);
265   return (it != live_registrations_.end()) ? it->second : NULL;
266 }
267
268 void ServiceWorkerContextCore::AddLiveRegistration(
269     ServiceWorkerRegistration* registration) {
270   DCHECK(!GetLiveRegistration(registration->id()));
271   live_registrations_[registration->id()] = registration;
272 }
273
274 void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) {
275   live_registrations_.erase(id);
276 }
277
278 ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion(
279     int64 id) {
280   VersionMap::iterator it = live_versions_.find(id);
281   return (it != live_versions_.end()) ? it->second : NULL;
282 }
283
284 void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) {
285   DCHECK(!GetLiveVersion(version->version_id()));
286   live_versions_[version->version_id()] = version;
287   version->AddListener(this);
288 }
289
290 void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) {
291   live_versions_.erase(id);
292 }
293
294 std::vector<ServiceWorkerRegistrationInfo>
295 ServiceWorkerContextCore::GetAllLiveRegistrationInfo() {
296   std::vector<ServiceWorkerRegistrationInfo> infos;
297   for (std::map<int64, ServiceWorkerRegistration*>::const_iterator iter =
298            live_registrations_.begin();
299        iter != live_registrations_.end();
300        ++iter) {
301     infos.push_back(iter->second->GetInfo());
302   }
303   return infos;
304 }
305
306 std::vector<ServiceWorkerVersionInfo>
307 ServiceWorkerContextCore::GetAllLiveVersionInfo() {
308   std::vector<ServiceWorkerVersionInfo> infos;
309   for (std::map<int64, ServiceWorkerVersion*>::const_iterator iter =
310            live_versions_.begin();
311        iter != live_versions_.end();
312        ++iter) {
313     infos.push_back(iter->second->GetInfo());
314   }
315   return infos;
316 }
317
318 int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() {
319   return next_handle_id_++;
320 }
321
322 int ServiceWorkerContextCore::GetNewRegistrationHandleId() {
323   return next_registration_handle_id_++;
324 }
325
326 void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const {
327   storage_->Disable();
328   base::MessageLoop::current()->PostTask(
329       FROM_HERE,
330       base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_));
331 }
332
333 void ServiceWorkerContextCore::DeleteAndStartOver(
334     const StatusCallback& callback) {
335   job_coordinator_->AbortAll();
336   storage_->DeleteAndStartOver(callback);
337 }
338
339 void ServiceWorkerContextCore::SetBlobParametersForCache(
340     net::URLRequestContext* request_context,
341     base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context) {
342   DCHECK_CURRENTLY_ON(BrowserThread::IO);
343
344   cache_manager_->SetBlobParametersForCache(request_context,
345                                             blob_storage_context);
346 }
347
348 void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) {
349   if (!observer_list_)
350     return;
351   observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted,
352                          version->version_id(),
353                          version->embedded_worker()->process_id(),
354                          version->embedded_worker()->thread_id());
355 }
356
357 void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) {
358   if (!observer_list_)
359     return;
360   observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped,
361                          version->version_id(),
362                          version->embedded_worker()->process_id(),
363                          version->embedded_worker()->thread_id());
364 }
365
366 void ServiceWorkerContextCore::OnVersionStateChanged(
367     ServiceWorkerVersion* version) {
368   if (!observer_list_)
369     return;
370   observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged,
371                          version->version_id());
372 }
373
374 void ServiceWorkerContextCore::OnErrorReported(
375     ServiceWorkerVersion* version,
376     const base::string16& error_message,
377     int line_number,
378     int column_number,
379     const GURL& source_url) {
380   if (!observer_list_)
381     return;
382   observer_list_->Notify(
383       &ServiceWorkerContextObserver::OnErrorReported,
384       version->version_id(),
385       version->embedded_worker()->process_id(),
386       version->embedded_worker()->thread_id(),
387       ServiceWorkerContextObserver::ErrorInfo(
388           error_message, line_number, column_number, source_url));
389 }
390
391 void ServiceWorkerContextCore::OnReportConsoleMessage(
392     ServiceWorkerVersion* version,
393     int source_identifier,
394     int message_level,
395     const base::string16& message,
396     int line_number,
397     const GURL& source_url) {
398   if (!observer_list_)
399     return;
400   observer_list_->Notify(
401       &ServiceWorkerContextObserver::OnReportConsoleMessage,
402       version->version_id(),
403       version->embedded_worker()->process_id(),
404       version->embedded_worker()->thread_id(),
405       ServiceWorkerContextObserver::ConsoleMessage(
406           source_identifier, message_level, message, line_number, source_url));
407 }
408
409 ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
410   return wrapper_->process_manager();
411 }
412
413 }  // namespace content