Bug 768096 - Web Console remote debugging protocol support - Part 4: cleanups; r=robcee
☠☠ backed out by b18888e94143 ☠ ☠
authorMihai Sucan <mihai.sucan@gmail.com>
Wed, 26 Sep 2012 18:04:34 +0100
changeset 108506 9c70da27ec28f740cc2ae2f60394b17141ab452e
parent 108505 8c127abc3ad847cda3bbcec3b7f1e66ccd4a8942
child 108507 89ab8685729df08d361ffa99000fd13f74cbbc40
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersrobcee
bugs768096
milestone18.0a1
Bug 768096 - Web Console remote debugging protocol support - Part 4: cleanups; r=robcee
browser/devtools/jar.mn
browser/devtools/shared/DeveloperToolbar.jsm
browser/devtools/shared/test/browser_toolbar_webconsole_errors_count.js
browser/devtools/webconsole/HUDService-content.js
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js
browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
browser/devtools/webconsole/webconsole.js
toolkit/devtools/webconsole/WebConsoleUtils.jsm
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -2,17 +2,16 @@
 # 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/.
 
 browser.jar:
     content/browser/inspector.html                (highlighter/inspector.html)
     content/browser/devtools/markup-view.xhtml    (markupview/markup-view.xhtml)
     content/browser/devtools/markup-view.css      (markupview/markup-view.css)
     content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
-    content/browser/devtools/HUDService-content.js (webconsole/HUDService-content.js)
     content/browser/devtools/webconsole.js        (webconsole/webconsole.js)
 *   content/browser/devtools/webconsole.xul       (webconsole/webconsole.xul)
 *   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
     content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
     content/browser/splitview.css                 (shared/splitview.css)
     content/browser/styleeditor.xul               (styleeditor/styleeditor.xul)
     content/browser/styleeditor.css               (styleeditor/styleeditor.css)
     content/browser/devtools/csshtmltree.xul      (styleinspector/csshtmltree.xul)
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -3,34 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const EXPORTED_SYMBOLS = [ "DeveloperToolbar" ];
 
 const NS_XHTML = "http://www.w3.org/1999/xhtml";
 
-const WEBCONSOLE_CONTENT_SCRIPT_URL =
-  "chrome://browser/content/devtools/HUDService-content.js";
-
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource:///modules/devtools/Commands.jsm");
 
 const Node = Components.interfaces.nsIDOMNode;
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource://gre/modules/devtools/Console.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "gcli",
                                   "resource:///modules/devtools/gcli.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
                                   "resource:///modules/devtools/CmdCmd.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PageErrorListener",
