Tighten up the named-target navigation policy to better match the HTML5 spec and Safari. Bug 408052, patch by Adam Barth <hk9565@gmail.com> and Collin Jackson <mozilla@collinjackson.com>, r=jst, sr=bzbarsky.
authorbzbarsky@mit.edu
Sun, 27 Jan 2008 11:39:10 -0800
changeset 10790 b7fe99fb17fb2baa3e975e82fc15af7b5bd85a95
parent 10789 b9b8c45017a818f275b26e1fc3a3d730392047d4
child 10791 7c27175011ded678005a977c527bdabbba4d4b07
push idunknown
push userunknown
push dateunknown
reviewersjst, bzbarsky
bugs408052
milestone1.9b3pre
Tighten up the named-target navigation policy to better match the HTML5 spec and Safari. Bug 408052, patch by Adam Barth <hk9565@gmail.com> and Collin Jackson <mozilla@collinjackson.com>, r=jst, sr=bzbarsky.
docshell/base/nsDocShell.cpp
docshell/test/Makefile.in
docshell/test/navigation/Makefile.in
docshell/test/navigation/NavigationUtils.js
docshell/test/navigation/blank.html
docshell/test/navigation/iframe.html
docshell/test/navigation/navigate.html
docshell/test/navigation/open.html
docshell/test/navigation/parent.html
docshell/test/navigation/test_bug13871.html
docshell/test/navigation/test_bug270414.html
docshell/test/navigation/test_bug278916.html
docshell/test/navigation/test_bug279495.html
docshell/test/navigation/test_child.html
docshell/test/navigation/test_grandchild.html
docshell/test/navigation/test_not-opener.html
docshell/test/navigation/test_opener.html
docshell/test/navigation/test_popup-navigates-children.html
docshell/test/navigation/test_reserved.html
docshell/test/navigation/test_sibling-matching-parent.html
docshell/test/navigation/test_sibling-off-domain.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1900,58 +1900,59 @@ nsDocShell::CanAccessItem(nsIDocShellTre
     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?
 
+    // For historical context, see:
+    // 
+    // Bug 13871:  Prevent frameset spoofing
+    // Bug 103638: Targets with same name in different windows open in wrong
+    //             window with javascript
+
     // 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));
+    //
+    // Allow navigation if
+    //  1) aAccessingItem can script aTargetItem or one of its ancestors in
+    //     the frame hierarchy or
+    //  2) aTargetItem is a top-level frame and aAccessingItem is its descendant
+    //  3) aTargetItem is a top-level frame and aAccessingItem can target
+    //     its opener per rule (1) or (2).
+
+    if (aTargetItem == aAccessingItem) {
+        // A frame is allowed to navigate itself.
+        return PR_TRUE;  
+    }
 
     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
 
-    if (targetRoot == accessingRoot) {
+    if (aTargetItem == accessingRoot) {
+        // A frame can navigate its root.
         return PR_TRUE;
     }
 
+    // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
     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);
 
+    nsCOMPtr<nsIDocShellTreeItem> targetRoot;
+    aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
+
     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) {
@@ -6414,60 +6415,16 @@ nsDocShell::CheckLoadingPermissions()
             sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED;
         }
 
         nsCOMPtr<nsIDocShellTreeItem> tmp;
         item->GetSameTypeParent(getter_AddRefs(tmp));
         item.swap(tmp);
     } while (item);
 
