commit fd219ed8433994befcbfa5d3b8387597de836bde
parent 055609159c4dac7a1c108377ae88890d8129b275
Author: Vincent Hilla <vhilla@mozilla.com>
Date: Mon, 5 Jan 2026 14:31:53 +0000
Bug 2007897 - Use normal load path when initial about:blank doesn't match remote type. r=hsivonen,dom-core
Differential Revision: https://phabricator.services.mozilla.com/D277764
Diffstat:
6 files changed, 115 insertions(+), 37 deletions(-)
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
@@ -10685,18 +10685,51 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal(
return true;
}
-bool nsDocShell::IsAboutBlankLoadOntoInitialAboutBlank(
- nsIURI* aURI, nsIPrincipal* aPrincipalToInherit) {
+bool nsDocShell::ShouldDoInitialAboutBlankSyncLoad(
+ nsIURI* aURI, nsDocShellLoadState* aLoadState,
+ nsIPrincipal* aPrincipalToInherit) {
MOZ_ASSERT(mDocumentViewer);
- bool ret = !mHasStartedLoadingOtherThanInitialBlankURI &&
- mDocumentViewer->GetDocument()->IsUncommittedInitialDocument() &&
- NS_IsAboutBlankAllowQueryAndFragment(aURI);
- if (ret && !aPrincipalToInherit) {
+
+ if (!NS_IsAboutBlankAllowQueryAndFragment(aURI)) {
+ return false;
+ }
+
+ if (aLoadState->IsInitialAboutBlankHandlingProhibited()) {
+ return false;
+ }
+
+ if (mHasStartedLoadingOtherThanInitialBlankURI ||
+ !mDocumentViewer->GetDocument()->IsUncommittedInitialDocument()) {
+ return false;
+ }
+
+ if (!aPrincipalToInherit) {
MOZ_ASSERT(
mDocumentViewer->GetDocument()->NodePrincipal()->GetIsNullPrincipal(),
"Load looks like first load but does not want principal inheritance.");
+ } else {
+ if (XRE_IsContentProcess() &&
+ !ValidatePrincipalCouldPotentiallyBeLoadedBy(
+ aPrincipalToInherit, ContentChild::GetSingleton()->GetRemoteType(),
+ {})) {
+ // Principal doesn't match our remote type, so the we need the normal
+ // load path to do a process switch.
+ return false;
+ }
+
+ // If a page opens about:blank, it will have a content principal.
+ // If it is then restored after a restart, we might not have initialized
+ // UsesOAC for it. If this is the case, do a normal load (bug 2004165).
+ // XXX bug 2005205 tracks removing this workaround.
+ if (aLoadState->LoadIsFromSessionHistory() &&
+ !mBrowsingContext->Group()
+ ->UsesOriginAgentCluster(aPrincipalToInherit)
+ .isSome()) {
+ return false;
+ }
}
- return ret;
+
+ return true;
}
void nsDocShell::UnsuppressPaintingIfNoNavigationAwayFromAboutBlank(
@@ -10977,29 +11010,14 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
inheritPrincipal = inheritAttrs && !uri->SchemeIs("data");
}
- // If a page opens about:blank, it will have a content principal.
- // If it is then restored after a restart, we might not have initialized
- // UsesOAC for it. If this is the case, do a normal load (bug 2004647).
- // XXX bug 2005205 tracks removing this workaround.
- const auto shouldSkipSyncLoadForSHRestore = [&] {
- return aLoadState->LoadIsFromSessionHistory() &&
- aLoadState->PrincipalToInherit() &&
- !mBrowsingContext->Group()
- ->UsesOriginAgentCluster(aLoadState->PrincipalToInherit())
- .isSome();
- };
-
MOZ_ASSERT_IF(NS_IsAboutBlankAllowQueryAndFragment(uri) &&
aLoadState->PrincipalToInherit(),
inheritPrincipal);
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1736570
- const bool isAboutBlankLoadOntoInitialAboutBlank =
- !aLoadState->IsInitialAboutBlankHandlingProhibited() &&
- IsAboutBlankLoadOntoInitialAboutBlank(uri,
- aLoadState->PrincipalToInherit()) &&
- !shouldSkipSyncLoadForSHRestore();
+ const bool doInitialSyncLoad = ShouldDoInitialAboutBlankSyncLoad(
+ uri, aLoadState, aLoadState->PrincipalToInherit());
- if (!isAboutBlankLoadOntoInitialAboutBlank) {
+ if (!doInitialSyncLoad) {
// https://wicg.github.io/document-picture-in-picture/#close-on-navigate
if (Document* doc = GetExtantDocument()) {
NS_DispatchToMainThread(NS_NewRunnableFunction(
@@ -11017,8 +11035,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
// in more places.
if (aLoadState->GetLoadingSessionHistoryInfo()) {
SetLoadingSessionHistoryInfo(*aLoadState->GetLoadingSessionHistoryInfo());
- } else if (isAboutBlankLoadOntoInitialAboutBlank &&
- mozilla::SessionHistoryInParent()) {
+ } else if (doInitialSyncLoad && mozilla::SessionHistoryInParent()) {
// Materialize LoadingSessionHistoryInfo here, because DocumentChannel
// loads have it, and later history behavior depends on it existing.
UniquePtr<SessionHistoryInfo> entry = MakeUnique<SessionHistoryInfo>(
@@ -11148,7 +11165,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
}
RefPtr<WindowContext> context = mBrowsingContext->GetCurrentWindowContext();
- if (isAboutBlankLoadOntoInitialAboutBlank) {
+ if (doInitialSyncLoad) {
// Stay on the eagerly created document and adjust it to match what we would
// be loading.
return CompleteInitialAboutBlankLoad(aLoadState, loadInfo);
@@ -11232,8 +11249,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
mBrowsingContext, uriModified, Some(isEmbeddingBlockedError));
nsCOMPtr<nsIChannel> channel;
- if (DocumentChannel::CanUseDocumentChannel(uri) &&
- !isAboutBlankLoadOntoInitialAboutBlank) {
+ if (DocumentChannel::CanUseDocumentChannel(uri)) {
channel = DocumentChannel::CreateForDocument(
aLoadState, loadInfo, loadFlags, this, cacheKey, uriModified,
isEmbeddingBlockedError);
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
@@ -677,8 +677,9 @@ class nsDocShell final : public nsDocLoader,
bool aNotifiedBeforeUnloadListeners = false);
public:
- bool IsAboutBlankLoadOntoInitialAboutBlank(nsIURI* aURI,
- nsIPrincipal* aPrincipalToInherit);
+ bool ShouldDoInitialAboutBlankSyncLoad(nsIURI* aURI,
+ nsDocShellLoadState* aLoadState,
+ nsIPrincipal* aPrincipalToInherit);
void UnsuppressPaintingIfNoNavigationAwayFromAboutBlank(
mozilla::PresShell* aPresShell);
diff --git a/docshell/test/browser/browser.toml b/docshell/test/browser/browser.toml
@@ -3,6 +3,7 @@ support-files = [
"Bug422543Child.sys.mjs",
"dummy_page.html",
"favicon_bug655270.ico",
+ "file_2007897.html",
"file_bug234628-1-child.html",
"file_bug234628-1.html",
"file_bug234628-10-child.xhtml",
@@ -281,6 +282,11 @@ skip-if = [
"debug", # bug 2005202
]
+["browser_bug2007897.js"]
+skip-if = [
+ "debug", # bug 2005202
+]
+
["browser_click_link_within_view_source.js"]
["browser_closewatcher_integration.js"]
diff --git a/docshell/test/browser/browser_bug2007897.js b/docshell/test/browser/browser_bug2007897.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { TabStateFlusher } = ChromeUtils.importESModule(
+ "resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
+);
+
+// Restore a page containing a cross-origin about:blank iframe
+add_task(async function test_restore_with_cross_origin_blank_iframe() {
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "https://example.com/browser/docshell/test/browser/file_2007897.html"
+ );
+
+ const blankLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, {
+ wantLoad: "about:blank",
+ includeSubFrames: true,
+ });
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
+ const ifr = content.document.querySelector("iframe");
+ await SpecialPowers.spawn(ifr, [], () => {
+ // Must use wrappedJSObject so we use the right content principal
+ content.wrappedJSObject.location = "about:blank";
+ });
+ });
+ await blankLoaded;
+
+ await TabStateFlusher.flush(tab.linkedBrowser);
+
+ const sessionStoreClosedObjectsChanged = TestUtils.topicObserved(
+ "sessionstore-closed-objects-changed"
+ );
+ gBrowser.removeTab(tab);
+ await sessionStoreClosedObjectsChanged;
+ const restoredTab = SessionStore.undoCloseTab(window, 0);
+ await BrowserTestUtils.waitForEvent(restoredTab, "SSTabRestored");
+
+ // The crash doesn't cause the test to fail, so check if the iframe was restored
+ await SpecialPowers.spawn(restoredTab.linkedBrowser, [], async () => {
+ const ifr = content.document.querySelector("iframe");
+ Assert.ok(ifr, "did not crash");
+ Assert.ok(!ifr.contentDocument && !ifr.document, "iframe is restricted");
+ });
+
+ BrowserTestUtils.removeTab(restoredTab);
+});
diff --git a/docshell/test/browser/file_2007897.html b/docshell/test/browser/file_2007897.html
@@ -0,0 +1 @@
+<iframe src="https://example.org"></iframe>
diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp
@@ -1404,11 +1404,17 @@ nsresult nsObjectLoadingContent::CloseChannel() {
bool nsObjectLoadingContent::IsAboutBlankLoadOntoInitialAboutBlank(
nsIURI* aURI, bool aInheritPrincipal, nsIPrincipal* aPrincipalToInherit) {
- return NS_IsAboutBlank(aURI) && aInheritPrincipal &&
- (!mFrameLoader || !mFrameLoader->GetExistingDocShell() ||
- mFrameLoader->GetExistingDocShell()
- ->IsAboutBlankLoadOntoInitialAboutBlank(aURI,
- aPrincipalToInherit));
+ if (!NS_IsAboutBlankAllowQueryAndFragment(aURI) || !aInheritPrincipal) {
+ return false;
+ }
+
+ if (!mFrameLoader || !mFrameLoader->GetExistingDocShell()) {
+ return false;
+ }
+
+ RefPtr<nsDocShellLoadState> dummyLoadState = new nsDocShellLoadState(mURI);
+ return mFrameLoader->GetExistingDocShell()->ShouldDoInitialAboutBlankSyncLoad(
+ aURI, dummyLoadState, aPrincipalToInherit);
}
nsresult nsObjectLoadingContent::OpenChannel() {