зеркало из https://github.com/mozilla/pjs.git
Fixing bug 103638 (and bug 273699). Targets with same name in different windows open in the wrong window. Patch by bzbarsky@mit.edu and myself, r=danm.moz@gmail.com, bzbarsky@mit.edu, sr=dveditz@cruzio.com, a=asa@mozilla.org
This commit is contained in:
Родитель
a6baf4ca33
Коммит
1a8e54667c
|
@ -185,6 +185,11 @@ static PRInt32 gDocShellCount = 0;
|
|||
// Global reference to the URI fixup service.
|
||||
nsIURIFixup *nsDocShell::sURIFixup = 0;
|
||||
|
||||
// True means we validate window targets to prevent frameset
|
||||
// spoofing. Initialize this to a non-bolean value so we know to check
|
||||
// the pref on the creation of the first docshell.
|
||||
static PRBool gValidateOrigin = (PRBool)0xffffffff;
|
||||
|
||||
// Hint for native dispatch of plevents on how long to delay after
|
||||
// all documents have loaded in milliseconds before favoring normal
|
||||
// native event dispatch priorites over performance
|
||||
|
@ -245,7 +250,6 @@ nsDocShell::nsDocShell():
|
|||
mEODForCurrentDocument(PR_FALSE),
|
||||
mURIResultedInDocument(PR_FALSE),
|
||||
mIsBeingDestroyed(PR_FALSE),
|
||||
mValidateOrigin(PR_TRUE), // validate frame origins by default
|
||||
mIsExecutingOnLoadHandler(PR_FALSE),
|
||||
mIsPrintingOrPP(PR_FALSE),
|
||||
mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
|
||||
|
@ -375,15 +379,9 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
|
|||
NS_SUCCEEDED(EnsureScriptEnvironment())) {
|
||||
*aSink = mScriptGlobal;
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal)) &&
|
||||
NS_SUCCEEDED(EnsureScriptEnvironment())) {
|
||||
return mScriptGlobal->QueryInterface(aIID, aSink);
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsPIDOMWindow)) &&
|
||||
NS_SUCCEEDED(EnsureScriptEnvironment())) {
|
||||
return mScriptGlobal->QueryInterface(aIID, aSink);
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIDOMWindow)) &&
|
||||
else if ((aIID.Equals(NS_GET_IID(nsIDOMWindowInternal)) ||
|
||||
aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
|
||||
aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
|
||||
NS_SUCCEEDED(EnsureScriptEnvironment())) {
|
||||
return mScriptGlobal->QueryInterface(aIID, aSink);
|
||||
}
|
||||
|
@ -863,8 +861,9 @@ nsDocShell::FireUnloadNotification()
|
|||
// to the host PL_strcmp, it accepts a subdomain (nsHTMLDocument::SetDomain)
|
||||
// if the document.domain was set.
|
||||
//
|
||||
static
|
||||
PRBool SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI, PRBool aDocumentDomainSet)
|
||||
static PRBool
|
||||
SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI,
|
||||
PRBool aDocumentDomainSet)
|
||||
{
|
||||
nsCAutoString targetScheme;
|
||||
nsresult rv = aTargetURI->GetScheme(targetScheme);
|
||||
|
@ -939,28 +938,54 @@ PRBool SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI, PRBool aD
|
|||
//
|
||||
// Bug 13871: Prevent frameset spoofing
|
||||
//
|
||||
// This routine answers: 'Is origin's document from same domain as target's document?'
|
||||
// This routine answers: 'Is origin's document from same domain as
|
||||
// target's document?'
|
||||
// Be optimistic that domain is same - error cases all answer 'yes'.
|
||||
//
|
||||
// We have to compare the URI of the actual document loaded in the origin,
|
||||
// ignoring any document.domain that was set, with the principal URI of the
|
||||
// target (including any document.domain that was set). This puts control
|
||||
// of loading in the hands of the target, which is more secure. (per Nav 4.x)
|
||||
// We have to compare the URI of the actual document loaded in the
|
||||
// origin, ignoring any document.domain that was set, with the
|
||||
// principal URI of the target (including any document.domain that was
|
||||
// set). This puts control of loading in the hands of the target,
|
||||
// which is more secure. (per Nav 4.x)
|
||||
//
|
||||
static
|
||||
PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
|
||||
static PRBool
|
||||
ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
|
||||
nsIDocShellTreeItem* aTargetTreeItem)
|
||||
{
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(securityManager, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal;
|
||||
nsresult rv =
|
||||
securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, PR_TRUE);
|
||||
|
||||
if (subjectPrincipal) {
|
||||
// We're called from JS, check if UniversalBrowserWrite is
|
||||
// enabled.
|
||||
PRBool ubwEnabled = PR_FALSE;
|
||||
rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
|
||||
&ubwEnabled);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
if (ubwEnabled) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Get origin document uri (ignoring document.domain)
|
||||
nsCOMPtr<nsIWebNavigation> originWebNav(do_QueryInterface(aOriginTreeItem));
|
||||
nsCOMPtr<nsIWebNavigation> originWebNav =
|
||||
do_QueryInterface(aOriginTreeItem);
|
||||
NS_ENSURE_TRUE(originWebNav, PR_TRUE);
|
||||
|
||||
nsCOMPtr<nsIURI> originDocumentURI;
|
||||
nsresult rv = originWebNav->GetCurrentURI(getter_AddRefs(originDocumentURI));
|
||||
rv = originWebNav->GetCurrentURI(getter_AddRefs(originDocumentURI));
|
||||
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && originDocumentURI, PR_TRUE);
|
||||
|
||||
// Get target principal uri (including document.domain)
|
||||
nsCOMPtr<nsIDOMDocument> targetDOMDocument(do_GetInterface(aTargetTreeItem));
|
||||
nsCOMPtr<nsIDOMDocument> targetDOMDocument =
|
||||
do_GetInterface(aTargetTreeItem);
|
||||
nsCOMPtr<nsIDocument> targetDocument(do_QueryInterface(targetDOMDocument));
|
||||
NS_ENSURE_TRUE(targetDocument, PR_TRUE);
|
||||
|
||||
|
@ -973,15 +998,18 @@ PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
|
|||
|
||||
// Find out if document.domain was set for HTML documents
|
||||
PRBool documentDomainSet = PR_FALSE;
|
||||
nsCOMPtr<nsIHTMLDocument> targetHTMLDocument(do_QueryInterface(targetDocument));
|
||||
nsCOMPtr<nsIHTMLDocument> targetHTMLDocument =
|
||||
do_QueryInterface(targetDocument);
|
||||
|
||||
// If we don't have an HTML document, fall through with documentDomainSet false
|
||||
// If we don't have an HTML document, fall through with
|
||||
// documentDomainSet false
|
||||
if (targetHTMLDocument) {
|
||||
documentDomainSet = targetHTMLDocument->WasDomainSet();
|
||||
}
|
||||
|
||||
// Is origin same principal or a subdomain of target's document.domain
|
||||
// Compare actual URI of origin document, not origin principal's URI. (Per Nav 4.x)
|
||||
// Is origin same principal or a subdomain of target's
|
||||
// document.domain Compare actual URI of origin document, not origin
|
||||
// principal's URI. (Per Nav 4.x)
|
||||
return SameOrSubdomainOfTarget(originDocumentURI, targetPrincipalURI,
|
||||
documentDomainSet);
|
||||
}
|
||||
|
@ -991,135 +1019,36 @@ nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget,
|
|||
nsIDocShell **aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
nsAutoString name(aWindowTarget);
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
PRBool mustMakeNewWindow = PR_FALSE;
|
||||
|
||||
*aResult = nsnull;
|
||||
*aIsNewWindow = PR_FALSE;
|
||||
|
||||
if(!name.Length() || name.LowerCaseEqualsLiteral("_self"))
|
||||
{
|
||||
*aResult = this;
|
||||
}
|
||||
else if (name.LowerCaseEqualsLiteral("_blank") || name.LowerCaseEqualsLiteral("_new"))
|
||||
{
|
||||
mustMakeNewWindow = PR_TRUE;
|
||||
name.Truncate();
|
||||
}
|
||||
else if(name.LowerCaseEqualsLiteral("_parent"))
|
||||
{
|
||||
GetSameTypeParent(getter_AddRefs(treeItem));
|
||||
if(!treeItem)
|
||||
*aResult = this;
|
||||
}
|
||||
else if(name.LowerCaseEqualsLiteral("_top"))
|
||||
{
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(treeItem));
|
||||
if(!treeItem)
|
||||
*aResult = this;
|
||||
}
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
// see bug 217886 for details
|
||||
else if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main"))
|
||||
{
|
||||
if (mTreeOwner) {
|
||||
mTreeOwner->FindItemWithName(name.get(), nsnull,
|
||||
getter_AddRefs(treeItem));
|
||||
} else {
|
||||
NS_ERROR("Someone isn't setting up the tree owner. "
|
||||
"You might like to try that. "
|
||||
"Things will.....you know, work.");
|
||||
}
|
||||
// _content should always exist. If the nsIDocShellTreeOwner did
|
||||
// not find one, then create one...
|
||||
if (!treeItem) {
|
||||
mustMakeNewWindow = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to locate the target window...
|
||||
FindItemWithName(name.get(), nsnull, getter_AddRefs(treeItem));
|
||||
|
||||
// The named window cannot be found so it must be created to receive
|
||||
// the channel data.
|
||||
|
||||
if (!treeItem) {
|
||||
mustMakeNewWindow = PR_TRUE;
|
||||
}
|
||||
|
||||
// Bug 13871: Prevent frameset spoofing
|
||||
// See BugSplat 336170, 338737 and XP_FindNamedContextInList in
|
||||
// the classic codebase
|
||||
// Per Nav's behaviour:
|
||||
// - pref controlled: "browser.frame.validate_origin"
|
||||
// (mValidateOrigin)
|
||||
// - allow load if host of target or target's parent is same
|
||||
// as host of origin
|
||||
// - allow load if target is a top level window
|
||||
|
||||
// Check to see if pref is true
|
||||
if (mValidateOrigin && treeItem)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> tmp;
|
||||
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(tmp));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
|
||||
|
||||
if (sameTypeRoot != tmp && treeItem != tmp) {
|
||||
// The load was targeted at a frame and initiated in
|
||||
// another toplevel window. Assume we'll need to make
|
||||
// a new window until we find that the target, or one
|
||||
// of its ancestors, are from the same origin as the
|
||||
// loading docshell.
|
||||
mustMakeNewWindow = PR_TRUE;
|
||||
|
||||
tmp = treeItem;
|
||||
|
||||
do {
|
||||
// Is origin frame from the same domain as target frame?
|
||||
if (ValidateOrigin(this, tmp)) {
|
||||
mustMakeNewWindow = PR_FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> t;
|
||||
tmp->GetSameTypeParent(getter_AddRefs(t));
|
||||
tmp.swap(t);
|
||||
} while (tmp);
|
||||
|
||||
if (mustMakeNewWindow) {
|
||||
// Origin mismatch, open the URL in a new blank
|
||||
// window.
|
||||
treeItem = nsnull;
|
||||
name.Truncate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
FindItemWithName(aWindowTarget, nsnull, this, getter_AddRefs(treeItem));
|
||||
|
||||
PRInt32 linkPref = nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW;
|
||||
if (mustMakeNewWindow) {
|
||||
// XXXbz this should live inside FindItemWithName, I think...
|
||||
if (!treeItem) {
|
||||
mPrefs->GetIntPref("browser.link.open_newwindow", &linkPref);
|
||||
if (linkPref == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
|
||||
// force new window to go to _top
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(treeItem));
|
||||
if(!treeItem)
|
||||
*aResult = this;
|
||||
mustMakeNewWindow = PR_FALSE;
|
||||
FindItemWithName(NS_LITERAL_STRING("_top").get(),
|
||||
nsnull, this, getter_AddRefs(treeItem));
|
||||
NS_ASSERTION(treeItem,
|
||||
"We better get a treeitem when asking for '_top' "
|
||||
"with |this| as the original requestor");
|
||||
}
|
||||
}
|
||||
|
||||
if (mustMakeNewWindow)
|
||||
if (!treeItem)
|
||||
{
|
||||
/// XXXbz this should really happen in FindItemWithName too, I think...
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
nsCOMPtr<nsIDOMWindowInternal> parentWindow;
|
||||
|
||||
// This DocShell is the parent window
|
||||
parentWindow = do_GetInterface(NS_STATIC_CAST(nsIDocShell*, this));
|
||||
parentWindow = do_GetInterface(GetAsSupports(this));
|
||||
if (!parentWindow) {
|
||||
NS_ASSERTION(0, "Can't get nsIDOMWindowInternal from nsDocShell!");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1169,12 +1098,19 @@ nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget,
|
|||
// the appropriate measures will be taken when the popup fails
|
||||
}
|
||||
|
||||
if (!newWindow)
|
||||
if (!newWindow) {
|
||||
nsAutoString name(aWindowTarget);
|
||||
// XXXbz this should be handled somewhere else.... and in fact, it
|
||||
// may be safe to just pass those through here. Check.
|
||||
if (name.LowerCaseEqualsLiteral("_blank") ||
|
||||
name.LowerCaseEqualsLiteral("_new")) {
|
||||
name.Truncate();
|
||||
}
|
||||
rv = parentWindow->Open(EmptyString(), // URL to load
|
||||
name, // Window name
|
||||
EmptyString(), // Window features
|
||||
getter_AddRefs(newWindow));
|
||||
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Get the DocShell from the new window...
|
||||
|
@ -1877,6 +1813,94 @@ nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
CanAccessItem(nsIDocShellTreeItem* aTargetItem,
|
||||
nsIDocShellTreeItem* aAccessingItem,
|
||||
PRBool aConsiderOpener = PR_TRUE)
|
||||
{
|
||||
NS_PRECONDITION(aTargetItem, "Must have target item!");
|
||||
|
||||
if (!gValidateOrigin || !aAccessingItem) {
|
||||
// Good to go
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// XXXbz should we care if aAccessingItem or the document therein is
|
||||
// chrome? Should those get extra privileges?
|
||||
|
||||
// Now do a security check
|
||||
// Bug 13871: Prevent frameset spoofing
|
||||
// See BugSplat 336170, 338737 and XP_FindNamedContextInList in
|
||||
// the classic codebase
|
||||
// Nav's behaviour was:
|
||||
// - pref controlled: "browser.frame.validate_origin"
|
||||
// (gValidateOrigin)
|
||||
// - allow load if host of target or target's parent is same
|
||||
// as host of origin
|
||||
// - allow load if target is a top level window
|
||||
|
||||
// We are going to be a little more restrictive, with the
|
||||
// following algorithm:
|
||||
// - pref controlled in the same way
|
||||
// - allow access if the two treeitems are in the same tree
|
||||
// - allow access if the aTargetItem or one of its ancestors
|
||||
// has the same origin as aAccessingItem
|
||||
// - allow access if the target is a toplevel window and we can
|
||||
// access its opener. Note that we only allow one level of
|
||||
// recursion there.
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> targetRoot;
|
||||
aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
|
||||
aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
|
||||
|
||||
if (targetRoot == accessingRoot) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
|
||||
do {
|
||||
if (ValidateOrigin(aAccessingItem, target)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
target->GetSameTypeParent(getter_AddRefs(parent));
|
||||
parent.swap(target);
|
||||
} while (target);
|
||||
|
||||
if (aTargetItem != targetRoot) {
|
||||
// target is a subframe, not in accessor's frame hierarchy, and all its
|
||||
// ancestors have origins different from that of the accessor. Don't
|
||||
// allow access.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!aConsiderOpener) {
|
||||
// All done here
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> targetWindow(do_GetInterface(aTargetItem));
|
||||
nsCOMPtr<nsIDOMWindowInternal> targetInternal(do_QueryInterface(targetWindow));
|
||||
if (!targetInternal) {
|
||||
NS_ERROR("This should not happen, really");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindowInternal> targetOpener;
|
||||
targetInternal->GetOpener(getter_AddRefs(targetOpener));
|
||||
nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
|
||||
nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
|
||||
|
||||
if (!openerItem) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return CanAccessItem(openerItem, aAccessingItem, PR_FALSE);
|
||||
}
|
||||
|
||||
static PRBool
|
||||
ItemIsActive(nsIDocShellTreeItem *aItem)
|
||||
{
|
||||
|
@ -1897,38 +1921,110 @@ ItemIsActive(nsIDocShellTreeItem *aItem)
|
|||
NS_IMETHODIMP
|
||||
nsDocShell::FindItemWithName(const PRUnichar * aName,
|
||||
nsISupports * aRequestor,
|
||||
nsIDocShellTreeItem * aOriginalRequestor,
|
||||
nsIDocShellTreeItem ** _retval)
|
||||
{
|
||||
NS_ENSURE_ARG(aName);
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
*_retval = nsnull; // if we don't find one, we return NS_OK and a null result
|
||||
// If we don't find one, we return NS_OK and a null result
|
||||
*_retval = nsnull;
|
||||
|
||||
// This QI may fail, but the places where we want to compare, comparing
|
||||
// against nsnull serves the same purpose.
|
||||
nsCOMPtr<nsIDocShellTreeItem>
|
||||
reqAsTreeItem(do_QueryInterface(aRequestor));
|
||||
if (!aRequestor)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> foundItem;
|
||||
|
||||
// This is the entry point into the target-finding algorithm. Check
|
||||
// for special names. This should only be done once, hence the check
|
||||
// for a null aRequestor.
|
||||
|
||||
nsDependentString name(aName);
|
||||
if (name.IsEmpty() || name.LowerCaseEqualsLiteral("_self")) {
|
||||
foundItem = this;
|
||||
}
|
||||
else if (name.LowerCaseEqualsLiteral("_blank") ||
|
||||
name.LowerCaseEqualsLiteral("_new"))
|
||||
{
|
||||
// Just return null. Caller must handle creating a new window with
|
||||
// a blank name himself.
|
||||
return NS_OK;
|
||||
}
|
||||
else if (name.LowerCaseEqualsLiteral("_parent"))
|
||||
{
|
||||
GetSameTypeParent(getter_AddRefs(foundItem));
|
||||
if(!foundItem)
|
||||
foundItem = this;
|
||||
}
|
||||
else if (name.LowerCaseEqualsLiteral("_top"))
|
||||
{
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
|
||||
if(!foundItem)
|
||||
foundItem = this;
|
||||
}
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
// see bug 217886 for details
|
||||
else if (name.LowerCaseEqualsLiteral("_content") ||
|
||||
name.EqualsLiteral("_main"))
|
||||
{
|
||||
if (mTreeOwner)
|
||||
mTreeOwner->GetPrimaryContentShell(getter_AddRefs(foundItem));
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
NS_ERROR("Someone isn't setting up the tree owner. "
|
||||
"You might like to try that. "
|
||||
"Things will.....you know, work.");
|
||||
// Note: _content should always exist. If we don't have one
|
||||
// hanging off the treeowner, just create a named window....
|
||||
// so don't return here, in case we did that and can now find
|
||||
// it.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
|
||||
foundItem = nsnull;
|
||||
}
|
||||
|
||||
if (foundItem) {
|
||||
// We return foundItem here even if it's not an active
|
||||
// item since all the names we've dealt with so far are
|
||||
// special cases that we won't bother looking for further.
|
||||
|
||||
foundItem.swap(*_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep looking
|
||||
|
||||
// First we check our name.
|
||||
if (mName.Equals(aName) && ItemIsActive(this)) {
|
||||
*_retval = this;
|
||||
NS_ADDREF(*_retval);
|
||||
if (mName.Equals(aName) && ItemIsActive(this) &&
|
||||
CanAccessItem(this, aOriginalRequestor)) {
|
||||
NS_ADDREF(*_retval = this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Second we check our children making sure not to ask a child if it
|
||||
// is the aRequestor.
|
||||
NS_ENSURE_SUCCESS(FindChildWithName(aName, PR_TRUE, PR_TRUE, reqAsTreeItem,
|
||||
_retval), NS_ERROR_FAILURE);
|
||||
// This QI may fail, but the places where we want to compare, comparing
|
||||
// against nsnull serves the same purpose.
|
||||
nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
|
||||
|
||||
// Second we check our children making sure not to ask a child if
|
||||
// it is the aRequestor.
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
FindChildWithName(aName, PR_TRUE, PR_TRUE, reqAsTreeItem,
|
||||
aOriginalRequestor, _retval);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"FindChildWithName should not be failing here.");
|
||||
if (*_retval)
|
||||
return NS_OK;
|
||||
|
||||
// Third if we have a parent and it isn't the requestor then we should ask
|
||||
// it to do the search. If it is the requestor we should just stop here
|
||||
// and let the parent do the rest.
|
||||
// If we don't have a parent, then we should ask the docShellTreeOwner to do
|
||||
// the search.
|
||||
|
||||
// Third if we have a parent and it isn't the requestor then we
|
||||
// should ask it to do the search. If it is the requestor we
|
||||
// should just stop here and let the parent do the rest. If we
|
||||
// don't have a parent, then we should ask the
|
||||
// docShellTreeOwner to do the search.
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
|
||||
do_QueryInterface(GetAsSupports(mParent));
|
||||
if (parentAsTreeItem) {
|
||||
|
@ -1938,12 +2034,15 @@ nsDocShell::FindItemWithName(const PRUnichar * aName,
|
|||
PRInt32 parentType;
|
||||
parentAsTreeItem->GetItemType(&parentType);
|
||||
if (parentType == mItemType) {
|
||||
return parentAsTreeItem->FindItemWithName(aName,
|
||||
NS_STATIC_CAST
|
||||
(nsIDocShellTreeItem *,
|
||||
this), _retval);
|
||||
return parentAsTreeItem->
|
||||
FindItemWithName(aName,
|
||||
NS_STATIC_CAST(nsIDocShellTreeItem*,
|
||||
this),
|
||||
aOriginalRequestor,
|
||||
_retval);
|
||||
}
|
||||
}
|
||||
|
||||
// If the parent is null or not of the same type fall through and ask tree
|
||||
// owner.
|
||||
|
||||
|
@ -1951,12 +2050,13 @@ nsDocShell::FindItemWithName(const PRUnichar * aName,
|
|||
nsCOMPtr<nsIDocShellTreeOwner>
|
||||
reqAsTreeOwner(do_GetInterface(aRequestor));
|
||||
|
||||
if (mTreeOwner && (mTreeOwner != reqAsTreeOwner.get())) {
|
||||
NS_ENSURE_SUCCESS(mTreeOwner->FindItemWithName(aName,
|
||||
NS_STATIC_CAST
|
||||
(nsIDocShellTreeItem *,
|
||||
this), _retval),
|
||||
NS_ERROR_FAILURE);
|
||||
if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
|
||||
return mTreeOwner->
|
||||
FindItemWithName(aName,
|
||||
NS_STATIC_CAST(nsIDocShellTreeItem*,
|
||||
this),
|
||||
aOriginalRequestor,
|
||||
_retval);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2275,6 +2375,7 @@ NS_IMETHODIMP
|
|||
nsDocShell::FindChildWithName(const PRUnichar * aName,
|
||||
PRBool aRecurse, PRBool aSameType,
|
||||
nsIDocShellTreeItem * aRequestor,
|
||||
nsIDocShellTreeItem * aOriginalRequestor,
|
||||
nsIDocShellTreeItem ** _retval)
|
||||
{
|
||||
NS_ENSURE_ARG(aName);
|
||||
|
@ -2295,9 +2396,9 @@ nsDocShell::FindChildWithName(const PRUnichar * aName,
|
|||
|
||||
PRBool childNameEquals = PR_FALSE;
|
||||
child->NameEquals(aName, &childNameEquals);
|
||||
if (childNameEquals && ItemIsActive(child)) {
|
||||
*_retval = child;
|
||||
NS_ADDREF(*_retval);
|
||||
if (childNameEquals && ItemIsActive(child) &&
|
||||
CanAccessItem(child, aOriginalRequestor)) {
|
||||
child.swap(*_retval);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2309,19 +2410,23 @@ nsDocShell::FindChildWithName(const PRUnichar * aName,
|
|||
// See if child contains the shell with the given name
|
||||
nsCOMPtr<nsIDocShellTreeNode>
|
||||
childAsNode(do_QueryInterface(child));
|
||||
if (child) {
|
||||
NS_ENSURE_SUCCESS(childAsNode->FindChildWithName(aName, PR_TRUE,
|
||||
if (childAsNode) {
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
childAsNode->FindChildWithName(aName, PR_TRUE,
|
||||
aSameType,
|
||||
NS_STATIC_CAST
|
||||
(nsIDocShellTreeItem
|
||||
*, this),
|
||||
_retval),
|
||||
NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
NS_STATIC_CAST(nsIDocShellTreeItem*,
|
||||
this),
|
||||
aOriginalRequestor,
|
||||
_retval);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"FindChildWithName should not fail here");
|
||||
if (*_retval) // found it
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3147,10 +3252,15 @@ nsDocShell::Create()
|
|||
if (NS_SUCCEEDED(rv))
|
||||
mAllowSubframes = tmpbool;
|
||||
|
||||
if (gValidateOrigin == (PRBool)0xffffffff) {
|
||||
// Check pref to see if we should prevent frameset spoofing
|
||||
rv = mPrefs->GetBoolPref("browser.frame.validate_origin", &tmpbool);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mValidateOrigin = tmpbool;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gValidateOrigin = tmpbool;
|
||||
} else {
|
||||
gValidateOrigin = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Should we use XUL error pages instead of alerts if possible?
|
||||
rv = mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool);
|
||||
|
@ -4929,9 +5039,16 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
|
|||
nsresult
|
||||
nsDocShell::CheckLoadingPermissions()
|
||||
{
|
||||
// This method checks whether the caller may load content into
|
||||
// this docshell. Even though we've done our best to hide windows
|
||||
// from code that doesn't have the right to access them, it's
|
||||
// still possible for an evil site to open a window and access
|
||||
// frames in the new window through window.frames[] (which is
|
||||
// allAccess for historic reasons), so we still need to do this
|
||||
// check on load.
|
||||
nsresult rv = NS_OK, sameOrigin = NS_OK;
|
||||
|
||||
if (!mValidateOrigin || !IsFrame()) {
|
||||
if (!gValidateOrigin || !IsFrame()) {
|
||||
// Origin validation was turned off, or we're not a frame.
|
||||
// Permit all loads.
|
||||
|
||||
|
@ -5139,6 +5256,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
// created. It really doesn't belong here, but until there is a
|
||||
// way for embeddors to get involved in window targeting, this is
|
||||
// as good a place as any...
|
||||
// XXXbz no, it's not.... fixme!!!!
|
||||
//
|
||||
PRInt32 linkPref = nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW;
|
||||
mPrefs->GetIntPref("browser.link.open_newwindow", &linkPref);
|
||||
|
@ -5166,6 +5284,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
nsCOMPtr<nsIDocShellTreeItem> targetTreeItem;
|
||||
FindItemWithName(name.get(),
|
||||
nsnull,
|
||||
this,
|
||||
getter_AddRefs(targetTreeItem));
|
||||
if (targetTreeItem)
|
||||
targetDocShell = do_QueryInterface(targetTreeItem);
|
||||
|
|
|
@ -368,9 +368,6 @@ protected:
|
|||
|
||||
PRPackedBool mIsBeingDestroyed;
|
||||
|
||||
// Validate window targets to prevent frameset spoofing
|
||||
PRPackedBool mValidateOrigin;
|
||||
|
||||
PRPackedBool mIsExecutingOnLoadHandler;
|
||||
|
||||
// Indicates that a DocShell in this "docshell tree" is printing
|
||||
|
|
|
@ -48,7 +48,7 @@ interface nsIDocShellTreeOwner;
|
|||
* node or a leaf.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(1b3416f3-0ec6-49e6-8bdf-77bfdbc4a102)]
|
||||
[scriptable, uuid(7d935d63-6d2a-4600-afb5-9a4f7d68b825)]
|
||||
interface nsIDocShellTreeItem : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -130,8 +130,12 @@ interface nsIDocShellTreeItem : nsISupports
|
|||
a shell by the specified name. Inversely the child uses it to ensure it
|
||||
does not ask its parent to do the search if its parent is the one that
|
||||
asked it to search. Children also use this to test against the treeOwner;
|
||||
aOriginalRequestor - The original treeitem that made the request, if any.
|
||||
This is used to ensure that we don't run into cross-site issues.
|
||||
*/
|
||||
nsIDocShellTreeItem findItemWithName(in wstring name, in nsISupports aRequestor);
|
||||
nsIDocShellTreeItem findItemWithName(in wstring name,
|
||||
in nsISupports aRequestor,
|
||||
in nsIDocShellTreeItem aOriginalRequestor);
|
||||
|
||||
/*
|
||||
The owner of the DocShell Tree. This interface will be called upon when
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
// XXXbz this interface should probably inherit from nsIDocShellTreeItem, and
|
||||
// some methods should move from there to here...
|
||||
|
||||
[scriptable, uuid(C094F810-A8AB-11d3-AFC6-00A024FFC08C)]
|
||||
[scriptable, uuid(37f1ab73-f224-44b1-82f0-d2834ab1cec0)]
|
||||
interface nsIDocShellTreeNode : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -87,11 +87,16 @@ interface nsIDocShellTreeNode : nsISupports
|
|||
aRequestor - This is the docshellTreeItem that is requesting the find. This
|
||||
parameter is used when recursion is being used to avoid searching the same
|
||||
tree again when a child has asked a parent to search for children.
|
||||
aOriginalRequestor - The original treeitem that made the request, if any.
|
||||
This is used to ensure that we don't run into cross-site issues.
|
||||
|
||||
Note the search is depth first when recursing.
|
||||
// XXXbz this should return an nsIDocShellTreeNode, I think.
|
||||
*/
|
||||
nsIDocShellTreeItem findChildWithName(in wstring aName, in boolean aRecurse,
|
||||
in boolean aSameType, in nsIDocShellTreeItem aRequestor);
|
||||
nsIDocShellTreeItem findChildWithName(in wstring aName,
|
||||
in boolean aRecurse,
|
||||
in boolean aSameType,
|
||||
in nsIDocShellTreeItem aRequestor,
|
||||
in nsIDocShellTreeItem aOriginalRequestor);
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
interface nsIDocShellTreeItem;
|
||||
|
||||
[scriptable, uuid(80F30E10-A7CF-11d3-AFC5-00A024FFC08C)]
|
||||
[scriptable, uuid(9e508466-5ebb-4618-abfa-9ad47bed0b2e)]
|
||||
interface nsIDocShellTreeOwner : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -58,9 +58,13 @@ interface nsIDocShellTreeOwner : nsISupports
|
|||
a shell by the specified name. Inversely the child uses it to ensure it
|
||||
does not ask its parent to do the search if its parent is the one that
|
||||
asked it to search.
|
||||
aOriginalRequestor - The original treeitem that made the request, if any.
|
||||
This is used to ensure that we don't run into cross-site issues.
|
||||
|
||||
*/
|
||||
nsIDocShellTreeItem findItemWithName(in wstring name,
|
||||
in nsIDocShellTreeItem aRequestor);
|
||||
in nsIDocShellTreeItem aRequestor,
|
||||
in nsIDocShellTreeItem aOriginalRequestor);
|
||||
|
||||
/*
|
||||
Called when a content shell is added to the the docShell Tree.
|
||||
|
|
|
@ -4712,7 +4712,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
const jschar *chars = ::JS_GetStringChars(str);
|
||||
|
||||
dsn->FindChildWithName(NS_REINTERPRET_CAST(const PRUnichar*, chars),
|
||||
PR_FALSE, PR_TRUE, nsnull,
|
||||
PR_FALSE, PR_TRUE, nsnull, nsnull,
|
||||
getter_AddRefs(child));
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> child_win(do_GetInterface(child));
|
||||
|
|
|
@ -175,7 +175,7 @@ nsDOMWindowList::NamedItem(const nsAString& aName, nsIDOMWindow** aReturn)
|
|||
|
||||
if (mDocShellNode) {
|
||||
mDocShellNode->FindChildWithName(PromiseFlatString(aName).get(),
|
||||
PR_FALSE, PR_FALSE,
|
||||
PR_FALSE, PR_FALSE, nsnull,
|
||||
nsnull, getter_AddRefs(item));
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(item));
|
||||
|
|
|
@ -2109,6 +2109,71 @@ nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
|
|||
return preventDefault;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIDocShellTreeItem>
|
||||
GetCallerDocShellTreeItem()
|
||||
{
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService(sJSStackContractID);
|
||||
|
||||
JSContext *cx = nsnull;
|
||||
|
||||
if (stack) {
|
||||
stack->Peek(&cx);
|
||||
}
|
||||
|
||||
nsIDocShellTreeItem *callerItem = nsnull;
|
||||
|
||||
if (cx) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
||||
do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
|
||||
|
||||
if (callerWebNav) {
|
||||
CallQueryInterface(callerWebNav, &callerItem);
|
||||
}
|
||||
}
|
||||
|
||||
return callerItem;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGlobalWindow::WindowExists(const nsAString& aName)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> caller = GetCallerDocShellTreeItem();
|
||||
PRBool foundWindow = PR_FALSE;
|
||||
|
||||
if (!caller) {
|
||||
// If we can't reach a caller, try to use our own docshell
|
||||
caller = do_QueryInterface(mDocShell);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(mDocShell));
|
||||
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> namedItem;
|
||||
|
||||
docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
|
||||
getter_AddRefs(namedItem));
|
||||
|
||||
foundWindow = !!namedItem;
|
||||
} else {
|
||||
// No caller reachable and we don't have a docshell any more. Fall
|
||||
// back to using the windowwatcher service to find any window by
|
||||
// name.
|
||||
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
|
||||
if (wwatch) {
|
||||
nsCOMPtr<nsIDOMWindow> namedWindow;
|
||||
wwatch->GetWindowByName(PromiseFlatString(aName).get(), nsnull,
|
||||
getter_AddRefs(namedWindow));
|
||||
|
||||
foundWindow = !!namedWindow;
|
||||
}
|
||||
}
|
||||
|
||||
return foundWindow;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
|
||||
{
|
||||
|
@ -3116,23 +3181,16 @@ nsGlobalWindow::CheckOpenAllow(PopupControlState aAbuseLevel,
|
|||
allowWindow = allowWhitelisted;
|
||||
else {
|
||||
// Special case items that don't actually open new windows.
|
||||
nsAutoString name(aName);
|
||||
if (!name.IsEmpty()) {
|
||||
if (!aName.IsEmpty()) {
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
// see bug 217886 for details
|
||||
if (name.LowerCaseEqualsLiteral("_top") ||
|
||||
name.LowerCaseEqualsLiteral("_self") ||
|
||||
name.LowerCaseEqualsLiteral("_content") ||
|
||||
name.EqualsLiteral("_main"))
|
||||
if (aName.LowerCaseEqualsLiteral("_top") ||
|
||||
aName.LowerCaseEqualsLiteral("_self") ||
|
||||
aName.LowerCaseEqualsLiteral("_content") ||
|
||||
aName.EqualsLiteral("_main"))
|
||||
allowWindow = allowSelf;
|
||||
else {
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
|
||||
if (wwatch) {
|
||||
nsCOMPtr<nsIDOMWindow> namedWindow;
|
||||
wwatch->GetWindowByName(PromiseFlatString(aName).get(), this,
|
||||
getter_AddRefs(namedWindow));
|
||||
if (namedWindow)
|
||||
if (WindowExists(aName)) {
|
||||
allowWindow = allowExtant;
|
||||
}
|
||||
}
|
||||
|
@ -4627,33 +4685,12 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoString nameString(aName);
|
||||
|
||||
// determine whether we must divert the open window to a new tab.
|
||||
|
||||
PRBool divertOpen = PR_TRUE; // at first, assume we will divert
|
||||
PRBool divertOpen = !WindowExists(aName);
|
||||
|
||||
// first, does the named window already exist? (see nsWindowWatcher)
|
||||
|
||||
if (nameString.EqualsIgnoreCase("_top") ||
|
||||
nameString.EqualsIgnoreCase("_self") ||
|
||||
nameString.EqualsIgnoreCase("_content") ||
|
||||
nameString.EqualsIgnoreCase("_parent") ||
|
||||
nameString.Equals(NS_LITERAL_STRING("_main")))
|
||||
divertOpen = PR_FALSE;
|
||||
else {
|
||||
nsCOMPtr<nsIDocShellTreeOwner> docOwner;
|
||||
GetTreeOwner(getter_AddRefs(docOwner));
|
||||
if (docOwner) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> namedWindow;
|
||||
docOwner->FindItemWithName(nameString.get(), 0,
|
||||
getter_AddRefs(namedWindow));
|
||||
if (namedWindow)
|
||||
divertOpen = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// second, what do the prefs prescribe?
|
||||
// also check what the prefs prescribe?
|
||||
// XXXbz this duplicates docshell code. Need to consolidate.
|
||||
|
||||
PRInt32 containerPref = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
|
||||
|
||||
|
@ -4671,8 +4708,8 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
PRBool chromeTab = PR_FALSE;
|
||||
if (tabURI)
|
||||
tabURI->SchemeIs("chrome", &chromeTab);
|
||||
if (!thisChrome && !chromeTab) {
|
||||
|
||||
if (!thisChrome && !chromeTab) {
|
||||
containerPref=nsContentUtils::GetIntPref("browser.link.open_newwindow",
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW);
|
||||
PRInt32 restrictionPref = nsContentUtils::GetIntPref(
|
||||
|
@ -4738,8 +4775,8 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
GetTop(getter_AddRefs(domReturn));
|
||||
}
|
||||
|
||||
if (domReturn && !nameString.EqualsIgnoreCase("_blank") &&
|
||||
!nameString.EqualsIgnoreCase("_new"))
|
||||
if (domReturn && !aName.LowerCaseEqualsLiteral("_blank") &&
|
||||
!aName.LowerCaseEqualsLiteral("_new"))
|
||||
domReturn->SetName(aName);
|
||||
}
|
||||
|
||||
|
|
|
@ -294,6 +294,8 @@ protected:
|
|||
|
||||
PRBool DispatchCustomEvent(const char *aEventName);
|
||||
|
||||
PRBool WindowExists(const nsAString& aName);
|
||||
|
||||
// When adding new member variables, be careful not to create cycles
|
||||
// through JavaScript. If there is any chance that a member variable
|
||||
// could own objects that are implemented in JavaScript, then those
|
||||
|
|
|
@ -209,6 +209,7 @@ nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
|
|||
NS_IMETHODIMP
|
||||
nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem)
|
||||
{
|
||||
NS_ENSURE_ARG(aName);
|
||||
|
@ -250,7 +251,8 @@ nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
|
|||
}
|
||||
|
||||
// next, check our children
|
||||
rv = FindChildWithName(aName, PR_TRUE, aRequestor, aFoundItem);
|
||||
rv = FindChildWithName(aName, PR_TRUE, aRequestor, aOriginalRequestor,
|
||||
aFoundItem);
|
||||
if(NS_FAILED(rv) || *aFoundItem)
|
||||
return rv;
|
||||
|
||||
|
@ -260,13 +262,13 @@ nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
|
|||
if(mTreeOwner) {
|
||||
if (mTreeOwner != reqAsTreeOwner)
|
||||
return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
|
||||
aFoundItem);
|
||||
aOriginalRequestor, aFoundItem);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// finally, failing everything else, search all windows, if we're not already
|
||||
if (mWebBrowser->mDocShellAsItem != aRequestor)
|
||||
return FindItemWithNameAcrossWindows(aName, aFoundItem);
|
||||
return FindItemWithNameAcrossWindows(aName, aOriginalRequestor, aFoundItem);
|
||||
|
||||
return NS_OK; // failed
|
||||
}
|
||||
|
@ -274,6 +276,7 @@ nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
|
|||
nsresult
|
||||
nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
|
||||
nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem **aFoundItem)
|
||||
{
|
||||
if (!mWebBrowser)
|
||||
|
@ -302,7 +305,8 @@ nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
|
|||
nsCOMPtr<nsIDocShellTreeItem> item =
|
||||
do_QueryInterface(sgo->GetDocShell());
|
||||
if (item && item != aRequestor) {
|
||||
rv = item->FindItemWithName(aName, mWebBrowser->mDocShellAsItem, aFoundItem);
|
||||
rv = item->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
|
||||
aOriginalRequestor, aFoundItem);
|
||||
if (NS_FAILED(rv) || *aFoundItem)
|
||||
break;
|
||||
}
|
||||
|
@ -314,6 +318,7 @@ nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
|
|||
|
||||
nsresult
|
||||
nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem)
|
||||
{
|
||||
// search for the item across the list of top-level windows
|
||||
|
@ -341,7 +346,7 @@ nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
|
|||
nsCOMPtr<nsIDocShellTreeItem> item =
|
||||
do_QueryInterface(sgo->GetDocShell());
|
||||
if (item) {
|
||||
rv = item->FindItemWithName(aName, item, aFoundItem);
|
||||
rv = item->FindItemWithName(aName, item, aOriginalRequestor, aFoundItem);
|
||||
if (NS_FAILED(rv) || *aFoundItem)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -124,8 +124,10 @@ protected:
|
|||
|
||||
nsresult FindChildWithName(const PRUnichar *aName,
|
||||
PRBool aRecurse, nsIDocShellTreeItem* aRequestor,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem **aFoundItem);
|
||||
nsresult FindItemWithNameAcrossWindows(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem **aFoundItem);
|
||||
|
||||
void EnsurePrompter();
|
||||
|
|
|
@ -563,13 +563,15 @@ NS_IMETHODIMP nsWebBrowser::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootT
|
|||
}
|
||||
|
||||
NS_IMETHODIMP nsWebBrowser::FindItemWithName(const PRUnichar *aName,
|
||||
nsISupports* aRequestor, nsIDocShellTreeItem **_retval)
|
||||
nsISupports* aRequestor, nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem **_retval)
|
||||
{
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
NS_ASSERTION(mDocShellTreeOwner, "This should always be set when in this situation");
|
||||
|
||||
return mDocShellAsItem->FindItemWithName(aName,
|
||||
NS_STATIC_CAST(nsIDocShellTreeOwner*, mDocShellTreeOwner), _retval);
|
||||
NS_STATIC_CAST(nsIDocShellTreeOwner*, mDocShellTreeOwner),
|
||||
aOriginalRequestor, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsWebBrowser::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
|
||||
|
|
|
@ -160,6 +160,10 @@ interface nsIWindowWatcher : nsISupports {
|
|||
@param aCurrentWindow a starting point in the window hierarchy to
|
||||
begin the search. If null, each toplevel window
|
||||
will be searched.
|
||||
|
||||
Note: This method will search all open windows for any window or
|
||||
frame with the given window name. Make sure you understand the
|
||||
security implications of this before using this method!
|
||||
*/
|
||||
nsIDOMWindow getWindowByName(in wstring aTargetName,
|
||||
in nsIDOMWindow aCurrentWindow);
|
||||
|
|
|
@ -91,6 +91,15 @@ nsWWJSUtils::GetDynamicScriptContext(JSContext *aContext)
|
|||
return GetScriptContextFromJSContext(aContext);
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject *
|
||||
nsWWJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
|
||||
{
|
||||
nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
|
||||
if (!scriptCX)
|
||||
return nsnull;
|
||||
return scriptCX->GetGlobalObject();
|
||||
}
|
||||
|
||||
nsIScriptContext *
|
||||
nsWWJSUtils::GetStaticScriptContext(JSContext* aContext,
|
||||
JSObject* aObj)
|
||||
|
|
|
@ -480,7 +480,7 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
uriToLoadIsChrome = PR_FALSE;
|
||||
PRUint32 chromeFlags;
|
||||
nsAutoString name; // string version of aName
|
||||
nsCString features; // string version of aFeatures
|
||||
nsCAutoString features; // string version of aFeatures
|
||||
nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
|
||||
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any
|
||||
nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window
|
||||
|
@ -522,41 +522,37 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
|
||||
// try to find an extant window with the given name
|
||||
if (nameSpecified) {
|
||||
/* Oh good. special target names are now handled in multiple places:
|
||||
Here and within FindItemWithName, just below. I put _top here because
|
||||
here it's able to do what it should: get the topmost shell of the same
|
||||
(content/chrome) type as the docshell. treeOwner is always chrome, so
|
||||
this scheme doesn't work there, where a lot of other special case
|
||||
targets are handled. (treeOwner is, however, a good place to look
|
||||
for browser windows by name, as it does.)
|
||||
*/
|
||||
if (aParent) {
|
||||
if (name.LowerCaseEqualsLiteral("_self")) {
|
||||
GetWindowTreeItem(aParent, getter_AddRefs(newDocShellItem));
|
||||
} else if (name.LowerCaseEqualsLiteral("_top")) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> shelltree;
|
||||
GetWindowTreeItem(aParent, getter_AddRefs(shelltree));
|
||||
if (shelltree)
|
||||
shelltree->GetSameTypeRootTreeItem(getter_AddRefs(newDocShellItem));
|
||||
} else if (name.LowerCaseEqualsLiteral("_parent")) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> shelltree;
|
||||
GetWindowTreeItem(aParent, getter_AddRefs(shelltree));
|
||||
if (shelltree)
|
||||
shelltree->GetSameTypeParent(getter_AddRefs(newDocShellItem));
|
||||
// If there is no real parent then _self acts as _parent
|
||||
if (!newDocShellItem)
|
||||
newDocShellItem = shelltree;
|
||||
} else {
|
||||
/* parent is being simultaneously torn down (probably because of
|
||||
the code that keeps an old docshell alive but disconnected while
|
||||
we load a new one). not much to do but open the new window
|
||||
without a parent. */
|
||||
if (parentTreeOwner)
|
||||
parentTreeOwner->FindItemWithName(name.get(), nsnull,
|
||||
getter_AddRefs(newDocShellItem));
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService(sJSStackContractID);
|
||||
|
||||
JSContext *cx = nsnull;
|
||||
|
||||
if (stack) {
|
||||
stack->Peek(&cx);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> callerItem;
|
||||
|
||||
if (cx) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
||||
do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx));
|
||||
|
||||
callerItem = do_QueryInterface(callerWebNav);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
|
||||
|
||||
if (!callerItem) {
|
||||
callerItem = parentItem;
|
||||
}
|
||||
|
||||
if (parentItem) {
|
||||
parentItem->FindItemWithName(name.get(), nsnull, callerItem,
|
||||
getter_AddRefs(newDocShellItem));
|
||||
} else
|
||||
FindItemWithName(name.get(), getter_AddRefs(newDocShellItem));
|
||||
FindItemWithName(name.get(), callerItem,
|
||||
getter_AddRefs(newDocShellItem));
|
||||
}
|
||||
|
||||
// no extant window? make a new one.
|
||||
|
@ -1055,14 +1051,15 @@ nsWindowWatcher::GetWindowByName(const PRUnichar *aTargetName,
|
|||
|
||||
docShellTreeItem = do_QueryInterface(webNav);
|
||||
if (docShellTreeItem) {
|
||||
docShellTreeItem->FindItemWithName(aTargetName, nsnull,
|
||||
// XXXbz sort out original requestor?
|
||||
docShellTreeItem->FindItemWithName(aTargetName, nsnull, nsnull,
|
||||
getter_AddRefs(treeItem));
|
||||
}
|
||||
}
|
||||
|
||||
// Next, see if the TargetName exists in any window hierarchy
|
||||
if (!treeItem) {
|
||||
FindItemWithName(aTargetName, getter_AddRefs(treeItem));
|
||||
FindItemWithName(aTargetName, nsnull, getter_AddRefs(treeItem));
|
||||
}
|
||||
|
||||
if (treeItem) {
|
||||
|
@ -1382,19 +1379,18 @@ nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName,
|
|||
necessarily return a failure method value. check aFoundItem.
|
||||
*/
|
||||
nsresult
|
||||
nsWindowWatcher::FindItemWithName(
|
||||
const PRUnichar* aName,
|
||||
nsWindowWatcher::FindItemWithName(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem)
|
||||
{
|
||||
PRBool more;
|
||||
nsresult rv;
|
||||
nsAutoString name(aName);
|
||||
|
||||
*aFoundItem = 0;
|
||||
|
||||
/* special cases */
|
||||
if(name.IsEmpty())
|
||||
if(!aName || !*aName)
|
||||
return NS_OK;
|
||||
|
||||
nsDependentString name(aName);
|
||||
|
||||
if(name.LowerCaseEqualsLiteral("_blank") || name.LowerCaseEqualsLiteral("_new"))
|
||||
return NS_OK;
|
||||
// _content will be handled by individual windows, below
|
||||
|
@ -1404,7 +1400,9 @@ nsWindowWatcher::FindItemWithName(
|
|||
if (!windows)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = NS_OK;
|
||||
PRBool more;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
do {
|
||||
windows->HasMoreElements(&more);
|
||||
if (!more)
|
||||
|
@ -1417,7 +1415,8 @@ nsWindowWatcher::FindItemWithName(
|
|||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
GetWindowTreeItem(nextWindow, getter_AddRefs(treeItem));
|
||||
if (treeItem) {
|
||||
rv = treeItem->FindItemWithName(aName, treeItem, aFoundItem);
|
||||
rv = treeItem->FindItemWithName(aName, treeItem, aOriginalRequestor,
|
||||
aFoundItem);
|
||||
if (NS_FAILED(rv) || *aFoundItem)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -85,6 +85,7 @@ private:
|
|||
nsresult RemoveWindow(nsWatcherWindowEntry *inInfo);
|
||||
|
||||
nsresult FindItemWithName(const PRUnichar *aName,
|
||||
nsIDocShellTreeItem *aOriginalRequestor,
|
||||
nsIDocShellTreeItem **aFoundItem);
|
||||
|
||||
static JSContext *GetJSContextFromWindow(nsIDOMWindow *aWindow);
|
||||
|
|
|
@ -376,7 +376,7 @@ nsMessenger::SetWindow(nsIDOMWindowInternal *aWin, nsIMsgWindow *aMsgWindow)
|
|||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> childAsItem;
|
||||
nsresult rv = rootDocShellAsNode->FindChildWithName(NS_LITERAL_STRING("messagepane").get(),
|
||||
PR_TRUE, PR_FALSE, nsnull, getter_AddRefs(childAsItem));
|
||||
PR_TRUE, PR_FALSE, nsnull, nsnull, getter_AddRefs(childAsItem));
|
||||
|
||||
mDocShell = do_QueryInterface(childAsItem);
|
||||
|
||||
|
|
|
@ -282,7 +282,8 @@ nsMsgPrintEngine::SetWindow(nsIDOMWindowInternal *aWin)
|
|||
NS_ENSURE_TRUE(rootAsNode, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> childItem;
|
||||
rootAsNode->FindChildWithName(NS_LITERAL_STRING("content").get(), PR_TRUE, PR_FALSE, nsnull,
|
||||
rootAsNode->FindChildWithName(NS_LITERAL_STRING("content").get(), PR_TRUE,
|
||||
PR_FALSE, nsnull, nsnull,
|
||||
getter_AddRefs(childItem));
|
||||
|
||||
mDocShell = do_QueryInterface(childItem);
|
||||
|
|
|
@ -123,8 +123,9 @@ void nsMsgWindow::GetMessageWindowDocShell(nsIDocShell ** aDocShell)
|
|||
|
||||
nsCOMPtr<nsIDocShellTreeItem> msgDocShellItem;
|
||||
if(rootAsNode)
|
||||
rootAsNode->FindChildWithName(NS_LITERAL_STRING("messagepane").get(), PR_TRUE, PR_FALSE,
|
||||
nsnull, getter_AddRefs(msgDocShellItem));
|
||||
rootAsNode->FindChildWithName(NS_LITERAL_STRING("messagepane").get(),
|
||||
PR_TRUE, PR_FALSE, nsnull, nsnull,
|
||||
getter_AddRefs(msgDocShellItem));
|
||||
|
||||
docShell = do_QueryInterface(msgDocShellItem);
|
||||
// we don't own mMessageWindowDocShell so don't try to keep a reference to it!
|
||||
|
|
|
@ -174,38 +174,6 @@ NS_IMETHODIMP nsWebBrowserChrome::DestroyBrowserWindow()
|
|||
return mBrowserWindow->Destroy();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Just commenting out for now because it looks like somebody went to
|
||||
a lot of work here. This method has been removed from nsIWebBrowserChrome
|
||||
per the 5 Feb 01 API review, to be handled one level further down
|
||||
in nsDocShellTreeOwner.
|
||||
*/
|
||||
NS_IMETHODIMP nsWebBrowserChrome::FindNamedBrowserItem(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem** aBrowserItem)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBrowserItem);
|
||||
*aBrowserItem = nsnull;
|
||||
|
||||
PRInt32 i = 0;
|
||||
PRInt32 n = mBrowserWindow->gBrowsers.Count();
|
||||
|
||||
nsString aNameStr(aName);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
nsBrowserWindow* bw = (nsBrowserWindow*)mBrowserWindow->gBrowsers.ElementAt(i);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(bw->mWebBrowser));
|
||||
NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
|
||||
|
||||
docShellAsItem->FindItemWithName(aName, NS_STATIC_CAST(nsIWebBrowserChrome*, this), aBrowserItem);
|
||||
|
||||
if(!*aBrowserItem)
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP nsWebBrowserChrome::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
|
||||
{
|
||||
mSizeSet = PR_TRUE;
|
||||
|
|
|
@ -165,19 +165,21 @@ NS_IMETHODIMP nsChromeTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
|
|||
//*****************************************************************************
|
||||
|
||||
NS_IMETHODIMP nsChromeTreeOwner::FindItemWithName(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem** aFoundItem)
|
||||
nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFoundItem);
|
||||
|
||||
*aFoundItem = nsnull;
|
||||
|
||||
nsAutoString name(aName);
|
||||
|
||||
PRBool fIs_Content = PR_FALSE;
|
||||
|
||||
/* Special Cases */
|
||||
if(name.IsEmpty())
|
||||
if(!aName || !*aName)
|
||||
return NS_OK;
|
||||
|
||||
nsDependentString name(aName);
|
||||
|
||||
if(name.LowerCaseEqualsLiteral("_blank"))
|
||||
return NS_OK;
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
|
@ -229,7 +231,8 @@ NS_IMETHODIMP nsChromeTreeOwner::FindItemWithName(const PRUnichar* aName,
|
|||
shellAsTreeItem->GetTreeOwner(getter_AddRefs(shellOwner));
|
||||
nsCOMPtr<nsISupports> shellOwnerSupports(do_QueryInterface(shellOwner));
|
||||
|
||||
shellAsTreeItem->FindItemWithName(aName, shellOwnerSupports, aFoundItem);
|
||||
shellAsTreeItem->FindItemWithName(aName, shellOwnerSupports,
|
||||
aOriginalRequestor, aFoundItem);
|
||||
}
|
||||
}
|
||||
if(*aFoundItem)
|
||||
|
|
|
@ -167,19 +167,21 @@ NS_IMETHODIMP nsContentTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
|
|||
//*****************************************************************************
|
||||
|
||||
NS_IMETHODIMP nsContentTreeOwner::FindItemWithName(const PRUnichar* aName,
|
||||
nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem** aFoundItem)
|
||||
nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem* aOriginalRequestor,
|
||||
nsIDocShellTreeItem** aFoundItem)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFoundItem);
|
||||
|
||||
*aFoundItem = nsnull;
|
||||
|
||||
nsAutoString name(aName);
|
||||
|
||||
PRBool fIs_Content = PR_FALSE;
|
||||
|
||||
/* Special Cases */
|
||||
if(name.IsEmpty())
|
||||
if(!aName || !*aName)
|
||||
return NS_OK;
|
||||
|
||||
nsDependentString name(aName);
|
||||
|
||||
if(name.LowerCaseEqualsLiteral("_blank"))
|
||||
return NS_OK;
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
|
@ -227,7 +229,8 @@ NS_IMETHODIMP nsContentTreeOwner::FindItemWithName(const PRUnichar* aName,
|
|||
shellAsTreeItem->GetTreeOwner(getter_AddRefs(shellOwner));
|
||||
nsCOMPtr<nsISupports> shellOwnerSupports(do_QueryInterface(shellOwner));
|
||||
|
||||
shellAsTreeItem->FindItemWithName(aName, shellOwnerSupports, aFoundItem);
|
||||
shellAsTreeItem->FindItemWithName(aName, shellOwnerSupports,
|
||||
aOriginalRequestor, aFoundItem);
|
||||
}
|
||||
if(*aFoundItem)
|
||||
return NS_OK;
|
||||
|
|
|
@ -1329,7 +1329,7 @@ nsCOMPtr<nsIDOMDocument> nsWebShellWindow::GetNamedDOMDoc(const nsAString & aDoc
|
|||
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem;
|
||||
nsCOMPtr<nsIDocShellTreeNode> docShellAsNode(do_QueryInterface(mDocShell));
|
||||
docShellAsNode->FindChildWithName(PromiseFlatString(aDocShellName).get(),
|
||||
PR_TRUE, PR_FALSE, nsnull, getter_AddRefs(docShellAsItem));
|
||||
PR_TRUE, PR_FALSE, nsnull, nsnull, getter_AddRefs(docShellAsItem));
|
||||
childDocShell = do_QueryInterface(docShellAsItem);
|
||||
if (!childDocShell)
|
||||
return domDoc;
|
||||
|
|
Загрузка…
Ссылка в новой задаче