Bug 1646899 - P4: Handle object & embed via DocumentChannel. r=mattwoodrow,jya

Pass internal content policy type to DLL and switch behavior depending on type
being loaded. This implementation immediately redirects channel back to the
content process for further handling.

Differential Revision: https://phabricator.services.mozilla.com/D80407
This commit is contained in:
Dan Glastonbury
2020-07-13 00:48:57 +00:00
parent 8cc0ad8e59
commit 88f5bd0463
12 changed files with 734 additions and 282 deletions

View File

@@ -9253,9 +9253,26 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal(
if (nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(channel)) { if (nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(channel)) {
timedChannel->SetTimingEnabled(true); timedChannel->SetTimingEnabled(true);
auto& embedderElementType = aBrowsingContext->GetEmbedderElementType(); nsString initiatorType;
if (embedderElementType) { switch (aLoadInfo->InternalContentPolicyType()) {
timedChannel->SetInitiatorType(*embedderElementType); case nsIContentPolicy::TYPE_INTERNAL_EMBED:
initiatorType = u"embed"_ns;
break;
case nsIContentPolicy::TYPE_INTERNAL_OBJECT:
initiatorType = u"object"_ns;
break;
default: {
const auto& embedderElementType =
aBrowsingContext->GetEmbedderElementType();
if (embedderElementType) {
initiatorType = *embedderElementType;
}
break;
}
}
if (!initiatorType.IsEmpty()) {
timedChannel->SetInitiatorType(initiatorType);
} }
} }
@@ -9574,9 +9591,9 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
if (DocumentChannel::CanUseDocumentChannel(aLoadState->URI(), if (DocumentChannel::CanUseDocumentChannel(aLoadState->URI(),
aLoadState->LoadFlags())) { aLoadState->LoadFlags())) {
channel = DocumentChannel::CreateDocumentChannel(aLoadState, loadInfo, channel = DocumentChannel::CreateForDocument(aLoadState, loadInfo,
loadFlags, this, cacheKey, loadFlags, this, cacheKey,
uriModified, isXFOError); uriModified, isXFOError);
MOZ_ASSERT(channel); MOZ_ASSERT(channel);
// Disable keyword fixup when using DocumentChannel, since // Disable keyword fixup when using DocumentChannel, since

View File

@@ -48,6 +48,7 @@
#include "nsContentPolicyUtils.h" #include "nsContentPolicyUtils.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDocShellCID.h" #include "nsDocShellCID.h"
#include "nsDocShellLoadState.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
@@ -88,6 +89,7 @@
#include "mozilla/dom/HTMLObjectElement.h" #include "mozilla/dom/HTMLObjectElement.h"
#include "mozilla/dom/UserActivation.h" #include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/nsCSPContext.h" #include "mozilla/dom/nsCSPContext.h"
#include "mozilla/net/DocumentChannel.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h" #include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/LoadInfo.h" #include "mozilla/LoadInfo.h"
#include "mozilla/PresShell.h" #include "mozilla/PresShell.h"
@@ -2267,38 +2269,28 @@ nsresult nsObjectLoadingContent::OpenChannel() {
RefPtr<ObjectInterfaceRequestorShim> shim = RefPtr<ObjectInterfaceRequestorShim> shim =
new ObjectInterfaceRequestorShim(this); new ObjectInterfaceRequestorShim(this);
bool inherit = nsContentUtils::ChannelShouldInheritPrincipal( bool inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
thisContent->NodePrincipal(), mURI, thisContent->NodePrincipal(), // aLoadState->PrincipalToInherit()
true, // aInheritForAboutBlank mURI, // aLoadState->URI()
false); // aForceInherit true, // aInheritForAboutBlank
nsSecurityFlags securityFlags = false); // aForceInherit
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
bool isURIUniqueOrigin = bool isURIUniqueOrigin =
StaticPrefs::security_data_uri_unique_opaque_origin() && StaticPrefs::security_data_uri_unique_opaque_origin() &&
mURI->SchemeIs("data"); SchemeIsData(mURI);
bool inheritPrincipal = inheritAttrs && !isURIUniqueOrigin;
if (inherit && !isURIUniqueOrigin) { nsSecurityFlags securityFlags =
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
if (inheritPrincipal) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
} }
nsContentPolicyType contentPolicyType = GetContentPolicyType(); nsContentPolicyType contentPolicyType = GetContentPolicyType();
nsLoadFlags loadFlags = nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
rv = NS_NewChannel(getter_AddRefs(chan), mURI, thisContent, securityFlags, nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
contentPolicyType, nsIRequest::LOAD_HTML_OBJECT_DATA;
nullptr, // aPerformanceStorage uint32_t sandboxFlags = doc->GetSandboxFlags();
group, // aLoadGroup
shim, // aCallbacks
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
nsIRequest::LOAD_HTML_OBJECT_DATA,
nullptr, // aIoService
doc->GetSandboxFlags());
NS_ENSURE_SUCCESS(rv, rv);
if (inherit) {
nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
}
// For object loads we store the CSP that potentially needs to // For object loads we store the CSP that potentially needs to
// be inherited, e.g. in case we are loading an opaque origin // be inherited, e.g. in case we are loading an opaque origin
@@ -2307,14 +2299,80 @@ nsresult nsObjectLoadingContent::OpenChannel() {
// (do not share the same reference) otherwise a Meta CSP of an // (do not share the same reference) otherwise a Meta CSP of an
// opaque origin will incorrectly be propagated to the embedding // opaque origin will incorrectly be propagated to the embedding
// document. // document.
nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp(); RefPtr<nsCSPContext> cspToInherit;
if (csp) { if (nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp()) {
RefPtr<nsCSPContext> cspToInherit = new nsCSPContext(); cspToInherit = new nsCSPContext();
cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get())); cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get()));
nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
static_cast<LoadInfo*>(loadinfo.get())->SetCSPToInherit(cspToInherit);
} }
// --- Create LoadInfo
RefPtr<LoadInfo> loadInfo = new LoadInfo(
/*aLoadingPrincipal = aLoadingContext->NodePrincipal() */ nullptr,
/*aTriggeringPrincipal = aLoadingPrincipal */ nullptr,
/*aLoadingContext = */ thisContent,
/*aSecurityFlags = */ securityFlags,
/*aContentPolicyType = */ contentPolicyType,
/*aLoadingClientInfo = */ Nothing(),
/*aController = */ Nothing(),
/*aSandboxFlags = */ sandboxFlags);
if (inheritAttrs) {
loadInfo->SetPrincipalToInherit(thisContent->NodePrincipal());
}
if (cspToInherit) {
loadInfo->SetCSPToInherit(cspToInherit);
}
if (DocumentChannel::CanUseDocumentChannel(
mURI, nsIWebNavigation::LOAD_FLAGS_NONE)) {
// --- Create LoadState
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(mURI);
loadState->SetPrincipalToInherit(thisContent->NodePrincipal());
loadState->SetTriggeringPrincipal(loadInfo->TriggeringPrincipal());
if (cspToInherit) {
loadState->SetCsp(cspToInherit);
}
// TODO(djg): This was httpChan->SetReferrerInfoWithoutClone(referrerInfo);
// Is the ...WithoutClone(...) important?
auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
loadState->SetReferrerInfo(referrerInfo);
chan =
DocumentChannel::CreateForObject(loadState, loadInfo, loadFlags, shim);
MOZ_ASSERT(chan);
// NS_NewChannel sets the group on the channel. CreateDocumentChannel does
// not.
chan->SetLoadGroup(group);
} else {
rv = NS_NewChannelInternal(getter_AddRefs(chan), // outChannel
mURI, // aUri
loadInfo, // aLoadInfo
nullptr, // aPerformanceStorage
group, // aLoadGroup
shim, // aCallbacks
loadFlags, // aLoadFlags
nullptr); // aIoService
NS_ENSURE_SUCCESS(rv, rv);
if (inheritAttrs) {
nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
}
// For object loads we store the CSP that potentially needs to
// be inherited, e.g. in case we are loading an opaque origin
// like a data: URI. The actual inheritance check happens within
// Document::InitCSP(). Please create an actual copy of the CSP
// (do not share the same reference) otherwise a Meta CSP of an
// opaque origin will incorrectly be propagated to the embedding
// document.
if (cspToInherit) {
nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
static_cast<LoadInfo*>(loadinfo.get())->SetCSPToInherit(cspToInherit);
}
};
// Referrer // Referrer
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan)); nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
if (httpChan) { if (httpChan) {

View File

@@ -88,6 +88,15 @@ static nsContentPolicyType InternalContentPolicyTypeForFrame(
aSandboxFlags); aSandboxFlags);
} }
/* static */ already_AddRefed<LoadInfo> LoadInfo::CreateForNonDocument(
dom::WindowGlobalParent* aParentWGP, nsIPrincipal* aTriggeringPrincipal,
uint64_t aFrameOuterWindowID, nsContentPolicyType aContentPolicyType,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags) {
return MakeAndAddRef<LoadInfo>(aParentWGP, aTriggeringPrincipal,
aFrameOuterWindowID, aContentPolicyType,
aSecurityFlags, aSandboxFlags);
}
LoadInfo::LoadInfo( LoadInfo::LoadInfo(
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
nsINode* aLoadingContext, nsSecurityFlags aSecurityFlags, nsINode* aLoadingContext, nsSecurityFlags aSecurityFlags,
@@ -1816,13 +1825,12 @@ PerformanceStorage* LoadInfo::GetPerformanceStorage() {
return mPerformanceStorage; return mPerformanceStorage;
} }
RefPtr<dom::Document> loadingDocument; auto* innerWindow = nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID);
GetLoadingDocument(getter_AddRefs(loadingDocument)); if (!innerWindow) {
if (!loadingDocument) {
return nullptr; return nullptr;
} }
if (!TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) { if (!TriggeringPrincipal()->Equals(innerWindow->GetPrincipal())) {
return nullptr; return nullptr;
} }
@@ -1834,11 +1842,6 @@ PerformanceStorage* LoadInfo::GetPerformanceStorage() {
return nullptr; return nullptr;
} }
nsCOMPtr<nsPIDOMWindowInner> innerWindow = loadingDocument->GetInnerWindow();
if (!innerWindow) {
return nullptr;
}
mozilla::dom::Performance* performance = innerWindow->GetPerformance(); mozilla::dom::Performance* performance = innerWindow->GetPerformance();
if (!performance) { if (!performance) {
return nullptr; return nullptr;

View File

@@ -73,6 +73,12 @@ class LoadInfo final : public nsILoadInfo {
nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID, nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags); nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags);
// Use for non-{TYPE_DOCUMENT|TYPE_FRAME|TYPE_IFRAME} load.
static already_AddRefed<LoadInfo> CreateForNonDocument(
dom::WindowGlobalParent* aParentWGP, nsIPrincipal* aTriggeringPrincipal,
uint64_t aFrameOuterWindowID, nsContentPolicyType aContentPolicyType,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags);
// aLoadingPrincipal MUST NOT BE NULL. // aLoadingPrincipal MUST NOT BE NULL.
LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
nsINode* aLoadingContext, nsSecurityFlags aSecurityFlags, nsINode* aLoadingContext, nsSecurityFlags aSecurityFlags,
@@ -90,12 +96,6 @@ class LoadInfo final : public nsILoadInfo {
nsISupports* aContextForTopLevelLoad, nsSecurityFlags aSecurityFlags, nsISupports* aContextForTopLevelLoad, nsSecurityFlags aSecurityFlags,
uint32_t aSandboxFlags); uint32_t aSandboxFlags);
// Used for loads initiated by DocumentLoadListener.
LoadInfo(dom::WindowGlobalParent* aParentWGP,
nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID,
nsContentPolicyType aContentPolicyType,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags);
private: private:
// Use factory function CreateForDocument // Use factory function CreateForDocument
// Used for TYPE_DOCUMENT load. // Used for TYPE_DOCUMENT load.
@@ -110,6 +110,13 @@ class LoadInfo final : public nsILoadInfo {
nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID, nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags); nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags);
// Used for loads initiated by DocumentLoadListener that are not TYPE_DOCUMENT
// | TYPE_FRAME | TYPE_FRAME.
LoadInfo(dom::WindowGlobalParent* aParentWGP,
nsIPrincipal* aTriggeringPrincipal, uint64_t aFrameOuterWindowID,
nsContentPolicyType aContentPolicyType,
nsSecurityFlags aSecurityFlags, uint32_t aSandboxFlags);
public: public:
// Compute a list of ancestor principals and BrowsingContext IDs. // Compute a list of ancestor principals and BrowsingContext IDs.
// See methods AncestorPrincipals and AncestorBrowsingContextIDs // See methods AncestorPrincipals and AncestorBrowsingContextIDs
@@ -132,6 +139,12 @@ class LoadInfo final : public nsILoadInfo {
// when a separate request is made with the same security properties. // when a separate request is made with the same security properties.
already_AddRefed<nsILoadInfo> CloneForNewRequest() const; already_AddRefed<nsILoadInfo> CloneForNewRequest() const;
// The `nsContentPolicyType GetExternalContentPolicyType()` version in the
// base class is hidden by the implementation of
// `GetExternalContentPolicyType(nsContentPolicyType* aResult)` in
// LoadInfo.cpp. Explicit mark it visible.
using nsILoadInfo::GetExternalContentPolicyType;
void SetIsPreflight(); void SetIsPreflight();
void SetUpgradeInsecureRequests(bool aValue); void SetUpgradeInsecureRequests(bool aValue);
void SetBrowserUpgradeInsecureRequests(); void SetBrowserUpgradeInsecureRequests();

View File

@@ -97,16 +97,22 @@ void DocumentChannel::ShutdownListeners(nsresult aStatusCode) {
mIsPending = false; mIsPending = false;
listener = mListener; // it might have changed! listener = mListener; // it might have changed!
if (listener) { nsCOMPtr<nsILoadGroup> loadGroup = mLoadGroup;
listener->OnStopRequest(this, aStatusCode);
}
mListener = nullptr; mListener = nullptr;
mLoadGroup = nullptr;
mCallbacks = nullptr; mCallbacks = nullptr;
if (mLoadGroup) { NS_DispatchToMainThread(NS_NewRunnableFunction(
mLoadGroup->RemoveRequest(this, nullptr, aStatusCode); "DocumentChannel::ShutdownListeners", [=, self = RefPtr{this}] {
mLoadGroup = nullptr; if (listener) {
} listener->OnStopRequest(self, aStatusCode);
}
if (loadGroup) {
loadGroup->RemoveRequest(self, nullptr, aStatusCode);
}
}));
DeleteIPDL(); DeleteIPDL();
} }
@@ -171,7 +177,7 @@ bool DocumentChannel::CanUseDocumentChannel(nsIURI* aURI, uint32_t aLoadFlags) {
} }
/* static */ /* static */
already_AddRefed<DocumentChannel> DocumentChannel::CreateDocumentChannel( already_AddRefed<DocumentChannel> DocumentChannel::CreateForDocument(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo, nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks, nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
uint32_t aCacheKey, bool aUriModified, bool aIsXFOError) { uint32_t aCacheKey, bool aUriModified, bool aIsXFOError) {
@@ -188,6 +194,14 @@ already_AddRefed<DocumentChannel> DocumentChannel::CreateDocumentChannel(
return channel.forget(); return channel.forget();
} }
/* static */
already_AddRefed<DocumentChannel> DocumentChannel::CreateForObject(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks) {
return CreateForDocument(aLoadState, aLoadInfo, aLoadFlags,
aNotificationCallbacks, 0, false, false);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// DocumentChannel::nsITraceableChannel // DocumentChannel::nsITraceableChannel
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -290,9 +304,17 @@ DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
} }
NS_IMETHODIMP DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { NS_IMETHODIMP DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
NS_ERROR( auto contentPolicy = mLoadInfo->GetExternalContentPolicyType();
"DocumentChannel::SetLoadFlags: " // Setting load flags for TYPE_OBJECT is permissible before channel to parent
"Don't set flags after creation"); // is opened.
if (contentPolicy != nsIContentPolicy::TYPE_OBJECT || mWasOpened) {
MOZ_CRASH("DocumentChannel::SetLoadFlags: Don't set flags after creation");
NS_ERROR(
"DocumentChannel::SetLoadFlags: "
"Don't set flags after creation");
} else {
mLoadFlags = aLoadFlags;
}
return NS_OK; return NS_OK;
} }
@@ -432,6 +454,23 @@ DocumentChannel::SetChannelId(uint64_t aChannelId) {
return NS_OK; return NS_OK;
} }
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
uint64_t InnerWindowIDForExtantDoc(nsDocShell* docShell) {
if (!docShell) {
return 0;
}
Document* doc = docShell->GetExtantDocument();
if (!doc) {
return 0;
}
return doc->InnerWindowID();
}
} // namespace net } // namespace net
} // namespace mozilla } // namespace mozilla

