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/profiler/scoped_tracker.h"
18 #include "base/threading/sequenced_worker_pool.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/browser/service_worker/service_worker_request_handler.h"
24 #include "content/browser/service_worker/service_worker_utils.h"
25 #include "content/browser/service_worker/service_worker_version.h"
26 #include "content/browser/storage_partition_impl.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/service_worker_context.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/net_util.h"
32 #include "storage/browser/quota/quota_manager_proxy.h"
33 #include "storage/browser/quota/special_storage_policy.h"
39 typedef std::set
<std::string
> HeaderNameSet
;
40 base::LazyInstance
<HeaderNameSet
> g_excluded_header_name_set
=
41 LAZY_INSTANCE_INITIALIZER
;
43 void RunSoon(const base::Closure
& closure
) {
44 base::MessageLoop::current()->PostTask(FROM_HERE
, closure
);
47 void WorkerStarted(const ServiceWorkerContextWrapper::StatusCallback
& callback
,
48 ServiceWorkerStatusCode status
) {
49 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
50 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
51 base::Bind(callback
, status
));
54 void StartActiveWorkerOnIO(
55 const ServiceWorkerContextWrapper::StatusCallback
& callback
,
56 ServiceWorkerStatusCode status
,
57 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
58 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
59 if (status
== SERVICE_WORKER_OK
) {
60 // Pass the reference of |registration| to WorkerStarted callback to prevent
61 // it from being deleted while starting the worker. If the refcount of
62 // |registration| is 1, it will be deleted after WorkerStarted is called.
63 registration
->active_version()->StartWorker(
64 base::Bind(WorkerStarted
, callback
));
67 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
68 base::Bind(callback
, SERVICE_WORKER_ERROR_NOT_FOUND
));
73 void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
74 const std::set
<std::string
>& header_names
) {
75 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
76 tracked_objects::ScopedTracker
tracking_profile(
77 FROM_HERE_WITH_EXPLICIT_FUNCTION(
78 "477117 ServiceWorkerContext::AddExcludedHeadersForFetchEvent"));
79 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
80 g_excluded_header_name_set
.Get().insert(header_names
.begin(),
84 bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
85 const std::string
& header_name
) {
86 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
87 return g_excluded_header_name_set
.Get().find(header_name
) !=
88 g_excluded_header_name_set
.Get().end();
91 ServiceWorkerContext
* ServiceWorkerContext::GetServiceWorkerContext(
92 net::URLRequest
* request
) {
93 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
94 ServiceWorkerRequestHandler
* handler
=
95 ServiceWorkerRequestHandler::GetHandler(request
);
96 if (!handler
|| !handler
->context())
98 return handler
->context()->wrapper_
;
101 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
102 BrowserContext
* browser_context
)
104 new ObserverListThreadSafe
<ServiceWorkerContextObserver
>()),
105 process_manager_(new ServiceWorkerProcessManager(browser_context
)),
106 is_incognito_(false),
107 storage_partition_(nullptr) {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
111 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
114 void ServiceWorkerContextWrapper::Init(
115 const base::FilePath
& user_data_directory
,
116 storage::QuotaManagerProxy
* quota_manager_proxy
,
117 storage::SpecialStoragePolicy
* special_storage_policy
) {
118 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
120 is_incognito_
= user_data_directory
.empty();
121 base::SequencedWorkerPool
* pool
= BrowserThread::GetBlockingPool();
122 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager(
123 new ServiceWorkerDatabaseTaskManagerImpl(pool
));
124 scoped_refptr
<base::SingleThreadTaskRunner
> disk_cache_thread
=
125 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE
);
126 InitInternal(user_data_directory
,
127 database_task_manager
.Pass(),
130 special_storage_policy
);
133 void ServiceWorkerContextWrapper::Shutdown() {
134 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
136 storage_partition_
= nullptr;
137 process_manager_
->Shutdown();
138 BrowserThread::PostTask(
141 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO
, this));
144 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
145 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
146 context_core_
->DeleteAndStartOver(
147 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver
, this));
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(
170 base::Bind(continuation
, status
== SERVICE_WORKER_OK
));
173 void ServiceWorkerContextWrapper::RegisterServiceWorker(
175 const GURL
& script_url
,
176 const ResultCallback
& continuation
) {
177 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
178 BrowserThread::PostTask(
181 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker
,
188 if (!context_core_
.get()) {
189 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
190 BrowserThread::PostTask(
193 base::Bind(continuation
, false));
196 context()->RegisterServiceWorker(
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(
210 base::Bind(continuation
, status
== SERVICE_WORKER_OK
));
213 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
215 const ResultCallback
& continuation
) {
216 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
217 BrowserThread::PostTask(
220 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker
,
226 if (!context_core_
.get()) {
227 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
228 BrowserThread::PostTask(
231 base::Bind(continuation
, false));
235 context()->UnregisterServiceWorker(
237 base::Bind(&FinishUnregistrationOnIO
, continuation
));
240 void ServiceWorkerContextWrapper::UpdateRegistration(const GURL
& pattern
) {
241 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
242 BrowserThread::PostTask(
243 BrowserThread::IO
, FROM_HERE
,
244 base::Bind(&ServiceWorkerContextWrapper::UpdateRegistration
, this,
248 if (!context_core_
.get()) {
249 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
252 context_core_
->storage()->FindRegistrationForPattern(
254 base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate
,
258 void ServiceWorkerContextWrapper::StartServiceWorker(
260 const StatusCallback
& callback
) {
261 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
262 BrowserThread::PostTask(
263 BrowserThread::IO
, FROM_HERE
,
264 base::Bind(&ServiceWorkerContextWrapper::StartServiceWorker
, this,
268 if (!context_core_
.get()) {
269 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
270 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
271 base::Bind(callback
, SERVICE_WORKER_ERROR_ABORT
));
274 context_core_
->storage()->FindRegistrationForPattern(
275 pattern
, base::Bind(&StartActiveWorkerOnIO
, callback
));
278 static void DidFindRegistrationForDocument(
279 const net::CompletionCallback
& callback
,
280 ServiceWorkerStatusCode status
,
281 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
282 int rv
= registration
? net::OK
: net::ERR_CACHE_MISS
;
283 // Use RunSoon here because FindRegistrationForDocument can complete
284 // immediately but CanHandleMainResourceOffline must be async.
285 RunSoon(base::Bind(callback
, rv
));
288 void ServiceWorkerContextWrapper::CanHandleMainResourceOffline(
290 const GURL
& first_party
,
291 const net::CompletionCallback
& callback
) {
292 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
293 context()->storage()->FindRegistrationForDocument(
295 base::Bind(&DidFindRegistrationForDocument
, callback
));
298 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
299 const GetUsageInfoCallback
& callback
) {
300 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
301 if (!context_core_
.get()) {
302 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
303 BrowserThread::PostTask(
306 base::Bind(callback
, std::vector
<ServiceWorkerUsageInfo
>()));
309 context()->storage()->GetAllRegistrations(base::Bind(
310 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins
,
315 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
316 const GetUsageInfoCallback
& callback
,
317 const std::vector
<ServiceWorkerRegistrationInfo
>& registrations
) {
318 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
319 std::vector
<ServiceWorkerUsageInfo
> usage_infos
;
321 std::map
<GURL
, ServiceWorkerUsageInfo
> origins
;
322 for (const auto& registration_info
: registrations
) {
323 GURL origin
= registration_info
.pattern
.GetOrigin();
325 ServiceWorkerUsageInfo
& usage_info
= origins
[origin
];
326 if (usage_info
.origin
.is_empty())
327 usage_info
.origin
= origin
;
328 usage_info
.scopes
.push_back(registration_info
.pattern
);
329 usage_info
.total_size_bytes
+= registration_info
.stored_version_size_bytes
;
332 for (const auto& origin_info_pair
: origins
) {
333 usage_infos
.push_back(origin_info_pair
.second
);
335 callback
.Run(usage_infos
);
338 void ServiceWorkerContextWrapper::DidFindRegistrationForCheckHasServiceWorker(
339 const GURL
& other_url
,
340 const CheckHasServiceWorkerCallback
& callback
,
341 ServiceWorkerStatusCode status
,
342 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
343 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
345 if (status
!= SERVICE_WORKER_OK
) {
346 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
347 base::Bind(callback
, false));
351 DCHECK(registration
);
352 BrowserThread::PostTask(
353 BrowserThread::UI
, FROM_HERE
,
354 base::Bind(callback
, registration
->active_version() &&
355 ServiceWorkerUtils::ScopeMatches(
356 registration
->pattern(), other_url
)));
359 void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
360 ServiceWorkerStatusCode status
,
361 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
362 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
364 if (status
!= SERVICE_WORKER_OK
)
366 if (!context_core_
.get()) {
367 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
370 DCHECK(registration
);
371 context_core_
->UpdateServiceWorker(registration
.get(),
372 true /* force_bypass_cache */);
376 void StatusCodeToBoolCallbackAdapter(
377 const ServiceWorkerContext::ResultCallback
& callback
,
378 ServiceWorkerStatusCode code
) {
379 callback
.Run(code
== ServiceWorkerStatusCode::SERVICE_WORKER_OK
);
382 void EmptySuccessCallback(bool success
) {
386 void ServiceWorkerContextWrapper::DeleteForOrigin(
387 const GURL
& origin_url
,
388 const ResultCallback
& result
) {
389 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
390 if (!context_core_
.get()) {
391 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
392 BrowserThread::PostTask(
395 base::Bind(result
, false));
398 context()->UnregisterServiceWorkers(
399 origin_url
, base::Bind(&StatusCodeToBoolCallbackAdapter
, result
));
402 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL
& origin_url
) {
403 DeleteForOrigin(origin_url
, base::Bind(&EmptySuccessCallback
));
406 void ServiceWorkerContextWrapper::CheckHasServiceWorker(
408 const GURL
& other_url
,
409 const CheckHasServiceWorkerCallback
& callback
) {
410 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
411 BrowserThread::PostTask(
412 BrowserThread::IO
, FROM_HERE
,
413 base::Bind(&ServiceWorkerContextWrapper::CheckHasServiceWorker
, this,
414 url
, other_url
, callback
));
417 if (!context_core_
.get()) {
418 LOG(ERROR
) << "ServiceWorkerContextCore is no longer alive.";
419 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
420 base::Bind(callback
, false));
423 GURL stripped_url
= net::SimplifyUrlForRequest(url
);
424 context()->storage()->FindRegistrationForDocument(
425 stripped_url
, base::Bind(&ServiceWorkerContextWrapper::
426 DidFindRegistrationForCheckHasServiceWorker
,
427 this, other_url
, callback
));
430 ServiceWorkerRegistration
* ServiceWorkerContextWrapper::GetLiveRegistration(
431 int64_t registration_id
) {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
435 return context_core_
->GetLiveRegistration(registration_id
);
438 ServiceWorkerVersion
* ServiceWorkerContextWrapper::GetLiveVersion(
439 int64_t version_id
) {
440 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
443 return context_core_
->GetLiveVersion(version_id
);
446 std::vector
<ServiceWorkerRegistrationInfo
>
447 ServiceWorkerContextWrapper::GetAllLiveRegistrationInfo() {
448 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
450 return std::vector
<ServiceWorkerRegistrationInfo
>();
451 return context_core_
->GetAllLiveRegistrationInfo();
454 std::vector
<ServiceWorkerVersionInfo
>
455 ServiceWorkerContextWrapper::GetAllLiveVersionInfo() {
456 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
458 return std::vector
<ServiceWorkerVersionInfo
>();
459 return context_core_
->GetAllLiveVersionInfo();
462 void ServiceWorkerContextWrapper::FindRegistrationForDocument(
463 const GURL
& document_url
,
464 const FindRegistrationCallback
& callback
) {
465 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
466 if (!context_core_
) {
467 // FindRegistrationForDocument() can run the callback synchronously.
468 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, nullptr);
471 context_core_
->storage()->FindRegistrationForDocument(document_url
, callback
);
474 void ServiceWorkerContextWrapper::FindRegistrationForId(
475 int64_t registration_id
,
477 const FindRegistrationCallback
& callback
) {
478 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
479 if (!context_core_
) {
480 // FindRegistrationForId() can run the callback synchronously.
481 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, nullptr);
484 context_core_
->storage()->FindRegistrationForId(registration_id
, origin
,
488 void ServiceWorkerContextWrapper::GetAllRegistrations(
489 const GetRegistrationsInfosCallback
& callback
) {
490 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
491 if (!context_core_
) {
492 RunSoon(base::Bind(callback
, std::vector
<ServiceWorkerRegistrationInfo
>()));
495 context_core_
->storage()->GetAllRegistrations(callback
);
498 void ServiceWorkerContextWrapper::GetRegistrationUserData(
499 int64_t registration_id
,
500 const std::string
& key
,
501 const GetUserDataCallback
& callback
) {
502 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
503 if (!context_core_
) {
504 RunSoon(base::Bind(callback
, std::string(), SERVICE_WORKER_ERROR_ABORT
));
507 context_core_
->storage()->GetUserData(registration_id
, key
, callback
);
510 void ServiceWorkerContextWrapper::StoreRegistrationUserData(
511 int64_t registration_id
,
513 const std::string
& key
,
514 const std::string
& data
,
515 const StatusCallback
& callback
) {
516 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
517 if (!context_core_
) {
518 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_ABORT
));
521 context_core_
->storage()->StoreUserData(registration_id
, origin
, key
, data
,
525 void ServiceWorkerContextWrapper::ClearRegistrationUserData(
526 int64_t registration_id
,
527 const std::string
& key
,
528 const StatusCallback
& callback
) {
529 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
530 if (!context_core_
) {
531 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_ABORT
));
534 context_core_
->storage()->ClearUserData(registration_id
, key
, callback
);
537 void ServiceWorkerContextWrapper::GetUserDataForAllRegistrations(
538 const std::string
& key
,
539 const GetUserDataForAllRegistrationsCallback
& callback
) {
540 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
541 if (!context_core_
) {
542 RunSoon(base::Bind(callback
, std::vector
<std::pair
<int64_t, std::string
>>(),
543 SERVICE_WORKER_ERROR_ABORT
));
546 context_core_
->storage()->GetUserDataForAllRegistrations(key
, callback
);
549 void ServiceWorkerContextWrapper::AddObserver(
550 ServiceWorkerContextObserver
* observer
) {
551 observer_list_
->AddObserver(observer
);
554 void ServiceWorkerContextWrapper::RemoveObserver(
555 ServiceWorkerContextObserver
* observer
) {
556 observer_list_
->RemoveObserver(observer
);
559 void ServiceWorkerContextWrapper::InitInternal(
560 const base::FilePath
& user_data_directory
,
561 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager
,
562 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
563 storage::QuotaManagerProxy
* quota_manager_proxy
,
564 storage::SpecialStoragePolicy
* special_storage_policy
) {
565 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
566 BrowserThread::PostTask(
569 base::Bind(&ServiceWorkerContextWrapper::InitInternal
,
572 base::Passed(&database_task_manager
),
574 make_scoped_refptr(quota_manager_proxy
),
575 make_scoped_refptr(special_storage_policy
)));
578 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
579 tracked_objects::ScopedTracker
tracking_profile(
580 FROM_HERE_WITH_EXPLICIT_FUNCTION(
581 "477117 ServiceWorkerContextWrapper::InitInternal"));
582 DCHECK(!context_core_
);
583 if (quota_manager_proxy
) {
584 quota_manager_proxy
->RegisterClient(new ServiceWorkerQuotaClient(this));
586 context_core_
.reset(new ServiceWorkerContextCore(user_data_directory
,
587 database_task_manager
.Pass(),
590 special_storage_policy
,
591 observer_list_
.get(),
595 void ServiceWorkerContextWrapper::ShutdownOnIO() {
596 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
597 context_core_
.reset();
600 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
601 ServiceWorkerStatusCode status
) {
602 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
603 if (status
!= SERVICE_WORKER_OK
) {
604 context_core_
.reset();
607 context_core_
.reset(new ServiceWorkerContextCore(context_core_
.get(), this));
608 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
610 observer_list_
->Notify(FROM_HERE
,
611 &ServiceWorkerContextObserver::OnStorageWiped
);
614 ServiceWorkerContextCore
* ServiceWorkerContextWrapper::context() {
615 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
616 return context_core_
.get();
619 } // namespace content