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 "nsIXULRuntime.h"
30 #include "nsTHashMap.h"
31 #include "nsThreadUtils.h"
33 namespace mozilla::dom
{
35 using namespace StorageUtils
;
37 // Parent process, background thread hashmap that stores top context id and
40 nsRefPtrHashtable
<nsUint64HashKey
, BackgroundSessionStorageManager
>>
43 bool RecvShutdownBackgroundSessionStorageManagers() {
44 ::mozilla::ipc::AssertIsOnBackgroundThread();
50 void RecvPropagateBackgroundSessionStorageManager(
51 uint64_t aCurrentTopContextId
, uint64_t aTargetTopContextId
) {
52 ::mozilla::ipc::AssertIsOnBackgroundThread();
55 if (RefPtr
<BackgroundSessionStorageManager
> mgr
=
56 sManagers
->Get(aCurrentTopContextId
)) {
57 mgr
->MaybeDispatchSessionStoreUpdate();
58 mgr
->SetCurrentBrowsingContextId(aTargetTopContextId
);
59 // Because of bfcache, we may re-register aTargetTopContextId in
60 // CanonicalBrowsingContext::ReplacedBy.
61 // XXXBFCache do we want to tweak this behavior and ensure this is
63 sManagers
->InsertOrUpdate(aTargetTopContextId
, std::move(mgr
));
68 bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId
) {
69 ::mozilla::ipc::AssertIsOnBackgroundThread();
72 RefPtr
<BackgroundSessionStorageManager
> mgr
;
73 sManagers
->Remove(aTopContextId
, getter_AddRefs(mgr
));
76 mgr
->CancelSessionStoreUpdate();
83 bool RecvLoadSessionStorageData(
84 uint64_t aTopContextId
,
85 nsTArray
<mozilla::dom::SSCacheCopy
>&& aCacheCopyList
) {
86 if (aCacheCopyList
.IsEmpty()) {
90 RefPtr
<BackgroundSessionStorageManager
> manager
=
91 BackgroundSessionStorageManager::GetOrCreate(aTopContextId
);
97 for (const auto& cacheInit
: aCacheCopyList
) {
98 OriginAttributes attrs
;
99 StoragePrincipalHelper::GetOriginAttributes(cacheInit
.principalInfo(),
102 nsAutoCString originAttrs
;
103 attrs
.CreateSuffix(originAttrs
);
105 manager
->UpdateData(originAttrs
, cacheInit
.originKey(), cacheInit
.data());
111 bool RecvGetSessionStorageData(
112 uint64_t aTopContextId
, uint32_t aSizeLimit
, bool aCancelSessionStoreTimer
,
113 ::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver
&&
115 nsTArray
<mozilla::dom::SSCacheCopy
> data
;
116 auto resolve
= MakeScopeExit([&]() { aResolver(std::move(data
)); });
122 RefPtr
<BackgroundSessionStorageManager
> manager
=
123 sManagers
->Get(aTopContextId
);
128 if (aCancelSessionStoreTimer
) {
129 manager
->CancelSessionStoreUpdate();
132 manager
->GetData(aSizeLimit
, data
);
137 bool RecvClearStoragesForOrigin(const nsACString
& aOriginAttrs
,
138 const nsACString
& aOriginKey
) {
139 mozilla::ipc::AssertIsInMainProcess();
140 mozilla::ipc::AssertIsOnBackgroundThread();
146 for (auto& entry
: *sManagers
) {
147 entry
.GetData()->ClearStoragesForOrigin(aOriginAttrs
, aOriginKey
);
153 void SessionStorageManagerBase::ClearStoragesInternal(
154 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
155 for (const auto& oaEntry
: mOATable
) {
157 DebugOnly
<bool> ok
= oa
.PopulateFromSuffix(oaEntry
.GetKey());
159 if (!aPattern
.Matches(oa
)) {
160 // This table doesn't match the given origin attributes pattern
164 OriginKeyHashTable
* table
= oaEntry
.GetWeak();
165 for (const auto& originKeyEntry
: *table
) {
166 if (aOriginScope
.IsEmpty() ||
167 StringBeginsWith(originKeyEntry
.GetKey(), aOriginScope
)) {
168 const auto cache
= originKeyEntry
.GetData()->mCache
;
170 cache
->ResetWriteInfos();
176 void SessionStorageManagerBase::ClearStoragesForOriginInternal(
177 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
178 for (const auto& oaEntry
: mOATable
) {
179 // Filter tables which match the given origin attrs.
180 if (oaEntry
.GetKey() != aOriginAttrs
) {
184 OriginKeyHashTable
* table
= oaEntry
.GetWeak();
185 for (const auto& originKeyEntry
: *table
) {
186 // Match exact origin (without origin attrs).
187 if (originKeyEntry
.GetKey() != aOriginKey
) {
191 const auto cache
= originKeyEntry
.GetData()->mCache
;
193 cache
->ResetWriteInfos();
198 SessionStorageManagerBase::OriginRecord
*
199 SessionStorageManagerBase::GetOriginRecord(
200 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
201 const bool aMakeIfNeeded
, SessionStorageCache
* const aCloneFrom
) {
202 // XXX It seems aMakeIfNeeded is always known at compile-time, so this could
203 // be split into two functions.
206 return mOATable
.GetOrInsertNew(aOriginAttrs
)
207 ->LookupOrInsertWith(
210 auto newOriginRecord
= MakeUnique
<OriginRecord
>();
212 newOriginRecord
->mCache
= aCloneFrom
->Clone();
214 newOriginRecord
->mCache
= new SessionStorageCache();
216 return newOriginRecord
;
221 auto* const table
= mOATable
.Get(aOriginAttrs
);
222 if (!table
) return nullptr;
224 return table
->Get(aOriginKey
);
227 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager
)
228 NS_INTERFACE_MAP_ENTRY(nsISupports
)
229 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager
)
230 NS_INTERFACE_MAP_ENTRY(nsIDOMSessionStorageManager
)
233 NS_IMPL_CYCLE_COLLECTION(SessionStorageManager
, mBrowsingContext
)
234 NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStorageManager
)
235 NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager
)
237 SessionStorageManager::SessionStorageManager(
238 RefPtr
<BrowsingContext
> aBrowsingContext
)
239 : mBrowsingContext(std::move(aBrowsingContext
)), mActor(nullptr) {
240 AssertIsOnMainThread();
242 StorageObserver
* observer
= StorageObserver::Self();
245 "No StorageObserver, cannot observe private data delete notifications!");
248 observer
->AddSink(this);
251 if (!XRE_IsParentProcess() && NextGenLocalStorageEnabled()) {
252 // When LSNG is enabled the thread IPC bridge doesn't exist, so we have to
253 // create own protocol to distribute chrome observer notifications to
254 // content processes.
255 mObserver
= SessionStorageObserver::Get();
258 ContentChild
* contentActor
= ContentChild::GetSingleton();
259 MOZ_ASSERT(contentActor
);
261 RefPtr
<SessionStorageObserver
> observer
= new SessionStorageObserver();
263 SessionStorageObserverChild
* actor
=
264 new SessionStorageObserverChild(observer
);
267 contentActor
->SendPSessionStorageObserverConstructor(actor
));
269 observer
->SetActor(actor
);
271 mObserver
= std::move(observer
);
276 SessionStorageManager::~SessionStorageManager() {
277 StorageObserver
* observer
= StorageObserver::Self();
279 observer
->RemoveSink(this);
283 mActor
->SendDeleteMeInternal();
284 MOZ_ASSERT(!mActor
, "SendDeleteMeInternal should have cleared!");
288 bool SessionStorageManager::CanLoadData() {
289 AssertIsOnMainThread();
291 return mBrowsingContext
&& !mBrowsingContext
->IsDiscarded();
294 void SessionStorageManager::SetActor(SessionStorageManagerChild
* aActor
) {
295 AssertIsOnMainThread();
302 bool SessionStorageManager::ActorExists() const {
303 AssertIsOnMainThread();
308 void SessionStorageManager::ClearActor() {
309 AssertIsOnMainThread();
315 nsresult
SessionStorageManager::EnsureManager() {
316 AssertIsOnMainThread();
317 MOZ_ASSERT(CanLoadData());
323 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
324 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
325 if (NS_WARN_IF(!backgroundActor
)) {
326 return NS_ERROR_FAILURE
;
329 RefPtr
<SessionStorageManagerChild
> actor
=
330 new SessionStorageManagerChild(this);
332 if (!backgroundActor
->SendPBackgroundSessionStorageManagerConstructor(
333 actor
, mBrowsingContext
->Top()->Id())) {
334 return NS_ERROR_FAILURE
;
342 SessionStorageCacheChild
* SessionStorageManager::EnsureCache(
343 nsIPrincipal
& aPrincipal
, const nsACString
& aOriginKey
,
344 SessionStorageCache
& aCache
) {
345 AssertIsOnMainThread();
346 MOZ_ASSERT(CanLoadData());
347 MOZ_ASSERT(ActorExists());
349 if (aCache
.Actor()) {
350 return aCache
.Actor();
353 mozilla::ipc::PrincipalInfo info
;
354 nsresult rv
= PrincipalToPrincipalInfo(&aPrincipal
, &info
);
360 RefPtr
<SessionStorageCacheChild
> actor
=
361 new SessionStorageCacheChild(&aCache
);
362 if (!mActor
->SendPBackgroundSessionStorageCacheConstructor(actor
, info
,
367 aCache
.SetActor(actor
);
372 nsresult
SessionStorageManager::LoadData(nsIPrincipal
& aPrincipal
,
373 SessionStorageCache
& aCache
) {
374 AssertIsOnMainThread();
377 nsAutoCString originKey
;
378 nsresult rv
= aPrincipal
.GetStorageOriginKey(originKey
);
379 if (NS_WARN_IF(NS_FAILED(rv
))) {
383 nsAutoCString originAttributes
;
384 aPrincipal
.OriginAttributesRef().CreateSuffix(originAttributes
);
386 auto* const originRecord
=
387 GetOriginRecord(originAttributes
, originKey
, true, nullptr);
388 MOZ_ASSERT(originRecord
);
390 if (originRecord
->mLoaded
) {
394 RefPtr
<SessionStorageCacheChild
> cacheActor
=
395 EnsureCache(aPrincipal
, originKey
, aCache
);
398 return NS_ERROR_FAILURE
;
401 nsTArray
<SSSetItemInfo
> data
;
402 if (!cacheActor
->SendLoad(&data
)) {
403 return NS_ERROR_FAILURE
;
406 originRecord
->mCache
->DeserializeData(data
);
408 originRecord
->mLoaded
.Flip();
409 aCache
.SetLoadedOrCloned();
414 void SessionStorageManager::CheckpointData(nsIPrincipal
& aPrincipal
,
415 SessionStorageCache
& aCache
) {
416 AssertIsOnMainThread();
419 nsAutoCString originKey
;
420 nsresult rv
= aPrincipal
.GetStorageOriginKey(originKey
);
421 if (NS_WARN_IF(NS_FAILED(rv
))) {
425 return CheckpointDataInternal(aPrincipal
, originKey
, aCache
);
428 void SessionStorageManager::CheckpointDataInternal(
429 nsIPrincipal
& aPrincipal
, const nsACString
& aOriginKey
,
430 SessionStorageCache
& aCache
) {
431 AssertIsOnMainThread();
434 nsTArray
<SSWriteInfo
> writeInfos
= aCache
.SerializeWriteInfos();
436 if (writeInfos
.IsEmpty()) {
440 RefPtr
<SessionStorageCacheChild
> cacheActor
=
441 EnsureCache(aPrincipal
, aOriginKey
, aCache
);
447 Unused
<< cacheActor
->SendCheckpoint(writeInfos
);
449 aCache
.ResetWriteInfos();
452 nsresult
SessionStorageManager::ClearStoragesForOrigin(
453 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
454 AssertIsOnMainThread();
456 ClearStoragesForOriginInternal(aOriginAttrs
, aOriginKey
);
462 SessionStorageManager::PrecacheStorage(nsIPrincipal
* aPrincipal
,
463 nsIPrincipal
* aStoragePrincipal
,
465 // Nothing to preload.
470 SessionStorageManager::GetSessionStorageCache(
471 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aStoragePrincipal
,
472 RefPtr
<SessionStorageCache
>* aRetVal
) {
473 return GetSessionStorageCacheHelper(aStoragePrincipal
, true, nullptr,
477 nsresult
SessionStorageManager::GetSessionStorageCacheHelper(
478 nsIPrincipal
* aPrincipal
, bool aMakeIfNeeded
,
479 SessionStorageCache
* aCloneFrom
, RefPtr
<SessionStorageCache
>* aRetVal
) {
480 nsAutoCString originKey
;
481 nsAutoCString originAttributes
;
482 nsresult rv
= aPrincipal
->GetStorageOriginKey(originKey
);
483 aPrincipal
->OriginAttributesRef().CreateSuffix(originAttributes
);
485 return NS_ERROR_NOT_AVAILABLE
;
488 return GetSessionStorageCacheHelper(originAttributes
, originKey
,
489 aMakeIfNeeded
, aCloneFrom
, aRetVal
);
492 nsresult
SessionStorageManager::GetSessionStorageCacheHelper(
493 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
494 bool aMakeIfNeeded
, SessionStorageCache
* aCloneFrom
,
495 RefPtr
<SessionStorageCache
>* aRetVal
) {
496 if (OriginRecord
* const originRecord
= GetOriginRecord(
497 aOriginAttrs
, aOriginKey
, aMakeIfNeeded
, aCloneFrom
)) {
498 *aRetVal
= originRecord
->mCache
;
506 SessionStorageManager::CreateStorage(mozIDOMWindow
* aWindow
,
507 nsIPrincipal
* aPrincipal
,
508 nsIPrincipal
* aStoragePrincipal
,
509 const nsAString
& aDocumentURI
,
510 bool aPrivate
, Storage
** aRetval
) {
511 RefPtr
<SessionStorageCache
> cache
;
512 nsresult rv
= GetSessionStorageCache(aPrincipal
, aStoragePrincipal
, &cache
);
517 nsCOMPtr
<nsPIDOMWindowInner
> inner
= nsPIDOMWindowInner::From(aWindow
);
519 RefPtr
<SessionStorage
> storage
=
520 new SessionStorage(inner
, aPrincipal
, aStoragePrincipal
, cache
, this,
521 aDocumentURI
, aPrivate
);
523 storage
.forget(aRetval
);
528 SessionStorageManager::GetStorage(mozIDOMWindow
* aWindow
,
529 nsIPrincipal
* aPrincipal
,
530 nsIPrincipal
* aStoragePrincipal
,
531 bool aPrivate
, Storage
** aRetval
) {
534 RefPtr
<SessionStorageCache
> cache
;
536 GetSessionStorageCacheHelper(aStoragePrincipal
, false, nullptr, &cache
);
537 if (NS_FAILED(rv
) || !cache
) {
541 nsCOMPtr
<nsPIDOMWindowInner
> inner
= nsPIDOMWindowInner::From(aWindow
);
543 RefPtr
<SessionStorage
> storage
= new SessionStorage(
544 inner
, aPrincipal
, aStoragePrincipal
, cache
, this, u
""_ns
, aPrivate
);
546 storage
.forget(aRetval
);
551 SessionStorageManager::CloneStorage(Storage
* aStorage
) {
552 if (NS_WARN_IF(!aStorage
)) {
553 return NS_ERROR_UNEXPECTED
;
556 if (aStorage
->Type() != Storage::eSessionStorage
) {
557 return NS_ERROR_UNEXPECTED
;
560 // ToDo: At the moment, we clone the cache on the child process and then
561 // send the checkpoint. It would be nicer if we either serailizing all the
562 // data and sync to the parent process directly or clonig storage on the
563 // parnet process and sync it to the child process on demand.
565 RefPtr
<SessionStorageCache
> cache
;
566 nsresult rv
= GetSessionStorageCacheHelper(
567 aStorage
->StoragePrincipal(), true,
568 static_cast<SessionStorage
*>(aStorage
)->Cache(), &cache
);
569 if (NS_WARN_IF(NS_FAILED(rv
))) {
573 // If cache was cloned from other storage, then we shouldn't load the cache
574 // at the first access.
575 cache
->SetLoadedOrCloned();
578 rv
= EnsureManager();
579 if (NS_WARN_IF(NS_FAILED(rv
))) {
583 CheckpointData(*aStorage
->StoragePrincipal(), *cache
);
590 SessionStorageManager::CheckStorage(nsIPrincipal
* aPrincipal
, Storage
* aStorage
,
592 if (NS_WARN_IF(!aStorage
)) {
593 return NS_ERROR_UNEXPECTED
;
597 return NS_ERROR_NOT_AVAILABLE
;
602 RefPtr
<SessionStorageCache
> cache
;
604 GetSessionStorageCacheHelper(aPrincipal
, false, nullptr, &cache
);
605 if (NS_FAILED(rv
) || !cache
) {
609 if (aStorage
->Type() != Storage::eSessionStorage
) {
613 RefPtr
<SessionStorage
> sessionStorage
=
614 static_cast<SessionStorage
*>(aStorage
);
615 if (sessionStorage
->Cache() != cache
) {
619 if (!StorageUtils::PrincipalsEqual(aStorage
->StoragePrincipal(),
628 void SessionStorageManager::ClearStorages(
629 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
631 nsresult rv
= EnsureManager();
632 if (NS_WARN_IF(NS_FAILED(rv
))) {
636 mActor
->SendClearStorages(aPattern
, nsCString(aOriginScope
));
639 ClearStoragesInternal(aPattern
, aOriginScope
);
642 nsresult
SessionStorageManager::Observe(
643 const char* aTopic
, const nsAString
& aOriginAttributesPattern
,
644 const nsACString
& aOriginScope
) {
645 OriginAttributesPattern pattern
;
646 if (!pattern
.Init(aOriginAttributesPattern
)) {
647 NS_ERROR("Cannot parse origin attributes pattern");
648 return NS_ERROR_FAILURE
;
651 // Clear everything, caches + database
652 if (!strcmp(aTopic
, "cookie-cleared")) {
653 ClearStorages(pattern
, ""_ns
);
657 // Clear from caches everything that has been stored
658 // while in session-only mode
659 if (!strcmp(aTopic
, "session-only-cleared")) {
660 ClearStorages(pattern
, aOriginScope
);
664 // Clear everything (including so and pb data) from caches and database
665 // for the given domain and subdomains.
666 if (!strcmp(aTopic
, "browser:purge-sessionStorage")) {
667 ClearStorages(pattern
, aOriginScope
);
671 // Clear entries which match an OriginAttributesPattern.
672 if (!strcmp(aTopic
, "dom-storage:clear-origin-attributes-data") ||
673 !strcmp(aTopic
, "session-storage:clear-origin-attributes-data")) {
674 ClearStorages(pattern
, aOriginScope
);
678 if (!strcmp(aTopic
, "profile-change")) {
679 // For case caches are still referenced - clear them completely
680 ClearStorages(pattern
, ""_ns
);
688 SessionStorageManager::OriginRecord::~OriginRecord() = default;
691 void BackgroundSessionStorageManager::RemoveManager(uint64_t aTopContextId
) {
692 MOZ_ASSERT(XRE_IsParentProcess());
693 AssertIsOnMainThread();
695 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
696 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
697 if (NS_WARN_IF(!backgroundActor
)) {
701 if (NS_WARN_IF(!backgroundActor
->SendRemoveBackgroundSessionStorageManager(
708 void BackgroundSessionStorageManager::PropagateManager(
709 uint64_t aCurrentTopContextId
, uint64_t aTargetTopContextId
) {
710 MOZ_ASSERT(XRE_IsParentProcess());
711 AssertIsOnMainThread();
712 MOZ_ASSERT(aCurrentTopContextId
!= aTargetTopContextId
);
714 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
715 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
716 if (NS_WARN_IF(!backgroundActor
)) {
720 if (NS_WARN_IF(!backgroundActor
->SendPropagateBackgroundSessionStorageManager(
721 aCurrentTopContextId
, aTargetTopContextId
))) {
727 void BackgroundSessionStorageManager::LoadData(
728 uint64_t aTopContextId
,
729 const nsTArray
<mozilla::dom::SSCacheCopy
>& aCacheCopyList
) {
730 MOZ_ASSERT(XRE_IsParentProcess());
731 AssertIsOnMainThread();
733 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
734 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
735 if (NS_WARN_IF(!backgroundActor
)) {
739 if (NS_WARN_IF(!backgroundActor
->SendLoadSessionStorageManagerData(
740 aTopContextId
, aCacheCopyList
))) {
746 BackgroundSessionStorageManager
* BackgroundSessionStorageManager::GetOrCreate(
747 uint64_t aTopContextId
) {
748 MOZ_ASSERT(XRE_IsParentProcess());
749 ::mozilla::ipc::AssertIsOnBackgroundThread();
752 sManagers
= new nsRefPtrHashtable
<nsUint64HashKey
,
753 BackgroundSessionStorageManager
>();
754 NS_DispatchToMainThread(NS_NewRunnableFunction(
755 "dom::BackgroundSessionStorageManager::GetOrCreate", [] {
758 ::mozilla::ipc::PBackgroundChild
* backgroundActor
= ::mozilla::
759 ipc::BackgroundChild::GetOrCreateForCurrentThread();
760 if (NS_WARN_IF(!backgroundActor
)) {
766 ->SendShutdownBackgroundSessionStorageManagers())) {
770 ShutdownPhase::XPCOMShutdown
);
775 ->LookupOrInsertWith(
778 return new BackgroundSessionStorageManager(aTopContextId
);
783 BackgroundSessionStorageManager::BackgroundSessionStorageManager(
784 uint64_t aBrowsingContextId
)
785 : mCurrentBrowsingContextId(aBrowsingContextId
) {
786 MOZ_ASSERT(XRE_IsParentProcess());
787 ::mozilla::ipc::AssertIsOnBackgroundThread();
790 BackgroundSessionStorageManager::~BackgroundSessionStorageManager() = default;
792 void BackgroundSessionStorageManager::CopyDataToContentProcess(
793 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
794 nsTArray
<SSSetItemInfo
>& aData
) {
795 MOZ_ASSERT(XRE_IsParentProcess());
796 ::mozilla::ipc::AssertIsOnBackgroundThread();
798 auto* const originRecord
=
799 GetOriginRecord(aOriginAttrs
, aOriginKey
, false, nullptr);
804 aData
= originRecord
->mCache
->SerializeData();
808 RefPtr
<BackgroundSessionStorageManager::DataPromise
>
809 BackgroundSessionStorageManager::GetData(BrowsingContext
* aContext
,
811 bool aClearSessionStoreTimer
) {
812 MOZ_ASSERT(XRE_IsParentProcess());
813 MOZ_ASSERT(aContext
->IsTop());
815 AssertIsOnMainThread();
817 ::mozilla::ipc::PBackgroundChild
* backgroundActor
=
818 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
819 if (NS_WARN_IF(!backgroundActor
)) {
820 return DataPromise::CreateAndReject(
821 ::mozilla::ipc::ResponseRejectReason::SendError
, __func__
);
824 return backgroundActor
->SendGetSessionStorageManagerData(
825 aContext
->Id(), aSizeLimit
, aClearSessionStoreTimer
);
828 void BackgroundSessionStorageManager::GetData(
829 uint32_t aSizeLimit
, nsTArray
<SSCacheCopy
>& aCacheCopyList
) {
830 for (auto& managerActor
: mParticipatingActors
) {
831 for (auto* cacheActor
:
832 managerActor
->ManagedPBackgroundSessionStorageCacheParent()) {
833 auto* cache
= static_cast<SessionStorageCacheParent
*>(cacheActor
);
834 ::mozilla::ipc::PrincipalInfo info
= cache
->PrincipalInfo();
836 OriginAttributes attributes
;
837 StoragePrincipalHelper::GetOriginAttributes(cache
->PrincipalInfo(),
840 nsAutoCString originAttrs
;
841 attributes
.CreateSuffix(originAttrs
);
844 GetOriginRecord(originAttrs
, cache
->OriginKey(), false, nullptr);
850 if (record
->mCache
->GetOriginQuotaUsage() > aSizeLimit
) {
854 nsTArray
<SSSetItemInfo
> data
= record
->mCache
->SerializeData();
855 if (data
.IsEmpty()) {
859 SSCacheCopy
& cacheCopy
= *aCacheCopyList
.AppendElement();
860 cacheCopy
.originKey() = cache
->OriginKey();
861 cacheCopy
.principalInfo() = info
;
862 cacheCopy
.data().SwapElements(data
);
867 void BackgroundSessionStorageManager::UpdateData(
868 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
869 const nsTArray
<SSWriteInfo
>& aWriteInfos
) {
870 MOZ_ASSERT(XRE_IsParentProcess());
871 ::mozilla::ipc::AssertIsOnBackgroundThread();
873 auto* const originRecord
=
874 GetOriginRecord(aOriginAttrs
, aOriginKey
, true, nullptr);
875 MOZ_ASSERT(originRecord
);
877 MaybeScheduleSessionStoreUpdate();
879 originRecord
->mCache
->DeserializeWriteInfos(aWriteInfos
);
882 void BackgroundSessionStorageManager::UpdateData(
883 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
,
884 const nsTArray
<SSSetItemInfo
>& aData
) {
885 MOZ_ASSERT(XRE_IsParentProcess());
886 ::mozilla::ipc::AssertIsOnBackgroundThread();
888 auto* const originRecord
=
889 GetOriginRecord(aOriginAttrs
, aOriginKey
, true, nullptr);
890 MOZ_ASSERT(originRecord
);
892 originRecord
->mCache
->DeserializeData(aData
);
895 void BackgroundSessionStorageManager::ClearStorages(
896 const OriginAttributesPattern
& aPattern
, const nsACString
& aOriginScope
) {
897 MOZ_ASSERT(XRE_IsParentProcess());
898 ::mozilla::ipc::AssertIsOnBackgroundThread();
899 ClearStoragesInternal(aPattern
, aOriginScope
);
902 void BackgroundSessionStorageManager::ClearStoragesForOrigin(
903 const nsACString
& aOriginAttrs
, const nsACString
& aOriginKey
) {
904 ::mozilla::ipc::AssertIsInMainProcess();
905 ::mozilla::ipc::AssertIsOnBackgroundThread();
907 for (auto& managerActor
: mParticipatingActors
) {
908 QM_WARNONLY_TRY(OkIf(managerActor
->SendClearStoragesForOrigin(
909 nsCString(aOriginAttrs
), nsCString(aOriginKey
))));
912 ClearStoragesForOriginInternal(aOriginAttrs
, aOriginKey
);
915 void BackgroundSessionStorageManager::SetCurrentBrowsingContextId(
916 uint64_t aBrowsingContextId
) {
917 MOZ_DIAGNOSTIC_ASSERT(aBrowsingContextId
!= mCurrentBrowsingContextId
);
918 mCurrentBrowsingContextId
= aBrowsingContextId
;
921 void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() {
922 if (!SessionStorePlatformCollection()) {
926 if (mSessionStoreCallbackTimer
) {
930 if (StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
931 DispatchSessionStoreUpdate();
935 auto result
= NS_NewTimerWithFuncCallback(
936 [](nsITimer
*, void* aClosure
) {
937 auto* mgr
= static_cast<BackgroundSessionStorageManager
*>(aClosure
);
938 mgr
->DispatchSessionStoreUpdate();
940 this, StaticPrefs::browser_sessionstore_interval(),
941 nsITimer::TYPE_ONE_SHOT
,
942 "BackgroundSessionStorageManager::DispatchSessionStoreUpdate");
944 if (result
.isErr()) {
948 mSessionStoreCallbackTimer
= result
.unwrap();
951 void BackgroundSessionStorageManager::MaybeDispatchSessionStoreUpdate() {
952 if (mSessionStoreCallbackTimer
) {
953 BackgroundSessionStorageManager::DispatchSessionStoreUpdate();
957 void BackgroundSessionStorageManager::DispatchSessionStoreUpdate() {
958 ::mozilla::ipc::AssertIsOnBackgroundThread();
959 NS_DispatchToMainThread(NS_NewRunnableFunction(
960 "CanonicalBrowsingContext::UpdateSessionStore",
961 [targetBrowsingContextId
= mCurrentBrowsingContextId
]() {
962 CanonicalBrowsingContext::UpdateSessionStoreForStorage(
963 targetBrowsingContextId
);
966 CancelSessionStoreUpdate();
969 void BackgroundSessionStorageManager::CancelSessionStoreUpdate() {
970 if (mSessionStoreCallbackTimer
) {
971 mSessionStoreCallbackTimer
->Cancel();
972 mSessionStoreCallbackTimer
= nullptr;
976 void BackgroundSessionStorageManager::AddParticipatingActor(
977 SessionStorageManagerParent
* aActor
) {
978 ::mozilla::ipc::AssertIsOnBackgroundThread();
979 mParticipatingActors
.AppendElement(aActor
);
982 void BackgroundSessionStorageManager::RemoveParticipatingActor(
983 SessionStorageManagerParent
* aActor
) {
984 ::mozilla::ipc::AssertIsOnBackgroundThread();
985 mParticipatingActors
.RemoveElement(aActor
);
988 } // namespace mozilla::dom