Bug 422808: remove forwarding of nsIAuthPrompt for XHR and document.load so that users fall back to the more useful docshell prompts, r=sicking, sr=biesi (r=dolske on tests)
authorgavin@gavinsharp.com
Tue, 18 Mar 2008 11:18:29 -0700
changeset 13239 912464efde6b4e6f54a0d5c570f8fb75afbfbfc0
parent 13238 484c482db80801282a2eaac982f8aa3be65c101b
child 13240 8cd7a0a39b080abb061e00f68a15b490d1033163
push idunknown
push userunknown
push dateunknown
reviewerssicking, biesi, dolske
bugs422808
milestone1.9b5pre
Bug 422808: remove forwarding of nsIAuthPrompt for XHR and document.load so that users fall back to the more useful docshell prompts, r=sicking, sr=biesi (r=dolske on tests)
content/base/src/nsXMLHttpRequest.cpp
content/xml/document/src/Makefile.in
content/xml/document/src/nsXMLDocument.cpp
toolkit/components/passwordmgr/test/Makefile.in
toolkit/components/passwordmgr/test/authenticate.sjs
toolkit/components/passwordmgr/test/prompt_common.js
toolkit/components/passwordmgr/test/test_prompt.html
toolkit/components/passwordmgr/test/test_xhr.html
toolkit/components/passwordmgr/test/test_xml_load.html
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -63,18 +63,16 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMWindow.h"
 #include "nsIVariant.h"
 #include "nsVariant.h"
 #include "nsIParser.h"
 #include "nsLoadListenerProxy.h"
-#include "nsIWindowWatcher.h"
-#include "nsIAuthPrompt.h"
 #include "nsStringStream.h"
 #include "nsIStreamConverterService.h"
 #include "nsICachingChannel.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMJSUtils.h"
 #include "nsCOMArray.h"
 #include "nsDOMClassInfo.h"
@@ -2732,44 +2730,24 @@ nsXMLHttpRequest::GetInterface(const nsI
   } else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
     mProgressEventSink = do_GetInterface(mNotificationCallbacks);
     *aResult = static_cast<nsIProgressEventSink*>(this);
     NS_ADDREF_THIS();
     return NS_OK;
   }
 
   // Now give mNotificationCallbacks (if non-null) a chance to return the
-  // desired interface.  Note that this means that it can override our
-  // nsIAuthPrompt impl, but that's fine, if it has a better auth prompt idea.
+  // desired interface.
   if (mNotificationCallbacks) {
     nsresult rv = mNotificationCallbacks->GetInterface(aIID, aResult);
     if (NS_SUCCEEDED(rv)) {
       NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
       return rv;
     }
   }
-  
-  if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {    
-    *aResult = nsnull;
-
-    nsresult rv;
-    nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
-    if (NS_FAILED(rv))
-      return rv;
-
-    nsCOMPtr<nsIAuthPrompt> prompt;
-    rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt));
-    if (NS_FAILED(rv))
-      return rv;
-
-    nsIAuthPrompt *p = prompt.get();
-    NS_ADDREF(p);
-    *aResult = p;
-    return NS_OK;
-  }
 
   return QueryInterface(aIID, aResult);
 }
 
 
 NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
 
 NS_IMETHODIMP nsXMLHttpRequest::
--- a/content/xml/document/src/Makefile.in
+++ b/content/xml/document/src/Makefile.in
@@ -61,17 +61,16 @@ REQUIRES	= xpcom \
 		  docshell \
 		  webshell \
 		  pref \
 		  xpconnect \
 		  uconv \
 		  exthandler \
 		  mimetype \
 		  unicharutil \
-		  windowwatcher \
 		  locale \
 		  util \
 		  $(NULL)
 
 CPPSRCS		= \
 		nsXMLContentSink.cpp \
 		nsXMLFragmentContentSink.cpp \
 		nsXMLDocument.cpp \
