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_storage.h"
7 #include "base/bind_helpers.h"
8 #include "base/files/file_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/task_runner_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/trace_event/trace_event.h"
15 #include "content/browser/service_worker/service_worker_context_core.h"
16 #include "content/browser/service_worker/service_worker_disk_cache.h"
17 #include "content/browser/service_worker/service_worker_info.h"
18 #include "content/browser/service_worker/service_worker_metrics.h"
19 #include "content/browser/service_worker/service_worker_registration.h"
20 #include "content/browser/service_worker/service_worker_utils.h"
21 #include "content/browser/service_worker/service_worker_version.h"
22 #include "content/common/service_worker/service_worker_types.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/base/completion_callback.h"
25 #include "net/base/io_buffer.h"
26 #include "net/base/net_errors.h"
27 #include "storage/browser/quota/quota_manager_proxy.h"
28 #include "storage/browser/quota/special_storage_policy.h"
34 void RunSoon(const tracked_objects::Location
& from_here
,
35 const base::Closure
& closure
) {
36 base::ThreadTaskRunnerHandle::Get()->PostTask(from_here
, closure
);
40 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
41 ServiceWorkerStatusCode status
,
42 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
43 if (registration
&& registration
->is_deleted()) {
44 // It's past the point of no return and no longer findable.
45 callback
.Run(SERVICE_WORKER_ERROR_NOT_FOUND
, nullptr);
48 callback
.Run(status
, registration
);
51 void CompleteFindSoon(
52 const tracked_objects::Location
& from_here
,
53 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
54 ServiceWorkerStatusCode status
,
55 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
57 base::Bind(&CompleteFindNow
, registration
, status
, callback
));
60 const base::FilePath::CharType kDatabaseName
[] =
61 FILE_PATH_LITERAL("Database");
62 const base::FilePath::CharType kDiskCacheName
[] =
63 FILE_PATH_LITERAL("Cache");
65 const int kMaxMemDiskCacheSize
= 10 * 1024 * 1024;
66 const int kMaxDiskCacheSize
= 250 * 1024 * 1024;
68 ServiceWorkerStatusCode
DatabaseStatusToStatusCode(
69 ServiceWorkerDatabase::Status status
) {
71 case ServiceWorkerDatabase::STATUS_OK
:
72 return SERVICE_WORKER_OK
;
73 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
:
74 return SERVICE_WORKER_ERROR_NOT_FOUND
;
75 case ServiceWorkerDatabase::STATUS_ERROR_MAX
:
78 return SERVICE_WORKER_ERROR_FAILED
;
82 class ResponseComparer
: public base::RefCounted
<ResponseComparer
> {
85 base::WeakPtr
<ServiceWorkerStorage
> owner
,
86 scoped_ptr
<ServiceWorkerResponseReader
> lhs
,
87 scoped_ptr
<ServiceWorkerResponseReader
> rhs
,
88 const ServiceWorkerStorage::CompareCallback
& callback
)
90 completion_callback_(callback
),
91 lhs_reader_(lhs
.release()),
92 rhs_reader_(rhs
.release()),
100 friend class base::RefCounted
<ResponseComparer
>;
102 static const int kBufferSize
= 16 * 1024;
104 ~ResponseComparer() {}
106 void OnReadInfoComplete(int result
);
108 void OnReadDataComplete(int result
);
110 base::WeakPtr
<ServiceWorkerStorage
> owner_
;
111 ServiceWorkerStorage::CompareCallback completion_callback_
;
112 scoped_ptr
<ServiceWorkerResponseReader
> lhs_reader_
;
113 scoped_refptr
<HttpResponseInfoIOBuffer
> lhs_info_
;
114 scoped_refptr
<net::IOBuffer
> lhs_buffer_
;
115 scoped_ptr
<ServiceWorkerResponseReader
> rhs_reader_
;
116 scoped_refptr
<HttpResponseInfoIOBuffer
> rhs_info_
;
117 scoped_refptr
<net::IOBuffer
> rhs_buffer_
;
118 int completion_count_
;
119 int previous_result_
;
120 DISALLOW_COPY_AND_ASSIGN(ResponseComparer
);
123 void ResponseComparer::Start() {
124 lhs_buffer_
= new net::IOBuffer(kBufferSize
);
125 lhs_info_
= new HttpResponseInfoIOBuffer();
126 rhs_buffer_
= new net::IOBuffer(kBufferSize
);
127 rhs_info_
= new HttpResponseInfoIOBuffer();
132 void ResponseComparer::ReadInfos() {
133 lhs_reader_
->ReadInfo(
134 lhs_info_
.get(), base::Bind(&ResponseComparer::OnReadInfoComplete
, this));
135 rhs_reader_
->ReadInfo(
136 rhs_info_
.get(), base::Bind(&ResponseComparer::OnReadInfoComplete
, this));
139 void ResponseComparer::OnReadInfoComplete(int result
) {
140 if (completion_callback_
.is_null() || !owner_
)
143 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
144 completion_callback_
.Reset();
147 if (++completion_count_
!= 2)
150 if (lhs_info_
->response_data_size
!= rhs_info_
->response_data_size
) {
151 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
157 void ResponseComparer::ReadSomeData() {
158 completion_count_
= 0;
159 lhs_reader_
->ReadData(
162 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
163 rhs_reader_
->ReadData(
166 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
169 void ResponseComparer::OnReadDataComplete(int result
) {
170 if (completion_callback_
.is_null() || !owner_
)
173 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
174 completion_callback_
.Reset();
177 if (++completion_count_
!= 2) {
178 previous_result_
= result
;
182 // TODO(michaeln): Probably shouldn't assume that the amounts read from
183 // each reader will always be the same. This would wrongly signal false
185 if (result
!= previous_result_
) {
186 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
191 completion_callback_
.Run(SERVICE_WORKER_OK
, true);
196 memcmp(lhs_buffer_
->data(), rhs_buffer_
->data(), result
);
197 if (compare_result
!= 0) {
198 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
207 ServiceWorkerStorage::InitialData::InitialData()
208 : next_registration_id(kInvalidServiceWorkerRegistrationId
),
209 next_version_id(kInvalidServiceWorkerVersionId
),
210 next_resource_id(kInvalidServiceWorkerResourceId
) {
213 ServiceWorkerStorage::InitialData::~InitialData() {
216 ServiceWorkerStorage::
217 DidDeleteRegistrationParams::DidDeleteRegistrationParams()
218 : registration_id(kInvalidServiceWorkerRegistrationId
) {
221 ServiceWorkerStorage::
222 DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
225 ServiceWorkerStorage::~ServiceWorkerStorage() {
226 ClearSessionOnlyOrigins();
227 weak_factory_
.InvalidateWeakPtrs();
228 database_task_manager_
->GetTaskRunner()->DeleteSoon(FROM_HERE
,
229 database_
.release());
233 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
234 const base::FilePath
& path
,
235 base::WeakPtr
<ServiceWorkerContextCore
> context
,
236 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager
,
237 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
238 storage::QuotaManagerProxy
* quota_manager_proxy
,
239 storage::SpecialStoragePolicy
* special_storage_policy
) {
240 return make_scoped_ptr(new ServiceWorkerStorage(path
,
242 database_task_manager
.Pass(),
245 special_storage_policy
));
249 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
250 base::WeakPtr
<ServiceWorkerContextCore
> context
,
251 ServiceWorkerStorage
* old_storage
) {
252 return make_scoped_ptr(
253 new ServiceWorkerStorage(old_storage
->path_
,
255 old_storage
->database_task_manager_
->Clone(),
256 old_storage
->disk_cache_thread_
,
257 old_storage
->quota_manager_proxy_
.get(),
258 old_storage
->special_storage_policy_
.get()));
261 void ServiceWorkerStorage::FindRegistrationForDocument(
262 const GURL
& document_url
,
263 const FindRegistrationCallback
& callback
) {
264 DCHECK(!document_url
.has_ref());
265 if (!LazyInitialize(base::Bind(
266 &ServiceWorkerStorage::FindRegistrationForDocument
,
267 weak_factory_
.GetWeakPtr(), document_url
, callback
))) {
268 if (state_
!= INITIALIZING
|| !context_
) {
269 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
270 SERVICE_WORKER_ERROR_FAILED
, callback
);
272 TRACE_EVENT_INSTANT1(
274 "ServiceWorkerStorage::FindRegistrationForDocument:LazyInitialize",
275 TRACE_EVENT_SCOPE_THREAD
,
276 "URL", document_url
.spec());
279 DCHECK_EQ(INITIALIZED
, state_
);
281 // See if there are any stored registrations for the origin.
282 if (!ContainsKey(registered_origins_
, document_url
.GetOrigin())) {
283 // Look for something currently being installed.
284 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
285 FindInstallingRegistrationForDocument(document_url
);
286 ServiceWorkerStatusCode status
= installing_registration
.get() ?
287 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
;
288 TRACE_EVENT_INSTANT2(
290 "ServiceWorkerStorage::FindRegistrationForDocument:CheckInstalling",
291 TRACE_EVENT_SCOPE_THREAD
,
292 "URL", document_url
.spec(),
293 "Status", ServiceWorkerStatusToString(status
));
294 CompleteFindNow(installing_registration
,
300 // To connect this TRACE_EVENT with the callback, TimeTicks is used for
302 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
303 TRACE_EVENT_ASYNC_BEGIN1(
305 "ServiceWorkerStorage::FindRegistrationForDocument",
307 "URL", document_url
.spec());
308 database_task_manager_
->GetTaskRunner()->PostTask(
311 &FindForDocumentInDB
,
313 base::ThreadTaskRunnerHandle::Get(),
315 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument
,
316 weak_factory_
.GetWeakPtr(),
322 void ServiceWorkerStorage::FindRegistrationForPattern(
324 const FindRegistrationCallback
& callback
) {
325 if (!LazyInitialize(base::Bind(
326 &ServiceWorkerStorage::FindRegistrationForPattern
,
327 weak_factory_
.GetWeakPtr(), scope
, callback
))) {
328 if (state_
!= INITIALIZING
|| !context_
) {
329 CompleteFindSoon(FROM_HERE
, scoped_refptr
<ServiceWorkerRegistration
>(),
330 SERVICE_WORKER_ERROR_FAILED
, callback
);
334 DCHECK_EQ(INITIALIZED
, state_
);
336 // See if there are any stored registrations for the origin.
337 if (!ContainsKey(registered_origins_
, scope
.GetOrigin())) {
338 // Look for something currently being installed.
339 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
340 FindInstallingRegistrationForPattern(scope
);
341 CompleteFindSoon(FROM_HERE
,
342 installing_registration
,
343 installing_registration
.get()
345 : SERVICE_WORKER_ERROR_NOT_FOUND
,
350 database_task_manager_
->GetTaskRunner()->PostTask(
355 base::ThreadTaskRunnerHandle::Get(),
357 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern
,
358 weak_factory_
.GetWeakPtr(),
363 ServiceWorkerRegistration
* ServiceWorkerStorage::GetUninstallingRegistration(
365 if (state_
!= INITIALIZED
|| !context_
)
367 for (RegistrationRefsById::const_iterator it
=
368 uninstalling_registrations_
.begin();
369 it
!= uninstalling_registrations_
.end();
371 if (it
->second
->pattern() == scope
) {
372 DCHECK(it
->second
->is_uninstalling());
373 return it
->second
.get();
379 void ServiceWorkerStorage::FindRegistrationForId(
380 int64 registration_id
,
382 const FindRegistrationCallback
& callback
) {
383 if (!LazyInitialize(base::Bind(
384 &ServiceWorkerStorage::FindRegistrationForId
,
385 weak_factory_
.GetWeakPtr(), registration_id
, origin
, callback
))) {
386 if (state_
!= INITIALIZING
|| !context_
) {
387 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
388 SERVICE_WORKER_ERROR_FAILED
, callback
);
392 DCHECK_EQ(INITIALIZED
, state_
);
394 // See if there are any stored registrations for the origin.
395 if (!ContainsKey(registered_origins_
, origin
)) {
396 // Look for something currently being installed.
397 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
398 FindInstallingRegistrationForId(registration_id
);
399 CompleteFindNow(installing_registration
,
400 installing_registration
.get()
402 : SERVICE_WORKER_ERROR_NOT_FOUND
,
407 scoped_refptr
<ServiceWorkerRegistration
> registration
=
408 context_
->GetLiveRegistration(registration_id
);
409 if (registration
.get()) {
410 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
414 database_task_manager_
->GetTaskRunner()->PostTask(
416 base::Bind(&FindForIdInDB
,
418 base::ThreadTaskRunnerHandle::Get(),
421 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
422 weak_factory_
.GetWeakPtr(),
426 void ServiceWorkerStorage::FindRegistrationForIdOnly(
427 int64 registration_id
,
428 const FindRegistrationCallback
& callback
) {
430 base::Bind(&ServiceWorkerStorage::FindRegistrationForIdOnly
,
431 weak_factory_
.GetWeakPtr(), registration_id
, callback
))) {
432 if (state_
!= INITIALIZING
|| !context_
) {
433 CompleteFindNow(nullptr, SERVICE_WORKER_ERROR_FAILED
, callback
);
437 DCHECK_EQ(INITIALIZED
, state_
);
439 scoped_refptr
<ServiceWorkerRegistration
> registration
=
440 context_
->GetLiveRegistration(registration_id
);
442 // Delegate to FindRegistrationForId to make sure the same subset of live
443 // registrations is returned.
444 // TODO(mek): CompleteFindNow should really do all the required checks, so
445 // calling that directly here should be enough.
446 FindRegistrationForId(registration_id
, registration
->pattern().GetOrigin(),
451 database_task_manager_
->GetTaskRunner()->PostTask(
453 base::Bind(&FindForIdOnlyInDB
,
455 base::ThreadTaskRunnerHandle::Get(),
457 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
458 weak_factory_
.GetWeakPtr(),
462 void ServiceWorkerStorage::GetRegistrationsForOrigin(
464 const GetRegistrationsCallback
& callback
) {
465 if (!LazyInitialize(base::Bind(
466 &ServiceWorkerStorage::GetRegistrationsForOrigin
,
467 weak_factory_
.GetWeakPtr(), origin
, callback
))) {
468 if (state_
!= INITIALIZING
|| !context_
) {
472 std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>()));
476 DCHECK_EQ(INITIALIZED
, state_
);
478 RegistrationList
* registrations
= new RegistrationList
;
479 std::vector
<ResourceList
>* resource_lists
= new std::vector
<ResourceList
>;
480 PostTaskAndReplyWithResult(
481 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
482 base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin
,
483 base::Unretained(database_
.get()), origin
,
484 base::Unretained(registrations
),
485 base::Unretained(resource_lists
)),
486 base::Bind(&ServiceWorkerStorage::DidGetRegistrations
,
487 weak_factory_
.GetWeakPtr(), callback
,
488 base::Owned(registrations
), base::Owned(resource_lists
),
492 void ServiceWorkerStorage::GetAllRegistrationsInfos(
493 const GetRegistrationsInfosCallback
& callback
) {
495 base::Bind(&ServiceWorkerStorage::GetAllRegistrationsInfos
,
496 weak_factory_
.GetWeakPtr(), callback
))) {
497 if (state_
!= INITIALIZING
|| !context_
) {
498 RunSoon(FROM_HERE
, base::Bind(
499 callback
, std::vector
<ServiceWorkerRegistrationInfo
>()));
503 DCHECK_EQ(INITIALIZED
, state_
);
505 RegistrationList
* registrations
= new RegistrationList
;
506 PostTaskAndReplyWithResult(
507 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
508 base::Bind(&ServiceWorkerDatabase::GetAllRegistrations
,
509 base::Unretained(database_
.get()),
510 base::Unretained(registrations
)),
511 base::Bind(&ServiceWorkerStorage::DidGetRegistrationsInfos
,
512 weak_factory_
.GetWeakPtr(), callback
,
513 base::Owned(registrations
), GURL()));
516 void ServiceWorkerStorage::StoreRegistration(
517 ServiceWorkerRegistration
* registration
,
518 ServiceWorkerVersion
* version
,
519 const StatusCallback
& callback
) {
520 DCHECK(registration
);
523 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
524 if (IsDisabled() || !context_
) {
525 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
529 ServiceWorkerDatabase::RegistrationData data
;
530 data
.registration_id
= registration
->id();
531 data
.scope
= registration
->pattern();
532 data
.script
= version
->script_url();
533 data
.has_fetch_handler
= true;
534 data
.version_id
= version
->version_id();
535 data
.last_update_check
= registration
->last_update_check();
536 data
.is_active
= (version
== registration
->active_version());
538 ResourceList resources
;
539 version
->script_cache_map()->GetResources(&resources
);
541 if (resources
.empty()) {
542 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
546 uint64 resources_total_size_bytes
= 0;
547 for (const auto& resource
: resources
) {
548 resources_total_size_bytes
+= resource
.size_bytes
;
550 data
.resources_total_size_bytes
= resources_total_size_bytes
;
552 if (!has_checked_for_stale_resources_
)
553 DeleteStaleResources();
555 database_task_manager_
->GetTaskRunner()->PostTask(
557 base::Bind(&WriteRegistrationInDB
,
559 base::ThreadTaskRunnerHandle::Get(),
562 base::Bind(&ServiceWorkerStorage::DidStoreRegistration
,
563 weak_factory_
.GetWeakPtr(),
567 registration
->set_is_deleted(false);
570 void ServiceWorkerStorage::UpdateToActiveState(
571 ServiceWorkerRegistration
* registration
,
572 const StatusCallback
& callback
) {
573 DCHECK(registration
);
575 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
576 if (IsDisabled() || !context_
) {
577 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
581 PostTaskAndReplyWithResult(
582 database_task_manager_
->GetTaskRunner(),
584 base::Bind(&ServiceWorkerDatabase::UpdateVersionToActive
,
585 base::Unretained(database_
.get()),
587 registration
->pattern().GetOrigin()),
588 base::Bind(&ServiceWorkerStorage::DidUpdateToActiveState
,
589 weak_factory_
.GetWeakPtr(),
593 void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
594 ServiceWorkerRegistration
* registration
) {
595 DCHECK(registration
);
597 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
598 if (IsDisabled() || !context_
)
601 database_task_manager_
->GetTaskRunner()->PostTask(
604 base::IgnoreResult(&ServiceWorkerDatabase::UpdateLastCheckTime
),
605 base::Unretained(database_
.get()),
607 registration
->pattern().GetOrigin(),
608 registration
->last_update_check()));
611 void ServiceWorkerStorage::DeleteRegistration(
612 int64 registration_id
,
614 const StatusCallback
& callback
) {
615 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
616 if (IsDisabled() || !context_
) {
617 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
621 if (!has_checked_for_stale_resources_
)
622 DeleteStaleResources();
624 DidDeleteRegistrationParams params
;
625 params
.registration_id
= registration_id
;
626 params
.origin
= origin
;
627 params
.callback
= callback
;
629 database_task_manager_
->GetTaskRunner()->PostTask(
631 base::Bind(&DeleteRegistrationFromDB
,
633 base::ThreadTaskRunnerHandle::Get(),
636 base::Bind(&ServiceWorkerStorage::DidDeleteRegistration
,
637 weak_factory_
.GetWeakPtr(),
640 // The registration should no longer be findable.
641 pending_deletions_
.insert(registration_id
);
642 ServiceWorkerRegistration
* registration
=
643 context_
->GetLiveRegistration(registration_id
);
645 registration
->set_is_deleted(true);
648 scoped_ptr
<ServiceWorkerResponseReader
>
649 ServiceWorkerStorage::CreateResponseReader(int64 response_id
) {
650 return make_scoped_ptr(
651 new ServiceWorkerResponseReader(response_id
, disk_cache()));
654 scoped_ptr
<ServiceWorkerResponseWriter
>
655 ServiceWorkerStorage::CreateResponseWriter(int64 response_id
) {
656 return make_scoped_ptr(
657 new ServiceWorkerResponseWriter(response_id
, disk_cache()));
660 scoped_ptr
<ServiceWorkerResponseMetadataWriter
>
661 ServiceWorkerStorage::CreateResponseMetadataWriter(int64 response_id
) {
662 return make_scoped_ptr(
663 new ServiceWorkerResponseMetadataWriter(response_id
, disk_cache()));
666 void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id
) {
667 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
668 DCHECK_EQ(INITIALIZED
, state_
);
670 if (!has_checked_for_stale_resources_
)
671 DeleteStaleResources();
673 database_task_manager_
->GetTaskRunner()->PostTask(
675 base::Bind(base::IgnoreResult(
676 &ServiceWorkerDatabase::WriteUncommittedResourceIds
),
677 base::Unretained(database_
.get()),
678 std::set
<int64
>(&id
, &id
+ 1)));
681 void ServiceWorkerStorage::DoomUncommittedResponse(int64 id
) {
682 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
683 database_task_manager_
->GetTaskRunner()->PostTask(
685 base::Bind(base::IgnoreResult(
686 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
687 base::Unretained(database_
.get()),
688 std::set
<int64
>(&id
, &id
+ 1)));
689 StartPurgingResources(std::vector
<int64
>(1, id
));
692 void ServiceWorkerStorage::CompareScriptResources(
693 int64 lhs_id
, int64 rhs_id
,
694 const CompareCallback
& callback
) {
695 DCHECK(!callback
.is_null());
696 scoped_refptr
<ResponseComparer
> comparer
=
697 new ResponseComparer(weak_factory_
.GetWeakPtr(),
698 CreateResponseReader(lhs_id
),
699 CreateResponseReader(rhs_id
),
701 comparer
->Start(); // It deletes itself when done.
704 void ServiceWorkerStorage::StoreUserData(
705 int64 registration_id
,
707 const std::string
& key
,
708 const std::string
& data
,
709 const StatusCallback
& callback
) {
710 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
711 if (IsDisabled() || !context_
) {
712 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
716 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
717 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
721 PostTaskAndReplyWithResult(
722 database_task_manager_
->GetTaskRunner(),
724 base::Bind(&ServiceWorkerDatabase::WriteUserData
,
725 base::Unretained(database_
.get()),
726 registration_id
, origin
, key
, data
),
727 base::Bind(&ServiceWorkerStorage::DidStoreUserData
,
728 weak_factory_
.GetWeakPtr(),
732 void ServiceWorkerStorage::GetUserData(
733 int64 registration_id
,
734 const std::string
& key
,
735 const GetUserDataCallback
& callback
) {
736 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
737 if (IsDisabled() || !context_
) {
739 base::Bind(callback
, std::string(), SERVICE_WORKER_ERROR_FAILED
));
743 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
745 base::Bind(callback
, std::string(), SERVICE_WORKER_ERROR_FAILED
));
749 database_task_manager_
->GetTaskRunner()->PostTask(
751 base::Bind(&ServiceWorkerStorage::GetUserDataInDB
,
753 base::ThreadTaskRunnerHandle::Get(),
756 base::Bind(&ServiceWorkerStorage::DidGetUserData
,
757 weak_factory_
.GetWeakPtr(),
761 void ServiceWorkerStorage::ClearUserData(
762 int64 registration_id
,
763 const std::string
& key
,
764 const StatusCallback
& callback
) {
765 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
766 if (IsDisabled() || !context_
) {
767 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
771 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
772 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
776 PostTaskAndReplyWithResult(
777 database_task_manager_
->GetTaskRunner(),
779 base::Bind(&ServiceWorkerDatabase::DeleteUserData
,
780 base::Unretained(database_
.get()),
781 registration_id
, key
),
782 base::Bind(&ServiceWorkerStorage::DidDeleteUserData
,
783 weak_factory_
.GetWeakPtr(),
787 void ServiceWorkerStorage::GetUserDataForAllRegistrations(
788 const std::string
& key
,
789 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback
&
792 base::Bind(&ServiceWorkerStorage::GetUserDataForAllRegistrations
,
793 weak_factory_
.GetWeakPtr(), key
, callback
))) {
794 if (state_
!= INITIALIZING
|| !context_
) {
796 base::Bind(callback
, std::vector
<std::pair
<int64
, std::string
>>(),
797 SERVICE_WORKER_ERROR_FAILED
));
801 DCHECK_EQ(INITIALIZED
, state_
);
805 base::Bind(callback
, std::vector
<std::pair
<int64
, std::string
>>(),
806 SERVICE_WORKER_ERROR_FAILED
));
810 database_task_manager_
->GetTaskRunner()->PostTask(
813 &ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB
,
815 base::ThreadTaskRunnerHandle::Get(),
817 base::Bind(&ServiceWorkerStorage::DidGetUserDataForAllRegistrations
,
818 weak_factory_
.GetWeakPtr(),
822 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback
& callback
) {
825 // Delete the database on the database thread.
826 PostTaskAndReplyWithResult(
827 database_task_manager_
->GetTaskRunner(),
829 base::Bind(&ServiceWorkerDatabase::DestroyDatabase
,
830 base::Unretained(database_
.get())),
831 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase
,
832 weak_factory_
.GetWeakPtr(),
836 int64
ServiceWorkerStorage::NewRegistrationId() {
837 if (state_
== DISABLED
)
838 return kInvalidServiceWorkerRegistrationId
;
839 DCHECK_EQ(INITIALIZED
, state_
);
840 return next_registration_id_
++;
843 int64
ServiceWorkerStorage::NewVersionId() {
844 if (state_
== DISABLED
)
845 return kInvalidServiceWorkerVersionId
;
846 DCHECK_EQ(INITIALIZED
, state_
);
847 return next_version_id_
++;
850 int64
ServiceWorkerStorage::NewResourceId() {
851 if (state_
== DISABLED
)
852 return kInvalidServiceWorkerResourceId
;
853 DCHECK_EQ(INITIALIZED
, state_
);
854 return next_resource_id_
++;
857 void ServiceWorkerStorage::NotifyInstallingRegistration(
858 ServiceWorkerRegistration
* registration
) {
859 DCHECK(installing_registrations_
.find(registration
->id()) ==
860 installing_registrations_
.end());
861 installing_registrations_
[registration
->id()] = registration
;
864 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
865 ServiceWorkerRegistration
* registration
,
866 ServiceWorkerVersion
* version
,
867 ServiceWorkerStatusCode status
) {
868 installing_registrations_
.erase(registration
->id());
869 if (status
!= SERVICE_WORKER_OK
&& version
) {
870 ResourceList resources
;
871 version
->script_cache_map()->GetResources(&resources
);
874 for (size_t i
= 0; i
< resources
.size(); ++i
)
875 ids
.insert(resources
[i
].resource_id
);
877 database_task_manager_
->GetTaskRunner()->PostTask(
879 base::Bind(base::IgnoreResult(
880 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
881 base::Unretained(database_
.get()),
886 void ServiceWorkerStorage::NotifyUninstallingRegistration(
887 ServiceWorkerRegistration
* registration
) {
888 DCHECK(uninstalling_registrations_
.find(registration
->id()) ==
889 uninstalling_registrations_
.end());
890 uninstalling_registrations_
[registration
->id()] = registration
;
893 void ServiceWorkerStorage::NotifyDoneUninstallingRegistration(
894 ServiceWorkerRegistration
* registration
) {
895 uninstalling_registrations_
.erase(registration
->id());
898 void ServiceWorkerStorage::Disable() {
901 disk_cache_
->Disable();
904 bool ServiceWorkerStorage::IsDisabled() const {
905 return state_
== DISABLED
;
908 void ServiceWorkerStorage::PurgeResources(const ResourceList
& resources
) {
909 if (!has_checked_for_stale_resources_
)
910 DeleteStaleResources();
911 StartPurgingResources(resources
);
914 ServiceWorkerStorage::ServiceWorkerStorage(
915 const base::FilePath
& path
,
916 base::WeakPtr
<ServiceWorkerContextCore
> context
,
917 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager
,
918 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
919 storage::QuotaManagerProxy
* quota_manager_proxy
,
920 storage::SpecialStoragePolicy
* special_storage_policy
)
921 : next_registration_id_(kInvalidServiceWorkerRegistrationId
),
922 next_version_id_(kInvalidServiceWorkerVersionId
),
923 next_resource_id_(kInvalidServiceWorkerResourceId
),
924 state_(UNINITIALIZED
),
927 database_task_manager_(database_task_manager
.Pass()),
928 disk_cache_thread_(disk_cache_thread
),
929 quota_manager_proxy_(quota_manager_proxy
),
930 special_storage_policy_(special_storage_policy
),
931 is_purge_pending_(false),
932 has_checked_for_stale_resources_(false),
933 weak_factory_(this) {
934 database_
.reset(new ServiceWorkerDatabase(GetDatabasePath()));
937 base::FilePath
ServiceWorkerStorage::GetDatabasePath() {
939 return base::FilePath();
940 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
941 .Append(kDatabaseName
);
944 base::FilePath
ServiceWorkerStorage::GetDiskCachePath() {
946 return base::FilePath();
947 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
948 .Append(kDiskCacheName
);
951 bool ServiceWorkerStorage::LazyInitialize(const base::Closure
& callback
) {
961 pending_tasks_
.push_back(callback
);
964 pending_tasks_
.push_back(callback
);
968 state_
= INITIALIZING
;
969 database_task_manager_
->GetTaskRunner()->PostTask(
971 base::Bind(&ReadInitialDataFromDB
,
973 base::ThreadTaskRunnerHandle::Get(),
974 base::Bind(&ServiceWorkerStorage::DidReadInitialData
,
975 weak_factory_
.GetWeakPtr())));
979 void ServiceWorkerStorage::DidReadInitialData(
981 ServiceWorkerDatabase::Status status
) {
983 DCHECK_EQ(INITIALIZING
, state_
);
985 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
986 next_registration_id_
= data
->next_registration_id
;
987 next_version_id_
= data
->next_version_id
;
988 next_resource_id_
= data
->next_resource_id
;
989 registered_origins_
.swap(data
->origins
);
990 state_
= INITIALIZED
;
992 DVLOG(2) << "Failed to initialize: "
993 << ServiceWorkerDatabase::StatusToString(status
);
994 ScheduleDeleteAndStartOver();
997 for (std::vector
<base::Closure
>::const_iterator it
= pending_tasks_
.begin();
998 it
!= pending_tasks_
.end(); ++it
) {
999 RunSoon(FROM_HERE
, *it
);
1001 pending_tasks_
.clear();
1004 void ServiceWorkerStorage::DidFindRegistrationForDocument(
1005 const GURL
& document_url
,
1006 const FindRegistrationCallback
& callback
,
1008 const ServiceWorkerDatabase::RegistrationData
& data
,
1009 const ResourceList
& resources
,
1010 ServiceWorkerDatabase::Status status
) {
1011 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
1012 ReturnFoundRegistration(callback
, data
, resources
);
1013 TRACE_EVENT_ASYNC_END1(
1015 "ServiceWorkerStorage::FindRegistrationForDocument",
1017 "Status", ServiceWorkerDatabase::StatusToString(status
));
1021 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1022 // Look for something currently being installed.
1023 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
1024 FindInstallingRegistrationForDocument(document_url
);
1025 ServiceWorkerStatusCode installing_status
= installing_registration
.get() ?
1026 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
;
1027 callback
.Run(installing_status
, installing_registration
);
1028 TRACE_EVENT_ASYNC_END2(
1030 "ServiceWorkerStorage::FindRegistrationForDocument",
1032 "Status", ServiceWorkerDatabase::StatusToString(status
),
1034 (installing_status
== SERVICE_WORKER_OK
) ?
1035 "Installing registration is found" :
1036 "Any registrations are not found");
1040 ScheduleDeleteAndStartOver();
1041 callback
.Run(DatabaseStatusToStatusCode(status
),
1042 scoped_refptr
<ServiceWorkerRegistration
>());
1043 TRACE_EVENT_ASYNC_END1(
1045 "ServiceWorkerStorage::FindRegistrationForDocument",
1047 "Status", ServiceWorkerDatabase::StatusToString(status
));
1050 void ServiceWorkerStorage::DidFindRegistrationForPattern(
1052 const FindRegistrationCallback
& callback
,
1053 const ServiceWorkerDatabase::RegistrationData
& data
,
1054 const ResourceList
& resources
,
1055 ServiceWorkerDatabase::Status status
) {
1056 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
1057 ReturnFoundRegistration(callback
, data
, resources
);
1061 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1062 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
1063 FindInstallingRegistrationForPattern(scope
);
1064 callback
.Run(installing_registration
.get() ? SERVICE_WORKER_OK
1065 : SERVICE_WORKER_ERROR_NOT_FOUND
,
1066 installing_registration
);
1070 ScheduleDeleteAndStartOver();
1071 callback
.Run(DatabaseStatusToStatusCode(status
),
1072 scoped_refptr
<ServiceWorkerRegistration
>());
1075 void ServiceWorkerStorage::DidFindRegistrationForId(
1076 const FindRegistrationCallback
& callback
,
1077 const ServiceWorkerDatabase::RegistrationData
& data
,
1078 const ResourceList
& resources
,
1079 ServiceWorkerDatabase::Status status
) {
1080 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
1081 ReturnFoundRegistration(callback
, data
, resources
);
1085 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1086 // TODO(nhiroki): Find a registration in |installing_registrations_|.
1087 callback
.Run(DatabaseStatusToStatusCode(status
),
1088 scoped_refptr
<ServiceWorkerRegistration
>());
1092 ScheduleDeleteAndStartOver();
1093 callback
.Run(DatabaseStatusToStatusCode(status
),
1094 scoped_refptr
<ServiceWorkerRegistration
>());
1097 void ServiceWorkerStorage::ReturnFoundRegistration(
1098 const FindRegistrationCallback
& callback
,
1099 const ServiceWorkerDatabase::RegistrationData
& data
,
1100 const ResourceList
& resources
) {
1101 DCHECK(!resources
.empty());
1102 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1103 GetOrCreateRegistration(data
, resources
);
1104 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
1107 void ServiceWorkerStorage::DidGetRegistrations(
1108 const GetRegistrationsCallback
& callback
,
1109 RegistrationList
* registration_data_list
,
1110 std::vector
<ResourceList
>* resources_list
,
1111 const GURL
& origin_filter
,
1112 ServiceWorkerDatabase::Status status
) {
1113 DCHECK(registration_data_list
);
1114 DCHECK(resources_list
);
1116 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1117 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1118 ScheduleDeleteAndStartOver();
1119 callback
.Run(std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>());
1123 // Add all stored registrations.
1124 std::set
<int64
> registration_ids
;
1125 std::vector
<scoped_refptr
<ServiceWorkerRegistration
>> registrations
;
1127 for (const auto& registration_data
: *registration_data_list
) {
1128 registration_ids
.insert(registration_data
.registration_id
);
1129 registrations
.push_back(GetOrCreateRegistration(
1130 registration_data
, resources_list
->at(index
++)));
1133 // Add unstored registrations that are being installed.
1134 for (RegistrationRefsById::const_iterator it
=
1135 installing_registrations_
.begin();
1136 it
!= installing_registrations_
.end(); ++it
) {
1137 if ((!origin_filter
.is_valid() ||
1138 it
->second
->pattern().GetOrigin() == origin_filter
) &&
1139 registration_ids
.insert(it
->first
).second
) {
1140 registrations
.push_back((it
->second
).get());
1144 callback
.Run(registrations
);
1147 void ServiceWorkerStorage::DidGetRegistrationsInfos(
1148 const GetRegistrationsInfosCallback
& callback
,
1149 RegistrationList
* registration_data_list
,
1150 const GURL
& origin_filter
,
1151 ServiceWorkerDatabase::Status status
) {
1152 DCHECK(registration_data_list
);
1153 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1154 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1155 ScheduleDeleteAndStartOver();
1156 callback
.Run(std::vector
<ServiceWorkerRegistrationInfo
>());
1160 // Add all stored registrations.
1161 std::set
<int64
> pushed_registrations
;
1162 std::vector
<ServiceWorkerRegistrationInfo
> infos
;
1163 for (const auto& registration_data
: *registration_data_list
) {
1164 const bool inserted
=
1165 pushed_registrations
.insert(registration_data
.registration_id
).second
;
1168 ServiceWorkerRegistration
* registration
=
1169 context_
->GetLiveRegistration(registration_data
.registration_id
);
1171 infos
.push_back(registration
->GetInfo());
1175 ServiceWorkerRegistrationInfo info
;
1176 info
.pattern
= registration_data
.scope
;
1177 info
.registration_id
= registration_data
.registration_id
;
1178 info
.stored_version_size_bytes
=
1179 registration_data
.resources_total_size_bytes
;
1180 if (ServiceWorkerVersion
* version
=
1181 context_
->GetLiveVersion(registration_data
.version_id
)) {
1182 if (registration_data
.is_active
)
1183 info
.active_version
= version
->GetInfo();
1185 info
.waiting_version
= version
->GetInfo();
1186 infos
.push_back(info
);
1190 if (registration_data
.is_active
) {
1191 info
.active_version
.status
= ServiceWorkerVersion::ACTIVATED
;
1192 info
.active_version
.script_url
= registration_data
.script
;
1193 info
.active_version
.version_id
= registration_data
.version_id
;
1194 info
.active_version
.registration_id
= registration_data
.registration_id
;
1196 info
.waiting_version
.status
= ServiceWorkerVersion::INSTALLED
;
1197 info
.waiting_version
.script_url
= registration_data
.script
;
1198 info
.waiting_version
.version_id
= registration_data
.version_id
;
1199 info
.waiting_version
.registration_id
= registration_data
.registration_id
;
1201 infos
.push_back(info
);
1204 // Add unstored registrations that are being installed.
1205 for (RegistrationRefsById::const_iterator it
=
1206 installing_registrations_
.begin();
1207 it
!= installing_registrations_
.end(); ++it
) {
1208 if ((!origin_filter
.is_valid() ||
1209 it
->second
->pattern().GetOrigin() == origin_filter
) &&
1210 pushed_registrations
.insert(it
->first
).second
) {
1211 infos
.push_back(it
->second
->GetInfo());
1215 callback
.Run(infos
);
1218 void ServiceWorkerStorage::DidStoreRegistration(
1219 const StatusCallback
& callback
,
1220 const ServiceWorkerDatabase::RegistrationData
& new_version
,
1222 const ServiceWorkerDatabase::RegistrationData
& deleted_version
,
1223 const std::vector
<int64
>& newly_purgeable_resources
,
1224 ServiceWorkerDatabase::Status status
) {
1225 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1226 ScheduleDeleteAndStartOver();
1227 callback
.Run(DatabaseStatusToStatusCode(status
));
1230 registered_origins_
.insert(origin
);
1232 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1233 context_
->GetLiveRegistration(new_version
.registration_id
);
1234 registration
->set_resources_total_size_bytes(
1235 new_version
.resources_total_size_bytes
);
1236 if (quota_manager_proxy_
.get()) {
1237 // Can be nullptr in tests.
1238 quota_manager_proxy_
->NotifyStorageModified(
1239 storage::QuotaClient::kServiceWorker
,
1241 storage::StorageType::kStorageTypeTemporary
,
1242 new_version
.resources_total_size_bytes
-
1243 deleted_version
.resources_total_size_bytes
);
1246 callback
.Run(SERVICE_WORKER_OK
);
1248 if (!context_
|| !context_
->GetLiveVersion(deleted_version
.version_id
))
1249 StartPurgingResources(newly_purgeable_resources
);
1252 void ServiceWorkerStorage::DidUpdateToActiveState(
1253 const StatusCallback
& callback
,
1254 ServiceWorkerDatabase::Status status
) {
1255 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1256 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1257 ScheduleDeleteAndStartOver();
1259 callback
.Run(DatabaseStatusToStatusCode(status
));
1262 void ServiceWorkerStorage::DidDeleteRegistration(
1263 const DidDeleteRegistrationParams
& params
,
1264 bool origin_is_deletable
,
1265 const ServiceWorkerDatabase::RegistrationData
& deleted_version
,
1266 const std::vector
<int64
>& newly_purgeable_resources
,
1267 ServiceWorkerDatabase::Status status
) {
1268 pending_deletions_
.erase(params
.registration_id
);
1269 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1270 ScheduleDeleteAndStartOver();
1271 params
.callback
.Run(DatabaseStatusToStatusCode(status
));
1274 if (quota_manager_proxy_
.get()) {
1275 // Can be nullptr in tests.
1276 quota_manager_proxy_
->NotifyStorageModified(
1277 storage::QuotaClient::kServiceWorker
,
1279 storage::StorageType::kStorageTypeTemporary
,
1280 -deleted_version
.resources_total_size_bytes
);
1282 if (origin_is_deletable
)
1283 registered_origins_
.erase(params
.origin
);
1284 params
.callback
.Run(SERVICE_WORKER_OK
);
1286 if (!context_
|| !context_
->GetLiveVersion(deleted_version
.version_id
))
1287 StartPurgingResources(newly_purgeable_resources
);
1290 void ServiceWorkerStorage::DidStoreUserData(
1291 const StatusCallback
& callback
,
1292 ServiceWorkerDatabase::Status status
) {
1293 // |status| can be NOT_FOUND when the associated registration did not exist in
1294 // the database. In the case, we don't have to schedule the corruption
1296 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1297 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1298 ScheduleDeleteAndStartOver();
1300 callback
.Run(DatabaseStatusToStatusCode(status
));
1303 void ServiceWorkerStorage::DidGetUserData(
1304 const GetUserDataCallback
& callback
,
1305 const std::string
& data
,
1306 ServiceWorkerDatabase::Status status
) {
1307 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1308 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1309 ScheduleDeleteAndStartOver();
1311 callback
.Run(data
, DatabaseStatusToStatusCode(status
));
1314 void ServiceWorkerStorage::DidDeleteUserData(
1315 const StatusCallback
& callback
,
1316 ServiceWorkerDatabase::Status status
) {
1317 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1318 ScheduleDeleteAndStartOver();
1319 callback
.Run(DatabaseStatusToStatusCode(status
));
1322 void ServiceWorkerStorage::DidGetUserDataForAllRegistrations(
1323 const GetUserDataForAllRegistrationsCallback
& callback
,
1324 const std::vector
<std::pair
<int64
, std::string
>>& user_data
,
1325 ServiceWorkerDatabase::Status status
) {
1326 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1327 ScheduleDeleteAndStartOver();
1328 callback
.Run(user_data
, DatabaseStatusToStatusCode(status
));
1331 scoped_refptr
<ServiceWorkerRegistration
>
1332 ServiceWorkerStorage::GetOrCreateRegistration(
1333 const ServiceWorkerDatabase::RegistrationData
& data
,
1334 const ResourceList
& resources
) {
1335 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1336 context_
->GetLiveRegistration(data
.registration_id
);
1337 if (registration
.get())
1338 return registration
;
1340 registration
= new ServiceWorkerRegistration(
1341 data
.scope
, data
.registration_id
, context_
);
1342 registration
->set_resources_total_size_bytes(data
.resources_total_size_bytes
);
1343 registration
->set_last_update_check(data
.last_update_check
);
1344 if (pending_deletions_
.find(data
.registration_id
) !=
1345 pending_deletions_
.end()) {
1346 registration
->set_is_deleted(true);
1348 scoped_refptr
<ServiceWorkerVersion
> version
=
1349 context_
->GetLiveVersion(data
.version_id
);
1350 if (!version
.get()) {
1351 version
= new ServiceWorkerVersion(
1352 registration
.get(), data
.script
, data
.version_id
, context_
);
1353 version
->SetStatus(data
.is_active
?
1354 ServiceWorkerVersion::ACTIVATED
: ServiceWorkerVersion::INSTALLED
);
1355 version
->script_cache_map()->SetResources(resources
);
1358 if (version
->status() == ServiceWorkerVersion::ACTIVATED
)
1359 registration
->SetActiveVersion(version
);
1360 else if (version
->status() == ServiceWorkerVersion::INSTALLED
)
1361 registration
->SetWaitingVersion(version
);
1365 return registration
;
1368 ServiceWorkerRegistration
*
1369 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
1370 const GURL
& document_url
) {
1371 DCHECK(!document_url
.has_ref());
1373 LongestScopeMatcher
matcher(document_url
);
1374 ServiceWorkerRegistration
* match
= NULL
;
1376 // TODO(nhiroki): This searches over installing registrations linearly and it
1377 // couldn't be scalable. Maybe the regs should be partitioned by origin.
1378 for (RegistrationRefsById::const_iterator it
=
1379 installing_registrations_
.begin();
1380 it
!= installing_registrations_
.end(); ++it
) {
1381 if (matcher
.MatchLongest(it
->second
->pattern()))
1382 match
= it
->second
.get();
1387 ServiceWorkerRegistration
*
1388 ServiceWorkerStorage::FindInstallingRegistrationForPattern(
1389 const GURL
& scope
) {
1390 for (RegistrationRefsById::const_iterator it
=
1391 installing_registrations_
.begin();
1392 it
!= installing_registrations_
.end(); ++it
) {
1393 if (it
->second
->pattern() == scope
)
1394 return it
->second
.get();
1399 ServiceWorkerRegistration
*
1400 ServiceWorkerStorage::FindInstallingRegistrationForId(
1401 int64 registration_id
) {
1402 RegistrationRefsById::const_iterator found
=
1403 installing_registrations_
.find(registration_id
);
1404 if (found
== installing_registrations_
.end())
1406 return found
->second
.get();
1409 ServiceWorkerDiskCache
* ServiceWorkerStorage::disk_cache() {
1411 return disk_cache_
.get();
1413 disk_cache_
= ServiceWorkerDiskCache::CreateWithBlockFileBackend();
1415 base::FilePath path
= GetDiskCachePath();
1417 int rv
= disk_cache_
->InitWithMemBackend(kMaxMemDiskCacheSize
,
1418 net::CompletionCallback());
1419 DCHECK_EQ(net::OK
, rv
);
1420 return disk_cache_
.get();
1423 int rv
= disk_cache_
->InitWithDiskBackend(
1428 base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized
,
1429 weak_factory_
.GetWeakPtr()));
1430 if (rv
!= net::ERR_IO_PENDING
)
1431 OnDiskCacheInitialized(rv
);
1433 return disk_cache_
.get();
1436 void ServiceWorkerStorage::OnDiskCacheInitialized(int rv
) {
1437 if (rv
!= net::OK
) {
1438 LOG(ERROR
) << "Failed to open the serviceworker diskcache: "
1439 << net::ErrorToString(rv
);
1440 ScheduleDeleteAndStartOver();
1442 ServiceWorkerMetrics::CountInitDiskCacheResult(rv
== net::OK
);
1445 void ServiceWorkerStorage::StartPurgingResources(
1446 const std::vector
<int64
>& ids
) {
1447 DCHECK(has_checked_for_stale_resources_
);
1448 for (size_t i
= 0; i
< ids
.size(); ++i
)
1449 purgeable_resource_ids_
.push_back(ids
[i
]);
1450 ContinuePurgingResources();
1453 void ServiceWorkerStorage::StartPurgingResources(
1454 const ResourceList
& resources
) {
1455 DCHECK(has_checked_for_stale_resources_
);
1456 for (size_t i
= 0; i
< resources
.size(); ++i
)
1457 purgeable_resource_ids_
.push_back(resources
[i
].resource_id
);
1458 ContinuePurgingResources();
1461 void ServiceWorkerStorage::ContinuePurgingResources() {
1462 if (purgeable_resource_ids_
.empty() || is_purge_pending_
)
1465 // Do one at a time until we're done, use RunSoon to avoid recursion when
1466 // DoomEntry returns immediately.
1467 is_purge_pending_
= true;
1468 int64 id
= purgeable_resource_ids_
.front();
1469 purgeable_resource_ids_
.pop_front();
1471 base::Bind(&ServiceWorkerStorage::PurgeResource
,
1472 weak_factory_
.GetWeakPtr(), id
));
1475 void ServiceWorkerStorage::PurgeResource(int64 id
) {
1476 DCHECK(is_purge_pending_
);
1477 int rv
= disk_cache()->DoomEntry(
1478 id
, base::Bind(&ServiceWorkerStorage::OnResourcePurged
,
1479 weak_factory_
.GetWeakPtr(), id
));
1480 if (rv
!= net::ERR_IO_PENDING
)
1481 OnResourcePurged(id
, rv
);
1484 void ServiceWorkerStorage::OnResourcePurged(int64 id
, int rv
) {
1485 DCHECK(is_purge_pending_
);
1486 is_purge_pending_
= false;
1488 database_task_manager_
->GetTaskRunner()->PostTask(
1490 base::Bind(base::IgnoreResult(
1491 &ServiceWorkerDatabase::ClearPurgeableResourceIds
),
1492 base::Unretained(database_
.get()),
1493 std::set
<int64
>(&id
, &id
+ 1)));
1495 ContinuePurgingResources();
1498 void ServiceWorkerStorage::DeleteStaleResources() {
1499 DCHECK(!has_checked_for_stale_resources_
);
1500 has_checked_for_stale_resources_
= true;
1501 database_task_manager_
->GetTaskRunner()->PostTask(
1503 base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB
,
1505 base::ThreadTaskRunnerHandle::Get(),
1506 base::Bind(&ServiceWorkerStorage::DidCollectStaleResources
,
1507 weak_factory_
.GetWeakPtr())));
1510 void ServiceWorkerStorage::DidCollectStaleResources(
1511 const std::vector
<int64
>& stale_resource_ids
,
1512 ServiceWorkerDatabase::Status status
) {
1513 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1514 DCHECK_NE(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
, status
);
1515 ScheduleDeleteAndStartOver();
1518 StartPurgingResources(stale_resource_ids
);
1521 void ServiceWorkerStorage::ClearSessionOnlyOrigins() {
1522 // Can be null in tests.
1523 if (!special_storage_policy_
.get())
1526 if (!special_storage_policy_
->HasSessionOnlyOrigins())
1529 std::set
<GURL
> session_only_origins
;
1530 for (const GURL
& origin
: registered_origins_
) {
1531 if (special_storage_policy_
->IsStorageSessionOnly(origin
))
1532 session_only_origins
.insert(origin
);
1535 database_task_manager_
->GetShutdownBlockingTaskRunner()->PostTask(
1537 base::Bind(&DeleteAllDataForOriginsFromDB
,
1539 session_only_origins
));
1542 void ServiceWorkerStorage::CollectStaleResourcesFromDB(
1543 ServiceWorkerDatabase
* database
,
1544 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1545 const GetResourcesCallback
& callback
) {
1546 std::set
<int64
> ids
;
1547 ServiceWorkerDatabase::Status status
=
1548 database
->GetUncommittedResourceIds(&ids
);
1549 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1550 original_task_runner
->PostTask(
1553 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1557 status
= database
->PurgeUncommittedResourceIds(ids
);
1558 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1559 original_task_runner
->PostTask(
1562 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1567 status
= database
->GetPurgeableResourceIds(&ids
);
1568 original_task_runner
->PostTask(
1570 base::Bind(callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1573 void ServiceWorkerStorage::ReadInitialDataFromDB(
1574 ServiceWorkerDatabase
* database
,
1575 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1576 const InitializeCallback
& callback
) {
1578 scoped_ptr
<ServiceWorkerStorage::InitialData
> data(
1579 new ServiceWorkerStorage::InitialData());
1581 ServiceWorkerDatabase::Status status
=
1582 database
->GetNextAvailableIds(&data
->next_registration_id
,
1583 &data
->next_version_id
,
1584 &data
->next_resource_id
);
1585 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1586 original_task_runner
->PostTask(
1587 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1591 status
= database
->GetOriginsWithRegistrations(&data
->origins
);
1592 original_task_runner
->PostTask(
1593 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1596 void ServiceWorkerStorage::DeleteRegistrationFromDB(
1597 ServiceWorkerDatabase
* database
,
1598 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1599 int64 registration_id
,
1601 const DeleteRegistrationCallback
& callback
) {
1604 ServiceWorkerDatabase::RegistrationData deleted_version
;
1605 std::vector
<int64
> newly_purgeable_resources
;
1606 ServiceWorkerDatabase::Status status
= database
->DeleteRegistration(
1607 registration_id
, origin
, &deleted_version
, &newly_purgeable_resources
);
1608 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1609 original_task_runner
->PostTask(
1612 callback
, false, deleted_version
, std::vector
<int64
>(), status
));
1616 // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
1617 // unique origin list.
1618 RegistrationList registrations
;
1619 status
= database
->GetRegistrationsForOrigin(origin
, ®istrations
, nullptr);
1620 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1621 original_task_runner
->PostTask(
1624 callback
, false, deleted_version
, std::vector
<int64
>(), status
));
1628 bool deletable
= registrations
.empty();
1629 original_task_runner
->PostTask(FROM_HERE
,
1630 base::Bind(callback
,
1633 newly_purgeable_resources
,
1637 void ServiceWorkerStorage::WriteRegistrationInDB(
1638 ServiceWorkerDatabase
* database
,
1639 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1640 const ServiceWorkerDatabase::RegistrationData
& data
,
1641 const ResourceList
& resources
,
1642 const WriteRegistrationCallback
& callback
) {
1644 ServiceWorkerDatabase::RegistrationData deleted_version
;
1645 std::vector
<int64
> newly_purgeable_resources
;
1646 ServiceWorkerDatabase::Status status
= database
->WriteRegistration(
1647 data
, resources
, &deleted_version
, &newly_purgeable_resources
);
1648 original_task_runner
->PostTask(FROM_HERE
,
1649 base::Bind(callback
,
1650 data
.script
.GetOrigin(),
1652 newly_purgeable_resources
,
1656 void ServiceWorkerStorage::FindForDocumentInDB(
1657 ServiceWorkerDatabase
* database
,
1658 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1659 const GURL
& document_url
,
1660 const FindInDBCallback
& callback
) {
1661 GURL origin
= document_url
.GetOrigin();
1662 RegistrationList registrations
;
1663 ServiceWorkerDatabase::Status status
=
1664 database
->GetRegistrationsForOrigin(origin
, ®istrations
, nullptr);
1665 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1666 original_task_runner
->PostTask(
1668 base::Bind(callback
,
1669 ServiceWorkerDatabase::RegistrationData(),
1675 ServiceWorkerDatabase::RegistrationData data
;
1676 ResourceList resources
;
1677 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1679 // Find one with a pattern match.
1680 LongestScopeMatcher
matcher(document_url
);
1681 int64 match
= kInvalidServiceWorkerRegistrationId
;
1682 for (size_t i
= 0; i
< registrations
.size(); ++i
) {
1683 if (matcher
.MatchLongest(registrations
[i
].scope
))
1684 match
= registrations
[i
].registration_id
;
1687 if (match
!= kInvalidServiceWorkerRegistrationId
)
1688 status
= database
->ReadRegistration(match
, origin
, &data
, &resources
);
1690 original_task_runner
->PostTask(
1692 base::Bind(callback
, data
, resources
, status
));
1695 void ServiceWorkerStorage::FindForPatternInDB(
1696 ServiceWorkerDatabase
* database
,
1697 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1699 const FindInDBCallback
& callback
) {
1700 GURL origin
= scope
.GetOrigin();
1701 RegistrationList registrations
;
1702 ServiceWorkerDatabase::Status status
=
1703 database
->GetRegistrationsForOrigin(origin
, ®istrations
, nullptr);
1704 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1705 original_task_runner
->PostTask(
1707 base::Bind(callback
,
1708 ServiceWorkerDatabase::RegistrationData(),
1714 // Find one with an exact matching scope.
1715 ServiceWorkerDatabase::RegistrationData data
;
1716 ResourceList resources
;
1717 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1718 for (RegistrationList::const_iterator it
= registrations
.begin();
1719 it
!= registrations
.end(); ++it
) {
1720 if (scope
!= it
->scope
)
1722 status
= database
->ReadRegistration(it
->registration_id
, origin
,
1724 break; // We're done looping.
1727 original_task_runner
->PostTask(
1729 base::Bind(callback
, data
, resources
, status
));
1732 void ServiceWorkerStorage::FindForIdInDB(
1733 ServiceWorkerDatabase
* database
,
1734 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1735 int64 registration_id
,
1737 const FindInDBCallback
& callback
) {
1738 ServiceWorkerDatabase::RegistrationData data
;
1739 ResourceList resources
;
1740 ServiceWorkerDatabase::Status status
=
1741 database
->ReadRegistration(registration_id
, origin
, &data
, &resources
);
1742 original_task_runner
->PostTask(
1743 FROM_HERE
, base::Bind(callback
, data
, resources
, status
));
1746 void ServiceWorkerStorage::FindForIdOnlyInDB(
1747 ServiceWorkerDatabase
* database
,
1748 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1749 int64 registration_id
,
1750 const FindInDBCallback
& callback
) {
1752 ServiceWorkerDatabase::Status status
=
1753 database
->ReadRegistrationOrigin(registration_id
, &origin
);
1754 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1755 original_task_runner
->PostTask(
1757 base::Bind(callback
, ServiceWorkerDatabase::RegistrationData(),
1758 ResourceList(), status
));
1761 FindForIdInDB(database
, original_task_runner
, registration_id
, origin
,
1765 void ServiceWorkerStorage::GetUserDataInDB(
1766 ServiceWorkerDatabase
* database
,
1767 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1768 int64 registration_id
,
1769 const std::string
& key
,
1770 const GetUserDataInDBCallback
& callback
) {
1772 ServiceWorkerDatabase::Status status
=
1773 database
->ReadUserData(registration_id
, key
, &data
);
1774 original_task_runner
->PostTask(
1775 FROM_HERE
, base::Bind(callback
, data
, status
));
1778 void ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB(
1779 ServiceWorkerDatabase
* database
,
1780 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1781 const std::string
& key
,
1782 const GetUserDataForAllRegistrationsInDBCallback
& callback
) {
1783 std::vector
<std::pair
<int64
, std::string
>> user_data
;
1784 ServiceWorkerDatabase::Status status
=
1785 database
->ReadUserDataForAllRegistrations(key
, &user_data
);
1786 original_task_runner
->PostTask(FROM_HERE
,
1787 base::Bind(callback
, user_data
, status
));
1790 void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB(
1791 ServiceWorkerDatabase
* database
,
1792 const std::set
<GURL
>& origins
) {
1795 std::vector
<int64
> newly_purgeable_resources
;
1796 database
->DeleteAllDataForOrigins(origins
, &newly_purgeable_resources
);
1799 // TODO(nhiroki): The corruption recovery should not be scheduled if the error
1800 // is transient and it can get healed soon (e.g. IO error). To do that, the
1801 // database should not disable itself when an error occurs and the storage
1802 // controls it instead.
1803 void ServiceWorkerStorage::ScheduleDeleteAndStartOver() {
1804 // TODO(dmurph): Notify the quota manager somehow that all of our data is now
1806 if (state_
== DISABLED
) {
1807 // Recovery process has already been scheduled.
1812 DVLOG(1) << "Schedule to delete the context and start over.";
1813 context_
->ScheduleDeleteAndStartOver();
1816 void ServiceWorkerStorage::DidDeleteDatabase(
1817 const StatusCallback
& callback
,
1818 ServiceWorkerDatabase::Status status
) {
1819 DCHECK_EQ(DISABLED
, state_
);
1820 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1821 // Give up the corruption recovery until the browser restarts.
1822 LOG(ERROR
) << "Failed to delete the database: "
1823 << ServiceWorkerDatabase::StatusToString(status
);
1824 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1825 ServiceWorkerMetrics::DELETE_DATABASE_ERROR
);
1826 callback
.Run(DatabaseStatusToStatusCode(status
));
1829 DVLOG(1) << "Deleted ServiceWorkerDatabase successfully.";
1831 // Delete the disk cache on the cache thread.
1832 // TODO(nhiroki): What if there is a bunch of files in the cache directory?
1833 // Deleting the directory could take a long time and restart could be delayed.
1834 // We should probably rename the directory and delete it later.
1835 PostTaskAndReplyWithResult(
1836 disk_cache_thread_
.get(), FROM_HERE
,
1837 base::Bind(&base::DeleteFile
, GetDiskCachePath(), true),
1838 base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache
,
1839 weak_factory_
.GetWeakPtr(), callback
));
1842 void ServiceWorkerStorage::DidDeleteDiskCache(
1843 const StatusCallback
& callback
, bool result
) {
1844 DCHECK_EQ(DISABLED
, state_
);
1846 // Give up the corruption recovery until the browser restarts.
1847 LOG(ERROR
) << "Failed to delete the diskcache.";
1848 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1849 ServiceWorkerMetrics::DELETE_DISK_CACHE_ERROR
);
1850 callback
.Run(SERVICE_WORKER_ERROR_FAILED
);
1853 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
1854 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1855 ServiceWorkerMetrics::DELETE_OK
);
1856 callback
.Run(SERVICE_WORKER_OK
);
1859 } // namespace content