Bug 1769952 - Fix running raptor on a Win10-64 VM r=sparky
[gecko.git] / dom / storage / StorageIPC.cpp
blob515af6efa9328cd8257138e6f9767dd3988f8b53
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 "StorageIPC.h"
9 #include "StorageCommon.h"
10 #include "StorageUtils.h"
11 #include "LocalStorageManager.h"
12 #include "SessionStorageObserver.h"
13 #include "SessionStorageManager.h"
14 #include "SessionStorageCache.h"
16 #include "mozilla/dom/LocalStorageCommon.h"
17 #include "mozilla/ipc/BackgroundChild.h"
18 #include "mozilla/ipc/BackgroundParent.h"
19 #include "mozilla/ipc/PBackgroundChild.h"
20 #include "mozilla/ipc/PBackgroundParent.h"
21 #include "mozilla/dom/ContentParent.h"
22 #include "mozilla/StoragePrincipalHelper.h"
23 #include "mozilla/Unused.h"
24 #include "nsCOMPtr.h"
25 #include "nsIPrincipal.h"
26 #include "nsThreadUtils.h"
28 namespace mozilla::dom {
30 namespace {
32 using LocalStorageCacheParentHashtable =
33 nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>;
35 StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents;
37 StorageDBChild* sStorageChild[kPrivateBrowsingIdCount] = {nullptr, nullptr};
39 // False until we shut the storage child down.
40 bool sStorageChildDown[kPrivateBrowsingIdCount] = {false, false};
42 } // namespace
44 LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache)
45 : mCache(aCache) {
46 AssertIsOnOwningThread();
47 MOZ_ASSERT(aCache);
48 aCache->AssertIsOnOwningThread();
50 MOZ_COUNT_CTOR(LocalStorageCacheChild);
53 LocalStorageCacheChild::~LocalStorageCacheChild() {
54 AssertIsOnOwningThread();
56 MOZ_COUNT_DTOR(LocalStorageCacheChild);
59 void LocalStorageCacheChild::SendDeleteMeInternal() {
60 AssertIsOnOwningThread();
62 if (mCache) {
63 mCache->ClearActor();
64 mCache = nullptr;
66 MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe());
70 void LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
71 AssertIsOnOwningThread();
73 if (mCache) {
74 mCache->ClearActor();
75 mCache = nullptr;
79 mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve(
80 const PrincipalInfo& aPrincipalInfo,
81 const PrincipalInfo& aCachePrincipalInfo,
82 const uint32_t& aPrivateBrowsingId, const nsString& aDocumentURI,
83 const nsString& aKey, const nsString& aOldValue,
84 const nsString& aNewValue) {
85 AssertIsOnOwningThread();
87 auto principalOrErr = PrincipalInfoToPrincipal(aPrincipalInfo);
88 if (NS_WARN_IF(principalOrErr.isErr())) {
89 return IPC_FAIL_NO_REASON(this);
92 auto cachePrincipalOrErr = PrincipalInfoToPrincipal(aCachePrincipalInfo);
93 if (NS_WARN_IF(cachePrincipalOrErr.isErr())) {
94 return IPC_FAIL_NO_REASON(this);
97 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
98 nsCOMPtr<nsIPrincipal> cachePrincipal = cachePrincipalOrErr.unwrap();
100 if (StorageUtils::PrincipalsEqual(principal, cachePrincipal)) {
101 Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
102 aNewValue,
103 /* aStorageType */ u"localStorage", aDocumentURI,
104 /* aIsPrivate */ !!aPrivateBrowsingId,
105 /* aImmediateDispatch */ true);
108 return IPC_OK();
111 // ----------------------------------------------------------------------------
112 // Child
113 // ----------------------------------------------------------------------------
115 class StorageDBChild::ShutdownObserver final : public nsIObserver {
116 // Expected to be only 0 or 1.
117 const uint32_t mPrivateBrowsingId;
119 public:
120 explicit ShutdownObserver(const uint32_t aPrivateBrowsingId)
121 : mPrivateBrowsingId(aPrivateBrowsingId) {
122 MOZ_ASSERT(NS_IsMainThread());
123 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
126 NS_DECL_ISUPPORTS
127 NS_DECL_NSIOBSERVER
129 private:
130 ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
133 void StorageDBChild::AddIPDLReference() {
134 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
135 mIPCOpen = true;
136 AddRef();
139 void StorageDBChild::ReleaseIPDLReference() {
140 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
141 mIPCOpen = false;
142 Release();
145 StorageDBChild::StorageDBChild(LocalStorageManager* aManager,
146 const uint32_t aPrivateBrowsingId)
147 : mManager(aManager),
148 mPrivateBrowsingId(aPrivateBrowsingId),
149 mStatus(NS_OK),
150 mIPCOpen(false) {
151 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
152 MOZ_ASSERT(!NextGenLocalStorageEnabled());
155 StorageDBChild::~StorageDBChild() = default;
157 // static
158 StorageDBChild* StorageDBChild::Get(const uint32_t aPrivateBrowsingId) {
159 MOZ_ASSERT(NS_IsMainThread());
160 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
161 MOZ_ASSERT(!NextGenLocalStorageEnabled());
163 return sStorageChild[aPrivateBrowsingId];
166 // static
167 StorageDBChild* StorageDBChild::GetOrCreate(const uint32_t aPrivateBrowsingId) {
168 MOZ_ASSERT(NS_IsMainThread());
169 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
170 MOZ_ASSERT(!NextGenLocalStorageEnabled());
172 StorageDBChild*& storageChild = sStorageChild[aPrivateBrowsingId];
173 if (storageChild || sStorageChildDown[aPrivateBrowsingId]) {
174 // When sStorageChildDown is at true, sStorageChild is null.
175 // Checking sStorageChildDown flag here prevents reinitialization of
176 // the storage child after shutdown.
177 return storageChild;
180 // Use LocalStorageManager::Ensure in case we're called from
181 // DOMSessionStorageManager's initializer and we haven't yet initialized the
182 // local storage manager.
183 RefPtr<StorageDBChild> newStorageChild =
184 new StorageDBChild(LocalStorageManager::Ensure(), aPrivateBrowsingId);
186 nsresult rv = newStorageChild->Init();
187 if (NS_WARN_IF(NS_FAILED(rv))) {
188 return nullptr;
191 newStorageChild.forget(&storageChild);
193 return storageChild;
196 nsTHashSet<nsCString>& StorageDBChild::OriginsHavingData() {
197 if (!mOriginsHavingData) {
198 mOriginsHavingData = MakeUnique<nsTHashSet<nsCString>>();
201 return *mOriginsHavingData;
204 nsresult StorageDBChild::Init() {
205 MOZ_ASSERT(NS_IsMainThread());
207 ::mozilla::ipc::PBackgroundChild* actor =
208 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
209 if (NS_WARN_IF(!actor)) {
210 return NS_ERROR_FAILURE;
213 nsString profilePath;
214 if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) {
215 nsresult rv = StorageDBThread::GetProfilePath(profilePath);
216 if (NS_WARN_IF(NS_FAILED(rv))) {
217 return rv;
221 AddIPDLReference();
223 actor->SendPBackgroundStorageConstructor(this, profilePath,
224 mPrivateBrowsingId);
226 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
227 MOZ_ASSERT(observerService);
229 nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mPrivateBrowsingId);
231 MOZ_ALWAYS_SUCCEEDS(
232 observerService->AddObserver(observer, "xpcom-shutdown", false));
234 return NS_OK;
237 nsresult StorageDBChild::Shutdown() {
238 // There is nothing to do here, IPC will release automatically and
239 // the actual thread running on the parent process will also stop
240 // automatically in profile-before-change topic observer.
241 return NS_OK;
244 void StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache,
245 bool aPriority) {
246 if (mIPCOpen) {
247 // Adding ref to cache for the time of preload. This ensures a reference to
248 // to the cache and that all keys will load into this cache object.
249 mLoadingCaches.Insert(aCache);
250 SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
251 aPriority);
252 } else {
253 // No IPC, no love. But the LoadDone call is expected.
254 aCache->LoadDone(NS_ERROR_UNEXPECTED);
258 void StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage) {
259 if (mIPCOpen) {
260 SendAsyncGetUsage(aUsage->OriginScope());
264 void StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache,
265 bool aForceSync) {
266 if (NS_FAILED(mStatus)) {
267 aCache->LoadDone(mStatus);
268 return;
271 if (!mIPCOpen) {
272 aCache->LoadDone(NS_ERROR_UNEXPECTED);
273 return;
276 // There is no way to put the child process to a wait state to receive all
277 // incoming async responses from the parent, hence we have to do a sync
278 // preload instead. We are smart though, we only demand keys that are left to
279 // load in case the async preload has already loaded some keys.
280 nsTArray<nsString> keys, values;
281 nsresult rv;
282 SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
283 aCache->LoadedCount(), &keys, &values, &rv);
285 for (uint32_t i = 0; i < keys.Length(); ++i) {
286 aCache->LoadItem(keys[i], values[i]);
289 aCache->LoadDone(rv);
292 nsresult StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache,
293 const nsAString& aKey,
294 const nsAString& aValue) {
295 if (NS_FAILED(mStatus) || !mIPCOpen) {
296 return mStatus;
299 SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
300 nsString(aKey), nsString(aValue));
301 OriginsHavingData().Insert(aCache->Origin());
302 return NS_OK;
305 nsresult StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache,
306 const nsAString& aKey,
307 const nsAString& aValue) {
308 if (NS_FAILED(mStatus) || !mIPCOpen) {
309 return mStatus;
312 SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
313 nsString(aKey), nsString(aValue));
314 OriginsHavingData().Insert(aCache->Origin());
315 return NS_OK;
318 nsresult StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache,
319 const nsAString& aKey) {
320 if (NS_FAILED(mStatus) || !mIPCOpen) {
321 return mStatus;
324 SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
325 nsString(aKey));
326 return NS_OK;
329 nsresult StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache) {
330 if (NS_FAILED(mStatus) || !mIPCOpen) {
331 return mStatus;
334 SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
335 OriginsHavingData().Remove(aCache->Origin());
336 return NS_OK;
339 bool StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin) {
340 // Return true if we didn't receive the origins list yet.
341 // I tend to rather preserve a bit of early-after-start performance
342 // than a bit of memory here.
343 return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
346 mozilla::ipc::IPCResult StorageDBChild::RecvObserve(
347 const nsCString& aTopic, const nsString& aOriginAttributesPattern,
348 const nsCString& aOriginScope) {
349 MOZ_ASSERT(!XRE_IsParentProcess());
351 StorageObserver* obs = StorageObserver::Self();
352 if (obs) {
353 obs->Notify(aTopic.get(), aOriginAttributesPattern, aOriginScope);
356 return IPC_OK();
359 mozilla::ipc::IPCResult StorageDBChild::RecvOriginsHavingData(
360 nsTArray<nsCString>&& aOrigins) {
361 // Force population of mOriginsHavingData even if there are no origins so that
362 // ShouldPreloadOrigin does not generate false positives for all origins.
363 if (!aOrigins.Length()) {
364 Unused << OriginsHavingData();
367 for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
368 OriginsHavingData().Insert(aOrigins[i]);
371 return IPC_OK();
374 mozilla::ipc::IPCResult StorageDBChild::RecvLoadItem(
375 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
376 const nsString& aKey, const nsString& aValue) {
377 LocalStorageCache* aCache =
378 mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
379 if (aCache) {
380 aCache->LoadItem(aKey, aValue);
383 return IPC_OK();
386 mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone(
387 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
388 const nsresult& aRv) {
389 LocalStorageCache* aCache =
390 mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
391 if (aCache) {
392 aCache->LoadDone(aRv);
394 // Just drop reference to this cache now since the load is done.
395 mLoadingCaches.Remove(static_cast<LocalStorageCacheBridge*>(aCache));
398 return IPC_OK();
401 mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage(
402 const nsCString& aOriginNoSuffix, const int64_t& aUsage) {
403 RefPtr<StorageUsageBridge> scopeUsage =
404 mManager->GetOriginUsage(aOriginNoSuffix, mPrivateBrowsingId);
405 scopeUsage->LoadUsage(aUsage);
406 return IPC_OK();
409 mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) {
410 mStatus = aRv;
411 return IPC_OK();
414 NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
416 NS_IMETHODIMP
417 StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject,
418 const char* aTopic,
419 const char16_t* aData) {
420 MOZ_ASSERT(NS_IsMainThread());
421 MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
423 nsCOMPtr<nsIObserverService> observerService =
424 mozilla::services::GetObserverService();
425 if (NS_WARN_IF(!observerService)) {
426 return NS_ERROR_FAILURE;
429 Unused << observerService->RemoveObserver(this, "xpcom-shutdown");
431 StorageDBChild*& storageChild = sStorageChild[mPrivateBrowsingId];
432 if (storageChild) {
433 sStorageChildDown[mPrivateBrowsingId] = true;
435 MOZ_ALWAYS_TRUE(storageChild->PBackgroundStorageChild::SendDeleteMe());
437 NS_RELEASE(storageChild);
438 storageChild = nullptr;
441 return NS_OK;
444 SessionStorageObserverChild::SessionStorageObserverChild(
445 SessionStorageObserver* aObserver)
446 : mObserver(aObserver) {
447 AssertIsOnOwningThread();
448 MOZ_ASSERT(NextGenLocalStorageEnabled());
449 MOZ_ASSERT(aObserver);
450 aObserver->AssertIsOnOwningThread();
452 MOZ_COUNT_CTOR(SessionStorageObserverChild);
455 SessionStorageObserverChild::~SessionStorageObserverChild() {
456 AssertIsOnOwningThread();
458 MOZ_COUNT_DTOR(SessionStorageObserverChild);
461 void SessionStorageObserverChild::SendDeleteMeInternal() {
462 AssertIsOnOwningThread();
464 if (mObserver) {
465 mObserver->ClearActor();
466 mObserver = nullptr;
468 // Don't check result here since IPC may no longer be available due to
469 // SessionStorageManager (which holds a strong reference to
470 // SessionStorageObserver) being destroyed very late in the game.
471 PSessionStorageObserverChild::SendDeleteMe();
475 void SessionStorageObserverChild::ActorDestroy(ActorDestroyReason aWhy) {
476 AssertIsOnOwningThread();
478 if (mObserver) {
479 mObserver->ClearActor();
480 mObserver = nullptr;
484 mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
485 const nsCString& aTopic, const nsString& aOriginAttributesPattern,
486 const nsCString& aOriginScope) {
487 AssertIsOnOwningThread();
489 StorageObserver* obs = StorageObserver::Self();
490 if (obs) {
491 obs->Notify(aTopic.get(), aOriginAttributesPattern, aOriginScope);
494 return IPC_OK();
497 SessionStorageCacheChild::SessionStorageCacheChild(SessionStorageCache* aCache)
498 : mCache(aCache) {
499 AssertIsOnOwningThread();
500 MOZ_ASSERT(mCache);
502 MOZ_COUNT_CTOR(SessionStorageCacheChild);
505 SessionStorageCacheChild::~SessionStorageCacheChild() {
506 AssertIsOnOwningThread();
508 MOZ_COUNT_DTOR(SessionStorageCacheChild);
511 void SessionStorageCacheChild::SendDeleteMeInternal() {
512 AssertIsOnOwningThread();
514 if (mCache) {
515 mCache->ClearActor();
516 mCache = nullptr;
518 MOZ_ALWAYS_TRUE(PBackgroundSessionStorageCacheChild::SendDeleteMe());
522 void SessionStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
523 AssertIsOnOwningThread();
525 if (mCache) {
526 mCache->ClearActor();
527 mCache = nullptr;
531 SessionStorageManagerChild::SessionStorageManagerChild(
532 SessionStorageManager* aSSManager)
533 : mSSManager(aSSManager) {
534 AssertIsOnOwningThread();
535 MOZ_ASSERT(mSSManager);
537 MOZ_COUNT_CTOR(SessionStorageManagerChild);
540 SessionStorageManagerChild::~SessionStorageManagerChild() {
541 AssertIsOnOwningThread();
543 MOZ_COUNT_DTOR(SessionStorageManagerChild);
546 void SessionStorageManagerChild::SendDeleteMeInternal() {
547 AssertIsOnOwningThread();
549 if (mSSManager) {
550 mSSManager->ClearActor();
551 mSSManager = nullptr;
553 MOZ_ALWAYS_TRUE(PBackgroundSessionStorageManagerChild::SendDeleteMe());
557 void SessionStorageManagerChild::ActorDestroy(ActorDestroyReason aWhy) {
558 AssertIsOnOwningThread();
560 if (mSSManager) {
561 mSSManager->ClearActor();
562 mSSManager = nullptr;
566 mozilla::ipc::IPCResult SessionStorageManagerChild::RecvClearStoragesForOrigin(
567 const nsCString& aOriginAttrs, const nsCString& aOriginKey) {
568 AssertIsOnOwningThread();
570 if (mSSManager) {
571 mSSManager->ClearStoragesForOrigin(aOriginAttrs, aOriginKey);
574 return IPC_OK();
577 LocalStorageCacheParent::LocalStorageCacheParent(
578 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
579 const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
580 : mPrincipalInfo(aPrincipalInfo),
581 mOriginKey(aOriginKey),
582 mPrivateBrowsingId(aPrivateBrowsingId),
583 mActorDestroyed(false) {
584 ::mozilla::ipc::AssertIsOnBackgroundThread();
587 LocalStorageCacheParent::~LocalStorageCacheParent() {
588 MOZ_ASSERT(mActorDestroyed);
591 void LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
592 ::mozilla::ipc::AssertIsOnBackgroundThread();
593 MOZ_ASSERT(!mActorDestroyed);
595 mActorDestroyed = true;
597 MOZ_ASSERT(gLocalStorageCacheParents);
599 nsTArray<LocalStorageCacheParent*>* array;
600 gLocalStorageCacheParents->Get(mOriginKey, &array);
601 MOZ_ASSERT(array);
603 array->RemoveElement(this);
605 if (array->IsEmpty()) {
606 gLocalStorageCacheParents->Remove(mOriginKey);
609 if (!gLocalStorageCacheParents->Count()) {
610 gLocalStorageCacheParents = nullptr;
614 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvDeleteMe() {
615 ::mozilla::ipc::AssertIsOnBackgroundThread();
616 MOZ_ASSERT(!mActorDestroyed);
618 IProtocol* mgr = Manager();
619 if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) {
620 return IPC_FAIL_NO_REASON(mgr);
622 return IPC_OK();
625 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvNotify(
626 const nsString& aDocumentURI, const nsString& aKey,
627 const nsString& aOldValue, const nsString& aNewValue) {
628 ::mozilla::ipc::AssertIsOnBackgroundThread();
629 MOZ_ASSERT(gLocalStorageCacheParents);
631 nsTArray<LocalStorageCacheParent*>* array;
632 gLocalStorageCacheParents->Get(mOriginKey, &array);
633 MOZ_ASSERT(array);
635 for (LocalStorageCacheParent* localStorageCacheParent : *array) {
636 if (localStorageCacheParent != this) {
637 // When bug 1443925 is fixed, we can compare mPrincipalInfo against
638 // localStorageCacheParent->PrincipalInfo() here on the background thread
639 // instead of posting it to the main thread. The advantage of doing so is
640 // that it would save an IPC message in the case where the principals do
641 // not match.
642 Unused << localStorageCacheParent->SendObserve(
643 mPrincipalInfo, localStorageCacheParent->PrincipalInfo(),
644 mPrivateBrowsingId, aDocumentURI, aKey, aOldValue, aNewValue);
648 return IPC_OK();
651 // ----------------------------------------------------------------------------
652 // Parent
653 // ----------------------------------------------------------------------------
655 class StorageDBParent::ObserverSink : public StorageObserverSink {
656 nsCOMPtr<nsIEventTarget> mOwningEventTarget;
658 // Only touched on the PBackground thread.
659 StorageDBParent* MOZ_NON_OWNING_REF mActor;
661 public:
662 explicit ObserverSink(StorageDBParent* aActor)
663 : mOwningEventTarget(GetCurrentEventTarget()), mActor(aActor) {
664 ::mozilla::ipc::AssertIsOnBackgroundThread();
665 MOZ_ASSERT(aActor);
668 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink);
670 void Start();
672 void Stop();
674 private:
675 ~ObserverSink() = default;
677 void AddSink();
679 void RemoveSink();
681 void Notify(const nsCString& aTopic, const nsString& aOriginAttributesPattern,
682 const nsCString& aOriginScope);
684 // StorageObserverSink
685 nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern,
686 const nsACString& aOriginScope) override;
689 NS_IMPL_ADDREF(StorageDBParent)
690 NS_IMPL_RELEASE(StorageDBParent)
692 void StorageDBParent::AddIPDLReference() {
693 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
694 mIPCOpen = true;
695 AddRef();
698 void StorageDBParent::ReleaseIPDLReference() {
699 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
700 mIPCOpen = false;
701 Release();
704 namespace {} // namespace
706 StorageDBParent::StorageDBParent(const nsString& aProfilePath,
707 const uint32_t aPrivateBrowsingId)
708 : mProfilePath(aProfilePath),
709 mPrivateBrowsingId(aPrivateBrowsingId),
710 mIPCOpen(false) {
711 ::mozilla::ipc::AssertIsOnBackgroundThread();
713 // We are always open by IPC only
714 AddIPDLReference();
717 StorageDBParent::~StorageDBParent() {
718 ::mozilla::ipc::AssertIsOnBackgroundThread();
720 if (mObserverSink) {
721 mObserverSink->Stop();
722 mObserverSink = nullptr;
726 void StorageDBParent::Init() {
727 ::mozilla::ipc::AssertIsOnBackgroundThread();
729 PBackgroundParent* actor = Manager();
730 MOZ_ASSERT(actor);
732 if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) {
733 mObserverSink = new ObserverSink(this);
734 mObserverSink->Start();
737 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
738 if (storageThread) {
739 nsTArray<nsCString> scopes;
740 storageThread->GetOriginsHavingData(&scopes);
741 mozilla::Unused << SendOriginsHavingData(scopes);
745 StorageDBParent::CacheParentBridge* StorageDBParent::NewCache(
746 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
747 return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
750 void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) {
751 // Implement me! Bug 1005169
754 mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
755 ::mozilla::ipc::AssertIsOnBackgroundThread();
757 IProtocol* mgr = Manager();
758 if (!PBackgroundStorageParent::Send__delete__(this)) {
759 return IPC_FAIL_NO_REASON(mgr);
761 return IPC_OK();
764 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
765 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
766 const bool& aPriority) {
767 StorageDBThread* storageThread =
768 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
769 if (!storageThread) {
770 return IPC_FAIL_NO_REASON(this);
773 storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
774 aPriority);
776 return IPC_OK();
779 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage(
780 const nsCString& aOriginNoSuffix) {
781 StorageDBThread* storageThread =
782 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
783 if (!storageThread) {
784 return IPC_FAIL_NO_REASON(this);
787 // The object releases it self in LoadUsage method
788 RefPtr<UsageParentBridge> usage =
789 new UsageParentBridge(this, aOriginNoSuffix);
791 storageThread->AsyncGetUsage(usage);
793 return IPC_OK();
796 namespace {
798 // We need another implementation of LocalStorageCacheBridge to do
799 // synchronous IPC preload. This class just receives Load* notifications
800 // and fills the returning arguments of RecvPreload with the database
801 // values for us.
802 class SyncLoadCacheHelper : public LocalStorageCacheBridge {
803 public:
804 SyncLoadCacheHelper(const nsCString& aOriginSuffix,
805 const nsCString& aOriginNoSuffix,
806 uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
807 nsTArray<nsString>* aValues, nsresult* rv)
808 : mMonitor("DOM Storage SyncLoad IPC"),
809 mSuffix(aOriginSuffix),
810 mOrigin(aOriginNoSuffix),
811 mKeys(aKeys),
812 mValues(aValues),
813 mRv(rv),
814 mLoaded(false),
815 mLoadedCount(aAlreadyLoadedCount) {
816 // Precaution
817 *mRv = NS_ERROR_UNEXPECTED;
820 virtual const nsCString Origin() const override {
821 return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
823 virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
824 virtual const nsCString& OriginSuffix() const override { return mSuffix; }
825 virtual bool Loaded() override { return mLoaded; }
826 virtual uint32_t LoadedCount() override { return mLoadedCount; }
827 virtual bool LoadItem(const nsAString& aKey,
828 const nsString& aValue) override {
829 // Called on the aCache background thread
830 MOZ_ASSERT(!mLoaded);
831 if (mLoaded) {
832 return false;
835 ++mLoadedCount;
836 mKeys->AppendElement(aKey);
837 mValues->AppendElement(aValue);
838 return true;
841 virtual void LoadDone(nsresult aRv) override {
842 // Called on the aCache background thread
843 MonitorAutoLock monitor(mMonitor);
844 MOZ_ASSERT(!mLoaded && mRv);
845 mLoaded = true;
846 if (mRv) {
847 *mRv = aRv;
848 mRv = nullptr;
850 monitor.Notify();
853 virtual void LoadWait() override {
854 // Called on the main thread, exits after LoadDone() call
855 MonitorAutoLock monitor(mMonitor);
856 while (!mLoaded) {
857 monitor.Wait();
861 private:
862 Monitor mMonitor MOZ_UNANNOTATED;
863 nsCString mSuffix, mOrigin;
864 nsTArray<nsString>* mKeys;
865 nsTArray<nsString>* mValues;
866 nsresult* mRv;
867 bool mLoaded;
868 uint32_t mLoadedCount;
871 } // namespace
873 mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
874 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
875 const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
876 nsTArray<nsString>* aValues, nsresult* aRv) {
877 StorageDBThread* storageThread =
878 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
879 if (!storageThread) {
880 return IPC_FAIL_NO_REASON(this);
883 RefPtr<SyncLoadCacheHelper> cache(
884 new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix,
885 aAlreadyLoadedCount, aKeys, aValues, aRv));
887 storageThread->SyncPreload(cache, true);
889 return IPC_OK();
892 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
893 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
894 const nsString& aKey, const nsString& aValue) {
895 StorageDBThread* storageThread =
896 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
897 if (!storageThread) {
898 return IPC_FAIL_NO_REASON(this);
901 nsresult rv = storageThread->AsyncAddItem(
902 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
903 if (NS_FAILED(rv) && mIPCOpen) {
904 mozilla::Unused << SendError(rv);
907 return IPC_OK();
910 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
911 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
912 const nsString& aKey, const nsString& aValue) {
913 StorageDBThread* storageThread =
914 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
915 if (!storageThread) {
916 return IPC_FAIL_NO_REASON(this);
919 nsresult rv = storageThread->AsyncUpdateItem(
920 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
921 if (NS_FAILED(rv) && mIPCOpen) {
922 mozilla::Unused << SendError(rv);
925 return IPC_OK();
928 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
929 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
930 const nsString& aKey) {
931 StorageDBThread* storageThread =
932 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
933 if (!storageThread) {
934 return IPC_FAIL_NO_REASON(this);
937 nsresult rv = storageThread->AsyncRemoveItem(
938 NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
939 if (NS_FAILED(rv) && mIPCOpen) {
940 mozilla::Unused << SendError(rv);
943 return IPC_OK();
946 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
947 const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix) {
948 StorageDBThread* storageThread =
949 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
950 if (!storageThread) {
951 return IPC_FAIL_NO_REASON(this);
954 nsresult rv =
955 storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
956 if (NS_FAILED(rv) && mIPCOpen) {
957 mozilla::Unused << SendError(rv);
960 return IPC_OK();
963 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
964 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
965 if (!storageThread) {
966 return IPC_FAIL_NO_REASON(this);
969 storageThread->AsyncFlush();
971 return IPC_OK();
974 mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
975 StorageDBThread* storageThread =
976 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
977 if (!storageThread) {
978 return IPC_FAIL_NO_REASON(this);
981 return IPC_OK();
984 mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
985 StorageDBThread* storageThread =
986 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
987 if (!storageThread) {
988 return IPC_FAIL_NO_REASON(this);
991 storageThread->AsyncClearAll();
993 return IPC_OK();
996 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
997 const nsCString& aOriginNoSuffix) {
998 StorageDBThread* storageThread =
999 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
1000 if (!storageThread) {
1001 return IPC_FAIL_NO_REASON(this);
1004 storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
1006 return IPC_OK();
1009 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes(
1010 const OriginAttributesPattern& aPattern) {
1011 StorageDBThread* storageThread =
1012 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
1013 if (!storageThread) {
1014 return IPC_FAIL_NO_REASON(this);
1017 storageThread->AsyncClearMatchingOriginAttributes(aPattern);
1019 return IPC_OK();
1022 void StorageDBParent::Observe(const nsCString& aTopic,
1023 const nsString& aOriginAttributesPattern,
1024 const nsCString& aOriginScope) {
1025 if (mIPCOpen) {
1026 mozilla::Unused << SendObserve(aTopic, aOriginAttributesPattern,
1027 aOriginScope);
1031 namespace {
1033 // Results must be sent back on the main thread
1034 class LoadRunnable : public Runnable {
1035 public:
1036 enum TaskType { loadItem, loadDone };
1038 LoadRunnable(StorageDBParent* aParent, TaskType aType,
1039 const nsACString& aOriginSuffix,
1040 const nsACString& aOriginNoSuffix,
1041 const nsAString& aKey = u""_ns, const nsAString& aValue = u""_ns)
1042 : Runnable("dom::LoadRunnable"),
1043 mParent(aParent),
1044 mType(aType),
1045 mSuffix(aOriginSuffix),
1046 mOrigin(aOriginNoSuffix),
1047 mKey(aKey),
1048 mValue(aValue),
1049 mRv(NS_ERROR_NOT_INITIALIZED) {}
1051 LoadRunnable(StorageDBParent* aParent, TaskType aType,
1052 const nsACString& aOriginSuffix,
1053 const nsACString& aOriginNoSuffix, nsresult aRv)
1054 : Runnable("dom::LoadRunnable"),
1055 mParent(aParent),
1056 mType(aType),
1057 mSuffix(aOriginSuffix),
1058 mOrigin(aOriginNoSuffix),
1059 mRv(aRv) {}
1061 private:
1062 RefPtr<StorageDBParent> mParent;
1063 TaskType mType;
1064 nsCString mSuffix, mOrigin;
1065 nsString mKey;
1066 nsString mValue;
1067 nsresult mRv;
1069 NS_IMETHOD Run() override {
1070 if (!mParent->IPCOpen()) {
1071 return NS_OK;
1074 switch (mType) {
1075 case loadItem:
1076 mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey,
1077 mValue);
1078 break;
1079 case loadDone:
1080 mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
1081 break;
1084 mParent = nullptr;
1086 return NS_OK;
1090 } // namespace
1092 // StorageDBParent::CacheParentBridge
1094 const nsCString StorageDBParent::CacheParentBridge::Origin() const {
1095 return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
1098 bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
1099 const nsString& aValue) {
1100 if (mLoaded) {
1101 return false;
1104 ++mLoadedCount;
1106 RefPtr<LoadRunnable> r =
1107 new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
1108 mOriginNoSuffix, aKey, aValue);
1110 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1112 return true;
1115 void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) {
1116 // Prevent send of duplicate LoadDone.
1117 if (mLoaded) {
1118 return;
1121 mLoaded = true;
1123 RefPtr<LoadRunnable> r = new LoadRunnable(
1124 mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
1126 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1129 void StorageDBParent::CacheParentBridge::LoadWait() {
1130 // Should never be called on this implementation
1131 MOZ_ASSERT(false);
1134 // XXX Fix me!
1135 // This should be just:
1136 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
1137 // But due to different strings used for refcount logging and different return
1138 // types, this is done manually for now.
1139 NS_IMETHODIMP_(void)
1140 StorageDBParent::CacheParentBridge::Release(void) {
1141 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1142 nsrefcnt count = --mRefCnt;
1143 NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
1144 if (0 == count) {
1145 mRefCnt = 1; /* stabilize */
1146 /* enable this to find non-threadsafe destructors: */
1147 /* NS_ASSERT_OWNINGTHREAD(_class); */
1148 Destroy();
1152 void StorageDBParent::CacheParentBridge::Destroy() {
1153 if (mOwningEventTarget->IsOnCurrentThread()) {
1154 delete this;
1155 return;
1158 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1159 "CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy);
1161 MOZ_ALWAYS_SUCCEEDS(
1162 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1165 // StorageDBParent::UsageParentBridge
1167 namespace {
1169 class UsageRunnable : public Runnable {
1170 public:
1171 UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope,
1172 const int64_t& aUsage)
1173 : Runnable("dom::UsageRunnable"),
1174 mParent(aParent),
1175 mOriginScope(aOriginScope),
1176 mUsage(aUsage) {}
1178 private:
1179 NS_IMETHOD Run() override {
1180 if (!mParent->IPCOpen()) {
1181 return NS_OK;
1184 mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
1186 mParent = nullptr;
1188 return NS_OK;
1191 RefPtr<StorageDBParent> mParent;
1192 nsCString mOriginScope;
1193 int64_t mUsage;
1196 } // namespace
1198 void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) {
1199 RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
1201 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1204 // XXX Fix me!
1205 // This should be just:
1206 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
1207 // But due to different strings used for refcount logging, this is done manually
1208 // for now.
1209 NS_IMETHODIMP_(MozExternalRefCountType)
1210 StorageDBParent::UsageParentBridge::Release(void) {
1211 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1212 nsrefcnt count = --mRefCnt;
1213 NS_LOG_RELEASE(this, count, "StorageUsageBridge");
1214 if (count == 0) {
1215 Destroy();
1216 return 0;
1218 return count;
1221 void StorageDBParent::UsageParentBridge::Destroy() {
1222 if (mOwningEventTarget->IsOnCurrentThread()) {
1223 delete this;
1224 return;
1227 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1228 "UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy);
1230 MOZ_ALWAYS_SUCCEEDS(
1231 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1234 void StorageDBParent::ObserverSink::Start() {
1235 ::mozilla::ipc::AssertIsOnBackgroundThread();
1237 RefPtr<Runnable> runnable =
1238 NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this,
1239 &StorageDBParent::ObserverSink::AddSink);
1241 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1244 void StorageDBParent::ObserverSink::Stop() {
1245 ::mozilla::ipc::AssertIsOnBackgroundThread();
1247 mActor = nullptr;
1249 RefPtr<Runnable> runnable =
1250 NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this,
1251 &StorageDBParent::ObserverSink::RemoveSink);
1253 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1256 void StorageDBParent::ObserverSink::AddSink() {
1257 MOZ_ASSERT(NS_IsMainThread());
1259 StorageObserver* observer = StorageObserver::Self();
1260 if (observer) {
1261 observer->AddSink(this);
1265 void StorageDBParent::ObserverSink::RemoveSink() {
1266 MOZ_ASSERT(NS_IsMainThread());
1268 StorageObserver* observer = StorageObserver::Self();
1269 if (observer) {
1270 observer->RemoveSink(this);
1274 void StorageDBParent::ObserverSink::Notify(
1275 const nsCString& aTopic, const nsString& aOriginAttributesPattern,
1276 const nsCString& aOriginScope) {
1277 ::mozilla::ipc::AssertIsOnBackgroundThread();
1279 if (mActor) {
1280 mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
1284 nsresult StorageDBParent::ObserverSink::Observe(
1285 const char* aTopic, const nsAString& aOriginAttributesPattern,
1286 const nsACString& aOriginScope) {
1287 MOZ_ASSERT(NS_IsMainThread());
1289 RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>(
1290 "StorageDBParent::ObserverSink::Observe2", this,
1291 &StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern,
1292 aOriginScope);
1294 MOZ_ALWAYS_SUCCEEDS(
1295 mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1297 return NS_OK;
1300 SessionStorageObserverParent::SessionStorageObserverParent()
1301 : mActorDestroyed(false) {
1302 MOZ_ASSERT(NS_IsMainThread());
1304 StorageObserver* observer = StorageObserver::Self();
1305 if (observer) {
1306 observer->AddSink(this);
1310 SessionStorageObserverParent::~SessionStorageObserverParent() {
1311 MOZ_ASSERT(mActorDestroyed);
1313 StorageObserver* observer = StorageObserver::Self();
1314 if (observer) {
1315 observer->RemoveSink(this);
1319 void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) {
1320 MOZ_ASSERT(NS_IsMainThread());
1321 MOZ_ASSERT(!mActorDestroyed);
1323 mActorDestroyed = true;
1326 mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() {
1327 MOZ_ASSERT(NS_IsMainThread());
1328 MOZ_ASSERT(!mActorDestroyed);
1330 IProtocol* mgr = Manager();
1331 if (!PSessionStorageObserverParent::Send__delete__(this)) {
1332 return IPC_FAIL_NO_REASON(mgr);
1334 return IPC_OK();
1337 nsresult SessionStorageObserverParent::Observe(
1338 const char* aTopic, const nsAString& aOriginAttributesPattern,
1339 const nsACString& aOriginScope) {
1340 MOZ_ASSERT(NS_IsMainThread());
1342 if (!mActorDestroyed) {
1343 mozilla::Unused << SendObserve(nsCString(aTopic),
1344 nsString(aOriginAttributesPattern),
1345 nsCString(aOriginScope));
1347 return NS_OK;
1350 SessionStorageCacheParent::SessionStorageCacheParent(
1351 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1352 const nsCString& aOriginKey, SessionStorageManagerParent* aActor)
1353 : mPrincipalInfo(aPrincipalInfo),
1354 mOriginKey(aOriginKey),
1355 mManagerActor(aActor) {
1356 ::mozilla::ipc::AssertIsOnBackgroundThread();
1357 MOZ_ASSERT(mManagerActor);
1360 SessionStorageCacheParent::~SessionStorageCacheParent() = default;
1362 void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
1363 ::mozilla::ipc::AssertIsOnBackgroundThread();
1365 mManagerActor = nullptr;
1368 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad(
1369 nsTArray<SSSetItemInfo>* aData) {
1370 ::mozilla::ipc::AssertIsOnBackgroundThread();
1371 MOZ_ASSERT(mManagerActor);
1373 mLoadReceived.Flip();
1375 RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
1376 MOZ_ASSERT(manager);
1378 OriginAttributes attrs;
1379 MOZ_ALWAYS_TRUE(
1380 StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs));
1382 nsAutoCString originAttrs;
1383 attrs.CreateSuffix(originAttrs);
1385 manager->CopyDataToContentProcess(originAttrs, mOriginKey, *aData);
1387 return IPC_OK();
1390 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint(
1391 nsTArray<SSWriteInfo>&& aWriteInfos) {
1392 ::mozilla::ipc::AssertIsOnBackgroundThread();
1393 MOZ_ASSERT(mManagerActor);
1395 RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
1396 MOZ_ASSERT(manager);
1398 OriginAttributes attrs;
1399 StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs);
1401 nsAutoCString originAttrs;
1402 attrs.CreateSuffix(originAttrs);
1404 manager->UpdateData(originAttrs, mOriginKey, aWriteInfos);
1406 return IPC_OK();
1409 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() {
1410 ::mozilla::ipc::AssertIsOnBackgroundThread();
1411 MOZ_ASSERT(mManagerActor);
1413 mManagerActor = nullptr;
1415 IProtocol* mgr = Manager();
1416 if (!PBackgroundSessionStorageCacheParent::Send__delete__(this)) {
1417 return IPC_FAIL(
1418 mgr, "Failed to delete PBackgroundSessionStorageCacheParent actor");
1420 return IPC_OK();
1423 SessionStorageManagerParent::SessionStorageManagerParent(uint64_t aTopContextId)
1424 : mBackgroundManager(
1425 BackgroundSessionStorageManager::GetOrCreate(aTopContextId)) {
1426 ::mozilla::ipc::AssertIsOnBackgroundThread();
1427 MOZ_ASSERT(mBackgroundManager);
1428 mBackgroundManager->AddParticipatingActor(this);
1431 SessionStorageManagerParent::~SessionStorageManagerParent() = default;
1433 void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
1434 ::mozilla::ipc::AssertIsOnBackgroundThread();
1436 if (mBackgroundManager) {
1437 mBackgroundManager->RemoveParticipatingActor(this);
1440 mBackgroundManager = nullptr;
1443 already_AddRefed<PBackgroundSessionStorageCacheParent>
1444 SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent(
1445 const PrincipalInfo& aPrincipalInfo, const nsCString& aOriginKey) {
1446 return MakeAndAddRef<SessionStorageCacheParent>(aPrincipalInfo, aOriginKey,
1447 this);
1450 BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager()
1451 const {
1452 return mBackgroundManager;
1455 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvClearStorages(
1456 const OriginAttributesPattern& aPattern, const nsCString& aOriginScope) {
1457 ::mozilla::ipc::AssertIsOnBackgroundThread();
1458 mBackgroundManager->ClearStorages(aPattern, aOriginScope);
1459 return IPC_OK();
1462 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() {
1463 ::mozilla::ipc::AssertIsOnBackgroundThread();
1464 MOZ_ASSERT(mBackgroundManager);
1466 mBackgroundManager->RemoveParticipatingActor(this);
1468 mBackgroundManager = nullptr;
1470 IProtocol* mgr = Manager();
1471 if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) {
1472 return IPC_FAIL(
1473 mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor");
1475 return IPC_OK();
1478 /*******************************************************************************
1479 * Exported functions
1480 ******************************************************************************/
1482 PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
1483 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1484 const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
1485 ::mozilla::ipc::AssertIsOnBackgroundThread();
1487 RefPtr<LocalStorageCacheParent> actor = new LocalStorageCacheParent(
1488 aPrincipalInfo, aOriginKey, aPrivateBrowsingId);
1490 // Transfer ownership to IPDL.
1491 return actor.forget().take();
1494 mozilla::ipc::IPCResult RecvPBackgroundLocalStorageCacheConstructor(
1495 mozilla::ipc::PBackgroundParent* aBackgroundActor,
1496 PBackgroundLocalStorageCacheParent* aActor,
1497 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1498 const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
1499 ::mozilla::ipc::AssertIsOnBackgroundThread();
1500 MOZ_ASSERT(aActor);
1502 auto* actor = static_cast<LocalStorageCacheParent*>(aActor);
1504 if (!gLocalStorageCacheParents) {
1505 gLocalStorageCacheParents = new LocalStorageCacheParentHashtable();
1508 gLocalStorageCacheParents->GetOrInsertNew(aOriginKey)->AppendElement(actor);
1510 // We are currently trusting the content process not to lie to us. It is
1511 // future work to consult the ClientManager to determine whether this is a
1512 // legitimate origin for the content process.
1514 return IPC_OK();
1517 bool DeallocPBackgroundLocalStorageCacheParent(
1518 PBackgroundLocalStorageCacheParent* aActor) {
1519 ::mozilla::ipc::AssertIsOnBackgroundThread();
1520 MOZ_ASSERT(aActor);
1522 // Transfer ownership back from IPDL.
1523 RefPtr<LocalStorageCacheParent> actor =
1524 dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor));
1526 return true;
1529 PBackgroundStorageParent* AllocPBackgroundStorageParent(
1530 const nsString& aProfilePath, const uint32_t& aPrivateBrowsingId) {
1531 ::mozilla::ipc::AssertIsOnBackgroundThread();
1533 if (NS_WARN_IF(NextGenLocalStorageEnabled()) ||
1534 NS_WARN_IF(aPrivateBrowsingId >= kPrivateBrowsingIdCount)) {
1535 return nullptr;
1538 return new StorageDBParent(aProfilePath, aPrivateBrowsingId);
1541 mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor(
1542 PBackgroundStorageParent* aActor, const nsString& aProfilePath,
1543 const uint32_t& aPrivateBrowsingId) {
1544 ::mozilla::ipc::AssertIsOnBackgroundThread();
1545 MOZ_ASSERT(aActor);
1546 MOZ_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
1547 MOZ_ASSERT(!NextGenLocalStorageEnabled());
1549 auto* actor = static_cast<StorageDBParent*>(aActor);
1550 actor->Init();
1551 return IPC_OK();
1554 bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) {
1555 ::mozilla::ipc::AssertIsOnBackgroundThread();
1556 MOZ_ASSERT(aActor);
1558 StorageDBParent* actor = static_cast<StorageDBParent*>(aActor);
1559 actor->ReleaseIPDLReference();
1560 return true;
1563 PSessionStorageObserverParent* AllocPSessionStorageObserverParent() {
1564 MOZ_ASSERT(NS_IsMainThread());
1566 RefPtr<SessionStorageObserverParent> actor =
1567 new SessionStorageObserverParent();
1569 // Transfer ownership to IPDL.
1570 return actor.forget().take();
1573 bool RecvPSessionStorageObserverConstructor(
1574 PSessionStorageObserverParent* aActor) {
1575 MOZ_ASSERT(NS_IsMainThread());
1576 MOZ_ASSERT(aActor);
1578 return true;
1581 bool DeallocPSessionStorageObserverParent(
1582 PSessionStorageObserverParent* aActor) {
1583 MOZ_ASSERT(NS_IsMainThread());
1584 MOZ_ASSERT(aActor);
1586 // Transfer ownership back from IPDL.
1587 RefPtr<SessionStorageObserverParent> actor =
1588 dont_AddRef(static_cast<SessionStorageObserverParent*>(aActor));
1590 return true;
1593 already_AddRefed<PBackgroundSessionStorageManagerParent>
1594 AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) {
1595 return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId);
1598 } // namespace mozilla::dom