Bug 1472491: Part 5k - Add NetErrorChild actor. r?felipe draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 29 Jul 2018 21:00:29 -0700
changeset 828393 0f13dfb6cc6397187a7d5c74ff06be0655f0799f
parent 828392 43e13ace321cde7cd614442eb6e77ca73c7d19c9
child 828394 935ffe21a6079d54efaa06e9450e0e2b914801c3
push id118679
push usermaglione.k@gmail.com
push dateFri, 10 Aug 2018 21:19:41 +0000
reviewersfelipe
bugs1472491
milestone63.0a1
Bug 1472491: Part 5k - Add NetErrorChild actor. r?felipe MozReview-Commit-ID: EclR3sogB4i
browser/base/content/content.js
browser/components/nsBrowserGlue.js
browser/modules/ClickHandlerChild.jsm
browser/modules/NetErrorChild.jsm
browser/modules/NetErrorContent.jsm
browser/modules/moz.build
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -17,19 +17,17 @@ var global = this;
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   ContentLinkHandler: "resource:///modules/ContentLinkHandler.jsm",
   ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
   ContentWebRTC: "resource:///modules/ContentWebRTC.jsm",
   LoginFormFactory: "resource://gre/modules/LoginManagerContent.jsm",
   InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
   FormSubmitObserver: "resource:///modules/FormSubmitObserver.jsm",
-  NetErrorContent: "resource:///modules/NetErrorContent.jsm",
   PageMetadata: "resource://gre/modules/PageMetadata.jsm",
