Bug 1469719: Avoid loading LoginManagerContent before it's needed. r?felipe
The "pageshow" and "blur" event listeners in LoginManagerContent only matter
once the module has loaded and processed other events. Before that, they're
guaranteed to be no-ops.
This patch delays adding those listeners before LoginManagerContent is used
for a given frame script.
MozReview-Commit-ID: 1f5AOkRkAhp
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -16,32 +16,38 @@ ChromeUtils.import("resource://gre/modul
var global = this;
XPCOMUtils.defineLazyModuleGetters(this, {
BlockedSiteContent: "resource:///modules/BlockedSiteContent.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
ContentLinkHandler: "resource:///modules/ContentLinkHandler.jsm",
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
ContentWebRTC: "resource:///modules/ContentWebRTC.jsm",
- LoginManagerContent: "resource://gre/modules/LoginManagerContent.jsm",
LoginFormFactory: "resource://gre/modules/LoginManagerContent.jsm",
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
PluginContent: "resource:///modules/PluginContent.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
FormSubmitObserver: "resource:///modules/FormSubmitObserver.jsm",
NetErrorContent: "resource:///modules/NetErrorContent.jsm",
PageMetadata: "resource://gre/modules/PageMetadata.jsm",
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
ContextMenu: "resource:///modules/ContextMenu.jsm",
});
XPCOMUtils.defineLazyProxy(this, "contextMenu", () => {
return new ContextMenu(global);
});
+XPCOMUtils.defineLazyGetter(this, "LoginManagerContent", () => {
+ let tmp = {};
+ ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", tmp);
+ tmp.LoginManagerContent.setupEventListeners(global);
+ return tmp.LoginManagerContent;
+});
+
XPCOMUtils.defineLazyProxy(this, "formSubmitObserver", () => {
return new FormSubmitObserver(content, this);
}, {
// stub QI
QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver, Ci.nsISupportsWeakReference])
});
XPCOMUtils.defineLazyProxy(this, "PageInfoListener",
@@ -51,40 +57,35 @@ XPCOMUtils.defineLazyProxy(this, "LightW
"resource:///modules/LightWeightThemeWebInstallListener.jsm");
Services.els.addSystemEventListener(global, "contextmenu", contextMenu, false);
Services.obs.addObserver(formSubmitObserver, "invalidformsubmit", true);
addMessageListener("PageInfo:getData", PageInfoListener);
+// NOTE: Much of this logic is duplicated in BrowserCLH.js for Android.
addMessageListener("RemoteLogins:fillForm", function(message) {
// intercept if ContextMenu.jsm had sent a plain object for remote targets
message.objects.inputElement = contextMenu.getTarget(message, "inputElement");
LoginManagerContent.receiveMessage(message, content);
});
addEventListener("DOMFormHasPassword", function(event) {
LoginManagerContent.onDOMFormHasPassword(event, content);
let formLike = LoginFormFactory.createFromForm(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
});
addEventListener("DOMInputPasswordAdded", function(event) {
LoginManagerContent.onDOMInputPasswordAdded(event, content);
let formLike = LoginFormFactory.createFromField(event.originalTarget);
InsecurePasswordUtils.reportInsecurePasswords(formLike);
});
-addEventListener("pageshow", function(event) {
- LoginManagerContent.onPageShow(event, content);
-});
addEventListener("DOMAutoComplete", function(event) {
LoginManagerContent.onUsernameInput(event);
});
-addEventListener("blur", function(event) {
- LoginManagerContent.onUsernameInput(event);
-});
var AboutBlockedSiteListener = {
init(chromeGlobal) {
addMessageListener("DeceptiveBlockedDetails", this);
chromeGlobal.addEventListener("AboutBlockedLoaded", this, false, true);
},
get isBlockedSite() {
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -21,16 +21,18 @@ const blacklist = {
components: new Set([
"PushComponents.js",
"TelemetryStartup.js",
]),
modules: new Set([
"resource:///modules/ContentWebRTC.jsm",
"resource://gre/modules/InlineSpellChecker.jsm",
"resource://gre/modules/InlineSpellCheckerContent.jsm",
+ "resource://gre/modules/LoginHelper.jsm",
+ "resource://gre/modules/LoginManagerContent.jsm",
"resource://gre/modules/Promise.jsm",
"resource://gre/modules/Task.jsm",
"resource://gre/modules/osfile.jsm",
"resource://pdf.js/PdfJs.jsm",
"resource://pdf.js/PdfStreamConverter.jsm",
]),
services: new Set([
"@mozilla.org/base/telemetry-startup;1",
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -180,16 +180,18 @@ BrowserCLH.prototype = {
return;
}
let options = {
capture: true,
mozSystemGroup: true,
};
+ // NOTE: Much of this logic is duplicated in browser/base/content/content.js
+ // for desktop.
aWindow.addEventListener("DOMFormHasPassword", event => {
this.LoginManagerContent.onDOMFormHasPassword(event, event.target.ownerGlobal.top);
}, options);
aWindow.addEventListener("DOMInputPasswordAdded", event => {
this.LoginManagerContent.onDOMInputPasswordAdded(event, event.target.ownerGlobal.top);
}, options);
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -29,17 +29,16 @@ ChromeUtils.import("resource://gre/modul
var LoginHelper = {
/**
* Warning: these only update if a logger was created.
*/
debug: Services.prefs.getBoolPref("signon.debug"),
formlessCaptureEnabled: Services.prefs.getBoolPref("signon.formlessCapture.enabled"),
schemeUpgrades: Services.prefs.getBoolPref("signon.schemeUpgrades"),
insecureAutofill: Services.prefs.getBoolPref("signon.autofillForms.http"),
- showInsecureFieldWarning: Services.prefs.getBoolPref("security.insecure_field_warning.contextual.enabled"),
createLogger(aLogPrefix) {
let getMaxLogLevel = () => {
return this.debug ? "debug" : "warn";
};
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
@@ -53,20 +52,16 @@ var LoginHelper = {
Services.prefs.addObserver("signon.", () => {
this.debug = Services.prefs.getBoolPref("signon.debug");
this.formlessCaptureEnabled = Services.prefs.getBoolPref("signon.formlessCapture.enabled");
this.schemeUpgrades = Services.prefs.getBoolPref("signon.schemeUpgrades");
this.insecureAutofill = Services.prefs.getBoolPref("signon.autofillForms.http");
logger.maxLogLevel = getMaxLogLevel();
});
- Services.prefs.addObserver("security.insecure_field_warning.", () => {
- this.showInsecureFieldWarning = Services.prefs.getBoolPref("security.insecure_field_warning.contextual.enabled");
- });
-
return logger;
},
/**
* Due to the way the signons2.txt file is formatted, we need to make
* sure certain field values or characters do not cause the file to
* be parsed incorrectly. Reject hostnames that we can't store correctly.
*
@@ -772,12 +767,15 @@ var LoginHelper = {
dataObject = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
dataObject.data = data;
}
Services.obs.notifyObservers(dataObject, "passwordmgr-storage-changed", changeType);
}
};
+XPCOMUtils.defineLazyPreferenceGetter(LoginHelper, "showInsecureFieldWarning",
+ "security.insecure_field_warning.contextual.enabled");
+
XPCOMUtils.defineLazyGetter(this, "log", () => {
let logger = LoginHelper.createLogger("LoginHelper");
return logger;
});
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -158,17 +158,16 @@ function messageManagerFromWindow(win) {
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}
// This object maps to the "child" process (even in the single-process case).
var LoginManagerContent = {
-
__formFillService: null, // FormFillController, for username autocompleting
get _formFillService() {
if (!this.__formFillService)
this.__formFillService =
Cc["@mozilla.org/satchel/form-fill-controller;1"].
getService(Ci.nsIFormFillController);
return this.__formFillService;
},
@@ -343,16 +342,25 @@ var LoginManagerContent = {
isPasswordField: aElement.type == "password",
};
return this._sendRequest(messageManager, requestData,
"RemoteLogins:autoCompleteLogins",
messageData);
},
+ setupEventListeners(global) {
+ global.addEventListener("pageshow", (event) => {
+ this.onPageShow(event, global.content);
+ });
+ global.addEventListener("blur", (event) => {
+ this.onUsernameInput(event);
+ });
+ },
+
setupProgressListener(window) {
if (!LoginHelper.formlessCaptureEnabled) {
return;
}
try {
let webProgress = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation).