Bug 1304001 - Stop passing the top window to LoginManagerContent. r=sfoster
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Fri, 22 Feb 2019 15:41:35 +0000
changeset 460598 d6646400f45d1a63ca75ac04e6b9b109c41970f4
parent 460597 32398fe05ec236a52a01c27bae96637b222c2bbd
child 460599 275692bc35bcf6ef35d3bacfa69d43c1e876d52b
push id35596
push userrmaries@mozilla.com
push dateSat, 23 Feb 2019 04:13:22 +0000
treeherdermozilla-central@fdd04819e350 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1304001
milestone67.0a1
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 1304001 - Stop passing the top window to LoginManagerContent. r=sfoster It wasn't clear in callee code that the window was the top-window and it wasn't necessary in many cases. Relying on the top-window would also cause problems with Fission if the windows are in separate processes. Differential Revision: https://phabricator.services.mozilla.com/D20395
browser/base/content/content.js
mobile/android/components/BrowserCLH.js
toolkit/components/passwordmgr/LoginManagerContent.jsm
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -40,17 +40,17 @@ function shouldIgnoreLoginManagerEvent(e
   // incorrectly using the document `location`.
   return event.target.nodePrincipal.isNullPrincipal;
 }
 
 addEventListener("DOMFormHasPassword", function(event) {
   if (shouldIgnoreLoginManagerEvent(event)) {
     return;
   }
-  LoginManagerContent.onDOMFormHasPassword(event, content);
+  LoginManagerContent.onDOMFormHasPassword(event);
   let formLike = LoginFormFactory.createFromForm(event.originalTarget);
   InsecurePasswordUtils.reportInsecurePasswords(formLike);
 });
 addEventListener("DOMInputPasswordAdded", function(event) {
   if (shouldIgnoreLoginManagerEvent(event)) {
     return;
   }
   LoginManagerContent.onDOMInputPasswordAdded(event, content);
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -225,17 +225,17 @@ BrowserCLH.prototype = {
     };
 
     // NOTE: Much of this logic is duplicated in browser/base/content/content.js
     // for desktop.
     aWindow.addEventListener("DOMFormHasPassword", event => {
       if (shouldIgnoreLoginManagerEvent(event)) {
         return;
       }
-      this.LoginManagerContent.onDOMFormHasPassword(event, event.target.ownerGlobal.top);
+      this.LoginManagerContent.onDOMFormHasPassword(event);
     }, options);
 
     aWindow.addEventListener("DOMInputPasswordAdded", event => {
       if (shouldIgnoreLoginManagerEvent(event)) {
         return;
       }
       this.LoginManagerContent.onDOMInputPasswordAdded(event, event.target.ownerGlobal.top);
     }, options);
@@ -245,17 +245,17 @@ BrowserCLH.prototype = {
         return;
       }
       this.LoginManagerContent.onDOMAutoComplete(event);
     }, options);
 
     aWindow.addEventListener("pageshow", event => {
       // XXXbz what about non-HTML documents??
       if (ChromeUtils.getClassName(event.target) == "HTMLDocument") {
-        this.LoginManagerContent.onPageShow(event, event.target.defaultView.top);
+        this.LoginManagerContent.onPageShow(event);
       }
     }, options);
   },
 
   // QI
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   // XPCOMUtils factory
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1,12 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/**
+ * Module doing most of the content process work for the password manager.
+ */
+
+// Disable use-ownerGlobal since FormLike don't have it.
+/* eslint-disable mozilla/use-ownerGlobal */
+
 "use strict";
 
 var EXPORTED_SYMBOLS = [ "LoginManagerContent",
                          "LoginFormFactory",
                          "UserAutoCompleteResult" ];
 
 const PASSWORD_INPUT_ADDED_COALESCING_THRESHOLD_MS = 1;
 const AUTOCOMPLETE_AFTER_RIGHT_CLICK_THRESHOLD_MS = 400;
@@ -231,20 +238,20 @@ var LoginManagerContent = {
     messageManager.sendAsyncMessage(name, messageData);
 
     let deferred = PromiseUtils.defer();
     requestData.promise = deferred;
     this._requests.set(requestId, requestData);
     return deferred.promise;
   },
 