View File

@@ -15,6 +15,8 @@
#include "nsIChildChannel.h" #include "nsIChildChannel.h"
#include "nsITraceableChannel.h" #include "nsITraceableChannel.h"
class nsDocShell;
#define DOCUMENT_CHANNEL_IID \ #define DOCUMENT_CHANNEL_IID \
{ \ { \
0x6977bc44, 0xb1db, 0x41b7, { \ 0x6977bc44, 0xb1db, 0x41b7, { \
@@ -25,6 +27,8 @@
namespace mozilla { namespace mozilla {
namespace net { namespace net {
uint64_t InnerWindowIDForExtantDoc(nsDocShell* docShell);
/** /**
* DocumentChannel is a protocol agnostic placeholder nsIChannel implementation * DocumentChannel is a protocol agnostic placeholder nsIChannel implementation
* that we use so that nsDocShell knows about a connecting load. It transfers * that we use so that nsDocShell knows about a connecting load. It transfers
@@ -59,10 +63,13 @@ class DocumentChannel : public nsIIdentChannel, public nsITraceableChannel {
* a ParentProcessDocumentChannel if called from the parent process. * a ParentProcessDocumentChannel if called from the parent process.
* This operation is infallible. * This operation is infallible.
*/ */
static already_AddRefed<DocumentChannel> CreateDocumentChannel( static already_AddRefed<DocumentChannel> CreateForDocument(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo, nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks, nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
uint32_t aCacheKey, bool aUriModified, bool aIsXFOError); uint32_t aCacheKey, bool aUriModified, bool aIsXFOError);
static already_AddRefed<DocumentChannel> CreateForObject(
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks);
static bool CanUseDocumentChannel(nsIURI* aURI, uint32_t aLoadFlags); static bool CanUseDocumentChannel(nsIURI* aURI, uint32_t aLoadFlags);

View File

@@ -73,8 +73,16 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
gHttpHandler->OnOpeningDocumentRequest(this); gHttpHandler->OnOpeningDocumentRequest(this);
if (!GetDocShell() || !GetDocShell()->GetBrowsingContext() || RefPtr<nsDocShell> docShell = GetDocShell();
GetDocShell()->GetBrowsingContext()->IsDiscarded()) { if (!docShell) {
return NS_ERROR_FAILURE;
}
// `loadingContext` is the BC that is initiating the resource load.
// For normal subdocument loads, the BC is the one that the subdoc will load
// into. For <object>/<embed> it's the embedder doc's BC.
RefPtr<BrowsingContext> loadingContext = docShell->GetBrowsingContext();
if (!loadingContext || loadingContext->IsDiscarded()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@@ -84,9 +92,6 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
args.cacheKey() = mCacheKey; args.cacheKey() = mCacheKey;
args.channelId() = mChannelId; args.channelId() = mChannelId;
args.asyncOpenTime() = mAsyncOpenTime; args.asyncOpenTime() = mAsyncOpenTime;
args.outerWindowId() = GetDocShell()->GetOuterWindowID();
args.uriModified() = mUriModified;
args.isXFOError() = mIsXFOError;
Maybe<IPCClientInfo> ipcClientInfo; Maybe<IPCClientInfo> ipcClientInfo;
if (mInitialClientInfo.isSome()) { if (mInitialClientInfo.isSome()) {
@@ -99,15 +104,44 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
} }
args.hasValidTransientUserAction() = args.hasValidTransientUserAction() =
GetDocShell() loadingContext->HasValidTransientUserGestureActivation();
->GetBrowsingContext()
->HasValidTransientUserGestureActivation();
GetDocShell()->GetBrowsingContext()->SetCurrentLoadIdentifier( switch (mLoadInfo->GetExternalContentPolicyType()) {
Some(mLoadState->GetLoadIdentifier())); case nsIContentPolicy::TYPE_DOCUMENT:
case nsIContentPolicy::TYPE_SUBDOCUMENT: {
DocumentCreationArgs docArgs;
docArgs.outerWindowId() = docShell->GetOuterWindowID();
docArgs.uriModified() = mUriModified;
docArgs.isXFOError() = mIsXFOError;
gNeckoChild->SendPDocumentChannelConstructor( args.elementCreationArgs() = docArgs;
this, GetDocShell()->GetBrowsingContext(), args); break;
}
case nsIContentPolicy::TYPE_OBJECT: {
ObjectCreationArgs objectArgs;
objectArgs.embedderInnerWindowId() = InnerWindowIDForExtantDoc(docShell);
objectArgs.loadFlags() = mLoadFlags;
objectArgs.contentPolicyType() = mLoadInfo->InternalContentPolicyType();
objectArgs.isUrgentStart() = UserActivation::IsHandlingUserInput();
args.elementCreationArgs() = objectArgs;
break;
}
}
switch (mLoadInfo->GetExternalContentPolicyType()) {
case nsIContentPolicy::TYPE_DOCUMENT:
case nsIContentPolicy::TYPE_SUBDOCUMENT:
loadingContext->SetCurrentLoadIdentifier(
Some(mLoadState->GetLoadIdentifier()));
break;
default:
break;
}
gNeckoChild->SendPDocumentChannelConstructor(this, loadingContext, args);
mIsPending = true; mIsPending = true;
mWasOpened = true; mWasOpened = true;

View File

@@ -11,6 +11,7 @@
#include "mozilla/dom/CanonicalBrowsingContext.h" #include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/ClientInfo.h" #include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#include "nsDocShellLoadState.h"
extern mozilla::LazyLogModule gDocumentChannelLog; extern mozilla::LazyLogModule gDocumentChannelLog;
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt) #define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
@@ -51,12 +52,30 @@ bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
} }
nsresult rv = NS_ERROR_UNEXPECTED; nsresult rv = NS_ERROR_UNEXPECTED;
promise = mDocumentLoadListener->Open(
loadState, aArgs.cacheKey(), Some(aArgs.channelId()), if (aArgs.elementCreationArgs().type() ==
aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr), DocumentChannelElementCreationArgs::TDocumentCreationArgs) {
std::move(clientInfo), aArgs.outerWindowId(), const DocumentCreationArgs& docArgs = aArgs.elementCreationArgs();
aArgs.hasValidTransientUserAction(), Some(aArgs.uriModified()),
Some(aArgs.isXFOError()), IProtocol::OtherPid(), &rv); promise = mDocumentLoadListener->OpenDocument(
loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr),
std::move(clientInfo), docArgs.outerWindowId(),
aArgs.hasValidTransientUserAction(), Some(docArgs.uriModified()),
Some(docArgs.isXFOError()), IProtocol::OtherPid(), &rv);
} else {
const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();
promise = mDocumentLoadListener->OpenObject(
loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr),
std::move(clientInfo), objectArgs.embedderInnerWindowId(),
objectArgs.loadFlags(), objectArgs.contentPolicyType(),
aArgs.hasValidTransientUserAction(), objectArgs.isUrgentStart(),
IProtocol::OtherPid(), &rv);
}
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
MOZ_ASSERT(!promise); MOZ_ASSERT(!promise);
return SendFailedAsyncOpen(rv); return SendFailedAsyncOpen(rv);

View File

@@ -42,10 +42,13 @@
#include "nsIViewSourceChannel.h" #include "nsIViewSourceChannel.h"
#include "nsImportModule.h" #include "nsImportModule.h"
#include "nsMimeTypes.h" #include "nsMimeTypes.h"
#include "nsQueryObject.h"
#include "nsRedirectHistoryEntry.h" #include "nsRedirectHistoryEntry.h"
#include "nsSandboxFlags.h" #include "nsSandboxFlags.h"
#include "nsStringStream.h"
#include "nsURILoader.h" #include "nsURILoader.h"
#include "nsWebNavigationInfo.h" #include "nsWebNavigationInfo.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/nsHTTPSOnlyUtils.h" #include "mozilla/dom/nsHTTPSOnlyUtils.h"
#include "mozilla/dom/RemoteWebProgress.h" #include "mozilla/dom/RemoteWebProgress.h"
@@ -76,6 +79,94 @@ static void SetNeedToAddURIVisit(nsIChannel* aChannel,
aNeedToAddURIVisit); aNeedToAddURIVisit);
} }
static auto SecurityFlagsForLoadInfo(nsDocShellLoadState* aLoadState)
-> nsSecurityFlags {
// TODO: Block copied from nsDocShell::DoURILoad, refactor out somewhere
nsSecurityFlags securityFlags =
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
if (aLoadState->LoadType() == LOAD_ERROR_PAGE) {
securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
}
if (aLoadState->PrincipalToInherit()) {
bool isSrcdoc =
aLoadState->HasLoadFlags(nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC);
bool inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
aLoadState->PrincipalToInherit(), aLoadState->URI(),
true, // aInheritForAboutBlank
isSrcdoc);
bool isURIUniqueOrigin =
StaticPrefs::security_data_uri_unique_opaque_origin() &&
SchemeIsData(aLoadState->URI());
if (inheritAttrs && !isURIUniqueOrigin) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
}
return securityFlags;
}
// Construct a LoadInfo object to use when creating the internal channel for a
// Document/SubDocument load.
static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext,
nsDocShellLoadState* aLoadState,
uint64_t aOuterWindowId)
-> already_AddRefed<LoadInfo> {
uint32_t sandboxFlags = aBrowsingContext->GetSandboxFlags();
RefPtr<LoadInfo> loadInfo;
auto securityFlags = SecurityFlagsForLoadInfo(aLoadState);
if (aBrowsingContext->GetParent()) {
loadInfo = LoadInfo::CreateForFrame(
aBrowsingContext, aLoadState->TriggeringPrincipal(), aOuterWindowId,
securityFlags, sandboxFlags);
} else {
OriginAttributes attrs;
aBrowsingContext->GetOriginAttributes(attrs);
loadInfo = LoadInfo::CreateForDocument(
aBrowsingContext, aLoadState->TriggeringPrincipal(), attrs,
aOuterWindowId, securityFlags, sandboxFlags);
}
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
return loadInfo.forget();
}
// Construct a LoadInfo object to use when creating the internal channel for an
// Object/Embed load.
static auto CreateObjectLoadInfo(nsDocShellLoadState* aLoadState,
uint64_t aInnerWindowId,
nsContentPolicyType aContentPolicyType,
uint32_t aSandboxFlags)
-> already_AddRefed<LoadInfo> {
RefPtr<WindowGlobalParent> wgp =
WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
MOZ_RELEASE_ASSERT(wgp);
auto securityFlags = SecurityFlagsForLoadInfo(aLoadState);
RefPtr<LoadInfo> loadInfo = LoadInfo::CreateForNonDocument(
wgp, wgp->DocumentPrincipal(), 0, aContentPolicyType, securityFlags,
aSandboxFlags);
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
return loadInfo.forget();
}
static auto WebProgressForBrowsingContext(
CanonicalBrowsingContext* aBrowsingContext)
-> already_AddRefed<BrowsingContextWebProgress> {
return RefPtr<BrowsingContextWebProgress>(aBrowsingContext->GetWebProgress())
.forget();
}
/** /**
* An extension to nsDocumentOpenInfo that we run in the parent process, so * An extension to nsDocumentOpenInfo that we run in the parent process, so
* that we can make the decision to retarget to content handlers or the external * that we can make the decision to retarget to content handlers or the external
@@ -94,10 +185,12 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
public: public:
ParentProcessDocumentOpenInfo(ParentChannelListener* aListener, ParentProcessDocumentOpenInfo(ParentChannelListener* aListener,
uint32_t aFlags, uint32_t aFlags,
mozilla::dom::BrowsingContext* aBrowsingContext) mozilla::dom::BrowsingContext* aBrowsingContext,
nsContentPolicyType aExternalContentPolicyType)
: nsDocumentOpenInfo(aFlags, false), : nsDocumentOpenInfo(aFlags, false),
mBrowsingContext(aBrowsingContext), mBrowsingContext(aBrowsingContext),
mListener(aListener) { mListener(aListener),
mExternalContentPolicyType(aExternalContentPolicyType) {
LOG(("ParentProcessDocumentOpenInfo ctor [this=%p]", this)); LOG(("ParentProcessDocumentOpenInfo ctor [this=%p]", this));
} }
@@ -169,12 +262,13 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
nsDocumentOpenInfo* Clone() override { nsDocumentOpenInfo* Clone() override {
mCloned = true; mCloned = true;
return new ParentProcessDocumentOpenInfo(mListener, mFlags, return new ParentProcessDocumentOpenInfo(
mBrowsingContext); mListener, mFlags, mBrowsingContext, mExternalContentPolicyType);
} }
NS_IMETHOD OnStartRequest(nsIRequest* request) override { nsresult OnDocumentStartRequest(nsIRequest* request) {
LOG(("ParentProcessDocumentOpenInfo OnStartRequest [this=%p]", this)); LOG(("ParentProcessDocumentOpenInfo OnDocumentStartRequest [this=%p]",
this));
nsresult rv = nsDocumentOpenInfo::OnStartRequest(request); nsresult rv = nsDocumentOpenInfo::OnStartRequest(request);
@@ -213,6 +307,32 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
return rv; return rv;
} }
nsresult OnObjectStartRequest(nsIRequest* request) {
LOG(("ParentProcessDocumentOpenInfo OnObjectStartRequest [this=%p]", this));
// Just redirect to the nsObjectLoadingContent in the content process.
m_targetStreamListener = mListener;
return m_targetStreamListener->OnStartRequest(request);
}
NS_IMETHOD OnStartRequest(nsIRequest* request) override {
LOG(("ParentProcessDocumentOpenInfo OnStartRequest [this=%p]", this));
switch (mExternalContentPolicyType) {
case nsIContentPolicy::TYPE_DOCUMENT:
case nsIContentPolicy::TYPE_SUBDOCUMENT:
return OnDocumentStartRequest(request);
break;
case nsIContentPolicy::TYPE_OBJECT:
return OnObjectStartRequest(request);
break;
default:
MOZ_CRASH("Unexpect external content policy type.");
return NS_BINDING_FAILED;
}
}
NS_IMETHOD OnAfterLastPart(nsresult aStatus) override { NS_IMETHOD OnAfterLastPart(nsresult aStatus) override {
mListener->OnAfterLastPart(aStatus); mListener->OnAfterLastPart(aStatus);
return NS_OK; return NS_OK;
@@ -236,6 +356,7 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext; RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
RefPtr<ParentChannelListener> mListener; RefPtr<ParentChannelListener> mListener;
nsContentPolicyType mExternalContentPolicyType;
/** /**
* Set to true if we got cloned to create a chained listener. * Set to true if we got cloned to create a chained listener.
@@ -267,10 +388,11 @@ NS_INTERFACE_MAP_BEGIN(DocumentLoadListener)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
DocumentLoadListener::DocumentLoadListener( DocumentLoadListener::DocumentLoadListener(
CanonicalBrowsingContext* aBrowsingContext) { CanonicalBrowsingContext* aLoadingBrowsingContext) {
LOG(("DocumentLoadListener ctor [this=%p]", this)); LOG(("DocumentLoadListener ctor [this=%p]", this));
mParentChannelListener = new ParentChannelListener( mParentChannelListener =
this, aBrowsingContext, aBrowsingContext->UsePrivateBrowsing()); new ParentChannelListener(this, aLoadingBrowsingContext,
aLoadingBrowsingContext->UsePrivateBrowsing());
} }
DocumentLoadListener::~DocumentLoadListener() { DocumentLoadListener::~DocumentLoadListener() {
@@ -304,7 +426,7 @@ void DocumentLoadListener::AddURIVisit(nsIChannel* aChannel,
} }
RefPtr<CanonicalBrowsingContext> browsingContext = RefPtr<CanonicalBrowsingContext> browsingContext =
mParentChannelListener->GetBrowsingContext(); GetDocumentBrowsingContext();
nsCOMPtr<nsIWidget> widget = nsCOMPtr<nsIWidget> widget =
browsingContext->GetParentProcessWidgetContaining(); browsingContext->GetParentProcessWidgetContaining();
@@ -313,97 +435,49 @@ void DocumentLoadListener::AddURIVisit(nsIChannel* aChannel,
mLoadStateLoadType); mLoadStateLoadType);
} }
already_AddRefed<LoadInfo> DocumentLoadListener::CreateLoadInfo( CanonicalBrowsingContext* DocumentLoadListener::GetLoadingBrowsingContext()
CanonicalBrowsingContext* aBrowsingContext, nsDocShellLoadState* aLoadState, const {
uint64_t aOuterWindowId) { return mParentChannelListener ? mParentChannelListener->GetBrowsingContext()
// TODO: Block copied from nsDocShell::DoURILoad, refactor out somewhere : nullptr;
bool inheritPrincipal = false;
if (aLoadState->PrincipalToInherit()) {
bool isSrcdoc =
aLoadState->HasLoadFlags(nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC);
bool inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
aLoadState->PrincipalToInherit(), aLoadState->URI(),
true, // aInheritForAboutBlank
isSrcdoc);
bool isURIUniqueOrigin =
StaticPrefs::security_data_uri_unique_opaque_origin() &&
SchemeIsData(aLoadState->URI());
inheritPrincipal = inheritAttrs && !isURIUniqueOrigin;
}
nsSecurityFlags securityFlags =
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
uint32_t sandboxFlags = aBrowsingContext->GetSandboxFlags();
if (aLoadState->LoadType() == LOAD_ERROR_PAGE) {
securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
}
if (inheritPrincipal) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
RefPtr<LoadInfo> loadInfo;
if (aBrowsingContext->GetParent()) {
// Build LoadInfo for TYPE_SUBDOCUMENT
loadInfo = LoadInfo::CreateForFrame(
aBrowsingContext, aLoadState->TriggeringPrincipal(), aOuterWindowId,
securityFlags, sandboxFlags);
} else {
// Build LoadInfo for TYPE_DOCUMENT
OriginAttributes attrs;
aBrowsingContext->GetOriginAttributes(attrs);
loadInfo = LoadInfo::CreateForDocument(
aBrowsingContext, aLoadState->TriggeringPrincipal(), attrs,
aOuterWindowId, securityFlags, sandboxFlags);
}
loadInfo->SetHasValidUserGestureActivation(
aLoadState->HasValidUserGestureActivation());
return loadInfo.forget();
} }
CanonicalBrowsingContext* DocumentLoadListener::GetBrowsingContext() const { CanonicalBrowsingContext* DocumentLoadListener::GetDocumentBrowsingContext()
if (!mParentChannelListener) { const {
if (mExternalContentPolicyType == nsIContentPolicy::TYPE_OBJECT) {
return nullptr; return nullptr;
} }
return mParentChannelListener->GetBrowsingContext();
return GetLoadingBrowsingContext();
} }
auto DocumentLoadListener::Open( CanonicalBrowsingContext* DocumentLoadListener::GetTopBrowsingContext() const {
nsDocShellLoadState* aLoadState, uint32_t aCacheKey, auto* loadingContext = GetLoadingBrowsingContext();
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime, return loadingContext ? loadingContext->Top() : nullptr;
nsDOMNavigationTiming* aTiming, Maybe<ClientInfo>&& aInfo, }
uint64_t aOuterWindowId, bool aHasGesture, Maybe<bool> aUriModified,
Maybe<bool> aIsXFOError, base::ProcessId aPid, nsresult* aRv) auto DocumentLoadListener::Open(nsDocShellLoadState* aLoadState,
-> RefPtr<OpenPromise> { LoadInfo* aLoadInfo, nsLoadFlags aLoadFlags,
LOG(("DocumentLoadListener Open [this=%p, uri=%s]", this, uint32_t aCacheKey,
aLoadState->URI()->GetSpecOrDefault().get())); const Maybe<uint64_t>& aChannelId,
RefPtr<CanonicalBrowsingContext> browsingContext = const TimeStamp& aAsyncOpenTime,
mParentChannelListener->GetBrowsingContext(); nsDOMNavigationTiming* aTiming,
Maybe<ClientInfo>&& aInfo, bool aHasGesture,
bool aUrgentStart, base::ProcessId aPid,
nsresult* aRv) -> RefPtr<OpenPromise> {
auto* loadingContext = GetLoadingBrowsingContext();
MOZ_DIAGNOSTIC_ASSERT_IF(loadingContext->GetParent(),
loadingContext->GetParentWindowContext());
OriginAttributes attrs; OriginAttributes attrs;
browsingContext->GetOriginAttributes(attrs); loadingContext->GetOriginAttributes(attrs);
mLoadIdentifier = aLoadState->GetLoadIdentifier(); mLoadIdentifier = aLoadState->GetLoadIdentifier();
MOZ_DIAGNOSTIC_ASSERT_IF(browsingContext->GetParent(), mExternalContentPolicyType = aLoadInfo->GetExternalContentPolicyType();
browsingContext->GetParentWindowContext());
// If this is a top-level load, then rebuild the LoadInfo from scratch,
// since the goal is to be able to initiate loads in the parent, where the
// content process won't have provided us with an existing one.
RefPtr<LoadInfo> loadInfo =
CreateLoadInfo(browsingContext, aLoadState, aOuterWindowId);
nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
browsingContext, std::move(aUriModified), std::move(aIsXFOError));
if (!nsDocShell::CreateAndConfigureRealChannelForLoadState( if (!nsDocShell::CreateAndConfigureRealChannelForLoadState(
browsingContext, aLoadState, loadInfo, mParentChannelListener, loadingContext, aLoadState, aLoadInfo, mParentChannelListener,
nullptr, attrs, loadFlags, aCacheKey, *aRv, nullptr, attrs, aLoadFlags, aCacheKey, *aRv,
getter_AddRefs(mChannel))) { getter_AddRefs(mChannel))) {
LOG(("DocumentLoadListener::Open failed to create channel [this=%p]", LOG(("DocumentLoadListener::Open failed to create channel [this=%p]",
this)); this));
@@ -411,19 +485,20 @@ auto DocumentLoadListener::Open(
return nullptr; return nullptr;
} }
nsCOMPtr<nsIURI> uriBeingLoaded = nsCOMPtr<nsIURI> uriBeingLoaded;
AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel); Unused << NS_WARN_IF(
NS_FAILED(mChannel->GetURI(getter_AddRefs(uriBeingLoaded))));
RefPtr<HttpBaseChannel> httpBaseChannel = do_QueryObject(mChannel, aRv); RefPtr<HttpBaseChannel> httpBaseChannel = do_QueryObject(mChannel, aRv);
if (httpBaseChannel) { if (uriBeingLoaded && httpBaseChannel) {
nsCOMPtr<nsIURI> topWindowURI; nsCOMPtr<nsIURI> topWindowURI;
if (browsingContext->IsTop()) { if (loadingContext->IsTop()) {
// If this is for the top level loading, the top window URI should be the // If this is for the top level loading, the top window URI should be the
// URI which we are loading. // URI which we are loading.
topWindowURI = uriBeingLoaded; topWindowURI = uriBeingLoaded;
} else if (RefPtr<WindowGlobalParent> topWindow = AntiTrackingUtils:: } else if (RefPtr<WindowGlobalParent> topWindow = AntiTrackingUtils::
GetTopWindowExcludingExtensionAccessibleContentFrames( GetTopWindowExcludingExtensionAccessibleContentFrames(
browsingContext, uriBeingLoaded)) { loadingContext, uriBeingLoaded)) {
nsCOMPtr<nsIPrincipal> topWindowPrincipal = nsCOMPtr<nsIPrincipal> topWindowPrincipal =
topWindow->DocumentPrincipal(); topWindow->DocumentPrincipal();
if (topWindowPrincipal && !topWindowPrincipal->GetIsNullPrincipal()) { if (topWindowPrincipal && !topWindowPrincipal->GetIsNullPrincipal()) {
@@ -451,7 +526,12 @@ auto DocumentLoadListener::Open(
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel)) { if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel)) {
Unused << httpChannel->SetRequestContextID( Unused << httpChannel->SetRequestContextID(
browsingContext->GetRequestContextId()); loadingContext->GetRequestContextId());
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(httpChannel));
if (cos && aUrgentStart) {
cos->AddClassFlags(nsIClassOfService::UrgentStart);
}
} }
// nsViewSourceChannel normally replaces the nsIRequest passed to // nsViewSourceChannel normally replaces the nsIRequest passed to
@@ -467,7 +547,8 @@ auto DocumentLoadListener::Open(
// across any serviceworker related data between channels as needed. // across any serviceworker related data between channels as needed.
AddClientChannelHelperInParent(mChannel, std::move(aInfo)); AddClientChannelHelperInParent(mChannel, std::move(aInfo));
if (!browsingContext->StartDocumentLoad(this)) { auto* documentContext = GetDocumentBrowsingContext();
if (documentContext && !documentContext->StartDocumentLoad(this)) {
LOG(("DocumentLoadListener::Open failed StartDocumentLoad [this=%p]", LOG(("DocumentLoadListener::Open failed StartDocumentLoad [this=%p]",
this)); this));
*aRv = NS_BINDING_ABORTED; *aRv = NS_BINDING_ABORTED;
@@ -480,29 +561,30 @@ auto DocumentLoadListener::Open(
// NOTE: The only case not handled here to mirror Content process is // NOTE: The only case not handled here to mirror Content process is
// redirecting to re-use the channel. // redirecting to re-use the channel.
MOZ_ASSERT(!aLoadState->GetPendingRedirectedChannel()); MOZ_ASSERT(!aLoadState->GetPendingRedirectedChannel());
uint32_t openFlags = nsDocShell::ComputeURILoaderFlags( uint32_t openFlags =
browsingContext, aLoadState->LoadType()); nsDocShell::ComputeURILoaderFlags(loadingContext, aLoadState->LoadType());
RefPtr<ParentProcessDocumentOpenInfo> openInfo = RefPtr<ParentProcessDocumentOpenInfo> openInfo =
new ParentProcessDocumentOpenInfo(mParentChannelListener, openFlags, new ParentProcessDocumentOpenInfo(mParentChannelListener, openFlags,
browsingContext); loadingContext,
mExternalContentPolicyType);
openInfo->Prepare(); openInfo->Prepare();
#ifdef ANDROID #ifdef ANDROID
RefPtr<MozPromise<bool, bool, false>> promise; RefPtr<MozPromise<bool, bool, false>> promise;
if (aLoadState->LoadType() != LOAD_ERROR_PAGE && if (documentContext && aLoadState->LoadType() != LOAD_ERROR_PAGE &&
!(aLoadState->HasLoadFlags( !(aLoadState->HasLoadFlags(
nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE)) && nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE)) &&
!(aLoadState->LoadType() & LOAD_HISTORY)) { !(aLoadState->LoadType() & LOAD_HISTORY)) {
nsCOMPtr<nsIWidget> widget = nsCOMPtr<nsIWidget> widget =
browsingContext->GetParentProcessWidgetContaining(); documentContext->GetParentProcessWidgetContaining();
RefPtr<nsWindow> window = nsWindow::From(widget); RefPtr<nsWindow> window = nsWindow::From(widget);
if (window) { if (window) {
promise = window->OnLoadRequest( promise = window->OnLoadRequest(
aLoadState->URI(), nsIBrowserDOMWindow::OPEN_CURRENTWINDOW, aLoadState->URI(), nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
aLoadState->LoadFlags(), aLoadState->TriggeringPrincipal(), aLoadState->LoadFlags(), aLoadState->TriggeringPrincipal(),
aHasGesture, browsingContext->IsTopContent()); aHasGesture, documentContext->IsTopContent());
} }
} }
@@ -533,7 +615,9 @@ auto DocumentLoadListener::Open(
LOG(("DocumentLoadListener::Open failed AsyncOpen [this=%p rv=%" PRIx32 LOG(("DocumentLoadListener::Open failed AsyncOpen [this=%p rv=%" PRIx32
"]", "]",
this, static_cast<uint32_t>(*aRv))); this, static_cast<uint32_t>(*aRv)));
browsingContext->EndDocumentLoad(false); if (documentContext) {
documentContext->EndDocumentLoad(false);
}
mParentChannelListener = nullptr; mParentChannelListener = nullptr;
return nullptr; return nullptr;
} }
@@ -548,9 +632,9 @@ auto DocumentLoadListener::Open(
mBaseURI = aLoadState->BaseURI(); mBaseURI = aLoadState->BaseURI();
mOriginalUriString = aLoadState->GetOriginalURIString(); mOriginalUriString = aLoadState->GetOriginalURIString();
if (StaticPrefs::fission_sessionHistoryInParent() && if (StaticPrefs::fission_sessionHistoryInParent() &&
browsingContext->GetSessionHistory()) { documentContext->GetSessionHistory()) {
mSessionHistoryInfo = mSessionHistoryInfo =
browsingContext->CreateSessionHistoryEntryForLoad(aLoadState, mChannel); documentContext->CreateSessionHistoryEntryForLoad(aLoadState, mChannel);
} }
*aRv = NS_OK; *aRv = NS_OK;
@@ -561,14 +645,72 @@ auto DocumentLoadListener::Open(
return mOpenPromise; return mOpenPromise;
} }
auto DocumentLoadListener::OpenDocument(
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
uint64_t aOuterWindowId, bool aHasGesture, Maybe<bool> aUriModified,
Maybe<bool> aIsXFOError, base::ProcessId aPid, nsresult* aRv)
-> RefPtr<OpenPromise> {
LOG(("DocumentLoadListener [%p] OpenDocument [uri=%s]", this,
aLoadState->URI()->GetSpecOrDefault().get()));
RefPtr<CanonicalBrowsingContext> browsingContext =
GetDocumentBrowsingContext();
// If this is a top-level load, then rebuild the LoadInfo from scratch,
// since the goal is to be able to initiate loads in the parent, where the
// content process won't have provided us with an existing one.
RefPtr<LoadInfo> loadInfo =
CreateDocumentLoadInfo(browsingContext, aLoadState, aOuterWindowId);
MOZ_ASSERT_IF(!browsingContext->GetParent(),
loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_DOCUMENT);
MOZ_ASSERT_IF(browsingContext->GetParent(),
loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_SUBDOCUMENT);
nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
browsingContext, std::move(aUriModified), std::move(aIsXFOError));
return Open(aLoadState, loadInfo, loadFlags, aCacheKey, aChannelId,
aAsyncOpenTime, aTiming, std::move(aInfo), aHasGesture, false,
aPid, aRv);
}
auto DocumentLoadListener::OpenObject(
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
uint64_t aInnerWindowId, nsLoadFlags aLoadFlags,
nsContentPolicyType aContentPolicyType, bool aHasGesture, bool aUrgentStart,
base::ProcessId aPid, nsresult* aRv) -> RefPtr<OpenPromise> {
LOG(("DocumentLoadListener [%p] OpenObject [uri=%s]", this,
aLoadState->URI()->GetSpecOrDefault().get()));
auto sandboxFlags = GetLoadingBrowsingContext()->GetSandboxFlags();
RefPtr<LoadInfo> loadInfo = CreateObjectLoadInfo(
aLoadState, aInnerWindowId, aContentPolicyType, sandboxFlags);
MOZ_ASSERT(loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_OBJECT);
return Open(aLoadState, loadInfo, aLoadFlags, aCacheKey, aChannelId,
aAsyncOpenTime, aTiming, std::move(aInfo), aHasGesture,
aUrgentStart, aPid, aRv);
}
auto DocumentLoadListener::OpenInParent(nsDocShellLoadState* aLoadState, auto DocumentLoadListener::OpenInParent(nsDocShellLoadState* aLoadState,
uint64_t aOuterWindowId, uint64_t aOuterWindowId,
bool aSupportsRedirectToRealChannel) bool aSupportsRedirectToRealChannel)
-> RefPtr<OpenPromise> { -> RefPtr<OpenPromise> {
// We currently only support passing nullptr for aLoadInfo for // We currently only support passing nullptr for aLoadInfo for
// top level browsing contexts. // top level browsing contexts.
if (!GetBrowsingContext()->IsTopContent() || auto* browsingContext = GetDocumentBrowsingContext();
!GetBrowsingContext()->GetContentParent()) { if (!browsingContext->IsTopContent() ||
!browsingContext->GetContentParent()) {
LOG(("DocumentLoadListener::OpenInParent failed because of subdoc")); LOG(("DocumentLoadListener::OpenInParent failed because of subdoc"));
return nullptr; return nullptr;
} }
@@ -607,7 +749,7 @@ auto DocumentLoadListener::OpenInParent(nsDocShellLoadState* aLoadState,
RefPtr<nsDOMNavigationTiming> timing = new nsDOMNavigationTiming(nullptr); RefPtr<nsDOMNavigationTiming> timing = new nsDOMNavigationTiming(nullptr);
timing->NotifyNavigationStart( timing->NotifyNavigationStart(
GetBrowsingContext()->GetIsActive() browsingContext->GetIsActive()
? nsDOMNavigationTiming::DocShellState::eActive ? nsDOMNavigationTiming::DocShellState::eActive
: nsDOMNavigationTiming::DocShellState::eInactive); : nsDOMNavigationTiming::DocShellState::eInactive);
@@ -625,27 +767,44 @@ auto DocumentLoadListener::OpenInParent(nsDocShellLoadState* aLoadState,
mSupportsRedirectToRealChannel = aSupportsRedirectToRealChannel; mSupportsRedirectToRealChannel = aSupportsRedirectToRealChannel;
// This is a top-level load, so rebuild the LoadInfo from scratch,
// since in the parent the
// content process won't have provided us with an existing one.
RefPtr<LoadInfo> loadInfo =
CreateDocumentLoadInfo(browsingContext, aLoadState, aOuterWindowId);
MOZ_ASSERT_IF(!browsingContext->GetParent(),
loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_DOCUMENT);
MOZ_ASSERT_IF(browsingContext->GetParent(),
loadInfo->GetExternalContentPolicyType() ==
nsIContentPolicy::TYPE_SUBDOCUMENT);
nsLoadFlags loadFlags = loadState->CalculateChannelLoadFlags(
browsingContext, Nothing(), Nothing());
nsresult rv; nsresult rv;
return Open(loadState, cacheKey, channelId, TimeStamp::Now(), timing, return Open(loadState, loadInfo, loadFlags, cacheKey, channelId,
std::move(initialClientInfo), aOuterWindowId, false, Nothing(), TimeStamp::Now(), timing, std::move(initialClientInfo), false,
Nothing(), GetBrowsingContext()->GetContentParent()->OtherPid(), false, browsingContext->GetContentParent()->OtherPid(), &rv);
&rv);
} }
static void FireStateChange(DocumentLoadListener* aLoad, uint32_t aStateFlags, void DocumentLoadListener::FireStateChange(uint32_t aStateFlags,
nsresult aStatus) { nsresult aStatus) {
nsCOMPtr<nsIChannel> request = aLoad->GetChannel(); nsCOMPtr<nsIChannel> request = GetChannel();
nsCOMPtr<nsIWebProgress> webProgress = nsCOMPtr<nsIWebProgress> webProgress =
new RemoteWebProgress(aLoad->GetLoadType(), true, true); new RemoteWebProgress(GetLoadType(), true, true);
RefPtr<CanonicalBrowsingContext> ctx = aLoad->GetBrowsingContext(); RefPtr<BrowsingContextWebProgress> loadingWebProgress =
NS_DispatchToMainThread( WebProgressForBrowsingContext(GetLoadingBrowsingContext());
NS_NewRunnableFunction("DocumentLoadListener::FireStateChange", [=]() {
if (ctx && ctx->GetWebProgress()) { if (loadingWebProgress) {
ctx->GetWebProgress()->OnStateChange(webProgress, request, NS_DispatchToMainThread(
aStateFlags, aStatus); NS_NewRunnableFunction("DocumentLoadListener::FireStateChange", [=]() {
} loadingWebProgress->OnStateChange(webProgress, request, aStateFlags,
})); aStatus);
}));
}
} }
static void SetNavigating(CanonicalBrowsingContext* aBrowsingContext, static void SetNavigating(CanonicalBrowsingContext* aBrowsingContext,
@@ -691,21 +850,19 @@ static void SetNavigating(CanonicalBrowsingContext* aBrowsingContext,
// finished (and failed), and we should fire a state change to notify // finished (and failed), and we should fire a state change to notify
// observers. Normally the docshell would fire this, and it would get // observers. Normally the docshell would fire this, and it would get
// filtered out by BrowserParent if needed. // filtered out by BrowserParent if needed.
FireStateChange(load, load->FireStateChange(nsIWebProgressListener::STATE_STOP |
nsIWebProgressListener::STATE_STOP | nsIWebProgressListener::STATE_IS_WINDOW |
nsIWebProgressListener::STATE_IS_WINDOW | nsIWebProgressListener::STATE_IS_NETWORK,
nsIWebProgressListener::STATE_IS_NETWORK, rejectValue.mStatus);
rejectValue.mStatus);
} }
}); });
FireStateChange(load, load->FireStateChange(nsIWebProgressListener::STATE_START |
nsIWebProgressListener::STATE_START | nsIWebProgressListener::STATE_IS_DOCUMENT |
nsIWebProgressListener::STATE_IS_DOCUMENT | nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_REQUEST | nsIWebProgressListener::STATE_IS_WINDOW |
nsIWebProgressListener::STATE_IS_WINDOW | nsIWebProgressListener::STATE_IS_NETWORK,
nsIWebProgressListener::STATE_IS_NETWORK, NS_OK);
NS_OK);
SetNavigating(aBrowsingContext, false); SetNavigating(aBrowsingContext, false);
return true; return true;
} }
@@ -793,7 +950,7 @@ void DocumentLoadListener::Disconnect() {
httpChannelImpl->SetWarningReporter(nullptr); httpChannelImpl->SetWarningReporter(nullptr);
} }
if (auto* ctx = GetBrowsingContext()) { if (auto* ctx = GetDocumentBrowsingContext()) {
ctx->EndDocumentLoad(mDoingProcessSwitch); ctx->EndDocumentLoad(mDoingProcessSwitch);
} }
} }
@@ -887,7 +1044,7 @@ void DocumentLoadListener::FinishReplacementChannelSetup(nsresult aResult) {
this, int(aResult))); this, int(aResult)));
auto endDocumentLoad = MakeScopeExit([&]() { auto endDocumentLoad = MakeScopeExit([&]() {
if (auto* ctx = GetBrowsingContext()) { if (auto* ctx = GetDocumentBrowsingContext()) {
ctx->EndDocumentLoad(false); ctx->EndDocumentLoad(false);
} }
}); });
@@ -1068,7 +1225,7 @@ bool DocumentLoadListener::ResumeSuspendedChannel(
mChannel->Resume(); mChannel->Resume();
if (auto* ctx = GetBrowsingContext()) { if (auto* ctx = GetDocumentBrowsingContext()) {
ctx->EndDocumentLoad(mDoingProcessSwitch); ctx->EndDocumentLoad(mDoingProcessSwitch);
} }
@@ -1295,6 +1452,12 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
LOG(("DocumentLoadListener MaybeTriggerProcessSwitch [this=%p]", this)); LOG(("DocumentLoadListener MaybeTriggerProcessSwitch [this=%p]", this));
// Don't switch process for <object>/<embed> loads.
if (mExternalContentPolicyType == nsIContentPolicy::TYPE_OBJECT) {
LOG(("Process Switch Abort: non-document load"));
return false;
}
// Get the BrowsingContext which will be switching processes. // Get the BrowsingContext which will be switching processes.
RefPtr<CanonicalBrowsingContext> browsingContext = RefPtr<CanonicalBrowsingContext> browsingContext =
mParentChannelListener->GetBrowsingContext(); mParentChannelListener->GetBrowsingContext();
@@ -1550,14 +1713,24 @@ DocumentLoadListener::RedirectToRealChannel(
"aRedirectFlags=%" PRIx32 ", aLoadFlags=%" PRIx32, "aRedirectFlags=%" PRIx32 ", aLoadFlags=%" PRIx32,
this, aRedirectFlags, aLoadFlags)); this, aRedirectFlags, aLoadFlags));
// TODO(djg): Add the last URI visit to history if success. Is there a better switch (mExternalContentPolicyType) {
// place to handle this? Need access to the updated aLoadFlags. case nsIContentPolicy::TYPE_DOCUMENT:
nsresult status = NS_OK; case nsIContentPolicy::TYPE_SUBDOCUMENT: {
mChannel->GetStatus(&status); // TODO(djg): Add the last URI visit to history if success. Is there a
bool updateGHistory = // better place to handle this? Need access to the updated aLoadFlags.
nsDocShell::ShouldUpdateGlobalHistory(mLoadStateLoadType); nsresult status = NS_OK;
if (NS_SUCCEEDED(status) && updateGHistory && !net::ChannelIsPost(mChannel)) { mChannel->GetStatus(&status);
AddURIVisit(mChannel, aLoadFlags); bool updateGHistory =
nsDocShell::ShouldUpdateGlobalHistory(mLoadStateLoadType);
if (NS_SUCCEEDED(status) && updateGHistory &&
!net::ChannelIsPost(mChannel)) {
AddURIVisit(mChannel, aLoadFlags);
}
break;
}
default:
break;
} }
// Register the new channel and obtain id for it // Register the new channel and obtain id for it
@@ -1703,7 +1876,9 @@ void DocumentLoadListener::TriggerRedirectToRealChannel(
MOZ_ALWAYS_SUCCEEDS(mChannel->GetLoadFlags(&newLoadFlags)); MOZ_ALWAYS_SUCCEEDS(mChannel->GetLoadFlags(&newLoadFlags));
// We're pulling our flags from the inner channel, which may not have this // We're pulling our flags from the inner channel, which may not have this
// flag set on it. This is the case when loading a 'view-source' channel. // flag set on it. This is the case when loading a 'view-source' channel.
newLoadFlags |= nsIChannel::LOAD_DOCUMENT_URI; if (mExternalContentPolicyType != nsIContentPolicy::TYPE_OBJECT) {
newLoadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
}
if (!aDestinationProcess) { if (!aDestinationProcess) {
newLoadFlags |= nsIChannel::LOAD_REPLACE; newLoadFlags |= nsIChannel::LOAD_REPLACE;
} }
@@ -1742,7 +1917,8 @@ void DocumentLoadListener::TriggerRedirectToRealChannel(
} }
void DocumentLoadListener::MaybeReportBlockedByURLClassifier(nsresult aStatus) { void DocumentLoadListener::MaybeReportBlockedByURLClassifier(nsresult aStatus) {
if (!GetBrowsingContext() || GetBrowsingContext()->IsTop() || auto* browsingContext = GetDocumentBrowsingContext();
if (!browsingContext || browsingContext->IsTop() ||
!StaticPrefs::privacy_trackingprotection_testing_report_blocked_node()) { !StaticPrefs::privacy_trackingprotection_testing_report_blocked_node()) {
return; return;
} }
@@ -1751,10 +1927,10 @@ void DocumentLoadListener::MaybeReportBlockedByURLClassifier(nsresult aStatus) {
return; return;
} }
RefPtr<WindowGlobalParent> parent = RefPtr<WindowGlobalParent> parent = browsingContext->GetParentWindowContext();
GetBrowsingContext()->GetParentWindowContext();
if (parent) { if (parent) {
Unused << parent->SendAddBlockedFrameNodeByClassifier(GetBrowsingContext()); Unused << parent->SendAddBlockedFrameNodeByClassifier(
GetLoadingBrowsingContext());
} }
} }
@@ -1768,15 +1944,17 @@ bool DocumentLoadListener::DocShellWillDisplayContent(nsresult aStatus) {
// succeed with fixup, so we don't need to check for it // succeed with fixup, so we don't need to check for it
// here. // here.
auto* loadingContext = GetLoadingBrowsingContext();
bool isInitialDocument = true; bool isInitialDocument = true;
if (WindowGlobalParent* currentWindow = if (WindowGlobalParent* currentWindow =
GetBrowsingContext()->GetCurrentWindowGlobal()) { loadingContext->GetCurrentWindowGlobal()) {
isInitialDocument = currentWindow->IsInitialDocument(); isInitialDocument = currentWindow->IsInitialDocument();
} }
nsresult rv = nsDocShell::FilterStatusForErrorPage( nsresult rv = nsDocShell::FilterStatusForErrorPage(
aStatus, mChannel, mLoadStateLoadType, GetBrowsingContext()->IsTop(), aStatus, mChannel, mLoadStateLoadType, loadingContext->IsTop(),
GetBrowsingContext()->GetUseErrorPages(), isInitialDocument, nullptr); loadingContext->GetUseErrorPages(), isInitialDocument, nullptr);
// If filtering returned a failure code, then an error page will // If filtering returned a failure code, then an error page will
// be display for that code, so return true; // be display for that code, so return true;
@@ -1784,14 +1962,17 @@ bool DocumentLoadListener::DocShellWillDisplayContent(nsresult aStatus) {
} }
bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) { bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
auto* bc = GetDocumentBrowsingContext();
if (!bc) {
return false;
}
nsCOMPtr<nsIInputStream> newPostData; nsCOMPtr<nsIInputStream> newPostData;
nsCOMPtr<nsIURI> newURI = nsDocShell::AttemptURIFixup( nsCOMPtr<nsIURI> newURI = nsDocShell::AttemptURIFixup(
mChannel, aStatus, mOriginalUriString, mLoadStateLoadType, mChannel, aStatus, mOriginalUriString, mLoadStateLoadType, bc->IsTop(),
GetBrowsingContext()->IsTop(),
mLoadStateLoadFlags & mLoadStateLoadFlags &
nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP,
GetBrowsingContext()->UsePrivateBrowsing(), true, bc->UsePrivateBrowsing(), true, getter_AddRefs(newPostData));
getter_AddRefs(newPostData));
if (!newURI) { if (!newURI) {
return false; return false;
} }
@@ -1812,7 +1993,7 @@ bool DocumentLoadListener::MaybeHandleLoadErrorWithURIFixup(nsresult aStatus) {
loadState->SetPostDataStream(newPostData); loadState->SetPostDataStream(newPostData);
GetBrowsingContext()->LoadURI(loadState, false); bc->LoadURI(loadState, false);
return true; return true;
} }
@@ -1834,7 +2015,8 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
// might cancel the channel. // might cancel the channel.
nsContentSecurityUtils::PerformCSPFrameAncestorAndXFOCheck(mChannel); nsContentSecurityUtils::PerformCSPFrameAncestorAndXFOCheck(mChannel);
if (!GetBrowsingContext() || GetBrowsingContext()->IsDiscarded()) { auto* loadingContext = GetLoadingBrowsingContext();
if (!loadingContext || loadingContext->IsDiscarded()) {
DisconnectListeners(NS_ERROR_UNEXPECTED, NS_ERROR_UNEXPECTED); DisconnectListeners(NS_ERROR_UNEXPECTED, NS_ERROR_UNEXPECTED);
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
@@ -1893,10 +2075,10 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
// If we're not going to process switch, then we must have an existing // If we're not going to process switch, then we must have an existing
// window global, right? // window global, right?
MOZ_ASSERT(GetBrowsingContext()->GetCurrentWindowGlobal()); MOZ_ASSERT(loadingContext->GetCurrentWindowGlobal());
RefPtr<BrowserParent> browserParent = RefPtr<BrowserParent> browserParent =
GetBrowsingContext()->GetCurrentWindowGlobal()->GetBrowserParent(); loadingContext->GetCurrentWindowGlobal()->GetBrowserParent();
// This load has already started, so we want to suspend the start progress // This load has already started, so we want to suspend the start progress
// events from the docshell from reaching the parent. // events from the docshell from reaching the parent.
@@ -1908,14 +2090,13 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
// Use the current process ID to run the 'process switch' path and connect // Use the current process ID to run the 'process switch' path and connect
// the channel into the current process. // the channel into the current process.
TriggerRedirectToRealChannel( TriggerRedirectToRealChannel(Some(loadingContext->OwnerProcessId()));
Some(GetBrowsingContext()->OwnerProcessId()));
} else { } else {
TriggerRedirectToRealChannel(Nothing()); TriggerRedirectToRealChannel(Nothing());
} }
// If we're not switching, then check if we're currently remote. // If we're not switching, then check if we're currently remote.
if (GetBrowsingContext() && GetBrowsingContext()->GetContentParent()) { if (auto* bc = GetDocumentBrowsingContext(); bc && bc->GetContentParent()) {
willBeRemote = true; willBeRemote = true;
} }
} }
@@ -2006,7 +2187,7 @@ DocumentLoadListener::OnAfterLastPart(nsresult aStatus) {
NS_IMETHODIMP NS_IMETHODIMP
DocumentLoadListener::GetInterface(const nsIID& aIID, void** result) { DocumentLoadListener::GetInterface(const nsIID& aIID, void** result) {
RefPtr<CanonicalBrowsingContext> browsingContext = RefPtr<CanonicalBrowsingContext> browsingContext =
mParentChannelListener->GetBrowsingContext(); GetDocumentBrowsingContext();
if (aIID.Equals(NS_GET_IID(nsILoadContext)) && browsingContext) { if (aIID.Equals(NS_GET_IID(nsILoadContext)) && browsingContext) {
browsingContext.forget(result); browsingContext.forget(result);
return NS_OK; return NS_OK;
@@ -2080,7 +2261,8 @@ DocumentLoadListener::Delete() {
NS_IMETHODIMP NS_IMETHODIMP
DocumentLoadListener::GetRemoteType(nsACString& aRemoteType) { DocumentLoadListener::GetRemoteType(nsACString& aRemoteType) {
RefPtr<CanonicalBrowsingContext> browsingContext = GetBrowsingContext(); RefPtr<CanonicalBrowsingContext> browsingContext =
GetDocumentBrowsingContext();
if (!browsingContext) { if (!browsingContext) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
@@ -2160,7 +2342,7 @@ DocumentLoadListener::AsyncOnChannelRedirect(
return NS_OK; return NS_OK;
} }
if (!net::ChannelIsPost(aOldChannel)) { if (GetDocumentBrowsingContext() && !net::ChannelIsPost(aOldChannel)) {
AddURIVisit(aOldChannel, 0); AddURIVisit(aOldChannel, 0);
nsCOMPtr<nsIURI> oldURI; nsCOMPtr<nsIURI> oldURI;
@@ -2207,7 +2389,8 @@ DocumentLoadListener::AsyncOnChannelRedirect(
AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel); AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(mChannel);
RefPtr<MozPromise<bool, bool, false>> promise; RefPtr<MozPromise<bool, bool, false>> promise;
nsCOMPtr<nsIWidget> widget = bc->GetParentProcessWidgetContaining(); nsCOMPtr<nsIWidget> widget =
bc ? bc->GetParentProcessWidgetContaining() : nullptr;
RefPtr<nsWindow> window = nsWindow::From(widget); RefPtr<nsWindow> window = nsWindow::From(widget);
if (window) { if (window) {
@@ -2283,16 +2466,17 @@ NS_IMETHODIMP DocumentLoadListener::OnStatus(nsIRequest* aRequest,
nsCOMPtr<nsIWebProgress> webProgress = nsCOMPtr<nsIWebProgress> webProgress =
new RemoteWebProgress(mLoadStateLoadType, true, true); new RemoteWebProgress(mLoadStateLoadType, true, true);
RefPtr<CanonicalBrowsingContext> ctx = GetBrowsingContext(); RefPtr<BrowsingContextWebProgress> topWebProgress =
WebProgressForBrowsingContext(GetTopBrowsingContext());
const nsString message(aStatusArg); const nsString message(aStatusArg);
NS_DispatchToMainThread( if (topWebProgress) {
NS_NewRunnableFunction("DocumentLoadListener::FireStateChange", [=]() { NS_DispatchToMainThread(
if (ctx && ctx->Top()->GetWebProgress()) { NS_NewRunnableFunction("DocumentLoadListener::OnStatus", [=]() {
ctx->Top()->GetWebProgress()->OnStatusChange(webProgress, channel, topWebProgress->OnStatusChange(webProgress, channel, aStatus,
aStatus, message.get()); message.get());
} }));
})); }
return NS_OK; return NS_OK;
} }

View File

@@ -94,8 +94,10 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
public nsIMultiPartChannelListener, public nsIMultiPartChannelListener,
public nsIProgressEventSink { public nsIProgressEventSink {
public: public:
// See the comment on GetLoadingBrowsingContext for explanation of
// aLoadingBrowsingContext.
explicit DocumentLoadListener( explicit DocumentLoadListener(
dom::CanonicalBrowsingContext* aBrowsingContext); dom::CanonicalBrowsingContext* aLoadingBrowsingContext);
struct OpenPromiseSucceededType { struct OpenPromiseSucceededType {
nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>> nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>
@@ -117,6 +119,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
true /* isExclusive */> true /* isExclusive */>
OpenPromise; OpenPromise;
private:
// Creates the channel, and then calls AsyncOpen on it. // Creates the channel, and then calls AsyncOpen on it.
// The DocumentLoadListener will require additional process from the consumer // The DocumentLoadListener will require additional process from the consumer
// in order to complete the redirect to the end channel. This is done by // in order to complete the redirect to the end channel. This is done by
@@ -125,14 +128,30 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// Once that promise is resolved; the consumer no longer needs to hold a // Once that promise is resolved; the consumer no longer needs to hold a
// reference to the DocumentLoadListener nor will the consumer required to be // reference to the DocumentLoadListener nor will the consumer required to be
// used again. // used again.
RefPtr<OpenPromise> Open(nsDocShellLoadState* aLoadState, uint32_t aCacheKey, RefPtr<OpenPromise> Open(nsDocShellLoadState* aLoadState, LoadInfo* aLoadInfo,
nsLoadFlags aLoadFlags, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const Maybe<uint64_t>& aChannelId,
const TimeStamp& aAsyncOpenTime, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, nsDOMNavigationTiming* aTiming,
Maybe<dom::ClientInfo>&& aInfo, Maybe<dom::ClientInfo>&& aInfo, bool aHasGesture,
uint64_t aOuterWindowId, bool aHasGesture, bool aUrgentStart, base::ProcessId aPid,
Maybe<bool> aUriModified, Maybe<bool> aIsXFOError, nsresult* aRv);
base::ProcessId aPid, nsresult* aRv);
public:
RefPtr<OpenPromise> OpenDocument(
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
uint64_t aOuterWindowId, bool aHasGesture, Maybe<bool> aUriModified,
Maybe<bool> aIsXFOError, base::ProcessId aPid, nsresult* aRv);
RefPtr<OpenPromise> OpenObject(
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
uint64_t aInnerWindowId, nsLoadFlags aLoadFlags,
nsContentPolicyType aContentPolicyType, bool aHasGesture,
bool aUrgentStart, base::ProcessId aPid, nsresult* aRv);
// Creates a DocumentLoadListener entirely in the parent process and opens it, // Creates a DocumentLoadListener entirely in the parent process and opens it,
// and never needs a DocumentChannel to connect to an existing docshell. // and never needs a DocumentChannel to connect to an existing docshell.
@@ -237,8 +256,6 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
dom::ContentParent* aParent) const; dom::ContentParent* aParent) const;
uint64_t GetLoadIdentifier() const { return mLoadIdentifier; } uint64_t GetLoadIdentifier() const { return mLoadIdentifier; }
dom::CanonicalBrowsingContext* GetBrowsingContext() const;
uint32_t GetLoadType() const { return mLoadStateLoadType; } uint32_t GetLoadType() const { return mLoadStateLoadType; }
protected: protected:
@@ -298,7 +315,18 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// Construct a LoadInfo object to use for the internal channel. // Construct a LoadInfo object to use for the internal channel.
already_AddRefed<LoadInfo> CreateLoadInfo( already_AddRefed<LoadInfo> CreateLoadInfo(
dom::CanonicalBrowsingContext* aBrowsingContext, dom::CanonicalBrowsingContext* aBrowsingContext,
nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId); nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId,
uint64_t aInnerWindowId, nsContentPolicyType aContentPolicyType);
// Return the Browsing Context that is performing the load.
// For document loads, the BC is the one that the (sub)doc
// will load into. For <object>/<embed>, it's the embedder document's BC.
dom::CanonicalBrowsingContext* GetLoadingBrowsingContext() const;
// Return the Browsing Context that document is being loaded into. For
// non-document loads, this will return nullptr.
dom::CanonicalBrowsingContext* GetDocumentBrowsingContext() const;
dom::CanonicalBrowsingContext* GetTopBrowsingContext() const;
void AddURIVisit(nsIChannel* aChannel, uint32_t aLoadFlags); void AddURIVisit(nsIChannel* aChannel, uint32_t aLoadFlags);
bool HasCrossOriginOpenerPolicyMismatch() const; bool HasCrossOriginOpenerPolicyMismatch() const;
@@ -314,6 +342,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// Returns false if the docshell will ignore the load entirely. // Returns false if the docshell will ignore the load entirely.
bool DocShellWillDisplayContent(nsresult aStatus); bool DocShellWillDisplayContent(nsresult aStatus);
void FireStateChange(uint32_t aStateFlags, nsresult aStatus);
// Returns true if this is a failed load, where we have successfully // Returns true if this is a failed load, where we have successfully
// created a fixed URI to attempt loading instead. // created a fixed URI to attempt loading instead.
// If successful, this calls DisconnectListeners to completely finish // If successful, this calls DisconnectListeners to completely finish
@@ -441,6 +471,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
mozilla::UniquePtr<mozilla::dom::SessionHistoryInfo> mSessionHistoryInfo; mozilla::UniquePtr<mozilla::dom::SessionHistoryInfo> mSessionHistoryInfo;
nsContentPolicyType mExternalContentPolicyType;
// Flags from nsDocShellLoadState::LoadFlags/Type that we want to make // Flags from nsDocShellLoadState::LoadFlags/Type that we want to make
// available to the new docshell if we switch processes. // available to the new docshell if we switch processes.
uint32_t mLoadStateLoadFlags = 0; uint32_t mLoadStateLoadFlags = 0;