+                                  "resource://gre/modules/devtools/WebConsoleUtils.jsm");
+
 /**
  * Due to a number of panel bugs we need a way to check if we are running on
  * Linux. See the comments for TooltipPanel and OutputPanel for further details.
  *
  * When bug 780102 is fixed all isLinux checks can be removed and we can revert
  * to using panels.
  */
 XPCOMUtils.defineLazyGetter(this, "isLinux", function () {
@@ -51,17 +51,18 @@ function DeveloperToolbar(aChromeWindow,
 
   this._element = aToolbarElement;
   this._element.hidden = true;
   this._doc = this._element.ownerDocument;
 
   this._lastState = NOTIFICATIONS.HIDE;
   this._pendingShowCallback = undefined;
   this._pendingHide = false;
-  this._errorsCount = {};
+  this._errorsCount = Object.create(null);
+  this._errorListeners = Object.create(null);
   this._webConsoleButton = this._doc
                            .getElementById("developer-toolbar-webconsole");
 
   try {
     CmdCommands.refreshAutoCommands(aChromeWindow);
   }
   catch (ex) {
     console.error(ex);
@@ -83,19 +84,16 @@ const NOTIFICATIONS = {
 };
 
 /**
  * Attach notification constants to the object prototype so tests etc can
  * use them without needing to import anything
  */
 DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS;
 
-DeveloperToolbar.prototype._contentMessageListeners =
-  ["WebConsole:CachedMessages", "WebConsole:PageError"];
-
 /**
  * Is the toolbar open?
  */
 Object.defineProperty(DeveloperToolbar.prototype, 'visible', {
   get: function DT_visible() {
     return !this._element.hidden;
   },
   enumerable: true
@@ -280,31 +278,28 @@ DeveloperToolbar.prototype._onload = fun
 DeveloperToolbar.prototype._initErrorsCount = function DT__initErrorsCount(aTab)
 {
   let tabId = aTab.linkedPanel;
   if (tabId in this._errorsCount) {
     this._updateErrorsCount();
     return;
   }
 
-  let messageManager = aTab.linkedBrowser.messageManager;
-  messageManager.loadFrameScript(WEBCONSOLE_CONTENT_SCRIPT_URL, true);
+  let window = aTab.linkedBrowser.contentWindow;
+  let listener = new PageErrorListener(window, {
+    onPageError: this._onPageError.bind(this, tabId),
+  });
+  listener.init();
 
+  this._errorListeners[tabId] = listener;
   this._errorsCount[tabId] = 0;
 
-  this._contentMessageListeners.forEach(function(aName) {
-    messageManager.addMessageListener(aName, this);
-  }, this);
+  let messages = listener.getCachedMessages();
+  messages.forEach(this._onPageError.bind(this, tabId));
 
-  let message = {
-    features: ["PageError"],
-    cachedMessages: ["PageError"],
-  };
-
-  this.sendMessageToTab(aTab, "WebConsole:Init", message);
   this._updateErrorsCount();
 };
 
 /**
  * Stop the listeners needed for tracking the number of errors for a given
  * tab.
  *
  * @private
@@ -314,24 +309,20 @@ DeveloperToolbar.prototype._initErrorsCo
 DeveloperToolbar.prototype._stopErrorsCount = function DT__stopErrorsCount(aTab)
 {
   let tabId = aTab.linkedPanel;
   if (!(tabId in this._errorsCount)) {
     this._updateErrorsCount();
     return;
   }
 
-  this.sendMessageToTab(aTab, "WebConsole:Destroy", {});
+  this._errorListeners[tabId].destroy();
+  delete this._errorListeners[tabId];
+  delete this._errorsCount[tabId];
 
-  let messageManager = aTab.linkedBrowser.messageManager;
-  this._contentMessageListeners.forEach(function(aName) {
-    messageManager.removeMessageListener(aName, this);
-  }, this);
-
-  delete this._errorsCount[tabId];
   this._updateErrorsCount();
 };
 
 /**
  * Hide the developer toolbar.
  */
 DeveloperToolbar.prototype.hide = function DT_hide()
 {
@@ -429,83 +420,36 @@ DeveloperToolbar.prototype.handleEvent =
     this._stopErrorsCount(aEvent.target);
   }
   else if (aEvent.type == "beforeunload") {
     this._onPageBeforeUnload(aEvent);
   }
 };
 
 /**
- * The handler of messages received from the nsIMessageManager.
- *
- * @param object aMessage the message received from the content process.
- */
-DeveloperToolbar.prototype.receiveMessage = function DT_receiveMessage(aMessage)
-{
-  if (!aMessage.json || !(aMessage.json.hudId in this._errorsCount)) {
-    return;
-  }
-
-  let tabId = aMessage.json.hudId;
-  let errors = this._errorsCount[tabId];
-
-  switch (aMessage.name) {
-    case "WebConsole:PageError":
-      this._onPageError(tabId, aMessage.json.pageError);
-      break;
-    case "WebConsole:CachedMessages":
-      aMessage.json.messages.forEach(this._onPageError.bind(this, tabId));
-      break;
-  }
-
-  if (errors != this._errorsCount[tabId]) {
-    this._updateErrorsCount(tabId);
-  }
-};
-
-/**
- * Send a message to the content process using the nsIMessageManager of the
- * given tab.
- *
- * @param nsIDOMNode aTab the tab you want to send a message to.
- * @param string aName the name of the message you want to send.
- * @param object aMessage the message to send.
- */
-DeveloperToolbar.prototype.sendMessageToTab =
-function DT_sendMessageToTab(aTab, aName, aMessage)
-{
-  let tabId = aTab.linkedPanel;
-  aMessage.hudId = tabId;
-  if (!("id" in aMessage)) {
-    aMessage.id = "DevToolbar-" + this.sequenceId;
-  }
-
-  aTab.linkedBrowser.messageManager.sendAsyncMessage(aName, aMessage);
-};
-
-/**
- * Process a "WebConsole:PageError" message received from the given tab. This
- * method counts the JavaScript exceptions received.
+ * Count a page error received for the currently selected tab. This
+ * method counts the JavaScript exceptions received and CSS errors/warnings.
  *
  * @private
  * @param string aTabId the ID of the tab from where the page error comes.
- * @param object aPageError the page error object received from the content
- * process.
+ * @param object aPageError the page error object received from the
+ * PageErrorListener.
  */
 DeveloperToolbar.prototype._onPageError =
 function DT__onPageError(aTabId, aPageError)
 {
   if (aPageError.category == "CSS Parser" ||
       aPageError.category == "CSS Loader" ||
       (aPageError.flags & aPageError.warningFlag) ||
       (aPageError.flags & aPageError.strictFlag)) {
     return; // just a CSS or JS warning
   }
 
   this._errorsCount[aTabId]++;
+  this._updateErrorsCount(aTabId);
 };
 
 /**
  * The |beforeunload| event handler. This function resets the errors count when
  * a different page starts loading.
  *
  * @private
  * @param nsIDOMEvent aEvent the beforeunload DOM event.
--- a/browser/devtools/shared/test/browser_toolbar_webconsole_errors_count.js
+++ b/browser/devtools/shared/test/browser_toolbar_webconsole_errors_count.js
@@ -42,18 +42,21 @@ function test() {
       value: 3,
       success: addErrors,
       failure: finish,
     });
   }
 
   function addErrors() {
     expectUncaughtException();
-    let button = content.document.querySelector("button");
-    EventUtils.synthesizeMouse(button, 2, 2, {}, content);
+
+    waitForFocus(function() {
+      let button = content.document.querySelector("button");
+      EventUtils.synthesizeMouse(button, 2, 2, {}, content);
+    }, content);
 
     waitForValue({
       name: "button shows one more error after click in page",
       validator: getErrorsCount,
       value: 4,
       success: function() {
         ignoreAllUncaughtExceptions();
         addTab(TEST_URI, onOpenSecondTab);
deleted file mode 100644
--- a/browser/devtools/webconsole/HUDService-content.js
+++ /dev/null
@@ -1,2541 +0,0 @@
-/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-"use strict";
-
-// This code is appended to the browser content script.
-(function _HUDServiceContent() {
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
-const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
-
-let tempScope = {};
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", tempScope);
-Cu.import("resource://gre/modules/Services.jsm", tempScope);
-Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", tempScope);
-Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tempScope);
-Cu.import("resource://gre/modules/devtools/NetworkHelper.jsm", tempScope);
-Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
-
-let XPCOMUtils = tempScope.XPCOMUtils;
-let Services = tempScope.Services;
-let gConsoleStorage = tempScope.ConsoleAPIStorage;
-let WebConsoleUtils = tempScope.WebConsoleUtils;
-let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
-let JSPropertyProvider = tempScope.JSPropertyProvider;
-let NetworkHelper = tempScope.NetworkHelper;
-let NetUtil = tempScope.NetUtil;
-tempScope = null;
-
-let activityDistributor = Cc["@mozilla.org/network/http-activity-distributor;1"].getService(Ci.nsIHttpActivityDistributor);
-
-let _alive = true; // Track if this content script should still be alive.
-
-/**
- * The Web Console content instance manager.
- */
-let Manager = {
-  get window() content,
-  hudId: null,
-  _sequence: 0,
-  _messageListeners: ["WebConsole:Init", "WebConsole:EnableFeature",
-                      "WebConsole:DisableFeature", "WebConsole:SetPreferences",
-                      "WebConsole:GetPreferences", "WebConsole:Destroy"],
-  _messageHandlers: null,
-  _enabledFeatures: null,
-  _prefs: { },
-
-  /**
-   * Getter for a unique ID for the current Web Console content instance.
-   */
-  get sequenceId() "HUDContent-" + (++this._sequence),
-
-  /**
-   * Initialize the Web Console manager.
-   */
-  init: function Manager_init()
-  {
-    this._enabledFeatures = [];
-    this._messageHandlers = {};
-
-    this._messageListeners.forEach(function(aName) {
-      addMessageListener(aName, this);
-    }, this);
-
-    // Need to track the owner XUL window to listen to the unload and TabClose
-    // events, to avoid memory leaks.
-    let xulWindow = this._xulWindow();
-    xulWindow.addEventListener("unload", this._onXULWindowClose, false);
-
-    let tabContainer = xulWindow.gBrowser.tabContainer;
-    tabContainer.addEventListener("TabClose", this._onTabClose, false);
-
-    // Need to track private browsing change and quit application notifications,
-    // again to avoid memory leaks. The Web Console main process cannot notify
-    // this content script when the XUL window close, tab close, private
-    // browsing change and quit application events happen, so we must call
-    // Manager.destroy() on our own.
-    Services.obs.addObserver(this, "private-browsing-change-granted", false);
-    Services.obs.addObserver(this, "quit-application-granted", false);
-  },
-
-  /**
-   * The message handler. This method forwards all the remote messages to the
-   * appropriate code.
-   */
-  receiveMessage: function Manager_receiveMessage(aMessage)
-  {
-    if (!_alive || !aMessage.json) {
-      return;
-    }
-
-    if (aMessage.name == "WebConsole:Init" && !this.hudId) {
-      this._onInit(aMessage.json);
-      return;
-    }
-    if (aMessage.json.hudId != this.hudId) {
-      return;
-    }
-
-    switch (aMessage.name) {
-      case "WebConsole:EnableFeature":
-        this.enableFeature(aMessage.json.feature, aMessage.json);
-        break;
-      case "WebConsole:DisableFeature":
-        this.disableFeature(aMessage.json.feature);
-        break;
-      case "WebConsole:GetPreferences":
-        this.handleGetPreferences(aMessage.json);
-        break;
-      case "WebConsole:SetPreferences":
-        this.handleSetPreferences(aMessage.json);
-        break;
-      case "WebConsole:Destroy":
-        this.destroy();
-        break;
-      default: {
-        let handler = this._messageHandlers[aMessage.name];
-        handler && handler(aMessage.json);
-        break;
-      }
-    }
-  },
-
-  /**
-   * Observe notifications from the nsIObserverService.
-   *
-   * @param mixed aSubject
-   * @param string aTopic
-   * @param mixed aData
-   */
-  observe: function Manager_observe(aSubject, aTopic, aData)
-  {
-    if (_alive && (aTopic == "quit-application-granted" ||
-        (aTopic == "private-browsing-change-granted" &&
-         (aData == "enter" || aData == "exit")))) {
-      this.destroy();
-    }
-  },
-
-  /**
-   * The manager initialization code. This method is called when the Web Console
-   * remote process initializes the content process (this code!).
-   *
-   * @param object aMessage
-   *        The object received from the remote process. The WebConsole:Init
-   *        message properties:
-   *        - hudId - (required) the remote Web Console instance ID.
-   *        - features - (optional) array of features you want to enable from
-   *        the start. For each feature you enable you can pass feature-specific
-   *        options in a property on the JSON object you send with the same name
-   *        as the feature. See this.enableFeature() for the list of available
-   *        features.
-   *        - preferences - (optional) an object of preferences you want to set.
-   *        Use keys for preference names and values for preference values.
-   *        - cachedMessages - (optional) an array of cached messages you want
-   *        to receive. See this._sendCachedMessages() for the list of available
-   *        message types.
-   *
-   *        Example message:
-   *        {
-   *          hudId: "foo1",
-   *          features: ["JSTerm", "ConsoleAPI"],
-   *          ConsoleAPI: { ... }, // ConsoleAPI-specific options
-   *          cachedMessages: ["ConsoleAPI"],
-   *          preferences: {"foo.bar": true},
-   *        }
-   */
-  _onInit: function Manager_onInit(aMessage)
-  {
-    this.hudId = aMessage.hudId;
-
-    if (aMessage.preferences) {
-      this.handleSetPreferences({ preferences: aMessage.preferences });
-    }
-
-    if (aMessage.features) {
-      aMessage.features.forEach(function(aFeature) {
-        this.enableFeature(aFeature, aMessage[aFeature]);
-      }, this);
-    }
-
-    if (aMessage.cachedMessages) {
-      this._sendCachedMessages(aMessage.cachedMessages);
-    }
-
-    this.sendMessage("WebConsole:Initialized", {});
-  },
-
-  /**
-   * Add a remote message handler. This is used by other components of the Web
-   * Console content script.
-   *
-   * @param string aName
-   *        Message name to listen for.
-   * @param function aCallback
-   *        Function to execute when the message is received. This function is
-   *        given the JSON object that came from the remote Web Console
-   *        instance.
-   *        Only one callback per message name is allowed!
-   */
-  addMessageHandler: function Manager_addMessageHandler(aName, aCallback)
-  {
-    if (aName in this._messageHandlers) {
-      Cu.reportError("Web Console content script: addMessageHandler() called for an existing message handler: " + aName);
-      return;
-    }
-
-    this._messageHandlers[aName] = aCallback;
-    addMessageListener(aName, this);
-  },
-
-  /**
-   * Remove the message handler for the given name.
-   *
-   * @param string aName
-   *        Message name for the handler you want removed.
-   */
-  removeMessageHandler: function Manager_removeMessageHandler(aName)
-  {
-    if (!(aName in this._messageHandlers)) {
-      return;
-    }
-
-    delete this._messageHandlers[aName];
-    removeMessageListener(aName, this);
-  },
-
-  /**
-   * Send a message to the remote Web Console instance.
-   *
-   * @param string aName
-   *        The name of the message you want to send.
-   * @param object aMessage
-   *        The message object you want to send.
-   */
-  sendMessage: function Manager_sendMessage(aName, aMessage)
-  {
-    aMessage.hudId = this.hudId;
-    if (!("id" in aMessage)) {
-      aMessage.id = this.sequenceId;
-    }
-
-    sendAsyncMessage(aName, aMessage);
-  },
-
-  /**
-   * Enable a feature in the Web Console content script. A feature is generally
-   * a set of observers/listeners that are added in the content process. This
-   * content script exposes the data via the message manager for the features
-   * you enable.
-   *
-   * Supported features:
-   *    - JSTerm - a JavaScript "terminal" which allows code execution.
-   *    - ConsoleAPI - support for routing the window.console API to the remote
-   *    process.
-   *    - PageError - route all the nsIScriptErrors from the nsIConsoleService
-   *    to the remote process.
-   *    - NetworkMonitor - log all the network activity and send HAR-like
-   *    messages to the remote Web Console process.
-   *    - LocationChange - log page location changes. See
-   *    ConsoleProgressListener.
-   *
-   * @param string aFeature
-   *        One of the supported features.
-   * @param object [aMessage]
-   *        Optional JSON message object coming from the remote Web Console
-   *        instance. This can be used for feature-specific options.
-   */
-  enableFeature: function Manager_enableFeature(aFeature, aMessage)
-  {
-    if (this._enabledFeatures.indexOf(aFeature) != -1) {
-      return;
-    }
-
-    switch (aFeature) {
-      case "JSTerm":
-        JSTerm.init(aMessage);
-        break;
-      case "ConsoleAPI":
-        ConsoleAPIObserver.init(aMessage);
-        break;
-      case "PageError":
-        ConsoleListener.init(aMessage);
-        break;
-      case "NetworkMonitor":
-        NetworkMonitor.init(aMessage);
-        break;
-      case "LocationChange":
-        ConsoleProgressListener.startMonitor(ConsoleProgressListener
-                                             .MONITOR_LOCATION_CHANGE);
-        ConsoleProgressListener.sendLocation(this.window.location.href,
-                                             this.window.document.title);
-        break;
-      default:
-        Cu.reportError("Web Console content: unknown feature " + aFeature);
-        break;
-    }
-
-    this._enabledFeatures.push(aFeature);
-  },
-
-  /**
-   * Disable a Web Console content script feature.
-   *
-   * @see this.enableFeature
-   * @param string aFeature
-   *        One of the supported features - see this.enableFeature() for the
-   *        list of supported features.
-   */
-  disableFeature: function Manager_disableFeature(aFeature)
-  {
-    let index = this._enabledFeatures.indexOf(aFeature);
-    if (index == -1) {
-      return;
-    }
-    this._enabledFeatures.splice(index, 1);
-
-    switch (aFeature) {
-      case "JSTerm":
-        JSTerm.destroy();
-        break;
-      case "ConsoleAPI":
-        ConsoleAPIObserver.destroy();
-        break;
-      case "PageError":
-        ConsoleListener.destroy();
-        break;
-      case "NetworkMonitor":
-        NetworkMonitor.destroy();
-        break;
-      case "LocationChange":
-        ConsoleProgressListener.stopMonitor(ConsoleProgressListener
-                                            .MONITOR_LOCATION_CHANGE);
-        break;
-      default:
-        Cu.reportError("Web Console content: unknown feature " + aFeature);
-        break;
-    }
-  },
-
-  /**
-   * Handle the "WebConsole:GetPreferences" messages from the remote Web Console
-   * instance.
-   *
-   * @param object aMessage
-   *        The JSON object of the remote message. This object holds one
-   *        property: preferences. The |preferences| value must be an array of
-   *        preference names you want to retrieve the values for.
-   *        A "WebConsole:Preferences" message is sent back to the remote Web
-   *        Console instance. The message holds a |preferences| object which has
-   *        key names for preference names and values for each preference value.
-   */
-  handleGetPreferences: function Manager_handleGetPreferences(aMessage)
-  {
-    let prefs = {};
-    aMessage.preferences.forEach(function(aName) {
-      prefs[aName] = this.getPreference(aName);
-    }, this);
-
-    this.sendMessage("WebConsole:Preferences", {preferences: prefs});
-  },
-
-  /**
-   * Handle the "WebConsole:SetPreferences" messages from the remote Web Console
-   * instance.
-   *
-   * @param object aMessage
-   *        The JSON object of the remote message. This object holds one
-   *        property: preferences. The |preferences| value must be an object of
-   *        preference names as keys and preference values as object values, for
-   *        each preference you want to change.
-   */
-  handleSetPreferences: function Manager_handleSetPreferences(aMessage)
-  {
-    for (let key in aMessage.preferences) {
-      this.setPreference(key, aMessage.preferences[key]);
-    }
-  },
-
-  /**
-   * Retrieve a preference.
-   *
-   * @param string aName
-   *        Preference name.
-   * @return mixed|null
-   *         Preference value. Null is returned if the preference does not
-   *         exist.
-   */
-  getPreference: function Manager_getPreference(aName)
-  {
-    return aName in this._prefs ? this._prefs[aName] : null;
-  },
-
-  /**
-   * Set a preference to a new value.
-   *
-   * @param string aName
-   *        Preference name.
-   * @param mixed aValue
-   *        Preference value.
-   */
-  setPreference: function Manager_setPreference(aName, aValue)
-  {
-    this._prefs[aName] = aValue;
-  },
-
-  /**
-   * Send the cached messages to the remote Web Console instance.
-   *
-   * @private
-   * @param array aMessageTypes
-   *        An array that lists which kinds of messages you want. Supported
-   *        message types: "ConsoleAPI" and "PageError".
-   */
-  _sendCachedMessages: function Manager__sendCachedMessages(aMessageTypes)
-  {
-    let messages = [];
-
-    while (aMessageTypes.length > 0) {
-      switch (aMessageTypes.shift()) {
-        case "ConsoleAPI":
-          messages.push.apply(messages, ConsoleAPIObserver.getCachedMessages());
-          break;
-        case "PageError":
-          messages.push.apply(messages, ConsoleListener.getCachedMessages());
-          break;
-      }
-    }
-
-    messages.sort(function(a, b) { return a.timeStamp - b.timeStamp; });
-
-    this.sendMessage("WebConsole:CachedMessages", {messages: messages});
-  },
-
-  /**
-   * The XUL window "unload" event handler which destroys this content script
-   * instance.
-   * @private
-   */
-  _onXULWindowClose: function Manager__onXULWindowClose()
-  {
-    if (_alive) {
-      Manager.destroy();
-    }
-  },
-
-  /**
-   * The "TabClose" event handler which destroys this content script
-   * instance, if needed.
-   * @private
-   */
-  _onTabClose: function Manager__onTabClose(aEvent)
-  {
-    let tab = aEvent.target;
-    if (_alive && tab.linkedBrowser.contentWindow === Manager.window) {
-      Manager.destroy();
-    }
-  },
-
-  /**
-   * Find the XUL window that owns the content script.
-   * @private
-   * @return Window
-   *         The XUL window that owns the content script.
-   */
-  _xulWindow: function Manager__xulWindow()
-  {
-    return this.window.QueryInterface(Ci.nsIInterfaceRequestor)
-           .getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell)
-           .chromeEventHandler.ownerDocument.defaultView;
-  },
-
-  /**
-   * Destroy the Web Console content script instance.
-   */
-  destroy: function Manager_destroy()
-  {
-    Services.obs.removeObserver(this, "private-browsing-change-granted");
-    Services.obs.removeObserver(this, "quit-application-granted");
-
-    _alive = false;
-    let xulWindow = this._xulWindow();
-    xulWindow.removeEventListener("unload", this._onXULWindowClose, false);
-    let tabContainer = xulWindow.gBrowser.tabContainer;
-    tabContainer.removeEventListener("TabClose", this._onTabClose, false);
-
-    this._messageListeners.forEach(function(aName) {
-      removeMessageListener(aName, this);
-    }, this);
-
-    this._enabledFeatures.slice().forEach(this.disableFeature, this);
-
-    this.hudId = null;
-    this._messageHandlers = null;
-
-    Manager = ConsoleAPIObserver = JSTerm = ConsoleListener = NetworkMonitor =
-      NetworkResponseListener = ConsoleProgressListener = null;
-
-    XPCOMUtils = gConsoleStorage = WebConsoleUtils = l10n = JSPropertyProvider =
-      null;
-  },
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// JavaScript Terminal
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * JSTerm helper functions.
- *
- * Defines a set of functions ("helper functions") that are available from the
- * Web Console but not from the web page.
- *
- * A list of helper functions used by Firebug can be found here:
- *   http://getfirebug.com/wiki/index.php/Command_Line_API
- */
-function JSTermHelper(aJSTerm)
-{
-  /**
-   * Find a node by ID.
-   *
-   * @param string aId
-   *        The ID of the element you want.
-   * @return nsIDOMNode or null
-   *         The result of calling document.querySelector(aSelector).
-   */
-  aJSTerm.sandbox.$ = function JSTH_$(aSelector)
-  {
-    return aJSTerm.window.document.querySelector(aSelector);
-  };
-
-  /**
-   * Find the nodes matching a CSS selector.
-   *
-   * @param string aSelector
-   *        A string that is passed to window.document.querySelectorAll.
-   * @return nsIDOMNodeList
-   *         Returns the result of document.querySelectorAll(aSelector).
-   */
-  aJSTerm.sandbox.$$ = function JSTH_$$(aSelector)
-  {
-    return aJSTerm.window.document.querySelectorAll(aSelector);
-  };
-
-  /**
-   * Runs an xPath query and returns all matched nodes.
-   *
-   * @param string aXPath
-   *        xPath search query to execute.
-   * @param [optional] nsIDOMNode aContext
-   *        Context to run the xPath query on. Uses window.document if not set.
-   * @returns array of nsIDOMNode
-   */
-  aJSTerm.sandbox.$x = function JSTH_$x(aXPath, aContext)
-  {
-    let nodes = [];
-    let doc = aJSTerm.window.document;
-    let aContext = aContext || doc;
-
-    try {
-      let results = doc.evaluate(aXPath, aContext, null,
-                                 Ci.nsIDOMXPathResult.ANY_TYPE, null);
-      let node;
-      while (node = results.iterateNext()) {
-        nodes.push(node);
-      }
-    }
-    catch (ex) {
-      aJSTerm.console.error(ex.message);
-    }
-
-    return nodes;
-  };
-
-  /**
-   * Returns the currently selected object in the highlighter.
-   *
-   * Warning: this implementation crosses the process boundaries! This is not
-   * usable within a remote browser. To implement this feature correctly we need
-   * support for remote inspection capabilities within the Inspector as well.
-   *
-   * @return nsIDOMElement|null
-   *         The DOM element currently selected in the highlighter.
-   */
-  Object.defineProperty(aJSTerm.sandbox, "$0", {
-    get: function() {
-      try {
-        return Manager._xulWindow().InspectorUI.selection;
-      }
-      catch (ex) {
-        aJSTerm.console.error(ex.message);
-      }
-    },
-    enumerable: true,
-    configurable: false
-  });
-
-  /**
-   * Clears the output of the JSTerm.
-   */
-  aJSTerm.sandbox.clear = function JSTH_clear()
-  {
-    aJSTerm.helperEvaluated = true;
-    Manager.sendMessage("JSTerm:ClearOutput", {});
-  };
-
-  /**
-   * Returns the result of Object.keys(aObject).
-   *
-   * @param object aObject
-   *        Object to return the property names from.
-   * @returns array of string
-   */
-  aJSTerm.sandbox.keys = function JSTH_keys(aObject)
-  {
-    return Object.keys(WebConsoleUtils.unwrap(aObject));
-  };
-
-  /**
-   * Returns the values of all properties on aObject.
-   *
-   * @param object aObject
-   *        Object to display the values from.
-   * @returns array of string
-   */
-  aJSTerm.sandbox.values = function JSTH_values(aObject)
-  {
-    let arrValues = [];
-    let obj = WebConsoleUtils.unwrap(aObject);
-
-    try {
-      for (let prop in obj) {
-        arrValues.push(obj[prop]);
-      }
-    }
-    catch (ex) {
-      aJSTerm.console.error(ex.message);
-    }
-    return arrValues;
-  };
-
-  /**
-   * Opens a help window in MDN.
-   */
-  aJSTerm.sandbox.help = function JSTH_help()
-  {
-    aJSTerm.helperEvaluated = true;
-    aJSTerm.window.open(
-        "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers",
-        "help", "");
-  };
-
-  /**
-   * Inspects the passed aObject. This is done by opening the PropertyPanel.
-   *
-   * @param object aObject
-   *        Object to inspect.
-   */
-  aJSTerm.sandbox.inspect = function JSTH_inspect(aObject)
-  {
-    if (!WebConsoleUtils.isObjectInspectable(aObject)) {
-      return aObject;
-    }
-
-    aJSTerm.helperEvaluated = true;
-
-    let message = {
-      input: aJSTerm._evalInput,
-      objectCacheId: Manager.sequenceId,
-    };
-
-    message.resultObject =
-      aJSTerm.prepareObjectForRemote(WebConsoleUtils.unwrap(aObject),
-                                     message.objectCacheId);
-
-    Manager.sendMessage("JSTerm:InspectObject", message);
-  };
-
-  /**
-   * Prints aObject to the output.
-   *
-   * @param object aObject
-   *        Object to print to the output.
-   * @return string
-   */
-  aJSTerm.sandbox.pprint = function JSTH_pprint(aObject)
-  {
-    aJSTerm.helperEvaluated = true;
-    if (aObject === null || aObject === undefined || aObject === true ||
-        aObject === false) {
-      aJSTerm.console.error(l10n.getStr("helperFuncUnsupportedTypeError"));
-      return;
-    }
-    else if (typeof aObject == "function") {
-      aJSTerm.helperRawOutput = true;
-      return aObject + "\n";
-    }
-
-    aJSTerm.helperRawOutput = true;
-
-    let output = [];
-    let pairs = WebConsoleUtils.namesAndValuesOf(WebConsoleUtils.unwrap(aObject));
-    pairs.forEach(function(aPair) {
-      output.push(aPair.name + ": " + aPair.value);
-    });
-
-    return "  " + output.join("\n  ");
-  };
-
-  /**
-   * Print a string to the output, as-is.
-   *
-   * @param string aString
-   *        A string you want to output.
-   * @returns void
-   */
-  aJSTerm.sandbox.print = function JSTH_print(aString)
-  {
-    aJSTerm.helperEvaluated = true;
-    aJSTerm.helperRawOutput = true;
-    return String(aString);
-  };
-}
-
-/**
- * The JavaScript terminal is meant to allow remote code execution for the Web
- * Console.
- */
-let JSTerm = {
-  get window() Manager.window,
-  get console() this.window.console,
-
-  /**
-   * The Cu.Sandbox() object where code is evaluated.
-   */
-  sandbox: null,
-
-  _sandboxLocation: null,
-  _messageHandlers: {},
-
-  /**
-   * Evaluation result objects are cached in this object. The chrome process can
-   * request any object based on its ID.
-   */
-  _objectCache: null,
-
-  /**
-   * Initialize the JavaScript terminal feature.
-   *
-   * @param object aMessage
-   *        Options for JSTerm sent from the remote Web Console instance. This
-   *        object holds the following properties:
-   *
-   *          - notifyNonNativeConsoleAPI - boolean that tells if you want to be
-   *          notified if the window.console API object in the page is not the
-   *          native one (if the page overrides it).
-   *          A "JSTerm:NonNativeConsoleAPI" message will be sent if this is the
-   *          case.
-   */
-  init: function JST_init(aMessage)
-  {
-    this._objectCache = {};
-    this._messageHandlers = {
-      "JSTerm:EvalRequest": this.handleEvalRequest,
-      "JSTerm:GetEvalObject": this.handleGetEvalObject,
-      "JSTerm:Autocomplete": this.handleAutocomplete,
-      "JSTerm:ClearObjectCache": this.handleClearObjectCache,
-    };
-
-    for (let name in this._messageHandlers) {
-      let handler = this._messageHandlers[name].bind(this);
-      Manager.addMessageHandler(name, handler);
-    }
-
-    if (aMessage && aMessage.notifyNonNativeConsoleAPI) {
-      let consoleObject = WebConsoleUtils.unwrap(this.window).console;
-      if (!("__mozillaConsole__" in consoleObject)) {
-        Manager.sendMessage("JSTerm:NonNativeConsoleAPI", {});
-      }
-    }
-  },
-
-  /**
-   * Handler for the "JSTerm:EvalRequest" remote message. This method evaluates
-   * user input in the JavaScript sandbox and sends the result back to the
-   * remote process. The "JSTerm:EvalResult" message includes the following
-   * data:
-   *   - id - the same ID as the EvalRequest (for tracking purposes).
-   *   - input - the JS string that was evaluated.
-   *   - resultString - the evaluation result converted to a string formatted
-   *   for display.
-   *   - timestamp - timestamp when evaluation occurred (Date.now(),
-   *   milliseconds since the UNIX epoch).
-   *   - inspectable - boolean that tells if the evaluation result object can be
-   *   inspected or not.
-   *   - error - the evaluation exception object (if any).
-   *   - errorMessage - the exception object converted to a string (if any error
-   *   occurred).
-   *   - helperResult - boolean that tells if a JSTerm helper was evaluated.
-   *   - helperRawOutput - boolean that tells if the helper evaluation result
-   *   should be displayed as raw output.
-   *
-   *   If the result object is inspectable then two additional properties are
-   *   included:
-   *     - childrenCacheId - tells where child objects are cached. This is the
-   *     same as aRequest.resultCacheId.
-   *     - resultObject - the result object prepared for the remote process. See
-   *     this.prepareObjectForRemote().
-   *
-   * @param object aRequest
-   *        The code evaluation request object:
-   *          - id - request ID.
-   *          - str - string to evaluate.
-   *          - resultCacheId - where to cache the evaluation child objects.
-   */
-  handleEvalRequest: function JST_handleEvalRequest(aRequest)
-  {
-    let id = aRequest.id;
-    let input = aRequest.str;
-    let result, error = null;
-    let timestamp;
-
-    this.helperEvaluated = false;
-    this.helperRawOutput = false;
-    this._evalInput = input;
-    try {
-      timestamp = Date.now();
-      result = this.evalInSandbox(input);
-    }
-    catch (ex) {
-      error = ex;
-    }
-    delete this._evalInput;
-
-    let inspectable = !error && WebConsoleUtils.isObjectInspectable(result);
-    let resultString = undefined;
-    if (!error) {
-      resultString = this.helperRawOutput ? result :
-                     WebConsoleUtils.formatResult(result);
-    }
-
-    let message = {
-      id: id,
-      input: input,
-      resultString: resultString,
-      timestamp: timestamp,
-      error: error,
-      errorMessage: error ? String(error) : null,
-      inspectable: inspectable,
-      helperResult: this.helperEvaluated,
-      helperRawOutput: this.helperRawOutput,
-    };
-
-    if (inspectable) {
-      message.childrenCacheId = aRequest.resultCacheId;
-      message.resultObject =
-        this.prepareObjectForRemote(result, message.childrenCacheId);
-    }
-
-    Manager.sendMessage("JSTerm:EvalResult", message);
-  },
-
-  /**
-   * Handler for the remote "JSTerm:GetEvalObject" message. This allows the
-   * remote Web Console instance to retrieve an object from the content process.
-   * The "JSTerm:EvalObject" message is sent back to the remote process:
-   *   - id - the request ID, used to trace back to the initial request.
-   *   - cacheId - the cache ID where the requested object is stored.
-   *   - objectId - the ID of the object being sent.
-   *   - object - the object representation prepared for remote inspection. See
-   *   this.prepareObjectForRemote().
-   *   - childrenCacheId - the cache ID where any child object of |object| are
-   *   stored.
-   *
-   * @param object aRequest
-   *        The message that requests the content object. Properties: cacheId,
-   *        objectId and resultCacheId.
-   *
-   *        Evaluated objects are stored in "buckets" (cache IDs). Each object
-   *        is assigned an ID (object ID). You can request a specific object
-   *        (objectId) from a specific cache (cacheId) and tell where the result
-   *        should be cached (resultCacheId). The requested object can have
-   *        further references to other objects - those references will be
-   *        cached in the "bucket" of your choice (based on resultCacheId). If
-   *        you do not provide any resultCacheId in the request message, then
-   *        cacheId will be used.
-   */
-  handleGetEvalObject: function JST_handleGetEvalObject(aRequest)
-  {
-    if (aRequest.cacheId in this._objectCache &&
-        aRequest.objectId in this._objectCache[aRequest.cacheId]) {
-      let object = this._objectCache[aRequest.cacheId][aRequest.objectId];
-      let resultCacheId = aRequest.resultCacheId || aRequest.cacheId;
-      let message = {
-        id: aRequest.id,
-        cacheId: aRequest.cacheId,
-        objectId: aRequest.objectId,
-        object: this.prepareObjectForRemote(object, resultCacheId),
-        childrenCacheId: resultCacheId,
-      };
-      Manager.sendMessage("JSTerm:EvalObject", message);
-    }
-    else {
-      Cu.reportError("JSTerm:GetEvalObject request " + aRequest.id +
-                     ": stale object.");
-    }
-  },
-
-  /**
-   * Handler for the remote "JSTerm:ClearObjectCache" message. This allows the
-   * remote Web Console instance to clear the cache of objects that it no longer
-   * uses.
-   *
-   * @param object aRequest
-   *        An object that holds one property: the cacheId you want cleared.
-   */
-  handleClearObjectCache: function JST_handleClearObjectCache(aRequest)
-  {
-    if (aRequest.cacheId in this._objectCache) {
-      delete this._objectCache[aRequest.cacheId];
-    }
-  },
-
-  /**
-   * Prepare an object to be sent to the remote Web Console instance.
-   *
-   * @param object aObject
-   *        The object you want to send to the remote Web Console instance.
-   * @param number aCacheId
-   *        Cache ID where you want object references to be stored into. The
-   *        given object may include references to other objects - those
-   *        references will be stored in the given cache ID so the remote
-   *        process can later retrieve them as well.
-   * @return array
-   *         An array that holds one element for each enumerable property and
-   *         method in aObject. Each element describes the property. For details
-   *         see WebConsoleUtils.namesAndValuesOf().
-   */
-  prepareObjectForRemote: function JST_prepareObjectForRemote(aObject, aCacheId)
-  {
-    // Cache the properties that have inspectable values.
-    let propCache = this._objectCache[aCacheId] || {};
-    let result = WebConsoleUtils.namesAndValuesOf(aObject, propCache);
-    if (!(aCacheId in this._objectCache) && Object.keys(propCache).length > 0) {
-      this._objectCache[aCacheId] = propCache;
-    }
-
-    return result;
-  },
-
-  /**
-   * Handler for the "JSTerm:Autocomplete" remote message. This handler provides
-   * completion results for user input. The "JSterm:AutocompleteProperties"
-   * message is sent to the remote process:
-   *   - id - the same as request ID.
-   *   - input - the user input (same as in the request message).
-   *   - matches - an array of matched properties (strings).
-   *   - matchProp - the part that was used from the user input for finding the
-   *   matches. For details see the JSPropertyProvider description and
-   *   implementation.
-   *
-   *
-   * @param object aRequest
-   *        The remote request object which holds two properties: an |id| and
-   *        the user |input|.
-   */
-  handleAutocomplete: function JST_handleAutocomplete(aRequest)
-  {
-    let result = JSPropertyProvider(this.window, aRequest.input) || {};
-    let message = {
-      id: aRequest.id,
-      input: aRequest.input,
-      matches: result.matches || [],
-      matchProp: result.matchProp,
-    };
-    Manager.sendMessage("JSTerm:AutocompleteProperties", message);
-  },
-
-  /**
-   * Create the JavaScript sandbox where user input is evaluated.
-   * @private
-   */
-  _createSandbox: function JST__createSandbox()
-  {
-    this._sandboxLocation = this.window.location;
-    this.sandbox = new Cu.Sandbox(this.window, {
-      sandboxPrototype: this.window,
-      wantXrays: false,
-    });
-
-    this.sandbox.console = this.console;
-
-    JSTermHelper(this);
-  },
-
-  /**
-   * Evaluates a string in the sandbox.
-   *
-   * @param string aString
-   *        String to evaluate in the sandbox.
-   * @return mixed
-   *         The result of the evaluation.
-   */
-  evalInSandbox: function JST_evalInSandbox(aString)
-  {
-    // If the user changed to a different location, we need to update the
-    // sandbox.
-    if (this._sandboxLocation !== this.window.location) {
-      this._createSandbox();
-    }
-
-    // The help function needs to be easy to guess, so we make the () optional
-    if (aString.trim() == "help" || aString.trim() == "?") {
-      aString = "help()";
-    }
-
-    let window = WebConsoleUtils.unwrap(this.sandbox.window);
-    let $ = null, $$ = null;
-
-    // We prefer to execute the page-provided implementations for the $() and
-    // $$() functions.
-    if (typeof window.$ == "function") {
-      $ = this.sandbox.$;
-      delete this.sandbox.$;
-    }
-    if (typeof window.$$ == "function") {
-      $$ = this.sandbox.$$;
-      delete this.sandbox.$$;
-    }
-
-    let result = Cu.evalInSandbox(aString, this.sandbox, "1.8",
-                                  "Web Console", 1);
-
-    if ($) {
-      this.sandbox.$ = $;
-    }
-    if ($$) {
-      this.sandbox.$$ = $$;
-    }
-
-    return result;
-  },
-
-  /**
-   * Destroy the JSTerm instance.
-   */
-  destroy: function JST_destroy()
-  {
-    for (let name in this._messageHandlers) {
-      Manager.removeMessageHandler(name);
-    }
-
-    delete this.sandbox;
-    delete this._sandboxLocation;
-    delete this._messageHandlers;
-    delete this._objectCache;
-  },
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// The window.console API observer
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * The window.console API observer. This allows the window.console API messages
- * to be sent to the remote Web Console instance.
- */
-let ConsoleAPIObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
-
-  /**
-   * Initialize the window.console API observer.
-   */
-  init: function CAO_init()
-  {
-    // Note that the observer is process-wide. We will filter the messages as
-    // needed, see CAO_observe().
-    Services.obs.addObserver(this, "console-api-log-event", false);
-
-    Manager.addMessageHandler("ConsoleAPI:ClearCache",
-                              this.handleClearCache.bind(this));
-  },
-
-  /**
-   * The console API message observer. When messages are received from the
-   * observer service we forward them to the remote Web Console instance.
-   *
-   * @param object aMessage
-   *        The message object receives from the observer service.
-   * @param string aTopic
-   *        The message topic received from the observer service.
-   */
-  observe: function CAO_observe(aMessage, aTopic)
-  {
-    if (!_alive || !aMessage || aTopic != "console-api-log-event") {
-      return;
-    }
-
-    let apiMessage = aMessage.wrappedJSObject;
-
-    let msgWindow =
-      WebConsoleUtils.getWindowByOuterId(apiMessage.ID, Manager.window);
-    if (!msgWindow || msgWindow.top != Manager.window) {
-      // Not the same window!
-      return;
-    }
-
-    let messageToChrome = {};
-    this._prepareApiMessageForRemote(apiMessage, messageToChrome);
-    Manager.sendMessage("WebConsole:ConsoleAPI", messageToChrome);
-  },
-
-  /**
-   * Prepare a message from the console APi to be sent to the remote Web Console
-   * instance.
-   *
-   * @param object aOriginalMessage
-   *        The original message received from console-api-log-event.
-   * @param object aRemoteMessage
-   *        The object you want to send to the remote Web Console. This object
-   *        is updated to hold information from the original message. New
-   *        properties added:
-   *        - timeStamp
-   *        Message timestamp (same as the aOriginalMessage.timeStamp property).
-   *        - apiMessage
-   *        An object that copies almost all the properties from
-   *        aOriginalMessage. Arguments might be skipped if it holds references
-   *        to objects that cannot be sent as they are to the remote Web Console
-   *        instance.
-   *        - argumentsToString
-   *        Optional: the aOriginalMessage.arguments object stringified.
-   *
-   *        The apiMessage.arguments property is set to hold data appropriate
-   *        to the message level. A similar approach is used for
-   *        argumentsToString.
-   */
-  _prepareApiMessageForRemote:
-  function CAO__prepareApiMessageForRemote(aOriginalMessage, aRemoteMessage)
-  {
-    aRemoteMessage.apiMessage =
-      WebConsoleUtils.cloneObject(aOriginalMessage, true,
-        function(aKey, aValue, aObject) {
-          // We need to skip the arguments property from the original object.
-          if (aKey == "wrappedJSObject" || aObject === aOriginalMessage &&
-              aKey == "arguments") {
-            return false;
-          }
-          return true;
-        });
-
-    aRemoteMessage.timeStamp = aOriginalMessage.timeStamp;
-
-    switch (aOriginalMessage.level) {
-      case "trace":
-      case "time":
-      case "timeEnd":
-      case "group":
-      case "groupCollapsed":
-        aRemoteMessage.apiMessage.arguments =
-          WebConsoleUtils.cloneObject(aOriginalMessage.arguments, true);
-        break;
-
-      case "groupEnd":
-        aRemoteMessage.argumentsToString =
-          Array.map(aOriginalMessage.arguments || [],
-                    this._formatObject.bind(this));
-        break;
-
-      case "log":
-      case "info":
-      case "warn":
-      case "error":
-      case "debug":
-      case "dir": {
-        aRemoteMessage.objectsCacheId = Manager.sequenceId;
-        aRemoteMessage.argumentsToString = [];
-        let mapFunction = function(aItem) {
-          let formattedObject = this._formatObject(aItem);
-          aRemoteMessage.argumentsToString.push(formattedObject);
-          if (WebConsoleUtils.isObjectInspectable(aItem)) {
-            return JSTerm.prepareObjectForRemote(aItem,
-                                                 aRemoteMessage.objectsCacheId);
-          }
-          return formattedObject;
-        }.bind(this);
-
-        aRemoteMessage.apiMessage.arguments =
-          Array.map(aOriginalMessage.arguments || [], mapFunction);
-        break;
-      }
-      default:
-        Cu.reportError("Unknown Console API log level: " +
-                       aOriginalMessage.level);
-        break;
-    }
-  },
-
-  /**
-   * Format an object's value to be displayed in the Web Console.
-   *
-   * @private
-   * @param object aObject
-   *        The object you want to display.
-   * @return string
-   *         The string you can display for the given object.
-   */
-  _formatObject: function CAO__formatObject(aObject)
-  {
-    return typeof aObject == "string" ?
-           aObject : WebConsoleUtils.formatResult(aObject);
-  },
-
-  /**
-   * Get the cached messages for the current inner window.
-   *
-   * @see this._prepareApiMessageForRemote()
-   * @return array
-   *         The array of cached messages. Each element is a Console API
-   *         prepared to be sent to the remote Web Console instance.
-   */
-  getCachedMessages: function CAO_getCachedMessages()
-  {
-    let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
-    let messages = gConsoleStorage.getEvents(innerWindowId);
-
-    let result = messages.map(function(aMessage) {
-      let remoteMessage = { _type: "ConsoleAPI" };
-      this._prepareApiMessageForRemote(aMessage.wrappedJSObject, remoteMessage);
-      return remoteMessage;
-    }, this);
-
-    return result;
-  },
-
-  /**
-   * Handler for the "ConsoleAPI:ClearCache" message.
-   */
-  handleClearCache: function CAO_handleClearCache()
-  {
-    let windowId = WebConsoleUtils.getInnerWindowId(Manager.window);
-    gConsoleStorage.clearEvents(windowId);
-  },
-
-  /**
-   * Destroy the ConsoleAPIObserver listeners.
-   */
-  destroy: function CAO_destroy()
-  {
-    Manager.removeMessageHandler("ConsoleAPI:ClearCache");
-    Services.obs.removeObserver(this, "console-api-log-event");
-  },
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// The page errors listener
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * The nsIConsoleService listener. This is used to send all the page errors
- * (JavaScript, CSS and more) to the remote Web Console instance.
- */
-let ConsoleListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
-
-  /**
-   * Initialize the nsIConsoleService listener.
-   */
-  init: function CL_init()
-  {
-    Services.console.registerListener(this);
-  },
-
-  /**
-   * The nsIConsoleService observer. This method takes all the script error
-   * messages belonging to the current window and sends them to the remote Web
-   * Console instance.
-   *
-   * @param nsIScriptError aScriptError
-   *        The script error object coming from the nsIConsoleService.
-   */
-  observe: function CL_observe(aScriptError)
-  {
-    if (!_alive || !(aScriptError instanceof Ci.nsIScriptError) ||
-        !aScriptError.outerWindowID) {
-      return;
-    }
-
-    if (!this.isCategoryAllowed(aScriptError.category)) {
-      return;
-    }
-
-    let errorWindow =
-      WebConsoleUtils.getWindowByOuterId(aScriptError.outerWindowID,
-                                         Manager.window);
-    if (!errorWindow || errorWindow.top != Manager.window) {
-      return;
-    }
-
-    Manager.sendMessage("WebConsole:PageError", { pageError: aScriptError });
-  },
-
-
-  /**
-   * Check if the given script error category is allowed to be tracked or not.
-   * We ignore chrome-originating errors as we only care about content.
-   *
-   * @param string aCategory
-   *        The nsIScriptError category you want to check.
-   * @return boolean
-   *         True if the category is allowed to be logged, false otherwise.
-   */
-  isCategoryAllowed: function CL_isCategoryAllowed(aCategory)
-  {
-    switch (aCategory) {
-      case "XPConnect JavaScript":
-      case "component javascript":
-      case "chrome javascript":
-      case "chrome registration":
-      case "XBL":
-      case "XBL Prototype Handler":
-      case "XBL Content Sink":
-      case "xbl javascript":
-        return false;
-    }
-
-    return true;
-  },
-
-  /**
-   * Get the cached page errors for the current inner window.
-   *
-   * @return array
-   *         The array of cached messages. Each element is an nsIScriptError
-   *         with an added _type property so the remote Web Console instance can
-   *         tell the difference between various types of cached messages.
-   */
-  getCachedMessages: function CL_getCachedMessages()
-  {
-    let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
-    let result = [];
-    let errors = {};
-    Services.console.getMessageArray(errors, {});
-
-    (errors.value || []).forEach(function(aError) {
-      if (!(aError instanceof Ci.nsIScriptError) ||
-          aError.innerWindowID != innerWindowId ||
-          !this.isCategoryAllowed(aError.category)) {
-        return;
-      }
-
-      let remoteMessage = WebConsoleUtils.cloneObject(aError);
-      remoteMessage._type = "PageError";
-      result.push(remoteMessage);
-    }, this);
-
-    return result;
-  },
-
-  /**
-   * Remove the nsIConsoleService listener.
-   */
-  destroy: function CL_destroy()
-  {
-    Services.console.unregisterListener(this);
-  },
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Network logging
-///////////////////////////////////////////////////////////////////////////////
-
-// The maximum uint32 value.
-const PR_UINT32_MAX = 4294967295;
-
-// HTTP status codes.
-const HTTP_MOVED_PERMANENTLY = 301;
-const HTTP_FOUND = 302;
-const HTTP_SEE_OTHER = 303;
-const HTTP_TEMPORARY_REDIRECT = 307;
-
-// The maximum number of bytes a NetworkResponseListener can hold.
-const RESPONSE_BODY_LIMIT = 1048576; // 1 MB
-
-/**
- * The network response listener implements the nsIStreamListener and
- * nsIRequestObserver interfaces. This is used within the NetworkMonitor feature
- * to get the response body of the request.
- *
- * The code is mostly based on code listings from:
- *
- *   http://www.softwareishard.com/blog/firebug/
- *      nsitraceablechannel-intercept-http-traffic/
- *
- * @constructor
- * @param object aHttpActivity
- *        HttpActivity object associated with this request. Once the request is
- *        complete the aHttpActivity object is updated to include the response
- *        headers and body.
- */
-function NetworkResponseListener(aHttpActivity) {
-  this.receivedData = "";
-  this.httpActivity = aHttpActivity;
-  this.bodySize = 0;
-}
-
-NetworkResponseListener.prototype = {
-  QueryInterface:
-    XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInputStreamCallback,
-                           Ci.nsIRequestObserver, Ci.nsISupports]),
-
-  /**
-   * This NetworkResponseListener tracks the NetworkMonitor.openResponses object
-   * to find the associated uncached headers.
-   * @private
-   */
-  _foundOpenResponse: false,
-
-  /**
-   * The response will be written into the outputStream of this nsIPipe.
-   * Both ends of the pipe must be blocking.
-   */
-  sink: null,
-
-  /**
-   * The HttpActivity object associated with this response.
-   */
-  httpActivity: null,
-
-  /**
-   * Stores the received data as a string.
-   */
-  receivedData: null,
-
-  /**
-   * The network response body size.
-   */
-  bodySize: null,
-
-  /**
-   * The nsIRequest we are started for.
-   */
-  request: null,
-
-  /**
-   * Set the async listener for the given nsIAsyncInputStream. This allows us to
-   * wait asynchronously for any data coming from the stream.
-   *
-   * @param nsIAsyncInputStream aStream
-   *        The input stream from where we are waiting for data to come in.
-   * @param nsIInputStreamCallback aListener
-   *        The input stream callback you want. This is an object that must have
-   *        the onInputStreamReady() method. If the argument is null, then the
-   *        current callback is removed.
-   * @return void
-   */
-  setAsyncListener: function NRL_setAsyncListener(aStream, aListener)
-  {
-    // Asynchronously wait for the stream to be readable or closed.
-    aStream.asyncWait(aListener, 0, 0, Services.tm.mainThread);
-  },
-
-  /**
-   * Stores the received data, if request/response body logging is enabled. It
-   * also does limit the number of stored bytes, based on the
-   * RESPONSE_BODY_LIMIT constant.
-   *
-   * Learn more about nsIStreamListener at:
-   * https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIStreamListener
-   *
-   * @param nsIRequest aRequest
-   * @param nsISupports aContext
-   * @param nsIInputStream aInputStream
-   * @param unsigned long aOffset
-   * @param unsigned long aCount
-   */
-  onDataAvailable:
-  function NRL_onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount)
-  {
-    this._findOpenResponse();
-    let data = NetUtil.readInputStreamToString(aInputStream, aCount);
-
-    this.bodySize += aCount;
-
-    if (!this.httpActivity.meta.discardResponseBody &&
-        this.receivedData.length < RESPONSE_BODY_LIMIT) {
-      this.receivedData += NetworkHelper.
-                           convertToUnicode(data, aRequest.contentCharset);
-    }
-  },
-
-  /**
-   * See documentation at
-   * https://developer.mozilla.org/En/NsIRequestObserver
-   *
-   * @param nsIRequest aRequest
-   * @param nsISupports aContext
-   */
-  onStartRequest: function NRL_onStartRequest(aRequest)
-  {
-    this.request = aRequest;
-    this._findOpenResponse();
-    // Asynchronously wait for the data coming from the request.
-    this.setAsyncListener(this.sink.inputStream, this);
-  },
-
-  /**
-   * Handle the onStopRequest by closing the sink output stream.
-   *
-   * For more documentation about nsIRequestObserver go to:
-   * https://developer.mozilla.org/En/NsIRequestObserver
-   */
-  onStopRequest: function NRL_onStopRequest()
-  {
-    this._findOpenResponse();
-    this.sink.outputStream.close();
-  },
-
-  /**
-   * Find the open response object associated to the current request. The
-   * NetworkMonitor.httpResponseExaminer() method saves the response headers in
-   * NetworkMonitor.openResponses. This method takes the data from the open
-   * response object and puts it into the HTTP activity object, then sends it to
-   * the remote Web Console instance.
-   *
-   * @private
-   */
-  _findOpenResponse: function NRL__findOpenResponse()
-  {
-    if (!_alive || this._foundOpenResponse) {
-      return;
-    }
-
-    let openResponse = null;
-
-    for each (let item in NetworkMonitor.openResponses) {
-      if (item.channel === this.httpActivity.channel) {
-        openResponse = item;
-        break;
-      }
-    }
-
-    if (!openResponse) {
-      return;
-    }
-    this._foundOpenResponse = true;
-
-    let logResponse = this.httpActivity.log.entries[0].response;
-    logResponse.headers = openResponse.headers;
-    logResponse.httpVersion = openResponse.httpVersion;
-    logResponse.status = openResponse.status;
-    logResponse.statusText = openResponse.statusText;
-    if (openResponse.cookies) {
-      logResponse.cookies = openResponse.cookies;
-    }
-
-    delete NetworkMonitor.openResponses[openResponse.id];
-
-    this.httpActivity.meta.stages.push("http-on-examine-response");
-    NetworkMonitor.sendActivity(this.httpActivity);
-  },
-
-  /**
-   * Clean up the response listener once the response input stream is closed.
-   * This is called from onStopRequest() or from onInputStreamReady() when the
-   * stream is closed.
-   * @return void
-   */
-  onStreamClose: function NRL_onStreamClose()
-  {
-    if (!this.httpActivity) {
-      return;
-    }
-    // Remove our listener from the request input stream.
-    this.setAsyncListener(this.sink.inputStream, null);
-
-    this._findOpenResponse();
-
-    let meta = this.httpActivity.meta;
-    let entry = this.httpActivity.log.entries[0];
-    let request = entry.request;
-    let response = entry.response;
-
-    meta.stages.push("REQUEST_STOP");
-
-    if (!meta.discardResponseBody && this.receivedData.length) {
-      this._onComplete(this.receivedData);
-    }
-    else if (!meta.discardResponseBody && response.status == 304) {
-      // Response is cached, so we load it from cache.
-      let charset = this.request.contentCharset || this.httpActivity.charset;
-      NetworkHelper.loadFromCache(request.url, charset,
-                                  this._onComplete.bind(this));
-    }
-    else {
-      this._onComplete();
-    }
-  },
-
-  /**
-   * Handler for when the response completes. This function cleans up the
-   * response listener.
-   *
-   * @param string [aData]
-   *        Optional, the received data coming from the response listener or
-   *        from the cache.
-   */
-  _onComplete: function NRL__onComplete(aData)
-  {
-    let response = this.httpActivity.log.entries[0].response;
-
-    try {
-      response.bodySize = response.status != 304 ? this.request.contentLength : 0;
-    }
-    catch (ex) {
-      response.bodySize = -1;
-    }
-
-    try {
-      response.content = { mimeType: this.request.contentType };
-    }
-    catch (ex) {
-      response.content = { mimeType: "" };
-    }
-
-    if (response.content.mimeType && this.request.contentCharset) {
-      response.content.mimeType += "; charset=" + this.request.contentCharset;
-    }
-
-    response.content.size = this.bodySize || (aData || "").length;
-
-    if (aData) {
-      response.content.text = aData;
-    }
-
-    this.receivedData = "";
-
-    if (_alive) {
-      NetworkMonitor.sendActivity(this.httpActivity);
-    }
-
-    this.httpActivity.channel = null;
-    this.httpActivity = null;
-    this.sink = null;
-    this.inputStream = null;
-    this.request = null;
-  },
-
-  /**
-   * The nsIInputStreamCallback for when the request input stream is ready -
-   * either it has more data or it is closed.
-   *
-   * @param nsIAsyncInputStream aStream
-   *        The sink input stream from which data is coming.
-   * @returns void
-   */
-  onInputStreamReady: function NRL_onInputStreamReady(aStream)
-  {
-    if (!(aStream instanceof Ci.nsIAsyncInputStream) || !this.httpActivity) {
-      return;
-    }
-
-    let available = -1;
-    try {
-      // This may throw if the stream is closed normally or due to an error.
-      available = aStream.available();
-    }
-    catch (ex) { }
-
-    if (available != -1) {
-      if (available != 0) {
-        // Note that passing 0 as the offset here is wrong, but the
-        // onDataAvailable() method does not use the offset, so it does not
-        // matter.
-        this.onDataAvailable(this.request, null, aStream, 0, available);
-      }
-      this.setAsyncListener(aStream, this);
-    }
-    else {
-      this.onStreamClose();
-    }
-  },
-};
-
-/**
- * The network monitor uses the nsIHttpActivityDistributor to monitor network
- * requests. The nsIObserverService is also used for monitoring
- * http-on-examine-response notifications. All network request information is
- * routed to the remote Web Console.
- */
-let NetworkMonitor = {
-  httpTransactionCodes: {
-    0x5001: "REQUEST_HEADER",
-    0x5002: "REQUEST_BODY_SENT",
-    0x5003: "RESPONSE_START",
-    0x5004: "RESPONSE_HEADER",
-    0x5005: "RESPONSE_COMPLETE",
-    0x5006: "TRANSACTION_CLOSE",
-
-    0x804b0003: "STATUS_RESOLVING",
-    0x804b000b: "STATUS_RESOLVED",
-    0x804b0007: "STATUS_CONNECTING_TO",
-    0x804b0004: "STATUS_CONNECTED_TO",
-    0x804b0005: "STATUS_SENDING_TO",
-    0x804b000a: "STATUS_WAITING_FOR",
-    0x804b0006: "STATUS_RECEIVING_FROM"
-  },
-
-  harCreator: {
-    name: Services.appinfo.name + " - Web Console",
-    version: Services.appinfo.version,
-  },
-
-  // Network response bodies are piped through a buffer of the given size (in
-  // bytes).
-  responsePipeSegmentSize: null,
-
-  /**
-   * Whether to save the bodies of network requests and responses. Disabled by
-   * default to save memory.
-   */
-  get saveRequestAndResponseBodies() {
-    return Manager.getPreference("NetworkMonitor.saveRequestAndResponseBodies");
-  },
-
-  openRequests: null,
-  openResponses: null,
-  progressListener: null,
-
-  /**
-   * The network monitor initializer.
-   *
-   * @param object aMessage
-   *        Initialization object sent by the remote Web Console instance. This
-   *        object can hold one property: monitorFileActivity - a boolean that
-   *        tells if monitoring of file:// requests should be enabled as well or
-   *        not.
-   */
-  init: function NM_init(aMessage)
-  {
-    this.responsePipeSegmentSize = Services.prefs
-                                   .getIntPref("network.buffer.cache.size");
-
-    this.openRequests = {};
-    this.openResponses = {};
-
-    activityDistributor.addObserver(this);
-
-    Services.obs.addObserver(this.httpResponseExaminer,
-                             "http-on-examine-response", false);
-
-    // Monitor file:// activity as well.
-    if (aMessage && aMessage.monitorFileActivity) {
-      ConsoleProgressListener.startMonitor(ConsoleProgressListener
-                                           .MONITOR_FILE_ACTIVITY);
-    }
-  },
-
-  /**
-   * Observe notifications for the http-on-examine-response topic, coming from
-   * the nsIObserverService.
-   *
-   * @param nsIHttpChannel aSubject
-   * @param string aTopic
-   * @returns void
-   */
-  httpResponseExaminer: function NM_httpResponseExaminer(aSubject, aTopic)
-  {
-    // The httpResponseExaminer is used to retrieve the uncached response
-    // headers. The data retrieved is stored in openResponses. The
-    // NetworkResponseListener is responsible with updating the httpActivity
-    // object with the data from the new object in openResponses.
-
-    if (!_alive || aTopic != "http-on-examine-response" ||
-        !(aSubject instanceof Ci.nsIHttpChannel)) {
-      return;
-    }
-
-    let channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
-    // Try to get the source window of the request.
-    let win = NetworkHelper.getWindowForRequest(channel);
-    if (!win || win.top !== Manager.window) {
-      return;
-    }
-
-    let response = {
-      id: Manager.sequenceId,
-      channel: channel,
-      headers: [],
-      cookies: [],
-    };
-
-    let setCookieHeader = null;
-
-    channel.visitResponseHeaders({
-      visitHeader: function NM__visitHeader(aName, aValue) {
-        let lowerName = aName.toLowerCase();
-        if (lowerName == "set-cookie") {
-          setCookieHeader = aValue;
-        }
-        response.headers.push({ name: aName, value: aValue });
-      }
-    });
-
-    if (!response.headers.length) {
-      return; // No need to continue.
-    }
-
-    if (setCookieHeader) {
-      response.cookies = NetworkHelper.parseSetCookieHeader(setCookieHeader);
-    }
-
-    // Determine the HTTP version.
-    let httpVersionMaj = {};
-    let httpVersionMin = {};
-
-    channel.QueryInterface(Ci.nsIHttpChannelInternal);
-    channel.getResponseVersion(httpVersionMaj, httpVersionMin);
-
-    response.status = channel.responseStatus;
-    response.statusText = channel.responseStatusText;
-    response.httpVersion = "HTTP/" + httpVersionMaj.value + "." +
-                                     httpVersionMin.value;
-
-    NetworkMonitor.openResponses[response.id] = response;
-  },
-
-  /**
-   * Begin observing HTTP traffic that originates inside the current tab.
-   *
-   * @see https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIHttpActivityObserver
-   *
-   * @param nsIHttpChannel aChannel
-   * @param number aActivityType
-   * @param number aActivitySubtype
-   * @param number aTimestamp
-   * @param number aExtraSizeData
-   * @param string aExtraStringData
-   */
-  observeActivity:
-  function NM_observeActivity(aChannel, aActivityType, aActivitySubtype,
-                              aTimestamp, aExtraSizeData, aExtraStringData)
-  {
-    if (!_alive ||
-        aActivityType != activityDistributor.ACTIVITY_TYPE_HTTP_TRANSACTION &&
-        aActivityType != activityDistributor.ACTIVITY_TYPE_SOCKET_TRANSPORT) {
-      return;
-    }
-
-    if (!(aChannel instanceof Ci.nsIHttpChannel)) {
-      return;
-    }
-
-    aChannel = aChannel.QueryInterface(Ci.nsIHttpChannel);
-
-    if (aActivitySubtype ==
-        activityDistributor.ACTIVITY_SUBTYPE_REQUEST_HEADER) {
-      this._onRequestHeader(aChannel, aTimestamp, aExtraStringData);
-      return;
-    }
-
-    // Iterate over all currently ongoing requests. If aChannel can't
-    // be found within them, then exit this function.
-    let httpActivity = null;
-    for each (let item in this.openRequests) {
-      if (item.channel === aChannel) {
-        httpActivity = item;
-        break;
-      }
-    }
-
-    if (!httpActivity) {
-      return;
-    }
-
-    let transCodes = this.httpTransactionCodes;
-
-    // Store the time information for this activity subtype.
-    if (aActivitySubtype in transCodes) {
-      let stage = transCodes[aActivitySubtype];
-      if (stage in httpActivity.timings) {
-        httpActivity.timings[stage].last = aTimestamp;
-      }
-      else {
-        httpActivity.meta.stages.push(stage);
-        httpActivity.timings[stage] = {
-          first: aTimestamp,
-          last: aTimestamp,
-        };
-      }
-    }
-
-    switch (aActivitySubtype) {
-      case activityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
-        this._onRequestBodySent(httpActivity);
-        break;
-      case activityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
-        this._onResponseHeader(httpActivity, aExtraStringData);
-        break;
-      case activityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE:
-        this._onTransactionClose(httpActivity);
-        break;
-      default:
-        break;
-    }
-  },
-
-  /**
-   * Handler for ACTIVITY_SUBTYPE_REQUEST_HEADER. When a request starts the
-   * headers are sent to the server. This method creates the |httpActivity|
-   * object where we store the request and response information that is
-   * collected through its lifetime.
-   *
-   * @private
-   * @param nsIHttpChannel aChannel
-   * @param number aTimestamp
-   * @param string aExtraStringData
-   * @return void
-   */
-  _onRequestHeader:
-  function NM__onRequestHeader(aChannel, aTimestamp, aExtraStringData)
-  {
-    // Try to get the source window of the request.
-    let win = NetworkHelper.getWindowForRequest(aChannel);
-    if (!win || win.top !== Manager.window) {
-      return;
-    }
-
-    let httpActivity = this.createActivityObject(aChannel);
-    httpActivity.charset = win.document.characterSet; // see NM__onRequestBodySent()
-    httpActivity.meta.stages.push("REQUEST_HEADER"); // activity stage (aActivitySubtype)
-
-    httpActivity.timings.REQUEST_HEADER = {
-      first: aTimestamp,
-      last: aTimestamp
-    };
-
-    let entry = httpActivity.log.entries[0];
-    entry.startedDateTime = new Date(Math.round(aTimestamp / 1000)).toISOString();
-
-    let request = httpActivity.log.entries[0].request;
-
-    let cookieHeader = null;
-
-    // Copy the request header data.
-    aChannel.visitRequestHeaders({
-      visitHeader: function NM__visitHeader(aName, aValue)
-      {
-        if (aName == "Cookie") {
-          cookieHeader = aValue;
-        }
-        request.headers.push({ name: aName, value: aValue });
-      }
-    });
-
-    if (cookieHeader) {
-      request.cookies = NetworkHelper.parseCookieHeader(cookieHeader);
-    }
-
-    // Determine the HTTP version.
-    let httpVersionMaj = {};
-    let httpVersionMin = {};
-
-    aChannel.QueryInterface(Ci.nsIHttpChannelInternal);
-    aChannel.getRequestVersion(httpVersionMaj, httpVersionMin);
-
-    request.httpVersion = "HTTP/" + httpVersionMaj.value + "." +
-                                    httpVersionMin.value;
-
-    request.headersSize = aExtraStringData.length;
-
-    this._setupResponseListener(httpActivity);
-
-    this.openRequests[httpActivity.id] = httpActivity;
-
-    this.sendActivity(httpActivity);
-  },
-
-  /**
-   * Create the empty HTTP activity object. This object is used for storing all
-   * the request and response information.
-   *
-   * This is a HAR-like object. Conformance to the spec is not guaranteed at
-   * this point.
-   *
-   * TODO: Bug 708717 - Add support for network log export to HAR
-   *
-   * @see http://www.softwareishard.com/blog/har-12-spec
-   * @param nsIHttpChannel aChannel
-   *        The HTTP channel for which the HTTP activity object is created.
-   * @return object
-   *         The new HTTP activity object.
-   */
-  createActivityObject: function NM_createActivityObject(aChannel)
-  {
-    return {
-      hudId: Manager.hudId,
-      id: Manager.sequenceId,
-      channel: aChannel,
-      charset: null, // see NM__onRequestHeader()
-      meta: { // holds metadata about the activity object
-        stages: [], // activity stages (aActivitySubtype)
-        discardRequestBody: !this.saveRequestAndResponseBodies,
-        discardResponseBody: !this.saveRequestAndResponseBodies,
-      },
-      timings: {}, // internal timing information, see NM_observeActivity()
-      log: { // HAR-like object
-        version: "1.2",
-        creator: this.harCreator,
-        // missing |browser| and |pages|
-        entries: [{  // we only track one entry at a time
-          connection: Manager.sequenceId, // connection ID
-          startedDateTime: 0, // see NM__onRequestHeader()
-          time: 0, // see NM__setupHarTimings()
-          // missing |serverIPAddress| and |cache|
-          request: {
-            method: aChannel.requestMethod,
-            url: aChannel.URI.spec,
-            httpVersion: "", // see NM__onRequestHeader()
-            headers: [], // see NM__onRequestHeader()
-            cookies: [], // see NM__onRequestHeader()
-            queryString: [], // never set
-            headersSize: -1, // see NM__onRequestHeader()
-            bodySize: -1, // see NM__onRequestBodySent()
-            postData: null, // see NM__onRequestBodySent()
-          },
-          response: {
-            status: 0, // see NM__onResponseHeader()
-            statusText: "", // see NM__onResponseHeader()
-            httpVersion: "", // see NM__onResponseHeader()
-            headers: [], // see NM_httpResponseExaminer()
-            cookies: [], // see NM_httpResponseExaminer()
-            content: null, // see NRL_onStreamClose()
-            redirectURL: "", // never set
-            headersSize: -1, // see NM__onResponseHeader()
-            bodySize: -1, // see NRL_onStreamClose()
-          },
-          timings: {}, // see NM__setupHarTimings()
-        }],
-      },
-    };
-  },
-
-  /**
-   * Setup the network response listener for the given HTTP activity. The
-   * NetworkResponseListener is responsible for storing the response body.
-   *
-   * @private
-   * @param object aHttpActivity
-   *        The HTTP activity object we are tracking.
-   */
-  _setupResponseListener: function NM__setupResponseListener(aHttpActivity)
-  {
-    let channel = aHttpActivity.channel;
-    channel.QueryInterface(Ci.nsITraceableChannel);
-
-    // The response will be written into the outputStream of this pipe.
-    // This allows us to buffer the data we are receiving and read it
-    // asynchronously.
-    // Both ends of the pipe must be blocking.
-    let sink = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
-
-    // The streams need to be blocking because this is required by the
-    // stream tee.
-    sink.init(false, false, this.responsePipeSegmentSize, PR_UINT32_MAX, null);
-
-    // Add listener for the response body.
-    let newListener = new NetworkResponseListener(aHttpActivity);
-
-    // Remember the input stream, so it isn't released by GC.
-    newListener.inputStream = sink.inputStream;
-    newListener.sink = sink;
-
-    let tee = Cc["@mozilla.org/network/stream-listener-tee;1"].
-              createInstance(Ci.nsIStreamListenerTee);
-
-    let originalListener = channel.setNewListener(tee);
-
-    tee.init(originalListener, sink.outputStream, newListener);
-  },
-
-  /**
-   * Send an HTTP activity object to the remote Web Console instance.
-   * A WebConsole:NetworkActivity message is sent. The message holds two
-   * properties:
-   *   - meta - the |aHttpActivity.meta| object.
-   *   - log - the |aHttpActivity.log| object.
-   *
-   * @param object aHttpActivity
-   *        The HTTP activity object you want to send.
-   */
-  sendActivity: function NM_sendActivity(aHttpActivity)
-  {
-    Manager.sendMessage("WebConsole:NetworkActivity", {
-      meta: aHttpActivity.meta,
-      log: aHttpActivity.log,
-    });
-  },
-
-  /**
-   * Handler for ACTIVITY_SUBTYPE_REQUEST_BODY_SENT. The request body is logged
-   * here.
-   *
-   * @private
-   * @param object aHttpActivity
-   *        The HTTP activity object we are working with.
-   */
-  _onRequestBodySent: function NM__onRequestBodySent(aHttpActivity)
-  {
-    if (aHttpActivity.meta.discardRequestBody) {
-      return;
-    }
-
-    let request = aHttpActivity.log.entries[0].request;
-
-    let sentBody = NetworkHelper.
-                   readPostTextFromRequest(aHttpActivity.channel,
-                                           aHttpActivity.charset);
-
-    if (!sentBody && request.url == Manager.window.location.href) {
-      // If the request URL is the same as the current page URL, then
-      // we can try to get the posted text from the page directly.
-      // This check is necessary as otherwise the
-      //   NetworkHelper.readPostTextFromPage()
-      // function is called for image requests as well but these
-      // are not web pages and as such don't store the posted text
-      // in the cache of the webpage.
-      sentBody = NetworkHelper.readPostTextFromPage(docShell,
-                                                    aHttpActivity.charset);
-    }
-    if (!sentBody) {
-      return;
-    }
-
-    request.postData = {
-      mimeType: "", // never set
-      params: [],  // never set
-      text: sentBody,
-    };
-
-    request.bodySize = sentBody.length;
-
-    this.sendActivity(aHttpActivity);
-  },
-
-  /**
-   * Handler for ACTIVITY_SUBTYPE_RESPONSE_HEADER. This method stores
-   * information about the response headers.
-   *
-   * @private
-   * @param object aHttpActivity
-   *        The HTTP activity object we are working with.
-   * @param string aExtraStringData
-   *        The uncached response headers.
-   */
-  _onResponseHeader:
-  function NM__onResponseHeader(aHttpActivity, aExtraStringData)
-  {
-    // aExtraStringData contains the uncached response headers. The first line
-    // contains the response status (e.g. HTTP/1.1 200 OK).
-    //
-    // Note: The response header is not saved here. Calling the
-    // channel.visitResponseHeaders() methood at this point sometimes causes an
-    // NS_ERROR_NOT_AVAILABLE exception.
-    //
-    // We could parse aExtraStringData to get the headers and their values, but
-    // that is not trivial to do in an accurate manner. Hence, we save the
-    // response headers in this.httpResponseExaminer().
-
-    let response = aHttpActivity.log.entries[0].response;
-
-    let headers = aExtraStringData.split(/\r\n|\n|\r/);
-    let statusLine = headers.shift();
-
-    let statusLineArray = statusLine.split(" ");
-    response.httpVersion = statusLineArray.shift();
-    response.status = statusLineArray.shift();
-    response.statusText = statusLineArray.join(" ");
-    response.headersSize = aExtraStringData.length;
-
-    // Discard the response body for known response statuses.
-    switch (parseInt(response.status)) {
-      case HTTP_MOVED_PERMANENTLY:
-      case HTTP_FOUND:
-      case HTTP_SEE_OTHER:
-      case HTTP_TEMPORARY_REDIRECT:
-        aHttpActivity.meta.discardResponseBody = true;
-        break;
-    }
-
-    this.sendActivity(aHttpActivity);
-  },
-
-  /**
-   * Handler for ACTIVITY_SUBTYPE_TRANSACTION_CLOSE. This method updates the HAR
-   * timing information on the HTTP activity object and clears the request
-   * from the list of known open requests.
-   *
-   * @private
-   * @param object aHttpActivity
-   *        The HTTP activity object we work with.
-   */
-  _onTransactionClose: function NM__onTransactionClose(aHttpActivity)
-  {
-    this._setupHarTimings(aHttpActivity);
-    this.sendActivity(aHttpActivity);
-    delete this.openRequests[aHttpActivity.id];
-  },
-
-  /**
-   * Update the HTTP activity object to include timing information as in the HAR
-   * spec. The HTTP activity object holds the raw timing information in
-   * |timings| - these are timings stored for each activity notification. The
-   * HAR timing information is constructed based on these lower level data.
-   *
-   * @param object aHttpActivity
-   *        The HTTP activity object we are working with.
-   */
-  _setupHarTimings: function NM__setupHarTimings(aHttpActivity)
-  {
-    let timings = aHttpActivity.timings;
-    let entry = aHttpActivity.log.entries[0];
-    let harTimings = entry.timings;
-
-    // Not clear how we can determine "blocked" time.
-    harTimings.blocked = -1;
-
-    // DNS timing information is available only in when the DNS record is not
-    // cached.
-    harTimings.dns = timings.STATUS_RESOLVING && timings.STATUS_RESOLVED ?
-                     timings.STATUS_RESOLVED.last -
-                     timings.STATUS_RESOLVING.first : -1;
-
-    if (timings.STATUS_CONNECTING_TO && timings.STATUS_CONNECTED_TO) {
-      harTimings.connect = timings.STATUS_CONNECTED_TO.last -
-                           timings.STATUS_CONNECTING_TO.first;
-    }
-    else if (timings.STATUS_SENDING_TO) {
-      harTimings.connect = timings.STATUS_SENDING_TO.first -
-                           timings.REQUEST_HEADER.first;
-    }
-    else {
-      harTimings.connect = -1;
-    }
-
-    if ((timings.STATUS_WAITING_FOR || timings.STATUS_RECEIVING_FROM) &&
-        (timings.STATUS_CONNECTED_TO || timings.STATUS_SENDING_TO)) {
-      harTimings.send = (timings.STATUS_WAITING_FOR ||
-                         timings.STATUS_RECEIVING_FROM).first -
-                        (timings.STATUS_CONNECTED_TO ||
-                         timings.STATUS_SENDING_TO).last;
-    }
-    else {
-      harTimings.send = -1;
-    }
-
-    if (timings.RESPONSE_START) {
-      harTimings.wait = timings.RESPONSE_START.first -
-                        (timings.REQUEST_BODY_SENT ||
-                         timings.STATUS_SENDING_TO).last;
-    }
-    else {
-      harTimings.wait = -1;
-    }
-
-    if (timings.RESPONSE_START && timings.RESPONSE_COMPLETE) {
-      harTimings.receive = timings.RESPONSE_COMPLETE.last -
-                           timings.RESPONSE_START.first;
-    }
-    else {
-      harTimings.receive = -1;
-    }
-
-    entry.time = 0;
-    for (let timing in harTimings) {
-      let time = Math.max(Math.round(harTimings[timing] / 1000), -1);
-      harTimings[timing] = time;
-      if (time > -1) {
-        entry.time += time;
-      }
-    }
-  },
-
-  /**
-   * Suspend Web Console activity. This is called when all Web Consoles are
-   * closed.
-   */
-  destroy: function NM_destroy()
-  {
-    Services.obs.removeObserver(this.httpResponseExaminer,
-                                "http-on-examine-response");
-
-    activityDistributor.removeObserver(this);
-
-    ConsoleProgressListener.stopMonitor(ConsoleProgressListener
-                                        .MONITOR_FILE_ACTIVITY);
-
-    delete this.openRequests;
-    delete this.openResponses;
-  },
-};
-
-/**
- * A WebProgressListener that listens for location changes.
- *
- * This progress listener is used to track file loads and other kinds of
- * location changes.
- *
- * When a file:// URI is loaded a "WebConsole:FileActivity" message is sent to
- * the remote Web Console instance. The message JSON holds only one property:
- * uri (the file URI).
- *
- * When the current page location changes a "WebConsole:LocationChange" message
- * is sent. See ConsoleProgressListener.sendLocation() for details.
- */
-let ConsoleProgressListener = {
-  /**
-   * Constant used for startMonitor()/stopMonitor() that tells you want to
-   * monitor file loads.
-   */
-  MONITOR_FILE_ACTIVITY: 1,
-
-  /**
-   * Constant used for startMonitor()/stopMonitor() that tells you want to
-   * monitor page location changes.
-   */
-  MONITOR_LOCATION_CHANGE: 2,
-
-  /**
-   * Tells if you want to monitor file activity.
-   * @private
-   * @type boolean
-   */
-  _fileActivity: false,
-
-  /**
-   * Tells if you want to monitor location changes.
-   * @private
-   * @type boolean
-   */
-  _locationChange: false,
-
-  /**
-   * Tells if the console progress listener is initialized or not.
-   * @private
-   * @type boolean
-   */
-  _initialized: false,
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
-
-  /**
-   * Initialize the ConsoleProgressListener.
-   * @private
-   */
-  _init: function CPL__init()
-  {
-    if (this._initialized) {
-      return;
-    }
-
-    this._initialized = true;
-    let webProgress = docShell.QueryInterface(Ci.nsIWebProgress);
-    webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_ALL);
-  },
-
-  /**
-   * Start a monitor/tracker related to the current nsIWebProgressListener
-   * instance.
-   *
-   * @param number aMonitor
-   *        Tells what you want to track. Available constants:
-   *        - this.MONITOR_FILE_ACTIVITY
-   *          Track file loads.
-   *        - this.MONITOR_LOCATION_CHANGE
-   *          Track location changes for the top window.
-   */
-  startMonitor: function CPL_startMonitor(aMonitor)
-  {
-    switch (aMonitor) {
-      case this.MONITOR_FILE_ACTIVITY:
-        this._fileActivity = true;
-        break;
-      case this.MONITOR_LOCATION_CHANGE:
-        this._locationChange = true;
-        break;
-      default:
-        throw new Error("HUDService-content: unknown monitor type " +
-                        aMonitor + " for the ConsoleProgressListener!");
-    }
-    this._init();
-  },
-
-  /**
-   * Stop a monitor.
-   *
-   * @param number aMonitor
-   *        Tells what you want to stop tracking. See this.startMonitor() for
-   *        the list of constants.
-   */
-  stopMonitor: function CPL_stopMonitor(aMonitor)
-  {
-    switch (aMonitor) {
-      case this.MONITOR_FILE_ACTIVITY:
-        this._fileActivity = false;
-        break;
-      case this.MONITOR_LOCATION_CHANGE:
-        this._locationChange = false;
-        break;
-      default:
-        throw new Error("HUDService-content: unknown monitor type " +
-                        aMonitor + " for the ConsoleProgressListener!");
-    }
-
-    if (!this._fileActivity && !this._locationChange) {
-      this.destroy();
-    }
-  },
-
-  onStateChange:
-  function CPL_onStateChange(aProgress, aRequest, aState, aStatus)
-  {
-    if (!_alive) {
-      return;
-    }
-
-    if (this._fileActivity) {
-      this._checkFileActivity(aProgress, aRequest, aState, aStatus);
-    }
-
-    if (this._locationChange) {
-      this._checkLocationChange(aProgress, aRequest, aState, aStatus);
-    }
-  },
-
-  /**
-   * Check if there is any file load, given the arguments of
-   * nsIWebProgressListener.onStateChange. If the state change tells that a file
-   * URI has been loaded, then the remote Web Console instance is notified.
-   * @private
-   */
-  _checkFileActivity:
-  function CPL__checkFileActivity(aProgress, aRequest, aState, aStatus)
-  {
-    if (!(aState & Ci.nsIWebProgressListener.STATE_START)) {
-      return;
-    }
-
-    let uri = null;
-    if (aRequest instanceof Ci.imgIRequest) {
-      let imgIRequest = aRequest.QueryInterface(Ci.imgIRequest);
-      uri = imgIRequest.URI;
-    }
-    else if (aRequest instanceof Ci.nsIChannel) {
-      let nsIChannel = aRequest.QueryInterface(Ci.nsIChannel);
-      uri = nsIChannel.URI;
-    }
-
-    if (!uri || !uri.schemeIs("file") && !uri.schemeIs("ftp")) {
-      return;
-    }
-
-    Manager.sendMessage("WebConsole:FileActivity", {uri: uri.spec});
-  },
-
-  /**
-   * Check if the current window.top location is changing, given the arguments
-   * of nsIWebProgressListener.onStateChange. If that is the case, the remote
-   * Web Console instance is notified.
-   * @private
-   */
-  _checkLocationChange:
-  function CPL__checkLocationChange(aProgress, aRequest, aState, aStatus)
-  {
-    let isStart = aState & Ci.nsIWebProgressListener.STATE_START;
-    let isStop = aState & Ci.nsIWebProgressListener.STATE_STOP;
-    let isNetwork = aState & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
-    let isWindow = aState & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
-
-    // Skip non-interesting states.
-    if (!isNetwork || !isWindow ||
-        aProgress.DOMWindow != Manager.window) {
-      return;
-    }
-
-    if (isStart && aRequest instanceof Ci.nsIChannel) {
-      this.sendLocation(aRequest.URI.spec, "");
-    }
-    else if (isStop) {
-      this.sendLocation(Manager.window.location.href,
-                        Manager.window.document.title);
-    }
-  },
-
-  onLocationChange: function() {},
-  onStatusChange: function() {},
-  onProgressChange: function() {},
-  onSecurityChange: function() {},
-
-  /**
-   * Send the location of the current top window to the remote Web Console.
-   * A "WebConsole:LocationChange" message is sent. The JSON object holds two
-   * properties: location and title.
-   *
-   * @param string aLocation
-   *        Current page address.
-   * @param string aTitle
-   *        Current page title.
-   */
-  sendLocation: function CPL_sendLocation(aLocation, aTitle)
-  {
-    let message = {
-      "location": aLocation,
-      "title": aTitle,
-    };
-    Manager.sendMessage("WebConsole:LocationChange", message);
-  },
-
-  /**
-   * Destroy the ConsoleProgressListener.
-   */
-  destroy: function CPL_destroy()
-  {
-    if (!this._initialized) {
-      return;
-    }
-
-    this._initialized = false;
-    this._fileActivity = false;
-    this._locationChange = false;
-    let webProgress = docShell.QueryInterface(Ci.nsIWebProgress);
-    webProgress.removeProgressListener(this);
-  },
-};
-
-Manager.init();
-})();
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -52,19 +52,16 @@ const MINIMUM_CONSOLE_HEIGHT = 150;
 
 // Minimum page height, in pixels. This prevents the Web Console from
 // remembering a height that covers the whole page.
 const MINIMUM_PAGE_HEIGHT = 50;
 
 // The default console height, as a ratio from the content window inner height.
 const DEFAULT_CONSOLE_HEIGHT = 0.33;
 
-// This script is inserted into the content process.
-const CONTENT_SCRIPT_URL = "chrome://browser/content/devtools/HUDService-content.js";
-
 // points to the file to load in the Web Console iframe.
 const UI_IFRAME_URL = "chrome://browser/content/devtools/webconsole.xul";
 
 ///////////////////////////////////////////////////////////////////////////
 //// The HUD service
 
 function HUD_SERVICE()
 {
@@ -495,46 +492,42 @@ HUD_SERVICE.prototype =
  * This object only wraps the iframe that holds the Web Console UI.
  *
  * @param nsIDOMElement aTab
  *        The xul:tab for which you want the WebConsole object.
  */
 function WebConsole(aTab)
 {
   this.tab = aTab;
+  this.chromeDocument = this.tab.ownerDocument;
+  this.chromeWindow = this.chromeDocument.defaultView;
+  this.hudId = "hud_" + this.tab.linkedPanel;
   this._onIframeLoad = this._onIframeLoad.bind(this);
-  this._asyncRequests = {};
-  this._init();
+  this._initUI();
 }
 
 WebConsole.prototype = {
   /**
    * The xul:tab for which the current Web Console instance was created.
    * @type nsIDOMElement
    */
   tab: null,
 
+  chromeWindow: null,
+  chromeDocument: null,
+
   /**
    * Getter for HUDService.lastFinishedRequestCallback.
    *
    * @see HUDService.lastFinishedRequestCallback
    * @type function
    */
   get lastFinishedRequestCallback() HUDService.lastFinishedRequestCallback,
 
   /**
-   * Track callback functions registered for specific async requests sent to
-   * the content process.
-   *
-   * @private
-   * @type object
-   */
-  _asyncRequests: null,
-
-  /**
    * The xul:panel that holds the Web Console when it is positioned as a window.
    * @type nsIDOMElement
    */
   consolePanel: null,
 
   /**
    * Getter for the xul:popupset that holds any popups we open.
    * @type nsIDOMElement
@@ -551,32 +544,16 @@ WebConsole.prototype = {
   get outputNode()
   {
     return this.ui ? this.ui.outputNode : null;
   },
 
   get gViewSourceUtils() this.chromeWindow.gViewSourceUtils,
 
   /**
-   * Initialize the Web Console instance.
-   * @private
-   */
-  _init: function WC__init()
-  {
-    this.chromeDocument = this.tab.ownerDocument;
-    this.chromeWindow = this.chromeDocument.defaultView;
-    this.messageManager = this.tab.linkedBrowser.messageManager;
-    this.hudId = "hud_" + this.tab.linkedPanel;
-    this.notificationBox = this.chromeDocument
-                           .getElementById(this.tab.linkedPanel);
-
-    this._initUI();
-  },
-
-  /**
    * Initialize the Web Console UI. This method sets up the iframe.
    * @private
    */
   _initUI: function WC__initUI()
   {
     this.splitter = this.chromeDocument.createElement("splitter");
     this.splitter.className = "devtools-horizontal-splitter";
 
@@ -778,17 +755,17 @@ WebConsole.prototype = {
       this._createOwnWindowPanel();
       return;
     }
 
     let height = this.iframe.clientHeight;
 
     // get the node position index
     let nodeIdx = this.positions[aPosition];
-    let nBox = this.notificationBox;
+    let nBox = this.chromeDocument.getElementById(this.tab.linkedPanel);
     let node = nBox.childNodes[nodeIdx];
 
     // check to see if console is already positioned in aPosition
     if (node == this.iframe) {
       return;
     }
 
     let lastIndex = -1;
@@ -883,102 +860,16 @@ WebConsole.prototype = {
    * @private
    */
   _onClearButton: function WC__onClearButton()
   {
     this.chromeWindow.DeveloperToolbar.resetErrorsCount(this.tab);
   },
 
   /**
-   * Setup the message manager used to communicate with the Web Console content
-   * script. This method loads the content script, adds the message listeners
-   * and initializes the connection to the content script.
-   *
-   * @private
-   */
-  _setupMessageManager: function WC__setupMessageManager()
-  {
-    this.messageManager.loadFrameScript(CONTENT_SCRIPT_URL, true);
-
-    this._messageListeners.forEach(function(aName) {
-      this.messageManager.addMessageListener(aName, this.ui);
-    }, this);
-
-    let message = {
-      features: ["NetworkMonitor", "LocationChange"],
-      NetworkMonitor: { monitorFileActivity: true },
-      preferences: {
-        "NetworkMonitor.saveRequestAndResponseBodies":
-          this.ui.saveRequestAndResponseBodies,
-      },
-    };
-
-    this.sendMessageToContent("WebConsole:Init", message);
-  },
-
-  /**
-   * Handler for messages that have an associated callback function. The
-   * this.sendMessageToContent() allows one to provide a function to be invoked
-   * when the content script replies to the message previously sent. This is the
-   * method that invokes the callback.
-   *
-   * @see this.sendMessageToContent
-   * @private
-   * @param object aResponse
-   *        Message object received from the content script.
-   */
-  _receiveMessageWithCallback:
-  function WC__receiveMessageWithCallback(aResponse)
-  {
-    if (aResponse.id in this._asyncRequests) {
-      let request = this._asyncRequests[aResponse.id];
-      request.callback(aResponse, request.message);
-      delete this._asyncRequests[aResponse.id];
-    }
-    else {
-      Cu.reportError("receiveMessageWithCallback response for stale request " +
-                     "ID " + aResponse.id);
-    }
-  },
-
-  /**
-   * Send a message to the content script.
-   *
-   * @param string aName
-   *        The name of the message you want to send.
-   *
-   * @param object aMessage
-   *        The message object you want to send. This object needs to have no
-   *        cyclic references and it needs to be JSON-stringifiable.
-   *
-   * @param function [aCallback]
-   *        Optional function you want to have called when the content script
-   *        replies to your message. Your callback receives two arguments:
-   *        (1) the response object from the content script and (2) the message
-   *        you sent to the content script (which is aMessage here).
-   */
-  sendMessageToContent:
-  function WC_sendMessageToContent(aName, aMessage, aCallback)
-  {
-    aMessage.hudId = this.hudId;
-    if (!("id" in aMessage)) {
-      aMessage.id = "HUDChrome-" + HUDService.sequenceId();
-    }
-
-    if (aCallback) {
-      this._asyncRequests[aMessage.id] = {
-        name: aName,
-        message: aMessage,
-        callback: aCallback,
-      };
-    }
-    this.messageManager.sendAsyncMessage(aName, aMessage);
-  },
-
-  /**
    * Handler for page location changes. If the Web Console is
    * opened in a panel the panel title is updated.
    *
    * @param string aURI
    *        New page location.
    * @param string aTitle
    *        New page title.
    */
--- a/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
+++ b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
@@ -3,17 +3,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that objects given to console.log() are inspectable.
 
 function test()
 {
   waitForExplicitFinish();
 
-  addTab("data:text/html,test for bug 676722 - inspectable objects for window.console");
+  addTab("data:text/html;charset=utf8,test for bug 676722 - inspectable objects for window.console");
 
   gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
     openConsole(null, performTest);
   }, true);
 }
 
 function performTest(hud)
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js
@@ -32,19 +32,19 @@ function test() {
   let jar = getJar(getRootDirectory(gTestPath));
   let dir = jar ?
             extractJarToTmp(jar) :
             getChromeDir(getResolvedURI(gTestPath));
   dir.append(TEST_FILE);
 
   let uri = Services.io.newFileURI(dir);
 
-  addTab(uri.spec);
+  addTab("data:text/html;charset=utf8,<p>test file URI");
   browser.addEventListener("load", function tabLoad() {
     browser.removeEventListener("load", tabLoad, true);
     openConsole(null, function(aHud) {
       hud = aHud;
       hud.jsterm.clearOutput();
       browser.addEventListener("load", tabReload, true);
-      content.location.reload();
+      content.location = uri.spec;
     });
   }, true);
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -33,17 +33,18 @@ function consoleOpened(aHud) {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
     // |props| values, and the following properties:
     // __defineGetter__  __defineSetter__ __lookupGetter__ __lookupSetter__
     // constructor hasOwnProperty isPrototypeOf propertyIsEnumerable
     // toLocaleString toSource toString unwatch valueOf watch.
-    let props = WCU.namesAndValuesOf(content.wrappedJSObject.document.body);
+    let props = WCU.inspectObject(content.wrappedJSObject.document.body,
+                                  function() { });
     is(popup.itemCount, 14 + props.length, "popup.itemCount is correct");
 
     popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
 
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   }, false);
 
   jsterm.setInputValue("document.body");
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
@@ -8,17 +8,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the Web Console Mixed Content messages are displayed
 
 const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
 
 function test() {
-  addTab("data:text/html,Web Console basic network logging test");
+  addTab("data:text/html;charset=utf8,Web Console mixed content test");
   browser.addEventListener("load", onLoad, true);
 }
 
 function onLoad(aEvent) {
   browser.removeEventListener("load", onLoad, true);
   openConsole(null, testMixedContent);
 }
 
@@ -63,18 +63,19 @@ function testSeverity(node) {
 }
 
 function testClickOpenNewTab(warningNode) {
   /* Invoke the click event and check if a new tab would open to the correct page */
   let linkOpened = false;
   let oldOpenUILinkIn = window.openUILinkIn;
 
   window.openUILinkIn = function(aLink) {
-   if (aLink == "https://developer.mozilla.org/en/Security/MixedContent");
-     linkOpened = true;
+    if (aLink == "https://developer.mozilla.org/en/Security/MixedContent") {
+      linkOpened = true;
+    }
   }
 
   EventUtils.synthesizeMouse(warningNode, 2, 2, {},
                              warningNode.ownerDocument.defaultView);
 
   ok(linkOpened, "Clicking the Mixed Content Warning node opens the desired page");
 
   window.openUILinkIn = oldOpenUILinkIn;
--- a/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
+++ b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
@@ -1,10 +1,11 @@
 <!DOCTYPE HTML>
 <html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+    <meta charset="utf8">
     <title>Mixed Content test - http on https</title>
     <script src="testscript.js"></script>
     <!--
        - Any copyright is dedicated to the Public Domain.
        - http://creativecommons.org/publicdomain/zero/1.0/
        -->
   </head>
   <body>
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -182,24 +182,27 @@ function WebConsoleFrame(aWebConsoleOwne
 
   this._cssNodes = {};
   this._outputQueue = [];
   this._pruneCategoriesQueue = {};
   this._networkRequests = {};
 
   this._toggleFilter = this._toggleFilter.bind(this);
   this._onPositionConsoleCommand = this._onPositionConsoleCommand.bind(this);
+  this._flushMessageQueue = this._flushMessageQueue.bind(this);
+
+  this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+  this._outputTimerInitialized = false;
 
   this._initDefaultFilterPrefs();
   this._commandController = new CommandController(this);
   this.positionConsole(aPosition, window);
 
   this.jsterm = new JSTerm(this);
   this.jsterm.inputNode.focus();
-
   this._initConnection();
 }
 
 WebConsoleFrame.prototype = {
   /**
    * The WebConsole instance that owns this frame.
    * @see HUDService.jsm::WebConsole
    * @type object
@@ -260,16 +263,25 @@ WebConsoleFrame.prototype = {
    * tests.
    *
    * @private
    * @type function
    */
   _flushCallback: null,
 
   /**
+   * Timer used for flushing the messages output queue.
+   *
+   * @private
+   * @type nsITimer
+   */
+  _outputTimer: null,
+  _outputTimerInitialized: null,
+
+  /**
    * Store for tracking repeated CSS nodes.
    * @private
    * @type object
    */
   _cssNodes: null,
 
   /**
    * Preferences for filtering messages by type.
@@ -1721,58 +1733,58 @@ WebConsoleFrame.prototype = {
     if (!this._outputQueue.length) {
       // If the queue is empty we consider that now was the last output flush.
       // This avoid an immediate output flush when the timer executes.
       this._lastOutputFlush = Date.now();
     }
 
     this._outputQueue.push([aCategory, aMethodOrNode, aArguments]);
 
-    if (!this._outputTimeout) {
-      this._outputTimeout =
-        this.window.setTimeout(this._flushMessageQueue.bind(this),
-                               OUTPUT_INTERVAL);
+    if (!this._outputTimerInitialized) {
+      this._initOutputTimer();
     }
   },
 
   /**
    * Try to flush the output message queue. This takes the messages in the
    * output queue and displays them. Outputting stops at MESSAGES_IN_INTERVAL.
    * Further output is queued to happen later - see OUTPUT_INTERVAL.
    *
    * @private
    */
   _flushMessageQueue: function WCF__flushMessageQueue()
   {
+    if (!this._outputTimer) {
+      return;
+    }
+
     let timeSinceFlush = Date.now() - this._lastOutputFlush;
     if (this._outputQueue.length > MESSAGES_IN_INTERVAL &&
         timeSinceFlush < THROTTLE_UPDATES) {
-      this._outputTimeout =
-        this.window.setTimeout(this._flushMessageQueue.bind(this),
-                               OUTPUT_INTERVAL);
+      this._initOutputTimer();
       return;
     }
 
     // Determine how many messages we can display now.
     let toDisplay = Math.min(this._outputQueue.length, MESSAGES_IN_INTERVAL);
     if (toDisplay < 1) {
-      this._outputTimeout = null;
+      this._outputTimerInitialized = false;
       return;
     }
 
     // Try to prune the message queue.
     let shouldPrune = false;
     if (this._outputQueue.length > toDisplay && this._pruneOutputQueue()) {
       toDisplay = Math.min(this._outputQueue.length, toDisplay);
       shouldPrune = true;
     }
 
     let batch = this._outputQueue.splice(0, toDisplay);
     if (!batch.length) {
-      this._outputTimeout = null;
+      this._outputTimerInitialized = false;
       return;
     }
 
     let outputNode = this.outputNode;
     let lastVisibleNode = null;
     let scrolledToBottom = Utils.isOutputScrolledToBottom(outputNode);
     let scrollBox = outputNode.scrollBoxObject.element;
 
@@ -1820,29 +1832,43 @@ WebConsoleFrame.prototype = {
              oldScrollHeight != scrollBox.scrollHeight) {
       // If there were pruned messages and if scroll is not at the bottom, then
       // we need to adjust the scroll location.
       scrollBox.scrollTop -= oldScrollHeight - scrollBox.scrollHeight;
     }
 
     // If the queue is not empty, schedule another flush.
     if (this._outputQueue.length > 0) {
-      this._outputTimeout =
-        this.window.setTimeout(this._flushMessageQueue.bind(this),
-                               OUTPUT_INTERVAL);
+      this._initOutputTimer();
     }
     else {
-      this._outputTimeout = null;
+      this._outputTimerInitialized = false;
       this._flushCallback && this._flushCallback();
     }
 
     this._lastOutputFlush = Date.now();
   },
 
   /**
+   * Initialize the output timer.
+   * @private
+   */
+  _initOutputTimer: function WCF__initOutputTimer()
+  {
+    if (!this._outputTimer) {
+      return;
+    }
+
+    this._outputTimerInitialized = true;
+    this._outputTimer.initWithCallback(this._flushMessageQueue,
+                                       OUTPUT_INTERVAL,
+                                       Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
+  /**
    * Output a message from the queue.
    *
    * @private
    * @param nsISupportsString aHudIdSupportsString
    *        The HUD ID as an nsISupportsString.
    * @param array aItem
    *        An item from the output queue - this item represents a message.
    * @return nsIDOMElement|undefined
@@ -2540,17 +2566,19 @@ WebConsoleFrame.prototype = {
    * Release an actor.
    *
    * @private
    * @param string aActor
    *        The actor ID you want to release.
    */
   _releaseObject: function WCF__releaseObject(aActor)
   {
-    this.proxy.releaseActor(aActor);
+    if (this.proxy) {
+      this.proxy.releaseActor(aActor);
+    }
   },
 
   /**
    * Open the selected item's URL in a new tab.
    */
   openSelectedItemInTab: function WCF_openSelectedItemInTab()
   {
     let item = this.outputNode.selectedItem;
@@ -2567,23 +2595,38 @@ WebConsoleFrame.prototype = {
    * Console is closed.
    *
    * @param function [aOnDestroy]
    *        Optional function to invoke when the Web Console instance is
    *        destroyed.
    */
   destroy: function WCF_destroy(aOnDestroy)
   {
+    this._cssNodes = {};
+    this._outputQueue = [];
+    this._pruneCategoriesQueue = {};
+    this._networkRequests = {};
+
+    if (this._outputTimerInitialized) {
+      this._outputTimerInitialized = false;
+      this._outputTimer.cancel();
+    }
+    this._outputTimer = null;
+
     if (this.proxy) {
       this.proxy.disconnect(aOnDestroy);
+      this.proxy = null;
     }
 
     if (this.jsterm) {
       this.jsterm.destroy();
+      this.jsterm = null;
     }
+
+    this._commandController = null;
   },
 };
 
 /**
  * Create a JSTerminal (a JavaScript command line). This is attached to an
  * existing HeadsUpDisplay (a Web Console instance). This code is responsible
  * with handling command line input, code evaluation and result output.
  *
@@ -2670,16 +2713,20 @@ JSTerm.prototype = {
    *        Optional function to invoke when the evaluation result is added to
    *        the output.
    * @param object aResponse
    *        The message received from the server.
    */
   _executeResultCallback:
   function JST__executeResultCallback(aAfterNode, aCallback, aResponse)
   {
+    if (!this.hud) {
+      return;
+    }
+
     let errorMessage = aResponse.errorMessage;
     let result = aResponse.result;
     let inspectable = result && typeof result == "object" && result.inspectable;
     let helperResult = aResponse.helperResult;
     let helperHasRawOutput = !!(helperResult || {}).rawOutput;
     let resultString =
       WebConsoleUtils.objectActorGripToString(result,
                                               !helperHasRawOutput);
@@ -3589,20 +3636,23 @@ JSTerm.prototype = {
    * Destroy the JSTerm object. Call this method to avoid memory leaks.
    */
   destroy: function JST_destroy()
   {
     this.clearCompletion();
     this.clearOutput();
 
     this.autocompletePopup.destroy();
+    this.autocompletePopup = null;
 
     this.inputNode.removeEventListener("keypress", this._keyPress, false);
     this.inputNode.removeEventListener("input", this._inputEventHandler, false);
     this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
+
+    this.hud = null;
   },
 };
 
 /**
  * Utils: a collection of globally used functions.
  */
 var Utils = {
   /**
@@ -3833,16 +3883,24 @@ WebConsoleConnectionProxy.prototype = {
    * The DebuggerClient object.
    *
    * @see DebuggerClient
    * @type object
    */
   client: null,
 
   /**
+   * The WebConsoleClient object.
+   *
+   * @see WebConsoleClient
+   * @type object
+   */
+  webConsoleClient: null,
+
+  /**
    * Tells if the connection is established.
    * @type boolean
    */
   connected: false,
 
   /**
    * The WebConsoleActor ID.
    *
@@ -4099,16 +4157,17 @@ WebConsoleConnectionProxy.prototype = {
     this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
     this.client.removeListener("fileActivity", this._onFileActivity);
     this.client.removeListener("locationChange", this._onLocationChange);
     this.client.close(aOnDisconnect);
 
     this.client = null;
     this.webConsoleClient = null;
     this.connected = false;
+    this.owner = null;
   },
 };
 
 function gSequenceId()
 {
   return gSequenceId.n++;
 }
 gSequenceId.n = 0;
--- a/toolkit/devtools/webconsole/WebConsoleUtils.jsm
+++ b/toolkit/devtools/webconsole/WebConsoleUtils.jsm
@@ -39,31 +39,17 @@ var EXPORTED_SYMBOLS = ["WebConsoleUtils
 // (function foobar(a, b) { ...
 // function foobar2(a) { ...
 // function() { ...
 const REGEX_MATCH_FUNCTION_NAME = /^\(?function\s+([^(\s]+)\s*\(/;
 
 // Match the function arguments from the result of toString() or toSource().
 const REGEX_MATCH_FUNCTION_ARGS = /^\(?function\s*[^\s(]*\s*\((.+?)\)/;
 
-const TYPES = { OBJECT: 0,
-                FUNCTION: 1,
-                ARRAY: 2,
-                OTHER: 3,
-                ITERATOR: 4,
-                GETTER: 5,
-                GENERATOR: 6,
-                STRING: 7
-              };
-
-var gObjectId = 0;
-
 var WebConsoleUtils = {
-  TYPES: TYPES,
-
   /**
    * Convenience function to unwrap a wrapped object.
    *
    * @param aObject the object to unwrap.
    * @return aObject unwrapped.
    */
   unwrap: function WCU_unwrap(aObject)
   {
@@ -350,113 +336,16 @@ var WebConsoleUtils = {
       // the Web Console. If the constructor.name is a getter that throws, or
       // something else bad happens.
     }
 
     return type.toLowerCase();
   },
 
   /**
-   * Figures out the type of aObject and the string to display as the object
-   * value.
-   *
-   * @see TYPES
-   * @param object aObject
-   *        The object to operate on.
-   * @return object
-   *         An object of the form:
-   *         {
-   *           type: TYPES.OBJECT || TYPES.FUNCTION || ...
-   *           display: string for displaying the object
-   *         }
-   */
-  presentableValueFor: function WCU_presentableValueFor(aObject)
-  {
-    let type = this.getResultType(aObject);
-    let presentable;
-
-    switch (type) {
-      case "undefined":
-      case "null":
-        return {
-          type: TYPES.OTHER,
-          display: type
-        };
-
-      case "array":
-        return {
-          type: TYPES.ARRAY,
-          display: "Array"
-        };
-
-      case "string":
-        return {
-          type: TYPES.STRING,
-          display: "\"" + aObject + "\""
-        };
-
-      case "date":
-      case "regexp":
-      case "number":
-      case "boolean":
-        return {
-          type: TYPES.OTHER,
-          display: aObject.toString()
-        };
-
-      case "iterator":
-        return {
-          type: TYPES.ITERATOR,
-          display: "Iterator"
-        };
-
-      case "function":
-        presentable = aObject.toString();
-        return {
-          type: TYPES.FUNCTION,
-          display: presentable.substring(0, presentable.indexOf(')') + 1)
-        };
-
-      default:
-        presentable = String(aObject);
-        let m = /^\[object (\S+)\]/.exec(presentable);
-
-        try {
-          if (typeof aObject == "object" && typeof aObject.next == "function" &&
-              m && m[1] == "Generator") {
-            return {
-              type: TYPES.GENERATOR,
-              display: m[1]
-            };
-          }
-        }
-        catch (ex) {
-          // window.history.next throws in the typeof check above.
-          return {
-            type: TYPES.OBJECT,
-            display: m ? m[1] : "Object"
-          };
-        }
-
-        if (typeof aObject == "object" &&
-            typeof aObject.__iterator__ == "function") {
-          return {
-            type: TYPES.ITERATOR,
-            display: "Iterator"
-          };
-        }
-
-        return {
-          type: TYPES.OBJECT,
-          display: m ? m[1] : "Object"
-        };
-    }
-  },
-
-  /**
    * Tells if the given function is native or not.
    *
    * @param function aFunction
    *        The function you want to check if it is native or not.
    * @return boolean
    *         True if the given function is native, false otherwise.
    */
   isNativeFunction: function WCU_isNativeFunction(aFunction)
@@ -515,105 +404,16 @@ var WebConsoleUtils = {
       catch (ex if (ex.name == "TypeError")) {
         return desc;
       }
     }
     return desc;
   },
 
   /**
-   * Get an array that describes the properties of the given object.
-   *
-   * @param object aObject
-   *        The object to get the properties from.
-   * @param object aObjectCache
-   *        Optional object cache where to store references to properties of
-   *        aObject that are inspectable. See this.isObjectInspectable().
-   * @return array
-   *         An array that describes each property from the given object. Each
-   *         array element is an object (a property descriptor). Each property
-   *         descriptor has the following properties:
-   *         - name - property name
-   *         - value - a presentable property value representation (see
-   *                   this.presentableValueFor())
-   *         - type - value type (see this.presentableValueFor())
-   *         - inspectable - tells if the property value holds further
-   *                         properties (see this.isObjectInspectable()).
-   *         - objectId - optional, available only if aObjectCache is given and
-   *         if |inspectable| is true. You can do
-   *         aObjectCache[propertyDescriptor.objectId] to get the actual object
-   *         referenced by the property of aObject.
-   */
-  namesAndValuesOf: function WCU_namesAndValuesOf(aObject, aObjectCache)
-  {
-    let pairs = [];
-    let value, presentable;
-
-    let isDOMDocument = aObject instanceof Ci.nsIDOMDocument;
-    let deprecated = ["width", "height", "inputEncoding"];
-
-    for (let propName in aObject) {
-      // See bug 632275: skip deprecated properties.
-      if (isDOMDocument && deprecated.indexOf(propName) > -1) {
-        continue;
-      }
-
-      // Also skip non-native getters.
-      if (this.isNonNativeGetter(aObject, propName)) {
-        value = "";
-        presentable = {type: TYPES.GETTER, display: "Getter"};
-      }
-      else {
-        try {
-          value = aObject[propName];
-          presentable = this.presentableValueFor(value);
-        }
-        catch (ex) {
-          continue;
-        }
-      }
-
-      let pair = {};
-      pair.name = propName;
-      pair.value = presentable.display;
-      pair.inspectable = false;
-      pair.type = presentable.type;
-
-      switch (presentable.type) {
-        case TYPES.GETTER:
-        case TYPES.ITERATOR:
-        case TYPES.GENERATOR:
-        case TYPES.STRING:
-          break;
-        default:
-          try {
-            for (let p in value) {
-              pair.inspectable = true;
-              break;
-            }
-          }
-          catch (ex) { }
-          break;
-      }
-
-      // Store the inspectable object.
-      if (pair.inspectable && aObjectCache) {
-        pair.objectId = ++gObjectId;
-        aObjectCache[pair.objectId] = value;
-      }
-
-      pairs.push(pair);
-    }
-
-    pairs.sort(this.propertiesSort);
-
-    return pairs;
-  },
-
-  /**
    * Sort function for object properties.
    *
    * @param object a
    *        Property descriptor.
    * @param object b
    *        Property descriptor.
    * @return integer
    *         -1 if a.name < b.name,
@@ -1363,27 +1163,27 @@ function getMatchedProps(aObj, aOptions 
 
   if (aObj == null) { return {}; }
   try {
     Object.getPrototypeOf(aObj);
   } catch(e) {
     aObj = aObj.constructor.prototype;
   }
   let c = MAX_COMPLETIONS;
-  let names = {};   // Using an Object to avoid duplicates.
+  let names = Object.create(null);   // Using an Object to avoid duplicates.
 
   // We need to go up the prototype chain.
   let ownNames = null;
   while (aObj !== null) {
     ownNames = Object.getOwnPropertyNames(aObj);
     for (let i = 0; i < ownNames.length; i++) {
       // Filtering happens here.
       // If we already have it in, no need to append it.
       if (ownNames[i].indexOf(aOptions.matchProp) != 0 ||
-          names[ownNames[i]] == true) {
+          ownNames[i] in names) {
         continue;
       }
       c--;
       if (c < 0) {
         return names;
       }
       // If it is an array index, we can't take it.
       // This uses a trick: converting a string to a number yields NaN if