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_wrapper.h"
      6 
      7 #include <map>
      8 
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/threading/sequenced_worker_pool.h"
     12 #include "content/browser/fileapi/chrome_blob_storage_context.h"
     13 #include "content/browser/service_worker/service_worker_context_core.h"
     14 #include "content/browser/service_worker/service_worker_context_observer.h"
     15 #include "content/browser/service_worker/service_worker_process_manager.h"
     16 #include "content/public/browser/browser_context.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "net/url_request/url_request_context_getter.h"
     19 #include "storage/browser/blob/blob_storage_context.h"
     20 #include "storage/browser/quota/quota_manager_proxy.h"
     21 
     22 namespace content {
     23 
     24 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
     25     BrowserContext* browser_context)
     26     : observer_list_(
     27           new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
     28       process_manager_(new ServiceWorkerProcessManager(browser_context)),
     29       is_incognito_(false) {
     30 }
     31 
     32 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
     33 }
     34 
     35 void ServiceWorkerContextWrapper::Init(
     36     const base::FilePath& user_data_directory,
     37     storage::QuotaManagerProxy* quota_manager_proxy) {
     38   is_incognito_ = user_data_directory.empty();
     39   scoped_refptr<base::SequencedTaskRunner> database_task_runner =
     40       BrowserThread::GetBlockingPool()->
     41           GetSequencedTaskRunnerWithShutdownBehavior(
     42               BrowserThread::GetBlockingPool()->GetSequenceToken(),
     43               base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
     44   scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
     45       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
     46   scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
     47       BrowserThread::GetBlockingPool()
     48           ->GetSequencedTaskRunnerWithShutdownBehavior(
     49               BrowserThread::GetBlockingPool()->GetSequenceToken(),
     50               base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
     51   InitInternal(user_data_directory,
     52                cache_task_runner,
     53                database_task_runner,
     54                disk_cache_thread,
     55                quota_manager_proxy);
     56 }
     57 
     58 void ServiceWorkerContextWrapper::Shutdown() {
     59   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     60   process_manager_->Shutdown();
     61   BrowserThread::PostTask(
     62       BrowserThread::IO,
     63       FROM_HERE,
     64       base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
     65 }
     66 
     67 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
     68   DCHECK_CURRENTLY_ON(BrowserThread::IO);
     69   context_core_->DeleteAndStartOver(
     70       base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
     71 }
     72 
     73 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
     74   DCHECK_CURRENTLY_ON(BrowserThread::IO);
     75   return context_core_.get();
     76 }
     77 
     78 static void FinishRegistrationOnIO(
     79     const ServiceWorkerContext::ResultCallback& continuation,
     80     ServiceWorkerStatusCode status,
     81     int64 registration_id,
     82     int64 version_id) {
     83   DCHECK_CURRENTLY_ON(BrowserThread::IO);
     84   BrowserThread::PostTask(
     85       BrowserThread::UI,
     86       FROM_HERE,
     87       base::Bind(continuation, status == SERVICE_WORKER_OK));
     88 }
     89 
     90 void ServiceWorkerContextWrapper::RegisterServiceWorker(
     91     const GURL& pattern,
     92     const GURL& script_url,
     93     const ResultCallback& continuation) {
     94   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
     95     BrowserThread::PostTask(
     96         BrowserThread::IO,
     97         FROM_HERE,
     98         base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
     99                    this,
    100                    pattern,
    101                    script_url,
    102                    continuation));
    103     return;
    104   }
    105 
    106   context()->RegisterServiceWorker(
    107       pattern,
    108       script_url,
    109       NULL /* provider_host */,
    110       base::Bind(&FinishRegistrationOnIO, continuation));
    111 }
    112 
    113 static void FinishUnregistrationOnIO(
    114     const ServiceWorkerContext::ResultCallback& continuation,
    115     ServiceWorkerStatusCode status) {
    116   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    117   BrowserThread::PostTask(
    118       BrowserThread::UI,
    119       FROM_HERE,
    120       base::Bind(continuation, status == SERVICE_WORKER_OK));
    121 }
    122 
    123 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
    124     const GURL& pattern,
    125     const ResultCallback& continuation) {
    126   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
    127     BrowserThread::PostTask(
    128         BrowserThread::IO,
    129         FROM_HERE,
    130         base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
    131                    this,
    132                    pattern,
    133                    continuation));
    134     return;
    135   }
    136 
    137   context()->UnregisterServiceWorker(
    138       pattern,
    139       base::Bind(&FinishUnregistrationOnIO, continuation));
    140 }
    141 
    142 void ServiceWorkerContextWrapper::Terminate() {
    143   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    144   process_manager_->Shutdown();
    145 }
    146 
    147 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
    148     const GetUsageInfoCallback& callback) {
    149   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    150   context_core_->storage()->GetAllRegistrations(base::Bind(
    151       &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
    152       this,
    153       callback));
    154 }
    155 
    156 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
    157     const GetUsageInfoCallback& callback,
    158     const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
    159   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    160   std::vector<ServiceWorkerUsageInfo> usage_infos;
    161 
    162   std::map<GURL, ServiceWorkerUsageInfo> origins;
    163   for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
    164            registrations.begin();
    165        it != registrations.end();
    166        ++it) {
    167     const ServiceWorkerRegistrationInfo& registration_info = *it;
    168     GURL origin = registration_info.pattern.GetOrigin();
    169 
    170     ServiceWorkerUsageInfo& usage_info = origins[origin];
    171     if (usage_info.origin.is_empty())
    172       usage_info.origin = origin;
    173     usage_info.scopes.push_back(registration_info.pattern);
    174   }
    175 
    176   for (std::map<GURL, ServiceWorkerUsageInfo>::const_iterator it =
    177            origins.begin();
    178        it != origins.end();
    179        ++it) {
    180     usage_infos.push_back(it->second);
    181   }
    182 
    183   callback.Run(usage_infos);
    184 }
    185 
    186 namespace {
    187 
    188 void EmptySuccessCallback(bool success) {
    189 }
    190 
    191 }  // namespace
    192 
    193 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
    194   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    195   context_core_->storage()->GetAllRegistrations(base::Bind(
    196       &ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin,
    197       this,
    198       origin_url));
    199 }
    200 
    201 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin(
    202     const GURL& origin,
    203     const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
    204   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    205 
    206   for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
    207            registrations.begin();
    208        it != registrations.end();
    209        ++it) {
    210     const ServiceWorkerRegistrationInfo& registration_info = *it;
    211     if (origin == registration_info.pattern.GetOrigin()) {
    212       UnregisterServiceWorker(registration_info.pattern,
    213                               base::Bind(&EmptySuccessCallback));
    214     }
    215   }
    216 }
    217 
    218 void ServiceWorkerContextWrapper::AddObserver(
    219     ServiceWorkerContextObserver* observer) {
    220   observer_list_->AddObserver(observer);
    221 }
    222 
    223 void ServiceWorkerContextWrapper::RemoveObserver(
    224     ServiceWorkerContextObserver* observer) {
    225   observer_list_->RemoveObserver(observer);
    226 }
    227 
    228 void ServiceWorkerContextWrapper::SetBlobParametersForCache(
    229     net::URLRequestContextGetter* request_context,
    230     ChromeBlobStorageContext* blob_storage_context) {
    231   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    232 
    233   if (context_core_ && request_context && blob_storage_context) {
    234     context_core_->SetBlobParametersForCache(
    235         request_context->GetURLRequestContext(),
    236         blob_storage_context->context()->AsWeakPtr());
    237   }
    238 }
    239 
    240 void ServiceWorkerContextWrapper::InitInternal(
    241     const base::FilePath& user_data_directory,
    242     const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner,
    243     const scoped_refptr<base::SequencedTaskRunner>& database_task_runner,
    244     const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
    245     storage::QuotaManagerProxy* quota_manager_proxy) {
    246   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
    247     BrowserThread::PostTask(
    248         BrowserThread::IO,
    249         FROM_HERE,
    250         base::Bind(&ServiceWorkerContextWrapper::InitInternal,
    251                    this,
    252                    user_data_directory,
    253                    stores_task_runner,
    254                    database_task_runner,
    255                    disk_cache_thread,
    256                    make_scoped_refptr(quota_manager_proxy)));
    257     return;
    258   }
    259   DCHECK(!context_core_);
    260   context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
    261                                                    stores_task_runner,
    262                                                    database_task_runner,
    263                                                    disk_cache_thread,
    264                                                    quota_manager_proxy,
    265                                                    observer_list_.get(),
    266                                                    this));
    267 }
    268 
    269 void ServiceWorkerContextWrapper::ShutdownOnIO() {
    270   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    271   context_core_.reset();
    272 }
    273 
    274 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
    275     ServiceWorkerStatusCode status) {
    276   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    277   if (status != SERVICE_WORKER_OK) {
    278     context_core_.reset();
    279     return;
    280   }
    281   context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
    282   DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
    283 }
    284 
    285 }  // namespace content
    286