-  WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
   ContextMenuChild: "resource:///modules/ContextMenuChild.jsm",
 });
 
 XPCOMUtils.defineLazyGetter(this, "LoginManagerContent", () => {
   let tmp = {};
   ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", tmp);
   tmp.LoginManagerContent.setupEventListeners(global);
   return tmp.LoginManagerContent;
@@ -59,72 +57,16 @@ addEventListener("DOMInputPasswordAdded"
   LoginManagerContent.onDOMInputPasswordAdded(event, content);
   let formLike = LoginFormFactory.createFromField(event.originalTarget);
   InsecurePasswordUtils.reportInsecurePasswords(formLike);
 });
 addEventListener("DOMAutoComplete", function(event) {
   LoginManagerContent.onUsernameInput(event);
 });
 
-this.AboutNetAndCertErrorListener = {
-  init(chromeGlobal) {
-    addMessageListener("CertErrorDetails", this);
-    addMessageListener("Browser:CaptivePortalFreed", this);
-    chromeGlobal.addEventListener("AboutNetErrorLoad", this, false, true);
-    chromeGlobal.addEventListener("AboutNetErrorOpenCaptivePortal", this, false, true);
-    chromeGlobal.addEventListener("AboutNetErrorSetAutomatic", this, false, true);
-    chromeGlobal.addEventListener("AboutNetErrorResetPreferences", this, false, true);
-    this.init = null;
-  },
-
-  isAboutNetError(doc) {
-    return doc.documentURI.startsWith("about:neterror");
-  },
-
-  isAboutCertError(doc) {
-    return doc.documentURI.startsWith("about:certerror");
-  },
-
-  receiveMessage(msg) {
-    if (msg.name == "CertErrorDetails") {
-      let frameDocShell = WebNavigationFrames.findDocShell(msg.data.frameId, docShell);
-      // We need nsIWebNavigation to access docShell.document.
-      frameDocShell && frameDocShell.QueryInterface(Ci.nsIWebNavigation);
-      if (!frameDocShell || !this.isAboutCertError(frameDocShell.document)) {
-        return;
-      }
-
-      NetErrorContent.onCertErrorDetails(global, msg, frameDocShell);
-    } else if (msg.name == "Browser:CaptivePortalFreed") {
-      // TODO: This check is not correct for frames.
-      if (!this.isAboutCertError(content.document)) {
-        return;
-      }
-
-      this.onCaptivePortalFreed(msg);
-    }
-  },
-
-  onCaptivePortalFreed(msg) {
-    content.dispatchEvent(new content.CustomEvent("AboutNetErrorCaptivePortalFreed"));
-  },
-
-  handleEvent(aEvent) {
-    // Documents have a null ownerDocument.
-    let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
-
-    if (!this.isAboutNetError(doc) && !this.isAboutCertError(doc)) {
-      return;
-    }
-
-    NetErrorContent.handleEvent(global, aEvent);
-  },
-};
-AboutNetAndCertErrorListener.init(this);
-
 new ContentLinkHandler(this);
 ContentMetaHandler.init(this);
 
 // This is a temporary hack to prevent regressions (bug 1471327).
 void content;
 
 addEventListener("DOMWindowFocus", function(event) {
   sendAsyncMessage("DOMWindowFocus", {});
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -108,16 +108,35 @@ let ACTORS = {
       events: {
         "InstallBrowserTheme": {wantUntrusted: true},
         "PreviewBrowserTheme": {wantUntrusted: true},
         "ResetBrowserThemePreview": {wantUntrusted: true},
       },
     },
   },
 
+  NetError: {
+    module: "resource:///modules/NetError",
+    child: {
+      events: {
+        "AboutNetErrorLoad": {wantUntrusted: true},
+        "AboutNetErrorOpenCaptivePortal": {wantUntrusted: true},
+        "AboutNetErrorSetAutomatic": {wantUntrusted: true},
+        "AboutNetErrorResetPreferences": {wantUntrusted: true},
+        "click": {},
+      },
+      matches: ["about:certerror?*", "about:neterror?*"],
+      allFrames: true,
+      messages: [
+        "Browser:CaptivePortalFreed",
+        "CertErrorDetails",
+      ],
+    },
+  },
+
   PageInfo: {
     module: "resource:///modules/PageInfo",
     child: {
       messages: ["PageInfo:getData"],
     },
   },
 
   PageStyle: {
--- a/browser/modules/ClickHandlerChild.jsm
+++ b/browser/modules/ClickHandlerChild.jsm
@@ -5,18 +5,16 @@
 
 var EXPORTED_SYMBOLS = ["ClickHandlerChild"];
 
 ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
                                "resource://gre/modules/BrowserUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "NetErrorContent",
-                               "resource:///modules/NetErrorContent.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
                                "resource://gre/modules/WebNavigationFrames.jsm");
 
 class ClickHandlerChild extends ActorChild {
   handleEvent(event) {
     if (!event.isTrusted || event.defaultPrevented || event.button == 2) {
@@ -26,23 +24,17 @@ class ClickHandlerChild extends ActorChi
     let originalTarget = event.originalTarget;
     let ownerDoc = originalTarget.ownerDocument;
     if (!ownerDoc) {
       return;
     }
 
     // Handle click events from about pages
     if (event.button == 0) {
-      if (this.mm.AboutNetAndCertErrorListener.isAboutCertError(ownerDoc)) {
-        NetErrorContent.onCertError(this.mm, originalTarget, ownerDoc.defaultView);
-        return;
-      } else if (ownerDoc.documentURI.startsWith("about:blocked")) {
-        return;
-      } else if (this.mm.AboutNetAndCertErrorListener.isAboutNetError(ownerDoc)) {
-        NetErrorContent.onAboutNetError(this.mm, event, ownerDoc.documentURI);
+      if (ownerDoc.documentURI.startsWith("about:blocked")) {
         return;
       }
     }
 
     let [href, node, principal] = this._hrefAndLinkNodeForClickEvent(event);
 
     // get referrer attribute from clicked link and parse it
     // if per element referrer is enabled, the element referrer overrules
rename from browser/modules/NetErrorContent.jsm
rename to browser/modules/NetErrorChild.jsm
--- a/browser/modules/NetErrorContent.jsm
+++ b/browser/modules/NetErrorChild.jsm
@@ -1,17 +1,18 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* 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/. */
 
-var EXPORTED_SYMBOLS = ["NetErrorContent"];
+var EXPORTED_SYMBOLS = ["NetErrorChild"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
                                "resource://gre/modules/BrowserUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
                                "resource://gre/modules/WebNavigationFrames.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
   return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
@@ -65,24 +66,24 @@ function getSerializedSecurityInfo(docSh
     return "";
   }
   securityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
               .QueryInterface(Ci.nsISerializable);
 
   return serhelper.serializeToString(securityInfo);
 }
 
-var NetErrorContent = {
+class NetErrorChild extends ActorChild {
   isAboutNetError(doc) {
     return doc.documentURI.startsWith("about:neterror");
-  },
+  }
 
   isAboutCertError(doc) {
     return doc.documentURI.startsWith("about:certerror");
-  },
+  }
 
   _getCertValidityRange(docShell) {
     let {securityInfo} = docShell.failedChannel;
     securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
     let certs = securityInfo.failedCertChain.getEnumerator();
     let notBefore = 0;
     let notAfter = Number.MAX_SAFE_INTEGER;
     while (certs.hasMoreElements()) {
@@ -90,17 +91,17 @@ var NetErrorContent = {
       cert.QueryInterface(Ci.nsIX509Cert);
       notBefore = Math.max(notBefore, cert.validity.notBefore);
       notAfter = Math.min(notAfter, cert.validity.notAfter);
     }
     // nsIX509Cert reports in PR_Date terms, which uses microseconds. Convert:
     notBefore /= 1000;
     notAfter /= 1000;
     return {notBefore, notAfter};
-  },
+  }
 
   _setTechDetails(input, doc) {
     // CSS class and error code are set from nsDocShell.
     let searchParams = new URLSearchParams(doc.documentURI.split("?")[1]);
     let cssClass = searchParams.get("s");
     let error = searchParams.get("e");
     let technicalInfo = doc.getElementById("badCertTechnicalInfo");
     technicalInfo.textContent = "";
@@ -324,17 +325,17 @@ var NetErrorContent = {
     if (errorCode) {
       errorCode.href = "javascript:void(0)";
       errorCode.addEventListener("click", () => {
         let debugInfo = doc.getElementById("certificateErrorDebugInformation");
         debugInfo.style.display = "block";
         debugInfo.scrollIntoView({block: "start", behavior: "smooth"});
       });
     }
-  },
+  }
 
   onCertErrorDetails(global, msg, docShell) {
     let doc = docShell.document;
 
   function updateContainerPosition() {
     let textContainer = doc.getElementById("text-container");
     textContainer.style.marginTop = `calc(50vh - ${textContainer.clientHeight / 2}px)`;
   }
@@ -458,101 +459,133 @@ var NetErrorContent = {
               .textContent = formatter.format(systemDate);
 
             doc.getElementById("errorShortDesc").style.display = "none";
             doc.getElementById("wrongSystemTimeWithoutReferencePanel").style.display = "block";
           }
         }
         break;
     }
-  },
+  }
 
-  handleEvent(aGlobal, aEvent) {
+  handleEvent(aEvent) {
     // Documents have a null ownerDocument.
     let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
 
     switch (aEvent.type) {
     case "AboutNetErrorLoad":
-      this.onPageLoad(aGlobal, aEvent.originalTarget, doc.defaultView);
+      this.onPageLoad(aEvent.originalTarget, doc.defaultView);
       break;
     case "AboutNetErrorOpenCaptivePortal":
-      this.openCaptivePortalPage(aGlobal, aEvent);
+      this.openCaptivePortalPage(aEvent);
       break;
     case "AboutNetErrorSetAutomatic":
-      this.onSetAutomatic(aGlobal, aEvent);
+      this.onSetAutomatic(aEvent);
       break;
     case "AboutNetErrorResetPreferences":
-      this.onResetPreferences(aGlobal, aEvent);
+      this.onResetPreferences(aEvent);
       break;
+    case "click":
+      if (aEvent.button == 0) {
+        if (this.isAboutCertError(doc)) {
+          this.onCertError(aEvent.originalTarget, doc.defaultView);
+        } else {
+          this.onClick(aEvent);
+        }
+      }
     }
-  },
+  }
+
+  receiveMessage(msg) {
+    if (msg.name == "CertErrorDetails") {
+      let frameDocShell = WebNavigationFrames.findDocShell(msg.data.frameId, this.docShell);
+      // We need nsIWebNavigation to access docShell.document.
+      frameDocShell && frameDocShell.QueryInterface(Ci.nsIWebNavigation);
+      if (!frameDocShell || !this.isAboutCertError(frameDocShell.document)) {
+        return;
+      }
+
+      this.onCertErrorDetails(this.mm, msg, frameDocShell);
+    } else if (msg.name == "Browser:CaptivePortalFreed") {
+      // TODO: This check is not correct for frames.
+      if (!this.isAboutCertError(this.content.document)) {
+        return;
+      }
+
+      this.onCaptivePortalFreed(msg);
+    }
+  }
+
+  onCaptivePortalFreed(msg) {
+    this.content.dispatchEvent(new this.content.CustomEvent("AboutNetErrorCaptivePortalFreed"));
+  }
 
   changedCertPrefs() {
     let prefSSLImpact = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
        return prefs.concat(Services.prefs.getChildList(root));
     }, []);
     for (let prefName of prefSSLImpact) {
       if (Services.prefs.prefHasUserValue(prefName)) {
         return true;
       }
     }
 
     return false;
-  },
+  }
 
