зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1654080 - Use PBackground for syncing SessionStorageCache and use LSWriteOptimizer to send data changes; r=dom-workers-and-storage-reviewers,janv,nika
This patch does: - Use LSWriteOptimizer - Remove SessionStorageService since it's unused. - Move IPC from PContent to PBackground (by SessionStorageManager{Child, Parent} and SessionStorageCache{Child, Parent}). - Extract SessionStorageManagerBase and add PBackgroundSessionStorageManager. - Expose a getter function to get a BackgroundParentManager for top context id on the parent. IPC - Before this patch: - Copy from parent while loading a document. - Mark cache entry on the parent process as loaded by the child id. - Update change on checkpoint. - Unmark cache entry on the parent process as unloaded for the child id while the parent actor is destorying. - After this patch: - Sync IPC load in the first SessionStorage operation. - Update change on checkpoint `BackgroundSessionStorageManager`'s lifecycle on the parent process. - Create by `SessionStorageManagerParent` and register to the `sManagers`. - Hold by `SessionStorageManagerParent` and `sManagers`. - Remove from the `sManagers` while the corresponding `BrowsingContext` is destructed (on the parent process). Depends on D89341 Differential Revision: https://phabricator.services.mozilla.com/D89342
This commit is contained in:
Родитель
4ca9a505c9
Коммит
45a97b5b83
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/dom/MediaControlService.h"
|
||||
#include "mozilla/dom/ContentPlaybackController.h"
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/net/DocumentLoadListener.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
@ -744,6 +745,10 @@ void CanonicalBrowsingContext::CanonicalDiscard() {
|
|||
mTabMediaController->Shutdown();
|
||||
mTabMediaController = nullptr;
|
||||
}
|
||||
|
||||
if (IsTop()) {
|
||||
BackgroundSessionStorageManager::RemoveManager(Id());
|
||||
}
|
||||
}
|
||||
|
||||
void CanonicalBrowsingContext::NotifyStartDelayedAutoplayMedia() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 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 "mozilla/dom/PGamepadEventChannelChild.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
#ifndef mozilla_dom_GamepadEventChannelChild_h_
|
||||
# define mozilla_dom_GamepadEventChannelChild_h_
|
||||
|
|
|
@ -3538,20 +3538,6 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateMediaControlAction(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvSessionStorageData(
|
||||
const uint64_t aTopContextId, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData) {
|
||||
if (const RefPtr<BrowsingContext> topContext =
|
||||
BrowsingContext::Get(aTopContextId)) {
|
||||
topContext->GetSessionStorageManager()->LoadSessionStorageData(
|
||||
nullptr, aOriginAttrs, aOriginKey, aDefaultData, aSessionData);
|
||||
} else {
|
||||
NS_WARNING("Got session storage data for a discarded session");
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvOnAllowAccessFor(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,
|
||||
|
|
|
@ -649,11 +649,6 @@ class ContentChild final : public PContentChild,
|
|||
return mBrowsingContextFieldEpoch;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvSessionStorageData(
|
||||
uint64_t aTopContextId, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvOnAllowAccessFor(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,
|
||||
|
|
|
@ -5818,11 +5818,6 @@ nsresult ContentParent::AboutToLoadHttpFtpDocumentForChild(
|
|||
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (browsingContext && !browsingContext->IsDiscarded()) {
|
||||
browsingContext->GetSessionStorageManager()
|
||||
->SendSessionStorageDataToContentProcess(this, principal);
|
||||
}
|
||||
|
||||
if (!NextGenLocalStorageEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -6404,20 +6399,6 @@ mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
|
|||
#endif // defined(XP_WIN)
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvSessionStorageData(
|
||||
const uint64_t aTopContextId, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData) {
|
||||
if (const RefPtr<BrowsingContext> topContext =
|
||||
BrowsingContext::Get(aTopContextId)) {
|
||||
topContext->GetSessionStorageManager()->LoadSessionStorageData(
|
||||
this, aOriginAttrs, aOriginKey, aDefaultData, aSessionData);
|
||||
} else {
|
||||
NS_WARNING("Got session storage data for a discarded session");
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
|
||||
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
|
||||
RefPtr<WindowGlobalParent> parent;
|
||||
|
|
|
@ -1321,11 +1321,6 @@ class ContentParent final
|
|||
ModulePaths&& aModPaths, bool aRunAtNormalPriority,
|
||||
GetModulesTrustResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSessionStorageData(
|
||||
uint64_t aTopContextId, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvReportServiceWorkerShutdownProgress(
|
||||
uint32_t aShutdownStateId,
|
||||
ServiceWorkerShutdownState::Progress aProgress);
|
||||
|
|
|
@ -365,12 +365,6 @@ struct PostMessageData
|
|||
uint64_t innerWindowId;
|
||||
};
|
||||
|
||||
struct KeyValuePair
|
||||
{
|
||||
nsString key;
|
||||
nsString value;
|
||||
};
|
||||
|
||||
union SyncedContextInitializer
|
||||
{
|
||||
BrowsingContextInitializer;
|
||||
|
@ -1790,13 +1784,6 @@ both:
|
|||
ClonedOrErrorMessageData aMessage,
|
||||
PostMessageData aData);
|
||||
|
||||
/**
|
||||
* Move sessionStorage data between parent and content processes. See
|
||||
* SessionStorageManager documentation for more details.
|
||||
*/
|
||||
async SessionStorageData(uint64_t aTopContextId, nsCString aOriginAttrs,
|
||||
nsCString aOriginKey, KeyValuePair[] aDefaultData,
|
||||
KeyValuePair[] aSessionData);
|
||||
async CommitWindowContextTransaction(MaybeDiscardedWindowContext aContext,
|
||||
WindowContextTransaction aTransaction,
|
||||
uint64_t aEpoch);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ClientManagerService.h"
|
||||
#include "mozilla/dom/FlippedOnce.h"
|
||||
#include "mozilla/dom/LSWriteOptimizer.h"
|
||||
#include "mozilla/dom/LSWriteOptimizerImpl.h"
|
||||
#include "mozilla/dom/PBackgroundLSDatabaseParent.h"
|
||||
#include "mozilla/dom/PBackgroundLSObserverParent.h"
|
||||
#include "mozilla/dom/PBackgroundLSRequestParent.h"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "ActorsChild.h"
|
||||
#include "LocalStorageCommon.h"
|
||||
#include "LSDatabase.h"
|
||||
#include "LSWriteOptimizer.h"
|
||||
#include "LSWriteOptimizerImpl.h"
|
||||
#include "mozilla/dom/PBackgroundLSSnapshot.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
|
|
|
@ -63,52 +63,5 @@ void LSWriteOptimizerBase::GetSortedWriteInfos(
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void LSWriteOptimizer<T, U>::InsertItem(const nsAString& aKey, const T& aValue,
|
||||
int64_t aDelta) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
WriteInfo* existingWriteInfo;
|
||||
UniquePtr<WriteInfo> newWriteInfo;
|
||||
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
|
||||
existingWriteInfo->GetType() == WriteInfo::DeleteItem) {
|
||||
// We could just simply replace the deletion with ordinary update, but that
|
||||
// would preserve item's original position/index. Imagine a case when we
|
||||
// have only one existing key k1. Now let's create a new optimizer and
|
||||
// remove k1, add k2 and add k1 back. The final order should be k2, k1
|
||||
// (ordinary update would produce k1, k2). So we need to differentiate
|
||||
// between normal update and "optimized" update which resulted from a
|
||||
// deletion followed by an insertion. We use the UpdateWithMove flag for
|
||||
// this.
|
||||
|
||||
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
|
||||
/* aUpdateWithMove */ true);
|
||||
} else {
|
||||
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
|
||||
}
|
||||
mWriteInfos.Put(aKey, std::move(newWriteInfo));
|
||||
|
||||
mTotalDelta += aDelta;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void LSWriteOptimizer<T, U>::UpdateItem(const nsAString& aKey, const T& aValue,
|
||||
int64_t aDelta) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
WriteInfo* existingWriteInfo;
|
||||
UniquePtr<WriteInfo> newWriteInfo;
|
||||
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
|
||||
existingWriteInfo->GetType() == WriteInfo::InsertItem) {
|
||||
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
|
||||
} else {
|
||||
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
|
||||
/* aUpdateWithMove */ false);
|
||||
}
|
||||
mWriteInfos.Put(aKey, std::move(newWriteInfo));
|
||||
|
||||
mTotalDelta += aDelta;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_localstorage_LSWriteOptimizerImpl_h
|
||||
#define mozilla_dom_localstorage_LSWriteOptimizerImpl_h
|
||||
|
||||
#include "LSWriteOptimizer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
template <typename T, typename U>
|
||||
void LSWriteOptimizer<T, U>::InsertItem(const nsAString& aKey, const T& aValue,
|
||||
int64_t aDelta) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
WriteInfo* existingWriteInfo;
|
||||
UniquePtr<WriteInfo> newWriteInfo;
|
||||
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
|
||||
existingWriteInfo->GetType() == WriteInfo::DeleteItem) {
|
||||
// We could just simply replace the deletion with ordinary update, but
|
||||
// that
|
||||
// would preserve item's original position/index. Imagine a case when we
|
||||
// have only one existing key k1. Now let's create a new optimizer and
|
||||
// remove k1, add k2 and add k1 back. The final order should be k2, k1
|
||||
// (ordinary update would produce k1, k2). So we need to differentiate
|
||||
// between normal update and "optimized" update which resulted from a
|
||||
// deletion followed by an insertion. We use the UpdateWithMove flag for
|
||||
// this.
|
||||
|
||||
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
|
||||
/* aUpdateWithMove */ true);
|
||||
} else {
|
||||
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
|
||||
}
|
||||
mWriteInfos.Put(aKey, std::move(newWriteInfo));
|
||||
|
||||
mTotalDelta += aDelta;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void LSWriteOptimizer<T, U>::UpdateItem(const nsAString& aKey, const T& aValue,
|
||||
int64_t aDelta) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
WriteInfo* existingWriteInfo;
|
||||
UniquePtr<WriteInfo> newWriteInfo;
|
||||
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
|
||||
existingWriteInfo->GetType() == WriteInfo::InsertItem) {
|
||||
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
|
||||
} else {
|
||||
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
|
||||
/* aUpdateWithMove */ false);
|
||||
}
|
||||
mWriteInfos.Put(aKey, std::move(newWriteInfo));
|
||||
|
||||
mTotalDelta += aDelta;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_localstorage_LSWriteOptimizerImpl_h
|
|
@ -40,6 +40,7 @@ EXPORTS.mozilla.dom += [
|
|||
'LSSnapshot.h',
|
||||
'LSValue.h',
|
||||
'LSWriteOptimizer.h',
|
||||
'LSWriteOptimizerImpl.h',
|
||||
'SnappyUtils.h',
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* 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 protocol PBackgroundSessionStorageManager;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct SSSetItemInfo
|
||||
{
|
||||
nsString key;
|
||||
nsString value;
|
||||
};
|
||||
|
||||
struct SSRemoveItemInfo
|
||||
{
|
||||
nsString key;
|
||||
};
|
||||
|
||||
struct SSClearInfo
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Union of SessionStorage mutation types.
|
||||
*/
|
||||
union SSWriteInfo
|
||||
{
|
||||
SSSetItemInfo;
|
||||
SSRemoveItemInfo;
|
||||
SSClearInfo;
|
||||
};
|
||||
|
||||
sync refcounted protocol PBackgroundSessionStorageCache
|
||||
{
|
||||
manager PBackgroundSessionStorageManager;
|
||||
|
||||
parent:
|
||||
async DeleteMe();
|
||||
|
||||
/**
|
||||
* Copy SessionStorageCache from the parent process to the content process.
|
||||
* See SessionStorageManager documentation for more details.
|
||||
*
|
||||
* This needs to be synchronous because SessionStorage's semantics are
|
||||
* synchronous. Note that the BackgroundSessionStorageManager in the
|
||||
* PBackground parent already has the answers to this request immediately
|
||||
* available without needing to consult any other threads or perform any I/O.
|
||||
*/
|
||||
sync Load()
|
||||
returns (SSSetItemInfo[] aDefaultData, SSSetItemInfo[] aSessionData);
|
||||
|
||||
/**
|
||||
* Send changes for SessionStorageCache from a content process to the parent
|
||||
* process so that the data in the parent can be updated to be in sync with
|
||||
* the content. See SessionStorageManager documentation for more details.
|
||||
*/
|
||||
async Checkpoint(SSWriteInfo[] aDefaultWriteInfos,
|
||||
SSWriteInfo[] aSessionWriteInfos);
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,26 @@
|
|||
/* 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 protocol PBackgroundSessionStorageCache;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
sync refcounted protocol PBackgroundSessionStorageManager
|
||||
{
|
||||
manager PBackground;
|
||||
manages PBackgroundSessionStorageCache;
|
||||
|
||||
parent:
|
||||
async PBackgroundSessionStorageCache(nsCString aOriginAttrs, nsCString aOriginKey);
|
||||
|
||||
async DeleteMe();
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -48,6 +48,11 @@ SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
|
|||
SessionStorage::~SessionStorage() = default;
|
||||
|
||||
int64_t SessionStorage::GetOriginQuotaUsage() const {
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mCache->GetOriginQuotaUsage(DATASET);
|
||||
}
|
||||
|
||||
|
@ -58,6 +63,12 @@ uint32_t SessionStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
|
|||
return 0;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mCache->Length(DATASET);
|
||||
}
|
||||
|
||||
|
@ -68,6 +79,12 @@ void SessionStorage::Key(uint32_t aIndex, nsAString& aResult,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
mCache->Key(DATASET, aIndex, aResult);
|
||||
}
|
||||
|
||||
|
@ -79,6 +96,12 @@ void SessionStorage::GetItem(const nsAString& aKey, nsAString& aResult,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
mCache->GetItem(DATASET, aKey, aResult);
|
||||
}
|
||||
|
||||
|
@ -89,6 +112,13 @@ void SessionStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// return just an empty array
|
||||
aKeys.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
mCache->GetKeys(DATASET, aKeys);
|
||||
}
|
||||
|
||||
|
@ -100,8 +130,14 @@ void SessionStorage::SetItem(const nsAString& aKey, const nsAString& aValue,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsString oldValue;
|
||||
nsresult rv = mCache->SetItem(DATASET, aKey, aValue, oldValue);
|
||||
rv = mCache->SetItem(DATASET, aKey, aValue, oldValue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
|
@ -122,8 +158,14 @@ void SessionStorage::RemoveItem(const nsAString& aKey,
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsString oldValue;
|
||||
nsresult rv = mCache->RemoveItem(DATASET, aKey, oldValue);
|
||||
rv = mCache->RemoveItem(DATASET, aKey, oldValue);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
|
||||
|
@ -139,6 +181,12 @@ void SessionStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureCacheLoadedOrCloned();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
mCache->Clear(DATASET);
|
||||
BroadcastChangeNotification(VoidString(), VoidString(), VoidString());
|
||||
}
|
||||
|
@ -149,9 +197,8 @@ void SessionStorage::BroadcastChangeNotification(const nsAString& aKey,
|
|||
NotifyChange(this, StoragePrincipal(), aKey, aOldValue, aNewValue,
|
||||
u"sessionStorage", mDocumentURI, mIsPrivate, false);
|
||||
|
||||
// Sync changes on SessionStorageCache to the parent process at the next
|
||||
// statble state.
|
||||
if (XRE_IsContentProcess()) {
|
||||
// Sync changes on SessionStorageCache at the next statble state.
|
||||
if (mManager->CanLoadData()) {
|
||||
MaybeScheduleStableStateCallback();
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +213,6 @@ bool SessionStorage::IsForkOf(const Storage* aOther) const {
|
|||
}
|
||||
|
||||
void SessionStorage::MaybeScheduleStableStateCallback() {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mHasPendingStableStateCallback) {
|
||||
|
@ -179,12 +225,36 @@ void SessionStorage::MaybeScheduleStableStateCallback() {
|
|||
}
|
||||
|
||||
void SessionStorage::StableStateCallback() {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mHasPendingStableStateCallback);
|
||||
MOZ_ASSERT(mManager);
|
||||
MOZ_ASSERT(mManager->CanLoadData());
|
||||
MOZ_ASSERT(mCache);
|
||||
|
||||
mHasPendingStableStateCallback = false;
|
||||
mManager->SendSessionStorageDataToParentProcess(*Principal(), *mCache);
|
||||
mManager->CheckpointData(*Principal(), *mCache);
|
||||
}
|
||||
|
||||
nsresult SessionStorage::EnsureCacheLoadedOrCloned() const {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mManager);
|
||||
|
||||
if (!mManager->CanLoadData()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Ensure manager actor.
|
||||
nsresult rv = mManager->EnsureManager();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Ensure cache is loaded or cloned.
|
||||
if (mCache->WasLoadedOrCloned()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mManager->LoadData(*Principal(), *mCache);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -72,6 +72,8 @@ class SessionStorage final : public Storage {
|
|||
|
||||
void StableStateCallback();
|
||||
|
||||
nsresult EnsureCacheLoadedOrCloned() const;
|
||||
|
||||
RefPtr<SessionStorageCache> mCache;
|
||||
RefPtr<SessionStorageManager> mManager;
|
||||
|
||||
|
|
|
@ -6,12 +6,92 @@
|
|||
|
||||
#include "SessionStorageCache.h"
|
||||
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/LSWriteOptimizer.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
SessionStorageCache::SessionStorageCache() = default;
|
||||
void SSWriteOptimizer::Enumerate(nsTArray<SSWriteInfo>& aWriteInfos) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// The mWriteInfos hash table contains all write infos, but it keeps them in
|
||||
// an arbitrary order, which means write infos need to be sorted before being
|
||||
// processed.
|
||||
|
||||
nsTArray<WriteInfo*> writeInfos;
|
||||
GetSortedWriteInfos(writeInfos);
|
||||
|
||||
for (WriteInfo* writeInfo : writeInfos) {
|
||||
switch (writeInfo->GetType()) {
|
||||
case WriteInfo::InsertItem: {
|
||||
auto* insertItemInfo = static_cast<InsertItemInfo*>(writeInfo);
|
||||
|
||||
SSSetItemInfo setItemInfo;
|
||||
setItemInfo.key() = insertItemInfo->GetKey();
|
||||
setItemInfo.value() = insertItemInfo->GetValue();
|
||||
|
||||
aWriteInfos.AppendElement(std::move(setItemInfo));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WriteInfo::UpdateItem: {
|
||||
auto* updateItemInfo = static_cast<UpdateItemInfo*>(writeInfo);
|
||||
|
||||
if (updateItemInfo->UpdateWithMove()) {
|
||||
// See the comment in LSWriteOptimizer::InsertItem for more details
|
||||
// about the UpdateWithMove flag.
|
||||
|
||||
SSRemoveItemInfo removeItemInfo;
|
||||
removeItemInfo.key() = updateItemInfo->GetKey();
|
||||
|
||||
aWriteInfos.AppendElement(std::move(removeItemInfo));
|
||||
}
|
||||
|
||||
SSSetItemInfo setItemInfo;
|
||||
setItemInfo.key() = updateItemInfo->GetKey();
|
||||
setItemInfo.value() = updateItemInfo->GetValue();
|
||||
|
||||
aWriteInfos.AppendElement(std::move(setItemInfo));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WriteInfo::DeleteItem: {
|
||||
auto* deleteItemInfo = static_cast<DeleteItemInfo*>(writeInfo);
|
||||
|
||||
SSRemoveItemInfo removeItemInfo;
|
||||
removeItemInfo.key() = deleteItemInfo->GetKey();
|
||||
|
||||
aWriteInfos.AppendElement(std::move(removeItemInfo));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WriteInfo::Truncate: {
|
||||
SSClearInfo clearInfo;
|
||||
|
||||
aWriteInfos.AppendElement(std::move(clearInfo));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageCache::SessionStorageCache()
|
||||
: mActor(nullptr), mLoadedOrCloned(false) {}
|
||||
|
||||
SessionStorageCache::~SessionStorageCache() {
|
||||
if (mActor) {
|
||||
mActor->SendDeleteMeInternal();
|
||||
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageCache::DataSet* SessionStorageCache::Set(
|
||||
DataSetType aDataSetType) {
|
||||
|
@ -64,9 +144,11 @@ void SessionStorageCache::GetKeys(DataSetType aDataSetType,
|
|||
nsresult SessionStorageCache::SetItem(DataSetType aDataSetType,
|
||||
const nsAString& aKey,
|
||||
const nsAString& aValue,
|
||||
nsString& aOldValue) {
|
||||
nsString& aOldValue,
|
||||
bool aRecordWriteInfo) {
|
||||
int64_t delta = 0;
|
||||
DataSet* dataSet = Set(aDataSetType);
|
||||
MOZ_ASSERT(dataSet);
|
||||
|
||||
if (!dataSet->mKeys.Get(aKey, &aOldValue)) {
|
||||
SetDOMStringToNull(aOldValue);
|
||||
|
@ -87,14 +169,24 @@ nsresult SessionStorageCache::SetItem(DataSetType aDataSetType,
|
|||
return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR;
|
||||
}
|
||||
|
||||
if (aRecordWriteInfo && XRE_IsContentProcess()) {
|
||||
if (DOMStringIsNull(aOldValue)) {
|
||||
dataSet->mWriteOptimizer.InsertItem(aKey, aValue);
|
||||
} else {
|
||||
dataSet->mWriteOptimizer.UpdateItem(aKey, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
dataSet->mKeys.Put(aKey, nsString(aValue));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult SessionStorageCache::RemoveItem(DataSetType aDataSetType,
|
||||
const nsAString& aKey,
|
||||
nsString& aOldValue) {
|
||||
nsString& aOldValue,
|
||||
bool aRecordWriteInfo) {
|
||||
DataSet* dataSet = Set(aDataSetType);
|
||||
MOZ_ASSERT(dataSet);
|
||||
|
||||
if (!dataSet->mKeys.Get(aKey, &aOldValue)) {
|
||||
return NS_SUCCESS_DOM_NO_OPERATION;
|
||||
|
@ -104,38 +196,56 @@ nsresult SessionStorageCache::RemoveItem(DataSetType aDataSetType,
|
|||
dataSet->ProcessUsageDelta(-(static_cast<int64_t>(aOldValue.Length()) +
|
||||
static_cast<int64_t>(aKey.Length())));
|
||||
|
||||
if (aRecordWriteInfo && XRE_IsContentProcess()) {
|
||||
dataSet->mWriteOptimizer.DeleteItem(aKey);
|
||||
}
|
||||
|
||||
dataSet->mKeys.Remove(aKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void SessionStorageCache::Clear(DataSetType aDataSetType,
|
||||
bool aByUserInteraction) {
|
||||
bool aByUserInteraction,
|
||||
bool aRecordWriteInfo) {
|
||||
DataSet* dataSet = Set(aDataSetType);
|
||||
MOZ_ASSERT(dataSet);
|
||||
|
||||
dataSet->ProcessUsageDelta(-dataSet->mOriginQuotaUsage);
|
||||
|
||||
if (aRecordWriteInfo && XRE_IsContentProcess()) {
|
||||
dataSet->mWriteOptimizer.Truncate();
|
||||
}
|
||||
|
||||
dataSet->mKeys.Clear();
|
||||
}
|
||||
|
||||
void SessionStorageCache::ResetWriteInfos(DataSetType aDataSetType) {
|
||||
Set(aDataSetType)->mWriteOptimizer.Reset();
|
||||
}
|
||||
|
||||
already_AddRefed<SessionStorageCache> SessionStorageCache::Clone() const {
|
||||
RefPtr<SessionStorageCache> cache = new SessionStorageCache();
|
||||
|
||||
cache->mDefaultSet.mOriginQuotaUsage = mDefaultSet.mOriginQuotaUsage;
|
||||
for (auto iter = mDefaultSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
cache->mDefaultSet.mKeys.Put(iter.Key(), iter.Data());
|
||||
cache->mDefaultSet.mWriteOptimizer.InsertItem(iter.Key(), iter.Data());
|
||||
}
|
||||
|
||||
cache->mSessionSet.mOriginQuotaUsage = mSessionSet.mOriginQuotaUsage;
|
||||
for (auto iter = mSessionSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
cache->mSessionSet.mKeys.Put(iter.Key(), iter.Data());
|
||||
cache->mSessionSet.mWriteOptimizer.InsertItem(iter.Key(), iter.Data());
|
||||
}
|
||||
|
||||
return cache.forget();
|
||||
}
|
||||
|
||||
nsTArray<KeyValuePair> SessionStorageCache::SerializeData(
|
||||
nsTArray<SSSetItemInfo> SessionStorageCache::SerializeData(
|
||||
DataSetType aDataSetType) {
|
||||
nsTArray<KeyValuePair> data;
|
||||
nsTArray<SSSetItemInfo> data;
|
||||
for (auto iter = Set(aDataSetType)->mKeys.Iter(); !iter.Done(); iter.Next()) {
|
||||
KeyValuePair keyValuePair;
|
||||
SSSetItemInfo keyValuePair;
|
||||
keyValuePair.key() = iter.Key();
|
||||
keyValuePair.value() = iter.Data();
|
||||
data.EmplaceBack(std::move(keyValuePair));
|
||||
|
@ -143,15 +253,74 @@ nsTArray<KeyValuePair> SessionStorageCache::SerializeData(
|
|||
return data;
|
||||
}
|
||||
|
||||
void SessionStorageCache::DeserializeData(DataSetType aDataSetType,
|
||||
const nsTArray<KeyValuePair>& aData) {
|
||||
Clear(aDataSetType, false);
|
||||
nsTArray<SSWriteInfo> SessionStorageCache::SerializeWriteInfos(
|
||||
DataSetType aDataSetType) {
|
||||
nsTArray<SSWriteInfo> writeInfos;
|
||||
Set(aDataSetType)->mWriteOptimizer.Enumerate(writeInfos);
|
||||
return writeInfos;
|
||||
}
|
||||
|
||||
void SessionStorageCache::DeserializeData(
|
||||
DataSetType aDataSetType, const nsTArray<SSSetItemInfo>& aData) {
|
||||
Clear(aDataSetType, false, /* aRecordWriteInfo */ false);
|
||||
for (const auto& keyValuePair : aData) {
|
||||
nsString oldValue;
|
||||
SetItem(aDataSetType, keyValuePair.key(), keyValuePair.value(), oldValue);
|
||||
SetItem(aDataSetType, keyValuePair.key(), keyValuePair.value(), oldValue,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageCache::DeserializeWriteInfos(
|
||||
DataSetType aDataSetType, const nsTArray<SSWriteInfo>& aInfos) {
|
||||
for (const auto& writeInfo : aInfos) {
|
||||
switch (writeInfo.type()) {
|
||||
case SSWriteInfo::TSSSetItemInfo: {
|
||||
const SSSetItemInfo& info = writeInfo.get_SSSetItemInfo();
|
||||
|
||||
nsString oldValue;
|
||||
SetItem(aDataSetType, info.key(), info.value(), oldValue,
|
||||
/* aRecordWriteInfo */ false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSWriteInfo::TSSRemoveItemInfo: {
|
||||
const SSRemoveItemInfo& info = writeInfo.get_SSRemoveItemInfo();
|
||||
|
||||
nsString oldValue;
|
||||
RemoveItem(aDataSetType, info.key(), oldValue,
|
||||
/* aRecordWriteInfo */ false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSWriteInfo::TSSClearInfo: {
|
||||
Clear(aDataSetType, false, /* aRecordWriteInfo */ false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageCache::SetActor(SessionStorageCacheChild* aActor) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mActor);
|
||||
|
||||
mActor = aActor;
|
||||
}
|
||||
|
||||
void SessionStorageCache::ClearActor() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
bool SessionStorageCache::DataSet::ProcessUsageDelta(int64_t aDelta) {
|
||||
// Check limit per this origin
|
||||
uint64_t newOriginUsage = mOriginQuotaUsage + aDelta;
|
||||
|
|
|
@ -7,12 +7,26 @@
|
|||
#ifndef mozilla_dom_SessionStorageCache_h
|
||||
#define mozilla_dom_SessionStorageCache_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/LSWriteOptimizerImpl.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class KeyValuePair;
|
||||
class SSSetItemInfo;
|
||||
class SSWriteInfo;
|
||||
class SessionStorageCacheChild;
|
||||
|
||||
/**
|
||||
* Coalescing manipulation queue used by `SessionStorageCache`. Used by
|
||||
* `SessionStorageCache` to buffer and coalesce manipulations before they
|
||||
* are sent to the parent process.
|
||||
*/
|
||||
class SSWriteOptimizer final : public LSWriteOptimizer<nsAString, nsString> {
|
||||
public:
|
||||
void Enumerate(nsTArray<SSWriteInfo>& aWriteInfos);
|
||||
};
|
||||
|
||||
class SessionStorageCache final {
|
||||
public:
|
||||
|
@ -37,35 +51,61 @@ class SessionStorageCache final {
|
|||
void GetKeys(DataSetType aDataSetType, nsTArray<nsString>& aKeys);
|
||||
|
||||
nsresult SetItem(DataSetType aDataSetType, const nsAString& aKey,
|
||||
const nsAString& aValue, nsString& aOldValue);
|
||||
const nsAString& aValue, nsString& aOldValue,
|
||||
bool aRecordWriteInfo = true);
|
||||
|
||||
nsresult RemoveItem(DataSetType aDataSetType, const nsAString& aKey,
|
||||
nsString& aOldValue);
|
||||
nsString& aOldValue, bool aRecordWriteInfo = true);
|
||||
|
||||
void Clear(DataSetType aDataSetType, bool aByUserInteraction = true);
|
||||
void Clear(DataSetType aDataSetType, bool aByUserInteraction = true,
|
||||
bool aRecordWriteInfo = true);
|
||||
|
||||
void ResetWriteInfos(DataSetType aDataSetType);
|
||||
|
||||
already_AddRefed<SessionStorageCache> Clone() const;
|
||||
|
||||
nsTArray<KeyValuePair> SerializeData(DataSetType aDataSetType);
|
||||
nsTArray<SSSetItemInfo> SerializeData(DataSetType aDataSetType);
|
||||
|
||||
nsTArray<SSWriteInfo> SerializeWriteInfos(DataSetType aDataSetType);
|
||||
|
||||
void DeserializeData(DataSetType aDataSetType,
|
||||
const nsTArray<KeyValuePair>& aData);
|
||||
const nsTArray<SSSetItemInfo>& aData);
|
||||
|
||||
void DeserializeWriteInfos(DataSetType aDataSetType,
|
||||
const nsTArray<SSWriteInfo>& aInfos);
|
||||
|
||||
void SetActor(SessionStorageCacheChild* aActor);
|
||||
|
||||
SessionStorageCacheChild* Actor() const { return mActor; }
|
||||
|
||||
void ClearActor();
|
||||
|
||||
void SetLoadedOrCloned() { mLoadedOrCloned = true; }
|
||||
|
||||
bool WasLoadedOrCloned() const { return mLoadedOrCloned; }
|
||||
|
||||
private:
|
||||
~SessionStorageCache() = default;
|
||||
~SessionStorageCache();
|
||||
|
||||
struct DataSet {
|
||||
DataSet() : mOriginQuotaUsage(0) {}
|
||||
|
||||
bool ProcessUsageDelta(int64_t aDelta);
|
||||
|
||||
int64_t mOriginQuotaUsage;
|
||||
nsDataHashtable<nsStringHashKey, nsString> mKeys;
|
||||
|
||||
SSWriteOptimizer mWriteOptimizer;
|
||||
|
||||
int64_t mOriginQuotaUsage;
|
||||
};
|
||||
|
||||
DataSet* Set(DataSetType aDataSetType);
|
||||
|
||||
DataSet mDefaultSet;
|
||||
DataSet mSessionSet;
|
||||
|
||||
SessionStorageCacheChild* mActor;
|
||||
bool mLoadedOrCloned;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -6,20 +6,80 @@
|
|||
|
||||
#include "SessionStorageManager.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "StorageIPC.h"
|
||||
#include "SessionStorage.h"
|
||||
#include "SessionStorageCache.h"
|
||||
#include "SessionStorageObserver.h"
|
||||
#include "SessionStorageService.h"
|
||||
#include "StorageUtils.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageManager.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace StorageUtils;
|
||||
|
||||
// Parent process, background thread hashmap that stores top context id and
|
||||
// manager pair.
|
||||
static StaticAutoPtr<
|
||||
nsRefPtrHashtable<nsUint64HashKey, BackgroundSessionStorageManager>>
|
||||
sManagers;
|
||||
|
||||
bool RecvShutdownBackgroundSessionStorageManagers() {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
sManagers = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (sManagers) {
|
||||
sManagers->Remove(aTopContextId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SessionStorageManagerBase::OriginRecord*
|
||||
SessionStorageManagerBase::GetOriginRecord(
|
||||
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
|
||||
const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
|
||||
OriginKeyHashTable* table;
|
||||
if (!mOATable.Get(aOriginAttrs, &table)) {
|
||||
if (aMakeIfNeeded) {
|
||||
table = new OriginKeyHashTable();
|
||||
mOATable.Put(aOriginAttrs, table);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
OriginRecord* originRecord;
|
||||
if (!table->Get(aOriginKey, &originRecord)) {
|
||||
if (aMakeIfNeeded) {
|
||||
originRecord = new OriginRecord();
|
||||
if (aCloneFrom) {
|
||||
originRecord->mCache = aCloneFrom->Clone();
|
||||
} else {
|
||||
originRecord->mCache = new SessionStorageCache();
|
||||
}
|
||||
table->Put(aOriginKey, originRecord);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return originRecord;
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
|
||||
|
@ -32,10 +92,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager)
|
|||
|
||||
SessionStorageManager::SessionStorageManager(
|
||||
RefPtr<BrowsingContext> aBrowsingContext)
|
||||
: mBrowsingContext(std::move(aBrowsingContext)) {
|
||||
if (const auto service = SessionStorageService::Get()) {
|
||||
service->RegisterSessionStorageManager(this);
|
||||
}
|
||||
: mBrowsingContext(std::move(aBrowsingContext)), mActor(nullptr) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
StorageObserver* observer = StorageObserver::Self();
|
||||
NS_ASSERTION(
|
||||
|
@ -77,11 +135,170 @@ SessionStorageManager::~SessionStorageManager() {
|
|||
observer->RemoveSink(this);
|
||||
}
|
||||
|
||||
if (const auto service = SessionStorageService::Get()) {
|
||||
service->UnregisterSessionStorageManager(this);
|
||||
if (mActor) {
|
||||
mActor->SendDeleteMeInternal();
|
||||
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionStorageManager::CanLoadData() {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return mBrowsingContext && !mBrowsingContext->IsDiscarded();
|
||||
}
|
||||
|
||||
void SessionStorageManager::SetActor(SessionStorageManagerChild* aActor) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mActor);
|
||||
|
||||
mActor = aActor;
|
||||
}
|
||||
|
||||
bool SessionStorageManager::ActorExists() const {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return mActor;
|
||||
}
|
||||
|
||||
void SessionStorageManager::ClearActor() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
nsresult SessionStorageManager::EnsureManager() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(CanLoadData());
|
||||
|
||||
if (ActorExists()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PBackgroundChild* backgroundActor =
|
||||
BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!backgroundActor)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<SessionStorageManagerChild> actor =
|
||||
new SessionStorageManagerChild(this);
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
MOZ_ALWAYS_TRUE(
|
||||
backgroundActor->SendPBackgroundSessionStorageManagerConstructor(
|
||||
actor, mBrowsingContext->Top()->Id()));
|
||||
|
||||
SetActor(actor);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SessionStorageCacheChild* SessionStorageManager::EnsureCache(
|
||||
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
|
||||
SessionStorageCache& aCache) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(CanLoadData());
|
||||
MOZ_ASSERT(ActorExists());
|
||||
|
||||
if (aCache.Actor()) {
|
||||
return aCache.Actor();
|
||||
}
|
||||
|
||||
RefPtr<SessionStorageCacheChild> actor =
|
||||
new SessionStorageCacheChild(&aCache);
|
||||
MOZ_ALWAYS_TRUE(mActor->SendPBackgroundSessionStorageCacheConstructor(
|
||||
actor, aOriginAttrs, aOriginKey));
|
||||
|
||||
aCache.SetActor(actor);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
nsresult SessionStorageManager::LoadData(nsIPrincipal& aPrincipal,
|
||||
SessionStorageCache& aCache) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsAutoCString originKey;
|
||||
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString originAttributes;
|
||||
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
|
||||
|
||||
auto* const originRecord =
|
||||
GetOriginRecord(originAttributes, originKey, true, nullptr);
|
||||
MOZ_ASSERT(originRecord);
|
||||
|
||||
if (originRecord->mLoaded) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<SessionStorageCacheChild> cacheActor =
|
||||
EnsureCache(originAttributes, originKey, aCache);
|
||||
|
||||
nsTArray<SSSetItemInfo> defaultData;
|
||||
nsTArray<SSSetItemInfo> sessionData;
|
||||
if (!cacheActor->SendLoad(&defaultData, &sessionData)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
originRecord->mCache->DeserializeData(SessionStorageCache::eDefaultSetType,
|
||||
defaultData);
|
||||
originRecord->mCache->DeserializeData(SessionStorageCache::eSessionSetType,
|
||||
sessionData);
|
||||
|
||||
originRecord->mLoaded.Flip();
|
||||
aCache.SetLoadedOrCloned();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void SessionStorageManager::CheckpointData(nsIPrincipal& aPrincipal,
|
||||
SessionStorageCache& aCache) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsAutoCString originKey;
|
||||
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString originAttributes;
|
||||
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
|
||||
|
||||
return CheckpointDataInternal(originAttributes, originKey, aCache);
|
||||
}
|
||||
|
||||
void SessionStorageManager::CheckpointDataInternal(
|
||||
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
|
||||
SessionStorageCache& aCache) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsTArray<SSWriteInfo> defaultWriteInfos =
|
||||
aCache.SerializeWriteInfos(SessionStorageCache::eDefaultSetType);
|
||||
nsTArray<SSWriteInfo> sessionWriteInfos =
|
||||
aCache.SerializeWriteInfos(SessionStorageCache::eSessionSetType);
|
||||
|
||||
if (defaultWriteInfos.IsEmpty() && sessionWriteInfos.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<SessionStorageCacheChild> cacheActor =
|
||||
EnsureCache(aOriginAttrs, aOriginKey, aCache);
|
||||
|
||||
Unused << cacheActor->SendCheckpoint(defaultWriteInfos, sessionWriteInfos);
|
||||
|
||||
aCache.ResetWriteInfos(SessionStorageCache::eDefaultSetType);
|
||||
aCache.ResetWriteInfos(SessionStorageCache::eSessionSetType);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aStoragePrincipal,
|
||||
|
@ -126,37 +343,6 @@ nsresult SessionStorageManager::GetSessionStorageCacheHelper(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
SessionStorageManager::OriginRecord* SessionStorageManager::GetOriginRecord(
|
||||
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
|
||||
const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
|
||||
OriginKeyHashTable* table;
|
||||
if (!mOATable.Get(aOriginAttrs, &table)) {
|
||||
if (aMakeIfNeeded) {
|
||||
table = new OriginKeyHashTable();
|
||||
mOATable.Put(aOriginAttrs, table);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
OriginRecord* originRecord;
|
||||
if (!table->Get(aOriginKey, &originRecord)) {
|
||||
if (aMakeIfNeeded) {
|
||||
originRecord = new OriginRecord();
|
||||
if (aCloneFrom) {
|
||||
originRecord->mCache = aCloneFrom->Clone();
|
||||
} else {
|
||||
originRecord->mCache = new SessionStorageCache();
|
||||
}
|
||||
table->Put(aOriginKey, originRecord);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return originRecord;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStorageManager::CreateStorage(mozIDOMWindow* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
|
@ -212,10 +398,33 @@ SessionStorageManager::CloneStorage(Storage* aStorage) {
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// ToDo: At the momnet, we clone the cache on the child process and then
|
||||
// send the checkpoint. It would be nicer if we either serailizing all the
|
||||
// data and sync to the parent process directly or clonig storage on the
|
||||
// parnet process and sync it to the child process on demand.
|
||||
|
||||
RefPtr<SessionStorageCache> cache;
|
||||
return GetSessionStorageCacheHelper(
|
||||
nsresult rv = GetSessionStorageCacheHelper(
|
||||
aStorage->StoragePrincipal(), true,
|
||||
static_cast<SessionStorage*>(aStorage)->Cache(), &cache);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If cache was cloned from other storage, then we shouldn't load the cache
|
||||
// at the first access.
|
||||
cache->SetLoadedOrCloned();
|
||||
|
||||
if (CanLoadData()) {
|
||||
rv = EnsureManager();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
CheckpointData(*aStorage->StoragePrincipal(), *cache);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -260,6 +469,13 @@ SessionStorageManager::CheckStorage(nsIPrincipal* aPrincipal, Storage* aStorage,
|
|||
void SessionStorageManager::ClearStorages(
|
||||
ClearStorageType aType, const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aOriginScope) {
|
||||
if (CanLoadData()) {
|
||||
nsresult rv = EnsureManager();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter1 = mOATable.Iter(); !iter1.Done(); iter1.Next()) {
|
||||
OriginAttributes oa;
|
||||
DebugOnly<bool> ok = oa.PopulateFromSuffix(iter1.Key());
|
||||
|
@ -281,85 +497,17 @@ void SessionStorageManager::ClearStorages(
|
|||
MOZ_ASSERT(aType == eSessionOnly);
|
||||
cache->Clear(SessionStorageCache::eSessionSetType, false);
|
||||
}
|
||||
|
||||
if (CanLoadData()) {
|
||||
MOZ_ASSERT(ActorExists());
|
||||
CheckpointDataInternal(nsCString{iter1.Key()}, nsCString{iter2.Key()},
|
||||
*cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageManager::SendSessionStorageDataToParentProcess(
|
||||
nsIPrincipal& aPrincipal, SessionStorageCache& aSSCache) {
|
||||
if (!mBrowsingContext || mBrowsingContext->IsDiscarded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString originKey;
|
||||
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString originAttributes;
|
||||
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
|
||||
|
||||
SendSessionStorageCache(ContentChild::GetSingleton(), originAttributes,
|
||||
originKey, &aSSCache);
|
||||
}
|
||||
|
||||
void SessionStorageManager::SendSessionStorageDataToContentProcess(
|
||||
ContentParent* const aActor, nsIPrincipal* const aPrincipal) {
|
||||
nsAutoCString originAttrs;
|
||||
nsAutoCString originKey;
|
||||
nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
|
||||
aPrincipal->OriginAttributesRef().CreateSuffix(originAttrs);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto originRecord =
|
||||
GetOriginRecord(originAttrs, originKey, false, nullptr);
|
||||
if (!originRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = aActor->ChildID();
|
||||
if (!originRecord->mKnownTo.Contains(id)) {
|
||||
originRecord->mKnownTo.PutEntry(id);
|
||||
SendSessionStorageCache(aActor, originAttrs, originKey,
|
||||
originRecord->mCache);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Actor>
|
||||
void SessionStorageManager::SendSessionStorageCache(
|
||||
Actor* const aActor, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, SessionStorageCache* const aCache) {
|
||||
nsTArray<KeyValuePair> defaultData =
|
||||
aCache->SerializeData(SessionStorageCache::eDefaultSetType);
|
||||
nsTArray<KeyValuePair> sessionData =
|
||||
aCache->SerializeData(SessionStorageCache::eSessionSetType);
|
||||
Unused << aActor->SendSessionStorageData(
|
||||
mBrowsingContext->Id(), nsCString{aOriginAttrs}, nsCString{aOriginKey},
|
||||
defaultData, sessionData);
|
||||
}
|
||||
|
||||
void SessionStorageManager::LoadSessionStorageData(
|
||||
ContentParent* const aSource, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData) {
|
||||
const auto originRecord =
|
||||
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
|
||||
MOZ_ASSERT(originRecord);
|
||||
|
||||
if (aSource) {
|
||||
originRecord->mKnownTo.RemoveEntry(aSource->ChildID());
|
||||
}
|
||||
|
||||
originRecord->mCache->DeserializeData(SessionStorageCache::eDefaultSetType,
|
||||
aDefaultData);
|
||||
originRecord->mCache->DeserializeData(SessionStorageCache::eSessionSetType,
|
||||
aSessionData);
|
||||
}
|
||||
|
||||
nsresult SessionStorageManager::Observe(
|
||||
const char* aTopic, const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope) {
|
||||
|
@ -399,11 +547,101 @@ nsresult SessionStorageManager::Observe(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> SessionStorageManager::GetBrowsingContext() const {
|
||||
return mBrowsingContext;
|
||||
SessionStorageManager::OriginRecord::~OriginRecord() = default;
|
||||
|
||||
// static
|
||||
void BackgroundSessionStorageManager::RemoveManager(uint64_t aTopContextId) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnMainThread();
|
||||
|
||||
PBackgroundChild* backgroundActor =
|
||||
BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!backgroundActor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!backgroundActor->SendRemoveBackgroundSessionStorageManager(
|
||||
aTopContextId))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageManager::OriginRecord::~OriginRecord() = default;
|
||||
// static
|
||||
BackgroundSessionStorageManager* BackgroundSessionStorageManager::GetOrCreate(
|
||||
uint64_t aTopContextId) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (!sManagers) {
|
||||
sManagers = new nsRefPtrHashtable<nsUint64HashKey,
|
||||
BackgroundSessionStorageManager>();
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"dom::BackgroundSessionStorageManager::GetOrCreate", [] {
|
||||
RunOnShutdown(
|
||||
[] {
|
||||
PBackgroundChild* backgroundActor =
|
||||
BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!backgroundActor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(
|
||||
!backgroundActor
|
||||
->SendShutdownBackgroundSessionStorageManagers())) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
ShutdownPhase::Shutdown);
|
||||
}));
|
||||
}
|
||||
|
||||
return sManagers->LookupForAdd(aTopContextId).OrInsert([] {
|
||||
return new BackgroundSessionStorageManager();
|
||||
});
|
||||
}
|
||||
|
||||
BackgroundSessionStorageManager::BackgroundSessionStorageManager() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
BackgroundSessionStorageManager::~BackgroundSessionStorageManager() = default;
|
||||
|
||||
void BackgroundSessionStorageManager::CopyDataToContentProcess(
|
||||
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
|
||||
nsTArray<SSSetItemInfo>& aDefaultData,
|
||||
nsTArray<SSSetItemInfo>& aSessionData) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto* const originRecord =
|
||||
GetOriginRecord(aOriginAttrs, aOriginKey, false, nullptr);
|
||||
if (!originRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
aDefaultData =
|
||||
originRecord->mCache->SerializeData(SessionStorageCache::eDefaultSetType);
|
||||
aSessionData =
|
||||
originRecord->mCache->SerializeData(SessionStorageCache::eSessionSetType);
|
||||
}
|
||||
|
||||
void BackgroundSessionStorageManager::UpdateData(
|
||||
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
|
||||
const nsTArray<SSWriteInfo>& aDefaultWriteInfos,
|
||||
const nsTArray<SSWriteInfo>& aSessionWriteInfos) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto* const originRecord =
|
||||
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
|
||||
MOZ_ASSERT(originRecord);
|
||||
|
||||
originRecord->mCache->DeserializeWriteInfos(
|
||||
SessionStorageCache::eDefaultSetType, aDefaultWriteInfos);
|
||||
originRecord->mCache->DeserializeWriteInfos(
|
||||
SessionStorageCache::eSessionSetType, aSessionWriteInfos);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,22 +7,32 @@
|
|||
#ifndef mozilla_dom_SessionStorageManager_h
|
||||
#define mozilla_dom_SessionStorageManager_h
|
||||
|
||||
#include "StorageObserver.h"
|
||||
|
||||
#include "mozilla/dom/FlippedOnce.h"
|
||||
#include "nsIDOMStorageManager.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "StorageObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributesPattern;
|
||||
|
||||
namespace dom {
|
||||
|
||||
bool RecvShutdownBackgroundSessionStorageManagers();
|
||||
bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId);
|
||||
|
||||
class BrowsingContext;
|
||||
class ContentParent;
|
||||
class KeyValuePair;
|
||||
class SSSetItemInfo;
|
||||
class SSWriteInfo;
|
||||
class SessionStorageCache;
|
||||
class SessionStorageCacheChild;
|
||||
class SessionStorageManagerChild;
|
||||
class SessionStorageManagerParent;
|
||||
class SessionStorageObserver;
|
||||
struct OriginRecord;
|
||||
|
||||
// sessionStorage is a data store that's unique to each tab (i.e. top-level
|
||||
// browsing context) and origin. Before the advent of Fission all the data
|
||||
|
@ -33,17 +43,44 @@ class SessionStorageObserver;
|
|||
// by navigating an iframe element). Therefore SessionStorageManager
|
||||
// objects exist in both the parent and content processes.
|
||||
//
|
||||
// Whenever a content process terminates it sends its sessionStorage data
|
||||
// to the parent process (see SessionStorageService); whenever a content
|
||||
// process navigates to an origin for the first time in a given tab, the
|
||||
// parent process sends it the saved data. To avoid sending the data
|
||||
// multiple times, the parent process maintains a table of content
|
||||
// processes that already received it; this table is empty in content
|
||||
// processes.
|
||||
// Whenever a write operation for SessionStorage executes, the content process
|
||||
// sends the changes to the parent process at the next stable state. Whenever a
|
||||
// content process navigates to an origin for the first time in a given tab, the
|
||||
// parent process sends it the saved data. SessionStorageCache has a flag
|
||||
// (mLoadedOrCloned) to ensure that it's only be loaded or cloned once.
|
||||
//
|
||||
// Note: the current implementation is expected to be replaced by a new
|
||||
// implementation using LSNG.
|
||||
class SessionStorageManager final : public nsIDOMSessionStorageManager,
|
||||
class SessionStorageManagerBase {
|
||||
public:
|
||||
SessionStorageManagerBase() = default;
|
||||
|
||||
protected:
|
||||
~SessionStorageManagerBase() = default;
|
||||
|
||||
struct OriginRecord {
|
||||
OriginRecord() = default;
|
||||
OriginRecord(OriginRecord&&) = default;
|
||||
OriginRecord& operator=(OriginRecord&&) = default;
|
||||
~OriginRecord();
|
||||
|
||||
RefPtr<SessionStorageCache> mCache;
|
||||
|
||||
// A flag to ensure that cache is only loaded once.
|
||||
FlippedOnce<false> mLoaded;
|
||||
};
|
||||
|
||||
OriginRecord* GetOriginRecord(const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey,
|
||||
bool aMakeIfNeeded,
|
||||
SessionStorageCache* aCloneFrom);
|
||||
|
||||
using OriginKeyHashTable = nsClassHashtable<nsCStringHashKey, OriginRecord>;
|
||||
nsClassHashtable<nsCStringHashKey, OriginKeyHashTable> mOATable;
|
||||
};
|
||||
|
||||
class SessionStorageManager final : public SessionStorageManagerBase,
|
||||
public nsIDOMSessionStorageManager,
|
||||
public StorageObserverSink {
|
||||
public:
|
||||
explicit SessionStorageManager(RefPtr<BrowsingContext> aBrowsingContext);
|
||||
|
@ -54,18 +91,19 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
|
|||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(SessionStorageManager)
|
||||
|
||||
RefPtr<BrowsingContext> GetBrowsingContext() const;
|
||||
bool CanLoadData();
|
||||
|
||||
void SendSessionStorageDataToParentProcess(nsIPrincipal& aPrincipal,
|
||||
SessionStorageCache& aSSCache);
|
||||
void SendSessionStorageDataToContentProcess(ContentParent* aActor,
|
||||
nsIPrincipal* aPrincipal);
|
||||
void SetActor(SessionStorageManagerChild* aActor);
|
||||
|
||||
void LoadSessionStorageData(ContentParent* aSource,
|
||||
const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey,
|
||||
const nsTArray<KeyValuePair>& aDefaultData,
|
||||
const nsTArray<KeyValuePair>& aSessionData);
|
||||
bool ActorExists() const;
|
||||
|
||||
void ClearActor();
|
||||
|
||||
nsresult EnsureManager();
|
||||
|
||||
nsresult LoadData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
|
||||
|
||||
void CheckpointData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
|
||||
|
||||
private:
|
||||
~SessionStorageManager();
|
||||
|
@ -75,15 +113,6 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
|
|||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope) override;
|
||||
|
||||
enum ClearStorageType {
|
||||
eAll,
|
||||
eSessionOnly,
|
||||
};
|
||||
|
||||
void ClearStorages(ClearStorageType aType,
|
||||
const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aOriginScope);
|
||||
|
||||
nsresult GetSessionStorageCacheHelper(nsIPrincipal* aPrincipal,
|
||||
bool aMakeIfNeeded,
|
||||
SessionStorageCache* aCloneFrom,
|
||||
|
@ -95,32 +124,58 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
|
|||
SessionStorageCache* aCloneFrom,
|
||||
RefPtr<SessionStorageCache>* aRetVal);
|
||||
|
||||
struct OriginRecord {
|
||||
OriginRecord() = default;
|
||||
OriginRecord(OriginRecord&&) = default;
|
||||
OriginRecord& operator=(OriginRecord&&) = default;
|
||||
~OriginRecord();
|
||||
|
||||
RefPtr<SessionStorageCache> mCache;
|
||||
nsTHashtable<nsUint64HashKey> mKnownTo;
|
||||
enum ClearStorageType {
|
||||
eAll,
|
||||
eSessionOnly,
|
||||
};
|
||||
void ClearStorages(ClearStorageType aType,
|
||||
const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aOriginScope);
|
||||
|
||||
OriginRecord* GetOriginRecord(const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey,
|
||||
bool aMakeIfNeeded,
|
||||
SessionStorageCache* aCloneFrom);
|
||||
SessionStorageCacheChild* EnsureCache(const nsCString& aOriginAttrs,
|
||||
const nsCString& aOriginKey,
|
||||
SessionStorageCache& aCache);
|
||||
|
||||
template <typename Actor>
|
||||
void SendSessionStorageCache(Actor* aActor, const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey,
|
||||
SessionStorageCache* aCache);
|
||||
|
||||
using OriginKeyHashTable = nsClassHashtable<nsCStringHashKey, OriginRecord>;
|
||||
nsClassHashtable<nsCStringHashKey, OriginKeyHashTable> mOATable;
|
||||
void CheckpointDataInternal(const nsCString& aOriginAttrs,
|
||||
const nsCString& aOriginKey,
|
||||
SessionStorageCache& aCache);
|
||||
|
||||
RefPtr<SessionStorageObserver> mObserver;
|
||||
|
||||
RefPtr<BrowsingContext> mBrowsingContext;
|
||||
|
||||
SessionStorageManagerChild* mActor;
|
||||
};
|
||||
|
||||
/**
|
||||
* A specialized SessionStorageManager class that lives on the parent process
|
||||
* background thread. It is a shadow copy of SessionStorageManager and it's used
|
||||
* to preserve SessionStorageCaches for the other SessionStorageManagers.
|
||||
*/
|
||||
class BackgroundSessionStorageManager final : public SessionStorageManagerBase {
|
||||
public:
|
||||
// Parent process getter function.
|
||||
static BackgroundSessionStorageManager* GetOrCreate(uint64_t aTopContextId);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(BackgroundSessionStorageManager);
|
||||
|
||||
// Only called by ~BrowsingContext on parent process.
|
||||
static void RemoveManager(uint64_t aTopContextId);
|
||||
|
||||
void CopyDataToContentProcess(const nsACString& aOriginAttrs,
|
||||
const nsACString& aOriginKey,
|
||||
nsTArray<SSSetItemInfo>& aDefaultData,
|
||||
nsTArray<SSSetItemInfo>& aSessionData);
|
||||
|
||||
void UpdateData(const nsACString& aOriginAttrs, const nsACString& aOriginKey,
|
||||
const nsTArray<SSWriteInfo>& aDefaultWriteInfos,
|
||||
const nsTArray<SSWriteInfo>& aSessionWriteInfos);
|
||||
|
||||
private:
|
||||
// Only be called by GetOrCreate() on the parent process.
|
||||
explicit BackgroundSessionStorageManager();
|
||||
|
||||
~BackgroundSessionStorageManager();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/* 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 "SessionStorageService.h"
|
||||
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* const kContentProcessShutdownTopic = "content-child-will-shutdown";
|
||||
|
||||
}
|
||||
|
||||
RefPtr<SessionStorageService> SessionStorageService::sService = nullptr;
|
||||
bool SessionStorageService::sShutdown = false;
|
||||
|
||||
NS_IMPL_ISUPPORTS(SessionStorageService, nsIObserver)
|
||||
|
||||
SessionStorageService::SessionStorageService() {
|
||||
if (const nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService()) {
|
||||
Unused << observerService->AddObserver(this, kContentProcessShutdownTopic,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageService::~SessionStorageService() {
|
||||
if (const nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService()) {
|
||||
Unused << observerService->RemoveObserver(this,
|
||||
kContentProcessShutdownTopic);
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageService* SessionStorageService::Get() {
|
||||
if (sShutdown) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ShutDown();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sService) {
|
||||
sService = new SessionStorageService();
|
||||
}
|
||||
|
||||
return sService;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP SessionStorageService::Observe(nsISupports* const aSubject,
|
||||
const char* const aTopic,
|
||||
const char16_t* const aData) {
|
||||
if (std::strcmp(aTopic, kContentProcessShutdownTopic) == 0) {
|
||||
ShutDown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void SessionStorageService::RegisterSessionStorageManager(
|
||||
SessionStorageManager* aManager) {
|
||||
mManagers.PutEntry(aManager);
|
||||
}
|
||||
|
||||
void SessionStorageService::UnregisterSessionStorageManager(
|
||||
SessionStorageManager* aManager) {
|
||||
if (const auto entry = mManagers.GetEntry(aManager)) {
|
||||
mManagers.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageService::ShutDown() {
|
||||
sShutdown = true;
|
||||
sService = nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,45 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_SessionStorageService_h
|
||||
#define mozilla_dom_SessionStorageService_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsPointerHashKeys.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SessionStorageManager;
|
||||
|
||||
class SessionStorageService final : public nsIObserver {
|
||||
public:
|
||||
SessionStorageService();
|
||||
|
||||
static SessionStorageService* Get();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
void RegisterSessionStorageManager(SessionStorageManager* aManager);
|
||||
void UnregisterSessionStorageManager(SessionStorageManager* aManager);
|
||||
|
||||
private:
|
||||
~SessionStorageService();
|
||||
|
||||
static void ShutDown();
|
||||
|
||||
static RefPtr<SessionStorageService> sService;
|
||||
static bool sShutdown;
|
||||
|
||||
nsTHashtable<nsPtrHashKey<SessionStorageManager>> mManagers;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SessionStorageService_h
|
|
@ -7,6 +7,8 @@
|
|||
#include "StorageIPC.h"
|
||||
|
||||
#include "LocalStorageManager.h"
|
||||
#include "SessionStorageManager.h"
|
||||
#include "SessionStorageCache.h"
|
||||
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
|
@ -464,6 +466,75 @@ mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
SessionStorageCacheChild::SessionStorageCacheChild(SessionStorageCache* aCache)
|
||||
: mCache(aCache) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mCache);
|
||||
|
||||
MOZ_COUNT_CTOR(SessionStorageCacheChild);
|
||||
}
|
||||
|
||||
SessionStorageCacheChild::~SessionStorageCacheChild() {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(SessionStorageCacheChild);
|
||||
}
|
||||
|
||||
void SessionStorageCacheChild::SendDeleteMeInternal() {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mCache) {
|
||||
mCache->ClearActor();
|
||||
mCache = nullptr;
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundSessionStorageCacheChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mCache) {
|
||||
mCache->ClearActor();
|
||||
mCache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SessionStorageManagerChild::SessionStorageManagerChild(
|
||||
SessionStorageManager* aSSManager)
|
||||
: mSSManager(aSSManager) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mSSManager);
|
||||
|
||||
MOZ_COUNT_CTOR(SessionStorageManagerChild);
|
||||
}
|
||||
|
||||
SessionStorageManagerChild::~SessionStorageManagerChild() {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(SessionStorageManagerChild);
|
||||
}
|
||||
|
||||
void SessionStorageManagerChild::SendDeleteMeInternal() {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mSSManager) {
|
||||
mSSManager->ClearActor();
|
||||
mSSManager = nullptr;
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundSessionStorageManagerChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStorageManagerChild::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mSSManager) {
|
||||
mSSManager->ClearActor();
|
||||
mSSManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LocalStorageCacheParent::LocalStorageCacheParent(
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
|
||||
|
@ -1223,6 +1294,111 @@ nsresult SessionStorageObserverParent::Observe(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
SessionStorageCacheParent::SessionStorageCacheParent(
|
||||
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
|
||||
SessionStorageManagerParent* aActor)
|
||||
: mOriginAttrs(aOriginAttrs),
|
||||
mOriginKey(aOriginKey),
|
||||
mManagerActor(aActor) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mManagerActor);
|
||||
}
|
||||
|
||||
SessionStorageCacheParent::~SessionStorageCacheParent() = default;
|
||||
|
||||
void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
mManagerActor = nullptr;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad(
|
||||
nsTArray<SSSetItemInfo>* aDefaultData,
|
||||
nsTArray<SSSetItemInfo>* aSessionData) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mManagerActor);
|
||||
|
||||
mLoadReceived.Flip();
|
||||
|
||||
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
manager->CopyDataToContentProcess(mOriginAttrs, mOriginKey, *aDefaultData,
|
||||
*aSessionData);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint(
|
||||
nsTArray<SSWriteInfo>&& aDefaultWriteInfos,
|
||||
nsTArray<SSWriteInfo>&& aSessionWriteInfos) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mManagerActor);
|
||||
|
||||
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
manager->UpdateData(mOriginAttrs, mOriginKey, aDefaultWriteInfos,
|
||||
aSessionWriteInfos);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mManagerActor);
|
||||
|
||||
mManagerActor = nullptr;
|
||||
|
||||
IProtocol* mgr = Manager();
|
||||
if (!PBackgroundSessionStorageCacheParent::Send__delete__(this)) {
|
||||
return IPC_FAIL(
|
||||
mgr, "Failed to delete PBackgroundSessionStorageCacheParent actor");
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
SessionStorageManagerParent::SessionStorageManagerParent(uint64_t aTopContextId)
|
||||
: mBackgroundManager(
|
||||
BackgroundSessionStorageManager::GetOrCreate(aTopContextId)) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mBackgroundManager);
|
||||
}
|
||||
|
||||
SessionStorageManagerParent::~SessionStorageManagerParent() = default;
|
||||
|
||||
void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
mBackgroundManager = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<PBackgroundSessionStorageCacheParent>
|
||||
SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent(
|
||||
const nsCString& aOriginAttrs, const nsCString& aOriginKey) {
|
||||
return MakeAndAddRef<SessionStorageCacheParent>(aOriginAttrs, aOriginKey,
|
||||
this);
|
||||
}
|
||||
|
||||
BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager()
|
||||
const {
|
||||
return mBackgroundManager;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mBackgroundManager);
|
||||
|
||||
mBackgroundManager = nullptr;
|
||||
|
||||
IProtocol* mgr = Manager();
|
||||
if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) {
|
||||
return IPC_FAIL(
|
||||
mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor");
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Exported functions
|
||||
******************************************************************************/
|
||||
|
@ -1335,5 +1511,10 @@ bool DeallocPSessionStorageObserverParent(
|
|||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<PBackgroundSessionStorageManagerParent>
|
||||
AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) {
|
||||
return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,17 +7,24 @@
|
|||
#ifndef mozilla_dom_StorageIPC_h
|
||||
#define mozilla_dom_StorageIPC_h
|
||||
|
||||
#include "LocalStorageCache.h"
|
||||
#include "StorageDBThread.h"
|
||||
#include "StorageObserver.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/FlippedOnce.h"
|
||||
#include "mozilla/dom/PBackgroundLocalStorageCacheChild.h"
|
||||
#include "mozilla/dom/PBackgroundLocalStorageCacheParent.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageCacheChild.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageCacheParent.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageManagerChild.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageManagerParent.h"
|
||||
#include "mozilla/dom/PBackgroundStorageChild.h"
|
||||
#include "mozilla/dom/PBackgroundStorageParent.h"
|
||||
#include "mozilla/dom/PSessionStorageObserverChild.h"
|
||||
#include "mozilla/dom/PSessionStorageObserverParent.h"
|
||||
#include "StorageDBThread.h"
|
||||
#include "LocalStorageCache.h"
|
||||
#include "StorageObserver.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -35,6 +42,11 @@ namespace dom {
|
|||
class LocalStorageManager;
|
||||
class PBackgroundStorageParent;
|
||||
class PSessionStorageObserverParent;
|
||||
class SessionStorageCache;
|
||||
class SessionStorageCacheParent;
|
||||
class SessionStorageManager;
|
||||
class SessionStorageManagerParent;
|
||||
class BackgroundSessionStorageManager;
|
||||
class SessionStorageObserver;
|
||||
|
||||
class LocalStorageCacheChild final : public PBackgroundLocalStorageCacheChild {
|
||||
|
@ -207,6 +219,76 @@ class SessionStorageObserverChild final : public PSessionStorageObserverChild {
|
|||
const nsCString& aOriginScope) override;
|
||||
};
|
||||
|
||||
class SessionStorageCacheChild final
|
||||
: public PBackgroundSessionStorageCacheChild {
|
||||
friend class PBackgroundSessionStorageCacheChild;
|
||||
friend class SessionStorageCache;
|
||||
friend class SessionStorageManager;
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
|
||||
// SessionStorageManagerChild effectively owns this instance, although IPC
|
||||
// handles its allocation/deallocation. When the SessionStorageManager
|
||||
// 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.
|
||||
SessionStorageCache* MOZ_NON_OWNING_REF mCache;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageCacheChild, override)
|
||||
|
||||
public:
|
||||
void AssertIsOnOwningThread() const {
|
||||
NS_ASSERT_OWNINGTHREAD(SesionStoragManagerChild);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only created by SessionStorageManager.
|
||||
explicit SessionStorageCacheChild(SessionStorageCache* aCache);
|
||||
|
||||
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
|
||||
~SessionStorageCacheChild();
|
||||
|
||||
// Only called by SessionStorageCache.
|
||||
void SendDeleteMeInternal();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
};
|
||||
|
||||
class SessionStorageManagerChild final
|
||||
: public PBackgroundSessionStorageManagerChild {
|
||||
friend class PBackgroundSessionStorageManagerChild;
|
||||
friend class SessionStorage;
|
||||
friend class SessionStorageManager;
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
|
||||
// SessionStorageManager effectively owns this instance, although IPC handles
|
||||
// its allocation/deallocation. When the SessionStorageManager 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.
|
||||
SessionStorageManager* MOZ_NON_OWNING_REF mSSManager;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageManagerChild, override)
|
||||
|
||||
public:
|
||||
void AssertIsOnOwningThread() const {
|
||||
NS_ASSERT_OWNINGTHREAD(SesionStoragManagerChild);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only created by SessionStorage.
|
||||
explicit SessionStorageManagerChild(SessionStorageManager* aSSManager);
|
||||
|
||||
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
|
||||
~SessionStorageManagerChild();
|
||||
|
||||
// Only called by SessionStorageManager.
|
||||
void SendDeleteMeInternal();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
};
|
||||
|
||||
class LocalStorageCacheParent final
|
||||
: public PBackgroundLocalStorageCacheParent {
|
||||
const PrincipalInfo mPrincipalInfo;
|
||||
|
@ -418,6 +500,66 @@ class SessionStorageObserverParent final : public PSessionStorageObserverParent,
|
|||
const nsACString& aOriginScope) override;
|
||||
};
|
||||
|
||||
class SessionStorageCacheParent final
|
||||
: public PBackgroundSessionStorageCacheParent {
|
||||
friend class PBackgroundSessionStorageCacheParent;
|
||||
const nsCString mOriginAttrs;
|
||||
const nsCString mOriginKey;
|
||||
|
||||
RefPtr<SessionStorageManagerParent> mManagerActor;
|
||||
FlippedOnce<false> mLoadReceived;
|
||||
|
||||
public:
|
||||
SessionStorageCacheParent(const nsCString& aOriginAttrs,
|
||||
const nsCString& aOriginKey,
|
||||
SessionStorageManagerParent* aActor);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageCacheParent, override)
|
||||
|
||||
private:
|
||||
~SessionStorageCacheParent();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvLoad(
|
||||
nsTArray<SSSetItemInfo>* aDefaultData,
|
||||
nsTArray<SSSetItemInfo>* aSessionData) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvCheckpoint(
|
||||
nsTArray<SSWriteInfo>&& aDefaultWriteInfos,
|
||||
nsTArray<SSWriteInfo>&& aSessionWriteInfos) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvDeleteMe() override;
|
||||
};
|
||||
|
||||
class SessionStorageManagerParent final
|
||||
: public PBackgroundSessionStorageManagerParent {
|
||||
friend class PBackgroundSessionStorageManagerParent;
|
||||
|
||||
RefPtr<BackgroundSessionStorageManager> mBackgroundManager;
|
||||
|
||||
public:
|
||||
explicit SessionStorageManagerParent(uint64_t aTopContextId);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageManagerParent,
|
||||
override)
|
||||
|
||||
already_AddRefed<PBackgroundSessionStorageCacheParent>
|
||||
AllocPBackgroundSessionStorageCacheParent(
|
||||
const nsCString& aOriginAttrs, const nsCString& aOriginKey) override;
|
||||
|
||||
BackgroundSessionStorageManager* GetManager() const;
|
||||
|
||||
private:
|
||||
~SessionStorageManagerParent();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvDeleteMe() override;
|
||||
};
|
||||
|
||||
PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
||||
const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId);
|
||||
|
@ -447,6 +589,12 @@ bool RecvPSessionStorageObserverConstructor(
|
|||
bool DeallocPSessionStorageObserverParent(
|
||||
PSessionStorageObserverParent* aActor);
|
||||
|
||||
already_AddRefed<PBackgroundSessionStorageCacheParent>
|
||||
AllocPBackgroundSessionStorageCacheParent(const nsCString& aOriginAttrs,
|
||||
const nsCString& aOriginKey);
|
||||
|
||||
already_AddRefed<PBackgroundSessionStorageManagerParent>
|
||||
AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId);
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ UNIFIED_SOURCES += [
|
|||
'SessionStorageCache.cpp',
|
||||
'SessionStorageManager.cpp',
|
||||
'SessionStorageObserver.cpp',
|
||||
'SessionStorageService.cpp',
|
||||
'Storage.cpp',
|
||||
'StorageActivityService.cpp',
|
||||
'StorageDBThread.cpp',
|
||||
|
@ -43,6 +42,8 @@ UNIFIED_SOURCES += [
|
|||
|
||||
IPDL_SOURCES += [
|
||||
'PBackgroundLocalStorageCache.ipdl',
|
||||
'PBackgroundSessionStorageCache.ipdl',
|
||||
'PBackgroundSessionStorageManager.ipdl',
|
||||
'PBackgroundStorage.ipdl',
|
||||
'PSessionStorageObserver.ipdl',
|
||||
]
|
||||
|
|
|
@ -122,5 +122,47 @@ add_task(async function() {
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
info(`Verifying SSCache is loaded to the content process only once`);
|
||||
|
||||
BrowserTestUtils.loadURI(browser, URL1);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[ORIGIN1, URL1, key, value],
|
||||
async (ORIGIN, iframeURL, key, value) => {
|
||||
is(content.window.origin, ORIGIN, `Navigate to ${ORIGIN} as expected`);
|
||||
|
||||
let iframe = content.document.createElement("iframe");
|
||||
iframe.src = iframeURL;
|
||||
content.document.body.appendChild(iframe);
|
||||
await ContentTaskUtils.waitForEvent(iframe, "load");
|
||||
|
||||
await content.SpecialPowers.spawn(
|
||||
iframe,
|
||||
[ORIGIN, key, value],
|
||||
async function(ORIGIN, key, value) {
|
||||
is(
|
||||
content.window.origin,
|
||||
ORIGIN,
|
||||
`Load an iframe to ${ORIGIN} as expected`
|
||||
);
|
||||
|
||||
let value1 = content.window.sessionStorage.getItem(key);
|
||||
is(
|
||||
value1,
|
||||
value,
|
||||
`SessionStorage for ${key} in ${content.window.origin} is ` +
|
||||
`preserved.`
|
||||
);
|
||||
|
||||
// When we are here, it means we didn't hit the assertion for
|
||||
// ensuring a SSCache can only be loaded on the content process
|
||||
// once.
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "mozilla/dom/RemoteWorkerControllerParent.h"
|
||||
#include "mozilla/dom/RemoteWorkerServiceParent.h"
|
||||
#include "mozilla/dom/ReportingHeader.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/SharedWorkerParent.h"
|
||||
#include "mozilla/dom/StorageIPC.h"
|
||||
#include "mozilla/dom/MIDIManagerParent.h"
|
||||
|
@ -471,6 +472,15 @@ bool BackgroundParentImpl::DeallocPBackgroundStorageParent(
|
|||
return mozilla::dom::DeallocPBackgroundStorageParent(aActor);
|
||||
}
|
||||
|
||||
already_AddRefed<BackgroundParentImpl::PBackgroundSessionStorageManagerParent>
|
||||
BackgroundParentImpl::AllocPBackgroundSessionStorageManagerParent(
|
||||
const uint64_t& aTopContextId) {
|
||||
AssertIsInMainOrSocketProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return dom::AllocPBackgroundSessionStorageManagerParent(aTopContextId);
|
||||
}
|
||||
|
||||
already_AddRefed<PIdleSchedulerParent>
|
||||
BackgroundParentImpl::AllocPIdleSchedulerParent() {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
@ -1072,6 +1082,37 @@ mozilla::ipc::IPCResult BackgroundParentImpl::RecvShutdownQuotaManager() {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvShutdownBackgroundSessionStorageManagers() {
|
||||
AssertIsInMainOrSocketProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (BackgroundParent::IsOtherProcessActor(this)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (!mozilla::dom::RecvShutdownBackgroundSessionStorageManagers()) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvRemoveBackgroundSessionStorageManager(
|
||||
const uint64_t& aTopContextId) {
|
||||
AssertIsInMainOrSocketProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (BackgroundParent::IsOtherProcessActor(this)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (!mozilla::dom::RecvRemoveBackgroundSessionStorageManager(aTopContextId)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<dom::PFileSystemRequestParent>
|
||||
BackgroundParentImpl::AllocPFileSystemRequestParent(
|
||||
const FileSystemParams& aParams) {
|
||||
|
|
|
@ -141,6 +141,10 @@ class BackgroundParentImpl : public PBackgroundParent,
|
|||
virtual bool DeallocPBackgroundStorageParent(
|
||||
PBackgroundStorageParent* aActor) override;
|
||||
|
||||
virtual already_AddRefed<PBackgroundSessionStorageManagerParent>
|
||||
AllocPBackgroundSessionStorageManagerParent(
|
||||
const uint64_t& aTopContextId) override;
|
||||
|
||||
virtual already_AddRefed<PIdleSchedulerParent> AllocPIdleSchedulerParent()
|
||||
override;
|
||||
|
||||
|
@ -316,6 +320,12 @@ class BackgroundParentImpl : public PBackgroundParent,
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvShutdownQuotaManager() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvShutdownBackgroundSessionStorageManagers()
|
||||
override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRemoveBackgroundSessionStorageManager(
|
||||
const uint64_t& aTopContextId) override;
|
||||
|
||||
virtual already_AddRefed<PFileSystemRequestParent>
|
||||
AllocPFileSystemRequestParent(const FileSystemParams&) override;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ include protocol PBackgroundLSObserver;
|
|||
include protocol PBackgroundLSRequest;
|
||||
include protocol PBackgroundLSSimpleRequest;
|
||||
include protocol PBackgroundLocalStorageCache;
|
||||
include protocol PBackgroundSessionStorageManager;
|
||||
include protocol PBackgroundStorage;
|
||||
include protocol PBackgroundTest;
|
||||
include protocol PBroadcastChannel;
|
||||
|
@ -82,6 +83,7 @@ sync protocol PBackground
|
|||
manages PBackgroundLSRequest;
|
||||
manages PBackgroundLSSimpleRequest;
|
||||
manages PBackgroundLocalStorageCache;
|
||||
manages PBackgroundSessionStorageManager;
|
||||
manages PBackgroundStorage;
|
||||
manages PBackgroundTest;
|
||||
manages PBroadcastChannel;
|
||||
|
@ -170,6 +172,8 @@ parent:
|
|||
nsCString originKey,
|
||||
uint32_t privateBrowsingId);
|
||||
|
||||
async PBackgroundSessionStorageManager(uint64_t aTopContextId);
|
||||
|
||||
async PBackgroundStorage(nsString profilePath);
|
||||
|
||||
async PVsync();
|
||||
|
@ -195,6 +199,10 @@ parent:
|
|||
|
||||
async ShutdownQuotaManager();
|
||||
|
||||
async ShutdownBackgroundSessionStorageManagers();
|
||||
|
||||
async RemoveBackgroundSessionStorageManager(uint64_t topContextId);
|
||||
|
||||
async PFileSystemRequest(FileSystemParams params);
|
||||
|
||||
async PGamepadEventChannel();
|
||||
|
|
|
@ -573,6 +573,10 @@ VIRTUAL_CALL_CLASSES = set([
|
|||
# .h includes something that's a LOCAL_INCLUDE
|
||||
("PBackgroundLocalStorageCache", "child"),
|
||||
("PBackgroundLocalStorageCache", "parent"),
|
||||
("PBackgroundSessionStorageCache", "child"),
|
||||
("PBackgroundSessionStorageCache", "parent"),
|
||||
("PBackgroundSessionStorageManager", "child"),
|
||||
("PBackgroundSessionStorageManager", "parent"),
|
||||
("PBackgroundStorage", "child"),
|
||||
("PBackgroundStorage", "parent"),
|
||||
("PBrowserStream", "parent"),
|
||||
|
|
|
@ -900,6 +900,8 @@ description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
|||
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
||||
[PBackgroundLSSnapshot::Ping]
|
||||
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
|
||||
[PBackgroundSessionStorageCache::Load]
|
||||
description = See corresponding comment in PBackgroundSessionStorageCache.ipdl
|
||||
[PRemoteSpellcheckEngine::CheckAndSuggest]
|
||||
description = legacy sync IPC - please add detailed description
|
||||
[PRemoteSpellcheckEngine::SetDictionary]
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
|
||||
#define LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "mozilla/AspectRatio.h"
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче