commit 45184e903fd682f6eef5a44b6fa44df86a0dbc9f Author: Arthur Edelstein arthuredelstein@gmail.com Date: Sun Mar 5 23:50:15 2017 -0800
Bug 21547: Fix circuit display under e10s --- src/chrome/content/tor-circuit-display.js | 70 +++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 22 deletions(-)
diff --git a/src/chrome/content/tor-circuit-display.js b/src/chrome/content/tor-circuit-display.js index 14e5e8e..b5c24f8 100644 --- a/src/chrome/content/tor-circuit-display.js +++ b/src/chrome/content/tor-circuit-display.js @@ -26,7 +26,7 @@ let createTorCircuitDisplay = (function () { "use strict";
// Mozilla utilities -const Cu = Components.utils; +const { Cu : utils , Ci : interfaces } = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm");
@@ -34,7 +34,7 @@ Cu.import("resource://gre/modules/Task.jsm"); let { controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
// Utility functions -let { bindPrefAndInit } = Cu.import("resource://torbutton/modules/utils.js", {}); +let { bindPrefAndInit, observe } = Cu.import("resource://torbutton/modules/utils.js", {});
// Make the TorButton logger available. let logger = Cc["@torproject.org/torbutton-logger;1"] @@ -47,7 +47,10 @@ let logger = Cc["@torproject.org/torbutton-logger;1"] let credentialsToNodeDataMap = {}, // A mutable map that reports `true` for IDs of "mature" circuits // (those that have conveyed a stream). - knownCircuitIDs = {}; + knownCircuitIDs = {}, + // A mutable map that records the SOCKS credentials for the + // latest channels for each browser. + browserToCredentialsMap = new Map();
// __trimQuotes(s)__. // Removes quotation marks around a quoted string. @@ -154,6 +157,42 @@ let collectIsolationData = function (aController, updateUI) { }).then(null, Cu.reportError)); };
+// __browserForChannel(channel)__. +// Returns the browser that loaded a given channel. +let browserForChannel = function (channel) { + if (!channel) return null; + let chan = channel.QueryInterface(Ci.nsIChannel); + let callbacks = chan.notificationCallbacks; + if (!callbacks) return null; + let loadContext; + try { + loadContext = callbacks.getInterface(Ci.nsILoadContext); + } catch (e) { + // Ignore + return null; + } + if (!loadContext) return null; + return loadContext.topFrameElement; +}; + +// __collectBrowserCredentials()__. +// Starts observing http channels. Each channel's proxyInfo +// username and password is recorded for the channel's browser. +let collectBrowserCredentials = function () { + return observe("http-on-modify-request", chan => { + try { + let proxyInfo = chan.QueryInterface(Ci.nsIProxiedChannel).proxyInfo; + let browser = browserForChannel(chan); + if (browser && proxyInfo) { + browserToCredentialsMap.set(browser, [proxyInfo.username, + proxyInfo.password]); + } + } catch (e) { + logger.eclog(3, `Error collecting browser credentials: ${e.message}, ${chan.URI.spec}`); + } + }); +}; + // ## User interface
// __torbuttonBundle__. @@ -221,24 +260,6 @@ let nodeLines = function (nodeData) { return result; };
-// __getSOCKSCredentials(browser)__. -// Reads the SOCKS credentials for the corresponding browser object. -let getSOCKSCredentialsForBrowser = function (browser) { - if (browser === null) return null; - let docShell = browser.docShell; - if (docShell === null) return null; - let channel = docShell.currentDocumentChannel; - if (channel === null) return null; - if (channel instanceof Ci.nsIMultiPartChannel) { - channel = channel.baseChannel; - } - if (channel === null) return null; - if (!(channel instanceof Ci.nsIProxiedChannel)) return null; - let proxyInfo = channel.proxyInfo; - if (proxyInfo === null) return null; - return [proxyInfo.username, proxyInfo.password]; -}; - // __onionSiteRelayLine__. // When we have an onion site, we simply show the word '(relay)'. let onionSiteRelayLine = "<li class='relay'>(" + uiString("relay") + ")</li>"; @@ -249,7 +270,7 @@ let onionSiteRelayLine = "<li class='relay'>(" + uiString("relay") + ")</li>"; let updateCircuitDisplay = function () { let selectedBrowser = gBrowser.selectedBrowser; if (selectedBrowser) { - let credentials = getSOCKSCredentialsForBrowser(selectedBrowser), + let credentials = browserToCredentialsMap.get(selectedBrowser), nodeData = null; if (credentials) { let [SOCKS_username, SOCKS_password] = credentials; @@ -319,12 +340,16 @@ let syncDisplayWithSelectedTab = (function() { let setupDisplay = function (ipcFile, host, port, password, enablePrefName) { let myController = null, stopCollectingIsolationData = null, + stopCollectingBrowserCredentials = null, stop = function() { syncDisplayWithSelectedTab(false); if (myController) { if (stopCollectingIsolationData) { stopCollectingIsolationData(); } + if (stopCollectingBrowserCredentials) { + stopCollectingBrowserCredentials(); + } myController = null; } }, @@ -340,6 +365,7 @@ let setupDisplay = function (ipcFile, host, port, password, enablePrefName) { }); syncDisplayWithSelectedTab(true); stopCollectingIsolationData = collectIsolationData(myController, updateCircuitDisplay); + stopCollectingBrowserCredentials = collectBrowserCredentials(); } }; try {