Bug 1418886 - Make LoginManagerContent use a WeakSet for login form root elements. r?MattN draft
authorMike Conley <mconley@mozilla.com>
Sat, 16 Dec 2017 02:08:14 -0500
changeset 712464 dc1c876557e9c97f2a489244b01f52a0374b419a
parent 710422 3a33e3beb0cd41e0080a63f153a24e0230033578
child 744060 63bfb2cd16ad5398c4e3cc4c7cca2b5aacf8a396
push id93341
push usermconley@mozilla.com
push dateSat, 16 Dec 2017 18:41:12 +0000
reviewersMattN
bugs1418886
milestone59.0a1
Bug 1418886 - Make LoginManagerContent use a WeakSet for login form root elements. r?MattN MozReview-Commit-ID: HXLrJf2mR4B
toolkit/components/passwordmgr/LoginManagerContent.jsm
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -469,34 +469,36 @@ var LoginManagerContent = {
   stateForDocument(document) {
     let loginFormState = this.loginFormStateByDocument.get(document);
     if (!loginFormState) {
       loginFormState = {
         /**
          * Keeps track of filled fields and values.
          */
         fillsByRootElement: new WeakMap(),
-        loginFormRootElements: new Set(),
+        loginFormRootElements: new WeakSet(),
       };
       this.loginFormStateByDocument.set(document, loginFormState);
     }
     return loginFormState;
   },
 
   /**
    * Compute whether there is an insecure login form on any frame of the current page, and
    * notify the parent process. This is used to control whether insecure password UI appears.
    */
   _detectInsecureFormLikes(topWindow) {
     log("_detectInsecureFormLikes", topWindow.location.href);
 
     // Returns true if this window or any subframes have insecure login forms.
     let hasInsecureLoginForms = (thisWindow) => {
       let doc = thisWindow.document;
-      let hasLoginForm = this.stateForDocument(doc).loginFormRootElements.size > 0;
+      let rootElsWeakSet = this.stateForDocument(doc).loginFormRootElements;
+      let hasLoginForm = ChromeUtils.nondeterministicGetWeakSetKeys(rootElsWeakSet)
+                                    .filter(el => el.isConnected).length > 0;
       return (hasLoginForm && !thisWindow.isSecureContext) ||
              Array.some(thisWindow.frames,
                         frame => hasInsecureLoginForms(frame));
     };
 
     let messageManager = messageManagerFromWindow(topWindow);
     messageManager.sendAsyncMessage("RemoteLogins:insecureLoginFormPresent", {
       hasInsecureLoginForms: hasInsecureLoginForms(topWindow),
@@ -875,21 +877,27 @@ var LoginManagerContent = {
    * To avoid multiple notifications for the same FormLike, this currently
    * avoids capturing when dealing with a real <form> which are ideally already
    * using a submit event.
    *
    * @param {Document} document being navigated
    */
   _onNavigation(aDocument) {
     let state = this.stateForDocument(aDocument);
-    let loginFormRootElements = state.loginFormRootElements;
-    log("_onNavigation: state:", state, "loginFormRootElements size:", loginFormRootElements.size,
+    let rootElsWeakSet = state.loginFormRootElements;
+    let weakLoginFormRootElements = ChromeUtils.nondeterministicGetWeakSetKeys(rootElsWeakSet);
+
+    log("_onNavigation: state:", state, "loginFormRootElements approx size:", weakLoginFormRootElements.length,
         "document:", aDocument);
 
-    for (let formRoot of state.loginFormRootElements) {
+    for (let formRoot of weakLoginFormRootElements) {
+      if (!formRoot.isConnected) {
+        continue;
+      }
+
       if (formRoot instanceof Ci.nsIDOMHTMLFormElement) {
         // For now only perform capture upon navigation for FormLike's without
         // a <form> to avoid capture from both an earlyformsubmit and
         // navigation for the same "form".
         log("Ignoring navigation for the form root to avoid multiple prompts " +
             "since it was for a real <form>");
         continue;
       }