View File

@@ -437,18 +437,33 @@ struct CookieStruct
uint8_t schemeMap; uint8_t schemeMap;
}; };
struct DocumentCreationArgs {
uint64_t outerWindowId;
bool uriModified;
bool isXFOError;
};
struct ObjectCreationArgs {
uint64_t embedderInnerWindowId;
uint32_t loadFlags;
uint8_t contentPolicyType;
bool isUrgentStart;
};
union DocumentChannelElementCreationArgs {
DocumentCreationArgs;
ObjectCreationArgs;
};
struct DocumentChannelCreationArgs { struct DocumentChannelCreationArgs {
DocShellLoadStateInit loadState; DocShellLoadStateInit loadState;
TimeStamp asyncOpenTime; TimeStamp asyncOpenTime;
uint64_t channelId; uint64_t channelId;
uint32_t cacheKey; uint32_t cacheKey;
bool pluginsAllowed;
nsDOMNavigationTiming? timing; nsDOMNavigationTiming? timing;
IPCClientInfo? initialClientInfo; IPCClientInfo? initialClientInfo;
uint64_t outerWindowId;
bool hasValidTransientUserAction; bool hasValidTransientUserAction;
bool uriModified; DocumentChannelElementCreationArgs elementCreationArgs;
bool isXFOError;
}; };
struct RedirectToRealChannelArgs { struct RedirectToRealChannelArgs {

View File

@@ -129,8 +129,10 @@ ParentProcessDocumentChannel::OnRedirectVerifyCallback(nsresult aResult) {
NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen( NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
nsIStreamListener* aListener) { nsIStreamListener* aListener) {
LOG(("ParentProcessDocumentChannel AsyncOpen [this=%p]", this)); LOG(("ParentProcessDocumentChannel AsyncOpen [this=%p]", this));
mDocumentLoadListener = new DocumentLoadListener( auto docShell = RefPtr<nsDocShell>(GetDocShell());
GetDocShell()->GetBrowsingContext()->Canonical()); MOZ_ASSERT(docShell);
mDocumentLoadListener = MakeRefPtr<DocumentLoadListener>(
docShell->GetBrowsingContext()->Canonical());
LOG(("Created PPDocumentChannel with listener=%p", LOG(("Created PPDocumentChannel with listener=%p",
mDocumentLoadListener.get())); mDocumentLoadListener.get()));
@@ -144,18 +146,47 @@ NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
gHttpHandler->OnOpeningDocumentRequest(this); gHttpHandler->OnOpeningDocumentRequest(this);
GetDocShell()->GetBrowsingContext()->SetCurrentLoadIdentifier( switch (mLoadInfo->GetExternalContentPolicyType()) {
Some(mLoadState->GetLoadIdentifier())); case nsIContentPolicy::TYPE_DOCUMENT:
case nsIContentPolicy::TYPE_SUBDOCUMENT:
GetDocShell()->GetBrowsingContext()->SetCurrentLoadIdentifier(
Some(mLoadState->GetLoadIdentifier()));
break;
default:
break;
}
nsresult rv = NS_OK; nsresult rv = NS_OK;
Maybe<dom::ClientInfo> initialClientInfo = mInitialClientInfo; Maybe<dom::ClientInfo> initialClientInfo = mInitialClientInfo;
auto promise = mDocumentLoadListener->Open(
mLoadState, mCacheKey, Some(mChannelId), mAsyncOpenTime, mTiming, const bool hasValidTransientUserGestureActivation =
std::move(initialClientInfo), GetDocShell()->GetOuterWindowID(), docShell->GetBrowsingContext()->HasValidTransientUserGestureActivation();
GetDocShell()
->GetBrowsingContext() RefPtr<DocumentLoadListener::OpenPromise> promise;
->HasValidTransientUserGestureActivation(), switch (mLoadInfo->GetExternalContentPolicyType()) {
Some(mUriModified), Some(mIsXFOError), 0 /* ProcessId */, &rv); case nsIContentPolicy::TYPE_DOCUMENT:
case nsIContentPolicy::TYPE_SUBDOCUMENT:
promise = mDocumentLoadListener->OpenDocument(
mLoadState, mCacheKey, Some(mChannelId), mAsyncOpenTime, mTiming,
std::move(initialClientInfo), docShell->GetOuterWindowID(),
hasValidTransientUserGestureActivation, Some(mUriModified),
Some(mIsXFOError), 0 /* ProcessId */, &rv);
break;
case nsIContentPolicy::TYPE_OBJECT:
promise = mDocumentLoadListener->OpenObject(
mLoadState, mCacheKey, Some(mChannelId), mAsyncOpenTime, mTiming,
std::move(initialClientInfo), InnerWindowIDForExtantDoc(docShell),
mLoadFlags, mLoadInfo->InternalContentPolicyType(),
hasValidTransientUserGestureActivation,
UserActivation::IsHandlingUserInput(), 0 /* ProcessId */, &rv);
break;
default:
MOZ_CRASH("Unhandled content policy type.");
}
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
MOZ_ASSERT(!promise); MOZ_ASSERT(!promise);
mDocumentLoadListener = nullptr; mDocumentLoadListener = nullptr;