Bug 605296 part 2. Make username/password stringify undefined to empty string. r=sicking, a=blocker
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 30 Nov 2010 13:18:15 -0500
changeset 58473 251cd89364a8e08eaa956de02fd279f5eca118bd
parent 58472 43437276f9f174878ac212b6c03eb4efa831ac20
child 58474 7ab0eb4c345b12838f45bfe19f3088be8025215a
push id17312
push userbzbarsky@mozilla.com
push dateThu, 02 Dec 2010 12:19:10 +0000
treeherdermozilla-central@251cd89364a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking, blocker
bugs605296
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 605296 part 2. Make username/password stringify undefined to empty string. r=sicking, a=blocker
content/base/public/nsIXMLHttpRequest.idl
content/base/test/file_CrossSiteXHR_inner.html
content/base/test/test_CrossSiteXHR.html
js/src/xpconnect/src/dom_quickstubs.qsconf
--- a/content/base/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -237,18 +237,18 @@ interface nsIXMLHttpRequest : nsISupport
    *              be thrown.
    * @param user (optional) A username for authentication if necessary.
    *             The default value is the empty string
    * @param password (optional) A password for authentication if necessary.
    *                 The default value is the empty string
    */
   [optional_argc] void open(in AUTF8String method, in AUTF8String url,
                             [optional] in boolean async,
-                            [optional] in DOMString user,
-                            [optional] in DOMString password);
+                            [optional,Undefined(Empty)] in DOMString user,
+                            [optional,Undefined(Empty)] in DOMString password);
 
   /**
    * Sends the request. If the request is asynchronous, returns
    * immediately after sending the request. If it is synchronous
    * returns only after the response has been received.
    *
    * All event listeners must be set before calling send().
    *
--- a/content/base/test/file_CrossSiteXHR_inner.html
+++ b/content/base/test/file_CrossSiteXHR_inner.html
@@ -11,17 +11,22 @@
 window.addEventListener("message", function(e) {
 
   sendData = null;
 
   req = eval(e.data);
   var res = {
     didFail: false,
     events: [],
-    progressEvents: 0
+    progressEvents: 0,
+    status: 0,
+    responseText: "",
+    statusText: "",
+    responseXML: null,
+    sendThrew: false
   };
   
   var xhr = new XMLHttpRequest();
   for each(type in ["load", "abort", "error", "loadstart"]) {
     xhr.addEventListener(type, function(e) {
       res.events.push(e.type);
     }, false);
   }
@@ -46,16 +51,17 @@ window.addEventListener("message", funct
   xhr.onload = xhr.onerror = function (event) {
     if (event.type == "error") {
       res.didFail = true;
     }
     res.status = xhr.status;
     try {
       res.statusText = xhr.statusText;
     } catch (e) {
+      delete(res.statusText);
     }
     res.responseXML = xhr.responseXML ?
       (new XMLSerializer()).serializeToString(xhr.responseXML) :
       null;
     res.responseText = xhr.responseText;
 
     res.responseHeaders = {};
     for (responseHeader in req.responseHeaders) {
@@ -67,24 +73,38 @@ window.addEventListener("message", funct
   }
 
   if (req.withCred)
     xhr.withCredentials = true;
   if (req.body)
     sendData = req.body;
 
   res.events.push("opening");
-  xhr.open(req.method, req.url, true);
+  // Allow passign in falsy usernames/passwords so we can test them
+  try {
+    xhr.open(req.method, req.url, true,
+             ("username" in req) ? req.username : "",
+             ("password" in req) ? req.password : "aa");
+  } catch (ex) {
+    res.didFail = true;
+    post(e, res);
+  }
 
   for (header in req.headers) {
     xhr.setRequestHeader(header, req.headers[header]);
   }
 
   res.events.push("sending");
-  xhr.send(sendData);
+  try {
+    xhr.send(sendData);
+  } catch (ex) {
+    res.didFail = true;
+    res.sendThrew = true;
+    post(e, res);
+  }
 
 }, false);
 
 function post(e, res) {
   e.source.postMessage(res.toSource(), "http://mochi.test:8888");
 }
 
 </script>
--- a/content/base/test/test_CrossSiteXHR.html
+++ b/content/base/test/test_CrossSiteXHR.html
@@ -44,16 +44,47 @@ function runTest() {
   yield;
 
   tests =     [// Plain request
                { pass: 1,
                  method: "GET",
                  noAllowPreflight: 1,
                },
 
+               // undefined username
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: undefined
+               },
+
+               // undefined username and password
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: undefined,
+                 password: undefined
+               },
+
+               // nonempty username
+               { pass: 0,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: "user",
+               },
+
+               // nonempty password
+               // XXXbz this passes for now, because we ignore passwords
+               // without usernames in most cases.
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 password: "password",
+               },
+
                // Default allowed headers
                { pass: 1,
                  method: "GET",
                  headers: { "Content-Type": "text/plain",
                             "Accept": "foo/bar",
                             "Accept-Language": "sv-SE" },
                  noAllowPreflight: 1,
                },
@@ -552,16 +583,24 @@ function runTest() {
       responseHeaders: test.responseHeaders,
     };
 
     if (test.pass) {
        req.url += "&origin=" + escape(origin) +
                   "&requestMethod=" + test.method;
     }
 
+    if ("username" in test) {
+      req.username = test.username;
+    }
+
+    if ("password" in test) {
+      req.password = test.password;
+    }
+
     if (test.noAllowPreflight)
       req.url += "&noAllowPreflight";
 
     if (test.pass && "headers" in test) {
       function isUnsafeHeader(name) {
         lName = name.toLowerCase();
         return lName != "accept" &&
                lName != "accept-language" &&
@@ -643,24 +682,26 @@ function runTest() {
           }
         }
       }
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
-      is(res.events.join(","),
-         "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
-         "wrong events in test for " + test.toSource());
+      if (!res.sendThrew) {
+        is(res.events.join(","),
+           "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
+           "wrong events in test for " + test.toSource());
+      }
       is(res.progressEvents, 0,
          "wrong events in test for " + test.toSource());
       if (test.responseHeaders) {
         for (header in test.responseHeaders) {
           is(res.responseHeaders[header], null,
              "wrong response header (" + header + ") in test for " +
              test.toSource());
         }
@@ -783,17 +824,17 @@ function runTest() {
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs3,rs4,load",
          "wrong responseText in test for " + test.toSource());
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
@@ -1052,17 +1093,17 @@ function runTest() {
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs3,rs4,load",
          "wrong responseText in test for " + test.toSource());
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
--- a/js/src/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/src/xpconnect/src/dom_quickstubs.qsconf
@@ -422,18 +422,16 @@ members = [
     'nsIBoxObject.width',
     'nsIBoxObject.height',
 
     # XHR
     'nsIXMLHttpRequest.*',
     # nsIXMLHttpRequest.channel is not used on the web, and more
     # importantly relies on the CAPS check that quickstubs don't make.
     '-nsIXMLHttpRequest.channel',
-    # nsIXMLHttpRequest.open uses the JS stack
-    '-nsIXMLHttpRequest.open',
     # various XHR things use ACString and AUTF8String and [cstring]
     # which quickstubs don't handle as return values (or at all in the
     # case of AUTF8String) yet.
     '-nsIXMLHttpRequest.statusText',
     '-nsIXMLHttpRequest.getAllResponseHeaders',
     '-nsIXMLHttpRequest.getResponseHeader',
     '-nsIXMLHttpRequest.setRequestHeader',
     '-nsIXMLHttpRequest.overrideMimeType',