Part 7: Bug 1700623 - Make session storage session store work with Fission. r=nika

Use the newly added session storage data getter to access the session
storage in the parent and store it in session store without a round
trip to content processes.

Depends on D111433

Differential Revision: https://phabricator.services.mozilla.com/D111434
This commit is contained in:
Andreas Farre 2021-05-20 12:48:23 +00:00
Родитель d1e7d2a409
Коммит dc6296a1ba
18 изменённых файлов: 303 добавлений и 413 удалений

Просмотреть файл

@ -3025,6 +3025,14 @@ void BrowsingContext::DidSet(FieldIndex<IDX_CurrentInnerWindowId>) {
prevWindowContext->Canonical()->DidBecomeCurrentWindowGlobal(false);
}
if (mCurrentWindowContext) {
// We set a timer when we set the current inner window. This
// will then flush the session storage to session store to
// make sure that we don't miss to store session storage to
// session store that is a result of navigation. This is due
// to Bug 1700623. We wish to fix this in Bug 1711886, where
// making sure to store everything would make this timer
// unnecessary.
Canonical()->MaybeScheduleSessionStoreUpdate();
mCurrentWindowContext->Canonical()->DidBecomeCurrentWindowGlobal(true);
}
}

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
#include "mozilla/dom/PWindowGlobalParent.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/ContentProcessManager.h"
@ -42,6 +43,9 @@
#include "nsBrowserStatusFilter.h"
#include "nsIBrowser.h"
#include "nsTHashSet.h"
#include "SessionStoreFunctions.h"
#include "nsIXPConnect.h"
#include "nsImportModule.h"
#ifdef NS_PRINTING
# include "mozilla/embedding/printingui/PrintingParent.h"
@ -1022,6 +1026,8 @@ void CanonicalBrowsingContext::CanonicalDiscard() {
if (IsTop()) {
BackgroundSessionStorageManager::RemoveManager(Id());
}
CancelSessionStoreUpdate();
}
void CanonicalBrowsingContext::NotifyStartDelayedAutoplayMedia() {
@ -2026,6 +2032,119 @@ void CanonicalBrowsingContext::RestoreState::Resolve() {
mPromise = nullptr;
}
nsresult CanonicalBrowsingContext::WriteSessionStorageToSessionStore(
const nsTArray<SSCacheCopy>& aSesssionStorage, uint32_t aEpoch) {
RefPtr<WindowGlobalParent> windowParent = GetCurrentWindowGlobal();
if (!windowParent) {
return NS_OK;
}
Element* frameElement = windowParent->GetRootOwnerElement();
if (!frameElement) {
return NS_OK;
}
nsCOMPtr<nsISessionStoreFunctions> funcs =
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");
if (!funcs) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
AutoJSAPI jsapi;
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
return NS_ERROR_FAILURE;
}
Record<nsCString, Record<nsString, nsString>> storage;
JS::RootedValue update(jsapi.cx());
if (!aSesssionStorage.IsEmpty()) {
SessionStoreUtils::ConstructSessionStorageValues(this, aSesssionStorage,
storage);
if (!ToJSValue(jsapi.cx(), storage, &update)) {
return NS_ERROR_FAILURE;
}
} else {
update.setNull();
}
return funcs->UpdateSessionStoreForStorage(frameElement, this, aEpoch,
update);
}
void CanonicalBrowsingContext::UpdateSessionStoreSessionStorage(
const std::function<void()>& aDone) {
using DataPromise = BackgroundSessionStorageManager::DataPromise;
BackgroundSessionStorageManager::GetData(
this, StaticPrefs::browser_sessionstore_dom_storage_limit(),
/* aCancelSessionStoreTiemr = */ true)
->Then(GetCurrentSerialEventTarget(), __func__,
[self = RefPtr{this}, aDone, epoch = GetSessionStoreEpoch()](
const DataPromise::ResolveOrRejectValue& valueList) {
if (valueList.IsResolve()) {
self->WriteSessionStorageToSessionStore(
valueList.ResolveValue(), epoch);
}
aDone();
});
}
/* static */
void CanonicalBrowsingContext::UpdateSessionStoreForStorage(
uint64_t aBrowsingContextId) {
RefPtr<CanonicalBrowsingContext> browsingContext = Get(aBrowsingContextId);
if (!browsingContext) {
return;
}
browsingContext->UpdateSessionStoreSessionStorage([]() {});
}
void CanonicalBrowsingContext::MaybeScheduleSessionStoreUpdate() {
if (!IsTop()) {
Top()->MaybeScheduleSessionStoreUpdate();
return;
}
if (IsInBFCache()) {
return;
}
if (mSessionStoreSessionStorageUpdateTimer) {
return;
}
if (StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
UpdateSessionStoreSessionStorage([]() {});
return;
}
auto result = NS_NewTimerWithFuncCallback(
[](nsITimer*, void* aClosure) {
auto* context = static_cast<CanonicalBrowsingContext*>(aClosure);
context->UpdateSessionStoreSessionStorage([]() {});
},
this, StaticPrefs::browser_sessionstore_interval(),
nsITimer::TYPE_ONE_SHOT,
"CanonicalBrowsingContext::MaybeScheduleSessionStoreUpdate");
if (result.isErr()) {
return;
}
mSessionStoreSessionStorageUpdateTimer = result.unwrap();
}
void CanonicalBrowsingContext::CancelSessionStoreUpdate() {
if (mSessionStoreSessionStorageUpdateTimer) {
mSessionStoreSessionStorageUpdateTimer->Cancel();
mSessionStoreSessionStorageUpdateTimer = nullptr;
}
}
void CanonicalBrowsingContext::SetContainerFeaturePolicy(
FeaturePolicy* aContainerFeaturePolicy) {
mContainerFeaturePolicy = aContainerFeaturePolicy;
@ -2231,7 +2350,8 @@ bool CanonicalBrowsingContext::AllowedInBFCache(
NS_IMPL_CYCLE_COLLECTION_INHERITED(CanonicalBrowsingContext, BrowsingContext,
mSessionHistory, mContainerFeaturePolicy,
mCurrentBrowserParent)
mCurrentBrowserParent,
mSessionStoreSessionStorageUpdateTimer)
NS_IMPL_ADDREF_INHERITED(CanonicalBrowsingContext, BrowsingContext)
NS_IMPL_RELEASE_INHERITED(CanonicalBrowsingContext, BrowsingContext)

Просмотреть файл

@ -30,6 +30,7 @@ class nsSHistory;
class nsBrowserStatusFilter;
class nsSecureBrowserUI;
class CallerWillNotifyHistoryIndexAndLengthChanges;
class nsITimer;
namespace mozilla {
enum class CallState;
@ -47,6 +48,7 @@ struct LoadURIOptions;
class MediaController;
struct LoadingSessionHistoryInfo;
class SessionHistoryEntry;
class SSCacheCopy;
class WindowGlobalParent;
// RemotenessChangeOptions is passed through the methods to store the state
@ -292,6 +294,11 @@ class CanonicalBrowsingContext final : public BrowsingContext {
void RequestRestoreTabContent(WindowGlobalParent* aWindow);
already_AddRefed<Promise> GetRestorePromise();
nsresult WriteSessionStorageToSessionStore(
const nsTArray<SSCacheCopy>& aSesssionStorage, uint32_t aEpoch);
void UpdateSessionStoreSessionStorage(const std::function<void()>& aDone);
// Called when a BrowserParent for this BrowsingContext has been fully
// destroyed (i.e. `ActorDestroy` was called).
void BrowserParentDestroyed(BrowserParent* aBrowserParent,
@ -405,6 +412,10 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// has become unloaded for one reason or another.
void ShowSubframeCrashedUI(BrowserBridgeParent* aBridge);
void MaybeScheduleSessionStoreUpdate();
void CancelSessionStoreUpdate();
// XXX(farre): Store a ContentParent pointer here rather than mProcessId?
// Indicates which process owns the docshell.
uint64_t mProcessId;
@ -458,6 +469,8 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// If this is a top level context, this is true if our browser ID is marked as
// active in the process priority manager.
bool mPriorityActive = false;
nsCOMPtr<nsITimer> mSessionStoreSessionStorageUpdateTimer;
};
} // namespace dom

Просмотреть файл

@ -117,6 +117,12 @@
#include "mozilla/dom/BrowserBridgeHost.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/ContentPrincipal.h"
@ -134,6 +140,7 @@ using namespace mozilla;
using namespace mozilla::hal;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
typedef ScrollableLayerGuid::ViewID ViewID;
@ -3189,42 +3196,28 @@ already_AddRefed<Promise> nsFrameLoader::RequestTabStateFlush(
if (mSessionStoreListener) {
context->FlushSessionStore();
mSessionStoreListener->ForceFlushFromParent(false);
context->Canonical()->UpdateSessionStoreSessionStorage(
[promise]() { promise->MaybeResolveWithUndefined(); });
// No async ipc call is involved in parent only case
promise->MaybeResolveWithUndefined();
return promise.forget();
}
// XXX(farre): We hack around not having fully implemented session
// store session storage collection in the parent. What we need to
// do is to make sure that we always flush the toplevel context
// first. And also to wait for that flush to resolve. This will be
// fixed by moving session storage collection to the parent, which
// will happen in Bug 1700623.
RefPtr<ContentParent> contentParent =
context->Canonical()->GetContentParent();
using FlushPromise = ContentParent::FlushTabStatePromise;
contentParent->SendFlushTabState(context)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, context,
contentParent](const FlushPromise::ResolveOrRejectValue&) {
nsTArray<RefPtr<FlushPromise>> flushPromises;
context->Group()->EachOtherParent(
contentParent, [&](ContentParent* aParent) {
if (aParent->CanSend()) {
flushPromises.AppendElement(
aParent->SendFlushTabState(context));
}
});
nsTArray<RefPtr<FlushPromise>> flushPromises;
context->Group()->EachParent([&](ContentParent* aParent) {
if (aParent->CanSend()) {
flushPromises.AppendElement(aParent->SendFlushTabState(context));
}
});
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise](
const FlushPromise::AllPromiseType::ResolveOrRejectValue&) {
promise->MaybeResolveWithUndefined();
});
});
RefPtr<FlushPromise::AllPromiseType> flushPromise =
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises);
context->Canonical()->UpdateSessionStoreSessionStorage([flushPromise,
promise]() {
flushPromise->Then(GetCurrentSerialEventTarget(), __func__,
[promise]() { promise->MaybeResolveWithUndefined(); });
});
return promise.forget();
}
@ -3241,7 +3234,6 @@ void nsFrameLoader::RequestTabStateFlush() {
// No async ipc call is involved in parent only case
return;
}
context->Group()->EachParent([&](ContentParent* aParent) {
if (aParent->CanSend()) {
aParent->SendFlushTabState(

Просмотреть файл

@ -180,11 +180,6 @@ dictionary InputElementData {
dictionary UpdateSessionStoreData {
ByteString docShellCaps;
boolean isPrivate;
// for sessionStorage
sequence<ByteString> storageOrigins;
sequence<DOMString> storageKeys;
sequence<DOMString> storageValues;
boolean isFullStorage;
};
[GenerateConversionToJS]

Просмотреть файл

@ -3791,15 +3791,7 @@ bool BrowserChild::UpdateSessionStore(bool aIsFinal) {
privatedMode.emplace(store->GetPrivateModeEnabled());
}
nsTArray<nsCString> origins;
nsTArray<nsString> keys, values;
bool isFullStorage = false;
if (store->IsStorageUpdated()) {
isFullStorage = store->GetAndClearStorageChanges(origins, keys, values);
}
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode, origins, keys,
values, isFullStorage,
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode,
store->GetAndClearSHistoryChanged(),
aIsFinal, mSessionStoreListener->GetEpoch());
return true;

Просмотреть файл

@ -2951,8 +2951,6 @@ bool BrowserParent::ReconstructWebProgressAndRequest(
mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
nsTArray<nsCString>&& aOrigins, nsTArray<nsString>&& aKeys,
nsTArray<nsString>&& aValues, const bool aIsFullStorage,
const bool aNeedCollectSHistory, const bool& aIsFinal,
const uint32_t& aEpoch) {
UpdateSessionStoreData data;
@ -2962,16 +2960,6 @@ mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
if (aPrivatedMode.isSome()) {
data.mIsPrivate.Construct() = aPrivatedMode.value();
}
// In normal case, we only update the storage when needed.
// However, we need to reset the session storage(aOrigins.Length() will be 0)
// if the usage is over the "browser_sessionstore_dom_storage_limit".
// In this case, aIsFullStorage is true.
if (aOrigins.Length() != 0 || aIsFullStorage) {
data.mStorageOrigins.Construct(std::move(aOrigins));
data.mStorageKeys.Construct(std::move(aKeys));
data.mStorageValues.Construct(std::move(aValues));
data.mIsFullStorage.Construct() = aIsFullStorage;
}
nsCOMPtr<nsISessionStoreFunctions> funcs =
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");

Просмотреть файл

@ -314,8 +314,6 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
nsTArray<nsCString>&& aOrigins, nsTArray<nsString>&& aKeys,
nsTArray<nsString>&& aValues, const bool aIsFullStorage,
const bool aNeedCollectSHistory, const bool& aIsFinal,
const uint32_t& aEpoch);

Просмотреть файл

@ -563,8 +563,6 @@ parent:
async NavigationFinished();
async SessionStoreUpdate(nsCString? aDocShellCaps, bool? aPrivatedMode,
nsCString[] aOrigins, nsString[] aKeys,
nsString[] aValues, bool aIsFullStorage,
bool aNeedCollectSHistory,
bool aIsFinal, uint32_t aEpoch);

Просмотреть файл

@ -67,6 +67,8 @@
#include "nsIXPConnect.h"
#include "nsImportModule.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
using namespace mozilla::ipc;
using namespace mozilla::dom::ipc;
@ -1244,7 +1246,7 @@ Element* WindowGlobalParent::GetRootOwnerElement() {
return nullptr;
}
nsresult WindowGlobalParent::UpdateSessionStore(
nsresult WindowGlobalParent::WriteFormDataAndScrollToSessionStore(
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
uint32_t aEpoch) {
if (!aFormData && !aScrollPosition) {
@ -1342,7 +1344,8 @@ nsresult WindowGlobalParent::ResetSessionStore(uint32_t aEpoch) {
mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateSessionStore(
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
uint32_t aEpoch) {
if (NS_FAILED(UpdateSessionStore(aFormData, aScrollPosition, aEpoch))) {
if (NS_FAILED(WriteFormDataAndScrollToSessionStore(aFormData, aScrollPosition,
aEpoch))) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Failed to update session store entry."));
}

Просмотреть файл

@ -46,6 +46,7 @@ class JSActorMessageMeta;
struct PageUseCounters;
class WindowSessionStoreState;
struct WindowSessionStoreUpdate;
class SSCacheQueryResult;
/**
* A handle in the parent process to a specific nsGlobalWindowInner object.
@ -213,9 +214,9 @@ class WindowGlobalParent final : public WindowContext,
const nsACString& GetRemoteType() override;
nsresult UpdateSessionStore(const Maybe<FormData>& aFormData,
const Maybe<nsPoint>& aScrollPosition,
uint32_t aEpoch);
nsresult WriteFormDataAndScrollToSessionStore(
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
uint32_t aEpoch);
Maybe<uint64_t> GetSingleChannelId() { return mSingleChannelId; }

Просмотреть файл

@ -145,7 +145,8 @@ void SessionStoreDataCollector::Collect() {
if (RefPtr<WindowGlobalParent> windowParent =
mWindowChild->GetParentActor()) {
windowParent->UpdateSessionStore(maybeFormData, maybeScroll, mEpoch);
windowParent->WriteFormDataAndScrollToSessionStore(maybeFormData,
maybeScroll, mEpoch);
} else {
mWindowChild->SendUpdateSessionStore(maybeFormData, maybeScroll, mEpoch);
}

Просмотреть файл

@ -20,4 +20,8 @@ interface nsISessionStoreFunctions : nsISupports {
void UpdateSessionStoreForWindow(
in Element aBrowser, in BrowsingContext aBrowsingContext,
in uint32_t aEpoch, in jsval aData);
void UpdateSessionStoreForStorage(
in Element aBrowser, in BrowsingContext aBrowsingContext,
in uint32_t aEpoch, in jsval aData);
};

Просмотреть файл

@ -40,37 +40,27 @@ function UpdateSessionStoreForWindow(
);
}
var EXPORTED_SYMBOLS = ["UpdateSessionStore", "UpdateSessionStoreForWindow"];
function UpdateSessionStoreForStorage(
aBrowser,
aBrowsingContext,
aEpoch,
aData
) {
return SessionStoreFuncInternal.updateSessionStoreForStorage(
aBrowser,
aBrowsingContext,
aEpoch,
aData
);
}
var EXPORTED_SYMBOLS = [
"UpdateSessionStore",
"UpdateSessionStoreForWindow",
"UpdateSessionStoreForStorage",
];
var SessionStoreFuncInternal = {
updateStorage: function SSF_updateStorage(aOrigins, aKeys, aValues) {
let data = {};
for (let i = 0; i < aOrigins.length; i++) {
// If the key isn't defined, then .clear() was called, and we send
// up null for this domain to indicate that storage has been cleared
// for it.
if (aKeys[i] == "") {
while (aOrigins[i + 1] == aOrigins[i]) {
i++;
}
data[aOrigins[i]] = null;
} else {
let hostData = {};
hostData[aKeys[i]] = aValues[i];
while (aOrigins[i + 1] == aOrigins[i]) {
i++;
hostData[aKeys[i]] = aValues[i];
}
data[aOrigins[i]] = hostData;
}
}
if (aOrigins.length) {
return data;
}
return null;
},
updateSessionStore: function SSF_updateSessionStore(
aBrowser,
aBrowsingContext,
@ -86,25 +76,13 @@ var SessionStoreFuncInternal = {
currentData.isPrivate = aData.isPrivate;
}
if (aData.isFullStorage != undefined) {
let storage = this.updateStorage(
aData.storageOrigins,
aData.storageKeys,
aData.storageValues
);
if (aData.isFullStorage) {
currentData.storage = storage;
} else {
currentData.storagechange = storage;
}
}
SessionStore.updateSessionStoreFromTablistener(aBrowser, aBrowsingContext, {
data: currentData,
epoch: aEpoch,
sHistoryNeeded: aCollectSHistory,
});
},
updateSessionStoreForWindow: function SSF_updateSessionStoreForWindow(
aBrowser,
aBrowsingContext,
@ -118,4 +96,16 @@ var SessionStoreFuncInternal = {
epoch: aEpoch,
});
},
updateSessionStoreForStorage: function SSF_updateSessionStoreForWindow(
aBrowser,
aBrowsingContext,
aEpoch,
aData
) {
SessionStore.updateSessionStoreFromTablistener(aBrowser, aBrowsingContext, {
data: { storage: aData },
epoch: aEpoch,
});
},
};

Просмотреть файл

@ -7,7 +7,6 @@
#include "mozilla/dom/SessionStoreListener.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/SessionStoreUtilsBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/StaticPrefs_browser.h"
#include "nsGenericHTMLElement.h"
@ -44,7 +43,6 @@ ContentSessionStore::ContentSessionStore(nsIDocShell* aDocShell)
: mDocShell(aDocShell),
mPrivateChanged(false),
mIsPrivate(false),
mStorageStatus(NO_STORAGE),
mDocCapChanged(false),
mSHistoryChanged(false),
mSHistoryChangedFromParent(false) {
@ -104,18 +102,6 @@ bool ContentSessionStore::GetPrivateModeEnabled() {
return mIsPrivate;
}
void ContentSessionStore::SetFullStorageNeeded() {
// We need the entire session storage, reset the pending individual change
ResetStorageChanges();
mStorageStatus = FULLSTORAGE;
}
void ContentSessionStore::ResetStorageChanges() {
mOrigins.Clear();
mKeys.Clear();
mValues.Clear();
}
void ContentSessionStore::SetSHistoryChanged() {
mSHistoryChanged = mozilla::SessionHistoryInParent();
}
@ -132,15 +118,12 @@ void ContentSessionStore::OnDocumentStart() {
mDocCapChanged = true;
}
SetFullStorageNeeded();
if (mozilla::SessionHistoryInParent()) {
mSHistoryChanged = true;
}
}
void ContentSessionStore::OnDocumentEnd() {
SetFullStorageNeeded();
if (mozilla::SessionHistoryInParent()) {
mSHistoryChanged = true;
}
@ -167,8 +150,6 @@ TabListener::TabListener(nsIDocShell* aDocShell, Element* aElement)
mProgressListenerRegistered(false),
mEventListenerRegistered(false),
mPrefObserverRegistered(false),
mStorageObserverRegistered(false),
mStorageChangeListenerRegistered(false),
mUpdatedTimer(nullptr),
mTimeoutDisabled(false),
mUpdateInterval(15000),
@ -208,13 +189,6 @@ nsresult TabListener::Init() {
mPrefObserverRegistered = true;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
NS_WARNING_ASSERTION(obs, "no observer service");
if (obs) {
obs->AddObserver(this, "browser:purge-sessionStorage", true);
mStorageObserverRegistered = true;
}
AddEventListeners();
return NS_OK;
}
@ -225,10 +199,6 @@ void TabListener::AddEventListeners() {
eventTarget->AddSystemEventListener(u"DOMTitleChanged"_ns, this, false);
}
mEventListenerRegistered = true;
eventTarget->AddSystemEventListener(u"MozSessionStorageChanged"_ns, this,
false);
mStorageChangeListenerRegistered = true;
}
}
@ -241,11 +211,6 @@ void TabListener::RemoveEventListeners() {
}
mEventListenerRegistered = false;
}
if (mStorageChangeListenerRegistered) {
eventTarget->RemoveSystemEventListener(u"MozSessionStorageChanged"_ns,
this, false);
mStorageChangeListenerRegistered = false;
}
}
}
@ -324,7 +289,6 @@ NS_IMETHODIMP TabListener::OnStateChange(nsIWebProgress* aWebProgress,
if (aStateFlags & (nsIWebProgressListener::STATE_START)) {
mSessionStore->OnDocumentStart();
ResetStorageChangeListener();
} else if (aStateFlags & (nsIWebProgressListener::STATE_STOP)) {
mSessionStore->OnDocumentEnd();
}
@ -351,24 +315,7 @@ TabListener::HandleEvent(Event* aEvent) {
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("MozSessionStorageChanged")) {
auto event = static_cast<StorageEvent*>(aEvent);
RefPtr<Storage> changingStorage = event->GetStorageArea();
if (!changingStorage) {
return NS_OK;
}
// How much data does DOMSessionStorage contain?
int64_t storageUsage = changingStorage->GetOriginQuotaUsage();
if (storageUsage > StaticPrefs::browser_sessionstore_dom_storage_limit()) {
RemoveStorageChangeListener();
mSessionStore->ResetStorageChanges();
mSessionStore->ResetStorage();
return NS_OK;
}
if (mSessionStore->AppendSessionStorageChange(event)) {
AddTimerForUpdate();
}
} else if (eventType.EqualsLiteral("DOMTitleChanged")) {
if (eventType.EqualsLiteral("DOMTitleChanged")) {
mSessionStore->SetSHistoryChanged();
AddTimerForUpdate();
}
@ -411,12 +358,6 @@ NS_IMETHODIMP TabListener::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsresult TabListener::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (!strcmp(aTopic, "browser:purge-sessionStorage")) {
mSessionStore->SetFullStorageNeeded();
AddTimerForUpdate();
return NS_OK;
}
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
@ -496,61 +437,6 @@ int CollectPositions(BrowsingContext* aBrowsingContext,
return aPositionDescendants[currentIdx] + 1;
}
bool ContentSessionStore::AppendSessionStorageChange(StorageEvent* aEvent) {
// We will collect the full SessionStore if mStorageStatus is FULLSTORAGE.
// These partial changes can be skipped in this case.
if (mStorageStatus == FULLSTORAGE) {
return false;
}
RefPtr<Storage> changingStorage = aEvent->GetStorageArea();
if (!changingStorage) {
return false;
}
nsCOMPtr<nsIPrincipal> storagePrincipal = changingStorage->StoragePrincipal();
if (!storagePrincipal) {
return false;
}
nsAutoCString origin;
nsresult rv = storagePrincipal->GetOrigin(origin);
if (NS_FAILED(rv)) {
return false;
}
mOrigins.AppendElement(origin);
aEvent->GetKey(*mKeys.AppendElement());
aEvent->GetNewValue(*mValues.AppendElement());
mStorageStatus = STORAGECHANGE;
return true;
}
bool ContentSessionStore::GetAndClearStorageChanges(
nsTArray<nsCString>& aOrigins, nsTArray<nsString>& aKeys,
nsTArray<nsString>& aValues) {
MOZ_ASSERT(IsStorageUpdated());
bool isFullStorage = false;
if (mStorageStatus == RESET) {
isFullStorage = true;
} else if (mStorageStatus == FULLSTORAGE) {
MOZ_ASSERT(mDocShell);
SessionStoreUtils::CollectedSessionStorage(
nsDocShell::Cast(mDocShell)->GetBrowsingContext(), aOrigins, aKeys,
aValues);
isFullStorage = true;
} else if (mStorageStatus == STORAGECHANGE) {
aOrigins.SwapElements(mOrigins);
aKeys.SwapElements(mKeys);
aValues.SwapElements(mValues);
}
ResetStorageChanges();
mStorageStatus = NO_STORAGE;
return isFullStorage;
}
bool TabListener::ForceFlushFromParent(bool aIsFinal) {
if (!XRE_IsParentProcess()) {
return false;
@ -610,15 +496,6 @@ bool TabListener::UpdateSessionStore(bool aIsFlush, bool aIsFinal) {
if (mSessionStore->IsPrivateChanged()) {
data.mIsPrivate.Construct() = mSessionStore->GetPrivateModeEnabled();
}
if (mSessionStore->IsStorageUpdated()) {
nsTArray<nsCString> origins;
nsTArray<nsString> keys, values;
data.mIsFullStorage.Construct() =
mSessionStore->GetAndClearStorageChanges(origins, keys, values);
data.mStorageOrigins.Construct(std::move(origins));
data.mStorageKeys.Construct(std::move(keys));
data.mStorageValues.Construct(std::move(values));
}
nsCOMPtr<nsISessionStoreFunctions> funcs =
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");
@ -638,33 +515,6 @@ bool TabListener::UpdateSessionStore(bool aIsFlush, bool aIsFinal) {
return true;
}
void TabListener::ResetStorageChangeListener() {
if (mStorageChangeListenerRegistered) {
return;
}
nsCOMPtr<EventTarget> eventTarget = GetEventTarget();
if (!eventTarget) {
return;
}
eventTarget->AddSystemEventListener(u"MozSessionStorageChanged"_ns, this,
false);
mStorageChangeListenerRegistered = true;
}
void TabListener::RemoveStorageChangeListener() {
if (!mStorageChangeListenerRegistered) {
return;
}
nsCOMPtr<EventTarget> eventTarget = GetEventTarget();
if (eventTarget) {
eventTarget->RemoveSystemEventListener(u"MozSessionStorageChanged"_ns, this,
false);
mStorageChangeListenerRegistered = false;
}
}
void TabListener::RemoveListeners() {
if (mProgressListenerRegistered) {
nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mDocShell);
@ -676,7 +526,7 @@ void TabListener::RemoveListeners() {
RemoveEventListeners();
if (mPrefObserverRegistered || mStorageObserverRegistered) {
if (mPrefObserverRegistered) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!obs) {
return;
@ -686,10 +536,6 @@ void TabListener::RemoveListeners() {
obs->RemoveObserver(this, kPrefInterval);
mPrefObserverRegistered = false;
}
if (mStorageObserverRegistered) {
obs->RemoveObserver(this, "browser:purge-sessionStorage");
mStorageObserverRegistered = false;
}
}
}

Просмотреть файл

@ -19,8 +19,6 @@ class nsITimer;
namespace mozilla {
namespace dom {
class StorageEvent;
class ContentSessionStore {
public:
explicit ContentSessionStore(nsIDocShell* aDocShell);
@ -33,31 +31,6 @@ class ContentSessionStore {
bool IsPrivateChanged() { return mPrivateChanged; }
bool GetPrivateModeEnabled();
// Use "mStorageStatus" to manage the status of storageChanges
bool IsStorageUpdated() { return mStorageStatus != NO_STORAGE; }
void ResetStorage() { mStorageStatus = RESET; }
/*
There are three situations we need entire session storage:
1. OnDocumentStart: PageLoad started
2. OnDocumentEnd: PageLoad completed
3. receive "browser:purge-sessionStorage" event
Use SetFullStorageNeeded() to set correct "mStorageStatus" and
reset the pending individual change.
*/
void SetFullStorageNeeded();
void ResetStorageChanges();
// GetAndClearStorageChanges() is used for getting storageChanges.
// It clears the stored storage changes before returning.
// It will return true if it is a entire session storage.
// Otherwise, it will return false.
bool GetAndClearStorageChanges(nsTArray<nsCString>& aOrigins,
nsTArray<nsString>& aKeys,
nsTArray<nsString>& aValues);
// Using AppendSessionStorageChange() to append session storage change when
// receiving "MozSessionStorageChanged".
// Return true if there is a new storage change which is appended.
bool AppendSessionStorageChange(StorageEvent* aEvent);
void SetSHistoryChanged();
// request "collect sessionHistory" which is happened in the parent process
void SetSHistoryFromParentChanged();
@ -71,8 +44,8 @@ class ContentSessionStore {
void OnDocumentStart();
void OnDocumentEnd();
bool UpdateNeeded() {
return mPrivateChanged || mDocCapChanged || IsStorageUpdated() ||
mSHistoryChanged || mSHistoryChangedFromParent;
return mPrivateChanged || mDocCapChanged || mSHistoryChanged ||
mSHistoryChangedFromParent;
}
private:
@ -82,18 +55,8 @@ class ContentSessionStore {
nsCOMPtr<nsIDocShell> mDocShell;
bool mPrivateChanged;
bool mIsPrivate;
enum {
NO_STORAGE,
RESET,
FULLSTORAGE,
STORAGECHANGE,
} mStorageStatus;
bool mDocCapChanged;
nsCString mDocCaps;
// mOrigins, mKeys, mValues are for sessionStorage partial changes
nsTArray<nsCString> mOrigins;
nsTArray<nsString> mKeys;
nsTArray<nsString> mValues;
// mSHistoryChanged means there are history changes which are found
// in the child process. The flag is set when
// 1. webProgress changes to STATE_START
@ -138,8 +101,6 @@ class TabListener : public nsIDOMEventListener,
void AddEventListeners();
void RemoveEventListeners();
bool UpdateSessionStore(bool aIsFlush = false, bool aIsFinal = false);
void ResetStorageChangeListener();
void RemoveStorageChangeListener();
virtual ~TabListener();
nsCOMPtr<nsIDocShell> mDocShell;
@ -148,8 +109,6 @@ class TabListener : public nsIDOMEventListener,
bool mProgressListenerRegistered;
bool mEventListenerRegistered;
bool mPrefObserverRegistered;
bool mStorageObserverRegistered;
bool mStorageChangeListenerRegistered;
// Timer used to update data
nsCOMPtr<nsITimer> mUpdatedTimer;
bool mTimeoutDisabled;

Просмотреть файл

@ -24,6 +24,8 @@
#include "mozilla/dom/XPathResult.h"
#include "mozilla/dom/XPathEvaluator.h"
#include "mozilla/dom/XPathExpression.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ReverseIterator.h"
#include "mozilla/UniquePtr.h"
#include "nsCharSeparatedTokenizer.h"
@ -1262,105 +1264,6 @@ void SessionStoreUtils::RestoreFormData(
}
}
/* Read entries in the session storage data contained in a tab's history. */
static void ReadAllEntriesFromStorage(nsPIDOMWindowOuter* aWindow,
nsTArray<nsCString>& aOrigins,
nsTArray<nsString>& aKeys,
nsTArray<nsString>& aValues) {
BrowsingContext* const browsingContext = aWindow->GetBrowsingContext();
if (!browsingContext) {
return;
}
Document* doc = aWindow->GetDoc();
if (!doc) {
return;
}
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
if (!principal) {
return;
}
nsCOMPtr<nsIPrincipal> storagePrincipal = doc->EffectiveStoragePrincipal();
if (!storagePrincipal) {
return;
}
nsAutoCString origin;
nsresult rv = storagePrincipal->GetOrigin(origin);
if (NS_FAILED(rv) || aOrigins.Contains(origin)) {
// Don't read a host twice.
return;
}
/* Completed checking for recursion and is about to read storage*/
const RefPtr<SessionStorageManager> storageManager =
browsingContext->GetSessionStorageManager();
if (!storageManager) {
return;
}
RefPtr<Storage> storage;
storageManager->GetStorage(aWindow->GetCurrentInnerWindow(), principal,
storagePrincipal, false, getter_AddRefs(storage));
if (!storage) {
return;
}
mozilla::IgnoredErrorResult result;
uint32_t len = storage->GetLength(*principal, result);
if (result.Failed() || len == 0) {
return;
}
int64_t storageUsage = storage->GetOriginQuotaUsage();
if (storageUsage > StaticPrefs::browser_sessionstore_dom_storage_limit()) {
return;
}
for (uint32_t i = 0; i < len; i++) {
nsString key, value;
mozilla::IgnoredErrorResult res;
storage->Key(i, key, *principal, res);
if (res.Failed()) {
continue;
}
storage->GetItem(key, value, *principal, res);
if (res.Failed()) {
continue;
}
aKeys.AppendElement(key);
aValues.AppendElement(value);
aOrigins.AppendElement(origin);
}
}
/* Collect Collect session storage from current frame and all child frame */
/* static */
void SessionStoreUtils::CollectedSessionStorage(
BrowsingContext* aBrowsingContext, nsTArray<nsCString>& aOrigins,
nsTArray<nsString>& aKeys, nsTArray<nsString>& aValues) {
/* Collect session store from current frame */
nsPIDOMWindowOuter* window = aBrowsingContext->GetDOMWindow();
if (!window) {
return;
}
ReadAllEntriesFromStorage(window, aOrigins, aKeys, aValues);
/* Collect session storage from all child frame */
if (!window->GetDocShell()) {
return;
}
// This is not going to work for fission. Bug 1572084 for tracking it.
for (BrowsingContext* child : aBrowsingContext->Children()) {
if (!child->CreatedDynamically()) {
SessionStoreUtils::CollectedSessionStorage(child, aOrigins, aKeys,
aValues);
}
}
}
/* static */
void SessionStoreUtils::RestoreSessionStorage(
const GlobalObject& aGlobal, nsIDocShell* aDocShell,
@ -1804,6 +1707,83 @@ nsresult SessionStoreUtils::ConstructFormDataValues(
return NS_OK;
}
static nsresult ConstructSessionStorageValue(
const nsTArray<SSSetItemInfo>& aValues,
Record<nsString, nsString>& aRecord) {
auto& entries = aRecord.Entries();
for (const auto& value : aValues) {
auto entry = entries.AppendElement();
entry->mKey = value.key();
entry->mValue = value.value();
}
return NS_OK;
}
/* static */
nsresult SessionStoreUtils::ConstructSessionStorageValues(
CanonicalBrowsingContext* aBrowsingContext,
const nsTArray<SSCacheCopy>& aValues,
Record<nsCString, Record<nsString, nsString>>& aRecord) {
if (!aRecord.Entries().SetCapacity(aValues.Length(), fallible)) {
return NS_ERROR_FAILURE;
}
// We wish to remove this step of mapping originAttributes+originKey
// to a storage principal in Bug 1711886 by consolidating the
// storage format in SessionStorageManagerBase and Session Store.
nsTHashMap<nsCStringHashKey, nsIPrincipal*> storagePrincipalList;
aBrowsingContext->PreOrderWalk([&storagePrincipalList](
BrowsingContext* aContext) {
WindowGlobalParent* windowParent =
aContext->Canonical()->GetCurrentWindowGlobal();
if (!windowParent) {
return;
}
nsIPrincipal* storagePrincipal = windowParent->DocumentStoragePrincipal();
if (!storagePrincipal) {
return;
}
const OriginAttributes& originAttributes =
storagePrincipal->OriginAttributesRef();
nsAutoCString originAttributesSuffix;
originAttributes.CreateSuffix(originAttributesSuffix);
nsAutoCString originKey;
storagePrincipal->GetStorageOriginKey(originKey);
storagePrincipalList.InsertOrUpdate(originAttributesSuffix + originKey,
storagePrincipal);
});
for (const auto& value : aValues) {
nsIPrincipal* storagePrincipal =
storagePrincipalList.Get(value.originAttributes() + value.originKey());
if (!storagePrincipal) {
continue;
}
auto entry = aRecord.Entries().AppendElement();
if (!entry->mValue.Entries().SetCapacity(
value.defaultData().Length() + value.sessionData().Length(),
fallible)) {
return NS_ERROR_FAILURE;
}
if (NS_FAILED(storagePrincipal->GetOrigin(entry->mKey))) {
return NS_ERROR_FAILURE;
}
ConstructSessionStorageValue(value.defaultData(), entry->mValue);
ConstructSessionStorageValue(value.sessionData(), entry->mValue);
}
return NS_OK;
}
/* static */ void SessionStoreUtils::ResetSessionStore(
BrowsingContext* aContext) {
MOZ_RELEASE_ASSERT(NATIVE_LISTENER);

Просмотреть файл

@ -25,6 +25,8 @@ namespace dom {
class CanonicalBrowsingContext;
class GlobalObject;
struct SSScrollPositionDict;
class SSCacheCopy;
class SSSetItemInfo;
namespace sessionstore {
class DocShellRestoreState;
@ -104,11 +106,6 @@ class SessionStoreUtils {
Document& aDocument, const nsString& aInnerHTML,
const nsTArray<SessionStoreRestoreData::Entry>& aEntries);
static void CollectedSessionStorage(BrowsingContext* aBrowsingContext,
nsTArray<nsCString>& aOrigins,
nsTArray<nsString>& aKeys,
nsTArray<nsString>& aValues);
static void RestoreSessionStorage(
const GlobalObject& aGlobal, nsIDocShell* aDocShell,
const Record<nsString, Record<nsString, nsString>>& aData);
@ -138,6 +135,11 @@ class SessionStoreUtils {
aEntries,
bool aParseSessionData = false);
static nsresult ConstructSessionStorageValues(
CanonicalBrowsingContext* aBrowsingContext,
const nsTArray<SSCacheCopy>& aValues,
Record<nsCString, Record<nsString, nsString>>& aStorage);
static void ResetSessionStore(BrowsingContext* aContext);
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_THUNDERBIRD) || \