-   _getErrorMessageFromCode(securityInfo, doc) {
-     let uri = Services.io.newURI(doc.location);
-     let hostString = uri.host;
-     if (uri.port != 443 && uri.port != -1) {
-       hostString = uri.hostPort;
-     }
+  _getErrorMessageFromCode(securityInfo, doc) {
+    let uri = Services.io.newURI(doc.location);
+    let hostString = uri.host;
+    if (uri.port != 443 && uri.port != -1) {
+      hostString = uri.hostPort;
+    }
 
-     let id_str = "";
-     switch (securityInfo.errorCode) {
-       case SSL_ERROR_SSL_DISABLED:
-         id_str = "PSMERR_SSL_Disabled";
-         break;
-       case SSL_ERROR_SSL2_DISABLED:
-         id_str = "PSMERR_SSL2_Disabled";
-         break;
-       case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
-         id_str = "PSMERR_HostReusedIssuerSerial";
-         break;
-     }
-     let nss_error_id_str = securityInfo.errorCodeString;
-     let msg2 = "";
-     if (id_str) {
-       msg2 = gPipNSSBundle.GetStringFromName(id_str) + "\n";
-     } else if (nss_error_id_str) {
-       msg2 = gNSSErrorsBundle.GetStringFromName(nss_error_id_str) + "\n";
-     }
+    let id_str = "";
+    switch (securityInfo.errorCode) {
+      case SSL_ERROR_SSL_DISABLED:
+        id_str = "PSMERR_SSL_Disabled";
+        break;
+      case SSL_ERROR_SSL2_DISABLED:
+        id_str = "PSMERR_SSL2_Disabled";
+        break;
+      case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
+        id_str = "PSMERR_HostReusedIssuerSerial";
+        break;
+    }
+    let nss_error_id_str = securityInfo.errorCodeString;
+    let msg2 = "";
+    if (id_str) {
+      msg2 = gPipNSSBundle.GetStringFromName(id_str) + "\n";
+    } else if (nss_error_id_str) {
+      msg2 = gNSSErrorsBundle.GetStringFromName(nss_error_id_str) + "\n";
+    }
 
-     if (!msg2) {
-       // We couldn't get an error message. Use the error string.
-       // Note that this is different from before where we used PR_ErrorToString.
-       msg2 = nss_error_id_str;
-     }
-     let msg = gPipNSSBundle.formatStringFromName("SSLConnectionErrorPrefix2",
-                                                  [hostString, msg2], 2);
+    if (!msg2) {
+      // We couldn't get an error message. Use the error string.
+      // Note that this is different from before where we used PR_ErrorToString.
+      msg2 = nss_error_id_str;
+    }
+    let msg = gPipNSSBundle.formatStringFromName("SSLConnectionErrorPrefix2",
+                                                 [hostString, msg2], 2);
 
-     if (nss_error_id_str) {
-       msg += gPipNSSBundle.formatStringFromName("certErrorCodePrefix3",
-                                                 [nss_error_id_str], 1) + "\n";
-     }
-     return msg;
-   },
+    if (nss_error_id_str) {
+      msg += gPipNSSBundle.formatStringFromName("certErrorCodePrefix3",
+                                                [nss_error_id_str], 1) + "\n";
+    }
+    return msg;
+  }
 
