Bug 1708193 - Remove mozapps/extensions/internal/Content.js r=rpl
[gecko.git] / dom / storage / SessionStorageManager.cpp
blob2def0d213c3e51dd73d59e3d6ab81c8c4deead46
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 {
33 namespace dom {
35 using namespace StorageUtils;
37 // Parent process, background thread hashmap that stores top context id and
38 // manager pair.
39 static StaticAutoPtr<
40 nsRefPtrHashtable<nsUint64HashKey, BackgroundSessionStorageManager>>
41 sManagers;
43 bool RecvShutdownBackgroundSessionStorageManagers() {
44 ::mozilla::ipc::AssertIsOnBackgroundThread();
46 sManagers = nullptr;
47 return true;
50 void RecvPropagateBackgroundSessionStorageManager(
51 uint64_t aCurrentTopContextId, uint64_t aTargetTopContextId) {
52 ::mozilla::ipc::AssertIsOnBackgroundThread();
54 if (sManagers) {
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
62 // called only once?
63 sManagers->InsertOrUpdate(aTargetTopContextId, std::move(mgr));
68 bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId) {
69 ::mozilla::ipc::AssertIsOnBackgroundThread();
71 if (sManagers) {
72 RefPtr<BackgroundSessionStorageManager> mgr;
73 sManagers->Remove(aTopContextId, getter_AddRefs(mgr));
75 if (mgr) {
76 mgr->CancelSessionStoreUpdate();
80 return true;
83 bool RecvLoadSessionStorageData(
84 uint64_t aTopContextId,
85 nsTArray<mozilla::dom::SSCacheCopy>&& aCacheCopyList) {
86 if (aCacheCopyList.IsEmpty()) {
87 return true;
90 RefPtr<BackgroundSessionStorageManager> manager =
91 BackgroundSessionStorageManager::GetOrCreate(aTopContextId);
93 if (!manager) {
94 return true;
97 for (const auto& cacheInit : aCacheCopyList) {
98 OriginAttributes attrs;
99 StoragePrincipalHelper::GetOriginAttributes(cacheInit.principalInfo(),
100 attrs);
102 nsAutoCString originAttrs;
103 attrs.CreateSuffix(originAttrs);
105 manager->UpdateData(originAttrs, cacheInit.originKey(), cacheInit.data());
108 return true;
111 bool RecvGetSessionStorageData(
112 uint64_t aTopContextId, uint32_t aSizeLimit, bool aCancelSessionStoreTimer,
113 ::mozilla::ipc::PBackgroundParent::GetSessionStorageManagerDataResolver&&
114 aResolver) {
115 nsTArray<mozilla::dom::SSCacheCopy> data;
116 auto resolve = MakeScopeExit([&]() { aResolver(std::move(data)); });
118 if (!sManagers) {
119 return true;
122 RefPtr<BackgroundSessionStorageManager> manager =
123 sManagers->Get(aTopContextId);
124 if (!manager) {
125 return true;
128 if (aCancelSessionStoreTimer) {
129 manager->CancelSessionStoreUpdate();
132 manager->GetData(aSizeLimit, data);
134 return true;
137 void SessionStorageManagerBase::ClearStoragesInternal(
138 const OriginAttributesPattern& aPattern, const nsACString& aOriginScope) {
139 for (const auto& oaEntry : mOATable) {
140 OriginAttributes oa;
141 DebugOnly<bool> ok = oa.PopulateFromSuffix(oaEntry.GetKey());
142 MOZ_ASSERT(ok);
143 if (!aPattern.Matches(oa)) {
144 // This table doesn't match the given origin attributes pattern
145 continue;
148 OriginKeyHashTable* table = oaEntry.GetWeak();
149 for (const auto& originKeyEntry : *table) {
150 if (aOriginScope.IsEmpty() ||
151 StringBeginsWith(originKeyEntry.GetKey(), aOriginScope)) {
152 const auto cache = originKeyEntry.GetData()->mCache;
153 cache->Clear(false);
154 cache->ResetWriteInfos();
160 SessionStorageManagerBase::OriginRecord*
161 SessionStorageManagerBase::GetOriginRecord(
162 const nsACString& aOriginAttrs, const nsACString& aOriginKey,
163 const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
164 // XXX It seems aMakeIfNeeded is always known at compile-time, so this could
165 // be split into two functions.
167 if (aMakeIfNeeded) {
168 return mOATable.GetOrInsertNew(aOriginAttrs)
169 ->LookupOrInsertWith(
170 aOriginKey,
171 [&] {
172 auto newOriginRecord = MakeUnique<OriginRecord>();
173 if (aCloneFrom) {
174 newOriginRecord->mCache = aCloneFrom->Clone();
175 } else {
176 newOriginRecord->mCache = new SessionStorageCache();
178 return newOriginRecord;
180 .get();
183 auto* const table = mOATable.Get(aOriginAttrs);
184 if (!table) return nullptr;
186 return table->Get(aOriginKey);
189 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager)
190 NS_INTERFACE_MAP_ENTRY(nsISupports)
191 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
192 NS_INTERFACE_MAP_ENTRY(nsIDOMSessionStorageManager)
193 NS_INTERFACE_MAP_END
195 NS_IMPL_CYCLE_COLLECTION(SessionStorageManager, mBrowsingContext)
196 NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStorageManager)
197 NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager)
199 SessionStorageManager::SessionStorageManager(
200 RefPtr<BrowsingContext> aBrowsingContext)
201 : mBrowsingContext(std::move(aBrowsingContext)), mActor(nullptr) {
202 AssertIsOnMainThread();
204 StorageObserver* observer = StorageObserver::Self();
205 NS_ASSERTION(
206 observer,
207 "No StorageObserver, cannot observe private data delete notifications!");
209 if (observer) {
210 observer->AddSink(this);
213 if (!XRE_IsParentProcess() && NextGenLocalStorageEnabled()) {
214 // When LSNG is enabled the thread IPC bridge doesn't exist, so we have to
215 // create own protocol to distribute chrome observer notifications to
216 // content processes.
217 mObserver = SessionStorageObserver::Get();
219 if (!mObserver) {
220 ContentChild* contentActor = ContentChild::GetSingleton();
221 MOZ_ASSERT(contentActor);
223 RefPtr<SessionStorageObserver> observer = new SessionStorageObserver();
225 SessionStorageObserverChild* actor =
226 new SessionStorageObserverChild(observer);
228 MOZ_ALWAYS_TRUE(
229 contentActor->SendPSessionStorageObserverConstructor(actor));
231 observer->SetActor(actor);
233 mObserver = std::move(observer);
238 SessionStorageManager::~SessionStorageManager() {
239 StorageObserver* observer = StorageObserver::Self();
240 if (observer) {
241 observer->RemoveSink(this);
244 if (mActor) {
245 mActor->SendDeleteMeInternal();
246 MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
250 bool SessionStorageManager::CanLoadData() {
251 AssertIsOnMainThread();
253 return mBrowsingContext && !mBrowsingContext->IsDiscarded();
256 void SessionStorageManager::SetActor(SessionStorageManagerChild* aActor) {
257 AssertIsOnMainThread();
258 MOZ_ASSERT(aActor);
259 MOZ_ASSERT(!mActor);
261 mActor = aActor;
264 bool SessionStorageManager::ActorExists() const {
265 AssertIsOnMainThread();
267 return mActor;
270 void SessionStorageManager::ClearActor() {
271 AssertIsOnMainThread();
272 MOZ_ASSERT(mActor);
274 mActor = nullptr;
277 nsresult SessionStorageManager::EnsureManager() {
278 AssertIsOnMainThread();
279 MOZ_ASSERT(CanLoadData());
281 if (ActorExists()) {
282 return NS_OK;
285 ::mozilla::ipc::PBackgroundChild* backgroundActor =
286 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
287 if (NS_WARN_IF(!backgroundActor)) {
288 return NS_ERROR_FAILURE;
291 RefPtr<SessionStorageManagerChild> actor =
292 new SessionStorageManagerChild(this);
294 if (!backgroundActor->SendPBackgroundSessionStorageManagerConstructor(
295 actor, mBrowsingContext->Top()->Id())) {
296 return NS_ERROR_FAILURE;
299 SetActor(actor);
301 return NS_OK;
304 SessionStorageCacheChild* SessionStorageManager::EnsureCache(
305 nsIPrincipal& aPrincipal, const nsCString& aOriginKey,
306 SessionStorageCache& aCache) {
307 AssertIsOnMainThread();
308 MOZ_ASSERT(CanLoadData());
309 MOZ_ASSERT(ActorExists());
311 if (aCache.Actor()) {
312 return aCache.Actor();
315 mozilla::ipc::PrincipalInfo info;
316 nsresult rv = PrincipalToPrincipalInfo(&aPrincipal, &info);
318 if (NS_FAILED(rv)) {
319 return nullptr;
322 RefPtr<SessionStorageCacheChild> actor =
323 new SessionStorageCacheChild(&aCache);
324 if (!mActor->SendPBackgroundSessionStorageCacheConstructor(actor, info,
325 aOriginKey)) {
326 return nullptr;
329 aCache.SetActor(actor);
331 return actor;
334 nsresult SessionStorageManager::LoadData(nsIPrincipal& aPrincipal,
335 SessionStorageCache& aCache) {
336 AssertIsOnMainThread();
337 MOZ_ASSERT(mActor);
339 nsAutoCString originKey;
340 nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
341 if (NS_WARN_IF(NS_FAILED(rv))) {
342 return rv;
345 nsAutoCString originAttributes;
346 aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
348 auto* const originRecord =
349 GetOriginRecord(originAttributes, originKey, true, nullptr);
350 MOZ_ASSERT(originRecord);
352 if (originRecord->mLoaded) {
353 return NS_OK;
356 RefPtr<SessionStorageCacheChild> cacheActor =
357 EnsureCache(aPrincipal, originKey, aCache);
359 if (!cacheActor) {
360 return NS_ERROR_FAILURE;
363 nsTArray<SSSetItemInfo> data;
364 if (!cacheActor->SendLoad(&data)) {
365 return NS_ERROR_FAILURE;
368 originRecord->mCache->DeserializeData(data);
370 originRecord->mLoaded.Flip();
371 aCache.SetLoadedOrCloned();
373 return NS_OK;
376 void SessionStorageManager::CheckpointData(nsIPrincipal& aPrincipal,
377 SessionStorageCache& aCache) {
378 AssertIsOnMainThread();
379 MOZ_ASSERT(mActor);
381 nsAutoCString originKey;
382 nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
383 if (NS_WARN_IF(NS_FAILED(rv))) {
384 return;
387 return CheckpointDataInternal(aPrincipal, originKey, aCache);
390 void SessionStorageManager::CheckpointDataInternal(
391 nsIPrincipal& aPrincipal, const nsCString& aOriginKey,
392 SessionStorageCache& aCache) {
393 AssertIsOnMainThread();
394 MOZ_ASSERT(mActor);
396 nsTArray<SSWriteInfo> writeInfos = aCache.SerializeWriteInfos();
398 if (writeInfos.IsEmpty()) {
399 return;
402 RefPtr<SessionStorageCacheChild> cacheActor =
403 EnsureCache(aPrincipal, aOriginKey, aCache);
405 if (!cacheActor) {
406 return;
409 Unused << cacheActor->SendCheckpoint(writeInfos);
411 aCache.ResetWriteInfos();
414 NS_IMETHODIMP
415 SessionStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal,
416 nsIPrincipal* aStoragePrincipal,
417 Storage** aRetval) {
418 // Nothing to preload.
419 return NS_OK;
422 NS_IMETHODIMP
423 SessionStorageManager::GetSessionStorageCache(
424 nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal,
425 RefPtr<SessionStorageCache>* aRetVal) {
426 return GetSessionStorageCacheHelper(aStoragePrincipal, true, nullptr,
427 aRetVal);
430 nsresult SessionStorageManager::GetSessionStorageCacheHelper(
431 nsIPrincipal* aPrincipal, bool aMakeIfNeeded,
432 SessionStorageCache* aCloneFrom, RefPtr<SessionStorageCache>* aRetVal) {
433 nsAutoCString originKey;
434 nsAutoCString originAttributes;
435 nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
436 aPrincipal->OriginAttributesRef().CreateSuffix(originAttributes);
437 if (NS_FAILED(rv)) {
438 return NS_ERROR_NOT_AVAILABLE;
441 return GetSessionStorageCacheHelper(originAttributes, originKey,
442 aMakeIfNeeded, aCloneFrom, aRetVal);
445 nsresult SessionStorageManager::GetSessionStorageCacheHelper(
446 const nsACString& aOriginAttrs, const nsACString& aOriginKey,
447 bool aMakeIfNeeded, SessionStorageCache* aCloneFrom,
448 RefPtr<SessionStorageCache>* aRetVal) {
449 if (OriginRecord* const originRecord = GetOriginRecord(
450 aOriginAttrs, aOriginKey, aMakeIfNeeded, aCloneFrom)) {
451 *aRetVal = originRecord->mCache;
452 } else {
453 *aRetVal = nullptr;
455 return NS_OK;
458 NS_IMETHODIMP
459 SessionStorageManager::CreateStorage(mozIDOMWindow* aWindow,
460 nsIPrincipal* aPrincipal,
461 nsIPrincipal* aStoragePrincipal,
462 const nsAString& aDocumentURI,
463 bool aPrivate, Storage** aRetval) {
464 RefPtr<SessionStorageCache> cache;
465 nsresult rv = GetSessionStorageCache(aPrincipal, aStoragePrincipal, &cache);
466 if (NS_FAILED(rv)) {
467 return rv;
470 nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
472 RefPtr<SessionStorage> storage =
473 new SessionStorage(inner, aPrincipal, aStoragePrincipal, cache, this,
474 aDocumentURI, aPrivate);
476 storage.forget(aRetval);
477 return NS_OK;
480 NS_IMETHODIMP
481 SessionStorageManager::GetStorage(mozIDOMWindow* aWindow,
482 nsIPrincipal* aPrincipal,
483 nsIPrincipal* aStoragePrincipal,
484 bool aPrivate, Storage** aRetval) {
485 *aRetval = nullptr;
487 RefPtr<SessionStorageCache> cache;
488 nsresult rv =
489 GetSessionStorageCacheHelper(aStoragePrincipal, false, nullptr, &cache);
490 if (NS_FAILED(rv) || !cache) {
491 return rv;
494 nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
496 RefPtr<SessionStorage> storage = new SessionStorage(
497 inner, aPrincipal, aStoragePrincipal, cache, this, u""_ns, aPrivate);
499 storage.forget(aRetval);
500 return NS_OK;
503 NS_IMETHODIMP
504 SessionStorageManager::CloneStorage(Storage* aStorage) {
505 if (NS_WARN_IF(!aStorage)) {
506 return NS_ERROR_UNEXPECTED;
509 if (aStorage->Type() != Storage::eSessionStorage) {
510 return NS_ERROR_UNEXPECTED;
513 // ToDo: At the moment, we clone the cache on the child process and then
514 // send the checkpoint. It would be nicer if we either serailizing all the
515 // data and sync to the parent process directly or clonig storage on the
516 // parnet process and sync it to the child process on demand.
518 RefPtr<SessionStorageCache> cache;
519 nsresult rv = GetSessionStorageCacheHelper(
520 aStorage->StoragePrincipal(), true,
521 static_cast<SessionStorage*>(aStorage)->Cache(), &cache);
522 if (NS_WARN_IF(NS_FAILED(rv))) {
523 return rv;
526 // If cache was cloned from other storage, then we shouldn't load the cache
527 // at the first access.
528 cache->SetLoadedOrCloned();
530 if (CanLoadData()) {
531 rv = EnsureManager();
532 if (NS_WARN_IF(NS_FAILED(rv))) {
533 return rv;
536 CheckpointData(*aStorage->StoragePrincipal(), *cache);
539 return rv;
542 NS_IMETHODIMP
543 SessionStorageManager::CheckStorage(nsIPrincipal* aPrincipal, Storage* aStorage,
544 bool* aRetval) {
545 if (NS_WARN_IF(!aStorage)) {
546 return NS_ERROR_UNEXPECTED;
549 if (!aPrincipal) {
550 return NS_ERROR_NOT_AVAILABLE;
553 *aRetval = false;
555 RefPtr<SessionStorageCache> cache;
556 nsresult rv =
557 GetSessionStorageCacheHelper(aPrincipal, false, nullptr, &cache);
558 if (NS_FAILED(rv) || !cache) {
559 return rv;
562 if (aStorage->Type() != Storage::eSessionStorage) {
563 return NS_OK;
566 RefPtr<SessionStorage> sessionStorage =
567 static_cast<SessionStorage*>(aStorage);
568 if (sessionStorage->Cache() != cache) {
569 return NS_OK;
572 if (!StorageUtils::PrincipalsEqual(aStorage->StoragePrincipal(),
573 aPrincipal)) {
574 return NS_OK;
577 *aRetval = true;
578 return NS_OK;
581 void SessionStorageManager::ClearStorages(
582 const OriginAttributesPattern& aPattern, const nsACString& aOriginScope) {
583 if (CanLoadData()) {
584 nsresult rv = EnsureManager();
585 if (NS_WARN_IF(NS_FAILED(rv))) {
586 return;
589 mActor->SendClearStorages(aPattern, nsCString(aOriginScope));
592 ClearStoragesInternal(aPattern, aOriginScope);
595 nsresult SessionStorageManager::Observe(
596 const char* aTopic, const nsAString& aOriginAttributesPattern,
597 const nsACString& aOriginScope) {
598 OriginAttributesPattern pattern;
599 if (!pattern.Init(aOriginAttributesPattern)) {
600 NS_ERROR("Cannot parse origin attributes pattern");
601 return NS_ERROR_FAILURE;
604 // Clear everything, caches + database
605 if (!strcmp(aTopic, "cookie-cleared")) {
606 ClearStorages(pattern, ""_ns);
607 return NS_OK;
610 // Clear from caches everything that has been stored
611 // while in session-only mode
612 if (!strcmp(aTopic, "session-only-cleared")) {
613 ClearStorages(pattern, aOriginScope);
614 return NS_OK;
617 // Clear everything (including so and pb data) from caches and database
618 // for the given domain and subdomains.
619 if (!strcmp(aTopic, "browser:purge-sessionStorage")) {
620 ClearStorages(pattern, aOriginScope);
621 return NS_OK;
624 // Clear entries which match an OriginAttributesPattern.
625 if (!strcmp(aTopic, "dom-storage:clear-origin-attributes-data") ||
626 !strcmp(aTopic, "session-storage:clear-origin-attributes-data")) {
627 ClearStorages(pattern, aOriginScope);
628 return NS_OK;
631 if (!strcmp(aTopic, "profile-change")) {
632 // For case caches are still referenced - clear them completely
633 ClearStorages(pattern, ""_ns);
634 mOATable.Clear();
635 return NS_OK;
638 return NS_OK;
641 SessionStorageManager::OriginRecord::~OriginRecord() = default;
643 // static
644 void BackgroundSessionStorageManager::RemoveManager(uint64_t aTopContextId) {
645 MOZ_ASSERT(XRE_IsParentProcess());
646 AssertIsOnMainThread();
648 ::mozilla::ipc::PBackgroundChild* backgroundActor =
649 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
650 if (NS_WARN_IF(!backgroundActor)) {
651 return;
654 if (NS_WARN_IF(!backgroundActor->SendRemoveBackgroundSessionStorageManager(
655 aTopContextId))) {
656 return;
660 // static
661 void BackgroundSessionStorageManager::PropagateManager(
662 uint64_t aCurrentTopContextId, uint64_t aTargetTopContextId) {
663 MOZ_ASSERT(XRE_IsParentProcess());
664 AssertIsOnMainThread();
665 MOZ_ASSERT(aCurrentTopContextId != aTargetTopContextId);
667 ::mozilla::ipc::PBackgroundChild* backgroundActor =
668 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
669 if (NS_WARN_IF(!backgroundActor)) {
670 return;
673 if (NS_WARN_IF(!backgroundActor->SendPropagateBackgroundSessionStorageManager(
674 aCurrentTopContextId, aTargetTopContextId))) {
675 return;
679 // static
680 void BackgroundSessionStorageManager::LoadData(
681 uint64_t aTopContextId,
682 const nsTArray<mozilla::dom::SSCacheCopy>& aCacheCopyList) {
683 MOZ_ASSERT(XRE_IsParentProcess());
684 AssertIsOnMainThread();
686 ::mozilla::ipc::PBackgroundChild* backgroundActor =
687 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
688 if (NS_WARN_IF(!backgroundActor)) {
689 return;
692 if (NS_WARN_IF(!backgroundActor->SendLoadSessionStorageManagerData(
693 aTopContextId, aCacheCopyList))) {
694 return;
698 // static
699 BackgroundSessionStorageManager* BackgroundSessionStorageManager::GetOrCreate(
700 uint64_t aTopContextId) {
701 MOZ_ASSERT(XRE_IsParentProcess());
702 ::mozilla::ipc::AssertIsOnBackgroundThread();
704 if (!sManagers) {
705 sManagers = new nsRefPtrHashtable<nsUint64HashKey,
706 BackgroundSessionStorageManager>();
707 NS_DispatchToMainThread(NS_NewRunnableFunction(
708 "dom::BackgroundSessionStorageManager::GetOrCreate", [] {
709 RunOnShutdown(
710 [] {
711 ::mozilla::ipc::PBackgroundChild* backgroundActor = ::mozilla::
712 ipc::BackgroundChild::GetOrCreateForCurrentThread();
713 if (NS_WARN_IF(!backgroundActor)) {
714 return;
717 if (NS_WARN_IF(
718 !backgroundActor
719 ->SendShutdownBackgroundSessionStorageManagers())) {
720 return;
723 ShutdownPhase::XPCOMShutdown);
724 }));
727 return sManagers
728 ->LookupOrInsertWith(
729 aTopContextId,
730 [aTopContextId] {
731 return new BackgroundSessionStorageManager(aTopContextId);
733 .get();
736 BackgroundSessionStorageManager::BackgroundSessionStorageManager(
737 uint64_t aBrowsingContextId)
738 : mCurrentBrowsingContextId(aBrowsingContextId) {
739 MOZ_ASSERT(XRE_IsParentProcess());
740 ::mozilla::ipc::AssertIsOnBackgroundThread();
743 BackgroundSessionStorageManager::~BackgroundSessionStorageManager() = default;
745 void BackgroundSessionStorageManager::CopyDataToContentProcess(
746 const nsACString& aOriginAttrs, const nsACString& aOriginKey,
747 nsTArray<SSSetItemInfo>& aData) {
748 MOZ_ASSERT(XRE_IsParentProcess());
749 ::mozilla::ipc::AssertIsOnBackgroundThread();
751 auto* const originRecord =
752 GetOriginRecord(aOriginAttrs, aOriginKey, false, nullptr);
753 if (!originRecord) {
754 return;
757 aData = originRecord->mCache->SerializeData();
760 /* static */
761 RefPtr<BackgroundSessionStorageManager::DataPromise>
762 BackgroundSessionStorageManager::GetData(BrowsingContext* aContext,
763 uint32_t aSizeLimit,
764 bool aClearSessionStoreTimer) {
765 MOZ_ASSERT(XRE_IsParentProcess());
766 MOZ_ASSERT(aContext->IsTop());
768 AssertIsOnMainThread();
770 ::mozilla::ipc::PBackgroundChild* backgroundActor =
771 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
772 if (NS_WARN_IF(!backgroundActor)) {
773 return DataPromise::CreateAndReject(
774 ::mozilla::ipc::ResponseRejectReason::SendError, __func__);
777 return backgroundActor->SendGetSessionStorageManagerData(
778 aContext->Id(), aSizeLimit, aClearSessionStoreTimer);
781 void BackgroundSessionStorageManager::GetData(
782 uint32_t aSizeLimit, nsTArray<SSCacheCopy>& aCacheCopyList) {
783 for (auto& managerActor : mParticipatingActors) {
784 for (auto* cacheActor :
785 managerActor->ManagedPBackgroundSessionStorageCacheParent()) {
786 auto* cache = static_cast<SessionStorageCacheParent*>(cacheActor);
787 ::mozilla::ipc::PrincipalInfo info = cache->PrincipalInfo();
789 OriginAttributes attributes;
790 StoragePrincipalHelper::GetOriginAttributes(cache->PrincipalInfo(),
791 attributes);
793 nsAutoCString originAttrs;
794 attributes.CreateSuffix(originAttrs);
796 auto* record =
797 GetOriginRecord(originAttrs, cache->OriginKey(), false, nullptr);
799 if (!record) {
800 continue;
803 if (record->mCache->GetOriginQuotaUsage() > aSizeLimit) {
804 continue;
807 nsTArray<SSSetItemInfo> data = record->mCache->SerializeData();
808 if (data.IsEmpty()) {
809 continue;
812 SSCacheCopy& cacheCopy = *aCacheCopyList.AppendElement();
813 cacheCopy.originKey() = cache->OriginKey();
814 cacheCopy.principalInfo() = info;
815 cacheCopy.data().SwapElements(data);
820 void BackgroundSessionStorageManager::UpdateData(
821 const nsACString& aOriginAttrs, const nsACString& aOriginKey,
822 const nsTArray<SSWriteInfo>& aWriteInfos) {
823 MOZ_ASSERT(XRE_IsParentProcess());
824 ::mozilla::ipc::AssertIsOnBackgroundThread();
826 auto* const originRecord =
827 GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
828 MOZ_ASSERT(originRecord);
830 MaybeScheduleSessionStoreUpdate();
832 originRecord->mCache->DeserializeWriteInfos(aWriteInfos);
835 void BackgroundSessionStorageManager::UpdateData(
836 const nsACString& aOriginAttrs, const nsACString& aOriginKey,
837 const nsTArray<SSSetItemInfo>& aData) {
838 MOZ_ASSERT(XRE_IsParentProcess());
839 ::mozilla::ipc::AssertIsOnBackgroundThread();
841 auto* const originRecord =
842 GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
843 MOZ_ASSERT(originRecord);
845 originRecord->mCache->DeserializeData(aData);
848 void BackgroundSessionStorageManager::ClearStorages(
849 const OriginAttributesPattern& aPattern, const nsCString& aOriginScope) {
850 MOZ_ASSERT(XRE_IsParentProcess());
851 ::mozilla::ipc::AssertIsOnBackgroundThread();
852 ClearStoragesInternal(aPattern, aOriginScope);
855 void BackgroundSessionStorageManager::SetCurrentBrowsingContextId(
856 uint64_t aBrowsingContextId) {
857 MOZ_DIAGNOSTIC_ASSERT(aBrowsingContextId != mCurrentBrowsingContextId);
858 mCurrentBrowsingContextId = aBrowsingContextId;
861 void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() {
862 if constexpr (!SessionStoreUtils::NATIVE_LISTENER) {
863 return;
866 if (mSessionStoreCallbackTimer) {
867 return;
870 if (StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
871 DispatchSessionStoreUpdate();
872 return;
875 auto result = NS_NewTimerWithFuncCallback(
876 [](nsITimer*, void* aClosure) {
877 auto* mgr = static_cast<BackgroundSessionStorageManager*>(aClosure);
878 mgr->DispatchSessionStoreUpdate();
880 this, StaticPrefs::browser_sessionstore_interval(),
881 nsITimer::TYPE_ONE_SHOT,
882 "BackgroundSessionStorageManager::DispatchSessionStoreUpdate");
884 if (result.isErr()) {
885 return;
888 mSessionStoreCallbackTimer = result.unwrap();
891 void BackgroundSessionStorageManager::MaybeDispatchSessionStoreUpdate() {
892 if (mSessionStoreCallbackTimer) {
893 BackgroundSessionStorageManager::DispatchSessionStoreUpdate();
897 void BackgroundSessionStorageManager::DispatchSessionStoreUpdate() {
898 ::mozilla::ipc::AssertIsOnBackgroundThread();
899 NS_DispatchToMainThread(NS_NewRunnableFunction(
900 "CanonicalBrowsingContext::UpdateSessionStore",
901 [targetBrowsingContextId = mCurrentBrowsingContextId]() {
902 CanonicalBrowsingContext::UpdateSessionStoreForStorage(
903 targetBrowsingContextId);
904 }));
906 CancelSessionStoreUpdate();
909 void BackgroundSessionStorageManager::CancelSessionStoreUpdate() {
910 if (mSessionStoreCallbackTimer) {
911 mSessionStoreCallbackTimer->Cancel();
912 mSessionStoreCallbackTimer = nullptr;
916 void BackgroundSessionStorageManager::AddParticipatingActor(
917 SessionStorageManagerParent* aActor) {
918 ::mozilla::ipc::AssertIsOnBackgroundThread();
919 mParticipatingActors.AppendElement(aActor);
922 void BackgroundSessionStorageManager::RemoveParticipatingActor(
923 SessionStorageManagerParent* aActor) {
924 ::mozilla::ipc::AssertIsOnBackgroundThread();
925 mParticipatingActors.RemoveElement(aActor);
928 } // namespace dom
929 } // namespace mozilla