-  receiveMessage(msg, window) {
+  receiveMessage(msg, topWindow) {
     if (msg.name == "RemoteLogins:fillForm") {
       this.fillForm({
-        topDocument: window.document,
+        topDocument: topWindow.document,
         loginFormOrigin: msg.data.loginFormOrigin,
         loginsFound: LoginHelper.vanillaObjectsToLogins(msg.data.logins),
         recipes: msg.data.recipes,
         inputElement: msg.objects.inputElement,
       });
       return;
     }
 
@@ -256,18 +263,17 @@ var LoginManagerContent = {
           form: request.form,
           loginsFound,
           recipes: msg.data.recipes,
         });
         break;
       }
 
       case "RemoteLogins:loginsAutoCompleted": {
-        let loginsFound =
-          LoginHelper.vanillaObjectsToLogins(msg.data.logins);
+        let loginsFound = LoginHelper.vanillaObjectsToLogins(msg.data.logins);
         let messageManager = msg.target;
         request.promise.resolve({ logins: loginsFound, messageManager });
         break;
       }
     }
   },
 
   /**
@@ -328,17 +334,17 @@ var LoginManagerContent = {
 
     return this._sendRequest(messageManager, requestData,
                              "RemoteLogins:autoCompleteLogins",
                              messageData);
   },
 
   setupEventListeners(global) {
     global.addEventListener("pageshow", (event) => {
-      this.onPageShow(event, global.content);
+      this.onPageShow(event);
     });
     global.addEventListener("blur", (event) => {
       this.onUsernameInput(event);
     });
   },
 
   setupProgressListener(window) {
     if (!LoginHelper.formlessCaptureEnabled) {
@@ -352,62 +358,63 @@ var LoginManagerContent = {
       webProgress.addProgressListener(observer,
                                       Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT |
                                       Ci.nsIWebProgress.NOTIFY_LOCATION);
     } catch (ex) {
       // Ignore NS_ERROR_FAILURE if the progress listener was already added
     }
   },
 
-  onDOMFormHasPassword(event, window) {
+  onDOMFormHasPassword(event) {
     if (!event.isTrusted) {
       return;
     }
 
     let form = event.target;
     let formLike = LoginFormFactory.createFromForm(form);
     log("onDOMFormHasPassword:", form, formLike);
-    this._fetchLoginsFromParentAndFillForm(formLike, window);
+    this._fetchLoginsFromParentAndFillForm(formLike);
   },
 
-  onDOMInputPasswordAdded(event, window) {
+  onDOMInputPasswordAdded(event, topWindow) {
     if (!event.isTrusted) {
       return;
     }
 
     let pwField = event.originalTarget;
     if (pwField.form) {
       // Fill is handled by onDOMFormHasPassword which is already throttled.
       return;
     }
 
     // Only setup the listener for formless inputs.
     // Capture within a <form> but without a submit event is bug 1287202.
-    this.setupProgressListener(window);
+    this.setupProgressListener(topWindow);
 
     let formLike = LoginFormFactory.createFromField(pwField);
     log("onDOMInputPasswordAdded:", pwField, formLike);
 
     let deferredTask = this._deferredPasswordAddedTasksByRootElement.get(formLike.rootElement);
     if (!deferredTask) {
       log("Creating a DeferredTask to call _fetchLoginsFromParentAndFillForm soon");
       this._formLikeByRootElement.set(formLike.rootElement, formLike);
 
       deferredTask = new DeferredTask(() => {
         // Get the updated formLike instead of the one at the time of creating the DeferredTask via
         // a closure since it could be stale since FormLike.elements isn't live.
         let formLike2 = this._formLikeByRootElement.get(formLike.rootElement);
         log("Running deferred processing of onDOMInputPasswordAdded", formLike2);
         this._deferredPasswordAddedTasksByRootElement.delete(formLike2.rootElement);
-        this._fetchLoginsFromParentAndFillForm(formLike2, window);
+        this._fetchLoginsFromParentAndFillForm(formLike2);
       }, PASSWORD_INPUT_ADDED_COALESCING_THRESHOLD_MS, 0);
 
       this._deferredPasswordAddedTasksByRootElement.set(formLike.rootElement, deferredTask);
     }
 
+    let window = pwField.ownerGlobal;
     if (deferredTask.isArmed) {
       log("DeferredTask is already armed so just updating the FormLike");
       // We update the FormLike so it (most important .elements) is fresh when the task eventually
       // runs since changes to the elements could affect our field heuristics.
       this._formLikeByRootElement.set(formLike.rootElement, formLike);
     } else if (window.document.readyState == "complete") {
       log("Arming the DeferredTask we just created since document.readyState == 'complete'");
       deferredTask.arm();
@@ -418,34 +425,35 @@ var LoginManagerContent = {
       }, {once: true});
     }
   },
 
   /**
    * Fetch logins from the parent for a given form and then attempt to fill it.
    *
    * @param {FormLike} form to fetch the logins for then try autofill.
-   * @param {Window} window
    */
-  _fetchLoginsFromParentAndFillForm(form, window) {
-    this._detectInsecureFormLikes(window);
+  _fetchLoginsFromParentAndFillForm(form) {
+    let window = form.ownerDocument.defaultView;
+    this._detectInsecureFormLikes(window.top);
 
     let messageManager = window.docShell.messageManager;
     messageManager.sendAsyncMessage("LoginStats:LoginEncountered");
 
     if (!LoginHelper.enabled) {
       return;
     }
 
     this._getLoginDataFromParent(form, { showMasterPassword: true })
         .then(this.loginsFound.bind(this))
         .catch(Cu.reportError);
   },
 
-  onPageShow(event, window) {
+  onPageShow(event) {
+    let window = event.target.ownerGlobal;
     this._detectInsecureFormLikes(window);
   },
 
   /**
    * Maps all DOM content documents in this content process, including those in
    * frames, to the current state used by the Login Manager.
    */
   loginFormStateByDocument: new WeakMap(),
@@ -520,17 +528,17 @@ var LoginManagerContent = {
   fillForm({ topDocument, loginFormOrigin, loginsFound, recipes, inputElement }) {
     if (!inputElement) {
       log("fillForm: No input element specified");
       return;
     }
     if (LoginHelper.getLoginOrigin(topDocument.documentURI) != loginFormOrigin) {
       if (!inputElement ||
           LoginHelper.getLoginOrigin(inputElement.ownerDocument.documentURI) != loginFormOrigin) {
-        log("fillForm: The requested origin doesn't match the one form the",
+        log("fillForm: The requested origin doesn't match the one from the",
             "document. This may mean we navigated to a document from a different",
             "site before we had a chance to indicate this change in the user",
             "interface.");
         return;
       }
     }
 
     let clobberUsername = true;