Bug 1650089 - Part 3: Rework DocumentChannel-triggered process switches to support null principals, r=annyG,kmag

This is a large refactoring of the DocumentChannel process switch codepath,
with the end goal of being better able to support future process switch
requirements such as dynamic isolation on android, as well as the immediate
requirement of null principal handling.

The major changes include:
1. The logic is in C++ and has less failure cases, meaning it should be harder
   for us to error out unexpectedly and not process switch.
2. Process selection decisions are more explicit, and tend to rely less on
   state such as the current remoteType when possible. This makes reasoning
   about where a specific load will complete easier.
3. Additional checks are made after a "WebContent" behavior is selected to
   ensure that if an existing document in the same BCG is found, the load will
   finish in the required content process. This should make dynamic checks such
   as Android's logged-in site isolation easier to implement.
4. ProcessIsolation logging is split out from DocumentChannel so that it's
   easier to log just the information related to process selection when
   debugging.
5. Null result principal precursors are considered when performing process
   selection.

Other uses of E10SUtils for process selection have not yet been migrated to the
new design as they have slightly different requirements. This will be done in
follow-up bugs.

Differential Revision: https://phabricator.services.mozilla.com/D120673
This commit is contained in:
Nika Layzell 2021-08-10 14:31:17 +00:00
parent 0ebcf6961e
commit aa9b1db7d6
18 changed files with 1018 additions and 347 deletions

View File