--- a/content/xml/document/src/nsXMLDocument.cpp
+++ b/content/xml/document/src/nsXMLDocument.cpp
@@ -78,17 +78,16 @@
 #include "nsCExternalHandlerService.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsIEventListenerManager.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsJSUtils.h"
 #include "nsCRT.h"
-#include "nsIWindowWatcher.h"
 #include "nsIAuthPrompt.h"
 #include "nsIScriptGlobalObjectOwner.h"
 #include "nsIJSContextStack.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventDispatcher.h"
 #include "nsNodeUtils.h"
 
@@ -237,37 +236,16 @@ nsXMLDocument::ResetToURI(nsIURI *aURI, 
 }
 
 /////////////////////////////////////////////////////
 // nsIInterfaceRequestor methods:
 //
 NS_IMETHODIMP
 nsXMLDocument::GetInterface(const nsIID& aIID, void** aSink)
 {
-  if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
-    NS_ENSURE_ARG_POINTER(aSink);
-    *aSink = nsnull;
-
-    nsresult rv;
-    nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
-    if (NS_FAILED(rv))
-      return rv;
-
-    nsCOMPtr<nsIAuthPrompt> prompt;
-    rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt));
-    if (NS_FAILED(rv))
-      return rv;
-
-    nsIAuthPrompt *p = prompt.get();
-    NS_ADDREF(p);
-    *aSink = p;
-    return NS_OK;
-  }
-
-
   return QueryInterface(aIID, aSink);
 }
 
 // nsIChannelEventSink
 NS_IMETHODIMP
 nsXMLDocument::OnChannelRedirect(nsIChannel *aOldChannel,
                                  nsIChannel *aNewChannel,
                                  PRUint32 aFlags)
--- a/toolkit/components/passwordmgr/test/Makefile.in
+++ b/toolkit/components/passwordmgr/test/Makefile.in
@@ -58,21 +58,24 @@ MOCHI_TESTS = \
 		test_basic_form_autocomplete.html \
 		test_basic_form_pwonly.html \
 		test_bug_227640.html \
 		test_bug_242956.html \
 		test_bug_360493_1.html \
 		test_bug_360493_2.html \
 		test_bug_391514.html \
 		test_prompt.html \
+		test_xhr.html \
+		test_xml_load.html \
 		test_zzz_finish.html \
 		$(NULL)
 
 MOCHI_CONTENT = \
 		pwmgr_common.js \
+		prompt_common.js \
 		authenticate.sjs \
 		$(NULL)
 
 XPCSHELL_TESTS  = unit
 
 # This test doesn't pass because we can't ensure a cross-platform
 # event that occurs between DOMContentLoaded and Pageload
 # test_bug_221634.html
