From ebd177e3cd0932dd4c115926d825990f1edbc9f0 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Fri, 5 Aug 2016 10:44:42 -0700 Subject: [PATCH] Bug 1288475 - Remove code unused in client and server versions of webconsole utils;r=tromey MozReview-Commit-ID: GcNg9nEI9d4 --HG-- extra : rebase_source : aa23b027673b9bcfcdb9d8751d528335ac5afbaa --- devtools/client/webconsole/utils.js | 1071 ----------------- .../server/actors/utils/webconsole-utils.js | 414 ------- devtools/server/actors/webconsole.js | 2 - 3 files changed, 1487 deletions(-) diff --git a/devtools/client/webconsole/utils.js b/devtools/client/webconsole/utils.js index 219f52ef64fe..427f6e4c8e19 100644 --- a/devtools/client/webconsole/utils.js +++ b/devtools/client/webconsole/utils.js @@ -7,18 +7,7 @@ "use strict"; const {Cc, Ci, Cu, components} = require("chrome"); -const {isWindowIncluded} = require("devtools/shared/layout/utils"); const Services = require("Services"); -const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); - -// TODO: Bug 842672 - browser/ imports modules from toolkit/. -// Note that these are only used in WebConsoleCommands, see $0 and pprint(). -loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, - "swm", - "@mozilla.org/serviceworkers/manager;1", - "nsIServiceWorkerManager"); // Match the function name from the result of toString() or toSource(). // @@ -52,17 +41,6 @@ var WebConsoleUtils = { return str; }, - /** - * Given a message, return one of CONSOLE_WORKER_IDS if it matches - * one of those. - * - * @return string - */ - getWorkerType: function (message) { - let id = message ? message.innerID : null; - return CONSOLE_WORKER_IDS[CONSOLE_WORKER_IDS.indexOf(id)] || null; - }, - /** * Clone an object. * @@ -124,154 +102,6 @@ var WebConsoleUtils = { to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText; }, - /** - * Gets the ID of the inner window of this DOM window. - * - * @param nsIDOMWindow window - * @return integer - * Inner ID for the given window. - */ - getInnerWindowId: function (window) { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID; - }, - - /** - * Recursively gather a list of inner window ids given a - * top level window. - * - * @param nsIDOMWindow window - * @return Array - * list of inner window ids. - */ - getInnerWindowIDsForFrames: function (window) { - let innerWindowID = this.getInnerWindowId(window); - let ids = [innerWindowID]; - - if (window.frames) { - for (let i = 0; i < window.frames.length; i++) { - let frame = window.frames[i]; - ids = ids.concat(this.getInnerWindowIDsForFrames(frame)); - } - } - - return ids; - }, - - /** - * Gets the ID of the outer window of this DOM window. - * - * @param nsIDOMWindow window - * @return integer - * Outer ID for the given window. - */ - getOuterWindowId: function (window) { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils).outerWindowID; - }, - - /** - * Tells if the given function is native or not. - * - * @param function func - * 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 (func) { - return typeof func == "function" && !("prototype" in func); - }, - - /** - * Tells if the given property of the provided object is a - * non-native getter or not. - * - * @param object object - * The object that contains the property. - * @param string prop - * The property you want to check if it is a getter or not. - * @return boolean - * True if the given property is a getter, false otherwise. - */ - isNonNativeGetter: function (object, prop) { - if (typeof object != "object") { - return false; - } - let desc = this.getPropertyDescriptor(object, prop); - return desc && desc.get && !this.isNativeFunction(desc.get); - }, - - /** - * Get the property descriptor for the given object. - * - * @param object object - * The object that contains the property. - * @param string prop - * The property you want to get the descriptor for. - * @return object - * Property descriptor. - */ - getPropertyDescriptor: function (object, prop) { - let desc = null; - while (object) { - try { - if ((desc = Object.getOwnPropertyDescriptor(object, prop))) { - break; - } - } catch (ex) { - // Native getters throw here. See bug 520882. - // null throws TypeError. - if (ex.name != "NS_ERROR_XPC_BAD_CONVERT_JS" && - ex.name != "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO" && - ex.name != "TypeError") { - throw ex; - } - } - - try { - object = Object.getPrototypeOf(object); - } catch (ex) { - if (ex.name == "TypeError") { - return desc; - } - throw ex; - } - } - return desc; - }, - - /** - * Sort function for object properties. - * - * @param object a - * Property descriptor. - * @param object b - * Property descriptor. - * @return integer - * -1 if a.name < b.name, - * 1 if a.name > b.name, - * 0 otherwise. - */ - propertiesSort: function (a, b) { - // Convert the pair.name to a number for later sorting. - let number = parseFloat(a.name); - let bNumber = parseFloat(b.name); - - // Sort numbers, then string. - if (!isNaN(number) && isNaN(bNumber)) { - return -1; - } else if (isNaN(number) && !isNaN(bNumber)) { - return 1; - } else if (!isNaN(number) && !isNaN(bNumber)) { - return number - bNumber; - } else if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } - return 0; - }, - /** * Create a grip for the given value. If the value is an object, * an object wrapper will be created. @@ -318,41 +148,6 @@ var WebConsoleUtils = { } }, - /** - * Check if the given object is an iterator or a generator. - * - * @param object object - * The object you want to check. - * @return boolean - * True if the given object is an iterator or a generator, otherwise - * false is returned. - */ - isIteratorOrGenerator: function (object) { - if (object === null) { - return false; - } - - if (typeof object == "object") { - if (typeof object.__iterator__ == "function" || - object.constructor && object.constructor.name == "Iterator") { - return true; - } - - try { - let str = object.toString(); - if (typeof object.next == "function" && - str.indexOf("[object Generator") == 0) { - return true; - } - } catch (ex) { - // window.history.next throws in the typeof check above. - return false; - } - } - - return false; - }, - /** * Determine if the given request mixes HTTP with HTTPS content. * @@ -613,869 +408,3 @@ WebConsoleUtils.L10n.prototype = { return result; }, }; - -// ///////////////////////////////////////////////////////////////////////////// -// The page errors listener -// ///////////////////////////////////////////////////////////////////////////// - -/** - * The nsIConsoleService listener. This is used to send all of the console - * messages (JavaScript, CSS and more) to the remote Web Console instance. - * - * @constructor - * @param nsIDOMWindow [window] - * Optional - the window object for which we are created. This is used - * for filtering out messages that belong to other windows. - * @param object listener - * The listener object must have one method: - * - onConsoleServiceMessage(). This method is invoked with one argument, - * the nsIConsoleMessage, whenever a relevant message is received. - */ -function ConsoleServiceListener(window, listener) { - this.window = window; - this.listener = listener; -} -exports.ConsoleServiceListener = ConsoleServiceListener; - -ConsoleServiceListener.prototype = -{ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]), - - /** - * The content window for which we listen to page errors. - * @type nsIDOMWindow - */ - window: null, - - /** - * The listener object which is notified of messages from the console service. - * @type object - */ - listener: null, - - /** - * Initialize the nsIConsoleService listener. - */ - init: function () { - 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 nsIConsoleMessage message - * The message object coming from the nsIConsoleService. - */ - observe: function (message) { - if (!this.listener) { - return; - } - - if (this.window) { - if (!(message instanceof Ci.nsIScriptError) || - !message.outerWindowID || - !this.isCategoryAllowed(message.category)) { - return; - } - - let errorWindow = Services.wm.getOuterWindowWithId(message.outerWindowID); - if (!errorWindow || !isWindowIncluded(this.window, errorWindow)) { - return; - } - } - - this.listener.onConsoleServiceMessage(message); - }, - - /** - * Check if the given message category is allowed to be tracked or not. - * We ignore chrome-originating errors as we only care about content. - * - * @param string category - * The message category you want to check. - * @return boolean - * True if the category is allowed to be logged, false otherwise. - */ - isCategoryAllowed: function (category) { - if (!category) { - return false; - } - - switch (category) { - 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 and its (i)frames. - * - * @param boolean [includePrivate=false] - * Tells if you want to also retrieve messages coming from private - * windows. Defaults to false. - * @return array - * The array of cached messages. Each element is an nsIScriptError or - * an nsIConsoleMessage - */ - getCachedMessages: function (includePrivate = false) { - let errors = Services.console.getMessageArray() || []; - - // if !this.window, we're in a browser console. Still need to filter - // private messages. - if (!this.window) { - return errors.filter((error) => { - if (error instanceof Ci.nsIScriptError) { - if (!includePrivate && error.isFromPrivateWindow) { - return false; - } - } - - return true; - }); - } - - let ids = WebConsoleUtils.getInnerWindowIDsForFrames(this.window); - - return errors.filter((error) => { - if (error instanceof Ci.nsIScriptError) { - if (!includePrivate && error.isFromPrivateWindow) { - return false; - } - if (ids && - (ids.indexOf(error.innerWindowID) == -1 || - !this.isCategoryAllowed(error.category))) { - return false; - } - } else if (ids && ids[0]) { - // If this is not an nsIScriptError and we need to do window-based - // filtering we skip this message. - return false; - } - - return true; - }); - }, - - /** - * Remove the nsIConsoleService listener. - */ - destroy: function () { - Services.console.unregisterListener(this); - this.listener = this.window = null; - }, -}; - -// ///////////////////////////////////////////////////////////////////////////// -// 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. - * - * @constructor - * @param nsIDOMWindow window - * Optional - the window object for which we are created. This is used - * for filtering out messages that belong to other windows. - * @param object owner - * The owner object must have the following methods: - * - onConsoleAPICall(). This method is invoked with one argument, the - * Console API message that comes from the observer service, whenever - * a relevant console API call is received. - * @param object filteringOptions - * Optional - The filteringOptions that this listener should listen to: - * - addonId: filter console messages based on the addonId. - */ -function ConsoleAPIListener(window, owner, {addonId} = {}) { - this.window = window; - this.owner = owner; - this.addonId = addonId; -} -exports.ConsoleAPIListener = ConsoleAPIListener; - -ConsoleAPIListener.prototype = -{ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), - - /** - * The content window for which we listen to window.console API calls. - * @type nsIDOMWindow - */ - window: null, - - /** - * The owner object which is notified of window.console API calls. It must - * have a onConsoleAPICall method which is invoked with one argument: the - * console API call object that comes from the observer service. - * - * @type object - * @see WebConsoleActor - */ - owner: null, - - /** - * The addonId that we listen for. If not null then only messages from this - * console will be returned. - */ - addonId: null, - - /** - * Initialize the window.console API observer. - */ - init: function () { - // Note that the observer is process-wide. We will filter the messages as - // needed, see CAL_observe(). - Services.obs.addObserver(this, "console-api-log-event", false); - }, - - /** - * The console API message observer. When messages are received from the - * observer service we forward them to the remote Web Console instance. - * - * @param object message - * The message object receives from the observer service. - * @param string topic - * The message topic received from the observer service. - */ - observe: function (message, topic) { - if (!this.owner) { - return; - } - - // Here, wrappedJSObject is not a security wrapper but a property defined - // by the XPCOM component which allows us to unwrap the XPCOM interface and - // access the underlying JSObject. - let apiMessage = message.wrappedJSObject; - - if (!this.isMessageRelevant(apiMessage)) { - return; - } - - this.owner.onConsoleAPICall(apiMessage); - }, - - /** - * Given a message, return true if this window should show it and false - * if it should be ignored. - * - * @param message - * The message from the Storage Service - * @return bool - * Do we care about this message? - */ - isMessageRelevant: function (message) { - let workerType = WebConsoleUtils.getWorkerType(message); - - if (this.window && workerType === "ServiceWorker") { - // For messages from Service Workers, message.ID is the - // scope, which can be used to determine whether it's controlling - // a window. - let scope = message.ID; - - if (!swm.shouldReportToWindow(this.window, scope)) { - return false; - } - } - - if (this.window && !workerType) { - let msgWindow = Services.wm.getCurrentInnerWindowWithId(message.innerID); - if (!msgWindow || !isWindowIncluded(this.window, msgWindow)) { - // Not the same window! - return false; - } - } - - if (this.addonId) { - // ConsoleAPI.jsm messages contains a consoleID, (and it is currently - // used in Addon SDK add-ons), the standard 'console' object - // (which is used in regular webpages and in WebExtensions pages) - // contains the originAttributes of the source document principal. - - // Filtering based on the originAttributes used by - // the Console API object. - if (message.originAttributes && - message.originAttributes.addonId == this.addonId) { - return true; - } - - // Filtering based on the old-style consoleID property used by - // the legacy Console JSM module. - if (message.consoleID && message.consoleID == `addon/${this.addonId}`) { - return true; - } - - return false; - } - - return true; - }, - - /** - * Get the cached messages for the current inner window and its (i)frames. - * - * @param boolean [includePrivate=false] - * Tells if you want to also retrieve messages coming from private - * windows. Defaults to false. - * @return array - * The array of cached messages. - */ - getCachedMessages: function (includePrivate = false) { - let messages = []; - let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"] - .getService(Ci.nsIConsoleAPIStorage); - - // if !this.window, we're in a browser console. Retrieve all events - // for filtering based on privacy. - if (!this.window) { - messages = ConsoleAPIStorage.getEvents(); - } else { - let ids = WebConsoleUtils.getInnerWindowIDsForFrames(this.window); - ids.forEach((id) => { - messages = messages.concat(ConsoleAPIStorage.getEvents(id)); - }); - } - - CONSOLE_WORKER_IDS.forEach((id) => { - messages = messages.concat(ConsoleAPIStorage.getEvents(id)); - }); - - messages = messages.filter(msg => { - return this.isMessageRelevant(msg); - }); - - if (includePrivate) { - return messages; - } - - return messages.filter((m) => !m.private); - }, - - /** - * Destroy the console API listener. - */ - destroy: function () { - Services.obs.removeObserver(this, "console-api-log-event"); - this.window = this.owner = null; - }, -}; - -/** - * WebConsole commands manager. - * - * Defines a set of functions /variables ("commands") that are available from - * the Web Console but not from the web page. - * - */ -var WebConsoleCommands = { - _registeredCommands: new Map(), - _originalCommands: new Map(), - - /** - * @private - * Reserved for built-in commands. To register a command from the code of an - * add-on, see WebConsoleCommands.register instead. - * - * @see WebConsoleCommands.register - */ - _registerOriginal: function (name, command) { - this.register(name, command); - this._originalCommands.set(name, this.getCommand(name)); - }, - - /** - * Register a new command. - * @param {string} name The command name (exemple: "$") - * @param {(function|object)} command The command to register. - * It can be a function so the command is a function (like "$()"), - * or it can also be a property descriptor to describe a getter / value (like - * "$0"). - * - * The command function or the command getter are passed a owner object as - * their first parameter (see the example below). - * - * Note that setters don't work currently and "enumerable" and "configurable" - * are forced to true. - * - * @example - * - * WebConsoleCommands.register("$", function JSTH_$(owner, selector) - * { - * return owner.window.document.querySelector(selector); - * }); - * - * WebConsoleCommands.register("$0", { - * get: function(owner) { - * return owner.makeDebuggeeValue(owner.selectedNode); - * } - * }); - */ - register: function (name, command) { - this._registeredCommands.set(name, command); - }, - - /** - * Unregister a command. - * - * If the command being unregister overrode a built-in command, - * the latter is restored. - * - * @param {string} name The name of the command - */ - unregister: function (name) { - this._registeredCommands.delete(name); - if (this._originalCommands.has(name)) { - this.register(name, this._originalCommands.get(name)); - } - }, - - /** - * Returns a command by its name. - * - * @param {string} name The name of the command. - * - * @return {(function|object)} The command. - */ - getCommand: function (name) { - return this._registeredCommands.get(name); - }, - - /** - * Returns true if a command is registered with the given name. - * - * @param {string} name The name of the command. - * - * @return {boolean} True if the command is registered. - */ - hasCommand: function (name) { - return this._registeredCommands.has(name); - }, -}; - -exports.WebConsoleCommands = WebConsoleCommands; - -/* - * Built-in commands. - * - * A list of helper functions used by Firebug can be found here: - * http://getfirebug.com/wiki/index.php/Command_Line_API - */ - -/** - * Find a node by ID. - * - * @param string id - * The ID of the element you want. - * @return nsIDOMNode or null - * The result of calling document.querySelector(selector). - */ -WebConsoleCommands._registerOriginal("$", function (owner, selector) { - return owner.window.document.querySelector(selector); -}); - -/** - * Find the nodes matching a CSS selector. - * - * @param string selector - * A string that is passed to window.document.querySelectorAll. - * @return nsIDOMNodeList - * Returns the result of document.querySelectorAll(selector). - */ -WebConsoleCommands._registerOriginal("$$", function (owner, selector) { - let nodes = owner.window.document.querySelectorAll(selector); - - // Calling owner.window.Array.from() doesn't work without accessing the - // wrappedJSObject, so just loop through the results instead. - let result = new owner.window.Array(); - for (let i = 0; i < nodes.length; i++) { - result.push(nodes[i]); - } - return result; -}); - -/** - * Returns the result of the last console input evaluation - * - * @return object|undefined - * Returns last console evaluation or undefined - */ -WebConsoleCommands._registerOriginal("$_", { - get: function (owner) { - return owner.consoleActor.getLastConsoleInputEvaluation(); - } -}); - -/** - * Runs an xPath query and returns all matched nodes. - * - * @param string xPath - * xPath search query to execute. - * @param [optional] nsIDOMNode context - * Context to run the xPath query on. Uses window.document if not set. - * @return array of nsIDOMNode - */ -WebConsoleCommands._registerOriginal("$x", function (owner, xPath, context) { - let nodes = new owner.window.Array(); - - // Not waiving Xrays, since we want the original Document.evaluate function, - // instead of anything that's been redefined. - let doc = owner.window.document; - context = context || doc; - - let results = doc.evaluate(xPath, context, null, - Ci.nsIDOMXPathResult.ANY_TYPE, null); - let node; - while ((node = results.iterateNext())) { - nodes.push(node); - } - - return nodes; -}); - -/** - * Returns the currently selected object in the highlighter. - * - * @return Object representing the current selection in the - * Inspector, or null if no selection exists. - */ -WebConsoleCommands._registerOriginal("$0", { - get: function (owner) { - return owner.makeDebuggeeValue(owner.selectedNode); - } -}); - -/** - * Clears the output of the WebConsole. - */ -WebConsoleCommands._registerOriginal("clear", function (owner) { - owner.helperResult = { - type: "clearOutput", - }; -}); - -/** - * Clears the input history of the WebConsole. - */ -WebConsoleCommands._registerOriginal("clearHistory", function (owner) { - owner.helperResult = { - type: "clearHistory", - }; -}); - -/** - * Returns the result of Object.keys(object). - * - * @param object object - * Object to return the property names from. - * @return array of strings - */ -WebConsoleCommands._registerOriginal("keys", function (owner, object) { - // Need to waive Xrays so we can iterate functions and accessor properties - return Cu.cloneInto(Object.keys(Cu.waiveXrays(object)), owner.window); -}); - -/** - * Returns the values of all properties on object. - * - * @param object object - * Object to display the values from. - * @return array of string - */ -WebConsoleCommands._registerOriginal("values", function (owner, object) { - let values = []; - // Need to waive Xrays so we can iterate functions and accessor properties - let waived = Cu.waiveXrays(object); - let names = Object.getOwnPropertyNames(waived); - - for (let name of names) { - values.push(waived[name]); - } - - return Cu.cloneInto(values, owner.window); -}); - -/** - * Opens a help window in MDN. - */ -WebConsoleCommands._registerOriginal("help", function (owner) { - owner.helperResult = { type: "help" }; -}); - -/** - * Change the JS evaluation scope. - * - * @param DOMElement|string|window window - * The window object to use for eval scope. This can be a string that - * is used to perform document.querySelector(), to find the iframe that - * you want to cd() to. A DOMElement can be given as well, the - * .contentWindow property is used. Lastly, you can directly pass - * a window object. If you call cd() with no arguments, the current - * eval scope is cleared back to its default (the top window). - */ -WebConsoleCommands._registerOriginal("cd", function (owner, window) { - if (!window) { - owner.consoleActor.evalWindow = null; - owner.helperResult = { type: "cd" }; - return; - } - - if (typeof window == "string") { - window = owner.window.document.querySelector(window); - } - if (window instanceof Ci.nsIDOMElement && window.contentWindow) { - window = window.contentWindow; - } - if (!(window instanceof Ci.nsIDOMWindow)) { - owner.helperResult = { - type: "error", - message: "cdFunctionInvalidArgument" - }; - return; - } - - owner.consoleActor.evalWindow = window; - owner.helperResult = { type: "cd" }; -}); - -/** - * Inspects the passed object. This is done by opening the PropertyPanel. - * - * @param object object - * Object to inspect. - */ -WebConsoleCommands._registerOriginal("inspect", function (owner, object) { - let dbgObj = owner.makeDebuggeeValue(object); - let grip = owner.createValueGrip(dbgObj); - owner.helperResult = { - type: "inspectObject", - input: owner.evalInput, - object: grip, - }; -}); - -/** - * Prints object to the output. - * - * @param object object - * Object to print to the output. - * @return string - */ -WebConsoleCommands._registerOriginal("pprint", function (owner, object) { - if (object === null || object === undefined || object === true || - object === false) { - owner.helperResult = { - type: "error", - message: "helperFuncUnsupportedTypeError", - }; - return null; - } - - owner.helperResult = { rawOutput: true }; - - if (typeof object == "function") { - return object + "\n"; - } - - let output = []; - - let obj = object; - for (let name in obj) { - let desc = WebConsoleUtils.getPropertyDescriptor(obj, name) || {}; - if (desc.get || desc.set) { - // TODO: Bug 842672 - toolkit/ imports modules from browser/. - let getGrip = VariablesView.getGrip(desc.get); - let setGrip = VariablesView.getGrip(desc.set); - let getString = VariablesView.getString(getGrip); - let setString = VariablesView.getString(setGrip); - output.push(name + ":", " get: " + getString, " set: " + setString); - } else { - let valueGrip = VariablesView.getGrip(obj[name]); - let valueString = VariablesView.getString(valueGrip); - output.push(name + ": " + valueString); - } - } - - return " " + output.join("\n "); -}); - -/** - * Print the String representation of a value to the output, as-is. - * - * @param any value - * A value you want to output as a string. - * @return void - */ -WebConsoleCommands._registerOriginal("print", function (owner, value) { - owner.helperResult = { rawOutput: true }; - if (typeof value === "symbol") { - return Symbol.prototype.toString.call(value); - } - // Waiving Xrays here allows us to see a closer representation of the - // underlying object. This may execute arbitrary content code, but that - // code will run with content privileges, and the result will be rendered - // inert by coercing it to a String. - return String(Cu.waiveXrays(value)); -}); - -/** - * Copy the String representation of a value to the clipboard. - * - * @param any value - * A value you want to copy as a string. - * @return void - */ -WebConsoleCommands._registerOriginal("copy", function (owner, value) { - let payload; - try { - if (value instanceof Ci.nsIDOMElement) { - payload = value.outerHTML; - } else if (typeof value == "string") { - payload = value; - } else { - payload = JSON.stringify(value, null, " "); - } - } catch (ex) { - payload = "/* " + ex + " */"; - } - owner.helperResult = { - type: "copyValueToClipboard", - value: payload, - }; -}); - -/** - * (Internal only) Add the bindings to |owner.sandbox|. - * This is intended to be used by the WebConsole actor only. - * - * @param object owner - * The owning object. - */ -function addWebConsoleCommands(owner) { - if (!owner) { - throw new Error("The owner is required"); - } - for (let [name, command] of WebConsoleCommands._registeredCommands) { - if (typeof command === "function") { - owner.sandbox[name] = command.bind(undefined, owner); - } else if (typeof command === "object") { - let clone = Object.assign({}, command, { - // We force the enumerability and the configurability (so the - // WebConsoleActor can reconfigure the property). - enumerable: true, - configurable: true - }); - - if (typeof command.get === "function") { - clone.get = command.get.bind(undefined, owner); - } - if (typeof command.set === "function") { - clone.set = command.set.bind(undefined, owner); - } - - Object.defineProperty(owner.sandbox, name, clone); - } - } -} - -exports.addWebConsoleCommands = addWebConsoleCommands; - -/** - * A ReflowObserver that listens for reflow events from the page. - * Implements nsIReflowObserver. - * - * @constructor - * @param object window - * The window for which we need to track reflow. - * @param object owner - * The listener owner which needs to implement: - * - onReflowActivity(reflowInfo) - */ - -function ConsoleReflowListener(window, listener) { - this.docshell = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell); - this.listener = listener; - this.docshell.addWeakReflowObserver(this); -} - -exports.ConsoleReflowListener = ConsoleReflowListener; - -ConsoleReflowListener.prototype = -{ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, - Ci.nsISupportsWeakReference]), - docshell: null, - listener: null, - - /** - * Forward reflow event to listener. - * - * @param DOMHighResTimeStamp start - * @param DOMHighResTimeStamp end - * @param boolean interruptible - */ - sendReflow: function (start, end, interruptible) { - let frame = components.stack.caller.caller; - - let filename = frame ? frame.filename : null; - - if (filename) { - // Because filename could be of the form "xxx.js -> xxx.js -> xxx.js", - // we only take the last part. - filename = filename.split(" ").pop(); - } - - this.listener.onReflowActivity({ - interruptible: interruptible, - start: start, - end: end, - sourceURL: filename, - sourceLine: frame ? frame.lineNumber : null, - functionName: frame ? frame.name : null - }); - }, - - /** - * On uninterruptible reflow - * - * @param DOMHighResTimeStamp start - * @param DOMHighResTimeStamp end - */ - reflow: function (start, end) { - this.sendReflow(start, end, false); - }, - - /** - * On interruptible reflow - * - * @param DOMHighResTimeStamp start - * @param DOMHighResTimeStamp end - */ - reflowInterruptible: function (start, end) { - this.sendReflow(start, end, true); - }, - - /** - * Unregister listener. - */ - destroy: function () { - this.docshell.removeWeakReflowObserver(this); - this.listener = this.docshell = null; - }, -}; - -function gSequenceId() { - return gSequenceId.n++; -} -gSequenceId.n = 0; diff --git a/devtools/server/actors/utils/webconsole-utils.js b/devtools/server/actors/utils/webconsole-utils.js index 219f52ef64fe..38c549011c86 100644 --- a/devtools/server/actors/utils/webconsole-utils.js +++ b/devtools/server/actors/utils/webconsole-utils.js @@ -20,17 +20,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "@mozilla.org/serviceworkers/manager;1", "nsIServiceWorkerManager"); -// Match the function name from the result of toString() or toSource(). -// -// Examples: -// (function foobar(a, b) { ... -// function foobar2(a) { ... -// function() { ... -const REGEX_MATCH_FUNCTION_NAME = /^\(?function\s+([^(\s]+)\s*\(/; - -// Number of terminal entries for the self-xss prevention to go away -const CONSOLE_ENTRY_THRESHOLD = 5; - const CONSOLE_WORKER_IDS = exports.CONSOLE_WORKER_IDS = [ "SharedWorker", "ServiceWorker", @@ -39,19 +28,6 @@ const CONSOLE_WORKER_IDS = exports.CONSOLE_WORKER_IDS = [ var WebConsoleUtils = { - /** - * Wrap a string in an nsISupportsString object. - * - * @param string string - * @return nsISupportsString - */ - supportsString: function (string) { - let str = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - str.data = string; - return str; - }, - /** * Given a message, return one of CONSOLE_WORKER_IDS if it matches * one of those. @@ -107,23 +83,6 @@ var WebConsoleUtils = { return temp; }, - /** - * Copies certain style attributes from one element to another. - * - * @param nsIDOMNode from - * The target node. - * @param nsIDOMNode to - * The destination node. - */ - copyTextStyles: function (from, to) { - let win = from.ownerDocument.defaultView; - let style = win.getComputedStyle(from); - to.style.fontFamily = style.getPropertyCSSValue("font-family").cssText; - to.style.fontSize = style.getPropertyCSSValue("font-size").cssText; - to.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText; - to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText; - }, - /** * Gets the ID of the inner window of this DOM window. * @@ -158,49 +117,6 @@ var WebConsoleUtils = { return ids; }, - /** - * Gets the ID of the outer window of this DOM window. - * - * @param nsIDOMWindow window - * @return integer - * Outer ID for the given window. - */ - getOuterWindowId: function (window) { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils).outerWindowID; - }, - - /** - * Tells if the given function is native or not. - * - * @param function func - * 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 (func) { - return typeof func == "function" && !("prototype" in func); - }, - - /** - * Tells if the given property of the provided object is a - * non-native getter or not. - * - * @param object object - * The object that contains the property. - * @param string prop - * The property you want to check if it is a getter or not. - * @return boolean - * True if the given property is a getter, false otherwise. - */ - isNonNativeGetter: function (object, prop) { - if (typeof object != "object") { - return false; - } - let desc = this.getPropertyDescriptor(object, prop); - return desc && desc.get && !this.isNativeFunction(desc.get); - }, - /** * Get the property descriptor for the given object. * @@ -240,38 +156,6 @@ var WebConsoleUtils = { return desc; }, - /** - * Sort function for object properties. - * - * @param object a - * Property descriptor. - * @param object b - * Property descriptor. - * @return integer - * -1 if a.name < b.name, - * 1 if a.name > b.name, - * 0 otherwise. - */ - propertiesSort: function (a, b) { - // Convert the pair.name to a number for later sorting. - let number = parseFloat(a.name); - let bNumber = parseFloat(b.name); - - // Sort numbers, then string. - if (!isNaN(number) && isNaN(bNumber)) { - return -1; - } else if (isNaN(number) && !isNaN(bNumber)) { - return 1; - } else if (!isNaN(number) && !isNaN(bNumber)) { - return number - bNumber; - } else if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } - return 0; - }, - /** * Create a grip for the given value. If the value is an object, * an object wrapper will be created. @@ -317,303 +201,10 @@ var WebConsoleUtils = { return null; } }, - - /** - * Check if the given object is an iterator or a generator. - * - * @param object object - * The object you want to check. - * @return boolean - * True if the given object is an iterator or a generator, otherwise - * false is returned. - */ - isIteratorOrGenerator: function (object) { - if (object === null) { - return false; - } - - if (typeof object == "object") { - if (typeof object.__iterator__ == "function" || - object.constructor && object.constructor.name == "Iterator") { - return true; - } - - try { - let str = object.toString(); - if (typeof object.next == "function" && - str.indexOf("[object Generator") == 0) { - return true; - } - } catch (ex) { - // window.history.next throws in the typeof check above. - return false; - } - } - - return false; - }, - - /** - * Determine if the given request mixes HTTP with HTTPS content. - * - * @param string request - * Location of the requested content. - * @param string location - * Location of the current page. - * @return boolean - * True if the content is mixed, false if not. - */ - isMixedHTTPSRequest: function (request, location) { - try { - let requestURI = Services.io.newURI(request, null, null); - let contentURI = Services.io.newURI(location, null, null); - return (contentURI.scheme == "https" && requestURI.scheme != "https"); - } catch (ex) { - return false; - } - }, - - /** - * Helper function to deduce the name of the provided function. - * - * @param funtion function - * The function whose name will be returned. - * @return string - * Function name. - */ - getFunctionName: function (func) { - let name = null; - if (func.name) { - name = func.name; - } else { - let desc; - try { - desc = func.getOwnPropertyDescriptor("displayName"); - } catch (ex) { - // Ignore. - } - if (desc && typeof desc.value == "string") { - name = desc.value; - } - } - if (!name) { - try { - let str = (func.toString() || func.toSource()) + ""; - name = (str.match(REGEX_MATCH_FUNCTION_NAME) || [])[1]; - } catch (ex) { - // Ignore. - } - } - return name; - }, - - /** - * Get the object class name. For example, the |window| object has the Window - * class name (based on [object Window]). - * - * @param object object - * The object you want to get the class name for. - * @return string - * The object class name. - */ - getObjectClassName: function (object) { - if (object === null) { - return "null"; - } - if (object === undefined) { - return "undefined"; - } - - let type = typeof object; - if (type != "object") { - // Grip class names should start with an uppercase letter. - return type.charAt(0).toUpperCase() + type.substr(1); - } - - let className; - - try { - className = ((object + "").match(/^\[object (\S+)\]$/) || [])[1]; - if (!className) { - className = ((object.constructor + "") - .match(/^\[object (\S+)\]$/) || [])[1]; - } - if (!className && typeof object.constructor == "function") { - className = this.getFunctionName(object.constructor); - } - } catch (ex) { - // Ignore. - } - - return className; - }, - - /** - * Check if the given value is a grip with an actor. - * - * @param mixed grip - * Value you want to check if it is a grip with an actor. - * @return boolean - * True if the given value is a grip with an actor. - */ - isActorGrip: function (grip) { - return grip && typeof (grip) == "object" && grip.actor; - }, - - /** - * Value of devtools.selfxss.count preference - * - * @type number - * @private - */ - _usageCount: 0, - get usageCount() { - if (WebConsoleUtils._usageCount < CONSOLE_ENTRY_THRESHOLD) { - WebConsoleUtils._usageCount = - Services.prefs.getIntPref("devtools.selfxss.count"); - if (Services.prefs.getBoolPref("devtools.chrome.enabled")) { - WebConsoleUtils.usageCount = CONSOLE_ENTRY_THRESHOLD; - } - } - return WebConsoleUtils._usageCount; - }, - set usageCount(newUC) { - if (newUC <= CONSOLE_ENTRY_THRESHOLD) { - WebConsoleUtils._usageCount = newUC; - Services.prefs.setIntPref("devtools.selfxss.count", newUC); - } - }, - /** - * The inputNode "paste" event handler generator. Helps prevent - * self-xss attacks - * - * @param nsIDOMElement inputField - * @param nsIDOMElement notificationBox - * @returns A function to be added as a handler to 'paste' and - *'drop' events on the input field - */ - pasteHandlerGen: function (inputField, notificationBox, msg, okstring) { - let handler = function (event) { - if (WebConsoleUtils.usageCount >= CONSOLE_ENTRY_THRESHOLD) { - inputField.removeEventListener("paste", handler); - inputField.removeEventListener("drop", handler); - return true; - } - if (notificationBox.getNotificationWithValue("selfxss-notification")) { - event.preventDefault(); - event.stopPropagation(); - return false; - } - - let notification = notificationBox.appendNotification(msg, - "selfxss-notification", null, - notificationBox.PRIORITY_WARNING_HIGH, null, - function (eventType) { - // Cleanup function if notification is dismissed - if (eventType == "removed") { - inputField.removeEventListener("keyup", pasteKeyUpHandler); - } - }); - - function pasteKeyUpHandler(event2) { - let value = inputField.value || inputField.textContent; - if (value.includes(okstring)) { - notificationBox.removeNotification(notification); - inputField.removeEventListener("keyup", pasteKeyUpHandler); - WebConsoleUtils.usageCount = CONSOLE_ENTRY_THRESHOLD; - } - } - inputField.addEventListener("keyup", pasteKeyUpHandler); - - event.preventDefault(); - event.stopPropagation(); - return false; - }; - return handler; - }, }; exports.Utils = WebConsoleUtils; -// //////////////////////////////////////////////////////////////////////// -// Localization -// //////////////////////////////////////////////////////////////////////// - -WebConsoleUtils.L10n = function (bundleURI) { - this._bundleUri = bundleURI; -}; - -WebConsoleUtils.L10n.prototype = { - _stringBundle: null, - - get stringBundle() { - if (!this._stringBundle) { - this._stringBundle = Services.strings.createBundle(this._bundleUri); - } - return this._stringBundle; - }, - - /** - * Generates a formatted timestamp string for displaying in console messages. - * - * @param integer [milliseconds] - * Optional, allows you to specify the timestamp in milliseconds since - * the UNIX epoch. - * @return string - * The timestamp formatted for display. - */ - timestampString: function (milliseconds) { - let d = new Date(milliseconds ? milliseconds : null); - let hours = d.getHours(), minutes = d.getMinutes(); - let seconds = d.getSeconds(); - milliseconds = d.getMilliseconds(); - let parameters = [hours, minutes, seconds, milliseconds]; - return this.getFormatStr("timestampFormat", parameters); - }, - - /** - * Retrieve a localized string. - * - * @param string name - * The string name you want from the Web Console string bundle. - * @return string - * The localized string. - */ - getStr: function (name) { - let result; - try { - result = this.stringBundle.GetStringFromName(name); - } catch (ex) { - console.error("Failed to get string: " + name); - throw ex; - } - return result; - }, - - /** - * Retrieve a localized string formatted with values coming from the given - * array. - * - * @param string name - * The string name you want from the Web Console string bundle. - * @param array array - * The array of values you want in the formatted string. - * @return string - * The formatted local string. - */ - getFormatStr: function (name, array) { - let result; - try { - result = this.stringBundle.formatStringFromName(name, array, - array.length); - } catch (ex) { - console.error("Failed to format string: " + name); - throw ex; - } - return result; - }, -}; - // ///////////////////////////////////////////////////////////////////////////// // The page errors listener // ///////////////////////////////////////////////////////////////////////////// @@ -1474,8 +1065,3 @@ ConsoleReflowListener.prototype = this.listener = this.docshell = null; }, }; - -function gSequenceId() { - return gSequenceId.n++; -} -gSequenceId.n = 0; diff --git a/devtools/server/actors/webconsole.js b/devtools/server/actors/webconsole.js index 57564b5d6fa0..2e6fbaef8db0 100644 --- a/devtools/server/actors/webconsole.js +++ b/devtools/server/actors/webconsole.js @@ -88,8 +88,6 @@ function WebConsoleActor(aConnection, aParentActor) }; } -WebConsoleActor.l10n = new WebConsoleUtils.L10n("chrome://global/locale/console.properties"); - WebConsoleActor.prototype = { /**