forked from mirrors/gecko-dev
Bug 1462162 - Filter local storage cache synchronization messages based on origin; r=asuth
This patch adds a new IPDL protocol PBackgroundLocalStorageCache. It is used by LocalStorageCache object to broadcast changes in local storage cache to other content processes. Each origin has its own PBackgroundLocalStorageCache, so now we can notify content processes that actually have a local storage cache for given origin. This greatly improves performance and reduces memory footprint especialy when local storage changes carry big strings and/or happen very quickly (before this patch all child processes were blindly notified).
This commit is contained in:
parent
5adedd4945
commit
5f8daf01d9
15 changed files with 626 additions and 147 deletions
|
|
@ -134,7 +134,7 @@ LocalStorage::SetItem(const nsAString& aKey, const nsAString& aData,
|
|||
}
|
||||
|
||||
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
||||
BroadcastChangeNotification(aKey, old, aData);
|
||||
OnChange(aKey, old, aData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ LocalStorage::RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
|
|||
}
|
||||
|
||||
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
||||
BroadcastChangeNotification(aKey, old, VoidString());
|
||||
OnChange(aKey, old, VoidString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,47 +172,24 @@ LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
||||
BroadcastChangeNotification(VoidString(), VoidString(), VoidString());
|
||||
OnChange(VoidString(), VoidString(), VoidString());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorage::BroadcastChangeNotification(const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue)
|
||||
LocalStorage::OnChange(const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue)
|
||||
{
|
||||
if (Principal()) {
|
||||
// We want to send a message to the parent in order to broadcast the
|
||||
// StorageEvent correctly to any child process.
|
||||
|
||||
PBackgroundChild* actor = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
PrincipalInfo principalInfo;
|
||||
nsresult rv = PrincipalToPrincipalInfo(Principal(), &principalInfo);
|
||||
if (!NS_WARN_IF(NS_FAILED(rv))) {
|
||||
Unused << NS_WARN_IF(!actor->SendBroadcastLocalStorageChange(
|
||||
mDocumentURI, nsString(aKey), nsString(aOldValue), nsString(aNewValue),
|
||||
principalInfo, mIsPrivate));
|
||||
}
|
||||
}
|
||||
|
||||
DispatchStorageEvent(mDocumentURI, aKey, aOldValue, aNewValue,
|
||||
Principal(), mIsPrivate, this, false);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
LocalStorage::DispatchStorageEvent(const nsAString& aDocumentURI,
|
||||
const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue,
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aIsPrivate,
|
||||
Storage* aStorage,
|
||||
bool aImmediateDispatch)
|
||||
{
|
||||
NotifyChange(aStorage, aPrincipal, aKey, aOldValue, aNewValue,
|
||||
u"localStorage", aDocumentURI, aIsPrivate, aImmediateDispatch);
|
||||
NotifyChange(/* aStorage */ this,
|
||||
Principal(),
|
||||
aKey,
|
||||
aOldValue,
|
||||
aNewValue,
|
||||
/* aStorageType */ u"localStorage",
|
||||
mDocumentURI,
|
||||
mIsPrivate,
|
||||
/* aImmediateDispatch */ false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ public:
|
|||
return mCache;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
DocumentURI() const
|
||||
{
|
||||
return mDocumentURI;
|
||||
}
|
||||
|
||||
bool PrincipalEquals(nsIPrincipal* aPrincipal);
|
||||
|
||||
LocalStorage(nsPIDOMWindowInner* aWindow,
|
||||
|
|
@ -77,24 +83,6 @@ public:
|
|||
|
||||
bool IsPrivate() const { return mIsPrivate; }
|
||||
|
||||
// aStorage can be null if this method is called by ContentChild.
|
||||
//
|
||||
// aImmediateDispatch is for use by (main-thread) IPC code so that PContent
|
||||
// ordering can be maintained. Without this, the event would be enqueued and
|
||||
// run in a future turn of the event loop, potentially allowing other PContent
|
||||
// Recv* methods to trigger script that wants to assume our localstorage
|
||||
// changes have already been applied. This is the case for message manager
|
||||
// messages which are used by ContentTask testing logic and webextensions.
|
||||
static void
|
||||
DispatchStorageEvent(const nsAString& aDocumentURI,
|
||||
const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue,
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aIsPrivate,
|
||||
Storage* aStorage,
|
||||
bool aImmediateDispatch);
|
||||
|
||||
void
|
||||
ApplyEvent(StorageEvent* aStorageEvent);
|
||||
|
||||
|
|
@ -115,9 +103,9 @@ private:
|
|||
// Whether this storage is running in private-browsing window.
|
||||
bool mIsPrivate : 1;
|
||||
|
||||
void BroadcastChangeNotification(const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue);
|
||||
void OnChange(const nsAString& aKey,
|
||||
const nsAString& aOldValue,
|
||||
const nsAString& aNewValue);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ NS_IMETHODIMP_(void) LocalStorageCacheBridge::Release(void)
|
|||
// LocalStorageCache
|
||||
|
||||
LocalStorageCache::LocalStorageCache(const nsACString* aOriginNoSuffix)
|
||||
: mOriginNoSuffix(*aOriginNoSuffix)
|
||||
: mActor(nullptr)
|
||||
, mOriginNoSuffix(*aOriginNoSuffix)
|
||||
, mMonitor("LocalStorageCache")
|
||||
, mLoaded(false)
|
||||
, mLoadResult(NS_OK)
|
||||
|
|
@ -89,6 +90,11 @@ LocalStorageCache::LocalStorageCache(const nsACString* aOriginNoSuffix)
|
|||
|
||||
LocalStorageCache::~LocalStorageCache()
|
||||
{
|
||||
if (mActor) {
|
||||
mActor->SendDeleteMeInternal();
|
||||
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
|
||||
if (mManager) {
|
||||
mManager->DropCache(this);
|
||||
}
|
||||
|
|
@ -96,6 +102,16 @@ LocalStorageCache::~LocalStorageCache()
|
|||
MOZ_COUNT_DTOR(LocalStorageCache);
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorageCache::SetActor(LocalStorageCacheChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mActor);
|
||||
|
||||
mActor = aActor;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
LocalStorageCache::Release(void)
|
||||
{
|
||||
|
|
@ -152,6 +168,28 @@ LocalStorageCache::Init(LocalStorageManager* aManager,
|
|||
mUsage = aManager->GetOriginUsage(mQuotaOriginScope);
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorageCache::NotifyObservers(const LocalStorage* aStorage,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aStorage);
|
||||
|
||||
if (!mActor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We want to send a message to the parent in order to broadcast the
|
||||
// StorageEvent correctly to any child process.
|
||||
|
||||
Unused << mActor->SendNotify(aStorage->DocumentURI(),
|
||||
aKey,
|
||||
aOldValue,
|
||||
aNewValue);
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalStorageCache::Persist(const LocalStorage* aStorage) const
|
||||
{
|
||||
|
|
@ -401,7 +439,13 @@ LocalStorageCache::SetItem(const LocalStorage* aStorage, const nsAString& aKey,
|
|||
|
||||
data.mKeys.Put(aKey, aValue);
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage)) {
|
||||
if (aSource != ContentMutation) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NotifyObservers(aStorage, nsString(aKey), aOld, aValue);
|
||||
|
||||
if (Persist(aStorage)) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
|
|
@ -443,7 +487,13 @@ LocalStorageCache::RemoveItem(const LocalStorage* aStorage,
|
|||
Unused << ProcessUsageDelta(aStorage, delta, aSource);
|
||||
data.mKeys.Remove(aKey);
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage)) {
|
||||
if (aSource != ContentMutation) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NotifyObservers(aStorage, nsString(aKey), aOld, VoidString());
|
||||
|
||||
if (Persist(aStorage)) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
|
|
@ -485,7 +535,15 @@ LocalStorageCache::Clear(const LocalStorage* aStorage,
|
|||
data.mKeys.Clear();
|
||||
}
|
||||
|
||||
if (aSource == ContentMutation && Persist(aStorage) && (refresh || hadData)) {
|
||||
if (aSource != ContentMutation) {
|
||||
return hadData ? NS_OK : NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
|
||||
if (hadData) {
|
||||
NotifyObservers(aStorage, VoidString(), VoidString(), VoidString());
|
||||
}
|
||||
|
||||
if (Persist(aStorage) && (refresh || hadData)) {
|
||||
StorageDBChild* storageChild = StorageDBChild::Get();
|
||||
if (!storageChild) {
|
||||
NS_ERROR("Writing to localStorage after the database has been shut down"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
class LocalStorage;
|
||||
class LocalStorageCacheChild;
|
||||
class LocalStorageManager;
|
||||
class StorageUsage;
|
||||
class StorageDBBridge;
|
||||
|
|
@ -76,6 +77,23 @@ protected:
|
|||
class LocalStorageCache : public LocalStorageCacheBridge
|
||||
{
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(LocalStorage);
|
||||
}
|
||||
|
||||
void
|
||||
SetActor(LocalStorageCacheChild* aActor);
|
||||
|
||||
void
|
||||
ClearActor()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(void) Release(void) override;
|
||||
|
||||
enum MutationSource {
|
||||
|
|
@ -181,6 +199,13 @@ private:
|
|||
// Helper to get one of the 3 data sets (regular, private, session)
|
||||
Data& DataSet(const LocalStorage* aStorage);
|
||||
|
||||
// Used for firing storage events and synchronization of caches in other
|
||||
// content processes.
|
||||
void NotifyObservers(const LocalStorage* aStorage,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue);
|
||||
|
||||
// Whether the storage change is about to persist
|
||||
bool Persist(const LocalStorage* aStorage) const;
|
||||
|
||||
|
|
@ -210,6 +235,14 @@ private:
|
|||
// Obtained from the manager during initialization (Init method).
|
||||
RefPtr<StorageUsage> mUsage;
|
||||
|
||||
// The LocalStorageCacheChild is created at the same time of this class.
|
||||
// In normal operation, the actor will be synchronously cleared in our
|
||||
// destructor when we tell it to delete itself. In a shutdown-related edge
|
||||
// case in the parent process for JSM's, it is possible for the actor to be
|
||||
// destroyed while this class remains alive, in which case it will be nulled
|
||||
// out.
|
||||
LocalStorageCacheChild* mActor;
|
||||
|
||||
// The origin this cache belongs to in the "DB format", i.e. reversed
|
||||
nsCString mOriginNoSuffix;
|
||||
|
||||
|
|
|
|||
|
|
@ -246,9 +246,38 @@ LocalStorageManager::GetStorageInternal(CreateMode aCreateMode,
|
|||
}
|
||||
}
|
||||
|
||||
PBackgroundChild* backgroundActor =
|
||||
BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!backgroundActor)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PrincipalInfo principalInfo;
|
||||
rv = mozilla::ipc::PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t privateBrowsingId;
|
||||
rv = aPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// There is always a single instance of a cache per scope
|
||||
// in a single instance of a DOM storage manager.
|
||||
cache = PutCache(originAttrSuffix, originKey, aPrincipal);
|
||||
|
||||
LocalStorageCacheChild* actor = new LocalStorageCacheChild(cache);
|
||||
|
||||
MOZ_ALWAYS_TRUE(
|
||||
backgroundActor->SendPBackgroundLocalStorageCacheConstructor(
|
||||
actor,
|
||||
principalInfo,
|
||||
originKey,
|
||||
privateBrowsingId));
|
||||
|
||||
cache->SetActor(actor);
|
||||
}
|
||||
|
||||
if (aRetval) {
|
||||
|
|
|
|||
41
dom/storage/PBackgroundLocalStorageCache.ipdl
Normal file
41
dom/storage/PBackgroundLocalStorageCache.ipdl
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
|
||||
include PBackgroundSharedTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
async protocol PBackgroundLocalStorageCache
|
||||
{
|
||||
manager PBackground;
|
||||
|
||||
parent:
|
||||
async DeleteMe();
|
||||
|
||||
async Notify(nsString documentURI,
|
||||
nsString key,
|
||||
nsString oldValue,
|
||||
nsString newValue);
|
||||
|
||||
child:
|
||||
// The principalInfo and privateBrowsingId could instead be retained by the
|
||||
// LocalStorageCacheChild/LocalStorageCache instead of being re-transmitted.
|
||||
// However, these changes are a temporary optimization intended for uplift,
|
||||
// and this constant factor overhead is very small compared to the upside of
|
||||
// filtering.
|
||||
async Observe(PrincipalInfo principalInfo,
|
||||
uint32_t privateBrowsingId,
|
||||
nsString documentURI,
|
||||
nsString key,
|
||||
nsString oldValue,
|
||||
nsString newValue);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
@ -111,6 +111,15 @@ public:
|
|||
|
||||
bool IsSessionOnly() const { return mIsSessionOnly; }
|
||||
|
||||
// aStorage can be null if this method is called by LocalStorageCacheChild.
|
||||
//
|
||||
// aImmediateDispatch is for use by child IPC code (LocalStorageCacheChild)
|
||||
// so that PBackground ordering can be maintained. Without this, the event
|
||||
// would be/ enqueued and run in a future turn of the event loop, potentially
|
||||
// allowing other PBackground Recv* methods to trigger script that wants to
|
||||
// assume our localstorage changes have already been applied. This is the
|
||||
// case for message manager messages which are used by ContentTask testing
|
||||
// logic and webextensions.
|
||||
static void
|
||||
NotifyChange(Storage* aStorage, nsIPrincipal* aPrincipal,
|
||||
const nsAString& aKey, const nsAString& aOldValue,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ namespace dom {
|
|||
|
||||
namespace {
|
||||
|
||||
typedef nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>
|
||||
LocalStorageCacheParentHashtable;
|
||||
|
||||
StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents;
|
||||
|
||||
StorageDBChild* sStorageChild = nullptr;
|
||||
|
||||
// False until we shut the storage child down.
|
||||
|
|
@ -30,6 +35,77 @@ bool sStorageChildDown = false;
|
|||
|
||||
}
|
||||
|
||||
LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache)
|
||||
: mCache(aCache)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aCache);
|
||||
aCache->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(LocalStorageCacheChild);
|
||||
}
|
||||
|
||||
LocalStorageCacheChild::~LocalStorageCacheChild()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(LocalStorageCacheChild);
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorageCacheChild::SendDeleteMeInternal()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mCache) {
|
||||
mCache->ClearActor();
|
||||
mCache = nullptr;
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mCache) {
|
||||
mCache->ClearActor();
|
||||
mCache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
LocalStorageCacheChild::RecvObserve(const PrincipalInfo& aPrincipalInfo,
|
||||
const uint32_t& aPrivateBrowsingId,
|
||||
const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
Storage::NotifyChange(/* aStorage */ nullptr,
|
||||
principal,
|
||||
aKey,
|
||||
aOldValue,
|
||||
aNewValue,
|
||||
/* aStorageType */ u"localStorage",
|
||||
aDocumentURI,
|
||||
/* aIsPrivate */ !!aPrivateBrowsingId,
|
||||
/* aImmediateDispatch */ true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Child
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -396,6 +472,88 @@ ShutdownObserver::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
LocalStorageCacheParent::LocalStorageCacheParent(
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsACString& aOriginKey,
|
||||
uint32_t aPrivateBrowsingId)
|
||||
: mPrincipalInfo(aPrincipalInfo)
|
||||
, mOriginKey(aOriginKey)
|
||||
, mPrivateBrowsingId(aPrivateBrowsingId)
|
||||
, mActorDestroyed(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
LocalStorageCacheParent::~LocalStorageCacheParent()
|
||||
{
|
||||
MOZ_ASSERT(mActorDestroyed);
|
||||
}
|
||||
|
||||
void
|
||||
LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
||||
mActorDestroyed = true;
|
||||
|
||||
MOZ_ASSERT(gLocalStorageCacheParents);
|
||||
|
||||
nsTArray<LocalStorageCacheParent*>* array;
|
||||
gLocalStorageCacheParents->Get(mOriginKey, &array);
|
||||
MOZ_ASSERT(array);
|
||||
|
||||
array->RemoveElement(this);
|
||||
|
||||
if (array->IsEmpty()) {
|
||||
gLocalStorageCacheParents->Remove(mOriginKey);
|
||||
}
|
||||
|
||||
if (!gLocalStorageCacheParents->Count()) {
|
||||
gLocalStorageCacheParents = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
LocalStorageCacheParent::RecvDeleteMe()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
||||
IProtocol* mgr = Manager();
|
||||
if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) {
|
||||
return IPC_FAIL_NO_REASON(mgr);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
LocalStorageCacheParent::RecvNotify(const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(gLocalStorageCacheParents);
|
||||
|
||||
nsTArray<LocalStorageCacheParent*>* array;
|
||||
gLocalStorageCacheParents->Get(mOriginKey, &array);
|
||||
MOZ_ASSERT(array);
|
||||
|
||||
for (LocalStorageCacheParent* localStorageCacheParent : *array) {
|
||||
if (localStorageCacheParent != this) {
|
||||
Unused << localStorageCacheParent->SendObserve(mPrincipalInfo,
|
||||
mPrivateBrowsingId,
|
||||
aDocumentURI,
|
||||
aKey,
|
||||
aOldValue,
|
||||
aNewValue);
|
||||
}
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Parent
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -1228,6 +1386,66 @@ ObserverSink::Observe(const char* aTopic,
|
|||
* Exported functions
|
||||
******************************************************************************/
|
||||
|
||||
PBackgroundLocalStorageCacheParent*
|
||||
AllocPBackgroundLocalStorageCacheParent(
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<LocalStorageCacheParent> actor =
|
||||
new LocalStorageCacheParent(aPrincipalInfo, aOriginKey, aPrivateBrowsingId);
|
||||
|
||||
// Transfer ownership to IPDL.
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvPBackgroundLocalStorageCacheConstructor(
|
||||
mozilla::ipc::PBackgroundParent* aBackgroundActor,
|
||||
PBackgroundLocalStorageCacheParent* aActor,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
auto* actor = static_cast<LocalStorageCacheParent*>(aActor);
|
||||
|
||||
if (!gLocalStorageCacheParents) {
|
||||
gLocalStorageCacheParents = new LocalStorageCacheParentHashtable();
|
||||
}
|
||||
|
||||
nsTArray<LocalStorageCacheParent*>* array;
|
||||
if (!gLocalStorageCacheParents->Get(aOriginKey, &array)) {
|
||||
array = new nsTArray<LocalStorageCacheParent*>();
|
||||
gLocalStorageCacheParents->Put(aOriginKey, array);
|
||||
}
|
||||
array->AppendElement(actor);
|
||||
|
||||
// We are currently trusting the content process not to lie to us. It is
|
||||
// future work to consult the ClientManager to determine whether this is a
|
||||
// legitimate origin for the content process.
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
DeallocPBackgroundLocalStorageCacheParent(
|
||||
PBackgroundLocalStorageCacheParent* aActor)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
// Transfer ownership back from IPDL.
|
||||
RefPtr<LocalStorageCacheParent> actor =
|
||||
dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PBackgroundStorageParent*
|
||||
AllocPBackgroundStorageParent(const nsString& aProfilePath)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef mozilla_dom_StorageIPC_h
|
||||
#define mozilla_dom_StorageIPC_h
|
||||
|
||||
#include "mozilla/dom/PBackgroundLocalStorageCacheChild.h"
|
||||
#include "mozilla/dom/PBackgroundLocalStorageCacheParent.h"
|
||||
#include "mozilla/dom/PBackgroundStorageChild.h"
|
||||
#include "mozilla/dom/PBackgroundStorageParent.h"
|
||||
#include "StorageDBThread.h"
|
||||
|
|
@ -19,11 +21,65 @@ namespace mozilla {
|
|||
|
||||
class OriginAttributesPattern;
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class BackgroundChildImpl;
|
||||
class PrincipalInfo;
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
|
||||
class LocalStorageManager;
|
||||
class PBackgroundStorageParent;
|
||||
|
||||
class LocalStorageCacheChild final
|
||||
: public PBackgroundLocalStorageCacheChild
|
||||
{
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
friend class LocalStorageCache;
|
||||
friend class LocalStorageManager;
|
||||
|
||||
// LocalStorageCache effectively owns this instance, although IPC handles its
|
||||
// allocation/deallocation. When the LocalStorageCache destructor runs, it
|
||||
// will invoke SendDeleteMeInternal() which will trigger both instances to
|
||||
// drop their mutual references and cause IPC to destroy the actor after the
|
||||
// DeleteMe round-trip.
|
||||
LocalStorageCache* MOZ_NON_OWNING_REF mCache;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(LocalStorageCacheChild);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only created by LocalStorageManager.
|
||||
explicit LocalStorageCacheChild(LocalStorageCache* aCache);
|
||||
|
||||
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
|
||||
~LocalStorageCacheChild();
|
||||
|
||||
// Only called by LocalStorageCache.
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvObserve(const PrincipalInfo& aPrincipalInfo,
|
||||
const uint32_t& aPrivateBrowsingId,
|
||||
const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue) override;
|
||||
};
|
||||
|
||||
// Child side of the IPC protocol, exposes as DB interface but
|
||||
// is responsible to send all requests to the parent process
|
||||
// and expects asynchronous answers. Those are then transparently
|
||||
|
|
@ -126,6 +182,39 @@ private:
|
|||
bool mIPCOpen;
|
||||
};
|
||||
|
||||
class LocalStorageCacheParent final
|
||||
: public PBackgroundLocalStorageCacheParent
|
||||
{
|
||||
const PrincipalInfo mPrincipalInfo;
|
||||
const nsCString mOriginKey;
|
||||
uint32_t mPrivateBrowsingId;
|
||||
bool mActorDestroyed;
|
||||
|
||||
public:
|
||||
// Created in AllocPBackgroundLocalStorageCacheParent.
|
||||
LocalStorageCacheParent(const PrincipalInfo& aPrincipalInfo,
|
||||
const nsACString& aOriginKey,
|
||||
uint32_t aPrivateBrowsingId);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::LocalStorageCacheParent)
|
||||
|
||||
private:
|
||||
// Reference counted.
|
||||
~LocalStorageCacheParent();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvDeleteMe() override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvNotify(const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue) override;
|
||||
};
|
||||
|
||||
// Receives async requests from child processes and is responsible
|
||||
// to send back responses from the DB thread. Exposes as a fake
|
||||
|
|
@ -283,6 +372,24 @@ private:
|
|||
bool mIPCOpen;
|
||||
};
|
||||
|
||||
PBackgroundLocalStorageCacheParent*
|
||||
AllocPBackgroundLocalStorageCacheParent(
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId);
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvPBackgroundLocalStorageCacheConstructor(
|
||||
mozilla::ipc::PBackgroundParent* aBackgroundActor,
|
||||
PBackgroundLocalStorageCacheParent* aActor,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId);
|
||||
|
||||
bool
|
||||
DeallocPBackgroundLocalStorageCacheParent(
|
||||
PBackgroundLocalStorageCacheParent* aActor);
|
||||
|
||||
PBackgroundStorageParent*
|
||||
AllocPBackgroundStorageParent(const nsString& aProfilePath);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PBackgroundLocalStorageCache.ipdl',
|
||||
'PBackgroundStorage.ipdl',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,26 @@ BackgroundChildImpl::DeallocPBackgroundIndexedDBUtilsChild(
|
|||
return true;
|
||||
}
|
||||
|
||||
BackgroundChildImpl::PBackgroundLocalStorageCacheChild*
|
||||
BackgroundChildImpl::AllocPBackgroundLocalStorageCacheChild(
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
{
|
||||
MOZ_CRASH("PBackgroundLocalStorageChild actors should be manually "
|
||||
"constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPBackgroundLocalStorageCacheChild(
|
||||
PBackgroundLocalStorageCacheChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
BackgroundChildImpl::PBackgroundStorageChild*
|
||||
BackgroundChildImpl::AllocPBackgroundStorageChild(const nsString& aProfilePath)
|
||||
{
|
||||
|
|
@ -715,32 +735,6 @@ BackgroundChildImpl::DeallocPServiceWorkerRegistrationChild(PServiceWorkerRegist
|
|||
return dom::DeallocServiceWorkerRegistrationChild(aActor);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundChildImpl::RecvDispatchLocalStorageChange(
|
||||
const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const bool& aIsPrivate)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
LocalStorage::DispatchStorageEvent(aDocumentURI, aKey, aOldValue, aNewValue,
|
||||
principal, aIsPrivate, nullptr, true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -70,6 +70,17 @@ protected:
|
|||
DeallocPBackgroundIndexedDBUtilsChild(PBackgroundIndexedDBUtilsChild* aActor)
|
||||
override;
|
||||
|
||||
virtual PBackgroundLocalStorageCacheChild*
|
||||
AllocPBackgroundLocalStorageCacheChild(const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundLocalStorageCacheChild(
|
||||
PBackgroundLocalStorageCacheChild* aActor)
|
||||
override;
|
||||
|
||||
virtual PBackgroundStorageChild*
|
||||
AllocPBackgroundStorageChild(const nsString& aProfilePath) override;
|
||||
|
||||
|
|
@ -227,14 +238,6 @@ protected:
|
|||
virtual bool
|
||||
DeallocPHttpBackgroundChannelChild(PHttpBackgroundChannelChild* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvDispatchLocalStorageChange(const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const bool& aIsPrivate) override;
|
||||
|
||||
bool
|
||||
GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,52 @@ BackgroundParentImpl::RecvFlushPendingFileDeletions()
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
BackgroundParentImpl::PBackgroundLocalStorageCacheParent*
|
||||
BackgroundParentImpl::AllocPBackgroundLocalStorageCacheParent(
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return
|
||||
mozilla::dom::AllocPBackgroundLocalStorageCacheParent(aPrincipalInfo,
|
||||
aOriginKey,
|
||||
aPrivateBrowsingId);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvPBackgroundLocalStorageCacheConstructor(
|
||||
PBackgroundLocalStorageCacheParent* aActor,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
return
|
||||
mozilla::dom::RecvPBackgroundLocalStorageCacheConstructor(
|
||||
this,
|
||||
aActor,
|
||||
aPrincipalInfo,
|
||||
aOriginKey,
|
||||
aPrivateBrowsingId);
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPBackgroundLocalStorageCacheParent(
|
||||
PBackgroundLocalStorageCacheParent* aActor)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
return mozilla::dom::DeallocPBackgroundLocalStorageCacheParent(aActor);
|
||||
}
|
||||
|
||||
auto
|
||||
BackgroundParentImpl::AllocPBackgroundStorageParent(const nsString& aProfilePath)
|
||||
-> PBackgroundStorageParent*
|
||||
|
|
@ -285,34 +331,6 @@ BackgroundParentImpl::DeallocPBackgroundStorageParent(
|
|||
return mozilla::dom::DeallocPBackgroundStorageParent(aActor);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvBroadcastLocalStorageChange(
|
||||
const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const bool& aIsPrivate)
|
||||
{
|
||||
// Let's inform the StorageActivityService about this change.
|
||||
dom::StorageActivityService::SendActivity(aPrincipalInfo);
|
||||
|
||||
nsTArray<PBackgroundParent*> liveActorArray;
|
||||
if (NS_WARN_IF(!BackgroundParent::GetLiveActorArray(this, liveActorArray))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
for (auto* liveActor : liveActorArray) {
|
||||
if (liveActor != this) {
|
||||
Unused << liveActor->SendDispatchLocalStorageChange(
|
||||
nsString(aDocumentURI), nsString(aKey), nsString(aOldValue),
|
||||
nsString(aNewValue), aPrincipalInfo, aIsPrivate);
|
||||
}
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PPendingIPCBlobParent*
|
||||
BackgroundParentImpl::AllocPPendingIPCBlobParent(const IPCBlob& aBlob)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,6 +63,25 @@ protected:
|
|||
virtual mozilla::ipc::IPCResult
|
||||
RecvFlushPendingFileDeletions() override;
|
||||
|
||||
virtual PBackgroundLocalStorageCacheParent*
|
||||
AllocPBackgroundLocalStorageCacheParent(const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPBackgroundLocalStorageCacheConstructor(
|
||||
PBackgroundLocalStorageCacheParent* aActor,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey,
|
||||
const uint32_t& aPrivateBrowsingId)
|
||||
override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundLocalStorageCacheParent(
|
||||
PBackgroundLocalStorageCacheParent* aActor)
|
||||
override;
|
||||
|
||||
virtual PBackgroundStorageParent*
|
||||
AllocPBackgroundStorageParent(const nsString& aProfilePath) override;
|
||||
|
||||
|
|
@ -73,14 +92,6 @@ protected:
|
|||
virtual bool
|
||||
DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvBroadcastLocalStorageChange(const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const bool& aIsPrivate) override;
|
||||
|
||||
virtual PPendingIPCBlobParent*
|
||||
AllocPPendingIPCBlobParent(const IPCBlob& aBlob) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
include protocol PAsmJSCacheEntry;
|
||||
include protocol PBackgroundIDBFactory;
|
||||
include protocol PBackgroundIndexedDBUtils;
|
||||
include protocol PBackgroundLocalStorageCache;
|
||||
include protocol PBackgroundStorage;
|
||||
include protocol PBackgroundTest;
|
||||
include protocol PBroadcastChannel;
|
||||
|
|
@ -65,6 +66,7 @@ sync protocol PBackground
|
|||
manages PAsmJSCacheEntry;
|
||||
manages PBackgroundIDBFactory;
|
||||
manages PBackgroundIndexedDBUtils;
|
||||
manages PBackgroundLocalStorageCache;
|
||||
manages PBackgroundStorage;
|
||||
manages PBackgroundTest;
|
||||
manages PBroadcastChannel;
|
||||
|
|
@ -106,14 +108,11 @@ parent:
|
|||
// Use only for testing!
|
||||
async FlushPendingFileDeletions();
|
||||
|
||||
async PBackgroundStorage(nsString profilePath);
|
||||
async PBackgroundLocalStorageCache(PrincipalInfo principalInfo,
|
||||
nsCString originKey,
|
||||
uint32_t privateBrowsingId);
|
||||
|
||||
async BroadcastLocalStorageChange(nsString documentURI,
|
||||
nsString key,
|
||||
nsString oldValue,
|
||||
nsString newValue,
|
||||
PrincipalInfo principalInfo,
|
||||
bool isPrivate);
|
||||
async PBackgroundStorage(nsString profilePath);
|
||||
|
||||
async PVsync();
|
||||
|
||||
|
|
@ -175,13 +174,6 @@ child:
|
|||
|
||||
async PPendingIPCBlob(IPCBlob blob);
|
||||
|
||||
async DispatchLocalStorageChange(nsString documentURI,
|
||||
nsString key,
|
||||
nsString oldValue,
|
||||
nsString newValue,
|
||||
PrincipalInfo principalInfo,
|
||||
bool isPrivate);
|
||||
|
||||
both:
|
||||
// PIPCBlobInputStream is created on the parent side only if the child starts
|
||||
// a migration.
|
||||
|
|
|
|||
Loading…
Reference in a new issue