Bug 1711544 - Move decision about name resetting to the parent process if we're replacing the BC for BFCache in the parent. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D116759
This commit is contained in:
Peter Van der Beken 2021-06-21 10:31:36 +00:00
parent 7474b83bc5
commit 71e7900a51
13 changed files with 148 additions and 54 deletions

View File

@ -258,8 +258,10 @@ void CanonicalBrowsingContext::ReplacedBy(
if (aRemotenessOptions.mTryUseBFCache) {
MOZ_ASSERT(!aNewContext->EverAttached());
aNewContext->mFields.SetWithoutSyncing<IDX_Name>(GetName());
aNewContext->mFields.SetWithoutSyncing<IDX_HasLoadedNonInitialDocument>(
GetHasLoadedNonInitialDocument());
// We don't copy over HasLoadedNonInitialDocument here, we'll actually end
// up loading a new initial document at this point, before the real load.
// The real load will then end up setting HasLoadedNonInitialDocument to
// true.
}
if (mSessionHistory) {

View File

@ -494,6 +494,10 @@ class nsDocShell final : public nsDocLoader,
void SetLoadingSessionHistoryInfo(
const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo);
const mozilla::dom::LoadingSessionHistoryInfo*
GetLoadingSessionHistoryInfo() {
return mLoadingEntry.get();
}
already_AddRefed<nsIInputStream> GetPostDataFromCurrentEntry() const;
mozilla::Maybe<uint32_t> GetCacheKeyFromCurrentEntry() const;

View File

@ -1583,6 +1583,8 @@ void IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Write(
WriteIPDLParam(aMsg, aActor, aParam.mLoadIsFromSessionHistory);
WriteIPDLParam(aMsg, aActor, aParam.mRequestedIndex);
WriteIPDLParam(aMsg, aActor, aParam.mSessionHistoryLength);
WriteIPDLParam(aMsg, aActor, aParam.mLoadingCurrentActiveEntry);
WriteIPDLParam(aMsg, aActor, aParam.mForceMaybeResetName);
}
bool IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Read(
@ -1593,7 +1595,10 @@ bool IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Read(
!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mLoadIsFromSessionHistory) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRequestedIndex) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSessionHistoryLength)) {
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSessionHistoryLength) ||
!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mLoadingCurrentActiveEntry) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mForceMaybeResetName)) {
aActor->FatalError("Error reading fields for LoadingSessionHistoryInfo");
return false;
}

View File

@ -236,6 +236,13 @@ struct LoadingSessionHistoryInfo {
// If we're loading from the current active entry we want to treat it as not
// a same-document navigation (see nsDocShell::IsSameDocumentNavigation).
bool mLoadingCurrentActiveEntry = false;
// If mForceMaybeResetName.isSome() is true then the parent process has
// determined whether the BC's name should be cleared and stored in session
// history (see https://html.spec.whatwg.org/#history-traversal step 4.2).
// This is used when we're replacing the BC for BFCache in the parent. In
// other cases mForceMaybeResetName.isSome() will be false and the child
// process should be able to make that determination itself.
Maybe<bool> mForceMaybeResetName;
};
// HistoryEntryCounterForBrowsingContext is used to count the number of entries

View File

