Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / storage / StorageIPC.cpp
blob811575f471b348d34029b545e5d38e66c98808de
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 nsAString& aDocumentURI,
83 const nsAString& aKey, const nsAString& aOldValue,
84 const nsAString& 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 nsACString& aTopic, const nsAString& aOriginAttributesPattern,
348 const nsACString& aOriginScope) {
349 MOZ_ASSERT(!XRE_IsParentProcess());
351 if (StorageObserver* obs = StorageObserver::Self()) {
352 obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
353 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 nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
376 const nsAString& aKey, const nsAString& 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 nsACString& aOriginSuffix, const nsACString& 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 nsACString& 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 nsACString& aTopic, const nsAString& aOriginAttributesPattern,
486 const nsACString& aOriginScope) {
487 AssertIsOnOwningThread();
489 if (StorageObserver* obs = StorageObserver::Self()) {
490 obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
491 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 nsACString& aOriginAttrs, const nsACString& 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 nsAString& aDocumentURI, const nsAString& aKey,
627 const nsAString& aOldValue, const nsAString& 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(GetCurrentSerialEventTarget()), 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 nsACString& aTopic,
682 const nsAString& aOriginAttributesPattern,
683 const nsACString& aOriginScope);
685 // StorageObserverSink
686 nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern,
687 const nsACString& aOriginScope) override;
690 NS_IMPL_ADDREF(StorageDBParent)
691 NS_IMPL_RELEASE(StorageDBParent)
693 void StorageDBParent::AddIPDLReference() {
694 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
695 mIPCOpen = true;
696 AddRef();
699 void StorageDBParent::ReleaseIPDLReference() {
700 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
701 mIPCOpen = false;
702 Release();
705 namespace {} // namespace
707 StorageDBParent::StorageDBParent(const nsAString& aProfilePath,
708 const uint32_t aPrivateBrowsingId)
709 : mProfilePath(aProfilePath),
710 mPrivateBrowsingId(aPrivateBrowsingId),
711 mIPCOpen(false) {
712 ::mozilla::ipc::AssertIsOnBackgroundThread();
714 // We are always open by IPC only
715 AddIPDLReference();
718 StorageDBParent::~StorageDBParent() {
719 ::mozilla::ipc::AssertIsOnBackgroundThread();
721 if (mObserverSink) {
722 mObserverSink->Stop();
723 mObserverSink = nullptr;
727 void StorageDBParent::Init() {
728 ::mozilla::ipc::AssertIsOnBackgroundThread();
730 PBackgroundParent* actor = Manager();
731 MOZ_ASSERT(actor);
733 if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) {
734 mObserverSink = new ObserverSink(this);
735 mObserverSink->Start();
738 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
739 if (storageThread) {
740 nsTArray<nsCString> scopes;
741 storageThread->GetOriginsHavingData(&scopes);
742 mozilla::Unused << SendOriginsHavingData(scopes);
746 StorageDBParent::CacheParentBridge* StorageDBParent::NewCache(
747 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
748 return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
751 void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) {
752 // Implement me! Bug 1005169
755 mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
756 ::mozilla::ipc::AssertIsOnBackgroundThread();
758 IProtocol* mgr = Manager();
759 if (!PBackgroundStorageParent::Send__delete__(this)) {
760 return IPC_FAIL_NO_REASON(mgr);
762 return IPC_OK();
765 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
766 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
767 const bool& aPriority) {
768 StorageDBThread* storageThread =
769 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
770 if (!storageThread) {
771 return IPC_FAIL_NO_REASON(this);
774 storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
775 aPriority);
777 return IPC_OK();
780 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage(
781 const nsACString& aOriginNoSuffix) {
782 StorageDBThread* storageThread =
783 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
784 if (!storageThread) {
785 return IPC_FAIL_NO_REASON(this);
788 // The object releases it self in LoadUsage method
789 RefPtr<UsageParentBridge> usage =
790 new UsageParentBridge(this, aOriginNoSuffix);
792 storageThread->AsyncGetUsage(usage);
794 return IPC_OK();
797 namespace {
799 // We need another implementation of LocalStorageCacheBridge to do
800 // synchronous IPC preload. This class just receives Load* notifications
801 // and fills the returning arguments of RecvPreload with the database
802 // values for us.
803 class SyncLoadCacheHelper : public LocalStorageCacheBridge {
804 public:
805 SyncLoadCacheHelper(const nsACString& aOriginSuffix,
806 const nsACString& aOriginNoSuffix,
807 uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
808 nsTArray<nsString>* aValues, nsresult* rv)
809 : mMonitor("DOM Storage SyncLoad IPC"),
810 mSuffix(aOriginSuffix),
811 mOrigin(aOriginNoSuffix),
812 mKeys(aKeys),
813 mValues(aValues),
814 mRv(rv),
815 mLoaded(false),
816 mLoadedCount(aAlreadyLoadedCount) {
817 // Precaution
818 *mRv = NS_ERROR_UNEXPECTED;
821 virtual const nsCString Origin() const override {
822 return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
824 virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
825 virtual const nsCString& OriginSuffix() const override { return mSuffix; }
826 virtual bool Loaded() override { return mLoaded; }
827 virtual uint32_t LoadedCount() override { return mLoadedCount; }
828 virtual bool LoadItem(const nsAString& aKey,
829 const nsAString& aValue) override {
830 // Called on the aCache background thread
831 MOZ_ASSERT(!mLoaded);
832 if (mLoaded) {
833 return false;
836 ++mLoadedCount;
837 mKeys->AppendElement(aKey);
838 mValues->AppendElement(aValue);
839 return true;
842 virtual void LoadDone(nsresult aRv) override {
843 // Called on the aCache background thread
844 MonitorAutoLock monitor(mMonitor);
845 MOZ_ASSERT(!mLoaded && mRv);
846 mLoaded = true;
847 if (mRv) {
848 *mRv = aRv;
849 mRv = nullptr;
851 monitor.Notify();
854 virtual void LoadWait() override {
855 // Called on the main thread, exits after LoadDone() call
856 MonitorAutoLock monitor(mMonitor);
857 while (!mLoaded) {
858 monitor.Wait();
862 private:
863 Monitor mMonitor MOZ_UNANNOTATED;
864 nsCString mSuffix, mOrigin;
865 nsTArray<nsString>* mKeys;
866 nsTArray<nsString>* mValues;
867 nsresult* mRv;
868 bool mLoaded;
869 uint32_t mLoadedCount;
872 } // namespace
874 mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
875 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
876 const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
877 nsTArray<nsString>* aValues, nsresult* aRv) {
878 StorageDBThread* storageThread =
879 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
880 if (!storageThread) {
881 return IPC_FAIL_NO_REASON(this);
884 RefPtr<SyncLoadCacheHelper> cache(
885 new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix,
886 aAlreadyLoadedCount, aKeys, aValues, aRv));
888 storageThread->SyncPreload(cache, true);
890 return IPC_OK();
893 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
894 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
895 const nsAString& aKey, const nsAString& aValue) {
896 StorageDBThread* storageThread =
897 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
898 if (!storageThread) {
899 return IPC_FAIL_NO_REASON(this);
902 nsresult rv = storageThread->AsyncAddItem(
903 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
904 if (NS_FAILED(rv) && mIPCOpen) {
905 mozilla::Unused << SendError(rv);
908 return IPC_OK();
911 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
912 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
913 const nsAString& aKey, const nsAString& aValue) {
914 StorageDBThread* storageThread =
915 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
916 if (!storageThread) {
917 return IPC_FAIL_NO_REASON(this);
920 nsresult rv = storageThread->AsyncUpdateItem(
921 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
922 if (NS_FAILED(rv) && mIPCOpen) {
923 mozilla::Unused << SendError(rv);
926 return IPC_OK();
929 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
930 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
931 const nsAString& aKey) {
932 StorageDBThread* storageThread =
933 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
934 if (!storageThread) {
935 return IPC_FAIL_NO_REASON(this);
938 nsresult rv = storageThread->AsyncRemoveItem(
939 NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
940 if (NS_FAILED(rv) && mIPCOpen) {
941 mozilla::Unused << SendError(rv);
944 return IPC_OK();
947 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
948 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
949 StorageDBThread* storageThread =
950 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
951 if (!storageThread) {
952 return IPC_FAIL_NO_REASON(this);
955 nsresult rv =
956 storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
957 if (NS_FAILED(rv) && mIPCOpen) {
958 mozilla::Unused << SendError(rv);
961 return IPC_OK();
964 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
965 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
966 if (!storageThread) {
967 return IPC_FAIL_NO_REASON(this);
970 storageThread->AsyncFlush();
972 return IPC_OK();
975 mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
976 StorageDBThread* storageThread =
977 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
978 if (!storageThread) {
979 return IPC_FAIL_NO_REASON(this);
982 return IPC_OK();
985 mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
986 StorageDBThread* storageThread =
987 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
988 if (!storageThread) {
989 return IPC_FAIL_NO_REASON(this);
992 storageThread->AsyncClearAll();
994 return IPC_OK();
997 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
998 const nsACString& aOriginNoSuffix) {
999 StorageDBThread* storageThread =
1000 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
1001 if (!storageThread) {
1002 return IPC_FAIL_NO_REASON(this);
1005 storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
1007 return IPC_OK();
1010 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes(
1011 const OriginAttributesPattern& aPattern) {
1012 StorageDBThread* storageThread =
1013 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
1014 if (!storageThread) {
1015 return IPC_FAIL_NO_REASON(this);
1018 storageThread->AsyncClearMatchingOriginAttributes(aPattern);
1020 return IPC_OK();
1023 void StorageDBParent::Observe(const nsACString& aTopic,
1024 const nsAString& aOriginAttributesPattern,
1025 const nsACString& aOriginScope) {
1026 if (mIPCOpen) {
1027 mozilla::Unused << SendObserve(aTopic, aOriginAttributesPattern,
1028 aOriginScope);
1032 namespace {
1034 // Results must be sent back on the main thread
1035 class LoadRunnable : public Runnable {
1036 public:
1037 enum TaskType { loadItem, loadDone };
1039 LoadRunnable(StorageDBParent* aParent, TaskType aType,
1040 const nsACString& aOriginSuffix,
1041 const nsACString& aOriginNoSuffix,
1042 const nsAString& aKey = u""_ns, const nsAString& aValue = u""_ns)
1043 : Runnable("dom::LoadRunnable"),
1044 mParent(aParent),
1045 mType(aType),
1046 mSuffix(aOriginSuffix),
1047 mOrigin(aOriginNoSuffix),
1048 mKey(aKey),
1049 mValue(aValue),
1050 mRv(NS_ERROR_NOT_INITIALIZED) {}
1052 LoadRunnable(StorageDBParent* aParent, TaskType aType,
1053 const nsACString& aOriginSuffix,
1054 const nsACString& aOriginNoSuffix, nsresult aRv)
1055 : Runnable("dom::LoadRunnable"),
1056 mParent(aParent),
1057 mType(aType),
1058 mSuffix(aOriginSuffix),
1059 mOrigin(aOriginNoSuffix),
1060 mRv(aRv) {}
1062 private:
1063 RefPtr<StorageDBParent> mParent;
1064 TaskType mType;
1065 nsCString mSuffix, mOrigin;
1066 nsString mKey;
1067 nsString mValue;
1068 nsresult mRv;
1070 NS_IMETHOD Run() override {
1071 if (!mParent->IPCOpen()) {
1072 return NS_OK;
1075 switch (mType) {
1076 case loadItem:
1077 mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey,
1078 mValue);
1079 break;
1080 case loadDone:
1081 mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
1082 break;
1085 mParent = nullptr;
1087 return NS_OK;
1091 } // namespace
1093 // StorageDBParent::CacheParentBridge
1095 const nsCString StorageDBParent::CacheParentBridge::Origin() const {
1096 return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
1099 bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
1100 const nsAString& aValue) {
1101 if (mLoaded) {
1102 return false;
1105 ++mLoadedCount;
1107 RefPtr<LoadRunnable> r =
1108 new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
1109 mOriginNoSuffix, aKey, aValue);
1111 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1113 return true;
1116 void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) {
1117 // Prevent send of duplicate LoadDone.
1118 if (mLoaded) {
1119 return;
1122 mLoaded = true;
1124 RefPtr<LoadRunnable> r = new LoadRunnable(
1125 mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
1127 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1130 void StorageDBParent::CacheParentBridge::LoadWait() {
1131 // Should never be called on this implementation
1132 MOZ_ASSERT(false);
1135 // XXX Fix me!
1136 // This should be just:
1137 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
1138 // But due to different strings used for refcount logging and different return
1139 // types, this is done manually for now.
1140 NS_IMETHODIMP_(void)
1141 StorageDBParent::CacheParentBridge::Release(void) {
1142 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1143 nsrefcnt count = --mRefCnt;
1144 NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
1145 if (0 == count) {
1146 mRefCnt = 1; /* stabilize */
1147 /* enable this to find non-threadsafe destructors: */
1148 /* NS_ASSERT_OWNINGTHREAD(_class); */
1149 Destroy();
1153 void StorageDBParent::CacheParentBridge::Destroy() {
1154 if (mOwningEventTarget->IsOnCurrentThread()) {
1155 delete this;
1156 return;
1159 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1160 "CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy);
1162 MOZ_ALWAYS_SUCCEEDS(
1163 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1166 // StorageDBParent::UsageParentBridge
1168 namespace {
1170 class UsageRunnable : public Runnable {
1171 public:
1172 UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope,
1173 const int64_t& aUsage)
1174 : Runnable("dom::UsageRunnable"),
1175 mParent(aParent),
1176 mOriginScope(aOriginScope),
1177 mUsage(aUsage) {}
1179 private:
1180 NS_IMETHOD Run() override {
1181 if (!mParent->IPCOpen()) {
1182 return NS_OK;
1185 mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
1187 mParent = nullptr;
1189 return NS_OK;
1192 RefPtr<StorageDBParent> mParent;
1193 nsCString mOriginScope;
1194 int64_t mUsage;
1197 } // namespace
1199 void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) {
1200 RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
1202 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1205 // XXX Fix me!
1206 // This should be just:
1207 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
1208 // But due to different strings used for refcount logging, this is done manually
1209 // for now.
1210 NS_IMETHODIMP_(MozExternalRefCountType)
1211 StorageDBParent::UsageParentBridge::Release(void) {
1212 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1213 nsrefcnt count = --mRefCnt;
1214 NS_LOG_RELEASE(this, count, "StorageUsageBridge");
1215 if (count == 0) {
1216 Destroy();
1217 return 0;
1219 return count;
1222 void StorageDBParent::UsageParentBridge::Destroy() {
1223 if (mOwningEventTarget->IsOnCurrentThread()) {
1224 delete this;
1225 return;
1228 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1229 "UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy);
1231 MOZ_ALWAYS_SUCCEEDS(
1232 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1235 void StorageDBParent::ObserverSink::Start() {
1236 ::mozilla::ipc::AssertIsOnBackgroundThread();
1238 RefPtr<Runnable> runnable =
1239 NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this,
1240 &StorageDBParent::ObserverSink::AddSink);
1242 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1245 void StorageDBParent::ObserverSink::Stop() {
1246 ::mozilla::ipc::AssertIsOnBackgroundThread();
1248 mActor = nullptr;
1250 RefPtr<Runnable> runnable =
1251 NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this,
1252 &StorageDBParent::ObserverSink::RemoveSink);
1254 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1257 void StorageDBParent::ObserverSink::AddSink() {
1258 MOZ_ASSERT(NS_IsMainThread());
1260 StorageObserver* observer = StorageObserver::Self();
1261 if (observer) {
1262 observer->AddSink(this);
1266 void StorageDBParent::ObserverSink::RemoveSink() {
1267 MOZ_ASSERT(NS_IsMainThread());
1269 StorageObserver* observer = StorageObserver::Self();
1270 if (observer) {
1271 observer->RemoveSink(this);
1275 void StorageDBParent::ObserverSink::Notify(
1276 const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
1277 const nsACString& aOriginScope) {
1278 ::mozilla::ipc::AssertIsOnBackgroundThread();
1280 if (mActor) {
1281 mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
1285 nsresult StorageDBParent::ObserverSink::Observe(
1286 const char* aTopic, const nsAString& aOriginAttributesPattern,
1287 const nsACString& aOriginScope) {
1288 MOZ_ASSERT(NS_IsMainThread());
1290 RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>(
1291 "StorageDBParent::ObserverSink::Observe2", this,
1292 &StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern,
1293 aOriginScope);
1295 MOZ_ALWAYS_SUCCEEDS(
1296 mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1298 return NS_OK;
1301 SessionStorageObserverParent::SessionStorageObserverParent()
1302 : mActorDestroyed(false) {
1303 MOZ_ASSERT(NS_IsMainThread());
1305 StorageObserver* observer = StorageObserver::Self();
1306 if (observer) {
1307 observer->AddSink(this);
1311 SessionStorageObserverParent::~SessionStorageObserverParent() {
1312 MOZ_ASSERT(mActorDestroyed);
1314 StorageObserver* observer = StorageObserver::Self();
1315 if (observer) {
1316 observer->RemoveSink(this);
1320 void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) {
1321 MOZ_ASSERT(NS_IsMainThread());
1322 MOZ_ASSERT(!mActorDestroyed);
1324 mActorDestroyed = true;
1327 mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() {
1328 MOZ_ASSERT(NS_IsMainThread());
1329 MOZ_ASSERT(!mActorDestroyed);
1331 IProtocol* mgr = Manager();
1332 if (!PSessionStorageObserverParent::Send__delete__(this)) {
1333 return IPC_FAIL_NO_REASON(mgr);
1335 return IPC_OK();
1338 nsresult SessionStorageObserverParent::Observe(
1339 const char* aTopic, const nsAString& aOriginAttributesPattern,
1340 const nsACString& aOriginScope) {
1341 MOZ_ASSERT(NS_IsMainThread());
1343 if (!mActorDestroyed) {
1344 mozilla::Unused << SendObserve(nsDependentCString(aTopic),
1345 aOriginAttributesPattern, aOriginScope);
1347 return NS_OK;
1350 SessionStorageCacheParent::SessionStorageCacheParent(
1351 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1352 const nsACString& 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 nsACString& 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 nsACString& 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 nsACString& 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 nsACString& 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 nsAString& 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 nsAString& 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