@ -279,7 +279,7 @@ void CanonicalBrowsingContext::MaybeAddAsProgressListener(
void CanonicalBrowsingContext::ReplacedBy(
CanonicalBrowsingContext* aNewContext,
const RemotenessChangeOptions& aRemotenessOptions) {
const NavigationIsolationOptions& aRemotenessOptions) {
MOZ_ASSERT(!aNewContext->mWebProgress);
MOZ_ASSERT(!aNewContext->mSessionHistory);
MOZ_ASSERT(IsTop() && aNewContext->IsTop());
@ -1696,7 +1696,7 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Clear() {
CanonicalBrowsingContext::PendingRemotenessChange::PendingRemotenessChange(
CanonicalBrowsingContext* aTarget, RemotenessPromise::Private* aPromise,
uint64_t aPendingSwitchId, const RemotenessChangeOptions& aOptions)
uint64_t aPendingSwitchId, const NavigationIsolationOptions& aOptions)
: mTarget(aTarget),
mPromise(aPromise),
mPendingSwitchId(aPendingSwitchId),
@ -1732,7 +1732,7 @@ void CanonicalBrowsingContext::SetCurrentBrowserParent(
RefPtr<CanonicalBrowsingContext::RemotenessPromise>
CanonicalBrowsingContext::ChangeRemoteness(
const RemotenessChangeOptions& aOptions, uint64_t aPendingSwitchId) {
const NavigationIsolationOptions& aOptions, uint64_t aPendingSwitchId) {
MOZ_DIAGNOSTIC_ASSERT(IsContent(),
"cannot change the process of chrome contexts");
MOZ_DIAGNOSTIC_ASSERT(
@ -2539,7 +2539,7 @@ void CanonicalBrowsingContext::RemovePageAwakeRequest() {
void CanonicalBrowsingContext::CloneDocumentTreeInto(
CanonicalBrowsingContext* aSource, const nsACString& aRemoteType,
embedding::PrintData&& aPrintData) {
RemotenessChangeOptions options;
NavigationIsolationOptions options;
options.mRemoteType = aRemoteType;
mClonePromise =

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/MediaControlKeySource.h"
#include "mozilla/dom/BrowsingContextWebProgress.h"
#include "mozilla/dom/ProcessIsolation.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStoreRestoreData.h"
@ -55,16 +56,6 @@ struct LoadingSessionHistoryInfo;
class SSCacheCopy;
class WindowGlobalParent;
// RemotenessChangeOptions is passed through the methods to store the state
// of the possible remoteness change.
struct RemotenessChangeOptions {
nsCString mRemoteType;
bool mReplaceBrowsingContext = false;
uint64_t mSpecificGroupId = 0;
bool mTryUseBFCache = false;
RefPtr<SessionHistoryEntry> mActiveSessionHistoryEntry;
};
// CanonicalBrowsingContext is a BrowsingContext living in the parent
// process, with whatever extra data that a BrowsingContext in the
// parent needs.
@ -233,7 +224,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// the parent process, and the method will resolve with a null BrowserParent.
using RemotenessPromise = MozPromise<RefPtr<BrowserParent>, nsresult, false>;
RefPtr<RemotenessPromise> ChangeRemoteness(
const RemotenessChangeOptions& aOptions, uint64_t aPendingSwitchId);
const NavigationIsolationOptions& aOptions, uint64_t aPendingSwitchId);
// Return a media controller from the top-level browsing context that can
// control all media belonging to this browsing context tree. Return nullptr
@ -272,7 +263,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// aNewContext is the newly created BrowsingContext that is replacing
// us.
void ReplacedBy(CanonicalBrowsingContext* aNewContext,
const RemotenessChangeOptions& aRemotenessOptions);
const NavigationIsolationOptions& aRemotenessOptions);
bool HasHistoryEntry(nsISHEntry* aEntry);
@ -388,7 +379,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
PendingRemotenessChange(CanonicalBrowsingContext* aTarget,
RemotenessPromise::Private* aPromise,
uint64_t aPendingSwitchId,
const RemotenessChangeOptions& aOptions);
const NavigationIsolationOptions& aOptions);
void Cancel(nsresult aRv);
@ -411,7 +402,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
RefPtr<BrowsingContextGroup> mSpecificGroup;
uint64_t mPendingSwitchId;
RemotenessChangeOptions mOptions;
NavigationIsolationOptions mOptions;
};
struct RestoreState {

View File

@ -1244,7 +1244,7 @@ static void FinishRestore(CanonicalBrowsingContext* aBrowsingContext,
// ReplacedBy will swap the entry back.
aBrowsingContext->SetActiveSessionHistoryEntry(aEntry);
loadingBC->SetActiveSessionHistoryEntry(nullptr);
RemotenessChangeOptions options;
NavigationIsolationOptions options;
aBrowsingContext->ReplacedBy(loadingBC, options);
// Assuming we still have the session history, update the index.

View File

@ -481,7 +481,7 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Create(
already_AddRefed<nsFrameLoader> nsFrameLoader::Recreate(
mozilla::dom::Element* aOwner, BrowsingContext* aContext,
BrowsingContextGroup* aSpecificGroup,
const RemotenessChangeOptions& aRemotenessOptions, bool aIsRemote,
const NavigationIsolationOptions& aRemotenessOptions, bool aIsRemote,
bool aNetworkCreated, bool aPreserveContext) {
NS_ENSURE_TRUE(aOwner, nullptr);

View File

@ -72,7 +72,7 @@ class MutableTabContext;
class BrowserBridgeChild;
class RemoteBrowser;
struct RemotenessOptions;
struct RemotenessChangeOptions;
struct NavigationIsolationOptions;
class SessionStoreChangeListener;
namespace ipc {
@ -123,7 +123,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
// FrameLoaders.
static already_AddRefed<nsFrameLoader> Recreate(
Element* aOwner, BrowsingContext* aContext, BrowsingContextGroup* aGroup,
const mozilla::dom::RemotenessChangeOptions& aRemotenessOptions,
const mozilla::dom::NavigationIsolationOptions& aRemotenessOptions,
bool aIsRemote, bool aNetworkCreated, bool aPreserveContext);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)

View File

@ -92,7 +92,7 @@ nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
void nsFrameLoaderOwner::ChangeRemotenessCommon(
const ChangeRemotenessContextType& aContextType,
const RemotenessChangeOptions& aOptions, bool aSwitchingInProgressLoad,
const NavigationIsolationOptions& aOptions, bool aSwitchingInProgressLoad,
bool aIsRemote, BrowsingContextGroup* aGroup,
std::function<void()>& aFrameLoaderInit, mozilla::ErrorResult& aRv) {
MOZ_ASSERT_IF(aGroup, aContextType != ChangeRemotenessContextType::PRESERVE);
@ -263,7 +263,7 @@ void nsFrameLoaderOwner::ChangeRemoteness(
auto shouldPreserve = ShouldPreserveBrowsingContext(
isRemote, /* replaceBrowsingContext */ false);
RemotenessChangeOptions options;
NavigationIsolationOptions options;
ChangeRemotenessCommon(shouldPreserve, options,
aOptions.mSwitchingInProgressLoad, isRemote,
/* group */ nullptr, frameLoaderInit, rv);
@ -286,7 +286,7 @@ void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
mFrameLoader->mInitialized = true;
};
RemotenessChangeOptions options;
NavigationIsolationOptions options;
ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE, options,
/* inProgress */ true,
/* isRemote */ true, /* group */ nullptr,
@ -294,7 +294,7 @@ void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
}
void nsFrameLoaderOwner::ChangeRemotenessToProcess(
ContentParent* aContentParent, const RemotenessChangeOptions& aOptions,
ContentParent* aContentParent, const NavigationIsolationOptions& aOptions,
BrowsingContextGroup* aGroup, mozilla::ErrorResult& rv) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT_IF(aGroup, aOptions.mReplaceBrowsingContext);
@ -337,7 +337,7 @@ void nsFrameLoaderOwner::SubframeCrashed() {
}));
};
RemotenessChangeOptions options;
NavigationIsolationOptions options;
ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE, options,
/* inProgress */ false, /* isRemote */ false,
/* group */ nullptr, frameLoaderInit, IgnoreErrors());

View File

@ -20,7 +20,7 @@ class BrowserBridgeChild;
class ContentParent;
class Element;
struct RemotenessOptions;
struct RemotenessChangeOptions;
struct NavigationIsolationOptions;
} // namespace dom
} // namespace mozilla
@ -75,7 +75,7 @@ class nsFrameLoaderOwner : public nsISupports {
// disabled for this process switch.
void ChangeRemotenessToProcess(
mozilla::dom::ContentParent* aContentParent,
const mozilla::dom::RemotenessChangeOptions& aOptions,
const mozilla::dom::NavigationIsolationOptions& aOptions,
mozilla::dom::BrowsingContextGroup* aGroup, mozilla::ErrorResult& rv);
void SubframeCrashed();
@ -104,7 +104,7 @@ class nsFrameLoaderOwner : public nsISupports {
void ChangeRemotenessCommon(
const ChangeRemotenessContextType& aContextType,
const mozilla::dom::RemotenessChangeOptions& aOptions,
const mozilla::dom::NavigationIsolationOptions& aOptions,
bool aSwitchingInProgressLoad, bool aIsRemote,
mozilla::dom::BrowsingContextGroup* aGroup,
std::function<void()>& aFrameLoaderInit, mozilla::ErrorResult& aRv);

View File

@ -0,0 +1,819 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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 "mozilla/dom/ProcessIsolation.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/RemoteType.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ContentPrincipal.h"
#include "mozilla/ExtensionPolicyService.h"
#include "mozilla/Logging.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/Preferences.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPtr.h"
#include "nsAboutProtocolUtils.h"
#include "nsDocShell.h"
#include "nsError.h"
#include "nsIChromeRegistry.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIProtocolHandler.h"
#include "nsIXULRuntime.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsSHistory.h"
#include "nsURLHelper.h"
namespace mozilla::dom {
mozilla::LazyLogModule gProcessIsolationLog{"ProcessIsolation"};
namespace {
/**
* Helper class for caching the result of splitting prefs which are represented
* as a comma-separated list of strings.
*/
struct CommaSeparatedPref {
public:
explicit constexpr CommaSeparatedPref(nsLiteralCString aPrefName)
: mPrefName(aPrefName) {}
void OnChange() {
if (mValues) {
mValues->Clear();
nsAutoCString prefValue;
if (NS_SUCCEEDED(Preferences::GetCString(mPrefName.get(), prefValue))) {
for (const auto& value :
nsCCharSeparatedTokenizer(prefValue, ',').ToRange()) {
mValues->EmplaceBack(value);
}
}
}
}
const nsTArray<nsCString>& Get() {
if (!mValues) {
mValues = new nsTArray<nsCString>;
Preferences::RegisterCallbackAndCall(
[](const char*, void* aData) {
static_cast<CommaSeparatedPref*>(aData)->OnChange();
},
mPrefName, this);
RunOnShutdown([this] {
delete this->mValues;
this->mValues = nullptr;
});
}
return *mValues;
}
auto begin() { return Get().cbegin(); }
auto end() { return Get().cend(); }
private:
nsLiteralCString mPrefName;
nsTArray<nsCString>* MOZ_OWNING_REF mValues = nullptr;
};
CommaSeparatedPref sSeparatedMozillaDomains{
"browser.tabs.remote.separatedMozillaDomains"_ns};
/**
* Certain URIs have special isolation behaviour, and need to be loaded within
* specific process types.
*/
enum class IsolationBehavior {
// This URI loads web content and should be treated as a content load, being
// isolated based on the response principal.
WebContent,
// Forcibly load in a process with the "web" remote type.
ForceWebRemoteType,
// Load this URI in the privileged about content process.
PrivilegedAbout,
// Load this URI in the extension process.
Extension,
// Load this URI in the file content process.
File,
// Load this URI in the priviliged mozilla content process.
PrivilegedMozilla,
// Load this URI explicitly in the parent process.
Parent,
// Load this URI wherever the browsing context is currently loaded. This is
// generally used for error pages.
Anywhere,
// May only be returned for subframes. Inherits the remote type of the parent
// document which is embedding this document.
Inherit,
// Special case for the `about:reader` URI which should be loaded in the same
// process which would be used for the "url" query parameter.
AboutReader,
// There was a fatal error, and the load should be aborted.
Error,
};
/**
* Returns a static string with the name of the given isolation behaviour. For
* use in logging code.
*/
static const char* IsolationBehaviorName(IsolationBehavior aBehavior) {
switch (aBehavior) {
case IsolationBehavior::WebContent:
return "WebContent";
case IsolationBehavior::ForceWebRemoteType:
return "ForceWebRemoteType";
case IsolationBehavior::PrivilegedAbout:
return "PrivilegedAbout";
case IsolationBehavior::Extension:
return "Extension";
case IsolationBehavior::File:
return "File";
case IsolationBehavior::PrivilegedMozilla:
return "PrivilegedMozilla";
case IsolationBehavior::Parent:
return "Parent";
case IsolationBehavior::Anywhere:
return "Anywhere";
case IsolationBehavior::Inherit:
return "Inherit";
case IsolationBehavior::AboutReader:
return "AboutReader";
case IsolationBehavior::Error:
return "Error";
default:
return "Unknown";
}
}
/**
* Check if a given URI has specialized process isolation behaviour, such as
* needing to be loaded within a specific type of content process.
*
* When handling a navigation, this method will be called twice: first with the
* channel's creation URI, and then it will be called with a result principal's
* URI.
*/
static IsolationBehavior IsolationBehaviorForURI(nsIURI* aURI, bool aIsSubframe,
bool aForChannelCreationURI) {
nsAutoCString scheme;
MOZ_ALWAYS_SUCCEEDS(aURI->GetScheme(scheme));
if (scheme == "chrome"_ns) {
// `chrome://` URIs are always loaded in the parent process, unless they
// have opted in to loading in a content process. This is currently only
// done in tests.
//
// FIXME: These flags should be removed from `chrome` URIs at some point.
nsCOMPtr<nsIXULChromeRegistry> chromeReg =
do_GetService("@mozilla.org/chrome/chrome-registry;1");
bool mustLoadRemotely = false;
if (NS_SUCCEEDED(chromeReg->MustLoadURLRemotely(aURI, &mustLoadRemotely)) &&
mustLoadRemotely) {
return IsolationBehavior::ForceWebRemoteType;
}
bool canLoadRemotely = false;
if (NS_SUCCEEDED(chromeReg->CanLoadURLRemotely(aURI, &canLoadRemotely)) &&
canLoadRemotely) {
return IsolationBehavior::Anywhere;
}
return IsolationBehavior::Parent;
}
if (scheme == "about"_ns) {
nsAutoCString path;
MOZ_ALWAYS_SUCCEEDS(NS_GetAboutModuleName(aURI, path));
// The `about:blank` and `about:srcdoc` pages are loaded by normal web
// content, and should be allocated processes based on their simple content
// principals.
if (path == "blank"_ns || path == "srcdoc"_ns) {
return IsolationBehavior::WebContent;
}
// If we're loading an `about:reader` URI, perform isolation based on the
// principal of the URI being loaded.
if (path == "reader"_ns && aForChannelCreationURI) {
return IsolationBehavior::AboutReader;
}
// Otherwise, we're going to be loading an about: page. Consult the module.
nsCOMPtr<nsIAboutModule> aboutModule;
if (NS_FAILED(NS_GetAboutModule(aURI, getter_AddRefs(aboutModule))) ||
!aboutModule) {
// If we don't know of an about: module for this load, it's going to end
// up being a network error. Allow the load to finish as normal.
return IsolationBehavior::WebContent;
}
// NOTE: about modules can be implemented in JS, so this may run script, and
// therefore can spuriously fail.
uint32_t flags = 0;
if (NS_FAILED(aboutModule->GetURIFlags(aURI, &flags))) {
NS_WARNING(
"nsIAboutModule::GetURIFlags unexpectedly failed. Abort the load");
return IsolationBehavior::Error;
}
if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
return IsolationBehavior::Extension;
}
if (flags & nsIAboutModule::URI_MUST_LOAD_IN_CHILD) {
if (flags & nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS) {
return IsolationBehavior::PrivilegedAbout;
}
return IsolationBehavior::ForceWebRemoteType;
}
if (flags & nsIAboutModule::URI_CAN_LOAD_IN_CHILD) {
return IsolationBehavior::Anywhere;
}
return IsolationBehavior::Parent;
}
// If the test-only `dataUriInDefaultWebProcess` pref is enabled, dump all
// `data:` URIs in a "web" content process, rather than loading them in
// content processes based on their precursor origins.
if (StaticPrefs::browser_tabs_remote_dataUriInDefaultWebProcess() &&
scheme == "data"_ns) {
return IsolationBehavior::ForceWebRemoteType;
}
// Make sure to unwrap nested URIs before we early return for channel creation
// URI. The checks past this point are intended to operate on the principal,
// which has it's origin constructed from the innermost URI.
nsCOMPtr<nsIURI> inner;
if (nsCOMPtr<nsINestedURI> nested = do_QueryInterface(aURI);
nested && NS_SUCCEEDED(nested->GetInnerURI(getter_AddRefs(inner)))) {
return IsolationBehaviorForURI(inner, aIsSubframe, aForChannelCreationURI);
}
// If we're doing the initial check based on the channel creation URI, stop
// here as we want to only perform the following checks on the true channel
// result principal.
if (aForChannelCreationURI) {
return IsolationBehavior::WebContent;
}
// Protocols used by Thunderbird to display email messages.
if (scheme == "imap"_ns || scheme == "mailbox"_ns || scheme == "news"_ns ||
scheme == "nntp"_ns || scheme == "snews"_ns) {
return IsolationBehavior::Parent;
}
// There is more handling for extension content processes in the caller, but
// they should load in an extension content process unless we're loading a
// subframe.
if (scheme == "moz-extension"_ns) {
if (aIsSubframe) {
// As a temporary measure, extension iframes must be loaded within the
// same process as their parent document.
return IsolationBehavior::Inherit;
}
return IsolationBehavior::Extension;
}
if (scheme == "file"_ns) {
return IsolationBehavior::File;
}
// Check if the URI is listed as a privileged mozilla content process.
if (scheme == "https"_ns &&
StaticPrefs::
browser_tabs_remote_separatePrivilegedMozillaWebContentProcess()) {
nsAutoCString host;
if (NS_SUCCEEDED(aURI->GetAsciiHost(host))) {
for (const auto& separatedDomain : sSeparatedMozillaDomains) {
// If the domain exactly matches our host, or our host ends with "." +
// separatedDomain, we consider it matching.
if (separatedDomain == host ||
(separatedDomain.Length() < host.Length() &&
host.CharAt(host.Length() - separatedDomain.Length() - 1) == '.' &&
StringEndsWith(host, separatedDomain))) {
return IsolationBehavior::PrivilegedMozilla;
}
}
}
}
nsCOMPtr<nsIScriptSecurityManager> secMan =
nsContentUtils::GetSecurityManager();
bool inFileURIAllowList = false;
if (NS_SUCCEEDED(secMan->InFileURIAllowlist(aURI, &inFileURIAllowList)) &&
inFileURIAllowList) {
return IsolationBehavior::File;
}
return IsolationBehavior::WebContent;
}
/**
* Helper method for logging the origin of a principal as a string.
*/
static nsAutoCString OriginString(nsIPrincipal* aPrincipal) {
nsAutoCString origin;
aPrincipal->GetOrigin(origin);
return origin;
}
/**
* Given an about:reader URI, extract the "url" query parameter, and use it to
* construct a principal which should be sed for process selection.
*/
static already_AddRefed<BasePrincipal> GetAboutReaderURLPrincipal(
nsIURI* aURI, const OriginAttributes& aAttrs) {
#ifdef DEBUG
MOZ_ASSERT(aURI->SchemeIs("about"));
nsAutoCString path;
MOZ_ALWAYS_SUCCEEDS(NS_GetAboutModuleName(aURI, path));
MOZ_ASSERT(path == "reader"_ns);
#endif
nsAutoCString query;
MOZ_ALWAYS_SUCCEEDS(aURI->GetQuery(query));
// Extract the "url" parameter from the `about:reader`'s query parameters,
// and recover a content principal from it.
nsAutoString readerSpec;
if (URLParams::Extract(query, u"url"_ns, readerSpec)) {
nsCOMPtr<nsIURI> readerUri;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(readerUri), readerSpec))) {
return BasePrincipal::CreateContentPrincipal(readerUri, aAttrs);
}
}
return nullptr;
}
/**
* Check if the given load has the `Large-Allocation` header set, and the header
* is enabled.
*/
static bool IsLargeAllocationLoad(CanonicalBrowsingContext* aBrowsingContext,
nsIChannel* aChannel) {
if (!StaticPrefs::dom_largeAllocationHeader_enabled() ||
aBrowsingContext->UseRemoteSubframes()) {
return false;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return false;
}
nsAutoCString ignoredHeaderValue;
nsresult rv =
httpChannel->GetResponseHeader("Large-Allocation"_ns, ignoredHeaderValue);
if (NS_FAILED(rv)) {
return false;
}
// On all platforms other than win32, LargeAllocation is disabled by default,
// and has to be force-enabled using `dom.largeAllocation.forceEnable`.
#if defined(XP_WIN) && defined(_X86_)
return true;
#else
return StaticPrefs::dom_largeAllocation_forceEnable();
#endif
}
/**
* Returns `true` if loads for this site should be isolated on a per-site basis.
* If `aTopBC` is nullptr, this is being called to check if a shared or service
* worker should be isolated.
*/
static bool ShouldIsolateSite(nsIPrincipal* aPrincipal,
CanonicalBrowsingContext* aTopBC) {
// non-content principals currently can't have webIsolated remote types
// assigned to them, so should not be isolated.
if (!aPrincipal->GetIsContentPrincipal()) {
return false;
}
// FIXME: This should contain logic to allow enabling/disabling whether a
// particular site should be isolated for e.g. android, where we may want to
// turn on/off isolating certain sites at runtime.
if (aTopBC) {
return aTopBC->UseRemoteSubframes();
}
return mozilla::FissionAutostart();
}
enum class WebProcessType {
Web,
WebIsolated,
WebCoopCoep,
};
} // namespace
Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
CanonicalBrowsingContext* aTopBC, WindowGlobalParent* aParentWindow,
nsIURI* aChannelCreationURI, nsIChannel* aChannel,
const nsACString& aCurrentRemoteType, bool aHasCOOPMismatch,
uint32_t aLoadStateLoadType, const Maybe<uint64_t>& aChannelId,
const Maybe<nsCString>& aRemoteTypeOverride) {
// Get the final principal, used to select which process to load into.
nsCOMPtr<nsIPrincipal> resultPrincipal;
nsresult rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
aChannel, getter_AddRefs(resultPrincipal));
if (NS_FAILED(rv)) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("failed to get channel result principal"));
return Err(rv);
}
MOZ_LOG(
gProcessIsolationLog, LogLevel::Verbose,
("IsolationOptionsForNavigation principal:%s, uri:%s, parentUri:%s",
OriginString(resultPrincipal).get(),
aChannelCreationURI->GetSpecOrDefault().get(),
aParentWindow ? aParentWindow->GetDocumentURI()->GetSpecOrDefault().get()
: ""));
// If we're loading a null principal, we can't easily make a process
// selection decision off ot it. Instead, we'll use our null principal's
// precursor principal to make process selection decisions.
bool principalIsSandboxed = false;
nsCOMPtr<nsIPrincipal> resultOrPrecursor(resultPrincipal);
if (nsCOMPtr<nsIPrincipal> precursor =
resultOrPrecursor->GetPrecursorPrincipal()) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("using null principal precursor origin %s",
OriginString(precursor).get()));
resultOrPrecursor = precursor;
principalIsSandboxed = true;
}
NavigationIsolationOptions options;
options.mReplaceBrowsingContext = aHasCOOPMismatch;
// Check if this load has an explicit remote type override. This is used to
// perform an about:blank load within a specific content process.
if (aRemoteTypeOverride) {
MOZ_DIAGNOSTIC_ASSERT(
NS_IsAboutBlank(aChannelCreationURI),
"Should only have aRemoteTypeOverride for about:blank URIs");
if (NS_WARN_IF(!resultPrincipal->GetIsNullPrincipal())) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("invalid remote type override on non-null principal"));
return Err(NS_ERROR_DOM_SECURITY_ERR);
}
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("using remote type override (%s) for load",
aRemoteTypeOverride->get()));
options.mRemoteType = *aRemoteTypeOverride;
return options;
}
// First, check for any special cases which should be handled using the
// channel creation URI, and handle them.
auto behavior = IsolationBehaviorForURI(aChannelCreationURI, aParentWindow,
/* aForChannelCreationURI */ true);
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Channel Creation Isolation Behavior: %s",
IsolationBehaviorName(behavior)));
// In the about:reader special case, we want to fetch the relevant information
// from the URI, an then treat it as a normal web content load.
if (behavior == IsolationBehavior::AboutReader) {
if (RefPtr<BasePrincipal> readerURIPrincipal = GetAboutReaderURLPrincipal(
aChannelCreationURI, resultOrPrecursor->OriginAttributesRef())) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("using about:reader's url origin %s",
OriginString(readerURIPrincipal).get()));
resultOrPrecursor = readerURIPrincipal;
}
behavior = IsolationBehavior::WebContent;
}
// If we're loading for a specific extension, we'll need to perform a
// BCG-switching load to get our toplevel extension window in the correct
// BrowsingContextGroup.
if (auto* addonPolicy =
BasePrincipal::Cast(resultOrPrecursor)->AddonPolicy()) {
if (aParentWindow) {
// As a temporary measure, extension iframes must be loaded within the
// same process as their parent document.
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Loading extension subframe in same process as parent"));
behavior = IsolationBehavior::Inherit;
} else {
MOZ_LOG(
gProcessIsolationLog, LogLevel::Verbose,
("Found extension frame with addon policy. Will use group id %" PRIx64
" (currentId: %" PRIx64 ")",
addonPolicy->GetBrowsingContextGroupId(), aTopBC->Group()->Id()));
behavior = IsolationBehavior::Extension;
if (aTopBC->Group()->Id() != addonPolicy->GetBrowsingContextGroupId()) {
options.mReplaceBrowsingContext = true;
options.mSpecificGroupId = addonPolicy->GetBrowsingContextGroupId();
}
}
}
// Do a second run of `GetIsolationBehavior`, this time using the
// principal's URI to handle additional special cases such as the file and
// privilegedmozilla content process.
if (behavior == IsolationBehavior::WebContent) {
if (resultOrPrecursor->IsSystemPrincipal()) {
// We're loading something with a system principal which isn't caught in
// one of our other edge-cases. If the load started in the parent process,
// and it's safe for it to end in the parent process, we should finish the
// load there.
bool isUIResource = false;
if (aCurrentRemoteType.IsEmpty() &&
(aChannelCreationURI->SchemeIs("about") ||
(NS_SUCCEEDED(NS_URIChainHasFlags(
aChannelCreationURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isUIResource)) &&
isUIResource))) {
behavior = IsolationBehavior::Parent;
} else {
// In general, we don't want to load documents with a system principal
// in a content process, however we need to in some cases, such as when
// loading blob: URLs created by system code. We can force the load to
// finish in a content process instead.
behavior = IsolationBehavior::ForceWebRemoteType;
}
} else if (nsCOMPtr<nsIURI> principalURI = resultOrPrecursor->GetURI()) {
behavior = IsolationBehaviorForURI(principalURI, aParentWindow,
/* aForChannelCreationURI */ false);
}
}
// If we're currently loaded in the extension process, and are going to switch
// to some other remote type, make sure we leave the extension's BCG which we
// may have entered earlier to separate extension and non-extension BCGs from
// each-other.
if (!aParentWindow && aCurrentRemoteType == EXTENSION_REMOTE_TYPE &&
behavior != IsolationBehavior::Extension &&
behavior != IsolationBehavior::Anywhere) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Forcing BC replacement to leave extension BrowsingContextGroup "
"%" PRIx64 " on navigation",
aTopBC->Group()->Id()));
options.mReplaceBrowsingContext = true;
}
// We don't want to load documents with sandboxed null principals, like
// `data:` URIs, in the parent process, even if they were created by a
// document which would otherwise be loaded in the parent process.
if (behavior == IsolationBehavior::Parent && principalIsSandboxed) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
("Ensuring sandboxed null-principal load doesn't occur in the "
"parent process"));
behavior = IsolationBehavior::ForceWebRemoteType;
}
MOZ_LOG(
gProcessIsolationLog, LogLevel::Debug,
("Using IsolationBehavior %s for %s (original uri %s)",
IsolationBehaviorName(behavior), OriginString(resultOrPrecursor).get(),
aChannelCreationURI->GetSpecOrDefault().get()));
// Check if we can put the previous document into the BFCache.
if (mozilla::BFCacheInParent() && nsSHistory::GetMaxTotalViewers() > 0 &&
!aParentWindow && !aTopBC->HadOriginalOpener() &&
behavior != IsolationBehavior::Parent &&
(ExtensionPolicyService::GetSingleton().UseRemoteExtensions() ||
behavior != IsolationBehavior::Extension) &&
!aCurrentRemoteType.IsEmpty() &&
aTopBC->GetHasLoadedNonInitialDocument() &&
(aLoadStateLoadType == LOAD_NORMAL ||
aLoadStateLoadType == LOAD_HISTORY || aLoadStateLoadType == LOAD_LINK ||
aLoadStateLoadType == LOAD_STOP_CONTENT ||
aLoadStateLoadType == LOAD_STOP_CONTENT_AND_REPLACE) &&
(!aTopBC->GetActiveSessionHistoryEntry() ||
aTopBC->GetActiveSessionHistoryEntry()->GetSaveLayoutStateFlag())) {
if (nsCOMPtr<nsIURI> uri = aTopBC->GetCurrentURI()) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("current uri: %s", uri->GetSpecOrDefault().get()));
}
options.mTryUseBFCache = aTopBC->AllowedInBFCache(aChannelId);
if (options.mTryUseBFCache) {
options.mReplaceBrowsingContext = true;
options.mActiveSessionHistoryEntry =
aTopBC->GetActiveSessionHistoryEntry();
}
}
// If the load has any special remote type handling, do so at this point.
if (behavior != IsolationBehavior::WebContent) {
switch (behavior) {
case IsolationBehavior::ForceWebRemoteType:
options.mRemoteType = WEB_REMOTE_TYPE;
break;
case IsolationBehavior::PrivilegedAbout:
// The privileged about: content process cannot be disabled, as it
// causes various actors to break.
options.mRemoteType = PRIVILEGEDABOUT_REMOTE_TYPE;
break;
case IsolationBehavior::Extension:
if (ExtensionPolicyService::GetSingleton().UseRemoteExtensions()) {
options.mRemoteType = EXTENSION_REMOTE_TYPE;
} else {
options.mRemoteType = NOT_REMOTE_TYPE;
}
break;
case IsolationBehavior::File:
if (StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
options.mRemoteType = FILE_REMOTE_TYPE;
} else {
options.mRemoteType = WEB_REMOTE_TYPE;
}
break;
case IsolationBehavior::PrivilegedMozilla:
options.mRemoteType = PRIVILEGEDMOZILLA_REMOTE_TYPE;
break;
case IsolationBehavior::Parent:
options.mRemoteType = NOT_REMOTE_TYPE;
break;
case IsolationBehavior::Anywhere:
options.mRemoteType = aCurrentRemoteType;
break;
case IsolationBehavior::Inherit:
MOZ_DIAGNOSTIC_ASSERT(aParentWindow);
options.mRemoteType = aParentWindow->GetRemoteType();
break;
case IsolationBehavior::WebContent:
case IsolationBehavior::AboutReader:
MOZ_ASSERT_UNREACHABLE();
return Err(NS_ERROR_UNEXPECTED);
case IsolationBehavior::Error:
return Err(NS_ERROR_UNEXPECTED);
}
if (options.mRemoteType != aCurrentRemoteType &&
(options.mRemoteType.IsEmpty() || aCurrentRemoteType.IsEmpty())) {
options.mReplaceBrowsingContext = true;
}
MOZ_LOG(
gProcessIsolationLog, LogLevel::Debug,
("Selecting specific remote type (%s) due to a special case isolation "
"behavior %s",
options.mRemoteType.get(), IsolationBehaviorName(behavior)));
return options;
}
// At this point we're definitely not going to be loading in the parent
// process anymore, so we're definitely going to be replacing BrowsingContext
// if we're in the parent process.
if (aCurrentRemoteType.IsEmpty()) {
MOZ_ASSERT(!aParentWindow);
options.mReplaceBrowsingContext = true;
}
// Handle the deprecated Large-Allocation header.
if (!aTopBC->UseRemoteSubframes()) {
MOZ_ASSERT(!aParentWindow,
"subframe switch when `UseRemoteSubframes()` is false?");
bool singleToplevel = aTopBC->Group()->Toplevels().Length() == 1;
bool isLargeAllocLoad = IsLargeAllocationLoad(aTopBC, aChannel);
// If we're starting a large-alloc load and have no opener relationships,
// force the load to finish in the large-allocation remote type.
if (isLargeAllocLoad && singleToplevel) {
options.mRemoteType = LARGE_ALLOCATION_REMOTE_TYPE;
options.mReplaceBrowsingContext = true;
return options;
}
if (aCurrentRemoteType == LARGE_ALLOCATION_REMOTE_TYPE) {
// If we're doing a non-large-alloc load, we may still need to finish in
// the large-allocation remote type if we have opener relationships.
if (!singleToplevel) {
options.mRemoteType = LARGE_ALLOCATION_REMOTE_TYPE;
return options;
}
options.mReplaceBrowsingContext = true;
}
}
nsAutoCString siteOriginNoSuffix;
MOZ_TRY(resultOrPrecursor->GetSiteOriginNoSuffix(siteOriginNoSuffix));
// Check if we've already loaded a document with the given principal in some
// content process. We want to finish the load in the same process in that
// case.
//
// The exception to that is with extension loads and the system principal,
// where we may have multiple documents with the same principal in different
// processes. Those have been handled above, and will not be reaching here.
//
// If we're doing a replace load, we won't be staying in the same
// BrowsingContext, so ignore this step.
if (!options.mReplaceBrowsingContext) {
// Helper for efficiently determining if a given origin is same-site. This
// will attempt to do a fast equality check, and will only fall back to
// computing the site-origin for content principals.
auto principalIsSameSite = [&](nsIPrincipal* aDocumentPrincipal) -> bool {
// If we're working with a null principal with a precursor, compare
// precursors, as `resultOrPrecursor` has already been stripped to its
// precursor.
nsCOMPtr<nsIPrincipal> documentPrincipal(aDocumentPrincipal);
if (nsCOMPtr<nsIPrincipal> precursor =
documentPrincipal->GetPrecursorPrincipal()) {
documentPrincipal = precursor;
}
// First, attempt to use `Equals` to compare principals, and if that
// fails compare siteOrigins. Only compare siteOrigin for content
// principals, as non-content principals will never have siteOrigin !=
// origin.
nsAutoCString documentSiteOrigin;
return resultOrPrecursor->Equals(documentPrincipal) ||
(documentPrincipal->GetIsContentPrincipal() &&
resultOrPrecursor->GetIsContentPrincipal() &&
NS_SUCCEEDED(documentPrincipal->GetSiteOriginNoSuffix(
documentSiteOrigin)) &&
documentSiteOrigin == siteOriginNoSuffix);
};
// XXX: Consider also checking in-flight process switches to see if any have
// matching principals?
AutoTArray<RefPtr<BrowsingContext>, 8> contexts;
aTopBC->Group()->GetToplevels(contexts);
while (!contexts.IsEmpty()) {
auto bc = contexts.PopLastElement();
for (const auto& wc : bc->GetWindowContexts()) {
WindowGlobalParent* wgp = wc->Canonical();
// Check if this WindowGlobalParent has the given resultPrincipal, and
// if it does, we need to load in that process.
if (!wgp->GetRemoteType().IsEmpty() &&
principalIsSameSite(wgp->DocumentPrincipal())) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Debug,
("Found existing frame with matching principal "
"(remoteType:(%s), origin:%s)",
PromiseFlatCString(wgp->GetRemoteType()).get(),
OriginString(wgp->DocumentPrincipal()).get()));
options.mRemoteType = wgp->GetRemoteType();
return options;
}
// Also enumerate over this WindowContexts' subframes.
contexts.AppendElements(wc->Children());
}
}
}
nsAutoCString originSuffix;
OriginAttributes attrs = resultOrPrecursor->OriginAttributesRef();
attrs.StripAttributes(OriginAttributes::STRIP_FIRST_PARTY_DOMAIN |
OriginAttributes::STRIP_PARITION_KEY);
attrs.CreateSuffix(originSuffix);
WebProcessType webProcessType = WebProcessType::Web;
if (ShouldIsolateSite(resultOrPrecursor, aTopBC)) {
webProcessType = WebProcessType::WebIsolated;
}
// Check if we should be loading in a webCOOP+COEP remote type due to our COOP
// status.
nsILoadInfo::CrossOriginOpenerPolicy coop =
nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
if (aParentWindow) {
coop = aTopBC->GetOpenerPolicy();
} else if (nsCOMPtr<nsIHttpChannelInternal> httpChannel =
do_QueryInterface(aChannel)) {
MOZ_ALWAYS_SUCCEEDS(httpChannel->GetCrossOriginOpenerPolicy(&coop));
}
if (coop ==
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP) {
webProcessType = WebProcessType::WebCoopCoep;
}
switch (webProcessType) {
case WebProcessType::Web:
options.mRemoteType = WEB_REMOTE_TYPE;
break;
case WebProcessType::WebIsolated:
options.mRemoteType =
FISSION_WEB_REMOTE_TYPE "="_ns + siteOriginNoSuffix + originSuffix;
break;
case WebProcessType::WebCoopCoep:
options.mRemoteType =
WITH_COOP_COEP_REMOTE_TYPE "="_ns + siteOriginNoSuffix + originSuffix;
break;
}
return options;
}
} // namespace mozilla::dom

