Home | History | Annotate | Download | only in service_worker
      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