Permalink
Browse files

Fixing bug 103638 (and bug 273699). Targets with same name in differe…

…nt 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
  • Loading branch information...
jst%mozilla.jstenback.com
jst%mozilla.jstenback.com committed Jan 11, 2005
1 parent d2fd476 commit 265b0ff136d1d8a90c9a81e15d88cfb3b4a503b0

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -368,9 +368,6 @@ friend class nsDSURIContentListener;
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)
{
@@ -2431,11 +2496,11 @@ nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
// Test whether title needs to prefixed with [script]
nsAutoString title;
if (!IsCallerChrome()) {
MakeScriptDialogTitle(aTitle, title);
MakeScriptDialogTitle(aTitle, title);
} else {
NS_WARNING("chrome shouldn't be calling prompt(), use the prompt "
"service");
title.Assign(aTitle);
NS_WARNING("chrome shouldn't be calling prompt(), use the prompt "
"service");
title.Assign(aTitle);
}
nsresult rv = prompter->Prompt(title.get(),
@@ -3116,24 +3181,17 @@ 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)
allowWindow = allowExtant;
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 @@ class nsGlobalWindow : public nsIScriptGlobalObject,
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,20 +262,21 @@ 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
}
nsresult
nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
nsIDocShellTreeItem* aRequestor,
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;
}
@@ -123,9 +123,11 @@ friend class nsCommandHandler;
NS_IMETHOD RemoveChromeListeners();
nsresult FindChildWithName(const PRUnichar *aName,
PRBool aRecurse, nsIDocShellTreeItem* aRequestor,
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)
Oops, something went wrong.

0 comments on commit 265b0ff

Please sign in to comment.