From 3252e220000430851ce92446f0fd1336258c7584 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 17 Aug 2019 22:28:30 +0200 Subject: Issue #1064: Don't get certificate details synchronously. This avoids getting data synchronously on the main thread in an XHR (which has been deprecated for a long time and _may_ actually be blocked in our networking) and attempts to be more predictable by always firing an update request for the dialog from the XHR request handlers. --- .../pki/resources/content/exceptionDialog.js | 82 ++++++++-------------- 1 file changed, 31 insertions(+), 51 deletions(-) diff --git a/security/manager/pki/resources/content/exceptionDialog.js b/security/manager/pki/resources/content/exceptionDialog.js index c106cdbf5..cebf51fa1 100644 --- a/security/manager/pki/resources/content/exceptionDialog.js +++ b/security/manager/pki/resources/content/exceptionDialog.js @@ -15,32 +15,6 @@ var gNeedReset; Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); -function badCertListener() {} -badCertListener.prototype = { - getInterface: function (aIID) { - return this.QueryInterface(aIID); - }, - QueryInterface: function(aIID) { - if (aIID.equals(Components.interfaces.nsIBadCertListener2) || - aIID.equals(Components.interfaces.nsIInterfaceRequestor) || - aIID.equals(Components.interfaces.nsISupports)) { - return this; - } - - throw new Error(Components.results.NS_ERROR_NO_INTERFACE); - }, - handle_test_result: function () { - if (gSSLStatus) { - gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert; - } - }, - notifyCertProblem: function MSR_notifyCertProblem(socketInfo, sslStatus, targetHost) { - gBroken = true; - gSSLStatus = sslStatus; - this.handle_test_result(); - return true; // suppress error UI - } -}; function initExceptionDialog() { gNeedReset = false; @@ -84,6 +58,28 @@ function initExceptionDialog() { } } +/** + * Helper function for checkCert. Set as the onerror/onload callbacks for an + * XMLHttpRequest. Sets gSSLStatus, gCert, gBroken, and gChecking according to + * the load information from the request. Probably should not be used directly. + * + * @param {XMLHttpRequest} req + * The XMLHttpRequest created and sent by checkCert. + * @param {Event} evt + * The load or error event. + */ +function grabCert(req, evt) { + if (req.channel && req.channel.securityInfo) { + gSSLStatus = req.channel.securityInfo + .QueryInterface(Ci.nsISSLStatusProvider).SSLStatus; + gCert = gSSLStatus ? gSSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert + : null; + } + gBroken = evt.type == "error"; + gChecking = false; + updateCertStatus(); +} + /** * Attempt to download the certificate for the location specified, and populate * the Certificate Status section with the result. @@ -95,34 +91,18 @@ function checkCert() { gBroken = false; updateCertStatus(); - var uri = getURI(); + let uri = getURI(); - var req = new XMLHttpRequest(); - try { - if (uri) { - req.open('GET', uri.prePath, false); - req.channel.notificationCallbacks = new badCertListener(); - req.send(null); - } - } catch (e) { - // We *expect* exceptions if there are problems with the certificate - // presented by the site. Log it, just in case, but we can proceed here, - // with appropriate sanity checks - Components.utils.reportError("Attempted to connect to a site with a bad certificate in the add exception dialog. " + - "This results in a (mostly harmless) exception being thrown. " + - "Logged for information purposes only: " + e); - } finally { + if (uri) { + let req = new XMLHttpRequest(); + req.open("GET", uri.prePath); + req.onerror = grabCert.bind(this, req); + req.onload = grabCert.bind(this, req); + req.send(null); + } else { gChecking = false; + updateCertStatus(); } - - if (req.channel && req.channel.securityInfo) { - const Ci = Components.interfaces; - gSSLStatus = req.channel.securityInfo - .QueryInterface(Ci.nsISSLStatusProvider).SSLStatus; - gCert = gSSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert; - } - - updateCertStatus(); } /** -- cgit v1.2.3