Bug 1598523 - Share code for creating a channel for a document between nsDocShell, DocumentChannelChild and ContentChild. r=kmag

Note that this also implicitly adds support for the view-source+srcdoc configuration, and setting of the BaseURI, which were both in the nsDocShell version but not the others.

Differential Revision: https://phabricator.services.mozilla.com/D57887
This commit is contained in:
Matt Woodrow
2020-01-07 21:17:22 +00:00
parent 3cdf0fa74e
commit 40b9b10577
5 changed files with 123 additions and 111 deletions

View File

@@ -9287,99 +9287,98 @@ static bool IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
return aTriggeringPrincipal->Equals(tmpResultPrincipal);
}
static bool SchemeUsesDocChannel(nsIURI* aURI) {
return !SchemeIsJavascript(aURI) && !SchemeIsViewSource(aURI) &&
!NS_IsAboutBlank(aURI) &&
!aURI->GetSpecOrDefault().EqualsLiteral("about:printpreview") &&
!aURI->GetSpecOrDefault().EqualsLiteral("about:privatebrowsing") &&
!aURI->GetSpecOrDefault().EqualsLiteral("about:crashcontent");
}
/* static */ bool nsDocShell::CreateChannelForLoadState(
nsDocShellLoadState* aLoadState, LoadInfo* aLoadInfo,
/* static */ nsresult nsDocShell::CreateRealChannelForDocument(
nsIChannel** aChannel, nsIURI* aURI, nsILoadInfo* aLoadInfo,
nsIInterfaceRequestor* aCallbacks, nsDocShell* aDocShell,
const nsString* aInitiatorType, nsLoadFlags aLoadFlags, uint32_t aLoadType,
uint32_t aCacheKey, bool aIsActive, bool aIsTopLevelDoc,
bool aHasNonEmptySandboxingFlags, nsresult& aRv, nsIChannel** aChannel) {
nsAutoString srcdoc;
bool isSrcdoc = aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC);
if (isSrcdoc) {
srcdoc = aLoadState->SrcdocData();
} else {
srcdoc = VoidString();
}
// We want to use DocumentChannel if we're a sandboxed srcdoc load or if
// we're using a supported scheme. Non-sandboxed srcdoc loads need to share
// the same principal object as their outer document (and must load in the
// same process), which breaks if we serialize to the parent process.
bool isSandboxed = false;
aLoadInfo->GetLoadingSandboxed(&isSandboxed);
bool canUseDocumentChannel =
isSrcdoc ? isSandboxed : SchemeUsesDocChannel(aLoadState->URI());
if (StaticPrefs::browser_tabs_documentchannel() && XRE_IsContentProcess() &&
canUseDocumentChannel) {
RefPtr<DocumentChannelChild> child = new DocumentChannelChild(
aLoadState, aLoadInfo, aInitiatorType, aLoadFlags, aLoadType, aCacheKey,
aIsActive, aIsTopLevelDoc, aHasNonEmptySandboxingFlags);
child->SetNotificationCallbacks(aCallbacks);
child.forget(aChannel);
aRv = NS_OK;
return true;
}
nsLoadFlags aLoadFlags, const nsAString& aSrcdoc, nsIURI* aBaseURI) {
nsCOMPtr<nsIChannel> channel;
nsIURI* baseURI = aLoadState->BaseURI();
if (!isSrcdoc) {
aRv = NS_NewChannelInternal(getter_AddRefs(channel), aLoadState->URI(),
aLoadInfo,
nullptr, // PerformanceStorage
nullptr, // loadGroup
aCallbacks, aLoadFlags);
nsresult rv;
if (aSrcdoc.IsVoid()) {
rv = NS_NewChannelInternal(getter_AddRefs(channel), aURI, aLoadInfo,
nullptr, // PerformanceStorage
nullptr, // loadGroup
aCallbacks, aLoadFlags);
if (NS_FAILED(aRv)) {
if (aRv == NS_ERROR_UNKNOWN_PROTOCOL && aDocShell) {
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_UNKNOWN_PROTOCOL && aDocShell) {
// This is a uri with a protocol scheme we don't know how
// to handle. Embedders might still be interested in
// handling the load, though, so we fire a notification
// before throwing the load away.
bool abort = false;
nsresult rv = aDocShell->mContentListener->OnStartURIOpen(
aLoadState->URI(), &abort);
rv = aDocShell->mContentListener->OnStartURIOpen(aURI, &abort);
if (NS_SUCCEEDED(rv) && abort) {
// Hey, they're handling the load for us! How convenient!
aRv = NS_OK;
return false;
return NS_OK;
}
}
return false;
return rv;
}
if (baseURI) {
if (aBaseURI) {
nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
if (vsc) {
aRv = vsc->SetBaseURI(baseURI);
MOZ_ASSERT(NS_SUCCEEDED(aRv));
MOZ_ALWAYS_SUCCEEDS(vsc->SetBaseURI(aBaseURI));
}
}
} else if (SchemeIsViewSource(aLoadState->URI())) {
} else if (SchemeIsViewSource(aURI)) {
nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
if (!vsh) {
aRv = NS_ERROR_FAILURE;
return false;
return NS_ERROR_FAILURE;
}
aRv = vsh->NewSrcdocChannel(aLoadState->URI(), baseURI, srcdoc, aLoadInfo,
getter_AddRefs(channel));
MOZ_TRY(vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, aLoadInfo,
getter_AddRefs(channel)));
} else {
aRv = NS_NewInputStreamChannelInternal(
getter_AddRefs(channel), aLoadState->URI(), srcdoc,
NS_LITERAL_CSTRING("text/html"), aLoadInfo, true);
NS_ENSURE_SUCCESS(aRv, false);
MOZ_TRY(NS_NewInputStreamChannelInternal(
getter_AddRefs(channel), aURI, aSrcdoc, NS_LITERAL_CSTRING("text/html"),
aLoadInfo, true));
nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
MOZ_ASSERT(isc);
isc->SetBaseURI(baseURI);
isc->SetBaseURI(aBaseURI);
}
channel.forget(aChannel);
return NS_OK;
}
static bool SchemeUsesDocChannel(nsIURI* aURI) {
if (SchemeIsJavascript(aURI) || SchemeIsViewSource(aURI) ||
NS_IsAboutBlank(aURI)) {
return false;
}
nsCString spec = aURI->GetSpecOrDefault();
if (spec.EqualsLiteral("about:printpreview") ||
spec.EqualsLiteral("about:privatebrowsing") ||
spec.EqualsLiteral("about:crashcontent")) {
return false;
}
return true;
}
/* static */ bool nsDocShell::CreateAndConfigureRealChannelForLoadState(
nsDocShellLoadState* aLoadState, LoadInfo* aLoadInfo,
nsIInterfaceRequestor* aCallbacks, nsDocShell* aDocShell,
const nsString* aInitiatorType, nsLoadFlags aLoadFlags, uint32_t aLoadType,
uint32_t aCacheKey, bool aIsActive, bool aIsTopLevelDoc,
bool aHasNonEmptySandboxingFlags, nsresult& aRv, nsIChannel** aChannel) {
nsString srcdoc = VoidString();
bool isSrcdoc = aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC);
if (isSrcdoc) {
srcdoc = aLoadState->SrcdocData();
}
nsCOMPtr<nsIChannel> channel;
aRv = CreateRealChannelForDocument(getter_AddRefs(channel), aLoadState->URI(),
aLoadInfo, aCallbacks, aDocShell,
aLoadFlags, srcdoc, aLoadState->BaseURI());
NS_ENSURE_SUCCESS(aRv, false);
if (!channel) {
return false;
}
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
@@ -9946,10 +9945,27 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
bool isActive = mBrowsingContext->GetIsActive() ||
(mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY));
if (!CreateChannelForLoadState(
aLoadState, loadInfo, this, this, initiatorType, loadFlags, mLoadType,
cacheKey, isActive, isTopLevelDoc,
mBrowsingContext->GetSandboxFlags(), rv, getter_AddRefs(channel))) {
// We want to use DocumentChannel if we're using a supported scheme, or if
// we're a sandboxed srcdoc load. Non-sandboxed srcdoc loads need to share
// the same principal object as their outer document (and must load in the
// same process), which breaks if we serialize to the parent process.
bool canUseDocumentChannel =
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC)
? isSandBoxed
: SchemeUsesDocChannel(aLoadState->URI());
if (StaticPrefs::browser_tabs_documentchannel() && XRE_IsContentProcess() &&
canUseDocumentChannel) {
channel = new DocumentChannelChild(
aLoadState, loadInfo, initiatorType, loadFlags, mLoadType, cacheKey,
isActive, isTopLevelDoc, mBrowsingContext->GetSandboxFlags());
channel->SetNotificationCallbacks(this);
} else if (!CreateAndConfigureRealChannelForLoadState(
aLoadState, loadInfo, this, this, initiatorType, loadFlags,
mLoadType, cacheKey, isActive, isTopLevelDoc,
mBrowsingContext->GetSandboxFlags(), rv,
getter_AddRefs(channel))) {
return rv;
}