StorageIPC.cpp (46701B)
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/. */ 6 7 #include "StorageIPC.h" 8 9 #include "LocalStorageManager.h" 10 #include "SessionStorageCache.h" 11 #include "SessionStorageManager.h" 12 #include "SessionStorageObserver.h" 13 #include "StorageCommon.h" 14 #include "StorageUtils.h" 15 #include "mozilla/StoragePrincipalHelper.h" 16 #include "mozilla/dom/ContentParent.h" 17 #include "mozilla/dom/LocalStorageCommon.h" 18 #include "mozilla/ipc/BackgroundChild.h" 19 #include "mozilla/ipc/BackgroundParent.h" 20 #include "mozilla/ipc/PBackgroundChild.h" 21 #include "mozilla/ipc/PBackgroundParent.h" 22 #include "nsCOMPtr.h" 23 #include "nsIPrincipal.h" 24 #include "nsThreadUtils.h" 25 26 namespace mozilla::dom { 27 28 namespace { 29 30 using LocalStorageCacheParentHashtable = 31 nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>; 32 33 StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents; 34 35 StorageDBChild* sStorageChild[kPrivateBrowsingIdCount] = {nullptr, nullptr}; 36 37 // False until we shut the storage child down. 38 bool sStorageChildDown[kPrivateBrowsingIdCount] = {false, false}; 39 40 } // namespace 41 42 LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache) 43 : mCache(aCache) { 44 AssertIsOnOwningThread(); 45 MOZ_ASSERT(aCache); 46 aCache->AssertIsOnOwningThread(); 47 48 MOZ_COUNT_CTOR(LocalStorageCacheChild); 49 } 50 51 LocalStorageCacheChild::~LocalStorageCacheChild() { 52 AssertIsOnOwningThread(); 53 54 MOZ_COUNT_DTOR(LocalStorageCacheChild); 55 } 56 57 void LocalStorageCacheChild::SendDeleteMeInternal() { 58 AssertIsOnOwningThread(); 59 60 if (mCache) { 61 mCache->ClearActor(); 62 mCache = nullptr; 63 64 MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe()); 65 } 66 } 67 68 void LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) { 69 AssertIsOnOwningThread(); 70 71 if (mCache) { 72 mCache->ClearActor(); 73 mCache = nullptr; 74 } 75 } 76 77 mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve( 78 const PrincipalInfo& aPrincipalInfo, 79 const PrincipalInfo& aCachePrincipalInfo, 80 const uint32_t& aPrivateBrowsingId, const nsAString& aDocumentURI, 81 const nsAString& aKey, const nsAString& aOldValue, 82 const nsAString& aNewValue) { 83 AssertIsOnOwningThread(); 84 85 auto principalOrErr = PrincipalInfoToPrincipal(aPrincipalInfo); 86 if (NS_WARN_IF(principalOrErr.isErr())) { 87 return IPC_FAIL_NO_REASON(this); 88 } 89 90 auto cachePrincipalOrErr = PrincipalInfoToPrincipal(aCachePrincipalInfo); 91 if (NS_WARN_IF(cachePrincipalOrErr.isErr())) { 92 return IPC_FAIL_NO_REASON(this); 93 } 94 95 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap(); 96 nsCOMPtr<nsIPrincipal> cachePrincipal = cachePrincipalOrErr.unwrap(); 97 98 if (StorageUtils::PrincipalsEqual(principal, cachePrincipal)) { 99 Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue, 100 aNewValue, 101 /* aStorageType */ u"localStorage", aDocumentURI, 102 /* aIsPrivate */ !!aPrivateBrowsingId, 103 /* aImmediateDispatch */ true); 104 } 105 106 return IPC_OK(); 107 } 108 109 // ---------------------------------------------------------------------------- 110 // Child 111 // ---------------------------------------------------------------------------- 112 113 class StorageDBChild::ShutdownObserver final : public nsIObserver { 114 // Expected to be only 0 or 1. 115 const uint32_t mPrivateBrowsingId; 116 117 public: 118 explicit ShutdownObserver(const uint32_t aPrivateBrowsingId) 119 : mPrivateBrowsingId(aPrivateBrowsingId) { 120 MOZ_ASSERT(NS_IsMainThread()); 121 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount); 122 } 123 124 NS_DECL_ISUPPORTS 125 NS_DECL_NSIOBSERVER 126 127 private: 128 ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); } 129 }; 130 131 void StorageDBChild::AddIPDLReference() { 132 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references"); 133 mIPCOpen = true; 134 AddRef(); 135 } 136 137 void StorageDBChild::ReleaseIPDLReference() { 138 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference"); 139 mIPCOpen = false; 140 Release(); 141 } 142 143 StorageDBChild::StorageDBChild(LocalStorageManager* aManager, 144 const uint32_t aPrivateBrowsingId) 145 : mManager(aManager), 146 mPrivateBrowsingId(aPrivateBrowsingId), 147 mStatus(NS_OK), 148 mIPCOpen(false) { 149 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount); 150 MOZ_ASSERT(!NextGenLocalStorageEnabled()); 151 } 152 153 StorageDBChild::~StorageDBChild() = default; 154 155 // static 156 StorageDBChild* StorageDBChild::Get(const uint32_t aPrivateBrowsingId) { 157 MOZ_ASSERT(NS_IsMainThread()); 158 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount); 159 MOZ_ASSERT(!NextGenLocalStorageEnabled()); 160 161 return sStorageChild[aPrivateBrowsingId]; 162 } 163 164 // static 165 StorageDBChild* StorageDBChild::GetOrCreate(const uint32_t aPrivateBrowsingId) { 166 MOZ_ASSERT(NS_IsMainThread()); 167 MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount); 168 MOZ_ASSERT(!NextGenLocalStorageEnabled()); 169 170 StorageDBChild*& storageChild = sStorageChild[aPrivateBrowsingId]; 171 if (storageChild || sStorageChildDown[aPrivateBrowsingId]) { 172 // When sStorageChildDown is at true, sStorageChild is null. 173 // Checking sStorageChildDown flag here prevents reinitialization of 174 // the storage child after shutdown. 175 return storageChild; 176 } 177 178 // Use LocalStorageManager::Ensure in case we're called from 179 // DOMSessionStorageManager's initializer and we haven't yet initialized the 180 // local storage manager. 181 RefPtr<StorageDBChild> newStorageChild = 182 new StorageDBChild(LocalStorageManager::Ensure(), aPrivateBrowsingId); 183 184 nsresult rv = newStorageChild->Init(); 185 if (NS_WARN_IF(NS_FAILED(rv))) { 186 return nullptr; 187 } 188 189 newStorageChild.forget(&storageChild); 190 191 return storageChild; 192 } 193 194 nsTHashSet<nsCString>& StorageDBChild::OriginsHavingData() { 195 if (!mOriginsHavingData) { 196 mOriginsHavingData = MakeUnique<nsTHashSet<nsCString>>(); 197 } 198 199 return *mOriginsHavingData; 200 } 201 202 nsresult StorageDBChild::Init() { 203 MOZ_ASSERT(NS_IsMainThread()); 204 205 ::mozilla::ipc::PBackgroundChild* actor = 206 ::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(); 207 if (NS_WARN_IF(!actor)) { 208 return NS_ERROR_FAILURE; 209 } 210 211 nsString profilePath; 212 if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) { 213 nsresult rv = StorageDBThread::GetProfilePath(profilePath); 214 if (NS_WARN_IF(NS_FAILED(rv))) { 215 return rv; 216 } 217 } 218 219 AddIPDLReference(); 220 221 actor->SendPBackgroundStorageConstructor(this, profilePath, 222 mPrivateBrowsingId); 223 224 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 225 MOZ_ASSERT(observerService); 226 227 nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mPrivateBrowsingId); 228 229 MOZ_ALWAYS_SUCCEEDS( 230 observerService->AddObserver(observer, "xpcom-shutdown", false)); 231 232 return NS_OK; 233 } 234 235 nsresult StorageDBChild::Shutdown() { 236 // There is nothing to do here, IPC will release automatically and 237 // the actual thread running on the parent process will also stop 238 // automatically in profile-before-change topic observer. 239 return NS_OK; 240 } 241 242 void StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache, 243 bool aPriority) { 244 if (mIPCOpen) { 245 // Adding ref to cache for the time of preload. This ensures a reference to 246 // to the cache and that all keys will load into this cache object. 247 mLoadingCaches.Insert(aCache); 248 SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), 249 aPriority); 250 } else { 251 // No IPC, no love. But the LoadDone call is expected. 252 aCache->LoadDone(NS_ERROR_UNEXPECTED); 253 } 254 } 255 256 void StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage) { 257 if (mIPCOpen) { 258 SendAsyncGetUsage(aUsage->OriginScope()); 259 } 260 } 261 262 void StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache, 263 bool aForceSync) { 264 if (NS_FAILED(mStatus)) { 265 aCache->LoadDone(mStatus); 266 return; 267 } 268 269 if (!mIPCOpen) { 270 aCache->LoadDone(NS_ERROR_UNEXPECTED); 271 return; 272 } 273 274 // There is no way to put the child process to a wait state to receive all 275 // incoming async responses from the parent, hence we have to do a sync 276 // preload instead. We are smart though, we only demand keys that are left to 277 // load in case the async preload has already loaded some keys. 278 nsTArray<nsString> keys, values; 279 nsresult rv; 280 SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), 281 aCache->LoadedCount(), &keys, &values, &rv); 282 283 for (uint32_t i = 0; i < keys.Length(); ++i) { 284 aCache->LoadItem(keys[i], values[i]); 285 } 286 287 aCache->LoadDone(rv); 288 } 289 290 nsresult StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache, 291 const nsAString& aKey, 292 const nsAString& aValue) { 293 if (NS_FAILED(mStatus) || !mIPCOpen) { 294 return mStatus; 295 } 296 297 SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(), 298 nsString(aKey), nsString(aValue)); 299 OriginsHavingData().Insert(aCache->Origin()); 300 return NS_OK; 301 } 302 303 nsresult StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache, 304 const nsAString& aKey, 305 const nsAString& aValue) { 306 if (NS_FAILED(mStatus) || !mIPCOpen) { 307 return mStatus; 308 } 309 310 SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(), 311 nsString(aKey), nsString(aValue)); 312 OriginsHavingData().Insert(aCache->Origin()); 313 return NS_OK; 314 } 315 316 nsresult StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache, 317 const nsAString& aKey) { 318 if (NS_FAILED(mStatus) || !mIPCOpen) { 319 return mStatus; 320 } 321 322 SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(), 323 nsString(aKey)); 324 return NS_OK; 325 } 326 327 nsresult StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache) { 328 if (NS_FAILED(mStatus) || !mIPCOpen) { 329 return mStatus; 330 } 331 332 SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix()); 333 OriginsHavingData().Remove(aCache->Origin()); 334 return NS_OK; 335 } 336 337 bool StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin) { 338 // Return true if we didn't receive the origins list yet. 339 // I tend to rather preserve a bit of early-after-start performance 340 // than a bit of memory here. 341 return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin); 342 } 343 344 mozilla::ipc::IPCResult StorageDBChild::RecvObserve( 345 const nsACString& aTopic, const nsAString& aOriginAttributesPattern, 346 const nsACString& aOriginScope) { 347 MOZ_ASSERT(!XRE_IsParentProcess()); 348 349 if (StorageObserver* obs = StorageObserver::Self()) { 350 obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern, 351 aOriginScope); 352 } 353 354 return IPC_OK(); 355 } 356 357 mozilla::ipc::IPCResult StorageDBChild::RecvOriginsHavingData( 358 nsTArray<nsCString>&& aOrigins) { 359 // Force population of mOriginsHavingData even if there are no origins so that 360 // ShouldPreloadOrigin does not generate false positives for all origins. 361 if (!aOrigins.Length()) { 362 (void)OriginsHavingData(); 363 } 364 365 for (uint32_t i = 0; i < aOrigins.Length(); ++i) { 366 OriginsHavingData().Insert(aOrigins[i]); 367 } 368 369 return IPC_OK(); 370 } 371 372 mozilla::ipc::IPCResult StorageDBChild::RecvLoadItem( 373 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 374 const nsAString& aKey, const nsAString& aValue) { 375 LocalStorageCache* aCache = 376 mManager->GetCache(aOriginSuffix, aOriginNoSuffix); 377 if (aCache) { 378 aCache->LoadItem(aKey, aValue); 379 } 380 381 return IPC_OK(); 382 } 383 384 mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone( 385 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 386 const nsresult& aRv) { 387 LocalStorageCache* aCache = 388 mManager->GetCache(aOriginSuffix, aOriginNoSuffix); 389 if (aCache) { 390 aCache->LoadDone(aRv); 391 392 // Just drop reference to this cache now since the load is done. 393 mLoadingCaches.Remove(static_cast<LocalStorageCacheBridge*>(aCache)); 394 } 395 396 return IPC_OK(); 397 } 398 399 mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage( 400 const nsACString& aOriginNoSuffix, const int64_t& aUsage) { 401 RefPtr<StorageUsageBridge> scopeUsage = 402 mManager->GetOriginUsage(aOriginNoSuffix, mPrivateBrowsingId); 403 scopeUsage->LoadUsage(aUsage); 404 return IPC_OK(); 405 } 406 407 mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) { 408 mStatus = aRv; 409 return IPC_OK(); 410 } 411 412 NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver) 413 414 NS_IMETHODIMP 415 StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject, 416 const char* aTopic, 417 const char16_t* aData) { 418 MOZ_ASSERT(NS_IsMainThread()); 419 MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown")); 420 421 nsCOMPtr<nsIObserverService> observerService = 422 mozilla::services::GetObserverService(); 423 if (NS_WARN_IF(!observerService)) { 424 return NS_ERROR_FAILURE; 425 } 426 427 (void)observerService->RemoveObserver(this, "xpcom-shutdown"); 428 429 StorageDBChild*& storageChild = sStorageChild[mPrivateBrowsingId]; 430 if (storageChild) { 431 sStorageChildDown[mPrivateBrowsingId] = true; 432 433 MOZ_ALWAYS_TRUE(storageChild->PBackgroundStorageChild::SendDeleteMe()); 434 435 NS_RELEASE(storageChild); 436 storageChild = nullptr; 437 } 438 439 return NS_OK; 440 } 441 442 SessionStorageObserverChild::SessionStorageObserverChild( 443 SessionStorageObserver* aObserver) 444 : mObserver(aObserver) { 445 AssertIsOnOwningThread(); 446 MOZ_ASSERT(NextGenLocalStorageEnabled()); 447 MOZ_ASSERT(aObserver); 448 aObserver->AssertIsOnOwningThread(); 449 450 MOZ_COUNT_CTOR(SessionStorageObserverChild); 451 } 452 453 SessionStorageObserverChild::~SessionStorageObserverChild() { 454 AssertIsOnOwningThread(); 455 456 MOZ_COUNT_DTOR(SessionStorageObserverChild); 457 } 458 459 void SessionStorageObserverChild::SendDeleteMeInternal() { 460 AssertIsOnOwningThread(); 461 462 if (mObserver) { 463 mObserver->ClearActor(); 464 mObserver = nullptr; 465 466 // Don't check result here since IPC may no longer be available due to 467 // SessionStorageManager (which holds a strong reference to 468 // SessionStorageObserver) being destroyed very late in the game. 469 PSessionStorageObserverChild::SendDeleteMe(); 470 } 471 } 472 473 void SessionStorageObserverChild::ActorDestroy(ActorDestroyReason aWhy) { 474 AssertIsOnOwningThread(); 475 476 if (mObserver) { 477 mObserver->ClearActor(); 478 mObserver = nullptr; 479 } 480 } 481 482 mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve( 483 const nsACString& aTopic, const nsAString& aOriginAttributesPattern, 484 const nsACString& aOriginScope) { 485 AssertIsOnOwningThread(); 486 487 if (StorageObserver* obs = StorageObserver::Self()) { 488 obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern, 489 aOriginScope); 490 } 491 492 return IPC_OK(); 493 } 494 495 SessionStorageCacheChild::SessionStorageCacheChild(SessionStorageCache* aCache) 496 : mCache(aCache) { 497 AssertIsOnOwningThread(); 498 MOZ_ASSERT(mCache); 499 500 MOZ_COUNT_CTOR(SessionStorageCacheChild); 501 } 502 503 SessionStorageCacheChild::~SessionStorageCacheChild() { 504 AssertIsOnOwningThread(); 505 506 MOZ_COUNT_DTOR(SessionStorageCacheChild); 507 } 508 509 void SessionStorageCacheChild::SendDeleteMeInternal() { 510 AssertIsOnOwningThread(); 511 512 if (mCache) { 513 mCache->ClearActor(); 514 mCache = nullptr; 515 516 MOZ_ALWAYS_TRUE(PBackgroundSessionStorageCacheChild::SendDeleteMe()); 517 } 518 } 519 520 void SessionStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) { 521 AssertIsOnOwningThread(); 522 523 if (mCache) { 524 mCache->ClearActor(); 525 mCache = nullptr; 526 } 527 } 528 529 SessionStorageManagerChild::SessionStorageManagerChild( 530 SessionStorageManager* aSSManager) 531 : mSSManager(aSSManager) { 532 AssertIsOnOwningThread(); 533 MOZ_ASSERT(mSSManager); 534 535 MOZ_COUNT_CTOR(SessionStorageManagerChild); 536 } 537 538 SessionStorageManagerChild::~SessionStorageManagerChild() { 539 AssertIsOnOwningThread(); 540 541 MOZ_COUNT_DTOR(SessionStorageManagerChild); 542 } 543 544 void SessionStorageManagerChild::SendDeleteMeInternal() { 545 AssertIsOnOwningThread(); 546 547 if (mSSManager) { 548 mSSManager->ClearActor(); 549 mSSManager = nullptr; 550 551 MOZ_ALWAYS_TRUE(PBackgroundSessionStorageManagerChild::SendDeleteMe()); 552 } 553 } 554 555 void SessionStorageManagerChild::ActorDestroy(ActorDestroyReason aWhy) { 556 AssertIsOnOwningThread(); 557 558 if (mSSManager) { 559 mSSManager->ClearActor(); 560 mSSManager = nullptr; 561 } 562 } 563 564 mozilla::ipc::IPCResult SessionStorageManagerChild::RecvClearStoragesForOrigin( 565 const nsACString& aOriginAttrs, const nsACString& aOriginKey) { 566 AssertIsOnOwningThread(); 567 568 if (mSSManager) { 569 mSSManager->ClearStoragesForOrigin(aOriginAttrs, aOriginKey); 570 } 571 572 return IPC_OK(); 573 } 574 575 LocalStorageCacheParent::LocalStorageCacheParent( 576 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, 577 const nsACString& aOriginKey, uint32_t aPrivateBrowsingId) 578 : mPrincipalInfo(aPrincipalInfo), 579 mOriginKey(aOriginKey), 580 mPrivateBrowsingId(aPrivateBrowsingId), 581 mActorDestroyed(false) { 582 ::mozilla::ipc::AssertIsOnBackgroundThread(); 583 } 584 585 LocalStorageCacheParent::~LocalStorageCacheParent() { 586 MOZ_ASSERT(mActorDestroyed); 587 } 588 589 void LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) { 590 ::mozilla::ipc::AssertIsOnBackgroundThread(); 591 MOZ_ASSERT(!mActorDestroyed); 592 593 mActorDestroyed = true; 594 595 MOZ_ASSERT(gLocalStorageCacheParents); 596 597 nsTArray<LocalStorageCacheParent*>* array; 598 gLocalStorageCacheParents->Get(mOriginKey, &array); 599 MOZ_ASSERT(array); 600 601 array->RemoveElement(this); 602 603 if (array->IsEmpty()) { 604 gLocalStorageCacheParents->Remove(mOriginKey); 605 } 606 607 if (!gLocalStorageCacheParents->Count()) { 608 gLocalStorageCacheParents = nullptr; 609 } 610 } 611 612 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvDeleteMe() { 613 ::mozilla::ipc::AssertIsOnBackgroundThread(); 614 MOZ_ASSERT(!mActorDestroyed); 615 616 IProtocol* mgr = Manager(); 617 if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) { 618 return IPC_FAIL_NO_REASON(mgr); 619 } 620 return IPC_OK(); 621 } 622 623 mozilla::ipc::IPCResult LocalStorageCacheParent::RecvNotify( 624 const nsAString& aDocumentURI, const nsAString& aKey, 625 const nsAString& aOldValue, const nsAString& aNewValue) { 626 ::mozilla::ipc::AssertIsOnBackgroundThread(); 627 MOZ_ASSERT(gLocalStorageCacheParents); 628 629 nsTArray<LocalStorageCacheParent*>* array; 630 gLocalStorageCacheParents->Get(mOriginKey, &array); 631 MOZ_ASSERT(array); 632 633 for (LocalStorageCacheParent* localStorageCacheParent : *array) { 634 if (localStorageCacheParent != this) { 635 // When bug 1443925 is fixed, we can compare mPrincipalInfo against 636 // localStorageCacheParent->PrincipalInfo() here on the background thread 637 // instead of posting it to the main thread. The advantage of doing so is 638 // that it would save an IPC message in the case where the principals do 639 // not match. 640 (void)localStorageCacheParent->SendObserve( 641 mPrincipalInfo, localStorageCacheParent->PrincipalInfo(), 642 mPrivateBrowsingId, aDocumentURI, aKey, aOldValue, aNewValue); 643 } 644 } 645 646 return IPC_OK(); 647 } 648 649 // ---------------------------------------------------------------------------- 650 // Parent 651 // ---------------------------------------------------------------------------- 652 653 class StorageDBParent::ObserverSink : public StorageObserverSink { 654 nsCOMPtr<nsIEventTarget> mOwningEventTarget; 655 656 // Only touched on the PBackground thread. 657 StorageDBParent* MOZ_NON_OWNING_REF mActor; 658 659 public: 660 explicit ObserverSink(StorageDBParent* aActor) 661 : mOwningEventTarget(GetCurrentSerialEventTarget()), mActor(aActor) { 662 ::mozilla::ipc::AssertIsOnBackgroundThread(); 663 MOZ_ASSERT(aActor); 664 } 665 666 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink); 667 668 void Start(); 669 670 void Stop(); 671 672 private: 673 ~ObserverSink() = default; 674 675 void AddSink(); 676 677 void RemoveSink(); 678 679 void Notify(const nsACString& aTopic, 680 const nsAString& aOriginAttributesPattern, 681 const nsACString& aOriginScope); 682 683 // StorageObserverSink 684 nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern, 685 const nsACString& aOriginScope) override; 686 }; 687 688 NS_IMPL_ADDREF(StorageDBParent) 689 NS_IMPL_RELEASE(StorageDBParent) 690 691 void StorageDBParent::AddIPDLReference() { 692 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references"); 693 mIPCOpen = true; 694 AddRef(); 695 } 696 697 void StorageDBParent::ReleaseIPDLReference() { 698 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference"); 699 mIPCOpen = false; 700 Release(); 701 } 702 703 namespace {} // namespace 704 705 StorageDBParent::StorageDBParent(const nsAString& aProfilePath, 706 const uint32_t aPrivateBrowsingId) 707 : mProfilePath(aProfilePath), 708 mPrivateBrowsingId(aPrivateBrowsingId), 709 mIPCOpen(false) { 710 ::mozilla::ipc::AssertIsOnBackgroundThread(); 711 712 // We are always open by IPC only 713 AddIPDLReference(); 714 } 715 716 StorageDBParent::~StorageDBParent() { 717 ::mozilla::ipc::AssertIsOnBackgroundThread(); 718 719 if (mObserverSink) { 720 mObserverSink->Stop(); 721 mObserverSink = nullptr; 722 } 723 } 724 725 void StorageDBParent::Init() { 726 ::mozilla::ipc::AssertIsOnBackgroundThread(); 727 728 PBackgroundParent* actor = Manager(); 729 MOZ_ASSERT(actor); 730 731 if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) { 732 mObserverSink = new ObserverSink(this); 733 mObserverSink->Start(); 734 } 735 736 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId); 737 if (storageThread) { 738 nsTArray<nsCString> scopes; 739 storageThread->GetOriginsHavingData(&scopes); 740 (void)SendOriginsHavingData(scopes); 741 } 742 } 743 744 StorageDBParent::CacheParentBridge* StorageDBParent::NewCache( 745 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) { 746 return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix); 747 } 748 749 void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) { 750 // Implement me! Bug 1005169 751 } 752 753 mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() { 754 ::mozilla::ipc::AssertIsOnBackgroundThread(); 755 756 IProtocol* mgr = Manager(); 757 if (!PBackgroundStorageParent::Send__delete__(this)) { 758 return IPC_FAIL_NO_REASON(mgr); 759 } 760 return IPC_OK(); 761 } 762 763 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload( 764 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 765 const bool& aPriority) { 766 StorageDBThread* storageThread = 767 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 768 if (!storageThread) { 769 return IPC_FAIL_NO_REASON(this); 770 } 771 772 storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix), 773 aPriority); 774 775 return IPC_OK(); 776 } 777 778 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage( 779 const nsACString& aOriginNoSuffix) { 780 StorageDBThread* storageThread = 781 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 782 if (!storageThread) { 783 return IPC_FAIL_NO_REASON(this); 784 } 785 786 // The object releases it self in LoadUsage method 787 RefPtr<UsageParentBridge> usage = 788 new UsageParentBridge(this, aOriginNoSuffix); 789 790 storageThread->AsyncGetUsage(usage); 791 792 return IPC_OK(); 793 } 794 795 namespace { 796 797 // We need another implementation of LocalStorageCacheBridge to do 798 // synchronous IPC preload. This class just receives Load* notifications 799 // and fills the returning arguments of RecvPreload with the database 800 // values for us. 801 class SyncLoadCacheHelper : public LocalStorageCacheBridge { 802 public: 803 SyncLoadCacheHelper(const nsACString& aOriginSuffix, 804 const nsACString& aOriginNoSuffix, 805 uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys, 806 nsTArray<nsString>* aValues, nsresult* rv) 807 : mMonitor("DOM Storage SyncLoad IPC"), 808 mSuffix(aOriginSuffix), 809 mOrigin(aOriginNoSuffix), 810 mKeys(aKeys), 811 mValues(aValues), 812 mRv(rv), 813 mLoaded(false), 814 mLoadedCount(aAlreadyLoadedCount) { 815 // Precaution 816 *mRv = NS_ERROR_UNEXPECTED; 817 } 818 819 virtual const nsCString Origin() const override { 820 return LocalStorageManager::CreateOrigin(mSuffix, mOrigin); 821 } 822 virtual const nsCString& OriginNoSuffix() const override { return mOrigin; } 823 virtual const nsCString& OriginSuffix() const override { return mSuffix; } 824 virtual bool Loaded() override { return mLoaded; } 825 virtual uint32_t LoadedCount() override { return mLoadedCount; } 826 virtual bool LoadItem(const nsAString& aKey, 827 const nsAString& aValue) override { 828 // Called on the aCache background thread 829 MOZ_ASSERT(!mLoaded); 830 if (mLoaded) { 831 return false; 832 } 833 834 ++mLoadedCount; 835 mKeys->AppendElement(aKey); 836 mValues->AppendElement(aValue); 837 return true; 838 } 839 840 virtual void LoadDone(nsresult aRv) override { 841 // Called on the aCache background thread 842 MonitorAutoLock monitor(mMonitor); 843 MOZ_ASSERT(!mLoaded && mRv); 844 mLoaded = true; 845 if (mRv) { 846 *mRv = aRv; 847 mRv = nullptr; 848 } 849 monitor.Notify(); 850 } 851 852 virtual void LoadWait() override { 853 // Called on the main thread, exits after LoadDone() call 854 MonitorAutoLock monitor(mMonitor); 855 while (!mLoaded) { 856 monitor.Wait(); 857 } 858 } 859 860 private: 861 Monitor mMonitor MOZ_UNANNOTATED; 862 nsCString mSuffix, mOrigin; 863 nsTArray<nsString>* mKeys; 864 nsTArray<nsString>* mValues; 865 nsresult* mRv; 866 bool mLoaded; 867 uint32_t mLoadedCount; 868 }; 869 870 } // namespace 871 872 mozilla::ipc::IPCResult StorageDBParent::RecvPreload( 873 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 874 const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys, 875 nsTArray<nsString>* aValues, nsresult* aRv) { 876 StorageDBThread* storageThread = 877 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 878 if (!storageThread) { 879 return IPC_FAIL_NO_REASON(this); 880 } 881 882 RefPtr<SyncLoadCacheHelper> cache( 883 new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix, 884 aAlreadyLoadedCount, aKeys, aValues, aRv)); 885 886 storageThread->SyncPreload(cache, true); 887 888 return IPC_OK(); 889 } 890 891 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem( 892 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 893 const nsAString& aKey, const nsAString& aValue) { 894 StorageDBThread* storageThread = 895 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 896 if (!storageThread) { 897 return IPC_FAIL_NO_REASON(this); 898 } 899 900 nsresult rv = storageThread->AsyncAddItem( 901 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue); 902 if (NS_FAILED(rv) && mIPCOpen) { 903 (void)SendError(rv); 904 } 905 906 return IPC_OK(); 907 } 908 909 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem( 910 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 911 const nsAString& aKey, const nsAString& aValue) { 912 StorageDBThread* storageThread = 913 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 914 if (!storageThread) { 915 return IPC_FAIL_NO_REASON(this); 916 } 917 918 nsresult rv = storageThread->AsyncUpdateItem( 919 NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue); 920 if (NS_FAILED(rv) && mIPCOpen) { 921 (void)SendError(rv); 922 } 923 924 return IPC_OK(); 925 } 926 927 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem( 928 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix, 929 const nsAString& aKey) { 930 StorageDBThread* storageThread = 931 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 932 if (!storageThread) { 933 return IPC_FAIL_NO_REASON(this); 934 } 935 936 nsresult rv = storageThread->AsyncRemoveItem( 937 NewCache(aOriginSuffix, aOriginNoSuffix), aKey); 938 if (NS_FAILED(rv) && mIPCOpen) { 939 (void)SendError(rv); 940 } 941 942 return IPC_OK(); 943 } 944 945 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear( 946 const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) { 947 StorageDBThread* storageThread = 948 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 949 if (!storageThread) { 950 return IPC_FAIL_NO_REASON(this); 951 } 952 953 nsresult rv = 954 storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix)); 955 if (NS_FAILED(rv) && mIPCOpen) { 956 (void)SendError(rv); 957 } 958 959 return IPC_OK(); 960 } 961 962 mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() { 963 StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId); 964 if (!storageThread) { 965 return IPC_FAIL_NO_REASON(this); 966 } 967 968 storageThread->AsyncFlush(); 969 970 return IPC_OK(); 971 } 972 973 mozilla::ipc::IPCResult StorageDBParent::RecvStartup() { 974 StorageDBThread* storageThread = 975 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 976 if (!storageThread) { 977 return IPC_FAIL_NO_REASON(this); 978 } 979 980 return IPC_OK(); 981 } 982 983 mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() { 984 StorageDBThread* storageThread = 985 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 986 if (!storageThread) { 987 return IPC_FAIL_NO_REASON(this); 988 } 989 990 storageThread->AsyncClearAll(); 991 992 return IPC_OK(); 993 } 994 995 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin( 996 const nsACString& aOriginNoSuffix) { 997 StorageDBThread* storageThread = 998 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 999 if (!storageThread) { 1000 return IPC_FAIL_NO_REASON(this); 1001 } 1002 1003 storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix); 1004 1005 return IPC_OK(); 1006 } 1007 1008 mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes( 1009 const OriginAttributesPattern& aPattern) { 1010 StorageDBThread* storageThread = 1011 StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId); 1012 if (!storageThread) { 1013 return IPC_FAIL_NO_REASON(this); 1014 } 1015 1016 storageThread->AsyncClearMatchingOriginAttributes(aPattern); 1017 1018 return IPC_OK(); 1019 } 1020 1021 void StorageDBParent::Observe(const nsACString& aTopic, 1022 const nsAString& aOriginAttributesPattern, 1023 const nsACString& aOriginScope) { 1024 if (mIPCOpen) { 1025 (void)SendObserve(aTopic, aOriginAttributesPattern, aOriginScope); 1026 } 1027 } 1028 1029 namespace { 1030 1031 // Results must be sent back on the main thread 1032 class LoadRunnable : public Runnable { 1033 public: 1034 enum TaskType { loadItem, loadDone }; 1035 1036 LoadRunnable(StorageDBParent* aParent, TaskType aType, 1037 const nsACString& aOriginSuffix, 1038 const nsACString& aOriginNoSuffix, 1039 const nsAString& aKey = u""_ns, const nsAString& aValue = u""_ns) 1040 : Runnable("dom::LoadRunnable"), 1041 mParent(aParent), 1042 mType(aType), 1043 mSuffix(aOriginSuffix), 1044 mOrigin(aOriginNoSuffix), 1045 mKey(aKey), 1046 mValue(aValue), 1047 mRv(NS_ERROR_NOT_INITIALIZED) {} 1048 1049 LoadRunnable(StorageDBParent* aParent, TaskType aType, 1050 const nsACString& aOriginSuffix, 1051 const nsACString& aOriginNoSuffix, nsresult aRv) 1052 : Runnable("dom::LoadRunnable"), 1053 mParent(aParent), 1054 mType(aType), 1055 mSuffix(aOriginSuffix), 1056 mOrigin(aOriginNoSuffix), 1057 mRv(aRv) {} 1058 1059 private: 1060 RefPtr<StorageDBParent> mParent; 1061 TaskType mType; 1062 nsCString mSuffix, mOrigin; 1063 nsString mKey; 1064 nsString mValue; 1065 nsresult mRv; 1066 1067 NS_IMETHOD Run() override { 1068 if (!mParent->IPCOpen()) { 1069 return NS_OK; 1070 } 1071 1072 switch (mType) { 1073 case loadItem: 1074 (void)mParent->SendLoadItem(mSuffix, mOrigin, mKey, mValue); 1075 break; 1076 case loadDone: 1077 (void)mParent->SendLoadDone(mSuffix, mOrigin, mRv); 1078 break; 1079 } 1080 1081 mParent = nullptr; 1082 1083 return NS_OK; 1084 } 1085 }; 1086 1087 } // namespace 1088 1089 // StorageDBParent::CacheParentBridge 1090 1091 const nsCString StorageDBParent::CacheParentBridge::Origin() const { 1092 return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix); 1093 } 1094 1095 bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey, 1096 const nsAString& aValue) { 1097 if (mLoaded) { 1098 return false; 1099 } 1100 1101 ++mLoadedCount; 1102 1103 RefPtr<LoadRunnable> r = 1104 new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix, 1105 mOriginNoSuffix, aKey, aValue); 1106 1107 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL)); 1108 1109 return true; 1110 } 1111 1112 void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) { 1113 // Prevent send of duplicate LoadDone. 1114 if (mLoaded) { 1115 return; 1116 } 1117 1118 mLoaded = true; 1119 1120 RefPtr<LoadRunnable> r = new LoadRunnable( 1121 mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv); 1122 1123 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL)); 1124 } 1125 1126 void StorageDBParent::CacheParentBridge::LoadWait() { 1127 // Should never be called on this implementation 1128 MOZ_ASSERT(false); 1129 } 1130 1131 // XXX Fix me! 1132 // This should be just: 1133 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy) 1134 // But due to different strings used for refcount logging and different return 1135 // types, this is done manually for now. 1136 NS_IMETHODIMP_(void) 1137 StorageDBParent::CacheParentBridge::Release(void) { 1138 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); 1139 nsrefcnt count = --mRefCnt; 1140 NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge"); 1141 if (0 == count) { 1142 mRefCnt = 1; /* stabilize */ 1143 /* enable this to find non-threadsafe destructors: */ 1144 /* NS_ASSERT_OWNINGTHREAD(_class); */ 1145 Destroy(); 1146 } 1147 } 1148 1149 void StorageDBParent::CacheParentBridge::Destroy() { 1150 if (mOwningEventTarget->IsOnCurrentThread()) { 1151 delete this; 1152 return; 1153 } 1154 1155 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod( 1156 "CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy); 1157 1158 MOZ_ALWAYS_SUCCEEDS( 1159 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL)); 1160 } 1161 1162 // StorageDBParent::UsageParentBridge 1163 1164 namespace { 1165 1166 class UsageRunnable : public Runnable { 1167 public: 1168 UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope, 1169 const int64_t& aUsage) 1170 : Runnable("dom::UsageRunnable"), 1171 mParent(aParent), 1172 mOriginScope(aOriginScope), 1173 mUsage(aUsage) {} 1174 1175 private: 1176 NS_IMETHOD Run() override { 1177 if (!mParent->IPCOpen()) { 1178 return NS_OK; 1179 } 1180 1181 (void)mParent->SendLoadUsage(mOriginScope, mUsage); 1182 1183 mParent = nullptr; 1184 1185 return NS_OK; 1186 } 1187 1188 RefPtr<StorageDBParent> mParent; 1189 nsCString mOriginScope; 1190 int64_t mUsage; 1191 }; 1192 1193 } // namespace 1194 1195 void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) { 1196 RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage); 1197 1198 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL)); 1199 } 1200 1201 // XXX Fix me! 1202 // This should be just: 1203 // NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy) 1204 // But due to different strings used for refcount logging, this is done manually 1205 // for now. 1206 NS_IMETHODIMP_(MozExternalRefCountType) 1207 StorageDBParent::UsageParentBridge::Release(void) { 1208 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); 1209 nsrefcnt count = --mRefCnt; 1210 NS_LOG_RELEASE(this, count, "StorageUsageBridge"); 1211 if (count == 0) { 1212 Destroy(); 1213 return 0; 1214 } 1215 return count; 1216 } 1217 1218 void StorageDBParent::UsageParentBridge::Destroy() { 1219 if (mOwningEventTarget->IsOnCurrentThread()) { 1220 delete this; 1221 return; 1222 } 1223 1224 RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod( 1225 "UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy); 1226 1227 MOZ_ALWAYS_SUCCEEDS( 1228 mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL)); 1229 } 1230 1231 void StorageDBParent::ObserverSink::Start() { 1232 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1233 1234 RefPtr<Runnable> runnable = 1235 NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this, 1236 &StorageDBParent::ObserverSink::AddSink); 1237 1238 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); 1239 } 1240 1241 void StorageDBParent::ObserverSink::Stop() { 1242 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1243 1244 mActor = nullptr; 1245 1246 RefPtr<Runnable> runnable = 1247 NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this, 1248 &StorageDBParent::ObserverSink::RemoveSink); 1249 1250 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); 1251 } 1252 1253 void StorageDBParent::ObserverSink::AddSink() { 1254 MOZ_ASSERT(NS_IsMainThread()); 1255 1256 StorageObserver* observer = StorageObserver::Self(); 1257 if (observer) { 1258 observer->AddSink(this); 1259 } 1260 } 1261 1262 void StorageDBParent::ObserverSink::RemoveSink() { 1263 MOZ_ASSERT(NS_IsMainThread()); 1264 1265 StorageObserver* observer = StorageObserver::Self(); 1266 if (observer) { 1267 observer->RemoveSink(this); 1268 } 1269 } 1270 1271 void StorageDBParent::ObserverSink::Notify( 1272 const nsACString& aTopic, const nsAString& aOriginAttributesPattern, 1273 const nsACString& aOriginScope) { 1274 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1275 1276 if (mActor) { 1277 mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope); 1278 } 1279 } 1280 1281 nsresult StorageDBParent::ObserverSink::Observe( 1282 const char* aTopic, const nsAString& aOriginAttributesPattern, 1283 const nsACString& aOriginScope) { 1284 MOZ_ASSERT(NS_IsMainThread()); 1285 1286 RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>( 1287 "StorageDBParent::ObserverSink::Observe2", this, 1288 &StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern, 1289 aOriginScope); 1290 1291 MOZ_ALWAYS_SUCCEEDS( 1292 mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)); 1293 1294 return NS_OK; 1295 } 1296 1297 SessionStorageObserverParent::SessionStorageObserverParent() 1298 : mActorDestroyed(false) { 1299 MOZ_ASSERT(NS_IsMainThread()); 1300 1301 StorageObserver* observer = StorageObserver::Self(); 1302 if (observer) { 1303 observer->AddSink(this); 1304 } 1305 } 1306 1307 SessionStorageObserverParent::~SessionStorageObserverParent() { 1308 MOZ_ASSERT(mActorDestroyed); 1309 1310 StorageObserver* observer = StorageObserver::Self(); 1311 if (observer) { 1312 observer->RemoveSink(this); 1313 } 1314 } 1315 1316 void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) { 1317 MOZ_ASSERT(NS_IsMainThread()); 1318 MOZ_ASSERT(!mActorDestroyed); 1319 1320 mActorDestroyed = true; 1321 } 1322 1323 mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() { 1324 MOZ_ASSERT(NS_IsMainThread()); 1325 MOZ_ASSERT(!mActorDestroyed); 1326 1327 IProtocol* mgr = Manager(); 1328 if (!PSessionStorageObserverParent::Send__delete__(this)) { 1329 return IPC_FAIL_NO_REASON(mgr); 1330 } 1331 return IPC_OK(); 1332 } 1333 1334 nsresult SessionStorageObserverParent::Observe( 1335 const char* aTopic, const nsAString& aOriginAttributesPattern, 1336 const nsACString& aOriginScope) { 1337 MOZ_ASSERT(NS_IsMainThread()); 1338 1339 if (!mActorDestroyed) { 1340 (void)SendObserve(nsDependentCString(aTopic), aOriginAttributesPattern, 1341 aOriginScope); 1342 } 1343 return NS_OK; 1344 } 1345 1346 SessionStorageCacheParent::SessionStorageCacheParent( 1347 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, 1348 const nsACString& aOriginKey, SessionStorageManagerParent* aActor) 1349 : mPrincipalInfo(aPrincipalInfo), 1350 mOriginKey(aOriginKey), 1351 mManagerActor(aActor) { 1352 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1353 MOZ_ASSERT(mManagerActor); 1354 } 1355 1356 SessionStorageCacheParent::~SessionStorageCacheParent() = default; 1357 1358 void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) { 1359 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1360 1361 mManagerActor = nullptr; 1362 } 1363 1364 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad( 1365 nsTArray<SSSetItemInfo>* aData) { 1366 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1367 MOZ_ASSERT(mManagerActor); 1368 1369 mLoadReceived.Flip(); 1370 1371 RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager(); 1372 MOZ_ASSERT(manager); 1373 1374 OriginAttributes attrs; 1375 MOZ_ALWAYS_TRUE( 1376 StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs)); 1377 1378 nsAutoCString originAttrs; 1379 attrs.CreateSuffix(originAttrs); 1380 1381 manager->CopyDataToContentProcess(originAttrs, mOriginKey, *aData); 1382 1383 return IPC_OK(); 1384 } 1385 1386 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint( 1387 nsTArray<SSWriteInfo>&& aWriteInfos) { 1388 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1389 MOZ_ASSERT(mManagerActor); 1390 1391 RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager(); 1392 MOZ_ASSERT(manager); 1393 1394 OriginAttributes attrs; 1395 StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs); 1396 1397 nsAutoCString originAttrs; 1398 attrs.CreateSuffix(originAttrs); 1399 1400 manager->UpdateData(originAttrs, mOriginKey, aWriteInfos); 1401 1402 return IPC_OK(); 1403 } 1404 1405 mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() { 1406 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1407 MOZ_ASSERT(mManagerActor); 1408 1409 mManagerActor = nullptr; 1410 1411 IProtocol* mgr = Manager(); 1412 if (!PBackgroundSessionStorageCacheParent::Send__delete__(this)) { 1413 return IPC_FAIL( 1414 mgr, "Failed to delete PBackgroundSessionStorageCacheParent actor"); 1415 } 1416 return IPC_OK(); 1417 } 1418 1419 SessionStorageManagerParent::SessionStorageManagerParent(uint64_t aTopContextId) 1420 : mBackgroundManager( 1421 BackgroundSessionStorageManager::GetOrCreate(aTopContextId)) { 1422 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1423 MOZ_ASSERT(mBackgroundManager); 1424 mBackgroundManager->AddParticipatingActor(this); 1425 } 1426 1427 SessionStorageManagerParent::~SessionStorageManagerParent() = default; 1428 1429 void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) { 1430 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1431 1432 if (mBackgroundManager) { 1433 mBackgroundManager->RemoveParticipatingActor(this); 1434 } 1435 1436 mBackgroundManager = nullptr; 1437 } 1438 1439 already_AddRefed<PBackgroundSessionStorageCacheParent> 1440 SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent( 1441 const PrincipalInfo& aPrincipalInfo, const nsACString& aOriginKey) { 1442 return MakeAndAddRef<SessionStorageCacheParent>(aPrincipalInfo, aOriginKey, 1443 this); 1444 } 1445 1446 BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager() 1447 const { 1448 return mBackgroundManager; 1449 } 1450 1451 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvClearStorages( 1452 const OriginAttributesPattern& aPattern, const nsACString& aOriginScope, 1453 const uint32_t& aMode) { 1454 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1455 mBackgroundManager->ClearStorages(aPattern, aOriginScope, 1456 static_cast<DomainMatchingMode>(aMode)); 1457 return IPC_OK(); 1458 } 1459 1460 mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() { 1461 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1462 MOZ_ASSERT(mBackgroundManager); 1463 1464 mBackgroundManager->RemoveParticipatingActor(this); 1465 1466 mBackgroundManager = nullptr; 1467 1468 IProtocol* mgr = Manager(); 1469 if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) { 1470 return IPC_FAIL( 1471 mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor"); 1472 } 1473 return IPC_OK(); 1474 } 1475 1476 /******************************************************************************* 1477 * Exported functions 1478 ******************************************************************************/ 1479 1480 PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent( 1481 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, 1482 const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) { 1483 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1484 1485 RefPtr<LocalStorageCacheParent> actor = new LocalStorageCacheParent( 1486 aPrincipalInfo, aOriginKey, aPrivateBrowsingId); 1487 1488 // Transfer ownership to IPDL. 1489 return actor.forget().take(); 1490 } 1491 1492 mozilla::ipc::IPCResult RecvPBackgroundLocalStorageCacheConstructor( 1493 mozilla::ipc::PBackgroundParent* aBackgroundActor, 1494 PBackgroundLocalStorageCacheParent* aActor, 1495 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, 1496 const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) { 1497 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1498 MOZ_ASSERT(aActor); 1499 1500 auto* actor = static_cast<LocalStorageCacheParent*>(aActor); 1501 1502 if (!gLocalStorageCacheParents) { 1503 gLocalStorageCacheParents = new LocalStorageCacheParentHashtable(); 1504 } 1505 1506 gLocalStorageCacheParents->GetOrInsertNew(aOriginKey)->AppendElement(actor); 1507 1508 // We are currently trusting the content process not to lie to us. It is 1509 // future work to consult the ClientManager to determine whether this is a 1510 // legitimate origin for the content process. 1511 1512 return IPC_OK(); 1513 } 1514 1515 bool DeallocPBackgroundLocalStorageCacheParent( 1516 PBackgroundLocalStorageCacheParent* aActor) { 1517 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1518 MOZ_ASSERT(aActor); 1519 1520 // Transfer ownership back from IPDL. 1521 RefPtr<LocalStorageCacheParent> actor = 1522 dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor)); 1523 1524 return true; 1525 } 1526 1527 PBackgroundStorageParent* AllocPBackgroundStorageParent( 1528 const nsAString& aProfilePath, const uint32_t& aPrivateBrowsingId) { 1529 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1530 1531 if (NS_WARN_IF(NextGenLocalStorageEnabled()) || 1532 NS_WARN_IF(aPrivateBrowsingId >= kPrivateBrowsingIdCount)) { 1533 return nullptr; 1534 } 1535 1536 return new StorageDBParent(aProfilePath, aPrivateBrowsingId); 1537 } 1538 1539 mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor( 1540 PBackgroundStorageParent* aActor, const nsAString& aProfilePath, 1541 const uint32_t& aPrivateBrowsingId) { 1542 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1543 MOZ_ASSERT(aActor); 1544 MOZ_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount); 1545 MOZ_ASSERT(!NextGenLocalStorageEnabled()); 1546 1547 auto* actor = static_cast<StorageDBParent*>(aActor); 1548 actor->Init(); 1549 return IPC_OK(); 1550 } 1551 1552 bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) { 1553 ::mozilla::ipc::AssertIsOnBackgroundThread(); 1554 MOZ_ASSERT(aActor); 1555 1556 StorageDBParent* actor = static_cast<StorageDBParent*>(aActor); 1557 actor->ReleaseIPDLReference(); 1558 return true; 1559 } 1560 1561 PSessionStorageObserverParent* AllocPSessionStorageObserverParent() { 1562 MOZ_ASSERT(NS_IsMainThread()); 1563 1564 RefPtr<SessionStorageObserverParent> actor = 1565 new SessionStorageObserverParent(); 1566 1567 // Transfer ownership to IPDL. 1568 return actor.forget().take(); 1569 } 1570 1571 bool RecvPSessionStorageObserverConstructor( 1572 PSessionStorageObserverParent* aActor) { 1573 MOZ_ASSERT(NS_IsMainThread()); 1574 MOZ_ASSERT(aActor); 1575 1576 return true; 1577 } 1578 1579 bool DeallocPSessionStorageObserverParent( 1580 PSessionStorageObserverParent* aActor) { 1581 MOZ_ASSERT(NS_IsMainThread()); 1582 MOZ_ASSERT(aActor); 1583 1584 // Transfer ownership back from IPDL. 1585 RefPtr<SessionStorageObserverParent> actor = 1586 dont_AddRef(static_cast<SessionStorageObserverParent*>(aActor)); 1587 1588 return true; 1589 } 1590 1591 already_AddRefed<PBackgroundSessionStorageManagerParent> 1592 AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) { 1593 return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId); 1594 } 1595 1596 } // namespace mozilla::dom