Bug 1471711 - Extract targeting from nsDocShell::InternalLoad; r=bzbarsky

Move targeting logic out of InternalLoad into its own method.

Differential Revision: https://phabricator.services.mozilla.com/D17015

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Kyle Machulis 2019-02-08 21:10:54 +00:00
Родитель 9b822034f6
Коммит 4257b88ad6
2 изменённых файлов: 311 добавлений и 301 удалений

Просмотреть файл

@ -8542,130 +8542,102 @@ bool nsDocShell::JustStartedNetworkLoad() {
return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
}
nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
nsresult nsDocShell::MaybeHandleLoadDelegate(nsDocShellLoadState* aLoadState,
uint32_t aWindowType,
bool* aDidHandleLoad) {
MOZ_ASSERT(aLoadState);
MOZ_ASSERT(aDidHandleLoad);
MOZ_ASSERT(aWindowType == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
aWindowType == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW);
*aDidHandleLoad = false;
// If we don't have a delegate or we're trying to load the error page, we
// shouldn't be trying to do sandbox loads.
if (!mLoadURIDelegate || aLoadState->LoadType() == LOAD_ERROR_PAGE) {
return NS_OK;
}
// Dispatch only load requests for the current or a new window to the
// delegate, e.g., to allow for GeckoView apps to handle the load event
// outside of Gecko.
Document* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
const bool isDocumentAuxSandboxed =
doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
if (aWindowType == nsIBrowserDOMWindow::OPEN_NEWWINDOW &&
isDocumentAuxSandboxed) {
// At this point, the load is invalid, and we can consider "handled", so
// we'll exit from InternalLoad.
*aDidHandleLoad = true;
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
return mLoadURIDelegate->LoadURI(
aLoadState->URI(), aWindowType, aLoadState->LoadFlags(),
aLoadState->TriggeringPrincipal(), aDidHandleLoad);
}
// The contentType will be INTERNAL_(I)FRAME if this docshell is for a
// non-toplevel browsing context in spec terms. (frame, iframe, <object>,
// <embed>, etc)
//
// This return value will be used when we call NS_CheckContentLoadPolicy, and
// later when we call DoURILoad.
uint32_t nsDocShell::DetermineContentType() {
if (!IsFrame()) {
return nsIContentPolicy::TYPE_DOCUMENT;
}
nsCOMPtr<Element> requestingElement =
mScriptGlobal->AsOuter()->GetFrameElementInternal();
if (requestingElement) {
return requestingElement->IsHTMLElement(nsGkAtoms::iframe)
? nsIContentPolicy::TYPE_INTERNAL_IFRAME
: nsIContentPolicy::TYPE_INTERNAL_FRAME;
}
// If we have lost our frame element by now, just assume we're
// an iframe since that's more common.
return nsIContentPolicy::TYPE_INTERNAL_IFRAME;
}
nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
MOZ_ASSERT(aLoadState, "need a load state!");
MOZ_ASSERT(aLoadState->TriggeringPrincipal(),
"need a valid TriggeringPrincipal");
MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!");
if (mUseStrictSecurityChecks && !aLoadState->TriggeringPrincipal()) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
mOriginalUriString.Truncate();
MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
("DOCSHELL %p InternalLoad %s\n", this,
aLoadState->URI()->GetSpecOrDefault().get()));
// Initialize aDocShell/aRequest
if (aDocShell) {
*aDocShell = nullptr;
}
if (aRequest) {
*aRequest = nullptr;
}
NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
rv = EnsureScriptEnvironment();
if (NS_FAILED(rv)) {
return rv;
}
// wyciwyg urls can only be loaded through history. Any normal load of
// wyciwyg through docshell is illegal. Disallow such loads.
if ((aLoadState->LoadType() & LOAD_CMD_NORMAL) &&
SchemeIsWYCIWYG(aLoadState->URI())) {
return NS_ERROR_FAILURE;
}
bool isJavaScript = SchemeIsJavascript(aLoadState->URI());
bool isTargetTopLevelDocShell = false;
nsresult rv;
nsCOMPtr<nsIDocShell> targetDocShell;
if (!aLoadState->Target().IsEmpty()) {
// Locate the target DocShell.
nsCOMPtr<nsIDocShellTreeItem> targetItem;
// Only _self, _parent, and _top are supported in noopener case. But we
// have to be careful to not apply that to the noreferrer case. See bug
// 1358469.
bool allowNamedTarget =
!aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
if (allowNamedTarget ||
aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
rv = FindItemWithName(aLoadState->Target(), nullptr, this, false,
getter_AddRefs(targetItem));
NS_ENSURE_SUCCESS(rv, rv);
}
targetDocShell = do_QueryInterface(targetItem);
if (targetDocShell) {
// If the targetDocShell and the rootDocShell are the same, then the
// targetDocShell is the top level document and hence we should
// consider this TYPE_DOCUMENT
//
// For example:
// 1. target="_top"
// 2. target="_parent", where this docshell is in the 2nd level of
// docshell tree.
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
NS_ASSERTION(sameTypeRoot,
"No document shell root tree item from targetDocShell!");
nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
NS_ASSERTION(rootShell,
"No root docshell from document shell root tree item.");
isTargetTopLevelDocShell = targetDocShell == rootShell;
} else {
// If the targetDocShell doesn't exist, then this is a new docShell
// and we should consider this a TYPE_DOCUMENT load
//
// For example, when target="_blank"
isTargetTopLevelDocShell = true;
}
// Locate the target DocShell.
nsCOMPtr<nsIDocShellTreeItem> targetItem;
// Only _self, _parent, and _top are supported in noopener case. But we
// have to be careful to not apply that to the noreferrer case. See bug
// 1358469.
bool allowNamedTarget =
!aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
if (allowNamedTarget ||
aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
rv = FindItemWithName(aLoadState->Target(), nullptr, this, false,
getter_AddRefs(targetItem));
NS_ENSURE_SUCCESS(rv, rv);
}
// The contentType will be INTERNAL_(I)FRAME if:
// 1. This docshell is for iframe.
// 2. AND aLoadState->Target() is not a new window, nor a top-level window.
//
// This variable will be used when we call NS_CheckContentLoadPolicy, and
// later when we call DoURILoad.
uint32_t contentType;
if (IsFrame() && !isTargetTopLevelDocShell) {
nsCOMPtr<Element> requestingElement =
mScriptGlobal->AsOuter()->GetFrameElementInternal();
if (requestingElement) {
contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe)
? nsIContentPolicy::TYPE_INTERNAL_IFRAME
: nsIContentPolicy::TYPE_INTERNAL_FRAME;
} else {
// If we have lost our frame element by now, just assume we're
// an iframe since that's more common.
contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
}
} else {
contentType = nsIContentPolicy::TYPE_DOCUMENT;
isTargetTopLevelDocShell = true;
}
// If there's no targetDocShell, that means we are about to create a new
// window (or aLoadState->Target() is empty). Perform a content policy check
// before creating the window. Please note for all other docshell loads
// content policy checks are performed within the contentSecurityManager when
// the channel is about to be openend.
if (!targetDocShell && !aLoadState->Target().IsEmpty()) {
MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
"opening a new window requires type to be TYPE_DOCUMENT");
targetDocShell = do_QueryInterface(targetItem);
if (!targetDocShell) {
// If the targetDocShell doesn't exist, then this is a new docShell
// and we should consider this a TYPE_DOCUMENT load
//
// For example, when target="_blank"
// If there's no targetDocShell, that means we are about to create a new
// window. Perform a content policy check before creating the window. Please
// note for all other docshell loads content policy checks are performed
// within the contentSecurityManager when the channel is about to be
// openend.
nsISupports* requestingContext = nullptr;
if (XRE_IsContentProcess()) {
// In e10s the child process doesn't have access to the element that
@ -8707,31 +8679,17 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
}
}
Document* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
const bool isDocumentAuxSandboxed =
doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
if (mLoadURIDelegate && aLoadState->LoadType() != LOAD_ERROR_PAGE &&
(!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
// Dispatch only load requests for the current or a new window to the
// delegate, e.g., to allow for GeckoView apps to handle the load event
// outside of Gecko.
const int where = (aLoadState->Target().IsEmpty() || targetDocShell)
? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
: nsIBrowserDOMWindow::OPEN_NEWWINDOW;
if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW &&
isDocumentAuxSandboxed) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
if ((!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
bool handled;
rv = MaybeHandleLoadDelegate(aLoadState,
targetDocShell ?
nsIBrowserDOMWindow::OPEN_CURRENTWINDOW :
nsIBrowserDOMWindow::OPEN_NEWWINDOW,
&handled);
if (NS_FAILED(rv)) {
return rv;
}
bool loadURIHandled = false;
rv = mLoadURIDelegate->LoadURI(
aLoadState->URI(), where, aLoadState->LoadFlags(),
aLoadState->TriggeringPrincipal(), &loadURIHandled);
if (NS_SUCCEEDED(rv) && loadURIHandled) {
// The request has been handled, nothing to do here.
if (handled) {
return NS_OK;
}
}
@ -8741,179 +8699,211 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
// If the load has been targeted to another DocShell, then transfer the
// load to it...
//
if (!aLoadState->Target().IsEmpty()) {
// We've already done our owner-inheriting. Mask out that bit, so we
// don't try inheriting an owner from the target window if we came up
// with a null owner above.
aLoadState->UnsetLoadFlag(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
bool isNewWindow = false;
if (!targetDocShell) {
// If the docshell's document is sandboxed, only open a new window
// if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
// (i.e. if allow-popups is specified)
NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
if (isDocumentAuxSandboxed) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
// We've already done our owner-inheriting. Mask out that bit, so we
// don't try inheriting an owner from the target window if we came up
// with a null owner above.
aLoadState->UnsetLoadFlag(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
if (!targetDocShell) {
// If the docshell's document is sandboxed, only open a new window
// if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
// (i.e. if allow-popups is specified)
NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
Document* doc = mContentViewer->GetDocument();
nsCOMPtr<nsPIDOMWindowOuter> newWin;
nsAutoCString spec;
aLoadState->URI()->GetSpec(spec);
const bool isDocumentAuxSandboxed =
doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
// If we are a noopener load, we just hand the whole thing over to our
// window.
if (aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER)) {
// Various asserts that we know to hold because NO_OPENER loads can only
// happen for links.
MOZ_ASSERT(!aLoadState->LoadReplace());
MOZ_ASSERT(aLoadState->PrincipalToInherit() ==
aLoadState->TriggeringPrincipal());
MOZ_ASSERT((aLoadState->LoadFlags() &
~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
INTERNAL_LOAD_FLAGS_NO_OPENER ||
(aLoadState->LoadFlags() &
~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
(INTERNAL_LOAD_FLAGS_NO_OPENER |
INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
MOZ_ASSERT(!aLoadState->PostDataStream());
MOZ_ASSERT(!aLoadState->HeadersStream());
// If OnLinkClickSync was invoked inside the onload handler, the load
// type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
// LOAD_LINK.
MOZ_ASSERT(aLoadState->LoadType() == LOAD_LINK ||
aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
MOZ_ASSERT(!aLoadState->SHEntry());
MOZ_ASSERT(
aLoadState->FirstParty()); // Windowwatcher will assume this.
RefPtr<nsDocShellLoadState> loadState =
new nsDocShellLoadState(aLoadState->URI());
// Set up our loadinfo so it will do the load as much like we would have
// as possible.
loadState->SetReferrer(aLoadState->Referrer());
loadState->SetReferrerPolicy(
(mozilla::net::ReferrerPolicy)aLoadState->ReferrerPolicy());
loadState->SetSendReferrer(!(
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)));
loadState->SetOriginalURI(aLoadState->OriginalURI());
Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
loadState->SetMaybeResultPrincipalURI(resultPrincipalURI);
loadState->SetKeepResultPrincipalURIIfSet(
aLoadState->KeepResultPrincipalURIIfSet());
// LoadReplace will always be false due to asserts above, skip setting
// it.
loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
loadState->SetInheritPrincipal(
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
// Explicit principal because we do not want any guesses as to what the
// principal to inherit is: it should be aTriggeringPrincipal.
loadState->SetPrincipalIsExplicit(true);
loadState->SetLoadType(LOAD_LINK);
loadState->SetForceAllowDataURI(
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
rv = win->Open(NS_ConvertUTF8toUTF16(spec),
aLoadState->Target(), // window name
EmptyString(), // Features
loadState,
true, // aForceNoOpener
getter_AddRefs(newWin));
MOZ_ASSERT(!newWin);
return rv;
}
rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
aLoadState->Target(), // window name
EmptyString(), // Features
getter_AddRefs(newWin));
// In some cases the Open call doesn't actually result in a new
// window being opened. We can detect these cases by examining the
// document in |newWin|, if any.
nsCOMPtr<nsPIDOMWindowOuter> piNewWin = newWin;
if (piNewWin) {
RefPtr<Document> newDoc = piNewWin->GetExtantDoc();
if (!newDoc || newDoc->IsInitialDocument()) {
isNewWindow = true;
aLoadState->SetLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
}
}
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
targetDocShell = do_QueryInterface(webNav);
if (isDocumentAuxSandboxed) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
//
// Transfer the load to the target DocShell... Pass empty string as the
// window target name from to prevent recursive retargeting!
//
if (NS_SUCCEEDED(rv) && targetDocShell) {
nsDocShell* docShell = nsDocShell::Cast(targetDocShell);
// No window target
aLoadState->SetTarget(EmptyString());
// No forced download
aLoadState->SetFileName(VoidString());
rv = docShell->InternalLoad(aLoadState, aDocShell, aRequest);
nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
if (rv == NS_ERROR_NO_CONTENT) {
// XXXbz except we never reach this code!
if (isNewWindow) {
//
// At this point, a new window has been created, but the
// URI did not have any data associated with it...
//
// So, the best we can do, is to tear down the new window
// that was just created!
//
if (nsCOMPtr<nsPIDOMWindowOuter> domWin =
targetDocShell->GetWindow()) {
domWin->Close();
}
}
//
// NS_ERROR_NO_CONTENT should not be returned to the
// caller... This is an internal error code indicating that
// the URI had no data associated with it - probably a
// helper-app style protocol (ie. mailto://)
//
rv = NS_OK;
} else if (isNewWindow) {
// XXX: Once new windows are created hidden, the new
// window will need to be made visible... For now,
// do nothing.
}
nsCOMPtr<nsPIDOMWindowOuter> newWin;
nsAutoCString spec;
aLoadState->URI()->GetSpec(spec);
if (NS_SUCCEEDED(rv)) {
// Switch to target tab if we're currently focused window.
// Take loadDivertedInBackground into account so the behavior would be
// the same as how the tab first opened.
bool isTargetActive = false;
targetDocShell->GetIsActive(&isTargetActive);
nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
if (mIsActive && !isTargetActive && domWin &&
!Preferences::GetBool("browser.tabs.loadDivertedInBackground",
false)) {
if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) {
return NS_ERROR_FAILURE;
}
}
// If we are a noopener load, we just hand the whole thing over to our
// window.
if (aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER)) {
// Various asserts that we know to hold because NO_OPENER loads can only
// happen for links.
MOZ_ASSERT(!aLoadState->LoadReplace());
MOZ_ASSERT(aLoadState->PrincipalToInherit() ==
aLoadState->TriggeringPrincipal());
MOZ_ASSERT(
(aLoadState->LoadFlags() & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
INTERNAL_LOAD_FLAGS_NO_OPENER ||
(aLoadState->LoadFlags() & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
(INTERNAL_LOAD_FLAGS_NO_OPENER |
INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
MOZ_ASSERT(!aLoadState->PostDataStream());
MOZ_ASSERT(!aLoadState->HeadersStream());
// If OnLinkClickSync was invoked inside the onload handler, the load
// type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
// LOAD_LINK.
MOZ_ASSERT(aLoadState->LoadType() == LOAD_LINK ||
aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
MOZ_ASSERT(!aLoadState->SHEntry());
MOZ_ASSERT(aLoadState->FirstParty()); // Windowwatcher will assume this.
RefPtr<nsDocShellLoadState> loadState =
new nsDocShellLoadState(aLoadState->URI());
// Set up our loadinfo so it will do the load as much like we would have
// as possible.
loadState->SetReferrer(aLoadState->Referrer());
loadState->SetReferrerPolicy(
(mozilla::net::ReferrerPolicy)aLoadState->ReferrerPolicy());
loadState->SetSendReferrer(
!(aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)));
loadState->SetOriginalURI(aLoadState->OriginalURI());
Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
loadState->SetMaybeResultPrincipalURI(resultPrincipalURI);
loadState->SetKeepResultPrincipalURIIfSet(
aLoadState->KeepResultPrincipalURIIfSet());
// LoadReplace will always be false due to asserts above, skip setting
// it.
loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
loadState->SetInheritPrincipal(
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
// Explicit principal because we do not want any guesses as to what the
// principal to inherit is: it should be aTriggeringPrincipal.
loadState->SetPrincipalIsExplicit(true);
loadState->SetLoadType(LOAD_LINK);
loadState->SetForceAllowDataURI(
aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
rv = win->Open(NS_ConvertUTF8toUTF16(spec),
aLoadState->Target(), // window name
EmptyString(), // Features
loadState,
true, // aForceNoOpener
getter_AddRefs(newWin));
MOZ_ASSERT(!newWin);
return rv;
}
rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
aLoadState->Target(), // window name
EmptyString(), // Features
getter_AddRefs(newWin));
// In some cases the Open call doesn't actually result in a new
// window being opened. We can detect these cases by examining the
// document in |newWin|, if any.
nsCOMPtr<nsPIDOMWindowOuter> piNewWin = newWin;
if (piNewWin) {
RefPtr<Document> newDoc = piNewWin->GetExtantDoc();
if (!newDoc || newDoc->IsInitialDocument()) {
aLoadState->SetLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
}
}
// Else we ran out of memory, or were a popup and got blocked,
// or something.
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
targetDocShell = do_QueryInterface(webNav);
}
//
// Transfer the load to the target DocShell... Pass empty string as the
// window target name from to prevent recursive retargeting!
//
if (NS_SUCCEEDED(rv) && targetDocShell) {
nsDocShell* docShell = nsDocShell::Cast(targetDocShell);
// No window target
aLoadState->SetTarget(EmptyString());
// No forced download
aLoadState->SetFileName(VoidString());
rv = docShell->InternalLoad(aLoadState, aDocShell, aRequest);
if (NS_SUCCEEDED(rv)) {
// Switch to target tab if we're currently focused window.
// Take loadDivertedInBackground into account so the behavior would be
// the same as how the tab first opened.
bool isTargetActive = false;
targetDocShell->GetIsActive(&isTargetActive);
nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
if (mIsActive && !isTargetActive && domWin &&
!Preferences::GetBool("browser.tabs.loadDivertedInBackground",
false)) {
if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) {
return NS_ERROR_FAILURE;
}
}
}
}
// Else we ran out of memory, or were a popup and got blocked,
// or something.
return rv;
}
nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
MOZ_ASSERT(aLoadState, "need a load state!");
MOZ_ASSERT(aLoadState->TriggeringPrincipal(),
"need a valid TriggeringPrincipal");
if (mUseStrictSecurityChecks && !aLoadState->TriggeringPrincipal()) {
return NS_ERROR_FAILURE;
}
mOriginalUriString.Truncate();
MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
("DOCSHELL %p InternalLoad %s\n", this,
aLoadState->URI()->GetSpecOrDefault().get()));
// Initialize aDocShell/aRequest
if (aDocShell) {
*aDocShell = nullptr;
}
if (aRequest) {
*aRequest = nullptr;
}
NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
nsresult rv = EnsureScriptEnvironment();
if (NS_FAILED(rv)) {
return rv;
}
// wyciwyg urls can only be loaded through history. Any normal load of
// wyciwyg through docshell is illegal. Disallow such loads.
if ((aLoadState->LoadType() & LOAD_CMD_NORMAL) &&
SchemeIsWYCIWYG(aLoadState->URI())) {
return NS_ERROR_FAILURE;
}
// If we have a target to move to, do that now.
if (!aLoadState->Target().IsEmpty()) {
return PerformRetargeting(aLoadState, aDocShell, aRequest);
}
// If we don't have a target, we're loading into ourselves, and our load
// delegate may want to intercept that load.
bool handled;
rv = MaybeHandleLoadDelegate(
aLoadState, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW, &handled);
if (NS_FAILED(rv)) {
return rv;
}
if (handled) {
return NS_OK;
}
// If we are loading a URI that should inherit a security context (basically
// javascript: at this point), and the caller has said that principal
// inheritance is allowed, there are a few possible cases:
@ -9323,6 +9313,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
// XXXbz mTiming should know what channel it's for, so we don't
// need this hackery.
bool toBeReset = false;
bool isJavaScript = SchemeIsJavascript(aLoadState->URI());
if (!isJavaScript) {
toBeReset = MaybeInitTiming();
}
@ -9480,8 +9472,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
srcdoc = VoidString();
}
bool isTopLevelDoc = mItemType == typeContent &&
(isTargetTopLevelDocShell || GetIsMozBrowser());
bool isTopLevelDoc =
mItemType == typeContent && (!IsFrame() || GetIsMozBrowser());
OriginAttributes attrs = GetOriginAttributes();
attrs.SetFirstPartyDomain(isTopLevelDoc, aLoadState->URI());

Просмотреть файл

@ -885,6 +885,24 @@ class nsDocShell final : public nsDocLoader,
// function comments for in-depth logic descriptions.
void MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState);
// If we are passed a named target during InternalLoad, this method handles
// moving the load to the browsing context the target name resolves to.
nsresult PerformRetargeting(nsDocShellLoadState* aLoadState,
nsIDocShell** aDocShell, nsIRequest** aRequest);
// Returns one of nsIContentPolicy::TYPE_DOCUMENT,
// nsIContentPolicy::TYPE_INTERNAL_IFRAME, or
// nsIContentPolicy::TYPE_INTERNAL_FRAME depending on who is responsible for
// this docshell.
uint32_t DetermineContentType();
// In cases where we have a LoadURIDelegate (loading external links via
// GeckoView), a load may need to be handled through the delegate. aWindowType
// is either nsIBrowserDOMWindow::OPEN_CURRENTWINDOW or
// nsIBrowserDOMWindow::OPEN_NEWWINDOW.
nsresult MaybeHandleLoadDelegate(nsDocShellLoadState* aLoadState,
uint32_t aWindowType, bool* aDidHandleLoad);
private: // data members
static nsIURIFixup* sURIFixup;