@ -928,8 +928,9 @@ static void LogEntry(nsISHEntry* aEntry, int32_t aIndex, int32_t aTotal,
}
nsCOMPtr<nsIURI> uri = aEntry->GetURI();
nsAutoString title;
nsAutoString title, name;
aEntry->GetTitle(title);
aEntry->GetName(name);
SHEntrySharedParentState* shared;
if (mozilla::SessionHistoryInParent()) {
@ -961,6 +962,9 @@ static void LogEntry(nsISHEntry* aEntry, int32_t aIndex, int32_t aTotal,
MOZ_LOG(gSHLog, LogLevel::Debug,
(" %s%s Title = %s\n", prefix.get(), childCount > 0 ? "|" : " ",
NS_LossyConvertUTF16toASCII(title).get()));
MOZ_LOG(gSHLog, LogLevel::Debug,
(" %s%s Name = %s\n", prefix.get(), childCount > 0 ? "|" : " ",
NS_LossyConvertUTF16toASCII(name).get()));
nsCOMPtr<nsISHEntry> prevChild;
for (int32_t i = 0; i < childCount; ++i) {

View File

@ -8605,6 +8605,10 @@ void Document::SetDomain(const nsAString& aDomain, ErrorResult& rv) {
MOZ_ALWAYS_SUCCEEDS(NodePrincipal()->SetDomain(newURI));
MOZ_ALWAYS_SUCCEEDS(PartitionedPrincipal()->SetDomain(newURI));
WindowGlobalChild* wgc = GetWindowGlobalChild();
if (wgc) {
wgc->SendSetDocumentDomain(newURI);
}
}
already_AddRefed<nsIURI> Document::CreateInheritingURIForHost(
@ -8645,6 +8649,21 @@ already_AddRefed<nsIURI> Document::RegistrableDomainSuffixOfInternal(
return nullptr;
}
if (!IsValidDomain(aOrigHost, newURI)) {
// Error: illegal domain
return nullptr;
}
nsAutoCString domain;
if (NS_FAILED(newURI->GetAsciiHost(domain))) {
return nullptr;
}
return CreateInheritingURIForHost(domain);
}
/* static */
bool Document::IsValidDomain(nsIURI* aOrigHost, nsIURI* aNewURI) {
// Check new domain - must be a superdomain of the current host
// For example, a page from foo.bar.com may set domain to bar.com,
// but not to ar.com, baz.com, or fi.foo.bar.com.
@ -8653,7 +8672,7 @@ already_AddRefed<nsIURI> Document::RegistrableDomainSuffixOfInternal(
if (NS_FAILED(aOrigHost->GetAsciiHost(current))) {
current.Truncate();
}
if (NS_FAILED(newURI->GetAsciiHost(domain))) {
if (NS_FAILED(aNewURI->GetAsciiHost(domain))) {
domain.Truncate();
}
@ -8665,7 +8684,7 @@ already_AddRefed<nsIURI> Document::RegistrableDomainSuffixOfInternal(
nsCOMPtr<nsIEffectiveTLDService> tldService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
if (!tldService) {
return nullptr;
return false;
}
nsAutoCString currentBaseDomain;
@ -8677,12 +8696,7 @@ already_AddRefed<nsIURI> Document::RegistrableDomainSuffixOfInternal(
ok = ok && domain.Length() >= currentBaseDomain.Length();
}
if (!ok) {
// Error: illegal domain
return nullptr;
}
return CreateInheritingURIForHost(domain);
return ok;
}
Element* Document::GetHtmlElement() const {

View File

@ -4025,6 +4025,8 @@ class Document : public nsINode,
bool ShouldAvoidNativeTheme() const;
static bool IsValidDomain(nsIURI* aOrigHost, nsIURI* aNewURI);
protected:
// Returns the WindowContext for the document that we will contribute
// page use counters to.

View File

@ -7555,8 +7555,11 @@ void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
return;
}
// We only reset the window name for the top-level content as well as storing
// in session entries.
const LoadingSessionHistoryInfo* info =
nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
if (!info || info->mForceMaybeResetName.isNothing()) {
// We only reset the window name for the top-level content as well as
// storing in session entries.
if (!GetBrowsingContext()->IsTopContent()) {
return;
}
@ -7570,7 +7573,7 @@ void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
return;
}
// If we have an existing doucment, directly check the document prinicpals
// If we have an existing document, directly check the document prinicpals
// with the new document to know if it is cross-origin.
//
// Note that there will be an issue of initial document handling in Fission
@ -7578,9 +7581,9 @@ void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
// about:blank page would be loaded with the principal of the testing domain
// in Fission and the window.name will be set there. Then, The window.name
// won't be reset after navigating to the testing page because the principal
// is the same. But, it won't be the case for non-Fission mode that the first
// about:blank will be loaded with a null principal and the window.name will
// be reset when loading the test page.
// is the same. But, it won't be the case for non-Fission mode that the
// first about:blank will be loaded with a null principal and the
// window.name will be reset when loading the test page.
if (mDoc && mDoc->NodePrincipal()->EqualsConsideringDomain(
aNewDocument->NodePrincipal())) {
return;
@ -7588,13 +7591,17 @@ void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
// If we don't have an existing document, and if it's not the initial
// about:blank, we could be loading a document because of the
// process-switching. In this case, this should be a cross-origin navigation.
// process-switching. In this case, this should be a cross-origin
// navigation.
} else if (!info->mForceMaybeResetName.ref()) {
return;
}
// Step 4.2.1 Store the window.name into all session history entries that have
// the same origin as the privious document.
// Step 4.2.2 Store the window.name into all session history entries that have
// the same origin as the previous document.
nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
// Step 4.2.2 Clear the window.name if the browsing context is the top-level
// Step 4.2.3 Clear the window.name if the browsing context is the top-level
// content and doesn't have an opener.
// We need to reset the window name in case of a cross-origin navigation,

View File

@ -200,6 +200,8 @@ parent:
*/
async SetSingleChannelId(uint64_t? singleChannelId);
async SetDocumentDomain(nsIURI aDomain);
async Destroy();
};

View File

@ -1435,6 +1435,39 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvSetSingleChannelId(
return IPC_OK();
}
mozilla::ipc::IPCResult WindowGlobalParent::RecvSetDocumentDomain(
nsIURI* aDomain) {
if (mSandboxFlags & SANDBOXED_DOMAIN) {
// We're sandboxed; disallow setting domain
return IPC_FAIL(this, "Sandbox disallows domain setting.");
}
// Might need to do a featurepolicy check here, like we currently do in the
// child process?
nsCOMPtr<nsIURI> uri;
mDocumentPrincipal->GetDomain(getter_AddRefs(uri));
if (!uri) {
uri = mDocumentPrincipal->GetURI();
if (!uri) {
return IPC_OK();
}
}
if (!Document::IsValidDomain(uri, aDomain)) {
// Error: illegal domain
return IPC_FAIL(
this, "Setting domain that's not a suffix of existing domain value.");
}
if (GetBrowsingContext()->CrossOriginIsolated()) {
return IPC_FAIL(this, "Setting domain in a cross-origin isolated BC.");
}
mDocumentPrincipal->SetDomain(aDomain);
return IPC_OK();
}
void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
if (mPageUseCountersWindow) {
mPageUseCountersWindow->FinishAccumulatingPageUseCounters();

View File

@ -299,6 +299,8 @@ class WindowGlobalParent final : public WindowContext,
mozilla::ipc::IPCResult RecvSetSingleChannelId(
const Maybe<uint64_t>& aSingleChannelId);
mozilla::ipc::IPCResult RecvSetDocumentDomain(nsIURI* aDomain);
private:
WindowGlobalParent(CanonicalBrowsingContext* aBrowsingContext,
uint64_t aInnerWindowId, uint64_t aOuterWindowId,

View File

@ -14,13 +14,7 @@ const TEST_URI =
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.window.name.update.enabled", true],
// https://bugzilla.mozilla.org/show_bug.cgi?id=1711544
// Disable bfcache for Fission for now.
// If Fission is disabled, the pref is no-op.
["fission.bfcacheInParent", false],
],
set: [["privacy.window.name.update.enabled", true]],
});
});
@ -67,6 +61,18 @@ add_task(async function doTests() {
}
});
let awaitPageShow = BrowserTestUtils.waitForContentEvent(
browser,
"pageshow"
);
browser.goBack();
await awaitPageShow;
// Check the window.name.
await SpecialPowers.spawn(browser, [], () => {
is(content.name, "Test", "The window.name is correct.");
});
BrowserTestUtils.removeTab(tab);
}
});

View File

@ -1715,6 +1715,12 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
options.mReplaceBrowsingContext = true;
options.mActiveSessionHistoryEntry =
browsingContext->GetActiveSessionHistoryEntry();
// We only reset the window name for content.
mLoadingSessionHistoryInfo->mForceMaybeResetName.emplace(
StaticPrefs::privacy_window_name_update_enabled() &&
browsingContext->IsContent() &&
(!currentPrincipal ||
!currentPrincipal->EqualsConsideringDomain(resultPrincipal)));
}
}