View File

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ProcessIsolation_h
#define mozilla_dom_ProcessIsolation_h
#include <stdint.h>
#include "mozilla/Logging.h"
#include "mozilla/dom/RemoteType.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "nsString.h"
class nsIURI;
class nsIPrincipal;
namespace mozilla::dom {
class CanonicalBrowsingContext;
class WindowGlobalParent;
extern mozilla::LazyLogModule gProcessIsolationLog;
// NavigationIsolationOptions is passed through the methods to store the state
// of the possible process and/or browsing context change.
struct NavigationIsolationOptions {
nsCString mRemoteType;
bool mReplaceBrowsingContext = false;
uint64_t mSpecificGroupId = 0;
bool mTryUseBFCache = false;
RefPtr<SessionHistoryEntry> mActiveSessionHistoryEntry;
};
/**
* Given a specific channel, determines which process the navigation should
* complete in, and whether or not to perform a BrowsingContext-replace load
* or enter the BFCache.
*
* This method will always return a `NavigationIsolationOptions` even if the
* current remote type is compatible. Compatibility with the current process
* should be checked at the call-site. An error should only be returned in
* exceptional circumstances, and should lead to the load being cancelled.
*
* This method is only intended for use with document navigations.
*/
Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
CanonicalBrowsingContext* aTopBC, WindowGlobalParent* aParentWindow,
nsIURI* aChannelCreationURI, nsIChannel* aChannel,
const nsACString& aCurrentRemoteType, bool aHasCOOPMismatch,
uint32_t aLoadStateLoadType, const Maybe<uint64_t>& aChannelId,
const Maybe<nsCString>& aRemoteTypeOverride);
} // namespace mozilla::dom
#endif

