Simplify ChildProcessLauncher
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_context_wrapper.cc
blob6c857eb63672be72dd91263cb0f653560050f84d
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"
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <vector>
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/service_worker/service_worker_context_core.h"
19 #include "content/browser/service_worker/service_worker_context_observer.h"
20 #include "content/browser/service_worker/service_worker_process_manager.h"
21 #include "content/browser/service_worker/service_worker_quota_client.h"
22 #include "content/browser/service_worker/service_worker_request_handler.h"
23 #include "content/browser/service_worker/service_worker_utils.h"
24 #include "content/browser/service_worker/service_worker_version.h"
25 #include "content/browser/storage_partition_impl.h"
26 #include "content/public/browser/browser_context.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/service_worker_context.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/net_util.h"
31 #include "storage/browser/quota/quota_manager_proxy.h"
32 #include "storage/browser/quota/special_storage_policy.h"
34 namespace content {
36 namespace {
38 typedef std::set<std::string> HeaderNameSet;
39 base::LazyInstance<HeaderNameSet> g_excluded_header_name_set =
40 LAZY_INSTANCE_INITIALIZER;
42 void RunSoon(const base::Closure& closure) {
43 base::MessageLoop::current()->PostTask(FROM_HERE, closure);
46 void WorkerStarted(const ServiceWorkerContextWrapper::StatusCallback& callback,
47 ServiceWorkerStatusCode status) {
48 DCHECK_CURRENTLY_ON(BrowserThread::IO);
49 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
50 base::Bind(callback, status));
53 void StartActiveWorkerOnIO(
54 const ServiceWorkerContextWrapper::StatusCallback& callback,
55 ServiceWorkerStatusCode status,
56 const scoped_refptr<ServiceWorkerRegistration>& registration) {
57 DCHECK_CURRENTLY_ON(BrowserThread::IO);
58 if (status == SERVICE_WORKER_OK) {
59 // Pass the reference of |registration| to WorkerStarted callback to prevent
60 // it from being deleted while starting the worker. If the refcount of
61 // |registration| is 1, it will be deleted after WorkerStarted is called.
62 registration->active_version()->StartWorker(
63 base::Bind(WorkerStarted, callback));
64 return;
66 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
67 base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
70 } // namespace
72 void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
73 const std::set<std::string>& header_names) {
74 DCHECK_CURRENTLY_ON(BrowserThread::IO);
75 g_excluded_header_name_set.Get().insert(header_names.begin(),
76 header_names.end());
79 bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
80 const std::string& header_name) {
81 DCHECK_CURRENTLY_ON(BrowserThread::IO);
82 return g_excluded_header_name_set.Get().find(header_name) !=
83 g_excluded_header_name_set.Get().end();
86 ServiceWorkerContext* ServiceWorkerContext::GetServiceWorkerContext(
87 net::URLRequest* request) {
88 DCHECK_CURRENTLY_ON(BrowserThread::IO);
89 ServiceWorkerRequestHandler* handler =
90 ServiceWorkerRequestHandler::GetHandler(request);
91 if (!handler || !handler->context())
92 return nullptr;
93 return handler->context()->wrapper_;
96 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
97 BrowserContext* browser_context)
98 : observer_list_(
99 new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
100 process_manager_(new ServiceWorkerProcessManager(browser_context)),
101 is_incognito_(false),
102 storage_partition_(nullptr) {
103 DCHECK_CURRENTLY_ON(BrowserThread::UI);
106 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
109 void ServiceWorkerContextWrapper::Init(
110 const base::FilePath& user_data_directory,
111 storage::QuotaManagerProxy* quota_manager_proxy,
112 storage::SpecialStoragePolicy* special_storage_policy) {
113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
115 is_incognito_ = user_data_directory.empty();
116 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
117 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
118 new ServiceWorkerDatabaseTaskManagerImpl(pool));
119 scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
120 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
121 InitInternal(user_data_directory,
122 database_task_manager.Pass(),
123 disk_cache_thread,
124 quota_manager_proxy,
125 special_storage_policy);
128 void ServiceWorkerContextWrapper::Shutdown() {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI);
131 storage_partition_ = nullptr;
132 process_manager_->Shutdown();
133 BrowserThread::PostTask(
134 BrowserThread::IO,
135 FROM_HERE,
136 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
139 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
140 DCHECK_CURRENTLY_ON(BrowserThread::IO);
141 context_core_->DeleteAndStartOver(
142 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
145 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
146 DCHECK_CURRENTLY_ON(BrowserThread::IO);
147 return context_core_.get();
150 StoragePartitionImpl* ServiceWorkerContextWrapper::storage_partition() const {
151 DCHECK_CURRENTLY_ON(BrowserThread::UI);
152 return storage_partition_;
155 void ServiceWorkerContextWrapper::set_storage_partition(
156 StoragePartitionImpl* storage_partition) {
157 DCHECK_CURRENTLY_ON(BrowserThread::UI);
158 storage_partition_ = storage_partition;
161 static void FinishRegistrationOnIO(
162 const ServiceWorkerContext::ResultCallback& continuation,
163 ServiceWorkerStatusCode status,
164 const std::string& status_message,
165 int64 registration_id) {
166 DCHECK_CURRENTLY_ON(BrowserThread::IO);
167 BrowserThread::PostTask(
168 BrowserThread::UI,
169 FROM_HERE,
170 base::Bind(continuation, status == SERVICE_WORKER_OK));
173 void ServiceWorkerContextWrapper::RegisterServiceWorker(
174 const GURL& pattern,
175 const GURL& script_url,
176 const ResultCallback& continuation) {
177 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
178 BrowserThread::PostTask(
179 BrowserThread::IO,
180 FROM_HERE,
181 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
182 this,
183 pattern,
184 script_url,
185 continuation));
186 return;
188 if (!context_core_.get()) {
189 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
190 BrowserThread::PostTask(
191 BrowserThread::IO,
192 FROM_HERE,
193 base::Bind(continuation, false));
194 return;
196 context()->RegisterServiceWorker(
197 pattern,
198 script_url,
199 NULL /* provider_host */,
200 base::Bind(&FinishRegistrationOnIO, continuation));
203 static void FinishUnregistrationOnIO(
204 const ServiceWorkerContext::ResultCallback& continuation,
205 ServiceWorkerStatusCode status) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 BrowserThread::PostTask(
208 BrowserThread::UI,
209 FROM_HERE,
210 base::Bind(continuation, status == SERVICE_WORKER_OK));
213 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
214 const GURL& pattern,
215 const ResultCallback& continuation) {
216 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
217 BrowserThread::PostTask(
218 BrowserThread::IO,
219 FROM_HERE,
220 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
221 this,
222 pattern,
223 continuation));
224 return;
226 if (!context_core_.get()) {
227 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
228 BrowserThread::PostTask(
229 BrowserThread::IO,
230 FROM_HERE,
231 base::Bind(continuation, false));
232 return;
235 context()->UnregisterServiceWorker(
236 pattern,
237 base::Bind(&FinishUnregistrationOnIO, continuation));
240 void ServiceWorkerContextWrapper::StartServiceWorker(
241 const GURL& pattern,
242 const StatusCallback& callback) {
243 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
244 BrowserThread::PostTask(
245 BrowserThread::IO, FROM_HERE,
246 base::Bind(&ServiceWorkerContextWrapper::StartServiceWorker, this,
247 pattern, callback));
248 return;
250 if (!context_core_.get()) {
251 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
252 BrowserThread::PostTask(
253 BrowserThread::UI, FROM_HERE,
254 base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
255 return;
257 context_core_->storage()->FindRegistrationForPattern(
258 pattern, base::Bind(&StartActiveWorkerOnIO, callback));
261 static void DidFindRegistrationForDocument(
262 const net::CompletionCallback& callback,
263 ServiceWorkerStatusCode status,
264 const scoped_refptr<ServiceWorkerRegistration>& registration) {
265 int rv = registration ? net::OK : net::ERR_CACHE_MISS;
266 // Use RunSoon here because FindRegistrationForDocument can complete
267 // immediately but CanHandleMainResourceOffline must be async.
268 RunSoon(base::Bind(callback, rv));
271 void ServiceWorkerContextWrapper::CanHandleMainResourceOffline(
272 const GURL& url,
273 const GURL& first_party,
274 const net::CompletionCallback& callback) {
275 DCHECK_CURRENTLY_ON(BrowserThread::IO);
276 context()->storage()->FindRegistrationForDocument(
277 url,
278 base::Bind(&DidFindRegistrationForDocument, callback));
281 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
282 const GetUsageInfoCallback& callback) {
283 DCHECK_CURRENTLY_ON(BrowserThread::IO);
284 if (!context_core_.get()) {
285 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
286 BrowserThread::PostTask(
287 BrowserThread::IO,
288 FROM_HERE,
289 base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
290 return;
292 context()->storage()->GetAllRegistrations(base::Bind(
293 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
294 this,
295 callback));
298 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
299 const GetUsageInfoCallback& callback,
300 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
301 DCHECK_CURRENTLY_ON(BrowserThread::IO);
302 std::vector<ServiceWorkerUsageInfo> usage_infos;
304 std::map<GURL, ServiceWorkerUsageInfo> origins;
305 for (const auto& registration_info : registrations) {
306 GURL origin = registration_info.pattern.GetOrigin();
308 ServiceWorkerUsageInfo& usage_info = origins[origin];
309 if (usage_info.origin.is_empty())
310 usage_info.origin = origin;
311 usage_info.scopes.push_back(registration_info.pattern);
312 usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
315 for (const auto& origin_info_pair : origins) {
316 usage_infos.push_back(origin_info_pair.second);
318 callback.Run(usage_infos);
321 void ServiceWorkerContextWrapper::DidFindRegistrationForCheckHasServiceWorker(
322 const GURL& other_url,
323 const CheckHasServiceWorkerCallback& callback,
324 ServiceWorkerStatusCode status,
325 const scoped_refptr<ServiceWorkerRegistration>& registration) {
326 DCHECK_CURRENTLY_ON(BrowserThread::IO);
328 if (status != SERVICE_WORKER_OK) {
329 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
330 base::Bind(callback, false));
331 return;
334 DCHECK(registration);
335 BrowserThread::PostTask(
336 BrowserThread::UI, FROM_HERE,
337 base::Bind(callback, registration->active_version() &&
338 ServiceWorkerUtils::ScopeMatches(
339 registration->pattern(), other_url)));
342 namespace {
343 void StatusCodeToBoolCallbackAdapter(
344 const ServiceWorkerContext::ResultCallback& callback,
345 ServiceWorkerStatusCode code) {
346 callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
349 void EmptySuccessCallback(bool success) {
351 } // namespace
353 void ServiceWorkerContextWrapper::DeleteForOrigin(
354 const GURL& origin_url,
355 const ResultCallback& result) {
356 DCHECK_CURRENTLY_ON(BrowserThread::IO);
357 if (!context_core_.get()) {
358 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
359 BrowserThread::PostTask(
360 BrowserThread::IO,
361 FROM_HERE,
362 base::Bind(result, false));
363 return;
365 context()->UnregisterServiceWorkers(
366 origin_url, base::Bind(&StatusCodeToBoolCallbackAdapter, result));
369 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
370 DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
373 void ServiceWorkerContextWrapper::CheckHasServiceWorker(
374 const GURL& url,
375 const GURL& other_url,
376 const CheckHasServiceWorkerCallback& callback) {
377 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
378 BrowserThread::PostTask(
379 BrowserThread::IO, FROM_HERE,
380 base::Bind(&ServiceWorkerContextWrapper::CheckHasServiceWorker, this,
381 url, other_url, callback));
382 return;
384 if (!context_core_.get()) {
385 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
386 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
387 base::Bind(callback, false));
388 return;
390 GURL stripped_url = net::SimplifyUrlForRequest(url);
391 context()->storage()->FindRegistrationForDocument(
392 stripped_url, base::Bind(&ServiceWorkerContextWrapper::
393 DidFindRegistrationForCheckHasServiceWorker,
394 this, other_url, callback));
397 void ServiceWorkerContextWrapper::AddObserver(
398 ServiceWorkerContextObserver* observer) {
399 observer_list_->AddObserver(observer);
402 void ServiceWorkerContextWrapper::RemoveObserver(
403 ServiceWorkerContextObserver* observer) {
404 observer_list_->RemoveObserver(observer);
407 void ServiceWorkerContextWrapper::InitInternal(
408 const base::FilePath& user_data_directory,
409 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
410 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
411 storage::QuotaManagerProxy* quota_manager_proxy,
412 storage::SpecialStoragePolicy* special_storage_policy) {
413 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
414 BrowserThread::PostTask(
415 BrowserThread::IO,
416 FROM_HERE,
417 base::Bind(&ServiceWorkerContextWrapper::InitInternal,
418 this,
419 user_data_directory,
420 base::Passed(&database_task_manager),
421 disk_cache_thread,
422 make_scoped_refptr(quota_manager_proxy),
423 make_scoped_refptr(special_storage_policy)));
424 return;
426 DCHECK(!context_core_);
427 if (quota_manager_proxy) {
428 quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
430 context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
431 database_task_manager.Pass(),
432 disk_cache_thread,
433 quota_manager_proxy,
434 special_storage_policy,
435 observer_list_.get(),
436 this));
439 void ServiceWorkerContextWrapper::ShutdownOnIO() {
440 DCHECK_CURRENTLY_ON(BrowserThread::IO);
441 context_core_.reset();
444 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
445 ServiceWorkerStatusCode status) {
446 DCHECK_CURRENTLY_ON(BrowserThread::IO);
447 if (status != SERVICE_WORKER_OK) {
448 context_core_.reset();
449 return;
451 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
452 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
454 observer_list_->Notify(FROM_HERE,
455 &ServiceWorkerContextObserver::OnStorageWiped);
458 } // namespace content