-    // The caller is not from the same origin as this item, or any if
-    // this items ancestors. Only permit loading content if both are
-    // part of the same window, assuming we can find the window of the
-    // caller.
-
-    nsCOMPtr<nsIJSContextStack> stack =
-        do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-    if (!stack) {
-        // No context stack available. Should never happen, but in
-        // case it does, return the sameOrigin error from the security
-        // check above.
-
-        return sameOrigin;
-    }
-
-    JSContext *cx = nsnull;
-    stack->Peek(&cx);
-
-    if (!cx) {
-        // No caller docshell reachable, return the sameOrigin error
-        // from the security check above.
-
-        return sameOrigin;
-    }
-
-    nsIScriptContext *currentCX = GetScriptContextFromJSContext(cx);
-    nsCOMPtr<nsIDocShellTreeItem> callerTreeItem;
-    nsCOMPtr<nsPIDOMWindow> win;
-    if (currentCX &&
-        (win = do_QueryInterface(currentCX->GetGlobalObject())) &&
-        (callerTreeItem = do_QueryInterface(win->GetDocShell()))) {
-        nsCOMPtr<nsIDocShellTreeItem> callerRoot;
-        callerTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(callerRoot));
-
-        nsCOMPtr<nsIDocShellTreeItem> ourRoot;
-        GetSameTypeRootTreeItem(getter_AddRefs(ourRoot));
-
-        if (ourRoot == callerRoot) {
-            // The running JS is in the same window as the target
-            // frame, permit load.
-            sameOrigin = NS_OK;
-        }
-    }
-
     return sameOrigin;
 }
 
 //*****************************************************************************
 // nsDocShell: Site Loading
 //*****************************************************************************   
 class InternalLoadEvent : public nsRunnable
 {
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -40,16 +40,17 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = docshell/test
 
 MODULE = test_docshell
 
 DIRS += chrome \
 	browser \
+	navigation \
 	$(NULL)
 
 XPCSHELL_TESTS = unit
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/Makefile.in
@@ -0,0 +1,73 @@
+#
+# ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+# # The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = docshell/test/navigation
+
+MODULE = test_docshell
+
+DIRS += $(NULL)
+
+XPCSHELL_TESTS = unit
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+		test_bug13871.html \
+		test_bug270414.html \
+		test_bug278916.html \
+		test_bug279495.html \
+		test_child.html \
+		test_grandchild.html \
+		test_sibling-off-domain.html \
+		test_sibling-matching-parent.html \
+		test_opener.html \
+		test_not-opener.html \
+		test_popup-navigates-children.html \
+		test_reserved.html \
+		NavigationUtils.js \
+		navigate.html \
+		open.html \
+		iframe.html \
+		parent.html \
+		blank.html \
+		$(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -0,0 +1,231 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is NavigationUtils.js
+ *
+ * The Initial Developer of the Original Code is
+ * Stanford University
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Adam Barth <hk9565@gmail.com>
+ *   Collin Jackson <mozilla@collinjackson.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Utilities for navigation tests
+// 
+///////////////////////////////////////////////////////////////////////////
+
+var body = "This frame was navigated.";
+var target_url = "data:text/html,<html><body>" + body + "</body></html>";
+
+///////////////////////////////////////////////////////////////////////////
+// Functions that navigate frames
+///////////////////////////////////////////////////////////////////////////
+
+function navigateByLocation(wnd) {
+  try {
+    wnd.location = target_url;
+  } catch(ex) {
+    // We need to keep our finished frames count consistent.
+    // Oddly, this ends up simulating the behavior of IE7.
+    window.open(target_url, "_blank", "width=10,height=10");
+  }
+}
+
+function navigateByOpen(name) {
+  window.open(target_url, name, "width=10,height=10");
+}
+
+function navigateByForm(name) {
+  var form = document.createElement("form");
+  form.action = target_url;
+  form.method = "POST";
+  form.target = name; document.body.appendChild(form);
+  form.submit();
+}
+
+var hyperlink_count = 0;
+
+function navigateByHyperlink(name) {
+  var link = document.createElement("a");
+  link.href = target_url;
+  link.target = name;
+  link.id = "navigation_hyperlink_" + hyperlink_count++;
+  document.body.appendChild(link);
+  sendMouseEvent({type:"click"}, link.id);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Functions that call into Mochitest framework
+///////////////////////////////////////////////////////////////////////////
+
+function isNavigated(wnd, message) {
+  var result = null;
+  try {
+    result = wnd.document.body.innerHTML;
+  } catch(ex) {
+    result = ex;
+  }
+  is(result, body, message);
+}
+
+function isBlank(wnd, message) {
+  var result = null;
+  try {
+    result = wnd.document.body.innerHTML;
+  } catch(ex) {
+    result = ex;
+  }
+  is(result, "This is a blank document.", message);
+}
+
+function isAccessible(wnd, message) {
+  try {
+    wnd.document.body.innerHTML;
+    ok(true, message);
+  } catch(ex) {
+    ok(false, message);
+  }
+}
+
+function isInaccessible(wnd, message) {
+  try {
+    wnd.document.body.innerHTML;
+    ok(false, message);
+  } catch(ex) {
+    ok(true, message);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Functions that require UniversalXPConnect privilege
+///////////////////////////////////////////////////////////////////////////
+
+// Note: This only searches for top-level frames with this name.
+function xpcGetFramesByName(name) {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                     .getService(Components.interfaces.nsIWindowWatcher);
+  var enumerator = ww.getWindowEnumerator();
+
+  var results = [];
+
+  while (enumerator.hasMoreElements()) {
+    var win = enumerator.getNext();
+    var tabs = win.gBrowser.browsers;
+
+    for (var i = 0; i < tabs.length; i++) {
+      var domwindow = tabs[i].docShell.document.defaultView;
+
+      if (domwindow.name == name)
+        results.push(domwindow);
+    }
+  }
+
+  return results;
+}
+
+function xpcCleanupWindows() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                     .getService(Components.interfaces.nsIWindowWatcher);
+  var enumerator = ww.getWindowEnumerator();
+
+  while (enumerator.hasMoreElements()) {
+    var win = enumerator.getNext();
+    var tabs = win.gBrowser.browsers;
+
+    for (var i = 0; i < tabs.length; i++) {
+      var domwindow = tabs[i].docShell.document.defaultView;
+
+      if (domwindow.location.protocol == "data:")
+        domwindow.close();
+    }
+  }
+}
+
+function xpcWaitForFinishedFrames(callback, numFrames) {
+  var finishedFrameCount = 0;
+  function frameFinished() {
+    finishedFrameCount++;
+
+    if (finishedFrameCount == numFrames) {
+      clearInterval(frameWaitInterval);
+      setTimeout(callback, 1);
+      return;
+    }
+
+    if (finishedFrameCount > numFrames)
+      throw "Too many frames loaded.";
+  }
+
+  var finishedWindows = [];
+
+  function contains(obj, arr) {
+    for (var i = 0; i < arr.length; i++) {
+      if (obj === arr[i])
+        return true;
+    }
+    return false;
+  }
+
+  function searchForFinishedFrames(win) {
+    if (escape(unescape(win.location)) == escape(target_url)) {
+      if (!contains(win, finishedWindows)) {
+        finishedWindows.push(win);
+        frameFinished();
+      }
+    }
+    for (var i = 0; i < win.frames.length; i++)
+      searchForFinishedFrames(win.frames[i]);
+  }
+
+  function poll() {
+    // This only gives us UniversalXPConnect for the current stack frame
+    // We're using setInterval, so the main page's privileges are still normal
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                       .getService(Components.interfaces.nsIWindowWatcher);
+    var enumerator = ww.getWindowEnumerator();
+    while (enumerator.hasMoreElements()) {
+      var win = enumerator.getNext();
+      if (!win.gBrowser)
+        continue;  // This window hasn't finished initializing
+      var tabs = win.gBrowser.browsers;
+
+      for (var i = 0; i < tabs.length; i++) {
+        searchForFinishedFrames(tabs[i].docShell.document.defaultView);
+      }
+    }
+  }
+
+  var frameWaitInterval = setInterval(poll, 500);
+}
+
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/blank.html
@@ -0,0 +1,1 @@
+<html><body>This is a blank document.</body></html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/iframe.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<script>
+var src = window.location.hash.substring(1);
+document.write('<iframe src="' + src + '"></iframe>');
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/navigate.html
@@ -0,0 +1,30 @@
+<html>
+<head>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script src="NavigationUtils.js"></script>
+</head>
+<body>
+<script>
+var arguments = window.location.hash.substring(1).split(",");
+var target = arguments[0];
+var mechanism = arguments[1];
+
+document.write("target=" + target + " mechanism=" + mechanism);
+
+switch(mechanism) {
+case "location":
+  navigateByLocation(eval(target));
+  break;
+case "open":
+  navigateByOpen(target);
+  break;
+case "form":
+  navigateByForm(target);
+  break;
+case "hyperlink":
+  navigateByHyperlink(target);
+  break;
+}
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/open.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+<script>
+var target = window.location.hash.substring(1);
+document.write("target=" + target);
+window.open("data:text/html,<html><body>This is a popup</body></html>", target, "width=10,height=10");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/parent.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+This document contains a frame.
+<div><iframe src="blank.html"></iframe></div>
+<script>
+frames[0].name = window.name + "_child0";
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_bug13871.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function () {
+  navigateByLocation(window0.frames[0]);
+  navigateByOpen("window1_child0");
+  navigateByForm("window2_child0");
+  navigateByHyperlink("window3_child0");
+}
+
+xpcWaitForFinishedFrames(function() {
+  isInaccessible(window0.frames[0], "Should not be able to navigate off-domain frame by setting location.");
+  isInaccessible(window1.frames[0], "Should not be able to navigate off-domain frame by calling window.open.");
+  isInaccessible(window2.frames[0], "Should not be able to navigate off-domain frame by submitting form.");
+  isInaccessible(window3.frames[0], "Should not be able to navigate off-domain frame by targeted hyperlink.");
+
+  window0.close();
+  window1.close();
+  window2.close();
+  window3.close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+
+var window0 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/parent.html", "window0", "width=10,height=10");
+var window1 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/parent.html", "window1", "width=10,height=10");
+var window2 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/parent.html", "window2", "width=10,height=10");
+var window3 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/parent.html", "window3", "width=10,height=10");
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=13871">Mozilla Bug 13871</a>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_bug270414.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+var headerHTML = "<html><head>" +
+                 "<script src='/tests/SimpleTest/EventUtils.js'></scr" + "ipt>" + 
+                 "<script src='NavigationUtils.js'></scr" + "ipt>" +
+                 "</head><body>";
+var footerHTML = "</body></html>";
+
+function testChild0() {
+  if (!window.window0) {
+    window0 = window.open("", "window0", "width=10,height=10");
+    window0.document.open();
+    window0.document.write(headerHTML);
+    window0.document.write("<script>navigateByLocation(opener.frames[0])</scr" + "ipt>");
+    window0.document.write(footerHTML);
+    window0.document.close();
+  }
+}
+
+function testChild1() {
+  if (!window.window1) {
+    window1 = window.open("", "window1", "width=10,height=10");
+    window1.document.open();
+    window1.document.write(headerHTML);
+    window1.document.write("<script>navigateByOpen('child1');</scr" + "ipt>");
+    window1.document.write(footerHTML);
+    window1.document.close();
+  }
+}
+
+function testChild2() {
+  if (!window.window2) {
+    window2 = window.open("", "window2", "width=10,height=10");
+    window2.document.open();
+    window2.document.write(headerHTML);
+    window2.document.write("<script>navigateByForm('child2');</scr" + "ipt>");
+    window2.document.write(footerHTML);
+    window2.document.close();
+  }
+}
+
+function testChild3() {
+  if (!window.window3) {
+    window3 = window.open("", "window3", "width=10,height=10");
+    window3.document.open();
+    window3.document.write(headerHTML);
+    window3.document.write("<script>navigateByHyperlink('child3');</scr" + "ipt>");
+    window3.document.write(footerHTML);
+    window3.document.close();
+  }
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(frames[0], "Should be able to navigate on-domain opener's children by setting location.");
+  isNavigated(frames[1], "Should be able to navigate on-domain opener's children by calling window.open.");
+  isNavigated(frames[2], "Should be able to navigate on-domain opener's children by submitting form.");
+  isNavigated(frames[3], "Should be able to navigate on-domain opener's children by targeted hyperlink.");
+
+  window0.close();
+  window1.close();
+  window2.close();
+  window3.close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=270414">Mozilla Bug 270414</a>
+<div id="frames">
+<iframe onload="testChild0();" name="child0" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild1();" name="child1" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild2();" name="child2" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild3();" name="child3" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_bug278916.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>
+<script>
+window.onload = function () {
+  document.getElementById("link0").href = target_url;
+
+  sendMouseEvent({type:"click"}, "link0");
+}
+
+xpcWaitForFinishedFrames(function() {
+  var array_of_frames = xpcGetFramesByName("window0");
+  is(array_of_frames.length, 1, "Should only open one window using a fancy hyperlink.");
+
+  for (var i=0; i < array_of_frames.length; ++i)
+    array_of_frames[i].close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 1);
+
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=278916">Mozilla Bug 278916</a>
+<div id="links">
+<a id="link0" target="window0" onclick="window.open('', 'window0', 'width=10,height=10');">This is a fancy hyperlink</a>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_bug279495.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>
+<script>
+window.onload = function () {
+  document.getElementById("link0").href = target_url;
+  document.getElementById("link1").href = target_url;
+
+  sendMouseEvent({type:"click"}, "link0");
+  sendMouseEvent({type:"click"}, "link1");
+}
+
+function countAndClose(name, expected_count) {
+  var array_of_frames = xpcGetFramesByName(name);
+  is(array_of_frames.length, expected_count,
+     "Should only open " + expected_count +
+     " window(s) with name " + name + " using a fancy hyperlink.");
+
+  for (var i=0; i < array_of_frames.length; ++i)
+    array_of_frames[i].close();
+}
+
+xpcWaitForFinishedFrames(function() {
+  countAndClose("window0", 1);
+  countAndClose("window1", 1);
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 2);
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=279495">Mozilla Bug 279495</a>
+<div id="links">
+<a id="link0" target="window0" onclick="window.open('blank.html', 'window0', 'width=10,height=10');">This is a fancy hyperlink</a>
+<a id="link1" target="window1" onclick="window.open('http://test1.example.org:80/tests/docshell/test/navigation/blank.html', 'window1', 'width=10,height=10');">This is a fancy hyperlink</a>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_child.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function() {
+  navigateByLocation(frames[0]);
+  navigateByOpen("child1");
+  navigateByForm("child2");
+  navigateByHyperlink("child3");
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(frames[0], "Should be able to navigate off-domain child by setting location.");
+  isNavigated(frames[1], "Should be able to navigate off-domain child by calling window.open.");
+  isNavigated(frames[2], "Should be able to navigate off-domain child by submitting form.");
+  isNavigated(frames[3], "Should be able to navigate off-domain child by targeted hyperlink.");
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<div id="frames">
+<iframe name="child0" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child1" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child2" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child3" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_grandchild.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 200px; }
+    </style>
+<script>
+window.onload = function () {
+  navigateByLocation(frames[0].frames[0]);
+  navigateByOpen("child1_child0");
+  navigateByForm("child2_child0");
+  navigateByHyperlink("child3_child0");
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(frames[0].frames[0], "Should be able to navigate off-domain grandchild by setting location.");
+  isNavigated(frames[1].frames[0], "Should be able to navigate off-domain grandchild by calling window.open.");
+  isNavigated(frames[2].frames[0], "Should be able to navigate off-domain grandchild by submitting form.");
+  isNavigated(frames[3].frames[0], "Should be able to navigate off-domain grandchild by targeted hyperlink.");
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<div id="frames">
+<iframe name="child0" src="http://test1.example.org:80/tests/docshell/test/navigation/parent.html"></iframe>
+<iframe name="child1" src="http://test1.example.org:80/tests/docshell/test/navigation/parent.html"></iframe>
+<iframe name="child2" src="http://test1.example.org:80/tests/docshell/test/navigation/parent.html"></iframe>
+<iframe name="child3" src="http://test1.example.org:80/tests/docshell/test/navigation/parent.html"></iframe>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_not-opener.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function () {
+  //navigateByLocation(window0);  // Don't have a handle to the window.
+  navigateByOpen("window1");
+  navigateByForm("window2");
+  navigateByHyperlink("window3");
+}
+
+xpcWaitForFinishedFrames(function() {
+  is(xpcGetFramesByName("window1").length, 2, "Should not be able to navigate popup's popup by calling window.open.");
+  is(xpcGetFramesByName("window2").length, 2, "Should not be able to navigate popup's popup by submitting form.");
+  is(xpcGetFramesByName("window3").length, 2, "Should not be able to navigate popup's popup by targeted hyperlink.");
+
+  //opener0.close();
+  opener1.close();
+  opener2.close();
+  opener3.close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 3);
+
+//opener0 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/open.html#window0", "_blank", "width=10,height=10");
+opener1 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/open.html#window1", "_blank", "width=10,height=10");
+opener2 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/open.html#window2", "_blank", "width=10,height=10");
+opener3 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/open.html#window3", "_blank", "width=10,height=10");
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_opener.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function () {
+  navigateByLocation(window0);
+  navigateByOpen("window1");
+  navigateByForm("window2");
+  navigateByHyperlink("window3");
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(window0, "Should be able to navigate popup by setting location.");
+  isNavigated(window1, "Should be able to navigate popup by calling window.open.");
+  isNavigated(window2, "Should be able to navigate popup by submitting form.");
+  isNavigated(window3, "Should be able to navigate popup by targeted hyperlink.");
+
+  window0.close();
+  window1.close();
+  window2.close();
+  window3.close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+
+var window0 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/blank.html", "window0", "width=10,height=10");
+var window1 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/blank.html", "window1", "width=10,height=10");
+var window2 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/blank.html", "window2", "width=10,height=10");
+var window3 = window.open("http://test1.example.org:80/tests/docshell/test/navigation/blank.html", "window3", "width=10,height=10");
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_popup-navigates-children.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+function testChild0() {
+  if (!window.window0)
+    window0 = window.open("navigate.html#opener.frames[0],location", "window0", "width=10,height=10");
+}
+
+function testChild1() {
+  if (!window.window1)
+    window1 = window.open("navigate.html#child1,open", "window1", "width=10,height=10");
+}
+
+function testChild2() {
+  if (!window.window2)
+    window2 = window.open("navigate.html#child2,form", "window2", "width=10,height=10");
+}
+
+function testChild3() {
+  if (!window.window3)
+    window3 = window.open("navigate.html#child3,hyperlink", "window3", "width=10,height=10");
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(frames[0], "Should be able to navigate on-domain opener's children by setting location.");
+  isNavigated(frames[1], "Should be able to navigate on-domain opener's children by calling window.open.");
+  isNavigated(frames[2], "Should be able to navigate on-domain opener's children by submitting form.");
+  isNavigated(frames[3], "Should be able to navigate on-domain opener's children by targeted hyperlink.");
+
+  window0.close();
+  window1.close();
+  window2.close();
+  window3.close();
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+
+</script>
+</head>
+<body>
+<div id="frames">
+<iframe onload="testChild0()" name="child0" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild1()" name="child1" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild2()" name="child2" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe onload="testChild3()" name="child3" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_reserved.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 200px; }
+    </style>
+<script>
+function testTop() {
+  window0 = window.open("iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#top,location", "_blank", "width=10,height=10");
+
+  xpcWaitForFinishedFrames(function() {
+    isInaccessible(window0, "Should be able to navigate off-domain top by setting location.");
+    window0.close();
+    xpcCleanupWindows();
+
+    window1 = window.open("iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_top,open", "_blank", "width=10,height=10");
+    
+    xpcWaitForFinishedFrames(function() {
+      isInaccessible(window1, "Should be able to navigate off-domain top by calling window.open.");
+      window1.close();
+      xpcCleanupWindows();
+
+      window2 = window.open("iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_top,form", "_blank", "width=10,height=10");
+
+      xpcWaitForFinishedFrames(function() {
+        isInaccessible(window2, "Should be able to navigate off-domain top by submitting form.");
+        window2.close();
+        xpcCleanupWindows();
+
+        window3 = window.open("iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_top,hyperlink", "_blank", "width=10,height=10");
+
+        xpcWaitForFinishedFrames(function() {
+          isInaccessible(window3, "Should be able to navigate off-domain top by targeted hyperlink.");
+          window3.close();
+          xpcCleanupWindows();
+
+          testParent();
+        }, 1);
+      }, 1);
+    }, 1);
+  }, 1);
+}
+
+function testParent() {
+  document.getElementById("frames").innerHTML = '<iframe src="iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#parent,location"></iframe>';
+
+  xpcWaitForFinishedFrames(function() {
+    isAccessible(frames[0], "Should not be able to navigate off-domain parent by setting location.");
+    xpcCleanupWindows();
+
+    document.getElementById("frames").innerHTML = '<iframe src="iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_parent,open"></iframe>';
+
+    xpcWaitForFinishedFrames(function() {
+      isAccessible(frames[0], "Should not be able to navigate off-domain parent by calling window.open.");
+      xpcCleanupWindows();
+
+      document.getElementById("frames").innerHTML = '<iframe src="iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_parent,form"></iframe>';
+
+      xpcWaitForFinishedFrames(function() {
+        isAccessible(frames[0], "Should not be able to navigate off-domain parent by submitting form.");
+        xpcCleanupWindows();
+
+        document.getElementById("frames").innerHTML = '<iframe src="iframe.html#http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#_parent,hyperlink"></iframe>';
+
+        xpcWaitForFinishedFrames(function() {
+          isAccessible(frames[0], "Should not be able to navigate off-domain parent by targeted hyperlink.");
+          xpcCleanupWindows();
+
+          document.getElementById("frames").innerHTML = "";
+          SimpleTest.finish();
+        }, 1);
+      }, 1);
+    }, 1);
+  }, 1);
+}
+
+window.onload = function() {
+  testTop();
+}
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<div id="frames">
+</div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_sibling-matching-parent.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function () {
+  document.getElementById('active').innerHTML =
+      '<iframe src="navigate.html#parent.frames[0],location"></iframe>' +
+      '<iframe src="navigate.html#child1,open"></iframe>' +
+      '<iframe src="navigate.html#child2,form"></iframe>' +
+      '<iframe src="navigate.html#child3,hyperlink"></iframe>';
+}
+
+xpcWaitForFinishedFrames(function() {
+  isNavigated(frames[0], "Should be able to navigate sibling with on-domain parent by setting location.");
+  isNavigated(frames[1], "Should be able to navigate sibling with on-domain parent by calling window.open.");
+  isNavigated(frames[2], "Should be able to navigate sibling with on-domain parent by submitting form.");
+  isNavigated(frames[3], "Should be able to navigate sibling with on-domain parent by targeted hyperlink.");
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<div id="frames">
+<iframe name="child0" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child1" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child2" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+<iframe name="child3" src="http://test1.example.org:80/tests/docshell/test/navigation/blank.html"></iframe>
+</div>
+<div id="active"></div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_sibling-off-domain.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+    <script type="text/javascript" src="NavigationUtils.js"></script>        
+    <style type="text/css">
+      iframe { width: 90%; height: 50px; }
+    </style>
+<script>
+window.onload = function () {
+  document.getElementById('active').innerHTML =
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#parent.frames[0],location"></iframe>' +
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child1,open"></iframe>' +
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child2,form"></iframe>' +
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child3,hyperlink"></iframe>';
+}
+
+xpcWaitForFinishedFrames(function() {
+  isBlank(frames[0], "Should not be able to navigate off-domain sibling by setting location.");
+  isBlank(frames[1], "Should not be able to navigate off-domain sibling by calling window.open.");
+  isBlank(frames[2], "Should not be able to navigate off-domain sibling by submitting form.");
+  isBlank(frames[3], "Should not be able to navigate off-domain sibling by targeted hyperlink.");
+
+  xpcCleanupWindows();
+  SimpleTest.finish();
+}, 4);
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408052">Mozilla Bug 408052</a>
+<div id="frames">
+<iframe name="child0" src="blank.html"></iframe>
+<iframe name="child1" src="blank.html"></iframe>
+<iframe name="child2" src="blank.html"></iframe>
+<iframe name="child3" src="blank.html"></iframe>
+</div>
+<div id="active"></div>
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>