diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 79248ba94bf0..ef5dc099296e 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1493,8 +1493,14 @@ function _loadURI(browser, uri, params = {}) { uri = "about:blank"; } - let { triggeringPrincipal, referrerInfo, postData, userContextId, csp } = - params || {}; + let { + triggeringPrincipal, + referrerInfo, + postData, + userContextId, + csp, + remoteTypeOverride, + } = params || {}; let loadFlags = params.loadFlags || params.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE; let hasValidUserGestureActivation = @@ -1539,6 +1545,7 @@ function _loadURI(browser, uri, params = {}) { referrerInfo, postData, hasValidUserGestureActivation, + remoteTypeOverride, }; try { browser.webNavigation.loadURI(uri, loadURIOptions); diff --git a/browser/components/sessionstore/ContentRestore.jsm b/browser/components/sessionstore/ContentRestore.jsm index 9f63b4ae3b9c..eaebb0c84b5c 100644 --- a/browser/components/sessionstore/ContentRestore.jsm +++ b/browser/components/sessionstore/ContentRestore.jsm @@ -218,6 +218,10 @@ ContentRestoreInternal.prototype = { let loadURIOptions = { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, + // Specify an override to force the load to finish in the current + // process, as tests rely on this behaviour for non-fission session + // restore. + remoteTypeOverride: Services.appinfo.remoteType, }; webNavigation.loadURI("about:blank", loadURIOptions); } diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 9141f3dd7f16..b2ab433a3b1f 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -3649,6 +3649,7 @@ var SessionStoreInternal = { triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({ userContextId: aTab.userContextId, }), + remoteTypeOverride: E10SUtils.NOT_REMOTE, }); let data = TabState.collect(aTab, TAB_CUSTOM_VALUES.get(aTab)); diff --git a/docshell/base/nsDocShellLoadState.cpp b/docshell/base/nsDocShellLoadState.cpp index 6cac48a51728..fea0e2485901 100644 --- a/docshell/base/nsDocShellLoadState.cpp +++ b/docshell/base/nsDocShellLoadState.cpp @@ -88,6 +88,7 @@ nsDocShellLoadState::nsDocShellLoadState( aLoadState.loadingSessionHistoryInfo().ref()); } mUnstrippedURI = aLoadState.UnstrippedURI(); + mRemoteTypeOverride = aLoadState.RemoteTypeOverride(); } nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther) @@ -133,7 +134,8 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther) mLoadIdentifier(aOther.mLoadIdentifier), mChannelInitialized(aOther.mChannelInitialized), mIsMetaRefresh(aOther.mIsMetaRefresh), - mUnstrippedURI(aOther.mUnstrippedURI) { + mUnstrippedURI(aOther.mUnstrippedURI), + mRemoteTypeOverride(aOther.mRemoteTypeOverride) { if (aOther.mLoadingSessionHistoryInfo) { mLoadingSessionHistoryInfo = MakeUnique( *aOther.mLoadingSessionHistoryInfo); @@ -369,6 +371,11 @@ nsresult nsDocShellLoadState::CreateFromLoadURIOptions( nsDocShell::MaybeNotifyKeywordSearchLoading(searchProvider, keyword); } + if (aLoadURIOptions.mRemoteTypeOverride.WasPassed()) { + loadState->SetRemoteTypeOverride( + aLoadURIOptions.mRemoteTypeOverride.Value()); + } + loadState.forget(aResult); return NS_OK; } @@ -1046,6 +1053,7 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() { loadState.loadingSessionHistoryInfo().emplace(*mLoadingSessionHistoryInfo); } loadState.UnstrippedURI() = mUnstrippedURI; + loadState.RemoteTypeOverride() = mRemoteTypeOverride; return loadState; } diff --git a/docshell/base/nsDocShellLoadState.h b/docshell/base/nsDocShellLoadState.h index 907c9dbce6d4..fa0836bf49e8 100644 --- a/docshell/base/nsDocShellLoadState.h +++ b/docshell/base/nsDocShellLoadState.h @@ -304,6 +304,14 @@ class nsDocShellLoadState final { bool IsMetaRefresh() const { return mIsMetaRefresh; } + const mozilla::Maybe& GetRemoteTypeOverride() const { + return mRemoteTypeOverride; + } + + void SetRemoteTypeOverride(const nsCString& aRemoteTypeOverride) { + mRemoteTypeOverride = mozilla::Some(aRemoteTypeOverride); + } + // When loading a document through nsDocShell::LoadURI(), a special set of // flags needs to be set based on other values in nsDocShellLoadState. This // function calculates those flags, before the LoadState is passed to @@ -524,6 +532,9 @@ class nsDocShellLoadState final { // The original URI before query stripping happened. If it's present, it shows // the query stripping happened. Otherwise, it will be a nullptr. nsCOMPtr mUnstrippedURI; + + // If set, the remote type which the load should be completed within. + mozilla::Maybe mRemoteTypeOverride; }; #endif /* nsDocShellLoadState_h__ */ diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index df89a0506b7c..ed7b2d015a0a 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -719,6 +719,16 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() { loadState->SetLoadFlags(flags); loadState->SetFirstParty(false); + + // If we're loading the default about:blank document in a element, + // prevent the load from causing a process switch by explicitly overriding + // remote type selection. + if (mPendingBrowsingContext->IsTopContent() && + mOwnerContent->IsXULElement(nsGkAtoms::browser) && + NS_IsAboutBlank(mURIToLoad) && + loadState->TriggeringPrincipal()->IsSystemPrincipal()) { + loadState->SetRemoteTypeOverride(mRemoteType); + } } if (IsRemoteFrame()) { diff --git a/dom/ipc/DOMTypes.ipdlh b/dom/ipc/DOMTypes.ipdlh index 38efbe357823..1d91b0adef3d 100644 --- a/dom/ipc/DOMTypes.ipdlh +++ b/dom/ipc/DOMTypes.ipdlh @@ -303,6 +303,8 @@ struct DocShellLoadStateInit bool IsMetaRefresh; nsIURI UnstrippedURI; + + nsCString? RemoteTypeOverride; }; struct TimedChannelInfo diff --git a/dom/webidl/LoadURIOptions.webidl b/dom/webidl/LoadURIOptions.webidl index 734256ce9c7b..ebc4d8a096e1 100644 --- a/dom/webidl/LoadURIOptions.webidl +++ b/dom/webidl/LoadURIOptions.webidl @@ -79,4 +79,14 @@ dictionary LoadURIOptions { * when initiating the load. */ long cancelContentJSEpoch = 0; + + /** + * If this is passed, it will control which remote type is used to finish this + * load. Ignored for non-`about:` loads. + * + * NOTE: This is _NOT_ defaulted to `null`, as `null` is the value for + * `NOT_REMOTE_TYPE`, and we need to determine the difference between no + * `remoteTypeOverride` and a `remoteTypeOverride` of `NOT_REMOTE_TYPE`. + */ + UTF8String? remoteTypeOverride; }; diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp index e55e95660e51..60f3a8f89e1b 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp @@ -539,6 +539,21 @@ auto DocumentLoadListener::Open(nsDocShellLoadState* aLoadState, } } + if (aLoadState->GetRemoteTypeOverride()) { + if (!mIsDocumentLoad || !NS_IsAboutBlank(aLoadState->URI()) || + !loadingContext->IsTopContent()) { + LOG( + ("DocumentLoadListener::Open with invalid remoteTypeOverride " + "[this=%p]", + this)); + *aRv = NS_ERROR_DOM_SECURITY_ERR; + mParentChannelListener = nullptr; + return nullptr; + } + + mRemoteTypeOverride = aLoadState->GetRemoteTypeOverride(); + } + if (!nsDocShell::CreateAndConfigureRealChannelForLoadState( loadingContext, aLoadState, aLoadInfo, mParentChannelListener, nullptr, attrs, aLoadFlags, aCacheKey, *aRv, @@ -1574,6 +1589,11 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch( nsAutoCString preferredRemoteType(currentRemoteType); RemotenessChangeOptions options; + // If there is a remote type override, default to it. + if (mRemoteTypeOverride) { + preferredRemoteType = *mRemoteTypeOverride; + } + // Update the preferred final process for our load based on the // Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. { @@ -2520,6 +2540,10 @@ DocumentLoadListener::AsyncOnChannelRedirect( // the new URI and set these again. mIParentChannelFunctions.Clear(); + // If we had a remote type override, ensure it's been cleared after a + // redirect, as it can't apply anymore. + mRemoteTypeOverride.reset(); + #ifdef ANDROID nsCOMPtr uriBeingLoaded = AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel); diff --git a/netwerk/ipc/DocumentLoadListener.h b/netwerk/ipc/DocumentLoadListener.h index fb9500e78f74..69aeb21b10cb 100644 --- a/netwerk/ipc/DocumentLoadListener.h +++ b/netwerk/ipc/DocumentLoadListener.h @@ -544,6 +544,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor, bool mSupportsRedirectToRealChannel = true; + Maybe mRemoteTypeOverride; + // The process id of the content process that we are being called from // or 0 initiated from a parent process load. base::ProcessId mOtherPid = 0; diff --git a/toolkit/content/widgets/browser-custom-element.js b/toolkit/content/widgets/browser-custom-element.js index d5fc1c4950ca..eea4a0fa8c7c 100644 --- a/toolkit/content/widgets/browser-custom-element.js +++ b/toolkit/content/widgets/browser-custom-element.js @@ -814,6 +814,7 @@ postData, headers, csp, + remoteTypeOverride, } = aParams; let loadFlags = aParams.loadFlags || @@ -826,6 +827,7 @@ loadFlags, postData, headers, + remoteTypeOverride, }; this._wrapURIChangeCall(() => this.webNavigation.loadURI(aURI, loadURIOptions)