-  onPageLoad(global, originalTarget, win) {
+  onPageLoad(originalTarget, win) {
     // Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
     const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
 
     let hideAddExceptionButton = false;
 
     if (this.isAboutCertError(win.document)) {
-      this.onCertError(global, originalTarget, win);
+      this.onCertError(originalTarget, win);
       hideAddExceptionButton =
         Services.prefs.getBoolPref("security.certerror.hideAddException", false);
     }
     if (this.isAboutNetError(win.document)) {
       let docShell = win.docShell;
       if (docShell) {
         let {securityInfo} = docShell.failedChannel;
         // We don't have a securityInfo when this is for example a DNS error.
@@ -571,70 +604,71 @@ var NetErrorContent = {
       detail: JSON.stringify({
         enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
         changedCertPrefs: this.changedCertPrefs(),
         automatic,
         hideAddExceptionButton,
       })
     }));
 
-    global.sendAsyncMessage("Browser:SSLErrorReportTelemetry",
+    this.mm.sendAsyncMessage("Browser:SSLErrorReportTelemetry",
                             {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
-  },
+  }
 
-  openCaptivePortalPage(global, evt) {
-    global.sendAsyncMessage("Browser:OpenCaptivePortalPage");
-  },
+  openCaptivePortalPage(evt) {
+    this.mm.sendAsyncMessage("Browser:OpenCaptivePortalPage");
+  }
 
 
-  onResetPreferences(global, evt) {
-    global.sendAsyncMessage("Browser:ResetSSLPreferences");
-  },
+  onResetPreferences(evt) {
+    this.mm.sendAsyncMessage("Browser:ResetSSLPreferences");
+  }
 
-  onSetAutomatic(global, evt) {
-    global.sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
+  onSetAutomatic(evt) {
+    this.mm.sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
       automatic: evt.detail
     });
 
     // If we're enabling reports, send a report for this failure.
     if (evt.detail) {
       let win = evt.originalTarget.ownerGlobal;
       let docShell = win.docShell;
 
       let {securityInfo} = docShell.failedChannel;
       securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
       let {host, port} = win.document.mozDocumentURIIfNotForErrorPages;
 
       let errorReporter = Cc["@mozilla.org/securityreporter;1"]
                             .getService(Ci.nsISecurityReporter);
       errorReporter.reportTLSError(securityInfo, host, port);
     }
-  },
+  }
 
-  onCertError(global, targetElement, win) {
-    let docShell = win.docShell;
-    global.sendAsyncMessage("Browser:CertExceptionError", {
+  onCertError(target, win) {
+    this.mm.sendAsyncMessage("Browser:CertExceptionError", {
       frameId: WebNavigationFrames.getFrameId(win),
       location: win.document.location.href,
-      elementId: targetElement.getAttribute("id"),
+      elementId: target.getAttribute("id"),
       isTopFrame: (win.parent === win),
-      securityInfoAsString: getSerializedSecurityInfo(docShell),
+      securityInfoAsString: getSerializedSecurityInfo(win.docShell),
     });
-  },
+  }
 
-  onAboutNetError(global, event, documentURI) {
+  onClick(event) {
+    let {documentURI} = event.target.ownerDocument;
+
     let elmId = event.originalTarget.getAttribute("id");
     if (elmId == "returnButton") {
-      global.sendAsyncMessage("Browser:SSLErrorGoBack", {});
+      this.mm.sendAsyncMessage("Browser:SSLErrorGoBack", {});
       return;
     }
     if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
       return;
     }
     // browser front end will handle clearing offline mode and refreshing
     // the page *if* we're in offline mode now. Otherwise let the error page
     // handle the click.
     if (Services.io.offline) {
       event.preventDefault();
-      global.sendAsyncMessage("Browser:EnableOnlineMode", {});
+      this.mm.sendAsyncMessage("Browser:EnableOnlineMode", {});
     }
-  },
-};
+  }
+}
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -153,17 +153,17 @@ EXTRA_JS_MODULES += [
     'ExtensionsUI.jsm',
     'Feeds.jsm',
     'FormSubmitObserver.jsm',
     'FormValidationHandler.jsm',
     'HomePage.jsm',
     'LaterRun.jsm',
     'LightweightThemeChildHelper.jsm',
     'LightWeightThemeInstallChild.jsm',
-    'NetErrorContent.jsm',
+    'NetErrorChild.jsm',
     'OpenInTabsUtils.jsm',
     'PageActions.jsm',
     'PageInfoChild.jsm',
     'PageStyleChild.jsm',
     'PermissionUI.jsm',
     'PingCentre.jsm',
     'PluginChild.jsm',
     'ProcessHangMonitor.jsm',