Bug 471906 - Login manager's onblur handler shouldn't do anything when the username is blank. r=gavin
authorJustin Dolske <dolske@mozilla.com>
Tue, 12 May 2009 12:09:18 -0700
changeset 28250 e1c90e99be30db4cb3280e372ea3220d9cc589fe
parent 28249 699b32591a665c09f6d6af71e1d62bebb9b3d3ae
child 28251 dee2ce1fce39dc32991866321d292425d37b02db
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin
bugs471906
milestone1.9.2a1pre
Bug 471906 - Login manager's onblur handler shouldn't do anything when the username is blank. r=gavin
toolkit/components/passwordmgr/src/nsLoginManager.js
toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
--- a/toolkit/components/passwordmgr/src/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/src/nsLoginManager.js
@@ -355,16 +355,23 @@ LoginManager.prototype = {
                 case "DOMContentLoaded":
                     this._pwmgr._fillDocument(event.target);
                     return;
 
                 case "DOMAutoComplete":
                 case "blur":
                     var acInputField = event.target;
                     var acForm = acInputField.form;
+
+                    // If the username is blank, bail out now -- we don't want
+                    // fillForm() to try filling in a login without a username
+                    // to filter on (bug 471906).
+                    if (!acInputField.value)
+                        return;
+
                     // Make sure the username field fillForm will use is the
                     // same field as the autocomplete was activated on. If
                     // not, the DOM has been altered and we'll just give up.
                     var [usernameField, passwordField, ignored] =
                         this._pwmgr._getFormFields(acForm, false);
                     if (usernameField == acInputField && passwordField) {
                         // Clobber any existing password.
                         passwordField.value = "";
@@ -613,19 +620,23 @@ LoginManager.prototype = {
 
             var doc = aElement.ownerDocument;
             var origin = this._getPasswordOrigin(doc.documentURI);
             var actionOrigin = this._getActionOrigin(aElement.form);
 
             var logins = this.findLogins({}, origin, actionOrigin, null);
             var matchingLogins = [];
 
+            // Filter out logins that don't match the search prefix. Also
+            // filter logins without a username, since that's confusing to see
+            // in the dropdown and we can't autocomplete them anyway.
             for (i = 0; i < logins.length; i++) {
                 var username = logins[i].username.toLowerCase();
-                if (aSearchString.length <= username.length &&
+                if (username &&
+                    aSearchString.length <= username.length &&
                     aSearchString.toLowerCase() ==
                         username.substr(0, aSearchString.length))
                 {
                     matchingLogins.push(logins[i]);
                 }
             }
             this.log(matchingLogins.length + " autocomplete logins avail.");
             result = new UserAutoCompleteResult(aSearchString, matchingLogins);
--- a/toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
+++ b/toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
@@ -11,24 +11,27 @@
 -->
 <form id="form" action="formsubmit.sjs">
   <input id="user" name="user" type="text">
   <input id="pass" name="pass" type="password">
   <button type='submit'>Submit</button>
 </form>
 
 <script>
-function submitForm() {
+function startAutocomplete() {
   userField.focus();
   doKey("down");
+  setTimeout(submitForm, 100);
+}
+
+function submitForm() {
   doKey("down");
   doKey("return");
-
   setTimeout(function(){ form.submit(); }, 100);
 }
 
-window.onload = submitForm;
+window.onload = startAutocomplete;
 var form      = document.getElementById("form");
 var userField = document.getElementById("user");
 
 </script>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
@@ -55,16 +55,23 @@ Login Manager test: multiple login autoc
   </form>
 
   <!-- This form will be manipulated to insert a different username field. -->
   <form id="form7" action="http://autocomplete3" onsubmit="return false;">
     <input  type="text"       name="uname">
     <input  type="password"   name="pword">
     <button type="submit">Submit</button>
   </form>
+
+  <!-- test for no autofill after onblur with blank username -->
+  <form id="form8" action="http://autocomplete4" onsubmit="return false;">
+    <input  type="text"       name="uname">
+    <input  type="password"   name="pword">
+    <button type="submit">Submit</button>
+  </form>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
@@ -80,16 +87,21 @@ ok(pwmgr != null, "nsLoginManager servic
 
 // Create some logins just for this form, since we'll be deleting them.
 var nsLoginInfo =
 Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
                        Components.interfaces.nsILoginInfo, "init");
 ok(nsLoginInfo != null, "nsLoginInfo constructor");
 
 
+// login0 has no username, so should be filtered out from the autocomplete list.
+var login0 = new nsLoginInfo(
+    "http://localhost:8888", "http://autocomplete:8888", null,
+    "", "user0pass", "", "pword");
+
 var login1 = new nsLoginInfo(
     "http://localhost:8888", "http://autocomplete:8888", null,
     "tempuser1", "temppass1", "uname", "pword");
 
 var login2 = new nsLoginInfo(
     "http://localhost:8888", "http://autocomplete:8888", null,
     "testuser2", "testpass2", "uname", "pword");
 
@@ -108,25 +120,30 @@ var login5 = new nsLoginInfo(
 
 var login6A = new nsLoginInfo(
     "http://localhost:8888", "http://autocomplete3", null,
     "form7user1", "form7pass1", "uname", "pword");
 var login6B = new nsLoginInfo(
     "http://localhost:8888", "http://autocomplete3", null,
     "form7user2", "form7pass2", "uname", "pword");
 
+var login7  = new nsLoginInfo(
+    "http://localhost:8888", "http://autocomplete4", null,
+    "form8user", "form8pass", "uname", "pword");
 // try/catch in case someone runs the tests manually, twice.
 try {
+    pwmgr.addLogin(login0);
     pwmgr.addLogin(login1);
     pwmgr.addLogin(login2);
     pwmgr.addLogin(login3);
     pwmgr.addLogin(login4);
     pwmgr.addLogin(login5);
     pwmgr.addLogin(login6A);
     pwmgr.addLogin(login6B);
+    pwmgr.addLogin(login7);
 } catch (e) {
     ok(false, "addLogin threw: " + e);
 }
 
 
 // Restore the form to the default state.
 function restoreForm() {
     uname.value = "";
@@ -342,25 +359,25 @@ function runTest(testNum) {
     // driver, so I'm not sure what's up.
 
 
     case 50:
         // Delete the first entry (of 4), "tempuser1"
         doKey("down");
         var numLogins;
         numLogins = pwmgr.countLogins("http://localhost:8888", "http://autocomplete:8888", null);
-        is(numLogins, 4, "Correct number of logins before deleting one");
+        is(numLogins, 5, "Correct number of logins before deleting one");
 
         // On OS X, shift-backspace and shift-delete work, just delete does not.
         // On Win/Linux, shift-backspace does not work, delete and shift-delete do.
         doKey("delete", shiftModifier);
 
         checkACForm("", "");
         numLogins = pwmgr.countLogins("http://localhost:8888", "http://autocomplete:8888", null);
-        is(numLogins, 3, "Correct number of logins after deleting one");
+        is(numLogins, 4, "Correct number of logins after deleting one");
         doKey("return");
         checkACForm("testuser2", "testpass2");
 
         // Trigger autocomplete popup
         restoreForm();
         doKey("down");
         break;
 
@@ -377,17 +394,17 @@ function runTest(testNum) {
 
     case 52:
         // Delete the second entry (of 3), "testuser3"
         doKey("down");
         doKey("down");
         doKey("delete", shiftModifier);
         checkACForm("", "");
         numLogins = pwmgr.countLogins("http://localhost:8888", "http://autocomplete:8888", null);
-        is(numLogins, 2, "Correct number of logins after deleting one");
+        is(numLogins, 3, "Correct number of logins after deleting one");
         doKey("return");
         checkACForm("zzzuser4", "zzzpass4");
 
         // Trigger autocomplete popup
         restoreForm();
         doKey("down");
         break;
 
@@ -404,17 +421,17 @@ function runTest(testNum) {
 
     case 54:
         // Delete the last entry (of 2), "zzzuser4"
         doKey("down");
         doKey("down");
         doKey("delete", shiftModifier);
         checkACForm("", "");
         numLogins = pwmgr.countLogins("http://localhost:8888", "http://autocomplete:8888", null);
-        is(numLogins, 1, "Correct number of logins after deleting one");
+        is(numLogins, 2, "Correct number of logins after deleting one");
         doKey("return");
         checkACForm("testuser2", "testpass2");
 
         // Trigger autocomplete popup
         restoreForm();
         doKey("down");
         break;
 
@@ -431,17 +448,18 @@ function runTest(testNum) {
 
     case 56:
         // Delete the only remaining entry, "testuser2"
         doKey("down");
         doKey("delete", shiftModifier);
         //doKey("return");
         checkACForm("", "");
         numLogins = pwmgr.countLogins("http://localhost:8888", "http://autocomplete:8888", null);
-        is(numLogins, 0, "Correct number of logins after deleting one");
+        is(numLogins, 1, "Correct number of logins after deleting one");
+        pwmgr.removeLogin(login0); // remove the login that's not shown in the list.
         testNum = 99;
         break;
 
 
     /* Tests for single-user forms with autocomplete=off */
 
     case 100:
         // Turn our attention to form2
@@ -455,16 +473,17 @@ function runTest(testNum) {
         break;
 
     case 101:
         // Check first entry
         doKey("down");
         checkACForm("", ""); // value shouldn't update
         doKey("return"); // not "enter"!
         checkACForm("singleuser5", "singlepass5");
+        restoreForm(); // clear field, so reloading test doesn't fail
         break;
 
     case 102:
         // Turn our attention to form3
         uname = $_(3, "uname");
         pword = $_(3, "pword");
         checkACForm("", "");
 
@@ -560,19 +579,44 @@ function runTest(testNum) {
         doKey("down");
         checkACForm("", ""); // value shouldn't update
         doKey("return"); // not "enter"!
         // The form changes, so we expect the old username field to get the
         // selected autocomplete value, but neither the new username field nor
         // the password field should have any values filled in.
         checkACForm("form7user1", "");
         is($_(7, "uname2").value, "", "Verifying empty uname2");;
+        restoreForm(); // clear field, so reloading test doesn't fail
 
         pwmgr.removeLogin(login6A);
+        testNum = 599;
+        break;
 
+    case 600:
+        // Turn our attention to form8
+        uname = $_(8, "uname");
+        pword = $_(8, "pword");
+        checkACForm("form8user", "form8pass");
+        restoreForm();
+        break;
+
+    case 601:
+        checkACForm("", "");
+        // Focus the previous form to trigger a blur.
+        $_(7, "uname").focus();
+        break;
+
+    case 602:
+        checkACForm("", "");
+        restoreForm();
+        break;
+
+    case 603:
+        checkACForm("", "");
+        pwmgr.removeLogin(login7);
 
         SimpleTest.finish();
         return;
 
     default:
         ok(false, "Unexpected invocataion of test #" + testNum);
         SimpleTest.finish();
         return;