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.
5 #include "content/browser/service_worker/service_worker_context_wrapper.h"
12 #include "base/barrier_closure.h"
13 #include "base/bind.h"
14 #include "base/files/file_path.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "content/browser/fileapi/chrome_blob_storage_context.h"
19 #include "content/browser/service_worker/service_worker_context_core.h"
20 #include "content/browser/service_worker/service_worker_context_observer.h"
21 #include "content/browser/service_worker/service_worker_process_manager.h"
22 #include "content/browser/service_worker/service_worker_quota_client.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/service_worker_context.h"
26 #include "net/url_request/url_request_context_getter.h"
27 #include "storage/browser/blob/blob_storage_context.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "storage/browser/quota/special_storage_policy.h"
35 typedef std::set<std::string> HeaderNameSet;
36 base::LazyInstance<HeaderNameSet> g_excluded_header_name_set =
37 LAZY_INSTANCE_INITIALIZER;
40 void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
41 const std::set<std::string>& header_names) {
42 DCHECK_CURRENTLY_ON(BrowserThread::IO);
43 g_excluded_header_name_set.Get().insert(header_names.begin(),
47 bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
48 const std::string& header_name) {
49 DCHECK_CURRENTLY_ON(BrowserThread::IO);
50 return g_excluded_header_name_set.Get().find(header_name) !=
51 g_excluded_header_name_set.Get().end();
54 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
55 BrowserContext* browser_context)
57 new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
58 process_manager_(new ServiceWorkerProcessManager(browser_context)),
59 is_incognito_(false) {
62 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
65 void ServiceWorkerContextWrapper::Init(
66 const base::FilePath& user_data_directory,
67 storage::QuotaManagerProxy* quota_manager_proxy,
68 storage::SpecialStoragePolicy* special_storage_policy) {
69 is_incognito_ = user_data_directory.empty();
70 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
71 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
72 new ServiceWorkerDatabaseTaskManagerImpl(pool));
73 scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
74 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
75 scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
76 pool->GetSequencedTaskRunnerWithShutdownBehavior(
77 BrowserThread::GetBlockingPool()->GetSequenceToken(),
78 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
79 InitInternal(user_data_directory,
81 database_task_manager.Pass(),
84 special_storage_policy);
87 void ServiceWorkerContextWrapper::Shutdown() {
88 DCHECK_CURRENTLY_ON(BrowserThread::UI);
89 process_manager_->Shutdown();
90 BrowserThread::PostTask(
93 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
96 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
97 DCHECK_CURRENTLY_ON(BrowserThread::IO);
98 context_core_->DeleteAndStartOver(
99 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
102 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
103 DCHECK_CURRENTLY_ON(BrowserThread::IO);
104 return context_core_.get();
107 static void FinishRegistrationOnIO(
108 const ServiceWorkerContext::ResultCallback& continuation,
109 ServiceWorkerStatusCode status,
110 int64 registration_id) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
112 BrowserThread::PostTask(
115 base::Bind(continuation, status == SERVICE_WORKER_OK));
118 void ServiceWorkerContextWrapper::RegisterServiceWorker(
120 const GURL& script_url,
121 const ResultCallback& continuation) {
122 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
123 BrowserThread::PostTask(
126 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
133 if (!context_core_.get()) {
134 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
135 BrowserThread::PostTask(
138 base::Bind(continuation, false));
141 context()->RegisterServiceWorker(
144 NULL /* provider_host */,
145 base::Bind(&FinishRegistrationOnIO, continuation));
148 static void FinishUnregistrationOnIO(
149 const ServiceWorkerContext::ResultCallback& continuation,
150 ServiceWorkerStatusCode status) {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO);
152 BrowserThread::PostTask(
155 base::Bind(continuation, status == SERVICE_WORKER_OK));
158 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
160 const ResultCallback& continuation) {
161 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
162 BrowserThread::PostTask(
165 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
171 if (!context_core_.get()) {
172 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
173 BrowserThread::PostTask(
176 base::Bind(continuation, false));
180 context()->UnregisterServiceWorker(
182 base::Bind(&FinishUnregistrationOnIO, continuation));
185 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
186 const GetUsageInfoCallback& callback) {
187 DCHECK_CURRENTLY_ON(BrowserThread::IO);
188 if (!context_core_.get()) {
189 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
190 BrowserThread::PostTask(
193 base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
196 context()->storage()->GetAllRegistrations(base::Bind(
197 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
202 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
203 const GetUsageInfoCallback& callback,
204 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
205 DCHECK_CURRENTLY_ON(BrowserThread::IO);
206 std::vector<ServiceWorkerUsageInfo> usage_infos;
208 std::map<GURL, ServiceWorkerUsageInfo> origins;
209 for (const auto& registration_info : registrations) {
210 GURL origin = registration_info.pattern.GetOrigin();
212 ServiceWorkerUsageInfo& usage_info = origins[origin];
213 if (usage_info.origin.is_empty())
214 usage_info.origin = origin;
215 usage_info.scopes.push_back(registration_info.pattern);
216 usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
219 for (const auto& origin_info_pair : origins) {
220 usage_infos.push_back(origin_info_pair.second);
222 callback.Run(usage_infos);
226 void StatusCodeToBoolCallbackAdapter(
227 const ServiceWorkerContext::ResultCallback& callback,
228 ServiceWorkerStatusCode code) {
229 callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
232 void EmptySuccessCallback(bool success) {
236 void ServiceWorkerContextWrapper::DeleteForOrigin(
237 const GURL& origin_url,
238 const ResultCallback& result) {
239 DCHECK_CURRENTLY_ON(BrowserThread::IO);
240 if (!context_core_.get()) {
241 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
242 BrowserThread::PostTask(
245 base::Bind(result, false));
248 context()->UnregisterServiceWorkers(
249 origin_url, base::Bind(&StatusCodeToBoolCallbackAdapter, result));
252 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
253 DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
256 void ServiceWorkerContextWrapper::AddObserver(
257 ServiceWorkerContextObserver* observer) {
258 observer_list_->AddObserver(observer);
261 void ServiceWorkerContextWrapper::RemoveObserver(
262 ServiceWorkerContextObserver* observer) {
263 observer_list_->RemoveObserver(observer);
266 void ServiceWorkerContextWrapper::SetBlobParametersForCache(
267 net::URLRequestContextGetter* request_context,
268 ChromeBlobStorageContext* blob_storage_context) {
269 DCHECK_CURRENTLY_ON(BrowserThread::IO);
271 if (context_core_ && request_context && blob_storage_context) {
272 context_core_->SetBlobParametersForCache(
273 request_context->GetURLRequestContext(),
274 blob_storage_context->context()->AsWeakPtr());
278 void ServiceWorkerContextWrapper::InitInternal(
279 const base::FilePath& user_data_directory,
280 const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner,
281 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
282 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
283 storage::QuotaManagerProxy* quota_manager_proxy,
284 storage::SpecialStoragePolicy* special_storage_policy) {
285 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
286 BrowserThread::PostTask(
289 base::Bind(&ServiceWorkerContextWrapper::InitInternal,
293 base::Passed(&database_task_manager),
295 make_scoped_refptr(quota_manager_proxy),
296 make_scoped_refptr(special_storage_policy)));
299 DCHECK(!context_core_);
300 if (quota_manager_proxy) {
301 quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
303 context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
305 database_task_manager.Pass(),
308 special_storage_policy,
309 observer_list_.get(),
313 void ServiceWorkerContextWrapper::ShutdownOnIO() {
314 DCHECK_CURRENTLY_ON(BrowserThread::IO);
315 context_core_.reset();
318 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
319 ServiceWorkerStatusCode status) {
320 DCHECK_CURRENTLY_ON(BrowserThread::IO);
321 if (status != SERVICE_WORKER_OK) {
322 context_core_.reset();
325 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
326 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
329 } // namespace content