1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SessionStorageManager.h"
9 #include "StorageIPC.h"
10 #include "SessionStorage.h"
11 #include "SessionStorageCache.h"
12 #include "SessionStorageObserver.h"
13 #include "StorageUtils.h"
14 #include "mozilla/ClearOnShutdown.h"
15 #include "mozilla/OriginAttributes.h"
16 #include "mozilla/PrincipalHashKey.h"
17 #include "mozilla/ScopeExit.h"
18 #include "mozilla/StoragePrincipalHelper.h"
19 #include "mozilla/dom/CanonicalBrowsingContext.h"
20 #include "mozilla/dom/ContentChild.h"
21 #include "mozilla/dom/LocalStorageCommon.h"
22 #include "mozilla/dom/PBackgroundSessionStorageCache.h"
23 #include "mozilla/dom/PBackgroundSessionStorageManager.h"
24 #include "mozilla/dom/PermissionMessageUtils.h"
25 #include "mozilla/dom/WindowGlobalParent.h"
26 #include "mozilla/ipc/BackgroundChild.h"
27 #include "mozilla/ipc/BackgroundParent.h"
28 #include "mozilla/ipc/PBackgroundChild.h"
29 #include "nsTHashMap.h"
30 #include "nsThreadUtils.h"
32 namespace mozilla::dom
{
34 using namespace StorageUtils
;
36 // Parent process, background thread hashmap that stores top context id and
39 nsRefPtrHashtable
<nsUint64HashKey
, BackgroundSessionStorageManager
>>
42 bool RecvShutdownBackgroundSessionStorageManagers() {
43 ::mozilla::ipc::AssertIsOnBackgroundThread();
49 void RecvPropagateBackgroundSessionStorageManager(
50 uint64_t aCurrentTopContextId
, uint64_t aTargetTopContextId
) {
51 ::mozilla::ipc::AssertIsOnBackgroundThread();
54 if (RefPtr
<BackgroundSessionStorageManager
> mgr
=
55 sManagers
->Get(aCurrentTopContextId
)) {
56 mgr
->MaybeDispatchSessionStoreUpdate();
57 mgr
->SetCurrentBrowsingContextId(aTargetTopContextId
);
58 // Because of bfcache, we may re-register aTargetTopContextId in
59 // CanonicalBrowsingContext::ReplacedBy.
60 // XXXBFCache do we want to tweak this behavior and ensure this is
62 sManagers
->InsertOrUpdate(aTargetTopContextId
, std::move(mgr
));
67 bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId
) {
68 ::mozilla::ipc::AssertIsOnBackgroundThread();
71 RefPtr
<BackgroundSessionStorageManager
> mgr
;
72 sManagers
->Remove(aTopContextId
, getter_AddRefs(mgr
));
75 mgr
->CancelSessionStoreUpdate();
82 bool RecvLoadSessionStorageData(
83 uint64_t aTopContextId
,
84 nsTArray
<mozilla::dom::SSCacheCopy
>&& aCacheCopyList
) {
85 if (aCacheCopyList
.IsEmpty()) {
89 RefPtr
<BackgroundSessionStorageManager
> manager
=
90 BackgroundSessionStorageManager::GetOrCreate(aTopContextId
);
96 for (const auto& cacheInit
: aCacheCopyList
) {
97 OriginAttributes attrs
;
98 StoragePrincipalHelper::GetOriginAttributes(cacheInit
.principalInfo(),
101 nsAutoCString originAttrs
;
102 attrs
.CreateSuffix(originAttrs
);
104 manager
->UpdateData(originAttrs
, cacheInit
.originKey(), cacheInit
.data());
110 bool RecvGetSessionStorageData(
111 uint64_t aTopContextId
, uint32_t aSizeLimit
, bool aCancelSessionStoreTimer
,
112 ::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver
&&
114 nsTArray
<mozilla::dom::SSCacheCopy
> data
;
115 auto resolve
= MakeScopeExit([&]() { aResolver(std::move(data
)); });
121 RefPtr
<BackgroundSessionStorageManager
> manager
=
122 sManagers
->Get(aTopContextId
);
127 if (aCancelSessionStoreTimer
) {
128 manager
->CancelSessionStoreUpdate();
131 manager
->GetData(aSizeLimit
, data
);
136 bool RecvClearStoragesForOrigin(const nsACString
& aOriginAttrs
,
137 const nsACString
& aOriginKey
) {
138 mozilla::ipc::AssertIsInMainProcess();
139 mozilla::ipc::AssertIsOnBackgroundThread();
145 for (auto& entry
: *sManagers
) {
146 entry
.GetData()->ClearStoragesForOrigin(aOriginAttrs
, aOriginKey
);
152 void SessionStorageManagerBase::ClearStoragesInternal(
153 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
154 for (const auto& oaEntry
: mOATable
) {
156 DebugOnly
<bool> ok
= oa
.PopulateFromSuffix(oaEntry
.GetKey());
158 if (!aPattern
.Matches(oa
)) {
159 // This table doesn't match the given origin attributes pattern
163 OriginKeyHashTable
* table
= oaEntry
.GetWeak();
164 for (const auto& originKeyEntry
: *table
) {
165 if (aOriginScope
.IsEmpty() ||
166 StringBeginsWith(originKeyEntry
.GetKey(), aOriginScope
)) {
167 const auto cache
= originKeyEntry
.GetData()->mCache
;
169 cache
->ResetWriteInfos();
175 void SessionStorageManagerBase::ClearStoragesForOriginInternal(
176 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
177 for (const auto& oaEntry
: mOATable
) {
178 // Filter tables which match the given origin attrs.
179 if (oaEntry
.GetKey() != aOriginAttrs
) {
183 OriginKeyHashTable
* table
= oaEntry
.GetWeak();
184 for (const auto& originKeyEntry
: *table
) {
185 // Match exact origin (without origin attrs).
186 if (originKeyEntry
.GetKey() != aOriginKey
) {
190 const auto cache
= originKeyEntry
.GetData()->mCache
;
192 cache
->ResetWriteInfos();
197 SessionStorageManagerBase::OriginRecord
*
198 SessionStorageManagerBase::GetOriginRecord(
199 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
200 const bool aMakeIfNeeded
, SessionStorageCache
* const aCloneFrom
) {
201 // XXX It seems aMakeIfNeeded is always known at compile-time, so this could
202 // be split into two functions.
205 return mOATable
.GetOrInsertNew(aOriginAttrs
)
206 ->LookupOrInsertWith(
209 auto newOriginRecord
= MakeUnique
<OriginRecord
>();
211 newOriginRecord
->mCache
= aCloneFrom
->Clone();
213 newOriginRecord
->mCache
= new SessionStorageCache();
215 return newOriginRecord
;
220 auto* const table
= mOATable
.Get(aOriginAttrs
);
221 if (!table
) return nullptr;
223 return table
->Get(aOriginKey
);
226 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager
)
227 NS_INTERFACE_MAP_ENTRY(nsISupports
)
228 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager
)
229 NS_INTERFACE_MAP_ENTRY(nsIDOMSessionStorageManager
)
232 NS_IMPL_CYCLE_COLLECTION(SessionStorageManager
, mBrowsingContext
)
233 NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStorageManager
)
234 NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager
)
236 SessionStorageManager::SessionStorageManager(
237 RefPtr
<BrowsingContext
> aBrowsingContext
)
238 : mBrowsingContext(std::move(aBrowsingContext
)), mActor(nullptr) {
239 AssertIsOnMainThread();
241 StorageObserver
* observer
= StorageObserver::Self();
244 "No StorageObserver, cannot observe private data delete notifications!");
247 observer
->AddSink(this);
250 if (!XRE_IsParentProcess() && NextGenLocalStorageEnabled()) {
251 // When LSNG is enabled the thread IPC bridge doesn't exist, so we have to
252 // create own protocol to distribute chrome observer notifications to
253 // content processes.
254 mObserver
= SessionStorageObserver::Get();
257 ContentChild
* contentActor
= ContentChild::GetSingleton();
258 MOZ_ASSERT(contentActor
);
260 RefPtr
<SessionStorageObserver
> observer
= new SessionStorageObserver();
262 SessionStorageObserverChild
* actor
=
263 new SessionStorageObserverChild(observer
);
266 contentActor
->SendPSessionStorageObserverConstructor(actor
));
268 observer
->SetActor(actor
);
270 mObserver
= std::move(observer
);
275 SessionStorageManager::~SessionStorageManager() {
276 StorageObserver
* observer
= StorageObserver::Self();
278 observer
->RemoveSink(this);
282 mActor
->SendDeleteMeInternal();
283 MOZ_ASSERT(!mActor
, "SendDeleteMeInternal should have cleared!");
287 bool SessionStorageManager::CanLoadData() {
288 AssertIsOnMainThread();
290 return mBrowsingContext
&& !mBrowsingContext
->IsDiscarded();
293 void SessionStorageManager::SetActor(SessionStorageManagerChild
* aActor
) {
294 AssertIsOnMainThread();
301 bool SessionStorageManager::ActorExists() const {
302 AssertIsOnMainThread();
307 void SessionStorageManager::ClearActor() {
308 AssertIsOnMainThread();
314 nsresult
SessionStorageManager::EnsureManager() {
315 AssertIsOnMainThread();
316 MOZ_ASSERT(CanLoadData());
322 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
323 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
324 if (NS_WARN_IF(!backgroundActor
)) {
325 return NS_ERROR_FAILURE
;
328 RefPtr
<SessionStorageManagerChild
> actor
=
329 new SessionStorageManagerChild(this);
331 if (!backgroundActor
->SendPBackgroundSessionStorageManagerConstructor(
332 actor
, mBrowsingContext
->Top()->Id())) {
333 return NS_ERROR_FAILURE
;
341 SessionStorageCacheChild
* SessionStorageManager::EnsureCache(
342 nsIPrincipal
& aPrincipal
, const nsACString
& aOriginKey
,
343 SessionStorageCache
& aCache
) {
344 AssertIsOnMainThread();
345 MOZ_ASSERT(CanLoadData());
346 MOZ_ASSERT(ActorExists());
348 if (aCache
.Actor()) {
349 return aCache
.Actor();
352 mozilla::ipc::PrincipalInfo info
;
353 nsresult rv
= PrincipalToPrincipalInfo(&aPrincipal
, &info
);
359 RefPtr
<SessionStorageCacheChild
> actor
=
360 new SessionStorageCacheChild(&aCache
);
361 if (!mActor
->SendPBackgroundSessionStorageCacheConstructor(actor
, info
,
366 aCache
.SetActor(actor
);
371 nsresult
SessionStorageManager::LoadData(nsIPrincipal
& aPrincipal
,
372 SessionStorageCache
& aCache
) {
373 AssertIsOnMainThread();
376 nsAutoCString originKey
;
377 nsresult rv
= aPrincipal
.GetStorageOriginKey(originKey
);
378 if (NS_WARN_IF(NS_FAILED(rv
))) {
382 nsAutoCString originAttributes
;
383 aPrincipal
.OriginAttributesRef().CreateSuffix(originAttributes
);
385 auto* const originRecord
=
386 GetOriginRecord(originAttributes
, originKey
, true, nullptr);
387 MOZ_ASSERT(originRecord
);
389 if (originRecord
->mLoaded
) {
393 RefPtr
<SessionStorageCacheChild
> cacheActor
=
394 EnsureCache(aPrincipal
, originKey
, aCache
);
397 return NS_ERROR_FAILURE
;
400 nsTArray
<SSSetItemInfo
> data
;
401 if (!cacheActor
->SendLoad(&data
)) {
402 return NS_ERROR_FAILURE
;
405 originRecord
->mCache
->DeserializeData(data
);
407 originRecord
->mLoaded
.Flip();
408 aCache
.SetLoadedOrCloned();
413 void SessionStorageManager::CheckpointData(nsIPrincipal
& aPrincipal
,
414 SessionStorageCache
& aCache
) {
415 AssertIsOnMainThread();
418 nsAutoCString originKey
;
419 nsresult rv
= aPrincipal
.GetStorageOriginKey(originKey
);
420 if (NS_WARN_IF(NS_FAILED(rv
))) {
424 return CheckpointDataInternal(aPrincipal
, originKey
, aCache
);
427 void SessionStorageManager::CheckpointDataInternal(
428 nsIPrincipal
& aPrincipal
, const nsACString
& aOriginKey
,
429 SessionStorageCache
& aCache
) {
430 AssertIsOnMainThread();
433 nsTArray
<SSWriteInfo
> writeInfos
= aCache
.SerializeWriteInfos();
435 if (writeInfos
.IsEmpty()) {
439 RefPtr
<SessionStorageCacheChild
> cacheActor
=
440 EnsureCache(aPrincipal
, aOriginKey
, aCache
);
446 Unused
<< cacheActor
->SendCheckpoint(writeInfos
);
448 aCache
.ResetWriteInfos();
451 nsresult
SessionStorageManager::ClearStoragesForOrigin(
452 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
453 AssertIsOnMainThread();
455 ClearStoragesForOriginInternal(aOriginAttrs
, aOriginKey
);
461 SessionStorageManager::PrecacheStorage(nsIPrincipal
* aPrincipal
,
462 nsIPrincipal
* aStoragePrincipal
,
464 // Nothing to preload.
469 SessionStorageManager::GetSessionStorageCache(
470 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aStoragePrincipal
,
471 RefPtr
<SessionStorageCache
>* aRetVal
) {
472 return GetSessionStorageCacheHelper(aStoragePrincipal
, true, nullptr,
476 nsresult
SessionStorageManager::GetSessionStorageCacheHelper(
477 nsIPrincipal
* aPrincipal
, bool aMakeIfNeeded
,
478 SessionStorageCache
* aCloneFrom
, RefPtr
<SessionStorageCache
>* aRetVal
) {
479 nsAutoCString originKey
;
480 nsAutoCString originAttributes
;
481 nsresult rv
= aPrincipal
->GetStorageOriginKey(originKey
);
482 aPrincipal
->OriginAttributesRef().CreateSuffix(originAttributes
);
484 return NS_ERROR_NOT_AVAILABLE
;
487 return GetSessionStorageCacheHelper(originAttributes
, originKey
,
488 aMakeIfNeeded
, aCloneFrom
, aRetVal
);
491 nsresult
SessionStorageManager::GetSessionStorageCacheHelper(
492 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
493 bool aMakeIfNeeded
, SessionStorageCache
* aCloneFrom
,
494 RefPtr
<SessionStorageCache
>* aRetVal
) {
495 if (OriginRecord
* const originRecord
= GetOriginRecord(
496 aOriginAttrs
, aOriginKey
, aMakeIfNeeded
, aCloneFrom
)) {
497 *aRetVal
= originRecord
->mCache
;
505 SessionStorageManager::CreateStorage(mozIDOMWindow
* aWindow
,
506 nsIPrincipal
* aPrincipal
,
507 nsIPrincipal
* aStoragePrincipal
,
508 const nsAString
& aDocumentURI
,
509 bool aPrivate
, Storage
** aRetval
) {
510 RefPtr
<SessionStorageCache
> cache
;
511 nsresult rv
= GetSessionStorageCache(aPrincipal
, aStoragePrincipal
, &cache
);
516 nsCOMPtr
<nsPIDOMWindowInner
> inner
= nsPIDOMWindowInner::From(aWindow
);
518 RefPtr
<SessionStorage
> storage
=
519 new SessionStorage(inner
, aPrincipal
, aStoragePrincipal
, cache
, this,
520 aDocumentURI
, aPrivate
);
522 storage
.forget(aRetval
);
527 SessionStorageManager::GetStorage(mozIDOMWindow
* aWindow
,
528 nsIPrincipal
* aPrincipal
,
529 nsIPrincipal
* aStoragePrincipal
,
530 bool aPrivate
, Storage
** aRetval
) {
533 RefPtr
<SessionStorageCache
> cache
;
535 GetSessionStorageCacheHelper(aStoragePrincipal
, false, nullptr, &cache
);
536 if (NS_FAILED(rv
) || !cache
) {
540 nsCOMPtr
<nsPIDOMWindowInner
> inner
= nsPIDOMWindowInner::From(aWindow
);
542 RefPtr
<SessionStorage
> storage
= new SessionStorage(
543 inner
, aPrincipal
, aStoragePrincipal
, cache
, this, u
""_ns
, aPrivate
);
545 storage
.forget(aRetval
);
550 SessionStorageManager::CloneStorage(Storage
* aStorage
) {
551 if (NS_WARN_IF(!aStorage
)) {
552 return NS_ERROR_UNEXPECTED
;
555 if (aStorage
->Type() != Storage::eSessionStorage
) {
556 return NS_ERROR_UNEXPECTED
;
559 // ToDo: At the moment, we clone the cache on the child process and then
560 // send the checkpoint. It would be nicer if we either serailizing all the
561 // data and sync to the parent process directly or clonig storage on the
562 // parnet process and sync it to the child process on demand.
564 RefPtr
<SessionStorageCache
> cache
;
565 nsresult rv
= GetSessionStorageCacheHelper(
566 aStorage
->StoragePrincipal(), true,
567 static_cast<SessionStorage
*>(aStorage
)->Cache(), &cache
);
568 if (NS_WARN_IF(NS_FAILED(rv
))) {
572 // If cache was cloned from other storage, then we shouldn't load the cache
573 // at the first access.
574 cache
->SetLoadedOrCloned();
577 rv
= EnsureManager();
578 if (NS_WARN_IF(NS_FAILED(rv
))) {
582 CheckpointData(*aStorage
->StoragePrincipal(), *cache
);
589 SessionStorageManager::CheckStorage(nsIPrincipal
* aPrincipal
, Storage
* aStorage
,
591 if (NS_WARN_IF(!aStorage
)) {
592 return NS_ERROR_UNEXPECTED
;
596 return NS_ERROR_NOT_AVAILABLE
;
601 RefPtr
<SessionStorageCache
> cache
;
603 GetSessionStorageCacheHelper(aPrincipal
, false, nullptr, &cache
);
604 if (NS_FAILED(rv
) || !cache
) {
608 if (aStorage
->Type() != Storage::eSessionStorage
) {
612 RefPtr
<SessionStorage
> sessionStorage
=
613 static_cast<SessionStorage
*>(aStorage
);
614 if (sessionStorage
->Cache() != cache
) {
618 if (!StorageUtils::PrincipalsEqual(aStorage
->StoragePrincipal(),
627 void SessionStorageManager::ClearStorages(
628 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
630 nsresult rv
= EnsureManager();
631 if (NS_WARN_IF(NS_FAILED(rv
))) {
635 mActor
->SendClearStorages(aPattern
, nsCString(aOriginScope
));
638 ClearStoragesInternal(aPattern
, aOriginScope
);
641 nsresult
SessionStorageManager::Observe(
642 const char* aTopic
, const nsAString
& aOriginAttributesPattern
,
643 const nsACString
& aOriginScope
) {
644 OriginAttributesPattern pattern
;
645 if (!pattern
.Init(aOriginAttributesPattern
)) {
646 NS_ERROR("Cannot parse origin attributes pattern");
647 return NS_ERROR_FAILURE
;
650 // Clear everything, caches + database
651 if (!strcmp(aTopic
, "cookie-cleared")) {
652 ClearStorages(pattern
, ""_ns
);
656 // Clear from caches everything that has been stored
657 // while in session-only mode
658 if (!strcmp(aTopic
, "session-only-cleared")) {
659 ClearStorages(pattern
, aOriginScope
);
663 // Clear everything (including so and pb data) from caches and database
664 // for the given domain and subdomains.
665 if (!strcmp(aTopic
, "browser:purge-sessionStorage")) {
666 ClearStorages(pattern
, aOriginScope
);
670 // Clear entries which match an OriginAttributesPattern.
671 if (!strcmp(aTopic
, "dom-storage:clear-origin-attributes-data") ||
672 !strcmp(aTopic
, "session-storage:clear-origin-attributes-data")) {
673 ClearStorages(pattern
, aOriginScope
);
677 if (!strcmp(aTopic
, "profile-change")) {
678 // For case caches are still referenced - clear them completely
679 ClearStorages(pattern
, ""_ns
);
687 SessionStorageManager::OriginRecord::~OriginRecord() = default;
690 void BackgroundSessionStorageManager::RemoveManager(uint64_t aTopContextId
) {
691 MOZ_ASSERT(XRE_IsParentProcess());
692 AssertIsOnMainThread();
694 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
695 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
696 if (NS_WARN_IF(!backgroundActor
)) {
700 if (NS_WARN_IF(!backgroundActor
->SendRemoveBackgroundSessionStorageManager(
707 void BackgroundSessionStorageManager::PropagateManager(
708 uint64_t aCurrentTopContextId
, uint64_t aTargetTopContextId
) {
709 MOZ_ASSERT(XRE_IsParentProcess());
710 AssertIsOnMainThread();
711 MOZ_ASSERT(aCurrentTopContextId
!= aTargetTopContextId
);
713 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
714 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
715 if (NS_WARN_IF(!backgroundActor
)) {
719 if (NS_WARN_IF(!backgroundActor
->SendPropagateBackgroundSessionStorageManager(
720 aCurrentTopContextId
, aTargetTopContextId
))) {
726 void BackgroundSessionStorageManager::LoadData(
727 uint64_t aTopContextId
,
728 const nsTArray
<mozilla::dom::SSCacheCopy
>& aCacheCopyList
) {
729 MOZ_ASSERT(XRE_IsParentProcess());
730 AssertIsOnMainThread();
732 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
733 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
734 if (NS_WARN_IF(!backgroundActor
)) {
738 if (NS_WARN_IF(!backgroundActor
->SendLoadSessionStorageManagerData(
739 aTopContextId
, aCacheCopyList
))) {
745 BackgroundSessionStorageManager
* BackgroundSessionStorageManager::GetOrCreate(
746 uint64_t aTopContextId
) {
747 MOZ_ASSERT(XRE_IsParentProcess());
748 ::mozilla::ipc::AssertIsOnBackgroundThread();
751 sManagers
= new nsRefPtrHashtable
<nsUint64HashKey
,
752 BackgroundSessionStorageManager
>();
753 NS_DispatchToMainThread(NS_NewRunnableFunction(
754 "dom::BackgroundSessionStorageManager::GetOrCreate", [] {
757 ::mozilla::ipc::PBackgroundChild
* backgroundActor
= ::mozilla::
758 ipc::BackgroundChild::GetOrCreateForCurrentThread();
759 if (NS_WARN_IF(!backgroundActor
)) {
765 ->SendShutdownBackgroundSessionStorageManagers())) {
769 ShutdownPhase::XPCOMShutdown
);
774 ->LookupOrInsertWith(
777 return new BackgroundSessionStorageManager(aTopContextId
);
782 BackgroundSessionStorageManager::BackgroundSessionStorageManager(
783 uint64_t aBrowsingContextId
)
784 : mCurrentBrowsingContextId(aBrowsingContextId
) {
785 MOZ_ASSERT(XRE_IsParentProcess());
786 ::mozilla::ipc::AssertIsOnBackgroundThread();
789 BackgroundSessionStorageManager::~BackgroundSessionStorageManager() = default;
791 void BackgroundSessionStorageManager::CopyDataToContentProcess(
792 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
793 nsTArray
<SSSetItemInfo
>& aData
) {
794 MOZ_ASSERT(XRE_IsParentProcess());
795 ::mozilla::ipc::AssertIsOnBackgroundThread();
797 auto* const originRecord
=
798 GetOriginRecord(aOriginAttrs
, aOriginKey
, false, nullptr);
803 aData
= originRecord
->mCache
->SerializeData();
807 RefPtr
<BackgroundSessionStorageManager::DataPromise
>
808 BackgroundSessionStorageManager::GetData(BrowsingContext
* aContext
,
810 bool aClearSessionStoreTimer
) {
811 MOZ_ASSERT(XRE_IsParentProcess());
812 MOZ_ASSERT(aContext
->IsTop());
814 AssertIsOnMainThread();
816 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
817 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
818 if (NS_WARN_IF(!backgroundActor
)) {
819 return DataPromise::CreateAndReject(
820 ::mozilla::ipc::ResponseRejectReason::SendError
, __func__
);
823 return backgroundActor
->SendGetSessionStorageManagerData(
824 aContext
->Id(), aSizeLimit
, aClearSessionStoreTimer
);
827 void BackgroundSessionStorageManager::GetData(
828 uint32_t aSizeLimit
, nsTArray
<SSCacheCopy
>& aCacheCopyList
) {
829 for (auto& managerActor
: mParticipatingActors
) {
830 for (auto* cacheActor
:
831 managerActor
->ManagedPBackgroundSessionStorageCacheParent()) {
832 auto* cache
= static_cast<SessionStorageCacheParent
*>(cacheActor
);
833 ::mozilla::ipc::PrincipalInfo info
= cache
->PrincipalInfo();
835 OriginAttributes attributes
;
836 StoragePrincipalHelper::GetOriginAttributes(cache
->PrincipalInfo(),
839 nsAutoCString originAttrs
;
840 attributes
.CreateSuffix(originAttrs
);
843 GetOriginRecord(originAttrs
, cache
->OriginKey(), false, nullptr);
849 if (record
->mCache
->GetOriginQuotaUsage() > aSizeLimit
) {
853 nsTArray
<SSSetItemInfo
> data
= record
->mCache
->SerializeData();
854 if (data
.IsEmpty()) {
858 SSCacheCopy
& cacheCopy
= *aCacheCopyList
.AppendElement();
859 cacheCopy
.originKey() = cache
->OriginKey();
860 cacheCopy
.principalInfo() = info
;
861 cacheCopy
.data().SwapElements(data
);
866 void BackgroundSessionStorageManager::UpdateData(
867 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
868 const nsTArray
<SSWriteInfo
>& aWriteInfos
) {
869 MOZ_ASSERT(XRE_IsParentProcess());
870 ::mozilla::ipc::AssertIsOnBackgroundThread();
872 auto* const originRecord
=
873 GetOriginRecord(aOriginAttrs
, aOriginKey
, true, nullptr);
874 MOZ_ASSERT(originRecord
);
876 MaybeScheduleSessionStoreUpdate();
878 originRecord
->mCache
->DeserializeWriteInfos(aWriteInfos
);
881 void BackgroundSessionStorageManager::UpdateData(
882 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
883 const nsTArray
<SSSetItemInfo
>& aData
) {
884 MOZ_ASSERT(XRE_IsParentProcess());
885 ::mozilla::ipc::AssertIsOnBackgroundThread();
887 auto* const originRecord
=
888 GetOriginRecord(aOriginAttrs
, aOriginKey
, true, nullptr);
889 MOZ_ASSERT(originRecord
);
891 originRecord
->mCache
->DeserializeData(aData
);
894 void BackgroundSessionStorageManager::ClearStorages(
895 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
896 MOZ_ASSERT(XRE_IsParentProcess());
897 ::mozilla::ipc::AssertIsOnBackgroundThread();
898 ClearStoragesInternal(aPattern
, aOriginScope
);
901 void BackgroundSessionStorageManager::ClearStoragesForOrigin(
902 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
903 ::mozilla::ipc::AssertIsInMainProcess();
904 ::mozilla::ipc::AssertIsOnBackgroundThread();
906 for (auto& managerActor
: mParticipatingActors
) {
907 QM_WARNONLY_TRY(OkIf(managerActor
->SendClearStoragesForOrigin(
908 nsCString(aOriginAttrs
), nsCString(aOriginKey
))));
911 ClearStoragesForOriginInternal(aOriginAttrs
, aOriginKey
);
914 void BackgroundSessionStorageManager::SetCurrentBrowsingContextId(
915 uint64_t aBrowsingContextId
) {
916 MOZ_DIAGNOSTIC_ASSERT(aBrowsingContextId
!= mCurrentBrowsingContextId
);
917 mCurrentBrowsingContextId
= aBrowsingContextId
;
920 void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() {
921 if (!StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
925 if (mSessionStoreCallbackTimer
) {
929 if (StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
930 DispatchSessionStoreUpdate();
934 auto result
= NS_NewTimerWithFuncCallback(
935 [](nsITimer
*, void* aClosure
) {
936 auto* mgr
= static_cast<BackgroundSessionStorageManager
*>(aClosure
);
937 mgr
->DispatchSessionStoreUpdate();
939 this, StaticPrefs::browser_sessionstore_interval(),
940 nsITimer::TYPE_ONE_SHOT
,
941 "BackgroundSessionStorageManager::DispatchSessionStoreUpdate");
943 if (result
.isErr()) {
947 mSessionStoreCallbackTimer
= result
.unwrap();
950 void BackgroundSessionStorageManager::MaybeDispatchSessionStoreUpdate() {
951 if (mSessionStoreCallbackTimer
) {
952 BackgroundSessionStorageManager::DispatchSessionStoreUpdate();
956 void BackgroundSessionStorageManager::DispatchSessionStoreUpdate() {
957 ::mozilla::ipc::AssertIsOnBackgroundThread();
958 NS_DispatchToMainThread(NS_NewRunnableFunction(
959 "CanonicalBrowsingContext::UpdateSessionStore",
960 [targetBrowsingContextId
= mCurrentBrowsingContextId
]() {
961 CanonicalBrowsingContext::UpdateSessionStoreForStorage(
962 targetBrowsingContextId
);
965 CancelSessionStoreUpdate();
968 void BackgroundSessionStorageManager::CancelSessionStoreUpdate() {
969 if (mSessionStoreCallbackTimer
) {
970 mSessionStoreCallbackTimer
->Cancel();
971 mSessionStoreCallbackTimer
= nullptr;
975 void BackgroundSessionStorageManager::AddParticipatingActor(
976 SessionStorageManagerParent
* aActor
) {
977 ::mozilla::ipc::AssertIsOnBackgroundThread();
978 mParticipatingActors
.AppendElement(aActor
);
981 void BackgroundSessionStorageManager::RemoveParticipatingActor(
982 SessionStorageManagerParent
* aActor
) {
983 ::mozilla::ipc::AssertIsOnBackgroundThread();
984 mParticipatingActors
.RemoveElement(aActor
);
987 } // namespace mozilla::dom