View File

@ -15,14 +15,17 @@
// ContentChild:RecvRemoteType. Add your value there too or it will be called
// "Web Content".
#define PREALLOC_REMOTE_TYPE "prealloc"_ns
#define DEFAULT_REMOTE_TYPE "web"_ns
#define WEB_REMOTE_TYPE "web"_ns
#define FILE_REMOTE_TYPE "file"_ns
#define EXTENSION_REMOTE_TYPE "extension"_ns
#define PRIVILEGEDABOUT_REMOTE_TYPE "privilegedabout"_ns
#define PRIVILEGEDMOZILLA_REMOTE_TYPE "privilegedmozilla"_ns
// These must start with the DEFAULT_REMOTE_TYPE above.
#define DEFAULT_REMOTE_TYPE WEB_REMOTE_TYPE
// These must start with the WEB_REMOTE_TYPE above.
#define FISSION_WEB_REMOTE_TYPE "webIsolated"_ns
#define WITH_COOP_COEP_REMOTE_TYPE "webCOOP+COEP"_ns
#define WITH_COOP_COEP_REMOTE_TYPE_PREFIX "webCOOP+COEP="_ns
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"_ns

View File

@ -58,6 +58,7 @@ EXPORTS.mozilla.dom += [
"NativeThreadId.h",
"PermissionMessageUtils.h",
"ProcessActor.h",
"ProcessIsolation.h",
"PropertyBagUtils.h",
"ReferrerInfoUtils.h",
"RefMessageBodyService.h",
@ -111,6 +112,7 @@ UNIFIED_SOURCES += [
"PermissionMessageUtils.cpp",
"PreallocatedProcessManager.cpp",
"ProcessActor.cpp",
"ProcessIsolation.cpp",
"ProcessPriorityManager.cpp",
"PropertyBagUtils.cpp",
"ReferrerInfoUtils.cpp",

View File

@ -653,4 +653,3 @@ pref("browser.tabs.remote.enforceRemoteTypeRestrictions", false);
// Allow Web Authentication
pref("security.webauth.webauthn_enable_android_fido2", true);
pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false);

View File

@ -1270,6 +1270,13 @@
value: false
mirror: always
# Testing-only pref which makes data: URIs be loaded in a "web" content process
# instead of within a process based on the URI's loader.
- name: browser.tabs.remote.dataUriInDefaultWebProcess
type: bool
value: false
mirror: always
- name: browser.tabs.remote.desktopbehavior
type: bool
value: false
@ -1313,6 +1320,14 @@
#endif
mirror: always
# Pref to control whether we use a separate privileged content process
# for certain mozilla webpages (which are listed in the pref
# browser.tabs.remote.separatedMozillaDomains).
- name: browser.tabs.remote.separatePrivilegedMozillaWebContentProcess
type: bool
value: false
mirror: always
# When this pref is enabled, opaque response is only allowed to enter the
# content process if it's a response for media (audio, image, video), CSS, or
# JavaScript.

View File

@ -2477,10 +2477,6 @@ pref("dom.ipc.processCount.webLargeAllocation", 10);
// Disable e10s for Gecko by default. This is overridden in firefox.js.
pref("browser.tabs.remote.autostart", false);
// Pref to control whether we put all data: uri's in the default
// web process when running with fission.
pref("browser.tabs.remote.dataUriInDefaultWebProcess", false);
// This pref will cause assertions when a remoteType triggers a process switch
// to a new remoteType it should not be able to trigger.
pref("browser.tabs.remote.enforceRemoteTypeRestrictions", false);
@ -2490,10 +2486,6 @@ pref("browser.tabs.remote.enforceRemoteTypeRestrictions", false);
// types of privileged content processes, each with different privileges.
pref("browser.tabs.remote.separatePrivilegedContentProcess", false);
// Pref to control whether we use a separate privileged content process
// for certain mozilla webpages (which are listed in the following pref).
pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false);
// The domains we will isolate into the Mozilla Content Process. Comma-separated
// full domains: any subdomains of the domains listed will also be allowed.
pref("browser.tabs.remote.separatedMozillaDomains", "addons.mozilla.org,accounts.firefox.com");

