gecko-dev/remote/Error.jsm
Andreas Tolfsen de8c9e85cf bug 1553317: remote: improve error message on missing method; r=remote-protocol-reviewers,ochameau CLOSED TREE
We return with this rather omnious message when we are missing the
implementation of a CDP method:

	Error: Protocol error (Target.createBrowserContext): TypeError: inst[command] is not a function:

This patch improves the error message so that debugging is not
necessary to find out which domain or command is missing.

Ideally Session.jsm and ContentProcessSession.jsm would share the
same execute() function (there's really not reason they don't),
but that involves more work.

Differential Revision: https://phabricator.services.mozilla.com/D32069

--HG--
extra : source : f3d44dbce7e3d1b529ce37b21a4d7471a918edd4
extra : histedit_source : df4d534565efb3e2babbc277a3aecce5d534ac39
2019-05-27 11:39:16 +00:00

136 lines
3.5 KiB
JavaScript

/* 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";
var EXPORTED_SYMBOLS = [
"FatalError",
"RemoteAgentError",
"UnknownMethodError",
"UnsupportedError",
];
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
class RemoteAgentError extends Error {
constructor(message = "", cause = undefined) {
cause = cause || message;
super(cause);
this.name = this.constructor.name;
this.message = message;
this.cause = cause;
this.notify();
}
notify() {
Cu.reportError(this);
log.error(this.toString({stack: true}));
}
toString({stack = false} = {}) {
return RemoteAgentError.format(this, {stack});
}
static format(e, {stack = false} = {}) {
return formatError(e, {stack});
}
/**
* Takes a serialised CDP error and reconstructs it
* as a RemoteAgentError.
*
* The error must be of this form:
*
* {"message": "TypeError: foo is not a function\n
* execute@chrome://remote/content/sessions/Session.jsm:73:39\n
* onMessage@chrome://remote/content/sessions/TabSession.jsm:65:20"}
*
* This approach has the notable deficiency that it cannot deal
* with causes to errors because of the unstructured nature of CDP
* errors. A possible future improvement would be to extend the
* error serialisation to include discrete fields for each data
* property.
*
* @param {Object} json
* CDP error encoded as a JSON object, which must have a
* "message" field, where the first line will make out the error
* message and the subsequent lines the stacktrace.
*
* @return {RemoteAgentError}
*/
static fromJSON(json) {
const [message, ...stack] = json.message.split("\n");
const err = new RemoteAgentError();
err.message = message.slice(0, -1);
err.stack = stack.map(s => s.trim()).join("\n");
err.cause = null;
return err;
}
}
/**
* A fatal error that it is not possible to recover from
* or send back to the client.
*
* Constructing this error will force the application to quit.
*/
class FatalError extends RemoteAgentError {
constructor(...args) {
super(...args);
this.quit();
}
notify() {
log.fatal(this.toString({stack: true}));
}
quit(mode = Ci.nsIAppStartup.eForceQuit) {
Services.startup.quit(mode);
}
}
/** When an operation is not yet implemented. */
class UnsupportedError extends RemoteAgentError {}
/** The requested remote method does not exist. */
class UnknownMethodError extends RemoteAgentError {
constructor(domain, command = null) {
if (command) {
super(`${domain}.${command}`);
} else {
super(domain);
}
}
}
function formatError(error, {stack = false} = {}) {
const els = [];
els.push(error.name);
if (error.message) {
els.push(": ");
els.push(error.message);
}
if (stack && error.stack) {
els.push(":\n");
const stack = error.stack.trim().split("\n");
els.push(stack.map(line => `\t${line}`).join("\n"));
if (error.cause) {
els.push("\n");
els.push("caused by: " + formatError(error.cause, {stack}));
}
}
return els.join("");
}