|
|
|
@ -629,10 +629,10 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
nsAutoString name; // string version of aName
|
|
|
|
|
nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner>
|
|
|
|
|
parentTreeOwner; // from the parent window, if any
|
|
|
|
|
RefPtr<BrowsingContext> targetBC; // from the new window
|
|
|
|
|
parentTreeOwner; // from the parent window, if any
|
|
|
|
|
RefPtr<BrowsingContext> newBC; // from the new window
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> parentOuterWin =
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
|
|
|
|
|
aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
|
|
|
|
|
|
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
@ -643,8 +643,8 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parentOuterWin) {
|
|
|
|
|
parentTreeOwner = parentOuterWin->GetTreeOwner();
|
|
|
|
|
if (parentWindow) {
|
|
|
|
|
parentTreeOwner = parentWindow->GetTreeOwner();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We expect BrowserParent to have provided us the absolute URI of the window
|
|
|
|
@ -676,13 +676,9 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<BrowsingContext> parentBC(
|
|
|
|
|
parentOuterWin ? parentOuterWin->GetBrowsingContext() : nullptr);
|
|
|
|
|
parentWindow ? parentWindow->GetBrowsingContext() : nullptr);
|
|
|
|
|
nsCOMPtr<nsIDocShell> parentDocShell(parentBC ? parentBC->GetDocShell()
|
|
|
|
|
: nullptr);
|
|
|
|
|
RefPtr<Document> parentDoc(parentOuterWin ? parentOuterWin->GetDoc()
|
|
|
|
|
: nullptr);
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> parentInnerWin(
|
|
|
|
|
parentOuterWin ? parentOuterWin->GetCurrentInnerWindow() : nullptr);
|
|
|
|
|
|
|
|
|
|
// Return null for any attempt to trigger a load from a discarded browsing
|
|
|
|
|
// context. The spec is non-normative, and doesn't specify what should happen
|
|
|
|
@ -698,18 +694,18 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try to find an extant browsing context with the given name
|
|
|
|
|
targetBC = GetBrowsingContextByName(name, aForceNoOpener, parentBC);
|
|
|
|
|
newBC = GetBrowsingContextByName(name, aForceNoOpener, parentBC);
|
|
|
|
|
|
|
|
|
|
// Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI.
|
|
|
|
|
// The state of the window can change before this call and if we are blocked
|
|
|
|
|
// because of sandboxing, we wouldn't want that to happen.
|
|
|
|
|
if (parentBC && parentBC->IsSandboxedFrom(targetBC)) {
|
|
|
|
|
if (parentBC && parentBC->IsSandboxedFrom(newBC)) {
|
|
|
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If our target BrowsingContext is still pending initialization, ignore the
|
|
|
|
|
// navigation request targeting it.
|
|
|
|
|
if (targetBC && NS_WARN_IF(targetBC->GetPendingInitialization())) {
|
|
|
|
|
if (newBC && NS_WARN_IF(newBC->GetPendingInitialization())) {
|
|
|
|
|
return NS_ERROR_ABORT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -719,7 +715,8 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
bool hasChromeParent = !XRE_IsContentProcess();
|
|
|
|
|
if (aParent) {
|
|
|
|
|
// Check if the parent document has chrome privileges.
|
|
|
|
|
hasChromeParent = parentDoc && nsContentUtils::IsChromeDoc(parentDoc);
|
|
|
|
|
Document* doc = parentWindow->GetDoc();
|
|
|
|
|
hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
|
|
|
|
@ -811,56 +808,10 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that the jsapiChromeGuard has been set, fetch the system principal
|
|
|
|
|
// potentially configured by it. We want to make sure to respect any principal
|
|
|
|
|
// changes imposed by that guard throughout this function.
|
|
|
|
|
//
|
|
|
|
|
// Note: The check for the current JSContext isn't necessarily sensical.
|
|
|
|
|
// It's just designed to preserve old semantics during a mass-conversion
|
|
|
|
|
// patch.
|
|
|
|
|
// Bug 1498605 verify usages of systemPrincipal here
|
|
|
|
|
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
|
|
|
|
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
|
|
|
|
cx ? nsContentUtils::SubjectPrincipal()
|
|
|
|
|
: nsContentUtils::GetSystemPrincipal();
|
|
|
|
|
MOZ_ASSERT(subjectPrincipal);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrincipal> newWindowPrincipal;
|
|
|
|
|
if (!targetBC) {
|
|
|
|
|
if (windowTypeIsChrome) {
|
|
|
|
|
// If we are creating a chrome window, we must be called with a system
|
|
|
|
|
// principal, and should inherit that for the new chrome window.
|
|
|
|
|
MOZ_RELEASE_ASSERT(subjectPrincipal->IsSystemPrincipal(),
|
|
|
|
|
"Only system principals can create chrome windows");
|
|
|
|
|
newWindowPrincipal = subjectPrincipal;
|
|
|
|
|
} else if (nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal)) {
|
|
|
|
|
// Don't allow initial about:blank documents to inherit a system or
|
|
|
|
|
// expanded principal, instead replace it with a null principal. We can't
|
|
|
|
|
// inherit origin attributes from the system principal, so use the parent
|
|
|
|
|
// BC if it's available.
|
|
|
|
|
if (parentBC) {
|
|
|
|
|
newWindowPrincipal = NullPrincipal::CreateWithInheritedAttributes(
|
|
|
|
|
parentBC->OriginAttributesRef());
|
|
|
|
|
} else {
|
|
|
|
|
newWindowPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
|
|
|
|
|
}
|
|
|
|
|
} else if (aForceNoOpener) {
|
|
|
|
|
// If we're opening a new window with noopener, create a new opaque
|
|
|
|
|
// principal for the new window, rather than re-using the existing
|
|
|
|
|
// principal.
|
|
|
|
|
newWindowPrincipal =
|
|
|
|
|
NullPrincipal::CreateWithInheritedAttributes(subjectPrincipal);
|
|
|
|
|
} else {
|
|
|
|
|
// Finally, if there's an opener relationship and it's not a special
|
|
|
|
|
// principal, we should inherit that principal for the new window.
|
|
|
|
|
newWindowPrincipal = subjectPrincipal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Information used when opening new content windows. This object will be
|
|
|
|
|
// passed through to the inner nsFrameLoader.
|
|
|
|
|
RefPtr<nsOpenWindowInfo> openWindowInfo;
|
|
|
|
|
if (!targetBC && !windowTypeIsChrome) {
|
|
|
|
|
if (!newBC && !windowTypeIsChrome) {
|
|
|
|
|
openWindowInfo = new nsOpenWindowInfo();
|
|
|
|
|
openWindowInfo->mForceNoOpener = aForceNoOpener;
|
|
|
|
|
openWindowInfo->mParent = parentBC;
|
|
|
|
@ -871,12 +822,17 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
// want it to match the current remoteness.
|
|
|
|
|
openWindowInfo->mIsRemote = XRE_IsContentProcess();
|
|
|
|
|
|
|
|
|
|
// Inherit our OriginAttributes from the computed new window principal.
|
|
|
|
|
MOZ_ASSERT(
|
|
|
|
|
newWindowPrincipal &&
|
|
|
|
|
!nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal));
|
|
|
|
|
openWindowInfo->mOriginAttributes =
|
|
|
|
|
newWindowPrincipal->OriginAttributesRef();
|
|
|
|
|
// If we have a non-system non-expanded subject principal, we can inherit
|
|
|
|
|
// our OriginAttributes from it.
|
|
|
|
|
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
|
|
|
|
nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
|
|
|
|
|
if (subjectPrincipal &&
|
|
|
|
|
!nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal)) {
|
|
|
|
|
openWindowInfo->mOriginAttributes =
|
|
|
|
|
subjectPrincipal->OriginAttributesRef();
|
|
|
|
|
} else if (parentBC) {
|
|
|
|
|
openWindowInfo->mOriginAttributes = parentBC->OriginAttributesRef();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
!parentBC || openWindowInfo->mOriginAttributes.EqualsIgnoringFPD(
|
|
|
|
@ -887,7 +843,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
uint32_t activeDocsSandboxFlags = 0;
|
|
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> cspToInheritForAboutBlank;
|
|
|
|
|
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> coepToInheritForAboutBlank;
|
|
|
|
|
if (!targetBC) {
|
|
|
|
|
if (!newBC) {
|
|
|
|
|
// We're going to either open up a new window ourselves or ask a
|
|
|
|
|
// nsIWindowProvider for one. In either case, we'll want to set the right
|
|
|
|
|
// name on it.
|
|
|
|
@ -895,20 +851,22 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
|
|
|
|
|
// If the parent trying to open a new window is sandboxed
|
|
|
|
|
// without 'allow-popups', this is not allowed and we fail here.
|
|
|
|
|
if (parentDoc) {
|
|
|
|
|
// Save sandbox flags for copying to new browsing context (docShell).
|
|
|
|
|
activeDocsSandboxFlags = parentDoc->GetSandboxFlags();
|
|
|
|
|
if (aParent) {
|
|
|
|
|
if (Document* doc = parentWindow->GetDoc()) {
|
|
|
|
|
// Save sandbox flags for copying to new browsing context (docShell).
|
|
|
|
|
activeDocsSandboxFlags = doc->GetSandboxFlags();
|
|
|
|
|
|
|
|
|
|
if (!aForceNoOpener) {
|
|
|
|
|
cspToInheritForAboutBlank = parentDoc->GetCsp();
|
|
|
|
|
coepToInheritForAboutBlank = parentDoc->GetEmbedderPolicy();
|
|
|
|
|
}
|
|
|
|
|
if (!aForceNoOpener) {
|
|
|
|
|
cspToInheritForAboutBlank = doc->GetCsp();
|
|
|
|
|
coepToInheritForAboutBlank = doc->GetEmbedderPolicy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check to see if this frame is allowed to navigate, but don't check if
|
|
|
|
|
// we're printing, as that's not a real navigation.
|
|
|
|
|
if (aPrintKind == PRINT_NONE &&
|
|
|
|
|
(activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION)) {
|
|
|
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
|
|
|
// Check to see if this frame is allowed to navigate, but don't check if
|
|
|
|
|
// we're printing, as that's not a real navigation.
|
|
|
|
|
if (aPrintKind == PRINT_NONE &&
|
|
|
|
|
(activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION)) {
|
|
|
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -926,17 +884,17 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
rv = provider->ProvideWindow(
|
|
|
|
|
openWindowInfo, chromeFlags, aCalledFromJS, uriToLoad, name,
|
|
|
|
|
featuresStr, aForceNoOpener, aForceNoReferrer, isPopupRequested,
|
|
|
|
|
aLoadState, &windowIsNew, getter_AddRefs(targetBC));
|
|
|
|
|
aLoadState, &windowIsNew, getter_AddRefs(newBC));
|
|
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && targetBC) {
|
|
|
|
|
nsCOMPtr<nsIDocShell> newDocShell = targetBC->GetDocShell();
|
|
|
|
|
if (NS_SUCCEEDED(rv) && newBC) {
|
|
|
|
|
nsCOMPtr<nsIDocShell> newDocShell = newBC->GetDocShell();
|
|
|
|
|
|
|
|
|
|
// If this is a new window, but it's incompatible with the current
|
|
|
|
|
// userContextId, we ignore it and we pretend that nothing has been
|
|
|
|
|
// returned by ProvideWindow.
|
|
|
|
|
if (!windowIsNew && newDocShell) {
|
|
|
|
|
if (!CheckUserContextCompatibility(newDocShell)) {
|
|
|
|
|
targetBC = nullptr;
|
|
|
|
|
newBC = nullptr;
|
|
|
|
|
windowIsNew = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -955,7 +913,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
|
|
|
|
|
bool newWindowShouldBeModal = false;
|
|
|
|
|
bool parentIsModal = false;
|
|
|
|
|
if (!targetBC) {
|
|
|
|
|
if (!newBC) {
|
|
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
|
// If our window provider failed to provide a window in the content
|
|
|
|
|
// process, we cannot recover. Reject the window open request and bail.
|
|
|
|
@ -1009,9 +967,9 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
nsCOMPtr<nsIWebBrowserChrome> newChrome;
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
|
|
|
|
|
if (parentOuterWin) {
|
|
|
|
|
if (parentWindow) {
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow =
|
|
|
|
|
parentOuterWin->GetInProcessTop();
|
|
|
|
|
parentWindow->GetInProcessTop();
|
|
|
|
|
if (parentTopWindow) {
|
|
|
|
|
parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
|
|
|
|
|
}
|
|
|
|
@ -1048,53 +1006,53 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
if (!newDocShellItem) {
|
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
targetBC = newDocShellItem->GetBrowsingContext();
|
|
|
|
|
newBC = newDocShellItem->GetBrowsingContext();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// better have a window to use by this point
|
|
|
|
|
if (!targetBC) {
|
|
|
|
|
if (!newBC) {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If our parent is sandboxed, set it as the one permitted sandboxed navigator
|
|
|
|
|
// on the new window we're opening.
|
|
|
|
|
if (activeDocsSandboxFlags && parentBC) {
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(targetBC->SetOnePermittedSandboxedNavigator(parentBC));
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(newBC->SetOnePermittedSandboxedNavigator(parentBC));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!aForceNoOpener && parentBC) {
|
|
|
|
|
// If we've created a new content window, its opener should have been set
|
|
|
|
|
// when its BrowsingContext was created, in order to ensure that the context
|
|
|
|
|
// is loaded within the correct BrowsingContextGroup.
|
|
|
|
|
if (windowIsNew && targetBC->IsContent()) {
|
|
|
|
|
if (windowIsNew && newBC->IsContent()) {
|
|
|
|
|
if (parentBC->IsDiscarded()) {
|
|
|
|
|
// If the parent BC was discarded in a nested event loop before we got
|
|
|
|
|
// to this point, we can't set it as the opener. Ideally we would still
|
|
|
|
|
// set `HadOriginalOpener()` in that case, but that's somewhat
|
|
|
|
|
// nontrivial, and not worth the effort given the nature of the corner
|
|
|
|
|
// case (see comment in `nsFrameLoader::CreateBrowsingContext`.
|
|
|
|
|
MOZ_RELEASE_ASSERT(targetBC->GetOpenerId() == parentBC->Id() ||
|
|
|
|
|
targetBC->GetOpenerId() == 0);
|
|
|
|
|
MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id() ||
|
|
|
|
|
newBC->GetOpenerId() == 0);
|
|
|
|
|
} else {
|
|
|
|
|
MOZ_RELEASE_ASSERT(targetBC->GetOpenerId() == parentBC->Id());
|
|
|
|
|
MOZ_RELEASE_ASSERT(targetBC->HadOriginalOpener());
|
|
|
|
|
MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id());
|
|
|
|
|
MOZ_RELEASE_ASSERT(newBC->HadOriginalOpener());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Update the opener for an existing or chrome BC.
|
|
|
|
|
targetBC->SetOpener(parentBC);
|
|
|
|
|
newBC->SetOpener(parentBC);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<nsDocShell> targetDocShell(nsDocShell::Cast(targetBC->GetDocShell()));
|
|
|
|
|
RefPtr<nsDocShell> newDocShell(nsDocShell::Cast(newBC->GetDocShell()));
|
|
|
|
|
|
|
|
|
|
// As required by spec, new windows always start out same-process, even if the
|
|
|
|
|
// URL being loaded will eventually load in a new process.
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!windowIsNew || targetDocShell);
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!windowIsNew || newDocShell);
|
|
|
|
|
// New top-level windows are only opened in the parent process and are, by
|
|
|
|
|
// definition, always in-process.
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!isNewToplevelWindow || targetDocShell);
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!isNewToplevelWindow || newDocShell);
|
|
|
|
|
|
|
|
|
|
// Copy sandbox flags to the new window if activeDocsSandboxFlags says to do
|
|
|
|
|
// so. Note that it's only nonzero if the window is new, so clobbering
|
|
|
|
@ -1102,46 +1060,45 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
if (activeDocsSandboxFlags &
|
|
|
|
|
SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) {
|
|
|
|
|
MOZ_ASSERT(windowIsNew, "Should only get here for new windows");
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(targetBC->SetSandboxFlags(activeDocsSandboxFlags));
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(newBC->SetSandboxFlags(activeDocsSandboxFlags));
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(
|
|
|
|
|
targetBC->SetInitialSandboxFlags(targetBC->GetSandboxFlags()));
|
|
|
|
|
newBC->SetInitialSandboxFlags(newBC->GetSandboxFlags()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<nsGlobalWindowOuter> targetOuterWin(
|
|
|
|
|
nsGlobalWindowOuter::Cast(targetBC->GetDOMWindow()));
|
|
|
|
|
RefPtr<nsGlobalWindowOuter> win(
|
|
|
|
|
nsGlobalWindowOuter::Cast(newBC->GetDOMWindow()));
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
if (targetOuterWin && windowIsNew) {
|
|
|
|
|
if (win && windowIsNew) {
|
|
|
|
|
// Assert that we're not loading things right now. If we are, when
|
|
|
|
|
// that load completes it will clobber whatever principals we set up
|
|
|
|
|
// on this new window!
|
|
|
|
|
nsCOMPtr<nsIChannel> chan;
|
|
|
|
|
targetDocShell->GetDocumentChannel(getter_AddRefs(chan));
|
|
|
|
|
newDocShell->GetDocumentChannel(getter_AddRefs(chan));
|
|
|
|
|
MOZ_ASSERT(!chan, "Why is there a document channel?");
|
|
|
|
|
|
|
|
|
|
if (RefPtr<Document> doc = targetOuterWin->GetExtantDoc()) {
|
|
|
|
|
if (RefPtr<Document> doc = win->GetExtantDoc()) {
|
|
|
|
|
MOZ_ASSERT(doc->IsInitialDocument(),
|
|
|
|
|
"New window's document should be an initial document");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(targetOuterWin || !windowIsNew,
|
|
|
|
|
"New windows are always created in-process");
|
|
|
|
|
MOZ_ASSERT(win || !windowIsNew, "New windows are always created in-process");
|
|
|
|
|
|
|
|
|
|
*aResult = do_AddRef(targetBC).take();
|
|
|
|
|
*aResult = do_AddRef(newBC).take();
|
|
|
|
|
|
|
|
|
|
if (isNewToplevelWindow) {
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
|
|
|
|
targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
MaybeDisablePersistence(sizeSpec, newTreeOwner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aDialog && aArgv) {
|
|
|
|
|
MOZ_ASSERT(targetOuterWin);
|
|
|
|
|
NS_ENSURE_TRUE(targetOuterWin, NS_ERROR_UNEXPECTED);
|
|
|
|
|
MOZ_ASSERT(win);
|
|
|
|
|
NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
|
|
// Set the args on the new window.
|
|
|
|
|
MOZ_TRY(targetOuterWin->SetArguments(aArgv));
|
|
|
|
|
MOZ_TRY(win->SetArguments(aArgv));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* allow a window that we found by name to keep its name (important for cases
|
|
|
|
@ -1149,40 +1106,52 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
is not a window name. */
|
|
|
|
|
if (windowNeedsName) {
|
|
|
|
|
if (nameSpecified && !name.LowerCaseEqualsLiteral("_blank")) {
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(targetBC->SetName(name));
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(newBC->SetName(name));
|
|
|
|
|
} else {
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(targetBC->SetName(u""_ns));
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(newBC->SetName(u""_ns));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now we have to set the right opener principal on the new window. Note
|
|
|
|
|
// that we have to do this _before_ starting any URI loads, thanks to the
|
|
|
|
|
// sync nature of javascript: loads.
|
|
|
|
|
//
|
|
|
|
|
// Note: The check for the current JSContext isn't necessarily sensical.
|
|
|
|
|
// It's just designed to preserve old semantics during a mass-conversion
|
|
|
|
|
// patch.
|
|
|
|
|
// Bug 1498605 verify usages of systemPrincipal here
|
|
|
|
|
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
|
|
|
|
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
|
|
|
|
cx ? nsContentUtils::SubjectPrincipal()
|
|
|
|
|
: nsContentUtils::GetSystemPrincipal();
|
|
|
|
|
|
|
|
|
|
if (windowIsNew) {
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
!targetBC->IsContent() ||
|
|
|
|
|
newWindowPrincipal->OriginAttributesRef().EqualsIgnoringFPD(
|
|
|
|
|
targetBC->OriginAttributesRef()));
|
|
|
|
|
if (subjectPrincipal &&
|
|
|
|
|
!nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal) &&
|
|
|
|
|
newBC->IsContent()) {
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
subjectPrincipal->OriginAttributesRef().EqualsIgnoringFPD(
|
|
|
|
|
newBC->OriginAttributesRef()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool autoPrivateBrowsing =
|
|
|
|
|
Preferences::GetBool("browser.privatebrowsing.autostart");
|
|
|
|
|
|
|
|
|
|
if (!autoPrivateBrowsing &&
|
|
|
|
|
(chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)) {
|
|
|
|
|
if (targetBC->IsChrome()) {
|
|
|
|
|
targetBC->SetUsePrivateBrowsing(false);
|
|
|
|
|
if (newBC->IsChrome()) {
|
|
|
|
|
newBC->SetUsePrivateBrowsing(false);
|
|
|
|
|
}
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
!targetBC->UsePrivateBrowsing(),
|
|
|
|
|
!newBC->UsePrivateBrowsing(),
|
|
|
|
|
"CHROME_NON_PRIVATE_WINDOW passed, but got private window");
|
|
|
|
|
} else if (autoPrivateBrowsing ||
|
|
|
|
|
(chromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
|
|
|
|
|
if (targetBC->IsChrome()) {
|
|
|
|
|
targetBC->SetUsePrivateBrowsing(true);
|
|
|
|
|
if (newBC->IsChrome()) {
|
|
|
|
|
newBC->SetUsePrivateBrowsing(true);
|
|
|
|
|
}
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
targetBC->UsePrivateBrowsing(),
|
|
|
|
|
newBC->UsePrivateBrowsing(),
|
|
|
|
|
"CHROME_PRIVATE_WINDOW passed, but got non-private window");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1191,47 +1160,26 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
// the JS stack, just use the principal of our parent window. In those
|
|
|
|
|
// cases we do _not_ set the parent window principal as the owner of the
|
|
|
|
|
// load--since we really don't know who the owner is, just leave it null.
|
|
|
|
|
NS_ASSERTION(targetOuterWin == targetDocShell->GetWindow(),
|
|
|
|
|
"Different windows??");
|
|
|
|
|
NS_ASSERTION(win == newDocShell->GetWindow(), "Different windows??");
|
|
|
|
|
|
|
|
|
|
// Initialize the principal of the initial about:blank document. For
|
|
|
|
|
// toplevel windows, this call may have already happened when the window was
|
|
|
|
|
// created, but SetInitialPrincipal is safe to call multiple times.
|
|
|
|
|
if (targetOuterWin) {
|
|
|
|
|
// The principal of the initial about:blank document gets set up in
|
|
|
|
|
// nsWindowWatcher::AddWindow. Make sure to call it. In the common case
|
|
|
|
|
// this call already happened when the window was created, but
|
|
|
|
|
// SetInitialPrincipalToSubject is safe to call multiple times.
|
|
|
|
|
if (win) {
|
|
|
|
|
MOZ_ASSERT(windowIsNew);
|
|
|
|
|
MOZ_ASSERT(!targetOuterWin->GetSameProcessOpener() ||
|
|
|
|
|
targetOuterWin->GetSameProcessOpener() == aParent);
|
|
|
|
|
targetOuterWin->SetInitialPrincipal(newWindowPrincipal,
|
|
|
|
|
cspToInheritForAboutBlank,
|
|
|
|
|
coepToInheritForAboutBlank);
|
|
|
|
|
MOZ_ASSERT(!win->GetSameProcessOpener() ||
|
|
|
|
|
win->GetSameProcessOpener() == aParent);
|
|
|
|
|
win->SetInitialPrincipalToSubject(cspToInheritForAboutBlank,
|
|
|
|
|
coepToInheritForAboutBlank);
|
|
|
|
|
|
|
|
|
|
if (aIsPopupSpam) {
|
|
|
|
|
MOZ_ASSERT(!targetBC->GetIsPopupSpam(),
|
|
|
|
|
MOZ_ASSERT(!newBC->GetIsPopupSpam(),
|
|
|
|
|
"Who marked it as popup spam already???");
|
|
|
|
|
// Make sure we don't mess up our counter even if the above assert
|
|
|
|
|
// fails.
|
|
|
|
|
if (!targetBC->GetIsPopupSpam()) {
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(targetBC->SetIsPopupSpam(true));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy the current session storage for the current domain. Don't perform
|
|
|
|
|
// the copy if we're forcing noopener, however.
|
|
|
|
|
if (!aForceNoOpener && subjectPrincipal && parentDocShell &&
|
|
|
|
|
targetDocShell) {
|
|
|
|
|
const RefPtr<SessionStorageManager> parentStorageManager =
|
|
|
|
|
parentDocShell->GetBrowsingContext()->GetSessionStorageManager();
|
|
|
|
|
const RefPtr<SessionStorageManager> newStorageManager =
|
|
|
|
|
targetDocShell->GetBrowsingContext()->GetSessionStorageManager();
|
|
|
|
|
|
|
|
|
|
if (parentStorageManager && newStorageManager) {
|
|
|
|
|
RefPtr<Storage> storage;
|
|
|
|
|
parentStorageManager->GetStorage(
|
|
|
|
|
parentInnerWin, subjectPrincipal, subjectPrincipal,
|
|
|
|
|
targetBC->UsePrivateBrowsing(), getter_AddRefs(storage));
|
|
|
|
|
if (storage) {
|
|
|
|
|
newStorageManager->CloneStorage(storage);
|
|
|
|
|
if (!newBC->GetIsPopupSpam()) {
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(newBC->SetIsPopupSpam(true));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1240,12 +1188,15 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
// We rely on CalculateChromeFlags to decide whether remote (out-of-process)
|
|
|
|
|
// tabs should be used.
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
targetBC->UseRemoteTabs() ==
|
|
|
|
|
newBC->UseRemoteTabs() ==
|
|
|
|
|
!!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
|
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
|
targetBC->UseRemoteSubframes() ==
|
|
|
|
|
newBC->UseRemoteSubframes() ==
|
|
|
|
|
!!(chromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW));
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> pInnerWin =
|
|
|
|
|
parentWindow ? parentWindow->GetCurrentInnerWindow() : nullptr;
|
|
|
|
|
;
|
|
|
|
|
RefPtr<nsDocShellLoadState> loadState = aLoadState;
|
|
|
|
|
if (uriToLoad && loadState) {
|
|
|
|
|
// If a URI was passed to this function, open that, not what was passed in
|
|
|
|
@ -1253,7 +1204,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
loadState->SetURI(uriToLoad);
|
|
|
|
|
} else if (uriToLoad && aNavigate && !loadState) {
|
|
|
|
|
RefPtr<WindowContext> context =
|
|
|
|
|
parentInnerWin ? parentInnerWin->GetWindowContext() : nullptr;
|
|
|
|
|
pInnerWin ? pInnerWin->GetWindowContext() : nullptr;
|
|
|
|
|
loadState = new nsDocShellLoadState(uriToLoad);
|
|
|
|
|
|
|
|
|
|
loadState->SetSourceBrowsingContext(parentBC);
|
|
|
|
@ -1280,8 +1231,8 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
screw up focus in the hidden window; see bug 36016.
|
|
|
|
|
*/
|
|
|
|
|
RefPtr<Document> doc = GetEntryDocument();
|
|
|
|
|
if (!doc) {
|
|
|
|
|
doc = parentDoc;
|
|
|
|
|
if (!doc && parentWindow) {
|
|
|
|
|
doc = parentWindow->GetExtantDoc();
|
|
|
|
|
}
|
|
|
|
|
if (doc) {
|
|
|
|
|
auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
|
|
|
|
@ -1304,14 +1255,14 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
|
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
|
if (obsSvc) {
|
|
|
|
|
obsSvc->NotifyObservers(ToSupports(targetOuterWin),
|
|
|
|
|
"toplevel-window-ready", nullptr);
|
|
|
|
|
obsSvc->NotifyObservers(ToSupports(win), "toplevel-window-ready",
|
|
|
|
|
nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Before loading the URI we want to be 100% sure that we use the correct
|
|
|
|
|
// userContextId.
|
|
|
|
|
MOZ_ASSERT_IF(targetDocShell, CheckUserContextCompatibility(targetDocShell));
|
|
|
|
|
MOZ_ASSERT_IF(newDocShell, CheckUserContextCompatibility(newDocShell));
|
|
|
|
|
|
|
|
|
|
// If this tab or window has been opened by a window.open call, we have to
|
|
|
|
|
// provide all the data needed to send a
|
|
|
|
@ -1331,7 +1282,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
|
|
|
|
|
props->SetPropertyAsInterface(u"sourceTabDocShell"_ns, parentDocShell);
|
|
|
|
|
props->SetPropertyAsInterface(u"createdTabDocShell"_ns,
|
|
|
|
|
ToSupports(targetDocShell));
|
|
|
|
|
ToSupports(newDocShell));
|
|
|
|
|
|
|
|
|
|
obsSvc->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
|
|
|
|
|
"webNavigation-createdNavigationTarget-from-js",
|
|
|
|
@ -1340,38 +1291,49 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (uriToLoad && aNavigate) {
|
|
|
|
|
uint32_t loadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
|
|
|
|
|
if (windowIsNew) {
|
|
|
|
|
loadFlags |= nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD;
|
|
|
|
|
|
|
|
|
|
// Per spec, the explicit navigation to about:blank after the initial
|
|
|
|
|
// about:blank document in a new window does not occur, so there is no
|
|
|
|
|
// opportunity for it to inherit the source document's principal. This
|
|
|
|
|
// doesn't perfectly model this, as a noopener creation of `about:blank`
|
|
|
|
|
// will replace the global due to a principal mismatch, but it should be
|
|
|
|
|
// unobservable (bug 1694993).
|
|
|
|
|
if (aForceNoOpener) {
|
|
|
|
|
loadFlags |= nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
loadState->SetLoadFlags(loadFlags);
|
|
|
|
|
// XXXBFCache Per spec this should effectively use
|
|
|
|
|
// LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL when noopener is passed to
|
|
|
|
|
// window.open(). Bug 1694993.
|
|
|
|
|
loadState->SetLoadFlags(
|
|
|
|
|
windowIsNew
|
|
|
|
|
? static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD)
|
|
|
|
|
: static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE));
|
|
|
|
|
loadState->SetFirstParty(true);
|
|
|
|
|
|
|
|
|
|
// Should this pay attention to errors returned by LoadURI?
|
|
|
|
|
targetBC->LoadURI(loadState);
|
|
|
|
|
newBC->LoadURI(loadState);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy the current session storage for the current domain. Don't perform the
|
|
|
|
|
// copy if we're forcing noopener, however.
|
|
|
|
|
if (!aForceNoOpener && subjectPrincipal && parentDocShell && newDocShell) {
|
|
|
|
|
const RefPtr<SessionStorageManager> parentStorageManager =
|
|
|
|
|
parentDocShell->GetBrowsingContext()->GetSessionStorageManager();
|
|
|
|
|
const RefPtr<SessionStorageManager> newStorageManager =
|
|
|
|
|
newDocShell->GetBrowsingContext()->GetSessionStorageManager();
|
|
|
|
|
|
|
|
|
|
if (parentStorageManager && newStorageManager) {
|
|
|
|
|
RefPtr<Storage> storage;
|
|
|
|
|
parentStorageManager->GetStorage(
|
|
|
|
|
pInnerWin, subjectPrincipal, subjectPrincipal,
|
|
|
|
|
newBC->UsePrivateBrowsing(), getter_AddRefs(storage));
|
|
|
|
|
if (storage) {
|
|
|
|
|
newStorageManager->CloneStorage(storage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isNewToplevelWindow) {
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
|
|
|
|
targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
SizeOpenedWindow(newTreeOwner, aParent, isCallerChrome, sizeSpec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (windowIsModal) {
|
|
|
|
|
NS_ENSURE_TRUE(targetDocShell, NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
|
NS_ENSURE_TRUE(newDocShell, NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
|
|
|
|
targetDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
|
|
|
nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
|
|
|
|
|
|
|
|
|
|
// Throw an exception here if no web browser chrome is available,
|
|
|
|
@ -1385,7 +1347,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
// Make sure we maintain the state on an outer window, because
|
|
|
|
|
// that's where it lives; inner windows assert if you try to
|
|
|
|
|
// maintain the state on them.
|
|
|
|
|
nsAutoWindowStateHelper windowStateHelper(parentOuterWin);
|
|
|
|
|
nsAutoWindowStateHelper windowStateHelper(parentWindow);
|
|
|
|
|
|
|
|
|
|
if (!windowStateHelper.DefaultEnabled()) {
|
|
|
|
|
// Default to cancel not opening the modal window.
|
|
|
|
@ -1417,8 +1379,8 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
|
|
|
|
}
|
|
|
|
|
// If a website opens a popup exit DOM fullscreen
|
|
|
|
|
if (StaticPrefs::full_screen_api_exit_on_windowOpen() && aCalledFromJS &&
|
|
|
|
|
!hasChromeParent && !isCallerChrome && parentOuterWin) {
|
|
|
|
|
Document::AsyncExitFullscreen(parentOuterWin->GetDoc());
|
|
|
|
|
!hasChromeParent && !isCallerChrome && parentWindow) {
|
|
|
|
|
Document::AsyncExitFullscreen(parentWindow->GetDoc());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aForceNoOpener && windowIsNew) {
|
|
|
|
|