View File

@ -22,6 +22,7 @@
#include "mozilla/dom/ClientChannelHelper.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentProcessManager.h"
#include "mozilla/dom/ProcessIsolation.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/ipc/IdType.h"
@ -37,7 +38,6 @@
#include "nsExternalHelperAppService.h"
#include "nsHttpChannel.h"
#include "nsIBrowser.h"
#include "nsIE10SUtils.h"
#include "nsIHttpChannelInternal.h"
#include "nsIStreamConverterService.h"
#include "nsIViewSourceChannel.h"
@ -1474,52 +1474,28 @@ void DocumentLoadListener::SerializeRedirectData(
}
}
static bool IsLargeAllocationLoad(CanonicalBrowsingContext* aBrowsingContext,
nsIChannel* aChannel) {
if (!StaticPrefs::dom_largeAllocationHeader_enabled() ||
aBrowsingContext->UseRemoteSubframes()) {
return false;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return false;
}
nsAutoCString ignoredHeaderValue;
nsresult rv =
httpChannel->GetResponseHeader("Large-Allocation"_ns, ignoredHeaderValue);
if (NS_FAILED(rv)) {
return false;
}
// On all platforms other than win32, LargeAllocation is disabled by default,
// and has to be force-enabled using `dom.largeAllocation.forceEnable`.
#if defined(XP_WIN) && defined(_X86_)
return true;
#else
return StaticPrefs::dom_largeAllocation_forceEnable();
#endif
}
static bool ContextCanProcessSwitch(CanonicalBrowsingContext* aBrowsingContext,
WindowGlobalParent* aParentWindow) {
if (NS_WARN_IF(!aBrowsingContext)) {
LOG(("Process Switch Abort: no browsing context"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: no browsing context"));
return false;
}
if (!aBrowsingContext->IsContent()) {
LOG(("Process Switch Abort: non-content browsing context"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: non-content browsing context"));
return false;
}
if (aParentWindow && !aBrowsingContext->UseRemoteSubframes()) {
LOG(("Process Switch Abort: remote subframes disabled"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: remote subframes disabled"));
return false;
}
if (aParentWindow && aParentWindow->IsInProcess()) {
LOG(("Process Switch Abort: Subframe with in-process parent"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: Subframe with in-process parent"));
return false;
}
@ -1527,12 +1503,14 @@ static bool ContextCanProcessSwitch(CanonicalBrowsingContext* aBrowsingContext,
// <browser> element.
Element* browserElement = aBrowsingContext->Top()->GetEmbedderElement();
if (!browserElement) {
LOG(("Process Switch Abort: cannot get embedder element"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: cannot get embedder element"));
return false;
}
nsCOMPtr<nsIBrowser> browser = browserElement->AsBrowser();
if (!browser) {
LOG(("Process Switch Abort: not loaded within nsIBrowser"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: not loaded within nsIBrowser"));
return false;
}
@ -1542,19 +1520,22 @@ static bool ContextCanProcessSwitch(CanonicalBrowsingContext* aBrowsingContext,
if (NS_FAILED(rv)) {
MOZ_ASSERT_UNREACHABLE(
"nsIBrowser::GetProcessSwitchBehavior shouldn't fail");
LOG(("Process Switch Abort: failed to get process switch behavior"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: failed to get process switch behavior"));
return false;
}
// Check if the process switch we're considering is disabled by the
// <browser>'s process behavior.
if (processBehavior == nsIBrowser::PROCESS_BEHAVIOR_DISABLED) {
LOG(("Process Switch Abort: switch disabled by <browser>"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: switch disabled by <browser>"));
return false;
}
if (!aParentWindow &&
processBehavior == nsIBrowser::PROCESS_BEHAVIOR_SUBFRAME_ONLY) {
LOG(("Process Switch Abort: toplevel switch disabled by <browser>"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: toplevel switch disabled by <browser>"));
return false;
}
@ -1570,19 +1551,25 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
MOZ_DIAGNOSTIC_ASSERT(mParentChannelListener);
MOZ_DIAGNOSTIC_ASSERT(aWillSwitchToRemote);
LOG(("DocumentLoadListener MaybeTriggerProcessSwitch [this=%p]", this));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("DocumentLoadListener MaybeTriggerProcessSwitch [this=%p, uri=%s, "
"browserid=%" PRIx64 "]",
this, mChannelCreationURI->GetSpecOrDefault().get(),
GetLoadingBrowsingContext()->Top()->BrowserId()));
// If we're doing an <object>/<embed> load, we may be doing a document load at
// this point. We never need to do a process switch for a non-document
// <object> or <embed> load.
if (!mIsDocumentLoad) {
if (!mChannel->IsDocument()) {
LOG(("Process Switch Abort: non-document load"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch Abort: non-document load"));
return false;
}
nsresult status;
if (!nsObjectLoadingContent::IsSuccessfulRequest(mChannel, &status)) {
LOG(("Process Switch Abort: error page"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch Abort: error page"));
return false;
}
}
@ -1602,178 +1589,77 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
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"));
if (!browsingContext->IsOwnedByProcess(GetContentProcessId(mContentParent))) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("Process Switch Abort: context no longer owned by creator"));
Cancel(NS_BINDING_ABORTED);
return false;
}
if (browsingContext->IsReplaced()) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: replaced browsing context"));
Cancel(NS_BINDING_ABORTED);
return false;
}
nsAutoCString currentRemoteType(NOT_REMOTE_TYPE);
if (RefPtr<ContentParent> contentParent =
browsingContext->GetContentParent()) {
currentRemoteType = contentParent->GetRemoteType();
}
MOZ_ASSERT_IF(currentRemoteType.IsEmpty(), !OtherPid());
// Determine what type of content process this load should finish in.
nsAutoCString preferredRemoteType(currentRemoteType);
RemotenessChangeOptions options;
// If there is a remote type override, default to it.
if (mRemoteTypeOverride) {
preferredRemoteType = *mRemoteTypeOverride;
if (mContentParent) {
currentRemoteType = mContentParent->GetRemoteType();
}
// Update the preferred final process for our load based on the
// Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers.
{
bool isCOOPSwitch = HasCrossOriginOpenerPolicyMismatch();
options.mReplaceBrowsingContext |= isCOOPSwitch;
// Determine our COOP status, which will be used to determine our preferred
// remote type.
nsILoadInfo::CrossOriginOpenerPolicy coop =
nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
if (parentWindow) {
coop = browsingContext->Top()->GetOpenerPolicy();
} else if (nsCOMPtr<nsIHttpChannelInternal> httpChannel =
do_QueryInterface(mChannel)) {
MOZ_ALWAYS_SUCCEEDS(httpChannel->GetCrossOriginOpenerPolicy(&coop));
}
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 = WITH_COOP_COEP_REMOTE_TYPE_PREFIX;
preferredRemoteType.Append(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 = DEFAULT_REMOTE_TYPE;
}
}
// If we're performing a large allocation load, override the remote type
// with `LARGE_ALLOCATION_REMOTE_TYPE` to move it into an exclusive content
// process. If we're already in one, and don't otherwise we force ourselves
// out of that content process.
if (!parentWindow && browsingContext->Group()->Toplevels().Length() == 1) {
if (IsLargeAllocationLoad(browsingContext, mChannel)) {
preferredRemoteType = LARGE_ALLOCATION_REMOTE_TYPE;
options.mReplaceBrowsingContext = true;
} else if (preferredRemoteType == LARGE_ALLOCATION_REMOTE_TYPE) {
preferredRemoteType = DEFAULT_REMOTE_TYPE;
options.mReplaceBrowsingContext = true;
}
}
// Put toplevel BrowsingContexts which load within the extension process into
// a specific BrowsingContextGroup.
if (auto* addonPolicy = BasePrincipal::Cast(resultPrincipal)->AddonPolicy()) {
if (!parentWindow) {
// Toplevel extension BrowsingContexts must be loaded in the extension
// browsing context group, within the extension content process.
if (ExtensionPolicyService::GetSingleton().UseRemoteExtensions()) {
preferredRemoteType = EXTENSION_REMOTE_TYPE;
} else {
preferredRemoteType = NOT_REMOTE_TYPE;
}
if (browsingContext->Group()->Id() !=
addonPolicy->GetBrowsingContextGroupId()) {
options.mReplaceBrowsingContext = true;
options.mSpecificGroupId = addonPolicy->GetBrowsingContextGroupId();
}
} else {
// As a temporary measure, extension iframes must be loaded within the
// same process as their parent document.
preferredRemoteType = parentWindow->GetRemoteType();
}
}
LOG(
("DocumentLoadListener GetRemoteTypeForPrincipal "
"[this=%p, contentParent=%s, preferredRemoteType=%s]",
this, currentRemoteType.get(), preferredRemoteType.get()));
nsCOMPtr<nsIE10SUtils> e10sUtils = do_ImportModule(
"resource://gre/modules/E10SUtils.jsm", "E10SUtils", fallible);
if (!e10sUtils) {
LOG(("Process Switch Abort: Could not import E10SUtils"));
auto optionsResult = IsolationOptionsForNavigation(
browsingContext->Top(), parentWindow, mChannelCreationURI, mChannel,
currentRemoteType, HasCrossOriginOpenerPolicyMismatch(),
mLoadStateLoadType, mDocumentChannelId, mRemoteTypeOverride);
if (optionsResult.isErr()) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("Process Switch Abort: CheckIsolationForNavigation Failed with %s",
GetStaticErrorName(optionsResult.inspectErr())));
Cancel(optionsResult.unwrapErr());
return false;
}
// Get information about the current document loaded in our BrowsingContext.
nsCOMPtr<nsIPrincipal> currentPrincipal;
RefPtr<WindowGlobalParent> wgp = browsingContext->GetCurrentWindowGlobal();
if (wgp) {
currentPrincipal = wgp->DocumentPrincipal();
}
NavigationIsolationOptions options = optionsResult.unwrap();
rv = e10sUtils->GetRemoteTypeForPrincipal(
resultPrincipal, mChannelCreationURI, browsingContext->UseRemoteTabs(),
browsingContext->UseRemoteSubframes(), preferredRemoteType,
currentPrincipal, parentWindow, options.mRemoteType);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Process Switch Abort: getRemoteTypeForPrincipal threw an exception"));
return false;
}
// If the final decision is to switch from an 'extension' remote type to any
// other remote type, ensure the browsing context is replaced so that we leave
// the extension-specific BrowsingContextGroup.
if (!parentWindow && currentRemoteType != options.mRemoteType &&
currentRemoteType == EXTENSION_REMOTE_TYPE) {
options.mReplaceBrowsingContext = true;
}
if (mozilla::BFCacheInParent() && nsSHistory::GetMaxTotalViewers() > 0 &&
!parentWindow && !browsingContext->HadOriginalOpener() &&
!options.mRemoteType.IsEmpty() &&
browsingContext->GetHasLoadedNonInitialDocument() &&
(mLoadStateLoadType == LOAD_NORMAL ||
mLoadStateLoadType == LOAD_HISTORY || mLoadStateLoadType == LOAD_LINK ||
mLoadStateLoadType == LOAD_STOP_CONTENT ||
mLoadStateLoadType == LOAD_STOP_CONTENT_AND_REPLACE) &&
(!browsingContext->GetActiveSessionHistoryEntry() ||
browsingContext->GetActiveSessionHistoryEntry()
->GetSaveLayoutStateFlag())) {
MOZ_ASSERT(mIsDocumentLoad);
options.mTryUseBFCache =
browsingContext->AllowedInBFCache(mDocumentChannelId);
if (options.mTryUseBFCache) {
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)));
if (options.mTryUseBFCache) {
MOZ_ASSERT(!parentWindow, "Can only BFCache toplevel windows");
bool sameOrigin = false;
if (auto* wgp = browsingContext->GetCurrentWindowGlobal()) {
nsCOMPtr<nsIPrincipal> resultPrincipal;
MOZ_ALWAYS_SUCCEEDS(
nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
mChannel, getter_AddRefs(resultPrincipal)));
sameOrigin =
wgp->DocumentPrincipal()->EqualsConsideringDomain(resultPrincipal);
}
// We only reset the window name for content.
mLoadingSessionHistoryInfo->mForceMaybeResetName.emplace(
StaticPrefs::privacy_window_name_update_enabled() &&
browsingContext->IsContent() && !sameOrigin);
}
LOG(("GetRemoteTypeForPrincipal -> current:%s remoteType:%s",
currentRemoteType.get(), options.mRemoteType.get()));
MOZ_LOG(
gProcessIsolationLog, LogLevel::Verbose,
("CheckIsolationForNavigation -> current:(%s) remoteType:(%s) replace:%d "
"group:%" PRIx64 " bfcache:%d shentry:%p",
currentRemoteType.get(), options.mRemoteType.get(),
options.mReplaceBrowsingContext, options.mSpecificGroupId,
options.mTryUseBFCache, options.mActiveSessionHistoryEntry.get()));
// Check if a process switch is needed.
if (currentRemoteType == options.mRemoteType &&
!options.mReplaceBrowsingContext) {
LOG(("Process Switch Abort: type (%s) is compatible",
options.mRemoteType.get()));
MOZ_LOG(gProcessIsolationLog, LogLevel::Info,
("Process Switch Abort: type (%s) is compatible",
options.mRemoteType.get()));
return false;
}
if (NS_WARN_IF(parentWindow && options.mRemoteType.IsEmpty())) {
LOG(("Process Switch Abort: non-remote target process for subframe"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("Process Switch Abort: non-remote target process for subframe"));
return false;
}
@ -1790,29 +1676,32 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
// object load. We need a BrowsingContext to perform the switch in, so will
// trigger an upgrade.
if (!mObjectUpgradeHandler) {
LOG(("Process Switch Abort: no object upgrade handler"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
("Process Switch Abort: no object upgrade handler"));
return false;
}
if (!StaticPrefs::fission_remoteObjectEmbed()) {
LOG(("Process Switch Abort: remote <object>/<embed> disabled"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch Abort: remote <object>/<embed> disabled"));
return false;
}
mObjectUpgradeHandler->UpgradeObjectLoad()->Then(
GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr{this}, options,
wgp](const RefPtr<CanonicalBrowsingContext>& aBrowsingContext) mutable {
[self = RefPtr{this}, options, parentWindow](
const RefPtr<CanonicalBrowsingContext>& aBrowsingContext) mutable {
if (aBrowsingContext->IsDiscarded() ||
wgp != aBrowsingContext->GetParentWindowContext()) {
LOG(
("Process Switch: Got invalid BrowsingContext from object "
"upgrade!"));
parentWindow != aBrowsingContext->GetParentWindowContext()) {
MOZ_LOG(gProcessIsolationLog, LogLevel::Error,
("Process Switch: Got invalid BrowsingContext from object "
"upgrade!"));
self->RedirectToRealChannelFinished(NS_ERROR_FAILURE);
return;
}
LOG(("Process Switch: Upgraded Object to Document Load"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch: Upgraded Object to Document Load"));
self->TriggerProcessSwitch(aBrowsingContext, options);
},
[self = RefPtr{this}](nsresult aStatusCode) {
@ -1824,7 +1713,7 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
void DocumentLoadListener::TriggerProcessSwitch(
CanonicalBrowsingContext* aContext,
const RemotenessChangeOptions& aOptions) {
const NavigationIsolationOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(
aContext->IsOwnedByProcess(GetContentProcessId(mContentParent)),
"not owned by creator process anymore?");
@ -1833,8 +1722,9 @@ void DocumentLoadListener::TriggerProcessSwitch(
currentRemoteType = mContentParent->GetRemoteType();
}
LOG(("Process Switch: Changing Remoteness from '%s' to '%s'",
currentRemoteType.get(), aOptions.mRemoteType.get()));
MOZ_LOG(gProcessIsolationLog, LogLevel::Info,
("Process Switch: Changing Remoteness from '%s' to '%s'",
currentRemoteType.get(), aOptions.mRemoteType.get()));
// We're now committing to a process switch, so we can disconnect from
// the listeners in the old process.
@ -1842,7 +1732,8 @@ void DocumentLoadListener::TriggerProcessSwitch(
DisconnectListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED, true);
LOG(("Process Switch: Calling ChangeRemoteness"));
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch: Calling ChangeRemoteness"));
aContext->ChangeRemoteness(aOptions, mLoadIdentifier)
->Then(
GetMainThreadSerialEventTarget(), __func__,

View File

@ -36,7 +36,7 @@
namespace mozilla {
namespace dom {
class CanonicalBrowsingContext;
struct RemotenessChangeOptions;
struct NavigationIsolationOptions;
} // namespace dom
namespace net {
using ChildEndpointPromise =
@ -329,7 +329,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// and that the new remote type will be something other than NOT_REMOTE
bool MaybeTriggerProcessSwitch(bool* aWillSwitchToRemote);
void TriggerProcessSwitch(dom::CanonicalBrowsingContext* aContext,
const dom::RemotenessChangeOptions& aOptions);
const dom::NavigationIsolationOptions& aOptions);
// A helper for TriggerRedirectToRealChannel that abstracts over
// the same-process and cross-process switch cases and returns

View File

@ -17,12 +17,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
"browser.tabs.remote.separateFileUriProcess",
false
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"useSeparateDataUriProcess",
"browser.tabs.remote.dataUriInDefaultWebProcess",
false
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"useSeparatePrivilegedAboutContentProcess",
@ -622,74 +616,6 @@ var E10SUtils = {
}
},
getRemoteTypeForPrincipal(
aPrincipal,
aOriginalURI,
aMultiProcess,
aRemoteSubframes,
aPreferredRemoteType = DEFAULT_REMOTE_TYPE,
aCurrentPrincipal,
aIsSubframe
) {
if (!aMultiProcess) {
return NOT_REMOTE;
}
// We want to use the original URI for "about:" (except for "about:srcdoc"
// and "about:blank") and "chrome://" scheme, so that we can properly
// determine the remote type.
let useOriginalURI;
if (aOriginalURI.scheme == "about") {
useOriginalURI = !["about:srcdoc", "about:blank"].includes(
aOriginalURI.spec
);
} else {
useOriginalURI = aOriginalURI.scheme == "chrome";
}
if (!useOriginalURI) {
// We can't pick a process based on a system principal or expanded
// principal.
if (aPrincipal.isSystemPrincipal || aPrincipal.isExpandedPrincipal) {
throw Components.Exception("", Cr.NS_ERROR_UNEXPECTED);
}
// Null principals can be loaded in any remote process, but when
// using fission we add the option to force them into the default
// web process for better test coverage.
if (aPrincipal.isNullPrincipal) {
if (aOriginalURI.spec == "about:blank") {
useOriginalURI = true;
} else if (
(aRemoteSubframes && useSeparateDataUriProcess) ||
aPreferredRemoteType == NOT_REMOTE
) {
return WEB_REMOTE_TYPE;
}
return aPreferredRemoteType;
}
}
// We might care about the currently loaded URI. Pull it out of our current
// principal. We never care about the current URI when working with a
// non-content principal.
let currentURI =
aCurrentPrincipal && aCurrentPrincipal.isContentPrincipal
? Services.io.newURI(aCurrentPrincipal.spec)
: null;
return E10SUtils.getRemoteTypeForURIObject(
useOriginalURI ? aOriginalURI : Services.io.newURI(aPrincipal.spec),
aMultiProcess,
aRemoteSubframes,
aPreferredRemoteType,
currentURI,
aPrincipal,
aIsSubframe,
false, //aIsWorker
aPrincipal.originAttributes
);
},
getRemoteTypeForWorkerPrincipal(
aPrincipal,
aWorkerType,

View File

@ -20,31 +20,6 @@ interface nsIE10SUtils : nsISupports {
REMOTE_WORKER_TYPE_SERVICE,
};
/**
* 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 aChannelOriginalURI. The original URI being loaded
* (which isn't always the same as the Principal's
* URI)
* @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.
*/
AUTF8String getRemoteTypeForPrincipal(in nsIPrincipal aPrincipal,
in nsIURI aChannelOriginalURI,
in boolean aMultiProcess,
in boolean aRemoteSubframes,
in AUTF8String aPreferredRemoteType,
in nsIPrincipal aCurrentPrincipal,
in boolean aIsSubframe);
/**
* Determine what remote type should be used to launch a worker script with
* the given principal.