mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
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:
parent
7474b83bc5
commit
71e7900a51
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -7555,46 +7555,53 @@ void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only reset the window name for the top-level content as well as storing
|
||||
// in session entries.
|
||||
if (!GetBrowsingContext()->IsTopContent()) {
|
||||
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;
|
||||
}
|
||||
|
||||
// Following implements https://html.spec.whatwg.org/#history-traversal:
|
||||
// Step 4.2. Check if the loading document has a different origin than the
|
||||
// previous document.
|
||||
|
||||
// We don't need to do anything if we haven't loaded a non-initial document.
|
||||
if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
// when running the WPT unset_context_name-1.html. In the test, the first
|
||||
// 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.
|
||||
if (mDoc && mDoc->NodePrincipal()->EqualsConsideringDomain(
|
||||
aNewDocument->NodePrincipal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
} else if (!info->mForceMaybeResetName.ref()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Following implements https://html.spec.whatwg.org/#history-traversal:
|
||||
// Step 4.2. Check if the loading document has a different origin than the
|
||||
// previous document.
|
||||
|
||||
// We don't need to do anything if we haven't loaded a non-initial document.
|
||||
if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have an existing doucment, 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
|
||||
// when running the WPT unset_context_name-1.html. In the test, the first
|
||||
// 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.
|
||||
if (mDoc && mDoc->NodePrincipal()->EqualsConsideringDomain(
|
||||
aNewDocument->NodePrincipal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
// 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,
|
||||
|
@ -200,6 +200,8 @@ parent:
|
||||
*/
|
||||
async SetSingleChannelId(uint64_t? singleChannelId);
|
||||
|
||||
async SetDocumentDomain(nsIURI aDomain);
|
||||
|
||||
async Destroy();
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user