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/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