зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1625513) for causing assertion in WindowGlobalChild.cpp
Backed out changeset 0366bbc9e0f7 (bug 1625513) Backed out changeset 3554e0be2e66 (bug 1625513) Backed out changeset ad09a911bc43 (bug 1625513) Backed out changeset f2dbff5d584f (bug 1625513)
This commit is contained in:
Родитель
94078e13fc
Коммит
6ce4e6b1e0
|
@ -5682,51 +5682,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
async performProcessSwitch(
|
||||
aBrowser,
|
||||
aRemoteType,
|
||||
aSwitchId,
|
||||
aReplaceBrowsingContext
|
||||
) {
|
||||
E10SUtils.log().info(
|
||||
`performing switch from ${aBrowser.remoteType} to ${aRemoteType}`
|
||||
);
|
||||
|
||||
// Don't try to switch tabs before delayed startup is completed.
|
||||
await window.delayedStartupPromise;
|
||||
|
||||
// Perform a navigateAndRestore to trigger the process switch.
|
||||
let tab = this.getTabForBrowser(aBrowser);
|
||||
let loadArguments = {
|
||||
newFrameloader: true, // Switch even if remoteType hasn't changed.
|
||||
remoteType: aRemoteType, // Don't derive remoteType to switch to.
|
||||
|
||||
// Information about which channel should be performing the load.
|
||||
redirectLoadSwitchId: aSwitchId,
|
||||
|
||||
// True if this is a process switch due to a policy mismatch, means we
|
||||
// shouldn't preserve our browsing context.
|
||||
replaceBrowsingContext: aReplaceBrowsingContext,
|
||||
};
|
||||
|
||||
await SessionStore.navigateAndRestore(tab, loadArguments, -1);
|
||||
|
||||
// If the process switch seems to have failed, send an error over to our
|
||||
// caller, to give it a chance to kill our channel.
|
||||
if (
|
||||
aBrowser.remoteType != aRemoteType ||
|
||||
!aBrowser.frameLoader ||
|
||||
!aBrowser.frameLoader.remoteTab
|
||||
) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Tell our caller to redirect the load into this newly created process.
|
||||
let remoteTab = aBrowser.frameLoader.remoteTab;
|
||||
E10SUtils.log().debug(`new tabID: ${remoteTab.tabId}`);
|
||||
return remoteTab.contentProcessId;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,6 +54,7 @@ const OBSERVING = [
|
|||
"browser:purge-session-history-for-domain",
|
||||
"idle-daily",
|
||||
"clear-origin-attributes-data",
|
||||
"channel-on-may-change-process",
|
||||
];
|
||||
|
||||
// XUL Window properties to (re)store
|
||||
|
@ -518,6 +519,9 @@ var SessionStoreInternal = {
|
|||
// A counter to be used to generate a unique ID for each closed tab or window.
|
||||
_nextClosedId: 0,
|
||||
|
||||
// A monotonic value used to generate a unique ID for each process switch.
|
||||
_switchIdMonotonic: 0,
|
||||
|
||||
// During the initial restore and setBrowserState calls tracks the number of
|
||||
// windows yet to be restored
|
||||
_restoreCount: -1,
|
||||
|
@ -943,6 +947,9 @@ var SessionStoreInternal = {
|
|||
this._forgetTabsWithUserContextId(userContextId);
|
||||
}
|
||||
break;
|
||||
case "channel-on-may-change-process":
|
||||
this.onMayChangeProcess(aSubject);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2912,6 +2919,237 @@ var SessionStoreInternal = {
|
|||
}
|
||||
},
|
||||
|
||||
async _doTabProcessSwitch(
|
||||
aBrowser,
|
||||
aRemoteType,
|
||||
aChannel,
|
||||
aSwitchId,
|
||||
aReplaceBrowsingContext
|
||||
) {
|
||||
E10SUtils.log().info(
|
||||
`performing switch from ${aBrowser.remoteType} to ${aRemoteType}`
|
||||
);
|
||||
|
||||
// Don't try to switch tabs before delayed startup is completed.
|
||||
await aBrowser.ownerGlobal.delayedStartupPromise;
|
||||
|
||||
// Perform a navigateAndRestore to trigger the process switch.
|
||||
let tab = aBrowser.ownerGlobal.gBrowser.getTabForBrowser(aBrowser);
|
||||
let loadArguments = {
|
||||
newFrameloader: true, // Switch even if remoteType hasn't changed.
|
||||
remoteType: aRemoteType, // Don't derive remoteType to switch to.
|
||||
|
||||
// Information about which channel should be performing the load.
|
||||
redirectLoadSwitchId: aSwitchId,
|
||||
|
||||
// True if this is a process switch due to a policy mismatch, means we
|
||||
// shouldn't preserve our browsing context.
|
||||
replaceBrowsingContext: aReplaceBrowsingContext,
|
||||
};
|
||||
|
||||
await SessionStore.navigateAndRestore(tab, loadArguments, -1);
|
||||
|
||||
// If the process switch seems to have failed, send an error over to our
|
||||
// caller, to give it a chance to kill our channel.
|
||||
if (
|
||||
aBrowser.remoteType != aRemoteType ||
|
||||
!aBrowser.frameLoader ||
|
||||
!aBrowser.frameLoader.remoteTab
|
||||
) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Tell our caller to redirect the load into this newly created process.
|
||||
let remoteTab = aBrowser.frameLoader.remoteTab;
|
||||
E10SUtils.log().debug(`new tabID: ${remoteTab.tabId}`);
|
||||
return remoteTab.contentProcessId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform a destructive process switch into a distinct process.
|
||||
* This method is asynchronous, as it requires multiple calls into content
|
||||
* processes.
|
||||
*/
|
||||
async _doProcessSwitch(
|
||||
aBrowsingContext,
|
||||
aRemoteType,
|
||||
aChannel,
|
||||
aSwitchId,
|
||||
aReplaceBrowsingContext
|
||||
) {
|
||||
// There are two relevant cases when performing a process switch for a
|
||||
// browsing context: in-process and out-of-process embedders.
|
||||
|
||||
// If our embedder is in-process (e.g. we're a xul:browser element embedded
|
||||
// within <tabbrowser>), then we can perform a process switch using the
|
||||
// traditional mechanism.
|
||||
if (aBrowsingContext.embedderElement) {
|
||||
return this._doTabProcessSwitch(
|
||||
aBrowsingContext.embedderElement,
|
||||
aRemoteType,
|
||||
aChannel,
|
||||
aSwitchId,
|
||||
aReplaceBrowsingContext
|
||||
);
|
||||
}
|
||||
|
||||
return aBrowsingContext.changeFrameRemoteness(aRemoteType, aSwitchId);
|
||||
},
|
||||
|
||||
// Examine the channel response to see if we should change the process
|
||||
// performing the given load. aRequestor implements nsIProcessSwitchRequestor
|
||||
onMayChangeProcess(aRequestor) {
|
||||
if (!E10SUtils.documentChannel()) {
|
||||
throw new Error("This code is only used by document channel");
|
||||
}
|
||||
|
||||
let switchRequestor;
|
||||
try {
|
||||
switchRequestor = aRequestor.QueryInterface(Ci.nsIProcessSwitchRequestor);
|
||||
} catch (e) {
|
||||
E10SUtils.log().warn(`object not compatible with process switching `);
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = switchRequestor.channel;
|
||||
if (!channel.isDocument || !channel.loadInfo) {
|
||||
return; // Not a document load.
|
||||
}
|
||||
|
||||
// Check that the document has a corresponding BrowsingContext.
|
||||
let browsingContext = channel.loadInfo.targetBrowsingContext;
|
||||
let isSubframe =
|
||||
channel.loadInfo.externalContentPolicyType !=
|
||||
Ci.nsIContentPolicy.TYPE_DOCUMENT;
|
||||
|
||||
if (!browsingContext) {
|
||||
E10SUtils.log().debug(`no BrowsingContext - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if remote subframes should be used for this load.
|
||||
let topBC = browsingContext.top;
|
||||
if (!topBC.embedderElement) {
|
||||
E10SUtils.log().debug(`no embedder for top - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
let topDocShell = topBC.embedderElement.ownerGlobal.docShell;
|
||||
let { useRemoteSubframes } = topDocShell.QueryInterface(Ci.nsILoadContext);
|
||||
if (!useRemoteSubframes && isSubframe) {
|
||||
E10SUtils.log().debug(`remote subframes disabled - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get principal for a document already loaded in the BrowsingContext.
|
||||
let currentPrincipal = null;
|
||||
if (browsingContext.currentWindowGlobal) {
|
||||
currentPrincipal = browsingContext.currentWindowGlobal.documentPrincipal;
|
||||
}
|
||||
|
||||
// We can only perform a process switch on in-process frames if they are
|
||||
// embedded within a normal tab. We can't do one of these swaps for a
|
||||
// cross-origin frame.
|
||||
if (browsingContext.embedderElement) {
|
||||
let tabbrowser = browsingContext.embedderElement.getTabBrowser();
|
||||
if (!tabbrowser) {
|
||||
E10SUtils.log().debug(
|
||||
`cannot find tabbrowser for loading tab - ignoring`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let tab = tabbrowser.getTabForBrowser(browsingContext.embedderElement);
|
||||
if (!tab) {
|
||||
E10SUtils.log().debug(
|
||||
`not a normal tab, so cannot swap processes - ignoring`
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (!browsingContext.parent) {
|
||||
E10SUtils.log().debug(
|
||||
`no parent or in-process embedder element - ignoring`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current remote type for the BrowsingContext.
|
||||
let currentRemoteType = browsingContext.currentRemoteType;
|
||||
if (currentRemoteType == E10SUtils.NOT_REMOTE) {
|
||||
E10SUtils.log().debug(`currently not remote - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the process type the load should be performed in.
|
||||
let resultPrincipal = Services.scriptSecurityManager.getChannelResultPrincipal(
|
||||
channel
|
||||
);
|
||||
|
||||
const isCOOPSwitch =
|
||||
E10SUtils.useCrossOriginOpenerPolicy() &&
|
||||
switchRequestor.hasCrossOriginOpenerPolicyMismatch();
|
||||
|
||||
let preferredRemoteType = currentRemoteType;
|
||||
if (
|
||||
E10SUtils.useCrossOriginOpenerPolicy() &&
|
||||
switchRequestor.crossOriginOpenerPolicy ==
|
||||
Ci.nsILoadInfo.OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
|
||||
) {
|
||||
// We want documents with a SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
|
||||
// COOP policy to be loaded in a separate process for which we can enable
|
||||
// high resolution timers.
|
||||
preferredRemoteType =
|
||||
E10SUtils.WEB_REMOTE_COOP_COEP_TYPE_PREFIX + resultPrincipal.siteOrigin;
|
||||
} else if (isCOOPSwitch) {
|
||||
// If it is a coop switch, but doesn't have this flag, we want to switch
|
||||
// to a default remoteType
|
||||
preferredRemoteType = E10SUtils.DEFAULT_REMOTE_TYPE;
|
||||
}
|
||||
E10SUtils.log().info(
|
||||
`currentRemoteType (${currentRemoteType}) preferredRemoteType: ${preferredRemoteType}`
|
||||
);
|
||||
|
||||
let remoteType = E10SUtils.getRemoteTypeForPrincipal(
|
||||
resultPrincipal,
|
||||
true,
|
||||
useRemoteSubframes,
|
||||
preferredRemoteType,
|
||||
currentPrincipal,
|
||||
isSubframe
|
||||
);
|
||||
|
||||
E10SUtils.log().debug(
|
||||
`${currentRemoteType}, ${remoteType}, ${isCOOPSwitch}`
|
||||
);
|
||||
|
||||
if (currentRemoteType == remoteType && !isCOOPSwitch) {
|
||||
E10SUtils.log().debug(`type (${remoteType}) is compatible - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
remoteType == E10SUtils.NOT_REMOTE ||
|
||||
currentRemoteType == E10SUtils.NOT_REMOTE
|
||||
) {
|
||||
E10SUtils.log().debug(`non-remote source/target - ignoring`);
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// DANGER ZONE: Perform a process switch into the new process. This is
|
||||
// destructive.
|
||||
// ------------------------------------------------------------------------
|
||||
let identifier = ++this._switchIdMonotonic;
|
||||
let tabPromise = this._doProcessSwitch(
|
||||
browsingContext,
|
||||
remoteType,
|
||||
channel,
|
||||
identifier,
|
||||
isCOOPSwitch
|
||||
);
|
||||
switchRequestor.switchProcessTo(tabPromise, identifier);
|
||||
},
|
||||
|
||||
/* ........ nsISessionStore API .............. */
|
||||
|
||||
getBrowserState: function ssi_getBrowserState() {
|
||||
|
|
|
@ -507,6 +507,25 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> CanonicalBrowsingContext::ChangeFrameRemoteness(
|
||||
const nsAString& aRemoteType, uint64_t aPendingSwitchId, ErrorResult& aRv) {
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ChangeFrameRemoteness(aRemoteType, aPendingSwitchId)
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[promise](BrowserParent* aBrowserParent) {
|
||||
promise->MaybeResolve(aBrowserParent->Manager()->ChildID());
|
||||
},
|
||||
[promise](nsresult aRv) { promise->MaybeReject(aRv); });
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
MediaController* CanonicalBrowsingContext::GetMediaController() {
|
||||
// We would only create one media controller per tab, so accessing the
|
||||
// controller via the top-level browsing context.
|
||||
|
|
|
@ -105,6 +105,12 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
RefPtr<RemotenessPromise> ChangeFrameRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId);
|
||||
|
||||
// Helper version for WebIDL - resolves to the PID where the load is being
|
||||
// resumed.
|
||||
already_AddRefed<Promise> ChangeFrameRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Return a media controller from the top-level browsing context that can
|
||||
// control all media belonging to this browsing context tree. Return nullptr
|
||||
// if the top-level browsing context has been discarded.
|
||||
|
|
|
@ -102,6 +102,10 @@ interface CanonicalBrowsingContext : BrowsingContext {
|
|||
[Throws]
|
||||
void loadURI(DOMString aURI, optional LoadURIOptions aOptions = {});
|
||||
|
||||
[Throws]
|
||||
Promise<unsigned long long> changeFrameRemoteness(
|
||||
DOMString remoteType, unsigned long long pendingSwitchId);
|
||||
|
||||
readonly attribute nsISHistory? sessionHistory;
|
||||
};
|
||||
|
||||
|
|
|
@ -173,25 +173,4 @@ interface nsIBrowser : nsISupports
|
|||
void updateSecurityUIForSecurityChange(in nsITransportSecurityInfo aSecurityInfo,
|
||||
in uint32_t aState,
|
||||
in boolean aIsSecureContext);
|
||||
|
||||
/**
|
||||
* Called by Gecko when it wants to change the process which is currently
|
||||
* being used to render content in this tab.
|
||||
*
|
||||
* Returns a promise which will be resolved with the ChildID of the new
|
||||
* process.
|
||||
*
|
||||
* @param aRemoteType the new remote type to switch this browser into
|
||||
* @param aPendingSwitchId unique identifier for the ongoing
|
||||
* process-switching load
|
||||
* @param aReplaceBrowsingContext if true, do not preserve the
|
||||
* BrowsingContext loaded inside this
|
||||
* browser after changing processes.
|
||||
*/
|
||||
Promise performProcessSwitch(in AString aRemoteType,
|
||||
in uint64_t aPendingSwitchId,
|
||||
in boolean aReplaceBrowsingContext);
|
||||
|
||||
/** If `true`, this browser supports the `performProcessSwitch` method */
|
||||
readonly attribute bool canPerformProcessSwitch;
|
||||
};
|
||||
|
|
|
@ -17,8 +17,7 @@ using mozilla::dom::AutoJSAPI;
|
|||
namespace mozilla {
|
||||
namespace loader {
|
||||
|
||||
nsresult ImportModule(const char* aURI, const char* aExportName,
|
||||
const nsIID& aIID, void** aResult) {
|
||||
nsresult ImportModule(const char* aURI, const nsIID& aIID, void** aResult) {
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
@ -28,17 +27,6 @@ nsresult ImportModule(const char* aURI, const char* aExportName,
|
|||
MOZ_TRY(mozJSComponentLoader::Get()->Import(cx, nsDependentCString(aURI),
|
||||
&global, &exports));
|
||||
|
||||
if (aExportName) {
|
||||
JS::RootedValue namedExport(cx);
|
||||
if (!JS_GetProperty(cx, exports, aExportName, &namedExport)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!namedExport.isObject()) {
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
}
|
||||
exports.set(&namedExport.toObject());
|
||||
}
|
||||
|
||||
return nsXPConnect::XPConnect()->WrapJS(cx, exports, aIID, aResult);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,21 +15,19 @@
|
|||
namespace mozilla {
|
||||
namespace loader {
|
||||
|
||||
nsresult ImportModule(const char* aURI, const char* aExportName,
|
||||
const nsIID& aIID, void** aResult);
|
||||
nsresult ImportModule(const char* aURI, const nsIID& aIID, void** aResult);
|
||||
|
||||
} // namespace loader
|
||||
} // namespace mozilla
|
||||
|
||||
class MOZ_STACK_CLASS nsImportModule final : public nsCOMPtr_helper {
|
||||
public:
|
||||
nsImportModule(const char* aURI, const char* aExportName, nsresult* aErrorPtr)
|
||||
: mURI(aURI), mExportName(aExportName), mErrorPtr(aErrorPtr) {}
|
||||
nsImportModule(const char* aURI, nsresult* aErrorPtr)
|
||||
: mURI(aURI), mErrorPtr(aErrorPtr) {}
|
||||
|
||||
virtual nsresult NS_FASTCALL operator()(const nsIID& aIID,
|
||||
void** aResult) const override {
|
||||
nsresult rv =
|
||||
::mozilla::loader::ImportModule(mURI, mExportName, aIID, aResult);
|
||||
nsresult rv = ::mozilla::loader::ImportModule(mURI, aIID, aResult);
|
||||
if (mErrorPtr) {
|
||||
*mErrorPtr = rv;
|
||||
}
|
||||
|
@ -38,7 +36,6 @@ class MOZ_STACK_CLASS nsImportModule final : public nsCOMPtr_helper {
|
|||
|
||||
private:
|
||||
const char* mURI;
|
||||
const char* mExportName;
|
||||
nsresult* mErrorPtr;
|
||||
};
|
||||
|
||||
|
@ -67,47 +64,14 @@ class MOZ_STACK_CLASS nsImportModule final : public nsCOMPtr_helper {
|
|||
* "resource://meh/Foo.jsm");
|
||||
*
|
||||
* MOZ_TRY(foo->Foo(42));
|
||||
*
|
||||
* For JS modules which export all fields within a single named object, a second
|
||||
* argument can be passed naming that object.
|
||||
*
|
||||
* Foo.jsm:
|
||||
*
|
||||
* var EXPORTED_SYMBOLS = ["Foo"];
|
||||
*
|
||||
* var Foo = {
|
||||
* function foo(bar) {
|
||||
* return bar.toString();
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* Thing.cpp:
|
||||
*
|
||||
* nsCOMPtr<mozIFoo> foo = do_ImportModule(
|
||||
* "resource:://meh/Foo.jsm", "Foo");
|
||||
*/
|
||||
|
||||
template <size_t N>
|
||||
inline nsImportModule do_ImportModule(const char (&aURI)[N]) {
|
||||
return {aURI, nullptr, nullptr};
|
||||
inline nsImportModule do_ImportModule(const char* aURI) {
|
||||
return {aURI, nullptr};
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
inline nsImportModule do_ImportModule(const char (&aURI)[N], nsresult* aRv) {
|
||||
return {aURI, nullptr, aRv};
|
||||
}
|
||||
|
||||
template <size_t N, size_t N2>
|
||||
inline nsImportModule do_ImportModule(const char (&aURI)[N],
|
||||
const char (&aExportName)[N2]) {
|
||||
return {aURI, aExportName, nullptr};
|
||||
}
|
||||
|
||||
template <size_t N, size_t N2>
|
||||
inline nsImportModule do_ImportModule(const char (&aURI)[N],
|
||||
const char (&aExportName)[N2],
|
||||
nsresult* aRv) {
|
||||
return {aURI, aExportName, aRv};
|
||||
inline nsImportModule do_ImportModule(const char* aURI, nsresult* aRv) {
|
||||
return {aURI, aRv};
|
||||
}
|
||||
|
||||
#endif // defined nsImportModule_h
|
||||
|
|
|
@ -75,6 +75,7 @@ XPIDL_SOURCES += [
|
|||
'nsIPermission.idl',
|
||||
'nsIPermissionManager.idl',
|
||||
'nsIPrivateBrowsingChannel.idl',
|
||||
'nsIProcessSwitchRequestor.idl',
|
||||
'nsIProgressEventSink.idl',
|
||||
'nsIPrompt.idl',
|
||||
'nsIProtocolHandler.idl',
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIChannel.idl"
|
||||
|
||||
/**
|
||||
* The nsIProcessSwitchRequestor interface allows clients to instruct
|
||||
* SessionStore.jsm that a channel setup has completed and a process switch
|
||||
* may be required. This works alongside the on-may-change-process observer
|
||||
* notification.
|
||||
* This interface must be used only from the XPCOM main thread.
|
||||
*/
|
||||
[scriptable, uuid(fce8497b-c57c-4557-b360-3efefc83eff5)]
|
||||
interface nsIProcessSwitchRequestor : nsISupports
|
||||
{
|
||||
/**
|
||||
* The underlying channel object that was intercepted and that could trigger
|
||||
* a process.
|
||||
*/
|
||||
readonly attribute nsIChannel channel;
|
||||
|
||||
/**
|
||||
* Instructs the callee to be loaded in a new process. Like 'redirectTo'
|
||||
* this can only be used on channels that have not yet called their
|
||||
* listener's OnStartRequest(). Can only be called during the
|
||||
* channel-on-may-change-process observer notification.
|
||||
*
|
||||
* @param aTabPromise a promise which resolves to a nsIRemotTab object
|
||||
* which the load will proceed in.
|
||||
* @param aIdentifier a 64-bit ID which will be provided to the
|
||||
* ChildProcessChannelListener.
|
||||
*/
|
||||
[must_use] void switchProcessTo(in Promise aTabPromise,
|
||||
in unsigned long long aIdentifier);
|
||||
|
||||
/**
|
||||
* Used to determine if there is a Cross-Origin-Opener-Policy mismatch
|
||||
* that would require switching the channel to another process.
|
||||
* @throws NS_ERROR_NOT_AVAILABLE if we don't have a responseHead
|
||||
*/
|
||||
[must_use] boolean hasCrossOriginOpenerPolicyMismatch();
|
||||
|
||||
/**
|
||||
* Returns a cached CrossOriginOpenerPolicy that is computed just before we
|
||||
* determine if there is a policy mismatch.
|
||||
* @throws NS_ERROR_NOT_AVAILABLE if called before onStartRequest
|
||||
*/
|
||||
[must_use, binaryname(CachedCrossOriginOpenerPolicy)] readonly attribute nsILoadInfo_CrossOriginOpenerPolicy crossOriginOpenerPolicy;
|
||||
};
|
|
@ -41,9 +41,6 @@
|
|||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsIBrowser.h"
|
||||
#include "nsIE10SUtils.h"
|
||||
#include "nsImportModule.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
# include "mozilla/widget/nsWindow.h"
|
||||
|
@ -241,6 +238,7 @@ NS_INTERFACE_MAP_BEGIN(DocumentLoadListener)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProcessSwitchRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannelListener)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentLoadListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
@ -885,196 +883,26 @@ void DocumentLoadListener::SerializeRedirectData(
|
|||
aArgs.loadStateLoadType() = mLoadStateLoadType;
|
||||
}
|
||||
|
||||
bool DocumentLoadListener::MaybeTriggerProcessSwitch() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mDoingProcessSwitch,
|
||||
"Already in the middle of switching?");
|
||||
MOZ_DIAGNOSTIC_ASSERT(mChannel);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mParentChannelListener);
|
||||
void DocumentLoadListener::TriggerCrossProcessSwitch() {
|
||||
MOZ_ASSERT(mRedirectContentProcessIdPromise);
|
||||
MOZ_ASSERT(!mDoingProcessSwitch, "Already in the middle of switching?");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
LOG(("DocumentLoadListener MaybeTriggerProcessSwitch [this=%p]", this));
|
||||
LOG(("DocumentLoadListener TriggerCrossProcessSwitch [this=%p]", this));
|
||||
|
||||
// Get the BrowsingContext which will be switching processes.
|
||||
RefPtr<CanonicalBrowsingContext> browsingContext =
|
||||
mParentChannelListener->GetBrowsingContext();
|
||||
if (NS_WARN_IF(!browsingContext)) {
|
||||
LOG(("Process Switch Abort: no browsing context"));
|
||||
return false;
|
||||
}
|
||||
if (!browsingContext->IsContent()) {
|
||||
LOG(("Process Switch Abort: non-content browsing context"));
|
||||
return false;
|
||||
}
|
||||
if (browsingContext->GetParent() && !browsingContext->UseRemoteSubframes()) {
|
||||
LOG(("Process Switch Abort: remote subframes disabled"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We currently can't switch processes for toplevel loads unless they're
|
||||
// loaded within a browser tab.
|
||||
// FIXME: Ideally we won't do this in the future.
|
||||
nsCOMPtr<nsIBrowser> browser;
|
||||
if (!browsingContext->GetParent()) {
|
||||
Element* browserElement = browsingContext->GetEmbedderElement();
|
||||
if (!browserElement) {
|
||||
LOG(("Process Switch Abort: cannot get browser element"));
|
||||
return false;
|
||||
}
|
||||
browser = browserElement->AsBrowser();
|
||||
if (!browser) {
|
||||
LOG(("Process Switch Abort: not loaded within nsIBrowser"));
|
||||
return false;
|
||||
}
|
||||
bool loadedInTab = false;
|
||||
if (NS_FAILED(browser->GetCanPerformProcessSwitch(&loadedInTab)) ||
|
||||
!loadedInTab) {
|
||||
LOG(("Process Switch Abort: browser is not loaded in a tab"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get information about the current document loaded in our BrowsingContext.
|
||||
nsCOMPtr<nsIPrincipal> currentPrincipal;
|
||||
if (RefPtr<WindowGlobalParent> wgp =
|
||||
browsingContext->GetCurrentWindowGlobal()) {
|
||||
currentPrincipal = wgp->DocumentPrincipal();
|
||||
}
|
||||
RefPtr<ContentParent> currentProcess = browsingContext->GetContentParent();
|
||||
if (!currentProcess) {
|
||||
LOG(("Process Switch Abort: frame currently not remote"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the final principal, used to select which process to load into.
|
||||
nsCOMPtr<nsIPrincipal> resultPrincipal;
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
|
||||
mChannel, getter_AddRefs(resultPrincipal));
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Process Switch Abort: failed to get channel result principal"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resultPrincipal->IsSystemPrincipal()) {
|
||||
LOG(("Process Switch Abort: cannot switch process for system principal"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine our COOP status, which will be used to determine our preferred
|
||||
// remote type.
|
||||
bool isCOOPSwitch = HasCrossOriginOpenerPolicyMismatch();
|
||||
nsILoadInfo::CrossOriginOpenerPolicy coop =
|
||||
nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
|
||||
if (RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel)) {
|
||||
MOZ_ALWAYS_SUCCEEDS(httpChannel->GetCrossOriginOpenerPolicy(&coop));
|
||||
}
|
||||
|
||||
nsAutoString preferredRemoteType(currentProcess->GetRemoteType());
|
||||
if (coop ==
|
||||
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP) {
|
||||
// We want documents with SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP COOP
|
||||
// policy to be loaded in a separate process in which we can enable
|
||||
// high-resolution timers.
|
||||
nsAutoCString siteOrigin;
|
||||
resultPrincipal->GetSiteOrigin(siteOrigin);
|
||||
preferredRemoteType.Assign(
|
||||
NS_LITERAL_STRING(WITH_COOP_COEP_REMOTE_TYPE_PREFIX));
|
||||
preferredRemoteType.Append(NS_ConvertUTF8toUTF16(siteOrigin));
|
||||
} else if (isCOOPSwitch) {
|
||||
// If we're doing a COOP switch, we do not need any affinity to the current
|
||||
// remote type. Clear it back to the default value.
|
||||
preferredRemoteType.Assign(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(!preferredRemoteType.IsEmpty(),
|
||||
"Unexpected empty remote type!");
|
||||
|
||||
LOG(
|
||||
("DocumentLoadListener GetRemoteTypeForPrincipal "
|
||||
"[this=%p, currentProcess=%s, preferredRemoteType=%s]",
|
||||
this, NS_ConvertUTF16toUTF8(currentProcess->GetRemoteType()).get(),
|
||||
NS_ConvertUTF16toUTF8(preferredRemoteType).get()));
|
||||
|
||||
nsCOMPtr<nsIE10SUtils> e10sUtils =
|
||||
do_ImportModule("resource://gre/modules/E10SUtils.jsm", "E10SUtils");
|
||||
if (!e10sUtils) {
|
||||
LOG(("Process Switch Abort: Could not import E10SUtils"));
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString remoteType;
|
||||
rv = e10sUtils->GetRemoteTypeForPrincipal(
|
||||
resultPrincipal, browsingContext->UseRemoteTabs(),
|
||||
browsingContext->UseRemoteSubframes(), preferredRemoteType,
|
||||
currentPrincipal, browsingContext->GetParent(), remoteType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("Process Switch Abort: getRemoteTypeForPrincipal threw an exception"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if a process switch is needed.
|
||||
if (currentProcess->GetRemoteType() == remoteType && !isCOOPSwitch) {
|
||||
LOG(("Process Switch Abort: type (%s) is compatible",
|
||||
NS_ConvertUTF16toUTF8(remoteType).get()));
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(remoteType.IsEmpty())) {
|
||||
LOG(("Process Switch Abort: non-remote target process"));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(("Process Switch: Changing Remoteness from '%s' to '%s'",
|
||||
NS_ConvertUTF16toUTF8(currentProcess->GetRemoteType()).get(),
|
||||
NS_ConvertUTF16toUTF8(remoteType).get()));
|
||||
|
||||
// XXX: This is super hacky, and we should be able to do something better.
|
||||
static uint64_t sNextCrossProcessRedirectIdentifier = 0;
|
||||
mCrossProcessRedirectIdentifier = ++sNextCrossProcessRedirectIdentifier;
|
||||
mDoingProcessSwitch = true;
|
||||
|
||||
RefPtr<DocumentLoadListener> self = this;
|
||||
// At this point, we're actually going to perform a process switch, which
|
||||
// involves calling into other logic.
|
||||
if (browsingContext->GetParent()) {
|
||||
LOG(("Process Switch: Calling ChangeFrameRemoteness"));
|
||||
// If we're switching a subframe, ask BrowsingContext to do it for us.
|
||||
MOZ_ASSERT(!isCOOPSwitch);
|
||||
browsingContext
|
||||
->ChangeFrameRemoteness(remoteType, mCrossProcessRedirectIdentifier)
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self](BrowserParent* aBrowserParent) {
|
||||
MOZ_ASSERT(self->mChannel,
|
||||
"Something went wrong, channel got cancelled");
|
||||
self->TriggerRedirectToRealChannel(
|
||||
Some(aBrowserParent->Manager()->ChildID()));
|
||||
},
|
||||
[self](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
self->RedirectToRealChannelFinished(aStatusCode);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG(("Process Switch: Calling nsIBrowser::PerformProcessSwitch"));
|
||||
// We're switching a toplevel BrowsingContext's process. This has to be done
|
||||
// using nsIBrowser.
|
||||
RefPtr<Promise> domPromise;
|
||||
browser->PerformProcessSwitch(remoteType, mCrossProcessRedirectIdentifier,
|
||||
isCOOPSwitch, getter_AddRefs(domPromise));
|
||||
MOZ_DIAGNOSTIC_ASSERT(domPromise,
|
||||
"PerformProcessSwitch didn't return a promise");
|
||||
|
||||
MozPromise<uint64_t, nsresult, true>::FromDomPromise(domPromise)
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self](uint64_t aCpId) {
|
||||
MOZ_ASSERT(self->mChannel,
|
||||
"Something went wrong, channel got cancelled");
|
||||
self->TriggerRedirectToRealChannel(Some(aCpId));
|
||||
},
|
||||
[self](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
self->RedirectToRealChannelFinished(aStatusCode);
|
||||
});
|
||||
return true;
|
||||
mRedirectContentProcessIdPromise->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self, this](uint64_t aCpId) {
|
||||
MOZ_ASSERT(mChannel, "Something went wrong, channel got cancelled");
|
||||
TriggerRedirectToRealChannel(Some(aCpId));
|
||||
},
|
||||
[self](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
self->RedirectToRealChannelFinished(aStatusCode);
|
||||
});
|
||||
}
|
||||
|
||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||
|
@ -1255,10 +1083,18 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
|
|||
httpChannel->SetApplyConversion(false);
|
||||
}
|
||||
|
||||
// Determine if a new process needs to be spawned. If it does, this will
|
||||
// trigger a cross process switch, and we should hold off on redirecting to
|
||||
// the real channel.
|
||||
if (status != NS_BINDING_ABORTED && MaybeTriggerProcessSwitch()) {
|
||||
// notify "channel-on-may-change-process" observers which is typically
|
||||
// SessionStore.jsm. This will determine if a new process needs to be
|
||||
// spawned and if so SwitchProcessTo() will be called which will set a
|
||||
// ContentProcessIdPromise.
|
||||
if (status != NS_BINDING_ABORTED) {
|
||||
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
||||
obsService->NotifyObservers(ToSupports(this),
|
||||
"channel-on-may-change-process", nullptr);
|
||||
}
|
||||
|
||||
if (mRedirectContentProcessIdPromise) {
|
||||
TriggerCrossProcessSwitch();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1421,8 +1257,10 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
// include the state of all channels we redirected through.
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(aOldChannel);
|
||||
if (httpChannel) {
|
||||
mHasCrossOriginOpenerPolicyMismatch |=
|
||||
httpChannel->HasCrossOriginOpenerPolicyMismatch();
|
||||
bool mismatch = false;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
httpChannel->HasCrossOriginOpenerPolicyMismatch(&mismatch));
|
||||
mHasCrossOriginOpenerPolicyMismatch |= mismatch;
|
||||
}
|
||||
|
||||
// We don't need to confirm internal redirects or record any
|
||||
|
@ -1513,22 +1351,70 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DocumentLoadListener::nsIProcessSwitchRequestor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP DocumentLoadListener::GetChannel(nsIChannel** aChannel) {
|
||||
MOZ_ASSERT(mChannel);
|
||||
nsCOMPtr<nsIChannel> channel(mChannel);
|
||||
channel.forget(aChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DocumentLoadListener::SwitchProcessTo(
|
||||
dom::Promise* aContentProcessIdPromise, uint64_t aIdentifier) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG(aContentProcessIdPromise);
|
||||
|
||||
mRedirectContentProcessIdPromise =
|
||||
ContentProcessIdPromise::FromDomPromise(aContentProcessIdPromise);
|
||||
mCrossProcessRedirectIdentifier = aIdentifier;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This method returns the cached result of running the Cross-Origin-Opener
|
||||
// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch
|
||||
bool DocumentLoadListener::HasCrossOriginOpenerPolicyMismatch() {
|
||||
NS_IMETHODIMP
|
||||
DocumentLoadListener::HasCrossOriginOpenerPolicyMismatch(bool* aMismatch) {
|
||||
MOZ_ASSERT(aMismatch);
|
||||
|
||||
if (!aMismatch) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// If we found a COOP mismatch on an earlier channel and then
|
||||
// redirected away from that, we should use that result.
|
||||
if (mHasCrossOriginOpenerPolicyMismatch) {
|
||||
return true;
|
||||
*aMismatch = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel);
|
||||
if (!httpChannel) {
|
||||
// Not an nsHttpChannel assume it's okay to switch.
|
||||
return false;
|
||||
*aMismatch = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return httpChannel->HasCrossOriginOpenerPolicyMismatch();
|
||||
return httpChannel->HasCrossOriginOpenerPolicyMismatch(aMismatch);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentLoadListener::GetCachedCrossOriginOpenerPolicy(
|
||||
nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) {
|
||||
MOZ_ASSERT(aPolicy);
|
||||
if (!aPolicy) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel);
|
||||
if (!httpChannel) {
|
||||
*aPolicy = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return httpChannel->GetCrossOriginOpenerPolicy(aPolicy);
|
||||
}
|
||||
|
||||
auto DocumentLoadListener::AttachStreamFilter(base::ProcessId aChildProcessId)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "nsIParentChannel.h"
|
||||
#include "nsIParentRedirectingChannel.h"
|
||||
#include "nsIProcessSwitchRequestor.h"
|
||||
#include "nsIRedirectResultListener.h"
|
||||
#include "nsIMultiPartChannel.h"
|
||||
|
||||
|
@ -87,6 +88,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
public nsIParentChannel,
|
||||
public nsIChannelEventSink,
|
||||
public HttpChannelSecurityWarningReporter,
|
||||
public nsIProcessSwitchRequestor,
|
||||
public nsIMultiPartChannelListener {
|
||||
public:
|
||||
explicit DocumentLoadListener(dom::CanonicalBrowsingContext* aBrowsingContext,
|
||||
|
@ -107,6 +109,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIPROCESSSWITCHREQUESTOR
|
||||
NS_DECL_NSIMULTIPARTCHANNELLISTENER
|
||||
|
||||
// We suspend the underlying channel when replacing ourselves with
|
||||
|
@ -197,10 +200,10 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
// by us, and resumes the underlying source channel.
|
||||
void FinishReplacementChannelSetup(bool aSucceeded);
|
||||
|
||||
// Called from `OnStartRequest` to make the decision about whether or not to
|
||||
// change process. This method will return `nullptr` if the current target
|
||||
// process is appropriate.
|
||||
bool MaybeTriggerProcessSwitch();
|
||||
// Called when we have a cross-process switch promise. Waits on the
|
||||
// promise, and then call TriggerRedirectToRealChannel with the
|
||||
// provided content process id.
|
||||
void TriggerCrossProcessSwitch();
|
||||
|
||||
// A helper for TriggerRedirectToRealChannel that abstracts over
|
||||
// the same-process and cross-process switch cases and returns
|
||||
|
@ -215,8 +218,6 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
dom::CanonicalBrowsingContext* aBrowsingContext,
|
||||
nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId);
|
||||
|
||||
bool HasCrossOriginOpenerPolicyMismatch();
|
||||
|
||||
// This defines a variant that describes all the attribute setters (and their
|
||||
// parameters) from nsIParentChannel
|
||||
//
|
||||
|
@ -371,8 +372,16 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
// channel.
|
||||
bool mIsFinished = false;
|
||||
|
||||
// This identifier is set by MaybeTriggerProcessSwitch, and is later
|
||||
// passed to the childChannel in order to identify it in the new process.
|
||||
typedef MozPromise<uint64_t, nsresult, true /* exclusive */>
|
||||
ContentProcessIdPromise;
|
||||
// This promise is set following a on-may-change-process observer
|
||||
// notification when the associated channel is getting relocated to another
|
||||
// process. It will be resolved when that process is set up.
|
||||
RefPtr<ContentProcessIdPromise> mRedirectContentProcessIdPromise;
|
||||
// This identifier is set at the same time as the
|
||||
// mRedirectContentProcessIdPromise.
|
||||
// This identifier is later passed to the childChannel in order to identify it
|
||||
// once the promise is resolved.
|
||||
uint64_t mCrossProcessRedirectIdentifier = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -6227,6 +6227,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
|
|||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannelWithDivertableParentListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestTailUnblockCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProcessSwitchRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(nsHttpChannel)
|
||||
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
|
||||
|
||||
|
@ -7421,6 +7422,59 @@ nsHttpChannel::GetRequestMethod(nsACString& aMethod) {
|
|||
return HttpBaseChannel::GetRequestMethod(aMethod);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIProcessSwitchRequestor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP nsHttpChannel::GetChannel(nsIChannel** aChannel) {
|
||||
*aChannel = do_AddRef(this).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHttpChannel::SwitchProcessTo(
|
||||
dom::Promise* aContentProcessIdPromise, uint64_t aIdentifier) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG(aContentProcessIdPromise);
|
||||
|
||||
LOG(("nsHttpChannel::SwitchProcessTo [this=%p]", this));
|
||||
LogCallingScriptLocation(this);
|
||||
|
||||
nsCOMPtr<nsIParentChannel> parentChannel;
|
||||
NS_QueryNotificationCallbacks(this, parentChannel);
|
||||
RefPtr<DocumentLoadListener> documentChannelParent =
|
||||
do_QueryObject(parentChannel);
|
||||
// This is a temporary change as the DocumentChannelParent currently must go
|
||||
// through the nsHttpChannel to perform a process switch via SessionStore.
|
||||
if (!documentChannelParent) {
|
||||
// We cannot do this after OnStartRequest of the listener has been called.
|
||||
NS_ENSURE_FALSE(mOnStartRequestCalled, NS_ERROR_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
mRedirectContentProcessIdPromise =
|
||||
ContentProcessIdPromise::FromDomPromise(aContentProcessIdPromise);
|
||||
mCrossProcessRedirectIdentifier = aIdentifier;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This method returns the cached result of running the Cross-Origin-Opener
|
||||
// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::HasCrossOriginOpenerPolicyMismatch(bool* aMismatch) {
|
||||
MOZ_ASSERT(aMismatch);
|
||||
if (!aMismatch) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aMismatch = mHasCrossOriginOpenerPolicyMismatch;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetCachedCrossOriginOpenerPolicy(
|
||||
nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) {
|
||||
return HttpBaseChannel::GetCrossOriginOpenerPolicy(aPolicy);
|
||||
}
|
||||
|
||||
// See https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
|
||||
// This method runs steps 1-4 of the algorithm to compare
|
||||
// cross-origin-opener policies
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/extensions/PStreamFilterParent.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIProcessSwitchRequestor.h"
|
||||
|
||||
class nsDNSPrefetch;
|
||||
class nsICancelable;
|
||||
|
@ -78,7 +79,8 @@ class nsHttpChannel final : public HttpBaseChannel,
|
|||
public nsIChannelWithDivertableParentListener,
|
||||
public nsIRaceCacheWithNetwork,
|
||||
public nsIRequestTailUnblockCallback,
|
||||
public nsITimerCallback {
|
||||
public nsITimerCallback,
|
||||
public nsIProcessSwitchRequestor {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
@ -100,6 +102,7 @@ class nsHttpChannel final : public HttpBaseChannel,
|
|||
NS_DECL_NSIRACECACHEWITHNETWORK
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSIREQUESTTAILUNBLOCKCALLBACK
|
||||
NS_DECL_NSIPROCESSSWITCHREQUESTOR
|
||||
|
||||
// nsIHttpAuthenticableChannel. We can't use
|
||||
// NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and
|
||||
|
@ -277,6 +280,16 @@ class nsHttpChannel final : public HttpBaseChannel,
|
|||
}
|
||||
TransactionObserver* GetTransactionObserver() { return mTransactionObserver; }
|
||||
|
||||
typedef MozPromise<uint64_t, nsresult, true /* exclusive */>
|
||||
ContentProcessIdPromise;
|
||||
already_AddRefed<ContentProcessIdPromise>
|
||||
TakeRedirectContentProcessIdPromise() {
|
||||
return mRedirectContentProcessIdPromise.forget();
|
||||
}
|
||||
uint64_t CrossProcessRedirectIdentifier() {
|
||||
return mCrossProcessRedirectIdentifier;
|
||||
}
|
||||
|
||||
CacheDisposition mCacheDisposition;
|
||||
|
||||
protected:
|
||||
|
@ -485,11 +498,6 @@ class nsHttpChannel final : public HttpBaseChannel,
|
|||
nsresult ProcessCrossOriginResourcePolicyHeader();
|
||||
|
||||
nsresult ComputeCrossOriginOpenerPolicyMismatch();
|
||||
// This method returns the cached result of running the Cross-Origin-Opener
|
||||
// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch
|
||||
bool HasCrossOriginOpenerPolicyMismatch() {
|
||||
return mHasCrossOriginOpenerPolicyMismatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to process a single security header (STS or PKP), assumes
|
||||
|
@ -577,6 +585,12 @@ class nsHttpChannel final : public HttpBaseChannel,
|
|||
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||
nsCOMPtr<nsIChannel> mPreflightChannel;
|
||||
|
||||
// The associated childChannel is getting relocated to another process.
|
||||
// This promise will be resolved when that process is set up.
|
||||
RefPtr<ContentProcessIdPromise> mRedirectContentProcessIdPromise;
|
||||
// This identifier is passed to the childChannel in order to identify it.
|
||||
uint64_t mCrossProcessRedirectIdentifier = 0;
|
||||
|
||||
// nsChannelClassifier checks this channel's URI against
|
||||
// the URI classifier service.
|
||||
// nsChannelClassifier will be invoked twice in InitLocalBlockList() and
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "nsStandardURL.h"
|
||||
#include "LoadContextInfo.h"
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
#include "nsIProcessSwitchRequestor.h"
|
||||
#include "nsSocketProviderService.h"
|
||||
#include "nsISocketProvider.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
|
|
@ -35,6 +35,7 @@ class nsIHttpUpgradeListener;
|
|||
class nsIPrefBranch;
|
||||
class nsICancelable;
|
||||
class nsICookieService;
|
||||
class nsIProcessSwitchRequestor;
|
||||
class nsIIOService;
|
||||
class nsIRequestContextService;
|
||||
class nsISiteSecurityService;
|
||||
|
|
|
@ -2052,23 +2052,6 @@
|
|||
}
|
||||
return origins;
|
||||
}
|
||||
|
||||
get canPerformProcessSwitch() {
|
||||
return this.getTabBrowser() != null;
|
||||
}
|
||||
|
||||
performProcessSwitch(
|
||||
remoteType,
|
||||
redirectLoadSwitchId,
|
||||
replaceBrowsingContext
|
||||
) {
|
||||
return this.getTabBrowser().performProcessSwitch(
|
||||
this,
|
||||
remoteType,
|
||||
redirectLoadSwitchId,
|
||||
replaceBrowsingContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MozXULElement.implementCustomInterface(MozBrowser, [Ci.nsIBrowser]);
|
||||
|
|
|
@ -66,9 +66,6 @@ with Files('DeferredTask.jsm'):
|
|||
with Files("E10SUtils.jsm"):
|
||||
BUG_COMPONENT = ("Core", "Security: Process Sandboxing")
|
||||
|
||||
with Files("nsIE10SUtils.idl"):
|
||||
BUG_COMPONENT = ("Core", "Security: Process Sandboxing")
|
||||
|
||||
with Files('Finder*.jsm'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Find Toolbar')
|
||||
|
||||
|
@ -302,9 +299,3 @@ for var in ('MOZ_ALLOW_ADDON_SIDELOAD',
|
|||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
DEFINES['TOPOBJDIR'] = TOPOBJDIR
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIE10SUtils.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'toolkit_modules'
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIPrincipal;
|
||||
|
||||
/**
|
||||
* C++ exposed interface for the `E10SUtils` object from the
|
||||
* `resource://gre/modules/E10SUtils.jsm` module.
|
||||
*/
|
||||
[scriptable, uuid(1e18680e-052d-4509-a17e-678f5c495e02)]
|
||||
interface nsIE10SUtils : nsISupports {
|
||||
/**
|
||||
* Determine what remote type should be used to load a document with the given
|
||||
* principal.
|
||||
*
|
||||
* @param aPrincipal The result principal for the document being loaded.
|
||||
* @param aMultiProcess Does the browser have remote tabs enabled.
|
||||
* @param aRemoteSubframes Does the browser have remote subframes enabled.
|
||||
* @param aPreferredRemoteType If multiple remote types are compatible with
|
||||
* the load, prefer staying in this remote type.
|
||||
* @param aCurrentPrincipal The principal of the currently loaded document.
|
||||
* @param aIsSubframe Is the process switch occuring in a subframe.
|
||||
*
|
||||
* @return The remote type to complete this load in.
|
||||
*/
|
||||
AString getRemoteTypeForPrincipal(in nsIPrincipal aPrincipal,
|
||||
in boolean aMultiProcess,
|
||||
in boolean aRemoteSubframes,
|
||||
in AString aPreferredRemoteType,
|
||||
in nsIPrincipal aCurrentPrincipal,
|
||||
in boolean aIsSubframe);
|
||||
};
|
Загрузка…
Ссылка в новой задаче