--- a/toolkit/components/passwordmgr/test/authenticate.sjs
+++ b/toolkit/components/passwordmgr/test/authenticate.sjs
@@ -65,21 +65,23 @@ function reallyHandleRequest(request, re
 
   if (requestAuth) {
     response.setStatusLine("1.0", 401, "Authentication required");
     response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", false);
   } else {
     response.setStatusLine("1.0", 200, "OK");
   }
 
-  response.setHeader("Content-Type", "text/html", false);
-  response.write("Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span><br>\n");
-  response.write("Auth: <span id='auth'>" + authHeader + "</span><br>\n");
-  response.write("User: <span id='user'>" + actual_user + "</span><br>\n");
-  response.write("Pass: <span id='pass'>" + actual_pass + "</span><br>\n");
+  response.setHeader("Content-Type", "application/xhtml+xml", false);
+  response.write("<html xmlns='http://www.w3.org/1999/xhtml'>");
+  response.write("<p>Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span></p>\n");
+  response.write("<p>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
+  response.write("<p>User: <span id='user'>" + actual_user + "</span></p>\n");
+  response.write("<p>Pass: <span id='pass'>" + actual_pass + "</span></p>\n");
+  response.write("</html>");
 }
 
 
 // base64 decoder
 //
 // Yoinked from extensions/xml-rpc/src/nsXmlRpcClient.js because btoa()
 // doesn't seem to exist. :-(
 /* Convert Base64 data to a string */
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/prompt_common.js
@@ -0,0 +1,77 @@
+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+const Ci = Components.interfaces;
+ok(Ci != null, "Access Ci");
+const Cc = Components.classes;
+ok(Cc != null, "Access Cc");
+
+var didDialog;
+
+var timer; // keep in outer scope so it's not GC'd before firing
+function startCallbackTimer() {
+    didDialog = false;
+
+    // Delay before the callback twiddles the prompt.
+    const dialogDelay = 10;
+
+    // Use a timer to invoke a callback to twiddle the authentication dialog
+    timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    timer.init(observer, dialogDelay, Ci.nsITimer.TYPE_ONE_SHOT);
+}
+
+
+var observer = {
+    QueryInterface : function (iid) {
+        const interfaces = [Ci.nsIObserver,
+                            Ci.nsISupports, Ci.nsISupportsWeakReference];
+
+        if (!interfaces.some( function(v) { return iid.equals(v) } ))
+            throw Components.results.NS_ERROR_NO_INTERFACE;
+        return this;
+    },
+
+    observe : function (subject, topic, data) {
+        netscape.security.PrivilegeManager
+                         .enablePrivilege('UniversalXPConnect');
+
+        var doc = getDialogDoc();
+        if (doc)
+            handleDialog(doc, testNum);
+        else
+            startCallbackTimer(); // try again in a bit
+    }
+};
+
+function getDialogDoc() {
+  // Find the <browser> which contains notifyWindow, by looking
+  // through all the open windows and all the <browsers> in each.
+  var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
+           getService(Ci.nsIWindowMediator);
+  //var enumerator = wm.getEnumerator("navigator:browser");
+  var enumerator = wm.getXULWindowEnumerator(null);
+
+  while (enumerator.hasMoreElements()) {
+    var win = enumerator.getNext();
+    var windowDocShell = win.QueryInterface(Ci.nsIXULWindow).docShell;
+
+    var containedDocShells = windowDocShell.getDocShellEnumerator(
+                                      Ci.nsIDocShellTreeItem.typeChrome,
+                                      Ci.nsIDocShell.ENUMERATE_FORWARDS);
+    while (containedDocShells.hasMoreElements()) {
+        // Get the corresponding document for this docshell
+        var childDocShell = containedDocShells.getNext();
+        // We don't want it if it's not done loading.
+        if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
+          continue;
+        var childDoc = childDocShell.QueryInterface(Ci.nsIDocShell)
+                                    .contentViewer
+                                    .DOMDocument;
+
+        //ok(true, "Got window: " + childDoc.location.href);
+        if (childDoc.location.href == "chrome://global/content/commonDialog.xul")
+          return childDoc;
+    }
+  }
+
+  return null;
+}
--- a/toolkit/components/passwordmgr/test/test_prompt.html
+++ b/toolkit/components/passwordmgr/test/test_prompt.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test for Login Manager</title>
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
   <script type="text/javascript" src="pwmgr_common.js"></script>
+  <script type="text/javascript" src="prompt_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: username/password prompts
 <p id="display"></p>
 
 <div id="content" style="display: none">
   <iframe id="iframe"></iframe>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: username / password prompts. **/
+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
 var pwmgr, login1, login2A, login2B, login3A, login3B;
 
 function initLogins() {
   pwmgr = Cc["@mozilla.org/login-manager;1"].
           getService(Ci.nsILoginManager);
 
   login1  = Cc["@mozilla.org/login-manager/loginInfo;1"].
@@ -62,53 +64,16 @@ function finishTest() {
   pwmgr.removeLogin(login2A);
   pwmgr.removeLogin(login2B);
   pwmgr.removeLogin(login3A);
   pwmgr.removeLogin(login3B);
 
   SimpleTest.finish();
 }
 
-
-function getDialogDoc() {
-  // Find the <browser> which contains notifyWindow, by looking
-  // through all the open windows and all the <browsers> in each.
-  var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
-           getService(Ci.nsIWindowMediator);
-  //var enumerator = wm.getEnumerator("navigator:browser");
-  var enumerator = wm.getXULWindowEnumerator(null);
-
-  while (enumerator.hasMoreElements()) {
-    var win = enumerator.getNext();
-    var windowDocShell = win.QueryInterface(Ci.nsIXULWindow).docShell;
-
-    var containedDocShells = windowDocShell.getDocShellEnumerator(
-                                      Ci.nsIDocShellTreeItem.typeChrome,
-                                      Ci.nsIDocShell.ENUMERATE_FORWARDS);
-    while (containedDocShells.hasMoreElements()) {
-        // Get the corresponding document for this docshell
-        var childDocShell = containedDocShells.getNext();
-        // We don't want it if it's not done loading.
-        if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
-          continue;
-        var childDoc = childDocShell.QueryInterface(Ci.nsIDocShell)
-                                    .contentViewer
-                                    .DOMDocument;
-
-        //ok(true, "Got window: " + childDoc.location.href);
-        if (childDoc.location.href == "chrome://global/content/commonDialog.xul")
-          return childDoc;
-    }
-  }
-
-  return null;
-}
-
-
-var didDialog;
 function handleDialog(doc, testNum) {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   ok(true, "handleDialog running for test " + testNum);
 
   var clickOK = true;
   var userfield = doc.getElementById("loginTextbox");
   var passfield = doc.getElementById("password1Textbox");
   var username = userfield.getAttribute("value");
@@ -335,94 +300,49 @@ function handleLoad() {
 
     default:
         ok(false, "Uhh, unhandled switch for testNum #" + testNum);
         break;
   }
 
 }
 
-
-netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-
-const Ci = Components.interfaces;
-ok(Ci != null, "Access Ci");
-const Cc = Components.classes;
-ok(Cc != null, "Access Cc");
-
 initLogins();
 
-const Cc_promptFac= Cc["@mozilla.org/passwordmanager/authpromptfactory;1"];
-ok(Cc_promptFac != null, "Access Cc[@mozilla.org/passwordmanager/authpromptfactory;1]");
-
-const Ci_promptFac = Ci.nsIPromptFactory;
-ok(Ci_promptFac != null, "Access Ci.nsIPromptFactory");
-
-const promptFac = Cc_promptFac.getService(Ci_promptFac);
-ok(promptFac != null, "promptFac getService()");
-
-
-var timer; // keep in outer scope so it's not GC'd before firing
-function startCallbackTimer() {
-    didDialog = false;
-
-    // Delay before the callback twiddles the prompt.
-    const dialogDelay = 10;
-
-    // Use a timer to invoke a callback to twiddle the authentication dialog
-    timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    timer.init(observer, dialogDelay, Ci.nsITimer.TYPE_ONE_SHOT);
-}
-
-
-var observer = {
-    QueryInterface : function (iid) {
-        const interfaces = [Ci.nsIObserver,
-                            Ci.nsISupports, Ci.nsISupportsWeakReference];
-
-        if (!interfaces.some( function(v) { return iid.equals(v) } ))
-            throw Components.results.NS_ERROR_NO_INTERFACE;
-        return this;
-    },
-
-    observe : function (subject, topic, data) {
-        netscape.security.PrivilegeManager
-                         .enablePrivilege('UniversalXPConnect');
-
-        var doc = getDialogDoc();
-        if (doc)
-            handleDialog(doc, testNum);
-        else
-            startCallbackTimer(); // try again in a bit
-    }
-};
-
-
 var authinfo = {
     // QueryInterface : ... ?
     username : "",
     password : "",
     domain   : "",
 
     flags : Ci.nsIAuthInformation.AUTH_HOST,
     authenticationScheme : "basic",
     realm : ""
 };
 
+const Cc_promptFac= Cc["@mozilla.org/passwordmanager/authpromptfactory;1"];
+ok(Cc_promptFac != null, "Access Cc[@mozilla.org/passwordmanager/authpromptfactory;1]");
+
+const Ci_promptFac = Ci.nsIPromptFactory;
+ok(Ci_promptFac != null, "Access Ci.nsIPromptFactory");
+
+const promptFac = Cc_promptFac.getService(Ci_promptFac);
+ok(promptFac != null, "promptFac getService()");
 
 var prompter1 = promptFac.getPrompt(window, Ci.nsIAuthPrompt);
 var prompter2 = promptFac.getPrompt(window, Ci.nsIAuthPrompt2);
 
 function dialogTitle() { return "nsILoginManagerPrompter test #" + testNum; }
 var dialogText  = "This dialog should be modified and dismissed by the test.";
 var uname  = { value : null };
 var pword  = { value : null };
 var result = { value : null };
 var isOk;
 
+// XXX Add test for host that doesn't yet exist to test login-saving logic
 
 // ===== test 1 ===== 
 var testNum = 1;
 startCallbackTimer();
 isOk = prompter1.prompt(dialogTitle(), dialogText, "http://example.com",
                         Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
 
 ok(isOk, "Checking dialog return value (accept)");
@@ -762,20 +682,25 @@ is(authinfo.password, "user2pass", "Chec
 // XXX check for and kill notification bar??
 // XXX check for checkbox / checkstate on old prompts?
 // XXX check NTLM domain stuff
 
 
 var iframe = document.getElementById("iframe");
 iframe.onload = handleLoad;
 
+// clear plain HTTP auth sessions before the test, to allow
+// running them more than once.
+var authMgr = Components.classes['@mozilla.org/network/http-auth-manager;1']
+                        .getService(Components.interfaces.nsIHttpAuthManager);
+authMgr.clearAll();
 
 // ===== test 1000 =====
 testNum = 1000;
 startCallbackTimer();
 iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
 
-// ...remaining tests are drived by handleLoad()...
+// ...remaining tests are driven by handleLoad()...
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/test_xhr.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Login Manager</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
+  <script type="text/javascript" src="pwmgr_common.js"></script>
+  <script type="text/javascript" src="prompt_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Login Manager test: XHR prompt
+<p id="display"></p>
+
+<div id="content" style="display: none">
+  <iframe id="iframe"></iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Login Manager: XHR prompts. **/
+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+var pwmgr, login1, login2;
+
+function initLogins() {
+  pwmgr = Cc["@mozilla.org/login-manager;1"].
+          getService(Ci.nsILoginManager);
+
+  login1 = Cc["@mozilla.org/login-manager/loginInfo;1"].
+            createInstance(Ci.nsILoginInfo);
+  login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].
+            createInstance(Ci.nsILoginInfo);
+
+  login1.init("http://localhost:8888", null, "xhr",
+               "xhruser1", "xhrpass1", "", "");
+  login2.init("http://localhost:8888", null, "xhr2",
+               "xhruser2", "xhrpass2", "", "");
+
+  pwmgr.addLogin(login1);
+  pwmgr.addLogin(login2);
+}
+
+function finishTest() {
+  ok(true, "finishTest removing testing logins...");
+  pwmgr.removeLogin(login1);
+  pwmgr.removeLogin(login2);
+
+  SimpleTest.finish();
+}
+
+function handleDialog(doc, testNum) {
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+  ok(true, "handleDialog running for test " + testNum);
+
+  var clickOK = true;
+  var userfield = doc.getElementById("loginTextbox");
+  var passfield = doc.getElementById("password1Textbox");
+  var username = userfield.getAttribute("value");
+  var password = passfield.getAttribute("value");
+  var dialog    = doc.getElementById("commonDialog");
+
+  switch(testNum) {
+    case 1:
+        is(username, "xhruser1", "Checking provided username");
+        is(password, "xhrpass1", "Checking provided password");
+        break;
+
+    case 2:
+        is(username, "xhruser2", "Checking provided username");
+        is(password, "xhrpass2", "Checking provided password");
+
+        // Check that the dialog has the correct parent
+        ok(doc.defaultView.opener, "dialog has opener");
+        // Not using is() because its "expected" text doesn't deal
+        // with window objects very well 
+        ok(doc.defaultView.opener == window, "dialog's opener is correct");
+
+        break;
+
+    default:
+        ok(false, "Uhh, unhandled switch for testNum #" + testNum);
+        break;
+  }
+
+  // Explicitly cancel the dialog and report a fail in this failure
+  // case, rather than letting the dialog get stuck due to an auth
+  // failure and having the test timeout.
+  if (!username && !password) {
+      ok(false, "No values prefilled");
+      clickOK = false;
+  }
+
+  if (clickOK)
+    dialog.acceptDialog();
+  else
+    dialog.cancelDialog();
+
+  ok(true, "handleDialog done");
+  didDialog = true;
+}
+
+var newWin;
+function xhrLoad(xmlDoc) {
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+  ok(true, "xhrLoad running for test " + testNum);
+
+  // The server echos back the user/pass it received.
+  var username = xmlDoc.getElementById("user").textContent;
+  var password = xmlDoc.getElementById("pass").textContent;
+  var authok = xmlDoc.getElementById("ok").textContent;
+
+
+  switch(testNum) {
+    case 1:
+        is(username, "xhruser1", "Checking provided username");
+        is(password, "xhrpass1", "Checking provided password");
+        break;
+
+    case 2:
+        is(username, "xhruser2", "Checking provided username");
+        is(password, "xhrpass2", "Checking provided password");
+
+        newWin.close();
+        break;
+
+    default:
+        ok(false, "Uhh, unhandled switch for testNum #" + testNum);
+        break;
+  }
+  
+  doTest();
+}
+
+function doTest() {
+  switch(++testNum) {
+    case 1:
+        startCallbackTimer();
+        makeRequest("authenticate.sjs?user=xhruser1&pass=xhrpass1&realm=xhr");
+        break;
+        
+    case 2:
+        // Test correct parenting, by opening another window and
+        // making sure the prompt's opener is correct
+        newWin = window.open();
+        newWin.focus();
+        startCallbackTimer();
+        makeRequest("authenticate.sjs?user=xhruser2&pass=xhrpass2&realm=xhr2");
+        break;
+
+    default:
+        finishTest();
+  }
+}
+
+function makeRequest(uri) {
+  var request = new XMLHttpRequest();
+  request.open("GET", uri, true);
+  request.onreadystatechange = function () {
+    if (request.readyState == 4)
+      xhrLoad(request.responseXML);
+  };
+  request.send(null);
+}
+
+
+initLogins();
+
+// clear plain HTTP auth sessions before the test, to allow
+// running them more than once.
+var authMgr = Components.classes['@mozilla.org/network/http-auth-manager;1']
+                        .getService(Components.interfaces.nsIHttpAuthManager);
+authMgr.clearAll();
+
+// start the tests
+testNum = 0;
+doTest();
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/test_xml_load.html
@@ -0,0 +1,183 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Login Manager</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
+  <script type="text/javascript" src="pwmgr_common.js"></script>
+  <script type="text/javascript" src="prompt_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Login Manager test: XML prompt
+<p id="display"></p>
+
+<div id="content" style="display: none">
+  <iframe id="iframe"></iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Login Manager: XML prompts. **/
+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+var pwmgr, login1, login2;
+
+function initLogins() {
+  pwmgr = Cc["@mozilla.org/login-manager;1"].
+          getService(Ci.nsILoginManager);
+
+  login1 = Cc["@mozilla.org/login-manager/loginInfo;1"].
+            createInstance(Ci.nsILoginInfo);
+  login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].
+            createInstance(Ci.nsILoginInfo);
+
+  login1.init("http://localhost:8888", null, "xml",
+               "xmluser1", "xmlpass1", "", "");
+  login2.init("http://localhost:8888", null, "xml2",
+               "xmluser2", "xmlpass2", "", "");
+
+  pwmgr.addLogin(login1);
+  pwmgr.addLogin(login2);
+}
+
+function finishTest() {
+  ok(true, "finishTest removing testing logins...");
+  pwmgr.removeLogin(login1);
+  pwmgr.removeLogin(login2);
+
+  SimpleTest.finish();
+}
+
+function handleDialog(doc, testNum) {
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+  ok(true, "handleDialog running for test " + testNum);
+
+  var clickOK = true;
+  var userfield = doc.getElementById("loginTextbox");
+  var passfield = doc.getElementById("password1Textbox");
+  var username = userfield.getAttribute("value");
+  var password = passfield.getAttribute("value");
+  var dialog    = doc.getElementById("commonDialog");
+
+  switch(testNum) {
+    case 1:
+        is(username, "xmluser1", "Checking provided username");
+        is(password, "xmlpass1", "Checking provided password");
+        break;
+
+    case 2:
+        is(username, "xmluser2", "Checking provided username");
+        is(password, "xmlpass2", "Checking provided password");
+
+        // Check that the dialog has the correct parent
+        ok(doc.defaultView.opener, "dialog has opener");
+        // Not using is() because its "expected" text doesn't deal
+        // with window objects very well 
+        ok(doc.defaultView.opener == window, "dialog's opener is correct");
+
+        break;
+
+    default:
+        ok(false, "Uhh, unhandled switch for testNum #" + testNum);
+        break;
+  }
+
+  // Explicitly cancel the dialog and report a fail in this failure
+  // case, rather than letting the dialog get stuck due to an auth
+  // failure and having the test timeout.
+  if (!username && !password) {
+      ok(false, "No values prefilled");
+      clickOK = false;
+  }
+
+  if (clickOK)
+    dialog.acceptDialog();
+  else
+    dialog.cancelDialog();
+
+  ok(true, "handleDialog done");
+  didDialog = true;
+}
+
+var newWin;
+function xmlLoad(responseDoc) {
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+  ok(true, "xmlLoad running for test " + testNum);
+
+  // The server echos back the user/pass it received.
+  var username = responseDoc.getElementById("user").textContent;
+  var password = responseDoc.getElementById("pass").textContent;
+  var authok = responseDoc.getElementById("ok").textContent;
+
+  switch(testNum) {
+    case 1:
+        is(username, "xmluser1", "Checking provided username");
+        is(password, "xmlpass1", "Checking provided password");
+        break;
+
+    case 2:
+        is(username, "xmluser2", "Checking provided username");
+        is(password, "xmlpass2", "Checking provided password");
+
+        newWin.close();
+        break;
+
+    default:
+        ok(false, "Uhh, unhandled switch for testNum #" + testNum);
+        break;
+  }
+  
+  doTest();
+}
+
+function doTest() {
+  switch(++testNum) {
+    case 1:
+        startCallbackTimer();
+        makeRequest("authenticate.sjs?user=xmluser1&pass=xmlpass1&realm=xml");
+        break;
+
+    case 2:
+        // Test correct parenting, by opening another window and
+        // making sure the prompt's opener is correct
+        newWin = window.open();
+        newWin.focus();
+        startCallbackTimer();
+        makeRequest("authenticate.sjs?user=xmluser2&pass=xmlpass2&realm=xml2");
+        break;
+
+    default:
+        finishTest();
+  }
+}
+
+function makeRequest(uri) {
+  var xmlDoc = document.implementation.createDocument("", "test", null);
+
+  function documentLoaded(e) {
+      xmlLoad(xmlDoc);
+  }
+  xmlDoc.addEventListener("load", documentLoaded, false);
+  xmlDoc.load(uri);
+}
+
+
+initLogins();
+
+// clear plain HTTP auth sessions before the test, to allow
+// running them more than once.
+var authMgr = Components.classes['@mozilla.org/network/http-auth-manager;1']
+                        .getService(Components.interfaces.nsIHttpAuthManager);
+authMgr.clearAll();
+
+// start the tests
+testNum = 0;
+doTest();
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>