Bug 1561435 - Format remote/, a=automatic-formatting

# ignore-this-changeset

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

--HG--
extra : source : b793788d0f38244b33eb59ea36e2c6624dbd12c5
This commit is contained in:
Victor Porof 2019-07-05 10:56:48 +02:00
parent 91f67eb25e
commit 991b3c93c6
64 changed files with 1477 additions and 674 deletions

View file

@ -45,7 +45,6 @@ module.exports = {
"overrides": [{
"files": [
"devtools/**",
"remote/**",
"security/**",
"services/**",
"servo/**",

View file

@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js
# Ignore all top-level directories for now.
remote/**
security/**
services/**
servo/**

View file

@ -6,11 +6,18 @@
var EXPORTED_SYMBOLS = ["Connection"];
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
XPCOMUtils.defineLazyServiceGetter(
this,
"UUIDGen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator"
);
class Connection {
/**
@ -40,8 +47,10 @@ class Connection {
registerSession(session) {
if (!session.id) {
if (this.defaultSession) {
throw new Error("Default session is already set on Connection," +
"can't register another one.");
throw new Error(
"Default session is already set on Connection," +
"can't register another one."
);
}
this.defaultSession = session;
}
@ -58,14 +67,14 @@ class Connection {
message: e.message,
data: e.stack,
};
this.send({id, error});
this.send({ id, error });
}
deserialize(data) {
const id = data.id;
const method = data.method;
const params = data.params || {};
return {id, method, params};
return { id, method, params };
}
// transport hooks
@ -73,7 +82,7 @@ class Connection {
onPacket(packet) {
log.trace(`(connection ${this.id})-> ${JSON.stringify(packet)}`);
let message = {id: null};
let message = { id: null };
try {
message = this.deserialize(packet);
const { sessionId } = packet;

View file

@ -11,9 +11,11 @@ var EXPORTED_SYMBOLS = [
"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");
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);
@ -31,15 +33,15 @@ class RemoteAgentError extends Error {
notify() {
Cu.reportError(this);
log.error(this.toString({stack: true}));
log.error(this.toString({ stack: true }));
}
toString({stack = false} = {}) {
return RemoteAgentError.format(this, {stack});
toString({ stack = false } = {}) {
return RemoteAgentError.format(this, { stack });
}
static format(e, {stack = false} = {}) {
return formatError(e, {stack});
static format(e, { stack = false } = {}) {
return formatError(e, { stack });
}
/**
@ -88,7 +90,7 @@ class FatalError extends RemoteAgentError {
}
notify() {
log.fatal(this.toString({stack: true}));
log.fatal(this.toString({ stack: true }));
}
quit(mode = Ci.nsIAppStartup.eForceQuit) {
@ -110,7 +112,7 @@ class UnknownMethodError extends RemoteAgentError {
}
}
function formatError(error, {stack = false} = {}) {
function formatError(error, { stack = false } = {}) {
const els = [];
els.push(error.name);
@ -127,7 +129,7 @@ function formatError(error, {stack = false} = {}) {
if (error.cause) {
els.push("\n");
els.push("caused by: " + formatError(error.cause, {stack}));
els.push("caused by: " + formatError(error.cause, { stack }));
}
}

View file

@ -6,10 +6,14 @@
var EXPORTED_SYMBOLS = ["JSONHandler"];
const {HTTP_404, HTTP_505} = ChromeUtils.import("chrome://remote/content/server/HTTPD.jsm");
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
const {Protocol} = ChromeUtils.import("chrome://remote/content/Protocol.jsm");
const {RemoteAgentError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const { HTTP_404, HTTP_505 } = ChromeUtils.import(
"chrome://remote/content/server/HTTPD.jsm"
);
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
const { Protocol } = ChromeUtils.import("chrome://remote/content/Protocol.jsm");
const { RemoteAgentError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
class JSONHandler {
constructor(agent) {
@ -24,12 +28,12 @@ class JSONHandler {
getVersion() {
const mainProcessTarget = this.agent.targets.getMainProcessTarget();
return {
"Browser": "Firefox",
Browser: "Firefox",
"Protocol-Version": "1.0",
"User-Agent": "Mozilla",
"V8-Version": "1.0",
"WebKit-Version": "1.0",
"webSocketDebuggerUrl": mainProcessTarget.toJSON().webSocketDebuggerUrl,
webSocketDebuggerUrl: mainProcessTarget.toJSON().webSocketDebuggerUrl,
};
}
@ -54,7 +58,11 @@ class JSONHandler {
try {
const body = this.routes[request.path]();
const payload = JSON.stringify(body, sanitise, Log.verbose ? "\t" : undefined);
const payload = JSON.stringify(
body,
sanitise,
Log.verbose ? "\t" : undefined
);
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/json");

View file

@ -6,8 +6,8 @@
var EXPORTED_SYMBOLS = ["Log"];
const {Log: StdLog} = ChromeUtils.import("resource://gre/modules/Log.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Log: StdLog } = ChromeUtils.import("resource://gre/modules/Log.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const LOG_LEVEL = "remote.log.level";

View file

@ -6,7 +6,7 @@
var EXPORTED_SYMBOLS = ["Observer"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class Observer {
static observe(type, observer) {

View file

@ -18,6 +18,7 @@ const RecommendedPreferences = {
// Prevent various error message on the console
// jest-puppeteer asserts that no error message is emitted by the console
"browser.contentblocking.features.standard": "-tp,tpPrivate,cookieBehavior0,-cm,-fp",
"browser.contentblocking.features.standard":
"-tp,tpPrivate,cookieBehavior0,-cm,-fp",
"network.cookie.cookieBehavior": 0,
};

View file

@ -6,8 +6,10 @@
var EXPORTED_SYMBOLS = ["RemoteAgent", "RemoteAgentFactory"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
FatalError: "chrome://remote/content/Error.jsm",
@ -36,7 +38,9 @@ class RemoteAgentClass {
throw new Error("Remote agent is disabled by its preference");
}
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
throw new Error("Remote agent can only be instantiated from the parent process");
throw new Error(
"Remote agent can only be instantiated from the parent process"
);
}
if (this.server) {
@ -48,7 +52,7 @@ class RemoteAgentClass {
this.server.registerPrefixHandler("/json/", new JSONHandler(this));
this.tabs = new TabObserver({registerExisting: true});
this.tabs = new TabObserver({ registerExisting: true });
this.tabs.on("open", (eventName, tab) => {
this.targets.connect(tab.linkedBrowser);
});
@ -78,7 +82,7 @@ class RemoteAgentClass {
throw new TypeError(`Expected nsIURI: ${address}`);
}
let {host, port} = address;
let { host, port } = address;
if (Preferences.get(FORCE_LOCAL) && !LOOPBACKS.includes(host)) {
throw new Error("Restricted to loopback devices");
}
@ -167,7 +171,9 @@ class RemoteAgentClass {
const remoteDebuggingPort = flag("remote-debugging-port");
if (remoteDebugger && remoteDebuggingPort) {
log.fatal("Conflicting flags --remote-debugger and --remote-debugging-port");
log.fatal(
"Conflicting flags --remote-debugger and --remote-debugging-port"
);
cmdLine.preventDefault = true;
return;
}
@ -185,9 +191,14 @@ class RemoteAgentClass {
let addr;
try {
addr = NetUtil.newURI(`http://${host || DEFAULT_HOST}:${port || DEFAULT_PORT}/`);
addr = NetUtil.newURI(
`http://${host || DEFAULT_HOST}:${port || DEFAULT_PORT}/`
);
} catch (e) {
log.fatal(`Expected address syntax [<host>]:<port>: ${remoteDebugger || remoteDebuggingPort}`);
log.fatal(
`Expected address syntax [<host>]:<port>: ${remoteDebugger ||
remoteDebuggingPort}`
);
cmdLine.preventDefault = true;
return;
}
@ -200,15 +211,20 @@ class RemoteAgentClass {
this.listen(addr);
} catch (e) {
this.close();
throw new FatalError(`Unable to start remote agent on ${addr.spec}: ${e.message}`, e);
throw new FatalError(
`Unable to start remote agent on ${addr.spec}: ${e.message}`,
e
);
}
}
get helpInfo() {
return " --remote-debugger [<host>][:<port>]\n" +
return (
" --remote-debugger [<host>][:<port>]\n" +
" --remote-debugging-port <port> Start the Firefox remote agent, which is \n" +
" a low-level debugging interface based on the CDP protocol.\n" +
" Defaults to listen on localhost:9222.\n";
" Defaults to listen on localhost:9222.\n"
);
}
// XPCOM

View file

@ -10,7 +10,7 @@ var EXPORTED_SYMBOLS = [
"MessagePromise",
];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* Wait for a single event to be fired on a specific EventListener.
@ -43,34 +43,48 @@ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
*
* @throws {TypeError}
*/
function EventPromise(listener, type, options = {
function EventPromise(
listener,
type,
options = {
capture: false,
wantsUntrusted: false,
mozSystemGroup: false,
}) {
}
) {
if (!listener || !("addEventListener" in listener)) {
throw new TypeError();
}
if (typeof type != "string") {
throw new TypeError();
}
if (("capture" in options && typeof options.capture != "boolean") ||
("wantsUntrusted" in options && typeof options.wantsUntrusted != "boolean") ||
("mozSystemGroup" in options && typeof options.mozSystemGroup != "boolean")) {
if (
("capture" in options && typeof options.capture != "boolean") ||
("wantsUntrusted" in options &&
typeof options.wantsUntrusted != "boolean") ||
("mozSystemGroup" in options && typeof options.mozSystemGroup != "boolean")
) {
throw new TypeError();
}
options.once = true;
return new Promise(resolve => {
listener.addEventListener(type, event => {
listener.addEventListener(
type,
event => {
Services.tm.dispatchToMainThread(() => resolve(event));
}, options);
},
options
);
});
}
function DOMContentLoadedPromise(window, options = {mozSystemGroup: true}) {
if (window.document.readyState == "complete" || window.document.readyState == "interactive") {
function DOMContentLoadedPromise(window, options = { mozSystemGroup: true }) {
if (
window.document.readyState == "complete" ||
window.document.readyState == "interactive"
) {
return Promise.resolve();
}
return new EventPromise(window, "DOMContentLoaded", options);

View file

@ -4,15 +4,15 @@
"use strict";
var EXPORTED_SYMBOLS = [
"TabManager",
"TabObserver",
"WindowObserver",
];
var EXPORTED_SYMBOLS = ["TabManager", "TabObserver", "WindowObserver"];
const {DOMContentLoadedPromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { DOMContentLoadedPromise } = ChromeUtils.import(
"chrome://remote/content/Sync.jsm"
);
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* The WindowManager provides tooling for application-agnostic
@ -40,7 +40,7 @@ class WindowObserver {
* Events will be despatched for the ChromeWindows that exist
* at the time the observer is started.
*/
constructor({registerExisting = false} = {}) {
constructor({ registerExisting = false } = {}) {
this.registerExisting = registerExisting;
EventEmitter.decorate(this);
}
@ -95,8 +95,8 @@ class TabObserver {
* Events will be fired for ChromeWIndows and their respective tabs
* at the time when the observer is started.
*/
constructor({registerExisting = false} = {}) {
this.windows = new WindowObserver({registerExisting});
constructor({ registerExisting = false } = {}) {
this.windows = new WindowObserver({ registerExisting });
EventEmitter.decorate(this);
}
@ -136,8 +136,10 @@ class TabObserver {
this.onTabOpen(tab);
}
window.addEventListener("TabOpen", ({target}) => this.onTabOpen(target));
window.addEventListener("TabClose", ({target}) => this.onTabClose(target));
window.addEventListener("TabOpen", ({ target }) => this.onTabOpen(target));
window.addEventListener("TabClose", ({ target }) =>
this.onTabClose(target)
);
}
onWindowClose(window) {

View file

@ -6,10 +6,15 @@
var EXPORTED_SYMBOLS = ["ContentProcessDomain"];
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
ChromeUtils.defineModuleGetter(this, "ContextObserver",
"chrome://remote/content/domains/ContextObserver.jsm");
ChromeUtils.defineModuleGetter(
this,
"ContextObserver",
"chrome://remote/content/domains/ContextObserver.jsm"
);
class ContentProcessDomain extends Domain {
destructor() {

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["ContentProcessDomains"];
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const ContentProcessDomains = {};

View file

@ -25,37 +25,45 @@
var EXPORTED_SYMBOLS = ["ContextObserver"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
class ContextObserver {
constructor(chromeEventHandler) {
this.chromeEventHandler = chromeEventHandler;
EventEmitter.decorate(this);
this.chromeEventHandler.addEventListener("DOMWindowCreated", this,
{mozSystemGroup: true});
this.chromeEventHandler.addEventListener("DOMWindowCreated", this, {
mozSystemGroup: true,
});
// Listen for pageshow and pagehide to track pages going in/out to/from the BF Cache
this.chromeEventHandler.addEventListener("pageshow", this,
{mozSystemGroup: true});
this.chromeEventHandler.addEventListener("pagehide", this,
{mozSystemGroup: true});
this.chromeEventHandler.addEventListener("pageshow", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.addEventListener("pagehide", this, {
mozSystemGroup: true,
});
Services.obs.addObserver(this, "inner-window-destroyed");
}
destructor() {
this.chromeEventHandler.removeEventListener("DOMWindowCreated", this,
{mozSystemGroup: true});
this.chromeEventHandler.removeEventListener("pageshow", this,
{mozSystemGroup: true});
this.chromeEventHandler.removeEventListener("pagehide", this,
{mozSystemGroup: true});
this.chromeEventHandler.removeEventListener("DOMWindowCreated", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.removeEventListener("pageshow", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.removeEventListener("pagehide", this, {
mozSystemGroup: true,
});
Services.obs.removeObserver(this, "inner-window-destroyed");
}
handleEvent({type, target, persisted}) {
handleEvent({ type, target, persisted }) {
const window = target.defaultView;
if (window.top != this.chromeEventHandler.ownerGlobal) {
// Ignore iframes for now.
@ -99,5 +107,3 @@ class ContextObserver {
this.emit("context-destroyed", { id: innerWindowID });
}
}

View file

@ -45,7 +45,7 @@ class Domain {
}
function isEventHandler(listener) {
return listener &&
"onEvent" in listener &&
typeof listener.onEvent == "function";
return (
listener && "onEvent" in listener && typeof listener.onEvent == "function"
);
}

View file

@ -6,8 +6,12 @@
var EXPORTED_SYMBOLS = ["Domains"];
const {UnknownMethodError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const { UnknownMethodError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
/**
* Lazy domain instance cache.

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["ParentProcessDomains"];
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const ParentProcessDomains = {};

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["DOM"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
class DOM extends ContentProcessDomain {
constructor(session) {
@ -48,10 +50,14 @@ class DOM extends ContentProcessDomain {
let quads = unsafeObject.getBoxQuads({ relativeTo: this.content.document });
quads = quads.map(quad => {
return [
quad.p1.x, quad.p1.y,
quad.p2.x, quad.p2.y,
quad.p3.x, quad.p3.y,
quad.p4.x, quad.p4.y,
quad.p1.x,
quad.p1.y,
quad.p2.x,
quad.p2.y,
quad.p3.x,
quad.p3.y,
quad.p4.x,
quad.p4.y,
].map(Math.round);
});
return { quads };
@ -67,7 +73,10 @@ class DOM extends ContentProcessDomain {
height: Math.round(bounding.height),
};
for (const box of ["content", "padding", "border", "margin"]) {
const quads = unsafeObject.getBoxQuads({box, relativeTo: this.content.document});
const quads = unsafeObject.getBoxQuads({
box,
relativeTo: this.content.document,
});
// getBoxQuads may return more than one element. In this case we have to compute the bounding box
// of all these boxes.
@ -99,10 +108,14 @@ class DOM extends ContentProcessDomain {
});
model[box] = [
bounding.p1.x, bounding.p1.y,
bounding.p2.x, bounding.p2.y,
bounding.p3.x, bounding.p3.y,
bounding.p4.x, bounding.p4.y,
bounding.p1.x,
bounding.p1.y,
bounding.p2.x,
bounding.p2.y,
bounding.p3.x,
bounding.p3.y,
bounding.p4.x,
bounding.p4.y,
].map(Math.round);
}
return {

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["Emulation"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
class Emulation extends ContentProcessDomain {
// commands

View file

@ -6,6 +6,8 @@
var EXPORTED_SYMBOLS = ["Input"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
class Input extends ContentProcessDomain {}

View file

@ -6,8 +6,10 @@
var EXPORTED_SYMBOLS = ["Log"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class Log extends ContentProcessDomain {
constructor(session) {
@ -57,7 +59,7 @@ class Log extends ContentProcessDomain {
entry = fromConsoleAPI(message.wrappedJSObject);
}
this.emit("Log.entryAdded", {entry});
this.emit("Log.entryAdded", { entry });
}
// XPCOM
@ -91,12 +93,11 @@ function fromConsoleAPI(message) {
// A couple of possible level are defined here:
// https://searchfox.org/mozilla-central/rev/00c0d068ece99717bea7475f7dc07e61f7f35984/dom/console/Console.cpp#1086-1100
const levels = {
"log": "verbose",
"info": "info",
"warn": "warning",
"error": "error",
"exception": "error",
log: "verbose",
info: "info",
warn: "warning",
error: "error",
exception: "error",
};
const level = levels[message.level] || "info";
@ -112,15 +113,19 @@ function fromConsoleAPI(message) {
}
function fromScriptError(error) {
const {flags, errorMessage, sourceName, lineNumber, stack} = error;
const { flags, errorMessage, sourceName, lineNumber, stack } = error;
// lossy reduction from bitmask to CDP string level
let level = "verbose";
if ((flags & Ci.nsIScriptError.exceptionFlag) ||
(flags & Ci.nsIScriptError.errorFlag)) {
if (
flags & Ci.nsIScriptError.exceptionFlag ||
flags & Ci.nsIScriptError.errorFlag
) {
level = "error";
} else if ((flags & Ci.nsIScriptError.warningFlag) ||
(flags & Ci.nsIScriptError.strictFlag)) {
} else if (
flags & Ci.nsIScriptError.warningFlag ||
flags & Ci.nsIScriptError.strictFlag
) {
level = "warning";
} else if (flags & Ci.nsIScriptError.infoFlag) {
level = "info";

View file

@ -6,9 +6,13 @@
var EXPORTED_SYMBOLS = ["Page"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {UnsupportedError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { UnsupportedError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
class Page extends ContentProcessDomain {
constructor(session) {
@ -31,10 +35,12 @@ class Page extends ContentProcessDomain {
this.enabled = true;
this.contextObserver.on("frame-navigated", this.onFrameNavigated);
this.chromeEventHandler.addEventListener("DOMContentLoaded", this,
{mozSystemGroup: true});
this.chromeEventHandler.addEventListener("pageshow", this,
{mozSystemGroup: true});
this.chromeEventHandler.addEventListener("DOMContentLoaded", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.addEventListener("pageshow", this, {
mozSystemGroup: true,
});
}
}
@ -42,15 +48,17 @@ class Page extends ContentProcessDomain {
if (this.enabled) {
this.contextObserver.off("frame-navigated", this.onFrameNavigated);
this.chromeEventHandler.removeEventListener("DOMContentLoaded", this,
{mozSystemGroup: true});
this.chromeEventHandler.removeEventListener("pageshow", this,
{mozSystemGroup: true});
this.chromeEventHandler.removeEventListener("DOMContentLoaded", this, {
mozSystemGroup: true,
});
this.chromeEventHandler.removeEventListener("pageshow", this, {
mozSystemGroup: true,
});
this.enabled = false;
}
}
async navigate({url, referrer, transitionType, frameId} = {}) {
async navigate({ url, referrer, transitionType, frameId } = {}) {
if (frameId && frameId != this.content.windowUtils.outerWindowID) {
throw new UnsupportedError("frameId not supported");
}
@ -108,7 +116,7 @@ class Page extends ContentProcessDomain {
});
}
handleEvent({type, target}) {
handleEvent({ type, target }) {
if (target.defaultView != this.content) {
// Ignore iframes for now
return;
@ -120,14 +128,14 @@ class Page extends ContentProcessDomain {
switch (type) {
case "DOMContentLoaded":
this.emit("Page.domContentEventFired", {timestamp});
this.emit("Page.domContentEventFired", { timestamp });
break;
case "pageshow":
this.emit("Page.loadEventFired", {timestamp, frameId});
this.emit("Page.loadEventFired", { timestamp, frameId });
// XXX this should most likely be sent differently
this.emit("Page.navigatedWithinDocument", {timestamp, frameId, url});
this.emit("Page.frameStoppedLoading", {timestamp, frameId});
this.emit("Page.navigatedWithinDocument", { timestamp, frameId, url });
this.emit("Page.frameStoppedLoading", { timestamp, frameId });
break;
}
}

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["Performance"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
class Performance extends ContentProcessDomain {
constructor(session) {

View file

@ -6,10 +6,17 @@
var EXPORTED_SYMBOLS = ["Runtime"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {ExecutionContext} = ChromeUtils.import("chrome://remote/content/domains/content/runtime/ExecutionContext.jsm");
const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {});
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { ExecutionContext } = ChromeUtils.import(
"chrome://remote/content/domains/content/runtime/ExecutionContext.jsm"
);
const { addDebuggerToGlobal } = ChromeUtils.import(
"resource://gre/modules/jsdebugger.jsm",
{}
);
// Import the `Debugger` constructor in the current scope
addDebuggerToGlobal(Cu.getGlobalForObject(this));
@ -63,11 +70,15 @@ class Runtime extends ContentProcessDomain {
evaluate(request) {
const context = this.contexts.get(request.contextId);
if (!context) {
throw new Error(`Unable to find execution context with id: ${request.contextId}`);
throw new Error(
`Unable to find execution context with id: ${request.contextId}`
);
}
if (typeof(request.expression) != "string") {
throw new Error(`Expecting 'expression' attribute to be a string. ` +
`But was: ${typeof(request.expression)}`);
if (typeof request.expression != "string") {
throw new Error(
`Expecting 'expression' attribute to be a string. ` +
`But was: ${typeof request.expression}`
);
}
return context.evaluate(request.expression);
}
@ -75,7 +86,7 @@ class Runtime extends ContentProcessDomain {
getRemoteObject(objectId) {
for (const ctx of this.contexts.values()) {
const obj = ctx.getRemoteObject(objectId);
if (typeof(obj) != "undefined") {
if (typeof obj != "undefined") {
return obj;
}
}
@ -108,33 +119,47 @@ class Runtime extends ContentProcessDomain {
}
}
if (!context) {
throw new Error(`Unable to get the context for object with id: ${request.objectId}`);
throw new Error(
`Unable to get the context for object with id: ${request.objectId}`
);
}
} else {
context = this.contexts.get(request.executionContextId);
if (!context) {
throw new Error(`Unable to find execution context with id: ${request.executionContextId}`);
throw new Error(
`Unable to find execution context with id: ${
request.executionContextId
}`
);
}
}
if (typeof(request.functionDeclaration) != "string") {
throw new Error("Expect 'functionDeclaration' attribute to be passed and be a string");
if (typeof request.functionDeclaration != "string") {
throw new Error(
"Expect 'functionDeclaration' attribute to be passed and be a string"
);
}
if (request.arguments && !Array.isArray(request.arguments)) {
throw new Error("Expect 'arguments' to be an array");
}
if (request.returnByValue && typeof(request.returnByValue) != "boolean") {
if (request.returnByValue && typeof request.returnByValue != "boolean") {
throw new Error("Expect 'returnByValue' to be a boolean");
}
if (request.awaitPromise && typeof(request.awaitPromise) != "boolean") {
if (request.awaitPromise && typeof request.awaitPromise != "boolean") {
throw new Error("Expect 'awaitPromise' to be a boolean");
}
return context.callFunctionOn(request.functionDeclaration, request.arguments, request.returnByValue, request.awaitPromise, request.objectId);
return context.callFunctionOn(
request.functionDeclaration,
request.arguments,
request.returnByValue,
request.awaitPromise,
request.objectId
);
}
getProperties({ objectId, ownProperties }) {
for (const ctx of this.contexts.values()) {
const obj = ctx.getRemoteObject(objectId);
if (typeof(obj) != "undefined") {
if (typeof obj != "undefined") {
return ctx.getProperties({ objectId, ownProperties });
}
}

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["Security"];
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
const { ContentProcessDomain } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomain.jsm"
);
class Security extends ContentProcessDomain {
constructor(session) {

View file

@ -6,13 +6,26 @@
var EXPORTED_SYMBOLS = ["ExecutionContext"];
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(
Ci.nsIUUIDGenerator
);
const TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
"Uint32Array", "Int8Array", "Int16Array", "Int32Array",
"Float32Array", "Float64Array"];
const TYPED_ARRAY_CLASSES = [
"Uint8Array",
"Uint8ClampedArray",
"Uint16Array",
"Uint32Array",
"Int8Array",
"Int16Array",
"Int32Array",
"Float32Array",
"Float64Array",
];
function uuid() {
return uuidGen.generateUUID().toString().slice(1, -1);
return uuidGen
.generateUUID()
.toString()
.slice(1, -1);
}
/**
@ -89,10 +102,15 @@ class ExecutionContext {
* describing the exception by following CDP ExceptionDetails specification.
*/
_returnError(exception) {
if (this._debuggee.executeInGlobalWithBindings("exception instanceof Error",
{exception}).return) {
const text = this._debuggee.executeInGlobalWithBindings("exception.message",
{exception}).return;
if (
this._debuggee.executeInGlobalWithBindings("exception instanceof Error", {
exception,
}).return
) {
const text = this._debuggee.executeInGlobalWithBindings(
"exception.message",
{ exception }
).return;
return {
exceptionDetails: {
text,
@ -108,7 +126,13 @@ class ExecutionContext {
};
}
async callFunctionOn(functionDeclaration, callArguments = [], returnByValue = false, awaitPromise = false, objectId = null) {
async callFunctionOn(
functionDeclaration,
callArguments = [],
returnByValue = false,
awaitPromise = false,
objectId = null
) {
// Map the given objectId to a JS reference.
let thisArg = null;
if (objectId) {
@ -188,8 +212,12 @@ class ExecutionContext {
enumerable: descriptor.enumerable,
writable: descriptor.writable,
value: this._toRemoteObject(descriptor.value),
get: descriptor.get ? this._toRemoteObject(descriptor.get) : undefined,
set: descriptor.set ? this._toRemoteObject(descriptor.set) : undefined,
get: descriptor.get
? this._toRemoteObject(descriptor.get)
: undefined,
set: descriptor.set
? this._toRemoteObject(descriptor.set)
: undefined,
isOwn,
});
@ -224,10 +252,13 @@ class ExecutionContext {
* The JSON string
*/
_serialize(obj) {
if (typeof(obj) == "undefined") {
if (typeof obj == "undefined") {
return undefined;
}
const result = this._debuggee.executeInGlobalWithBindings("JSON.stringify(e)", {e: obj});
const result = this._debuggee.executeInGlobalWithBindings(
"JSON.stringify(e)",
{ e: obj }
);
if (result.throw) {
throw new Error("Object is not serializable");
}
@ -247,10 +278,14 @@ class ExecutionContext {
}
if (arg.unserializableValue) {
switch (arg.unserializableValue) {
case "Infinity": return Infinity;
case "-Infinity": return -Infinity;
case "-0": return -0;
case "NaN": return NaN;
case "Infinity":
return Infinity;
case "-Infinity":
return -Infinity;
case "-0":
return -0;
case "NaN":
return NaN;
}
}
return this._deserialize(arg.value);
@ -263,8 +298,10 @@ class ExecutionContext {
if (typeof obj !== "object") {
return obj;
}
const result = this._debuggee.executeInGlobalWithBindings("JSON.parse(obj)",
{obj: JSON.stringify(obj)});
const result = this._debuggee.executeInGlobalWithBindings(
"JSON.parse(obj)",
{ obj: JSON.stringify(obj) }
);
if (result.throw) {
throw new Error("Unable to deserialize object");
}
@ -318,7 +355,7 @@ class ExecutionContext {
}
const type = typeof rawObj;
return {objectId, type, subtype};
return { objectId, type, subtype };
}
// Now, handle all values that Debugger API isn't wrapping into Debugger.API.
@ -331,19 +368,20 @@ class ExecutionContext {
if (type == "symbol" || type == "bigint") {
const objectId = uuid();
this._remoteObjects.set(objectId, debuggerObj);
return {objectId, type};
return { objectId, type };
}
// A few primitive type can't be serialized and CDP has special case for them
let unserializableValue = undefined;
if (Object.is(debuggerObj, NaN))
if (Object.is(debuggerObj, NaN)) {
unserializableValue = "NaN";
else if (Object.is(debuggerObj, -0))
} else if (Object.is(debuggerObj, -0)) {
unserializableValue = "-0";
else if (Object.is(debuggerObj, Infinity))
} else if (Object.is(debuggerObj, Infinity)) {
unserializableValue = "Infinity";
else if (Object.is(debuggerObj, -Infinity))
} else if (Object.is(debuggerObj, -Infinity)) {
unserializableValue = "-Infinity";
}
if (unserializableValue) {
return {
unserializableValue,

View file

@ -6,14 +6,19 @@
var EXPORTED_SYMBOLS = ["Browser"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
class Browser extends Domain {
getVersion() {
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
const { userAgent } = Cc["@mozilla.org/network/protocol;1?name=http"]
.getService(Ci.nsIHttpProtocolHandler);
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(
Ci.nsIGfxInfo
);
const { userAgent } = Cc[
"@mozilla.org/network/protocol;1?name=http"
].getService(Ci.nsIHttpProtocolHandler);
return {
protocolVersion: "1",
product: (isHeadless ? "Headless " : "") + "Firefox",

View file

@ -6,8 +6,10 @@
var EXPORTED_SYMBOLS = ["Input"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
class Input extends Domain {
// commands
@ -28,12 +30,7 @@ class Input extends Domain {
* - windowsVirtualKeyCode
*/
async dispatchKeyEvent(options) {
const {
key,
modifiers,
type,
windowsVirtualKeyCode,
} = options;
const { key, modifiers, type, windowsVirtualKeyCode } = options;
let domType;
if (type == "keyDown" || type == "rawKeyDown") {
@ -54,8 +51,10 @@ class Input extends Domain {
const EventUtils = this._getEventUtils(browserWindow);
const onEvent = new Promise(r => {
browserWindow.addEventListener(domType, r,
{mozSystemGroup: true, once: true});
browserWindow.addEventListener(domType, r, {
mozSystemGroup: true,
once: true,
});
});
if (type == "char") {
@ -65,21 +64,23 @@ class Input extends Domain {
} else {
// Non printable keys should be prefixed with `KEY_`
const eventUtilsKey = key.length == 1 ? key : "KEY_" + key;
EventUtils.synthesizeKey(eventUtilsKey, {
EventUtils.synthesizeKey(
eventUtilsKey,
{
keyCode: windowsVirtualKeyCode,
type: domType,
altKey: !!(modifiers & 1),
ctrlKey: !!(modifiers & 2),
metaKey: !!(modifiers & 4),
shiftKey: !!(modifiers & 8),
}, browserWindow);
},
browserWindow
);
}
await onEvent;
}
async dispatchMouseEvent({
type, button, x, y, modifiers, clickCount,
}) {
async dispatchMouseEvent({ type, button, x, y, modifiers, clickCount }) {
if (type == "mousePressed") {
type = "mousedown";
} else if (type == "mouseReleased") {
@ -135,8 +136,10 @@ class Input extends Domain {
_EU_Ci: Ci,
_EU_Cc: Cc,
};
Services.scriptloader.loadSubScript("chrome://remote/content/external/EventUtils.js",
this._eventUtils);
Services.scriptloader.loadSubScript(
"chrome://remote/content/external/EventUtils.js",
this._eventUtils
);
}
return this._eventUtils;
}

View file

@ -6,8 +6,12 @@
var EXPORTED_SYMBOLS = ["Network"];
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const {NetworkObserver} = ChromeUtils.import("chrome://remote/content/domains/parent/network/NetworkObserver.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
const { NetworkObserver } = ChromeUtils.import(
"chrome://remote/content/domains/parent/network/NetworkObserver.jsm"
);
const LOAD_CAUSE_STRINGS = {
[Ci.nsIContentPolicy.TYPE_INVALID]: "Invalid",
@ -120,13 +124,17 @@ function getLoadContext(httpChannel) {
let loadContext = null;
try {
if (httpChannel.notificationCallbacks) {
loadContext = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext);
loadContext = httpChannel.notificationCallbacks.getInterface(
Ci.nsILoadContext
);
}
} catch (e) {}
try {
if (!loadContext && httpChannel.loadGroup) {
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(
Ci.nsILoadContext
);
}
} catch (e) { }
} catch (e) {}
return loadContext;
}

View file

@ -6,7 +6,9 @@
var EXPORTED_SYMBOLS = ["Page"];
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
class Page extends Domain {
// commands

View file

@ -6,10 +6,18 @@
var EXPORTED_SYMBOLS = ["Target"];
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const {TabManager} = ChromeUtils.import("chrome://remote/content/WindowManager.jsm");
const {TabSession} = ChromeUtils.import("chrome://remote/content/sessions/TabSession.jsm");
const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
const { TabManager } = ChromeUtils.import(
"chrome://remote/content/WindowManager.jsm"
);
const { TabSession } = ChromeUtils.import(
"chrome://remote/content/sessions/TabSession.jsm"
);
const { ContextualIdentityService } = ChromeUtils.import(
"resource://gre/modules/ContextualIdentityService.jsm"
);
let sessionIds = 1;
let browserContextIds = 1;
@ -29,7 +37,9 @@ class Target extends Domain {
}
createBrowserContext() {
const identity = ContextualIdentityService.create("remote-agent-" + (browserContextIds++));
const identity = ContextualIdentityService.create(
"remote-agent-" + browserContextIds++
);
return { browserContextId: identity.userContextId };
}
@ -75,9 +85,11 @@ class Target extends Domain {
const tab = TabManager.addTab({ userContextId: browserContextId });
const target = await onTarget;
if (tab.linkedBrowser != target.browser) {
throw new Error("Unexpected tab opened: " + tab.linkedBrowser.currentURI.spec);
throw new Error(
"Unexpected tab opened: " + tab.linkedBrowser.currentURI.spec
);
}
return {targetId: target.id};
return { targetId: target.id };
}
closeTarget({ targetId }) {
@ -93,7 +105,12 @@ class Target extends Domain {
return new Error(`Unable to find target with id '${targetId}'`);
}
const session = new TabSession(this.session.connection, target, sessionIds++, this.session);
const session = new TabSession(
this.session.connection,
target,
sessionIds++,
this.session
);
this.emit("Target.attachedToTarget", {
targetInfo: {
type: "page",

View file

@ -4,17 +4,33 @@
"use strict";
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const {CommonUtils} = ChromeUtils.import("resource://services-common/utils.js");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const { CommonUtils } = ChromeUtils.import(
"resource://services-common/utils.js"
);
const Cm = Components.manager;
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream", "setInputStream");
const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");
const StorageStream = CC("@mozilla.org/storagestream;1", "nsIStorageStream", "init");
const BinaryInputStream = CC(
"@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream"
);
const BinaryOutputStream = CC(
"@mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream",
"setOutputStream"
);
const StorageStream = CC(
"@mozilla.org/storagestream;1",
"nsIStorageStream",
"init"
);
// Cap response storage with 100Mb per tracked tab.
const MAX_RESPONSE_STORAGE_SIZE = 100 * 1024 * 1024;
@ -36,7 +52,9 @@ class NetworkObserver {
constructor() {
EventEmitter.decorate(this);
this._browserSessionCount = new Map();
this._activityDistributor = Cc["@mozilla.org/network/http-activity-distributor;1"].getService(Ci.nsIHttpActivityDistributor);
this._activityDistributor = Cc[
"@mozilla.org/network/http-activity-distributor;1"
].getService(Ci.nsIHttpActivityDistributor);
this._activityDistributor.addObserver(this);
this._redirectMap = new Map();
@ -53,8 +71,19 @@ class NetworkObserver {
};
// Register self as ChannelEventSink to track redirects.
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(SINK_CLASS_ID, SINK_CLASS_DESCRIPTION, SINK_CONTRACT_ID, this._channelSinkFactory);
Services.catMan.addCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, SINK_CONTRACT_ID, false, true);
registrar.registerFactory(
SINK_CLASS_ID,
SINK_CLASS_DESCRIPTION,
SINK_CONTRACT_ID,
this._channelSinkFactory
);
Services.catMan.addCategoryEntry(
SINK_CATEGORY_NAME,
SINK_CONTRACT_ID,
SINK_CONTRACT_ID,
false,
true
);
// Request interception state.
this._browserSuspendedChannels = new Map();
@ -62,12 +91,24 @@ class NetworkObserver {
this._browserResponseStorages = new Map();
this._onRequest = this._onRequest.bind(this);
this._onExamineResponse = this._onResponse.bind(this, false /* fromCache */);
this._onExamineResponse = this._onResponse.bind(
this,
false /* fromCache */
);
this._onCachedResponse = this._onResponse.bind(this, true /* fromCache */);
Services.obs.addObserver(this._onRequest, "http-on-modify-request");
Services.obs.addObserver(this._onExamineResponse, "http-on-examine-response");
Services.obs.addObserver(this._onCachedResponse, "http-on-examine-cached-response");
Services.obs.addObserver(this._onCachedResponse, "http-on-examine-merged-response");
Services.obs.addObserver(
this._onExamineResponse,
"http-on-examine-response"
);
Services.obs.addObserver(
this._onCachedResponse,
"http-on-examine-cached-response"
);
Services.obs.addObserver(
this._onCachedResponse,
"http-on-examine-merged-response"
);
}
setExtraHTTPHeaders(browser, headers) {
@ -111,7 +152,11 @@ class NetworkObserver {
}
// 2. Set new headers.
for (const header of headers) {
httpChannel.setRequestHeader(header.name, header.value, false /* merge */);
httpChannel.setRequestHeader(
header.name,
header.value,
false /* merge */
);
}
}
suspendedChannels.delete(requestId);
@ -150,14 +195,26 @@ class NetworkObserver {
}
const httpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel);
const loadContext = getLoadContext(httpChannel);
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
if (
!loadContext ||
!this._browserSessionCount.has(loadContext.topFrameElement)
) {
return;
}
this._redirectMap.set(newChannel, oldChannel);
}
observeActivity(channel, activityType, activitySubtype, timestamp, extraSizeData, extraStringData) {
if (activityType !== Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION) {
observeActivity(
channel,
activityType,
activitySubtype,
timestamp,
extraSizeData,
extraStringData
) {
if (
activityType !== Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION
) {
return;
}
if (!(channel instanceof Ci.nsIHttpChannel)) {
@ -165,10 +222,16 @@ class NetworkObserver {
}
const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
const loadContext = getLoadContext(httpChannel);
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
if (
!loadContext ||
!this._browserSessionCount.has(loadContext.topFrameElement)
) {
return;
}
if (activitySubtype !== Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE) {
if (
activitySubtype !==
Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE
) {
return;
}
this.emit("requestfinished", httpChannel, {
@ -182,17 +245,30 @@ class NetworkObserver {
}
const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
const loadContext = getLoadContext(httpChannel);
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
if (
!loadContext ||
!this._browserSessionCount.has(loadContext.topFrameElement)
) {
return;
}
const extraHeaders = this._extraHTTPHeaders.get(loadContext.topFrameElement);
const extraHeaders = this._extraHTTPHeaders.get(
loadContext.topFrameElement
);
if (extraHeaders) {
for (const header of extraHeaders) {
httpChannel.setRequestHeader(header.name, header.value, false /* merge */);
httpChannel.setRequestHeader(
header.name,
header.value,
false /* merge */
);
}
}
const causeType = httpChannel.loadInfo ? httpChannel.loadInfo.externalContentPolicyType : Ci.nsIContentPolicy.TYPE_OTHER;
const suspendedChannels = this._browserSuspendedChannels.get(loadContext.topFrameElement);
const causeType = httpChannel.loadInfo
? httpChannel.loadInfo.externalContentPolicyType
: Ci.nsIContentPolicy.TYPE_OTHER;
const suspendedChannels = this._browserSuspendedChannels.get(
loadContext.topFrameElement
);
if (suspendedChannels) {
httpChannel.suspend();
suspendedChannels.set(requestId(httpChannel), httpChannel);
@ -218,13 +294,16 @@ class NetworkObserver {
_onResponse(fromCache, httpChannel, topic) {
const loadContext = getLoadContext(httpChannel);
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
if (
!loadContext ||
!this._browserSessionCount.has(loadContext.topFrameElement)
) {
return;
}
httpChannel.QueryInterface(Ci.nsIHttpChannelInternal);
const headers = [];
httpChannel.visitResponseHeaders({
visitHeader: (name, value) => headers.push({name, value}),
visitHeader: (name, value) => headers.push({ name, value }),
});
let remoteIPAddress = undefined;
@ -262,7 +341,13 @@ class NetworkObserver {
const value = this._browserSessionCount.get(browser) || 0;
this._browserSessionCount.set(browser, value + 1);
if (value === 0) {
this._browserResponseStorages.set(browser, new ResponseStorage(MAX_RESPONSE_STORAGE_SIZE, MAX_RESPONSE_STORAGE_SIZE / 10));
this._browserResponseStorages.set(
browser,
new ResponseStorage(
MAX_RESPONSE_STORAGE_SIZE,
MAX_RESPONSE_STORAGE_SIZE / 10
)
);
}
return () => this.stopTrackingBrowserNetwork(browser);
}
@ -281,11 +366,24 @@ class NetworkObserver {
this._activityDistributor.removeObserver(this);
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(SINK_CLASS_ID, this._channelSinkFactory);
Services.catMan.deleteCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, false);
Services.catMan.deleteCategoryEntry(
SINK_CATEGORY_NAME,
SINK_CONTRACT_ID,
false
);
Services.obs.removeObserver(this._onRequest, "http-on-modify-request");
Services.obs.removeObserver(this._onExamineResponse, "http-on-examine-response");
Services.obs.removeObserver(this._onCachedResponse, "http-on-examine-cached-response");
Services.obs.removeObserver(this._onCachedResponse, "http-on-examine-merged-response");
Services.obs.removeObserver(
this._onExamineResponse,
"http-on-examine-response"
);
Services.obs.removeObserver(
this._onCachedResponse,
"http-on-examine-cached-response"
);
Services.obs.removeObserver(
this._onCachedResponse,
"http-on-examine-merged-response"
);
}
}
@ -335,8 +433,9 @@ function readRequestPostData(httpChannel) {
let text = undefined;
try {
text = NetUtil.readInputStreamToString(iStream, iStream.available());
const converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
const converter = Cc[
"@mozilla.org/intl/scriptableunicodeconverter"
].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
text = converter.ConvertToUnicode(text);
} catch (err) {
@ -356,14 +455,18 @@ function getLoadContext(httpChannel) {
let loadContext = null;
try {
if (httpChannel.notificationCallbacks) {
loadContext = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext);
loadContext = httpChannel.notificationCallbacks.getInterface(
Ci.nsILoadContext
);
}
} catch (e) {}
try {
if (!loadContext && httpChannel.loadGroup) {
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(
Ci.nsILoadContext
);
}
} catch (e) { }
} catch (e) {}
return loadContext;
}
@ -374,7 +477,7 @@ function requestId(httpChannel) {
function requestHeaders(httpChannel) {
const headers = [];
httpChannel.visitRequestHeaders({
visitHeader: (name, value) => headers.push({name, value}),
visitHeader: (name, value) => headers.push({ name, value }),
});
return headers;
}
@ -405,11 +508,15 @@ class ResponseStorage {
return;
}
let encodings = [];
if ((httpChannel instanceof Ci.nsIEncodedChannel) && httpChannel.contentEncodings && !httpChannel.applyConversion) {
if (
httpChannel instanceof Ci.nsIEncodedChannel &&
httpChannel.contentEncodings &&
!httpChannel.applyConversion
) {
const encodingHeader = httpChannel.getResponseHeader("Content-Encoding");
encodings = encodingHeader.split(/\s*\t*,\s*\t*/);
}
this._responses.set(requestId(httpChannel), {body, encodings});
this._responses.set(requestId(httpChannel), { body, encodings });
this._totalSize += body.length;
if (this._totalSize > this._maxTotalSize) {
for (let [, response] of this._responses) {
@ -425,17 +532,19 @@ class ResponseStorage {
getBase64EncodedResponse(requestId) {
const response = this._responses.get(requestId);
if (!response)
if (!response) {
throw new Error(`Request "${requestId}" is not found`);
if (response.evicted)
return {base64body: "", evicted: true};
}
if (response.evicted) {
return { base64body: "", evicted: true };
}
let result = response.body;
if (response.encodings && response.encodings.length) {
for (const encoding of response.encodings) {
result = CommonUtils.convertString(result, encoding, "uncompressed");
}
}
return {base64body: btoa(result)};
return { base64body: btoa(result) };
}
}
@ -460,7 +569,12 @@ class ResponseBodyListener {
this._chunks.push(data);
oStream.writeBytes(data, aCount);
this.originalListener.onDataAvailable(aRequest, sStream.newInputStream(0), aOffset, aCount);
this.originalListener.onDataAvailable(
aRequest,
sStream.newInputStream(0),
aOffset,
aCount
);
}
onStartRequest(aRequest) {
@ -471,25 +585,35 @@ class ResponseBodyListener {
this.originalListener.onStopRequest(aRequest, aStatusCode);
const body = this._chunks.join("");
delete this._chunks;
this._networkObserver._onResponseFinished(this._browser, this._httpChannel, body);
this._networkObserver._onResponseFinished(
this._browser,
this._httpChannel,
body
);
}
}
function getNetworkErrorStatusText(status) {
if (!status)
if (!status) {
return null;
}
for (const key of Object.keys(Cr)) {
if (Cr[key] === status)
if (Cr[key] === status) {
return key;
}
}
// Security module. The following is taken from
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL
if ((status & 0xff0000) === 0x5a0000) {
// NSS_SEC errors (happen below the base value because of negative vals)
if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
if (
(status & 0xffff) <
Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)
) {
// The bases are actually negative, so in our positive numeric space, we
// need to subtract the base off our value.
const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
const nssErr =
Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
switch (nssErr) {
case 11:
return "SEC_ERROR_EXPIRED_CERTIFICATE";
@ -511,7 +635,8 @@ function getNetworkErrorStatusText(status) {
return "SEC_ERROR_UNKNOWN";
}
}
const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);
const sslErr =
Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);
switch (sslErr) {
case 3:
return "SSL_ERROR_NO_CERTIFICATE";

View file

@ -10,15 +10,23 @@ var EXPORTED_SYMBOLS = ["WebSocketServer"];
const CC = Components.Constructor;
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {Stream} = ChromeUtils.import("chrome://remote/content/server/Stream.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Stream } = ChromeUtils.import(
"chrome://remote/content/server/Stream.jsm"
);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyGetter(this, "WebSocket", () => {
return Services.appShell.hiddenDOMWindow.WebSocket;
});
const CryptoHash = CC("@mozilla.org/security/hash;1", "nsICryptoHash", "initWithString");
const CryptoHash = CC(
"@mozilla.org/security/hash;1",
"nsICryptoHash",
"initWithString"
);
const threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
// limit the header size to put an upper bound on allocated memory
@ -36,7 +44,8 @@ function readLine(input) {
return new Promise((resolve, reject) => {
let line = "";
const wait = () => {
input.asyncWait(stream => {
input.asyncWait(
stream => {
try {
const amountToRead = HEADER_MAX_LEN - line.length;
line += Stream.delimitedRead(input, "\n", amountToRead);
@ -48,14 +57,19 @@ function readLine(input) {
if (line.length >= HEADER_MAX_LEN) {
throw new Error(
`Failed to read HTTP header longer than ${HEADER_MAX_LEN} bytes`);
`Failed to read HTTP header longer than ${HEADER_MAX_LEN} bytes`
);
}
wait();
} catch (ex) {
reject(ex);
}
}, 0, 0, threadManager.currentThread);
},
0,
0,
threadManager.currentThread
);
};
wait();
@ -76,7 +90,8 @@ function writeString(output, data) {
return;
}
output.asyncWait(stream => {
output.asyncWait(
stream => {
try {
const written = output.write(data, data.length);
data = data.slice(written);
@ -84,7 +99,11 @@ function writeString(output, data) {
} catch (ex) {
reject(ex);
}
}, 0, 0, threadManager.currentThread);
},
0,
0,
threadManager.currentThread
);
};
wait();
@ -120,7 +139,7 @@ const readHttpRequest = async function(input) {
}
}
return {requestLine, headers};
return { requestLine, headers };
};
/** Write HTTP response (array of strings) to async output stream. */
@ -133,7 +152,7 @@ function writeHttpResponse(output, response) {
* Process the WebSocket handshake headers and return the key to be sent in
* Sec-WebSocket-Accept response header.
*/
function processRequest({requestLine, headers}) {
function processRequest({ requestLine, headers }) {
const method = requestLine.split(" ")[0];
if (method !== "GET") {
throw new Error("The handshake request must use GET method");
@ -145,19 +164,29 @@ function processRequest({requestLine, headers}) {
}
const connection = headers.get("connection");
if (!connection || !connection.split(",").map(t => t.trim()).includes("Upgrade")) {
if (
!connection ||
!connection
.split(",")
.map(t => t.trim())
.includes("Upgrade")
) {
throw new Error("The handshake request has incorrect Connection header");
}
const version = headers.get("sec-websocket-version");
if (!version || version !== "13") {
throw new Error("The handshake request must have Sec-WebSocket-Version: 13");
throw new Error(
"The handshake request must have Sec-WebSocket-Version: 13"
);
}
// Compute the accept key
const key = headers.get("sec-websocket-key");
if (!key) {
throw new Error("The handshake request must have a Sec-WebSocket-Key header");
throw new Error(
"The handshake request must have a Sec-WebSocket-Key header"
);
}
return { acceptKey: computeKey(key) };
@ -178,7 +207,7 @@ function computeKey(key) {
async function serverHandshake(request, output) {
try {
// Check and extract info from the request
const {acceptKey} = processRequest(request);
const { acceptKey } = processRequest(request);
// Send response headers
await writeHttpResponse(output, [
@ -189,7 +218,7 @@ async function serverHandshake(request, output) {
]);
} catch (error) {
// Send error response in case of error
await writeHttpResponse(output, [ "HTTP/1.1 400 Bad Request" ]);
await writeHttpResponse(output, ["HTTP/1.1 400 Bad Request"]);
throw error;
}
}
@ -205,7 +234,12 @@ async function createWebSocket(transport, input, output) {
};
return new Promise((resolve, reject) => {
const socket = WebSocket.createServerWebSocket(null, [], transportProvider, "");
const socket = WebSocket.createServerWebSocket(
null,
[],
transportProvider,
""
);
socket.addEventListener("close", () => {
input.close();
output.close();
@ -233,7 +267,7 @@ async function upgrade(request, response) {
// handle response manually, allowing us to send arbitrary data
response._powerSeized = true;
const {transport, input, output} = response._connection;
const { transport, input, output } = response._connection;
const headers = new Map();
for (let [key, values] of Object.entries(request._headers._headers)) {
@ -248,4 +282,4 @@ async function upgrade(request, response) {
return createWebSocket(transport, input, output);
}
const WebSocketServer = {accept, upgrade};
const WebSocketServer = { accept, upgrade };

View file

@ -8,7 +8,9 @@
var EXPORTED_SYMBOLS = ["WebSocketDebuggerTransport"];
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
function WebSocketDebuggerTransport(socket) {
EventEmitter.decorate(this);
@ -72,7 +74,9 @@ WebSocketDebuggerTransport.prototype = {
onMessage({ data }) {
if (typeof data !== "string") {
throw new Error("Binary messages are not supported by WebSocket transport");
throw new Error(
"Binary messages are not supported by WebSocket transport"
);
}
const object = JSON.parse(data);

View file

@ -6,9 +6,15 @@
var EXPORTED_SYMBOLS = ["ContentProcessSession"];
const {ContentProcessDomains} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomains.jsm");
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
const {UnknownMethodError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const { ContentProcessDomains } = ChromeUtils.import(
"chrome://remote/content/domains/ContentProcessDomains.jsm"
);
const { Domains } = ChromeUtils.import(
"chrome://remote/content/domains/Domains.jsm"
);
const { UnknownMethodError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
class ContentProcessSession {
constructor(messageManager, browsingContext, content, docShell) {
@ -45,8 +51,8 @@ class ContentProcessSession {
// nsIMessageListener
async receiveMessage({name, data}) {
const {browsingContextId} = data;
async receiveMessage({ name, data }) {
const { browsingContextId } = data;
// We may have more than one tab loaded in the same process,
// and debug the two at the same time. We want to ensure not
@ -61,7 +67,7 @@ class ContentProcessSession {
switch (name) {
case "remote:request":
try {
const {id, domain, command, params} = data.request;
const { id, domain, command, params } = data.request;
if (!this.domains.domainSupportsMethod(domain, command)) {
throw new UnknownMethodError(domain, command);
}

View file

@ -6,12 +6,15 @@
var EXPORTED_SYMBOLS = ["Session"];
const {ParentProcessDomains} = ChromeUtils.import("chrome://remote/content/domains/ParentProcessDomains.jsm");
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
const {
RemoteAgentError,
UnknownMethodError,
} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const { ParentProcessDomains } = ChromeUtils.import(
"chrome://remote/content/domains/ParentProcessDomains.jsm"
);
const { Domains } = ChromeUtils.import(
"chrome://remote/content/domains/Domains.jsm"
);
const { RemoteAgentError, UnknownMethodError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
/**
* A session represents exactly one client WebSocket connection.
@ -55,7 +58,7 @@ class Session {
this.domains.clear();
}
async onMessage({id, method, params}) {
async onMessage({ id, method, params }) {
try {
if (typeof id == "undefined") {
throw new TypeError("Message missing 'id' field");
@ -64,7 +67,7 @@ class Session {
throw new TypeError("Message missing 'method' field");
}
const {domain, command} = Domains.splitMethod(method);
const { domain, command } = Domains.splitMethod(method);
await this.execute(id, domain, command, params);
} catch (e) {
this.onError(id, e);
@ -93,7 +96,7 @@ class Session {
id,
sessionId: this.id,
error: {
message: RemoteAgentError.format(error, {stack: true}),
message: RemoteAgentError.format(error, { stack: true }),
},
});
}

View file

@ -6,8 +6,12 @@
var EXPORTED_SYMBOLS = ["TabSession"];
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
const { Domains } = ChromeUtils.import(
"chrome://remote/content/domains/Domains.jsm"
);
const { Session } = ChromeUtils.import(
"chrome://remote/content/sessions/Session.jsm"
);
/**
* A session to communicate with a given tab
@ -36,7 +40,10 @@ class TabSession extends Session {
this.mm.addMessageListener("remote:result", this);
this.mm.addMessageListener("remote:error", this);
this.mm.loadFrameScript("chrome://remote/content/sessions/frame-script.js", false);
this.mm.loadFrameScript(
"chrome://remote/content/sessions/frame-script.js",
false
);
}
destructor() {
@ -51,7 +58,7 @@ class TabSession extends Session {
this.mm.removeMessageListener("remote:error", this);
}
async onMessage({id, method, params}) {
async onMessage({ id, method, params }) {
try {
if (typeof id == "undefined") {
throw new TypeError("Message missing 'id' field");
@ -60,7 +67,7 @@ class TabSession extends Session {
throw new TypeError("Message missing 'method' field");
}
const {domain, command} = Domains.splitMethod(method);
const { domain, command } = Domains.splitMethod(method);
if (this.domains.domainSupportsMethod(domain, command)) {
await this.execute(id, domain, command, params);
} else {
@ -74,7 +81,7 @@ class TabSession extends Session {
executeInChild(id, domain, command, params) {
this.mm.sendAsyncMessage("remote:request", {
browsingContextId: this.browsingContext.id,
request: {id, domain, command, params},
request: { id, domain, command, params },
});
}
@ -117,8 +124,8 @@ class TabSession extends Session {
// nsIMessageListener
receiveMessage({name, data}) {
const {id, result, event, error} = data;
receiveMessage({ name, data }) {
const { id, result, event, error } = data;
switch (name) {
case "remote:result":

View file

@ -4,8 +4,9 @@
"use strict";
const {ContentProcessSession} =
ChromeUtils.import("chrome://remote/content/sessions/ContentProcessSession.jsm");
const { ContentProcessSession } = ChromeUtils.import(
"chrome://remote/content/sessions/ContentProcessSession.jsm"
);
/* global content, docShell */
new ContentProcessSession(this, docShell.browsingContext, content, docShell);

View file

@ -6,11 +6,19 @@
var EXPORTED_SYMBOLS = ["MainProcessTarget"];
const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.jsm");
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
const { Target } = ChromeUtils.import(
"chrome://remote/content/targets/Target.jsm"
);
const { Session } = ChromeUtils.import(
"chrome://remote/content/sessions/Session.jsm"
);
const { RemoteAgent } = ChromeUtils.import(
"chrome://remote/content/RemoteAgent.jsm"
);
const UUIDGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
const UUIDGen = Cc["@mozilla.org/uuid-generator;1"].getService(
Ci.nsIUUIDGenerator
);
/**
* The main process Target.
@ -26,14 +34,16 @@ class MainProcessTarget extends Target {
super(targets, Session);
this.type = "browser";
this.id = UUIDGen.generateUUID().toString().slice(1, -1);
this.id = UUIDGen.generateUUID()
.toString()
.slice(1, -1);
// Define the HTTP path to query this target
this.path = `/devtools/browser/${this.id}`;
}
get wsDebuggerURL() {
const {host, port} = RemoteAgent;
const { host, port } = RemoteAgent;
return `ws://${host}:${port}${this.path}`;
}

View file

@ -6,14 +6,26 @@
var EXPORTED_SYMBOLS = ["TabTarget"];
const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {TabSession} = ChromeUtils.import("chrome://remote/content/sessions/TabSession.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
const { Target } = ChromeUtils.import(
"chrome://remote/content/targets/Target.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { TabSession } = ChromeUtils.import(
"chrome://remote/content/sessions/TabSession.jsm"
);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { RemoteAgent } = ChromeUtils.import(
"chrome://remote/content/RemoteAgent.jsm"
);
XPCOMUtils.defineLazyServiceGetter(this, "Favicons",
"@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
XPCOMUtils.defineLazyServiceGetter(
this,
"Favicons",
"@mozilla.org/browser/favicon-service;1",
"nsIFaviconService"
);
/**
* Target for a local tab or a remoted frame.
@ -110,7 +122,7 @@ class TabTarget extends Target {
}
get wsDebuggerURL() {
const {host, port} = RemoteAgent;
const { host, port } = RemoteAgent;
return `ws://${host}:${port}${this.path}`;
}
@ -147,9 +159,6 @@ class TabTarget extends Target {
// XPCOM
get QueryInterface() {
return ChromeUtils.generateQI([
Ci.nsIHttpRequestHandler,
Ci.nsIObserver,
]);
return ChromeUtils.generateQI([Ci.nsIHttpRequestHandler, Ci.nsIObserver]);
}
}

View file

@ -6,9 +6,15 @@
var EXPORTED_SYMBOLS = ["Target"];
const {Connection} = ChromeUtils.import("chrome://remote/content/Connection.jsm");
const {WebSocketDebuggerTransport} = ChromeUtils.import("chrome://remote/content/server/WebSocketTransport.jsm");
const {WebSocketServer} = ChromeUtils.import("chrome://remote/content/server/WebSocket.jsm");
const { Connection } = ChromeUtils.import(
"chrome://remote/content/Connection.jsm"
);
const { WebSocketDebuggerTransport } = ChromeUtils.import(
"chrome://remote/content/server/WebSocketTransport.jsm"
);
const { WebSocketServer } = ChromeUtils.import(
"chrome://remote/content/server/WebSocket.jsm"
);
/**
* Base class for all the Targets.
@ -45,8 +51,6 @@ class Target {
// XPCOM
get QueryInterface() {
return ChromeUtils.generateQI([
Ci.nsIHttpRequestHandler,
]);
return ChromeUtils.generateQI([Ci.nsIHttpRequestHandler]);
}
}

View file

@ -6,10 +6,18 @@
var EXPORTED_SYMBOLS = ["Targets"];
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
const {MessagePromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
const {TabTarget} = ChromeUtils.import("chrome://remote/content/targets/TabTarget.jsm");
const {MainProcessTarget} = ChromeUtils.import("chrome://remote/content/targets/MainProcessTarget.jsm");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const { MessagePromise } = ChromeUtils.import(
"chrome://remote/content/Sync.jsm"
);
const { TabTarget } = ChromeUtils.import(
"chrome://remote/content/targets/TabTarget.jsm"
);
const { MainProcessTarget } = ChromeUtils.import(
"chrome://remote/content/targets/MainProcessTarget.jsm"
);
class Targets {
constructor() {
@ -91,7 +99,7 @@ class Targets {
return this.mainProcessTarget;
}
* [Symbol.iterator]() {
*[Symbol.iterator]() {
for (const target of this._targets.values()) {
yield target;
}

View file

@ -28,22 +28,32 @@ add_task(async function testCDP() {
});
ok(true, "CDP client has been instantiated");
const {Browser, Log, Page} = client;
const { Browser, Log, Page } = client;
ok("Browser" in client, "Browser domain is available");
ok("Log" in client, "Log domain is available");
ok("Page" in client, "Page domain is available");
const version = await Browser.getVersion();
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
is(version.product, isHeadless ? "Headless Firefox" : "Firefox", "Browser.getVersion works and depends on headless mode");
is(version.userAgent, window.navigator.userAgent, "Browser.getVersion().userAgent is correct");
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(
Ci.nsIGfxInfo
);
is(
version.product,
isHeadless ? "Headless Firefox" : "Firefox",
"Browser.getVersion works and depends on headless mode"
);
is(
version.userAgent,
window.navigator.userAgent,
"Browser.getVersion().userAgent is correct"
);
// receive console.log messages and print them
Log.enable();
ok(true, "Log domain has been enabled");
Log.entryAdded(({entry}) => {
const {timestamp, level, text, args} = entry;
Log.entryAdded(({ entry }) => {
const { timestamp, level, text, args } = entry;
const msg = text || args.join(" ");
console.log(`${new Date(timestamp)}\t${level.toUpperCase()}\t${msg}`);
});
@ -55,7 +65,10 @@ add_task(async function testCDP() {
const frameStoppedLoading = Page.frameStoppedLoading();
const navigatedWithinDocument = Page.navigatedWithinDocument();
const loadEventFired = Page.loadEventFired();
await Page.navigate({url: "data:text/html;charset=utf-8,test-page<script>console.log('foo');</script><script>'</script>"});
await Page.navigate({
url:
"data:text/html;charset=utf-8,test-page<script>console.log('foo');</script><script>'</script>",
});
ok(true, "A new page has been loaded");
await loadEventFired;

View file

@ -9,13 +9,13 @@ const TEST_URI = "data:text/html;charset=utf-8,<input type=text>";
// Map of key codes used in this test.
const KEYCODES = {
"a": 65,
"Backspace": 8,
"h": 72,
"H": 72,
"AltLeft": 18,
"ArrowLeft": 37,
"ArrowRight": 39,
a: 65,
Backspace: 8,
h: 72,
H: 72,
AltLeft: 18,
ArrowLeft: 37,
ArrowRight: 39,
};
// Modifier for move forward shortcut is CTRL+RightArrow on Linux/Windows, ALT+RightArrow
@ -72,7 +72,6 @@ add_task(async function() {
await sendArrowKey(Input, "ArrowLeft");
await checkInputContent("hH", 2);
info("Write 'a'");
await sendTextKey(Input, "a");
await checkInputContent("hHa", 3);
@ -144,15 +143,25 @@ function dispatchKeyEvent(Input, key, type, modifiers = 0) {
}
async function checkInputContent(expectedValue, expectedCaret) {
const { value, caret } =
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
const { value, caret } = await ContentTask.spawn(
gBrowser.selectedBrowser,
null,
function() {
const input = content.document.querySelector("input");
return { value: input.value, caret: input.selectionStart };
});
}
);
is(value, expectedValue, `The input value is correct ("${value}"="${expectedValue}")`);
is(caret, expectedCaret,
`The input caret has the correct index ("${caret}"="${expectedCaret}")`);
is(
value,
expectedValue,
`The input value is correct ("${value}"="${expectedValue}")`
);
is(
caret,
expectedCaret,
`The input caret has the correct index ("${caret}"="${expectedCaret}")`
);
}
async function sendBackspace(Input, expected) {
@ -182,16 +191,25 @@ async function sendBackspace(Input, expected) {
* await waitForInputEvent();
*/
function addInputEventListener(eventName) {
return ContentTask.spawn(gBrowser.selectedBrowser, eventName, async (_eventName) => {
return ContentTask.spawn(
gBrowser.selectedBrowser,
eventName,
async _eventName => {
const input = content.document.querySelector("input");
this.__onInputEvent =
new Promise(r => input.addEventListener(_eventName, r, { once: true }));
});
this.__onInputEvent = new Promise(r =>
input.addEventListener(_eventName, r, { once: true })
);
}
);
}
/**
* See documentation for addInputEventListener.
*/
function waitForInputEvent() {
return ContentTask.spawn(gBrowser.selectedBrowser, null, () => this.__onInputEvent);
return ContentTask.spawn(
gBrowser.selectedBrowser,
null,
() => this.__onInputEvent
);
}

View file

@ -12,26 +12,31 @@ add_task(async function() {
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
const { mainProcessTarget } = RemoteAgent.targets;
ok(mainProcessTarget,
"The main process target is instantiated after the call to `listen`");
ok(
mainProcessTarget,
"The main process target is instantiated after the call to `listen`"
);
const targetURL = mainProcessTarget.wsDebuggerURL;
const CDP = await getCDP();
const client = await CDP({"target": targetURL});
const client = await CDP({ target: targetURL });
ok(true, "CDP client has been instantiated");
const {Browser, Target} = client;
const { Browser, Target } = client;
ok(Browser, "The main process target exposes Browser domain");
ok(Target, "The main process target exposes Target domain");
const version = await Browser.getVersion();
is(version.product, "Firefox", "Browser.getVersion works");
const {webSocketDebuggerUrl} = await CDP.Version();
is(webSocketDebuggerUrl, targetURL,
"Version endpoint refers to the same Main process target");
const { webSocketDebuggerUrl } = await CDP.Version();
is(
webSocketDebuggerUrl,
targetURL,
"Version endpoint refers to the same Main process target"
);
await RemoteAgent.close();
});

View file

@ -6,13 +6,15 @@
// Test the Network.requestWillBeSent event
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
const PAGE_URI = "http://example.com/browser/remote/test/browser/doc_network_requestWillBeSent.html";
const JS_URI = "http://example.com/browser/remote/test/browser/file_network_requestWillBeSent.js";
const PAGE_URI =
"http://example.com/browser/remote/test/browser/doc_network_requestWillBeSent.html";
const JS_URI =
"http://example.com/browser/remote/test/browser/file_network_requestWillBeSent.js";
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const {Page, Network} = client;
const { Page, Network } = client;
await Network.enable();
ok(true, "Network domain has been enabled");
@ -25,7 +27,11 @@ add_task(async function() {
case 1:
is(event.request.url, PAGE_URI, "Got the page request");
is(event.type, "Document", "The page request has 'Document' type");
is(event.requestId, event.loaderId, "The page request has requestId = loaderId (puppeteer assumes that to detect the page start request)");
is(
event.requestId,
event.loaderId,
"The page request has requestId = loaderId (puppeteer assumes that to detect the page start request)"
);
break;
case 2:
is(event.request.url, JS_URI, "Got the JS request");

View file

@ -11,11 +11,16 @@ add_task(async function testBringToFrontUpdatesSelectedTab() {
is(gBrowser.selectedTab, tab, "Selected tab is the target tab");
info("Open another tab that should become the front tab");
const otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, OTHER_URI);
const otherTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
OTHER_URI
);
is(gBrowser.selectedTab, otherTab, "Selected tab is now the new tab");
const { Page } = client;
info("Call Page.bringToFront() and check that the test tab becomes the selected tab");
info(
"Call Page.bringToFront() and check that the test tab becomes the selected tab"
);
await Page.bringToFront();
is(gBrowser.selectedTab, tab, "Selected tab is the target tab again");
is(tab.ownerGlobal, getFocusedNavigator(), "The initial window is focused");
@ -39,9 +44,15 @@ add_task(async function testBringToFrontUpdatesFocusedWindow() {
is(otherWindow, getFocusedNavigator(), "The new window is focused");
const { Page } = client;
info("Call Page.bringToFront() and check that the tab window is focused again");
info(
"Call Page.bringToFront() and check that the tab window is focused again"
);
await Page.bringToFront();
is(tab.ownerGlobal, getFocusedNavigator(), "The initial window is focused again");
is(
tab.ownerGlobal,
getFocusedNavigator(),
"The initial window is focused again"
);
await client.close();
ok(true, "The client is closed");

View file

@ -11,9 +11,9 @@ const promises = new Set();
const resolutions = new Map();
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const {Page} = client;
const { Page } = client;
// turn on navigation related events, such as DOMContentLoaded et al.
await Page.enable();
@ -45,13 +45,17 @@ add_task(async function() {
info("Test Page.navigate");
recordPromises();
const url = "http://example.com/browser/remote/test/browser/doc_page_frameNavigated.html";
const url =
"http://example.com/browser/remote/test/browser/doc_page_frameNavigated.html";
const { frameId } = await Page.navigate({ url });
ok(true, "A new page has been loaded");
ok(frameId, "Page.navigate returned a frameId");
is(frameId, frameTree.frame.id, "The Page.navigate's frameId is the same than " +
"getFrameTree's one");
is(
frameId,
frameTree.frame.id,
"The Page.navigate's frameId is the same than " + "getFrameTree's one"
);
await assertNavigationEvents({ url, frameId });
@ -68,7 +72,11 @@ add_task(async function() {
const randomId2 = await getTestTabRandomId();
ok(!!randomId2, "Test tab has a valid randomId");
isnot(randomId2, randomId1, "Test tab randomId has been updated after reload");
isnot(
randomId2,
randomId1,
"Test tab randomId has been updated after reload"
);
info("Test Page.navigate with the same URL still reloads the current page");
recordPromises();
@ -80,7 +88,11 @@ add_task(async function() {
const randomId3 = await getTestTabRandomId();
ok(!!randomId3, "Test tab has a valid randomId");
isnot(randomId3, randomId2, "Test tab randomId has been updated after reload");
isnot(
randomId3,
randomId2,
"Test tab randomId has been updated after reload"
);
await client.close();
ok(true, "The client is closed");
@ -102,25 +114,44 @@ async function assertNavigationEvents({ url, frameId }) {
"navigatedWithinDocument",
"frameStoppedLoading",
];
Assert.deepEqual([...resolutions.keys()],
Assert.deepEqual(
[...resolutions.keys()],
expectedResolutions,
"Received various Page navigation events in the expected order");
"Received various Page navigation events in the expected order"
);
// Now assert the data exposed by each of these events
const frameNavigated = resolutions.get("frameNavigated");
ok(!frameNavigated.frame.parentId, "frameNavigated is for the top level document and" +
" has a null parentId");
ok(
!frameNavigated.frame.parentId,
"frameNavigated is for the top level document and" + " has a null parentId"
);
is(frameNavigated.frame.id, frameId, "frameNavigated id is the right one");
is(frameNavigated.frame.name, undefined, "frameNavigated name isn't implemented yet");
is(
frameNavigated.frame.name,
undefined,
"frameNavigated name isn't implemented yet"
);
is(frameNavigated.frame.url, url, "frameNavigated url is the right one");
const navigatedWithinDocument = resolutions.get("navigatedWithinDocument");
is(navigatedWithinDocument.frameId, frameId, "navigatedWithinDocument frameId is " +
"the same one");
is(navigatedWithinDocument.url, url, "navigatedWithinDocument url is the same one");
is(
navigatedWithinDocument.frameId,
frameId,
"navigatedWithinDocument frameId is " + "the same one"
);
is(
navigatedWithinDocument.url,
url,
"navigatedWithinDocument url is the same one"
);
const frameStoppedLoading = resolutions.get("frameStoppedLoading");
is(frameStoppedLoading.frameId, frameId, "frameStoppedLoading frameId is the same one");
is(
frameStoppedLoading.frameId,
frameId,
"frameStoppedLoading frameId is the same one"
);
promises.clear();
resolutions.clear();

View file

@ -10,8 +10,8 @@
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
add_task(async function testCDP() {
const {client} = await setupTestForUri(TEST_URI);
const {Page, Runtime} = client;
const { client } = await setupTestForUri(TEST_URI);
const { Page, Runtime } = client;
const events = [];
function assertReceivedEvents(expected, message) {
@ -43,14 +43,21 @@ add_task(async function testCDP() {
ok(context.auxData.isDefault, "The execution context is the default one");
ok(!!context.auxData.frameId, "The execution context has a frame id set");
assertReceivedEvents(["executionContextCreated"], "Received only executionContextCreated event after Runtime.enable call");
assertReceivedEvents(
["executionContextCreated"],
"Received only executionContextCreated event after Runtime.enable call"
);
const { frameTree } = await Page.getFrameTree();
ok(!!frameTree.frame, "getFrameTree exposes one frame");
is(frameTree.childFrames.length, 0, "getFrameTree reports no child frame");
ok(!!frameTree.frame.id, "getFrameTree's frame has an id");
is(frameTree.frame.url, TEST_URI, "getFrameTree's frame has the right url");
is(frameTree.frame.id, context.auxData.frameId, "getFrameTree and executionContextCreated refers about the same frame Id");
is(
frameTree.frame.id,
context.auxData.frameId,
"getFrameTree and executionContextCreated refers about the same frame Id"
);
const onFrameNavigated = Page.frameNavigated();
const onExecutionContextDestroyed = Runtime.executionContextDestroyed();
@ -59,33 +66,61 @@ add_task(async function testCDP() {
const { frameId } = await Page.navigate({ url });
ok(true, "A new page has been loaded");
ok(frameId, "Page.navigate returned a frameId");
is(frameId, frameTree.frame.id, "The Page.navigate's frameId is the same than " +
"getFrameTree's one");
is(
frameId,
frameTree.frame.id,
"The Page.navigate's frameId is the same than " + "getFrameTree's one"
);
const frameNavigated = await onFrameNavigated;
ok(!frameNavigated.frame.parentId, "frameNavigated is for the top level document and" +
" has a null parentId");
is(frameNavigated.frame.id, frameId, "frameNavigated id is the same than the one " +
"returned by Page.navigate");
is(frameNavigated.frame.name, undefined, "frameNavigated name isn't implemented yet");
is(frameNavigated.frame.url, url, "frameNavigated url is the same being given to " +
"Page.navigate");
ok(
!frameNavigated.frame.parentId,
"frameNavigated is for the top level document and" + " has a null parentId"
);
is(
frameNavigated.frame.id,
frameId,
"frameNavigated id is the same than the one " + "returned by Page.navigate"
);
is(
frameNavigated.frame.name,
undefined,
"frameNavigated name isn't implemented yet"
);
is(
frameNavigated.frame.url,
url,
"frameNavigated url is the same being given to " + "Page.navigate"
);
const { executionContextId } = await onExecutionContextDestroyed;
ok(executionContextId, "The destroyed event reports an id");
is(executionContextId, context.id, "The destroyed event is for the first reported execution context");
is(
executionContextId,
context.id,
"The destroyed event is for the first reported execution context"
);
({ context } = await onExecutionContextCreated2);
ok(!!context.id, "The execution context has an id");
ok(context.auxData.isDefault, "The execution context is the default one");
is(context.auxData.frameId, frameId, "The execution context frame id is the same " +
"the one returned by Page.navigate");
is(
context.auxData.frameId,
frameId,
"The execution context frame id is the same " +
"the one returned by Page.navigate"
);
isnot(executionContextId, context.id, "The destroyed id is different from the " +
"created one");
isnot(
executionContextId,
context.id,
"The destroyed id is different from the " + "created one"
);
assertReceivedEvents(["executionContextDestroyed", "frameNavigated", "executionContextCreated"],
"Received frameNavigated between the two execution context events during navigation to another URL");
assertReceivedEvents(
["executionContextDestroyed", "frameNavigated", "executionContextCreated"],
"Received frameNavigated between the two execution context events during navigation to another URL"
);
await client.close();
ok(true, "The client is closed");

View file

@ -9,7 +9,7 @@
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const firstContext = await testRuntimeEnable(client);
const contextId = firstContext.id;
@ -43,7 +43,10 @@ async function testRuntimeEnable({ Runtime }) {
async function testObjectReferences({ Runtime }, contextId) {
// First create a JS object remotely via Runtime.evaluate
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 1 })" });
const { result } = await Runtime.evaluate({
contextId,
expression: "({ foo: 1 })",
});
is(result.type, "object", "The type is correct");
is(result.subtype, null, "The subtype is null for objects");
ok(!!result.objectId, "Got an object id");
@ -57,7 +60,11 @@ async function testObjectReferences({ Runtime }, contextId) {
});
is(result2.type, "number", "The type is correct");
is(result2.subtype, null, "The subtype is null for numbers");
is(result2.value, 2, "Updated the existing object and returned the incremented value");
is(
result2.value,
2,
"Updated the existing object and returned the incremented value"
);
// Finally, try to pass this JS object and get it back. Ensure that it returns
// the same object id. Also increment the attribute again.
@ -83,7 +90,11 @@ async function testObjectReferences({ Runtime }, contextId) {
});
is(result4.type, "number", "The type is correct");
is(result4.subtype, null, "The subtype is null for numbers");
is(result4.value, 3, "Updated the existing object and returned the incremented value");
is(
result4.value,
3,
"Updated the existing object and returned the incremented value"
);
}
async function testExceptions({ Runtime }, executionContextId) {
@ -92,28 +103,36 @@ async function testExceptions({ Runtime }, executionContextId) {
executionContextId,
functionDeclaration: "doesNotExists()",
});
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
is(
exceptionDetails.text,
"doesNotExists is not defined",
"Exception message is passed to the client"
);
// Test error when calling the function
({ exceptionDetails } = await Runtime.callFunctionOn({
executionContextId,
functionDeclaration: "() => doesNotExists()",
}));
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
is(
exceptionDetails.text,
"doesNotExists is not defined",
"Exception message is passed to the client"
);
}
async function testReturnByValue({ Runtime }, executionContextId) {
const values = [
42,
"42",
42.00,
42.0,
true,
false,
null,
{ foo: true },
{ foo: { bar: 42, str: "str", array: [1, 2, 3] } },
[ 42, "42", true ],
[ { foo: true } ],
[42, "42", true],
[{ foo: true }],
];
for (const value of values) {
const { result } = await Runtime.callFunctionOn({
@ -121,7 +140,11 @@ async function testReturnByValue({ Runtime }, executionContextId) {
functionDeclaration: "() => (" + JSON.stringify(value) + ")",
returnByValue: true,
});
Assert.deepEqual(result.value, value, "The returned value is the same than the input value");
Assert.deepEqual(
result.value,
value,
"The returned value is the same than the input value"
);
}
// Test undefined individually as JSON.stringify doesn't return a string
@ -150,7 +173,11 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
functionDeclaration: "() => Promise.reject(42)",
awaitPromise: true,
});
is(exceptionDetails.exception.value, 42, "The result is the promise's rejection");
is(
exceptionDetails.exception.value,
42,
"The result is the promise's rejection"
);
// Then check delayed promise resolution
({ result } = await Runtime.callFunctionOn({
@ -165,10 +192,15 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
// And delayed promise rejection
({ exceptionDetails } = await Runtime.callFunctionOn({
executionContextId,
functionDeclaration: "() => new Promise((_,r) => setTimeout(() => r(42), 0))",
functionDeclaration:
"() => new Promise((_,r) => setTimeout(() => r(42), 0))",
awaitPromise: true,
}));
is(exceptionDetails.exception.value, 42, "The result is the promise's rejection");
is(
exceptionDetails.exception.value,
42,
"The result is the promise's rejection"
);
// Finally assert promise resolution without awaitPromise
({ result } = await Runtime.callFunctionOn({
@ -195,7 +227,10 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
async function testObjectId({ Runtime }, contextId) {
// First create an object via Runtime.evaluate
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
const { result } = await Runtime.evaluate({
contextId,
expression: "({ foo: 42 })",
});
is(result.type, "object", "The type is correct");
is(result.subtype, null, "The subtype is null for objects");
ok(!!result.objectId, "Got an object id");
@ -208,5 +243,9 @@ async function testObjectId({ Runtime }, contextId) {
});
is(result2.type, "number", "The type is correct");
is(result2.subtype, null, "The subtype is null for numbers");
is(result2.value, 42, "We have a good proof that the function was ran against the target object");
is(
result2.value,
42,
"We have a good proof that the function was ran against the target object"
);
}

View file

@ -76,7 +76,11 @@ add_task(async function() {
});
}
for (const fun of [runtimeEvaluate, callFunctionOn, callFunctionOnArguments]) {
for (const fun of [
runtimeEvaluate,
callFunctionOn,
callFunctionOnArguments,
]) {
info("Test " + fun.name);
await testPrimitiveTypes(fun);
await testUnserializable(fun);
@ -114,8 +118,15 @@ async function testRuntimeEnable({ Runtime }) {
}
async function testEvaluate({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: "location.href" });
is(result.value, TEST_URI, "Runtime.evaluate works and is against the test page");
const { result } = await Runtime.evaluate({
contextId,
expression: "location.href",
});
is(
result.value,
TEST_URI,
"Runtime.evaluate works and is against the test page"
);
}
async function testEvaluateInvalidContextId({ Runtime }, contextId) {
@ -123,23 +134,40 @@ async function testEvaluateInvalidContextId({ Runtime }, contextId) {
await Runtime.evaluate({ contextId: -1, expression: "" });
ok(false, "Evaluate shouldn't pass");
} catch (e) {
ok(e.message.includes("Unable to find execution context with id: -1"),
"Throws with the expected error message");
ok(
e.message.includes("Unable to find execution context with id: -1"),
"Throws with the expected error message"
);
}
}
async function testCallFunctionOn({ Runtime }, executionContextId) {
const { result } = await Runtime.callFunctionOn({ executionContextId, functionDeclaration: "() => location.href" });
is(result.value, TEST_URI, "Runtime.callFunctionOn works and is against the test page");
const { result } = await Runtime.callFunctionOn({
executionContextId,
functionDeclaration: "() => location.href",
});
is(
result.value,
TEST_URI,
"Runtime.callFunctionOn works and is against the test page"
);
}
async function testCallFunctionOnInvalidContextId({ Runtime }, executionContextId) {
async function testCallFunctionOnInvalidContextId(
{ Runtime },
executionContextId
) {
try {
await Runtime.callFunctionOn({ executionContextId: -1, functionDeclaration: "" });
await Runtime.callFunctionOn({
executionContextId: -1,
functionDeclaration: "",
});
ok(false, "callFunctionOn shouldn't pass");
} catch (e) {
ok(e.message.includes("Unable to find execution context with id: -1"),
"Throws with the expected error message");
ok(
e.message.includes("Unable to find execution context with id: -1"),
"Throws with the expected error message"
);
}
}
@ -148,7 +176,7 @@ async function testPrimitiveTypes(testFunction) {
for (const expression of expressions) {
const { result } = await testFunction(JSON.stringify(expression));
is(result.value, expression, `Evaluating primitive '${expression}' works`);
is(result.type, typeof(expression), `${expression} type is correct`);
is(result.type, typeof expression, `${expression} type is correct`);
}
// undefined doesn't work with JSON.stringify, so test it independently
@ -169,7 +197,11 @@ async function testUnserializable(testFunction) {
const expressions = ["NaN", "-0", "Infinity", "-Infinity"];
for (const expression of expressions) {
const { result } = await testFunction(expression);
is(result.unserializableValue, expression, `Evaluating unserializable '${expression}' works`);
is(
result.unserializableValue,
expression,
`Evaluating unserializable '${expression}' works`
);
}
}
@ -190,29 +222,48 @@ async function testObjectTypes(testFunction) {
{ expression: "new Date()", type: "object", subtype: "date" },
{ expression: "document", type: "object", subtype: "node" },
{ expression: "document.documentElement", type: "object", subtype: "node" },
{ expression: "document.createElement('div')", type: "object", subtype: "node" },
{
expression: "document.createElement('div')",
type: "object",
subtype: "node",
},
];
for (const { expression, type, subtype } of expressions) {
const { result } = await testFunction(expression);
is(result.subtype, subtype, `Evaluating '${expression}' has the expected subtype`);
is(
result.subtype,
subtype,
`Evaluating '${expression}' has the expected subtype`
);
is(result.type, type, "The type is correct");
ok(!!result.objectId, "Got an object id");
}
}
async function testThrowError(testFunction) {
const { exceptionDetails } = await testFunction("throw new Error('foo')", true);
const { exceptionDetails } = await testFunction(
"throw new Error('foo')",
true
);
is(exceptionDetails.text, "foo", "Exception message is passed to the client");
}
async function testThrowValue(testFunction) {
const { exceptionDetails } = await testFunction("throw 'foo'", true);
is(exceptionDetails.exception.type, "string", "Exception type is correct");
is(exceptionDetails.exception.value, "foo", "Exception value is passed as a RemoteObject");
is(
exceptionDetails.exception.value,
"foo",
"Exception value is passed as a RemoteObject"
);
}
async function testJSError(testFunction) {
const { exceptionDetails } = await testFunction("doesNotExists()", true);
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
is(
exceptionDetails.text,
"doesNotExists is not defined",
"Exception message is passed to the client"
);
}

View file

@ -8,7 +8,7 @@
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const firstContext = await testRuntimeEnable(client);
await testEvaluate(client, firstContext);
@ -42,8 +42,15 @@ async function testRuntimeEnable({ Runtime }) {
async function testEvaluate({ Runtime }, previousContext) {
const contextId = previousContext.id;
const { result } = await Runtime.evaluate({ contextId, expression: "location.href" });
is(result.value, TEST_URI, "Runtime.evaluate works and is against the test page");
const { result } = await Runtime.evaluate({
contextId,
expression: "location.href",
});
is(
result.value,
TEST_URI,
"Runtime.evaluate works and is against the test page"
);
}
async function testNavigate({ Runtime, Page }, previousContext) {
@ -55,20 +62,39 @@ async function testNavigate({ Runtime, Page }, previousContext) {
const url = "data:text/html;charset=utf-8,test-page";
const { frameId } = await Page.navigate({ url });
ok(true, "A new page has been loaded");
is(frameId, previousContext.auxData.frameId, "Page.navigate returns the same frameId than executionContextCreated");
is(
frameId,
previousContext.auxData.frameId,
"Page.navigate returns the same frameId than executionContextCreated"
);
const { executionContextId } = await executionContextDestroyed;
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
is(
executionContextId,
previousContext.id,
"The destroyed event reports the previous context id"
);
const { context } = await executionContextCreated;
ok(!!context.id, "The execution context has an id");
isnot(previousContext.id, context.id, "The new execution context has a different id");
isnot(
previousContext.id,
context.id,
"The new execution context has a different id"
);
ok(context.auxData.isDefault, "The execution context is the default one");
is(context.auxData.frameId, frameId, "The execution context frame id is the same " +
"than the one returned by Page.navigate");
is(
context.auxData.frameId,
frameId,
"The execution context frame id is the same " +
"than the one returned by Page.navigate"
);
isnot(executionContextId, context.id, "The destroyed id is different from the " +
"created one");
isnot(
executionContextId,
context.id,
"The destroyed id is different from the " + "created one"
);
return context;
}
@ -85,15 +111,34 @@ async function testNavigateBack({ Runtime }, firstContext, previousContext) {
gBrowser.selectedBrowser.goBack();
const { context } = await executionContextCreated;
is(context.id, firstContext.id, "The new execution context should be the same than the first one");
is(
context.id,
firstContext.id,
"The new execution context should be the same than the first one"
);
ok(context.auxData.isDefault, "The execution context is the default one");
is(context.auxData.frameId, firstContext.auxData.frameId, "The execution context frame id is always the same");
is(
context.auxData.frameId,
firstContext.auxData.frameId,
"The execution context frame id is always the same"
);
const { executionContextId } = await executionContextDestroyed;
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
is(
executionContextId,
previousContext.id,
"The destroyed event reports the previous context id"
);
const { result } = await Runtime.evaluate({ contextId: context.id, expression: "location.href" });
is(result.value, TEST_URI, "Runtime.evaluate works and is against the page we just navigated to");
const { result } = await Runtime.evaluate({
contextId: context.id,
expression: "location.href",
});
is(
result.value,
TEST_URI,
"Runtime.evaluate works and is against the page we just navigated to"
);
}
async function testNavigateViaLocation({ Runtime }, previousContext) {
@ -103,19 +148,33 @@ async function testNavigateViaLocation({ Runtime }, previousContext) {
const executionContextCreated = Runtime.executionContextCreated();
const url2 = "data:text/html;charset=utf-8,test-page-2";
await Runtime.evaluate({ contextId: previousContext.id, expression: `window.location = '${url2}';` });
await Runtime.evaluate({
contextId: previousContext.id,
expression: `window.location = '${url2}';`,
});
const { executionContextId } = await executionContextDestroyed;
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
is(
executionContextId,
previousContext.id,
"The destroyed event reports the previous context id"
);
const { context } = await executionContextCreated;
ok(!!context.id, "The execution context has an id");
ok(context.auxData.isDefault, "The execution context is the default one");
is(context.auxData.frameId, previousContext.auxData.frameId, "The execution context frame id is the same " +
"the one returned by Page.navigate");
is(
context.auxData.frameId,
previousContext.auxData.frameId,
"The execution context frame id is the same " +
"the one returned by Page.navigate"
);
isnot(executionContextId, context.id, "The destroyed id is different from the " +
"created one");
isnot(
executionContextId,
context.id,
"The destroyed id is different from the " + "created one"
);
return context;
}
@ -129,14 +188,24 @@ async function testReload({ Runtime, Page }, previousContext) {
await Page.reload();
const { executionContextId } = await executionContextDestroyed;
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
is(
executionContextId,
previousContext.id,
"The destroyed event reports the previous context id"
);
const { context } = await executionContextCreated;
ok(!!context.id, "The execution context has an id");
ok(context.auxData.isDefault, "The execution context is the default one");
is(context.auxData.frameId, previousContext.auxData.frameId, "The execution context " +
"frame id is the same one");
is(
context.auxData.frameId,
previousContext.auxData.frameId,
"The execution context " + "frame id is the same one"
);
isnot(executionContextId, context.id, "The destroyed id is different from the " +
"created one");
isnot(
executionContextId,
context.id,
"The destroyed id is different from the " + "created one"
);
}

View file

@ -8,7 +8,7 @@
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const firstContext = await testRuntimeEnable(client);
const contextId = firstContext.id;
@ -41,13 +41,23 @@ async function testRuntimeEnable({ Runtime }) {
}
async function testGetOwnSimpleProperties({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: "({ bool: true, fun() {}, int: 1, object: {}, string: 'foo' })" });
const { result } = await Runtime.evaluate({
contextId,
expression: "({ bool: true, fun() {}, int: 1, object: {}, string: 'foo' })",
});
is(result.subtype, null, "JS Object have no subtype");
is(result.type, "object", "The type is correct");
ok(!!result.objectId, "Got an object id");
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
is(result2.length, 5, "ownProperties=true allows to iterate only over direct object properties (i.e. ignore prototype)");
const { result: result2 } = await Runtime.getProperties({
objectId: result.objectId,
ownProperties: true,
});
is(
result2.length,
5,
"ownProperties=true allows to iterate only over direct object properties (i.e. ignore prototype)"
);
result2.sort((a, b) => a.name > b.name);
is(result2[0].name, "bool");
is(result2[0].configurable, true);
@ -91,35 +101,55 @@ async function testGetOwnSimpleProperties({ Runtime }, contextId) {
}
async function testGetPrototypeProperties({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
const { result } = await Runtime.evaluate({
contextId,
expression: "({ foo: 42 })",
});
is(result.subtype, null, "JS Object have no subtype");
is(result.type, "object", "The type is correct");
ok(!!result.objectId, "Got an object id");
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: false });
const { result: result2 } = await Runtime.getProperties({
objectId: result.objectId,
ownProperties: false,
});
ok(result2.length > 1, "We have more properties than just the object one");
const foo = result2.find(p => p.name == "foo");
ok(foo, "The object property is described");
ok(foo.isOwn, "and is reported as 'own' property");
const toString = result2.find(p => p.name == "toString");
ok(toString, "Function from Object's prototype are also described like toString");
ok(
toString,
"Function from Object's prototype are also described like toString"
);
ok(!toString.isOwn, "but are reported as not being an 'own' property");
}
async function testGetGetterSetterProperties({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: "({ get prop() { return this.x; }, set prop(v) { this.x = v; } })" });
const { result } = await Runtime.evaluate({
contextId,
expression:
"({ get prop() { return this.x; }, set prop(v) { this.x = v; } })",
});
is(result.subtype, null, "JS Object have no subtype");
is(result.type, "object", "The type is correct");
ok(!!result.objectId, "Got an object id");
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
const { result: result2 } = await Runtime.getProperties({
objectId: result.objectId,
ownProperties: true,
});
is(result2.length, 1);
is(result2[0].name, "prop");
is(result2[0].configurable, true);
is(result2[0].enumerable, true);
is(result2[0].writable, undefined, "writable is only set for data properties");
is(
result2[0].writable,
undefined,
"writable is only set for data properties"
);
is(result2[0].get.type, "function");
ok(!!result2[0].get.objectId);
@ -131,7 +161,10 @@ async function testGetGetterSetterProperties({ Runtime }, contextId) {
const { result: result3 } = await Runtime.callFunctionOn({
executionContextId: contextId,
functionDeclaration: "(set, get) => { set(42); return get(); }",
arguments: [{ objectId: result2[0].set.objectId }, { objectId: result2[0].get.objectId }],
arguments: [
{ objectId: result2[0].set.objectId },
{ objectId: result2[0].get.objectId },
],
});
is(result3.type, "number", "The type is correct");
is(result3.subtype, null, "The subtype is null for numbers");
@ -139,12 +172,18 @@ async function testGetGetterSetterProperties({ Runtime }, contextId) {
}
async function testGetCustomProperty({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: `const obj = {}; Object.defineProperty(obj, "prop", { value: 42 }); obj` });
const { result } = await Runtime.evaluate({
contextId,
expression: `const obj = {}; Object.defineProperty(obj, "prop", { value: 42 }); obj`,
});
is(result.subtype, null, "JS Object have no subtype");
is(result.type, "object", "The type is correct");
ok(!!result.objectId, "Got an object id");
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
const { result: result2 } = await Runtime.getProperties({
objectId: result.objectId,
ownProperties: true,
});
is(result2.length, 1, "We only get the one object's property");
is(result2[0].name, "prop");
is(result2[0].configurable, false);

View file

@ -8,7 +8,7 @@
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
add_task(async function() {
const {client} = await setupTestForUri(TEST_URI);
const { client } = await setupTestForUri(TEST_URI);
const firstContext = await testRuntimeEnable(client);
const contextId = firstContext.id;
@ -38,7 +38,10 @@ async function testRuntimeEnable({ Runtime }) {
}
async function testObjectRelease({ Runtime }, contextId) {
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
const { result } = await Runtime.evaluate({
contextId,
expression: "({ foo: 42 })",
});
is(result.subtype, null, "JS Object have no subtype");
is(result.type, "object", "The type is correct");
ok(!!result.objectId, "Got an object id");
@ -71,7 +74,10 @@ async function testObjectRelease({ Runtime }, contextId) {
});
ok(false, "callFunctionOn with a released object as argument should throw");
} catch (e) {
ok(e.message.includes("Cannot find object with ID:"), "callFunctionOn throws on released argument");
ok(
e.message.includes("Cannot find object with ID:"),
"callFunctionOn throws on released argument"
);
}
try {
await Runtime.callFunctionOn({
@ -80,6 +86,9 @@ async function testObjectRelease({ Runtime }, contextId) {
});
ok(false, "callFunctionOn with a released object as target should throw");
} catch (e) {
ok(e.message.includes("Unable to get the context for object with id"), "callFunctionOn throws on released target");
ok(
e.message.includes("Unable to get the context for object with id"),
"callFunctionOn throws on released target"
);
}
}

View file

@ -6,8 +6,8 @@
add_task(async function() {
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
const CDP = await getCDP();
const {webSocketDebuggerUrl} = await CDP.Version();
const client = await CDP({"target": webSocketDebuggerUrl});
const { webSocketDebuggerUrl } = await CDP.Version();
const client = await CDP({ target: webSocketDebuggerUrl });
try {
await client.send("Hoobaflooba");

View file

@ -24,12 +24,18 @@ add_task(async function() {
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
let targets = await getTargets(CDP);
ok(targets.some(target => target.url == TEST_URI), "Found the tab in target list");
ok(
targets.some(target => target.url == TEST_URI),
"Found the tab in target list"
);
BrowserTestUtils.removeTab(tab);
targets = await getTargets(CDP);
ok(!targets.some(target => target.url == TEST_URI), "Tab has been removed from the target list");
ok(
!targets.some(target => target.url == TEST_URI),
"Tab has been removed from the target list"
);
await RemoteAgent.close();
});

View file

@ -13,18 +13,21 @@ add_task(async function() {
const CDP = await getCDP();
// Connect to the server
const {webSocketDebuggerUrl} = await CDP.Version();
const client = await CDP({"target": webSocketDebuggerUrl});
const { webSocketDebuggerUrl } = await CDP.Version();
const client = await CDP({ target: webSocketDebuggerUrl });
ok(true, "CDP client has been instantiated");
const {Target} = client;
const { Target } = client;
ok("Target" in client, "Target domain is available");
const onTargetsCreated = new Promise(resolve => {
let gotTabTarget = false, gotMainTarget = false;
let gotTabTarget = false,
gotMainTarget = false;
const unsubscribe = Target.targetCreated(event => {
if (event.targetInfo.type == "page" &&
event.targetInfo.url == gBrowser.selectedBrowser.currentURI.spec) {
if (
event.targetInfo.type == "page" &&
event.targetInfo.url == gBrowser.selectedBrowser.currentURI.spec
) {
info("Got the current tab target");
gotTabTarget = true;
}
@ -48,21 +51,33 @@ add_task(async function() {
// Create a new target so that the test runs against a fresh new tab
const targetCreated = Target.targetCreated();
const {targetId} = await Target.createTarget();
const { targetId } = await Target.createTarget();
ok(true, `Target created: ${targetId}`);
ok(!!targetId, "createTarget returns a non-empty target id");
const {targetInfo} = await targetCreated;
is(targetId, targetInfo.targetId, "createTarget and targetCreated refers to the same target id");
const { targetInfo } = await targetCreated;
is(
targetId,
targetInfo.targetId,
"createTarget and targetCreated refers to the same target id"
);
is(targetInfo.type, "page", "The target is a page");
const attachedToTarget = Target.attachedToTarget();
const {sessionId} = await Target.attachToTarget({ targetId });
const { sessionId } = await Target.attachToTarget({ targetId });
ok(true, "Target attached");
const attachedEvent = await attachedToTarget;
ok(true, "Received Target.attachToTarget event");
is(attachedEvent.sessionId, sessionId, "attachedToTarget and attachToTarget returns the same session id");
is(attachedEvent.targetInfo.type, "page", "attachedToTarget creates a tab by default");
is(
attachedEvent.sessionId,
sessionId,
"attachedToTarget and attachToTarget returns the same session id"
);
is(
attachedEvent.targetInfo.type,
"page",
"attachedToTarget creates a tab by default"
);
const onResponse = Target.receivedMessageFromTarget();
const id = 1;
@ -78,7 +93,10 @@ add_task(async function() {
is(response.sessionId, sessionId, "The response is from the same session");
const responseMessage = JSON.parse(response.message);
is(responseMessage.id, id, "The response is from the same session");
ok(!!responseMessage.result.frameId, "received the `frameId` out of `Page.navigate` request");
ok(
!!responseMessage.result.frameId,
"received the `frameId` out of `Page.navigate` request"
);
await client.close();
ok(true, "The client is closed");

View file

@ -13,11 +13,11 @@ add_task(async function() {
const CDP = await getCDP();
// Connect to the server
const {webSocketDebuggerUrl} = await CDP.Version();
const client = await CDP({"target": webSocketDebuggerUrl});
const { webSocketDebuggerUrl } = await CDP.Version();
const client = await CDP({ target: webSocketDebuggerUrl });
ok(true, "CDP client has been instantiated");
const {Target} = client;
const { Target } = client;
ok("Target" in client, "Target domain is available");
// Wait for all Target.targetCreated event. One for each tab, plus the one
@ -34,16 +34,24 @@ add_task(async function() {
Target.setDiscoverTargets({ discover: true });
await targetsCreated;
const {browserContextId} = await Target.createBrowserContext();
const { browserContextId } = await Target.createBrowserContext();
const targetCreated = Target.targetCreated();
const {targetId} = await Target.createTarget({ browserContextId });
const { targetId } = await Target.createTarget({ browserContextId });
ok(true, `Target created: ${targetId}`);
ok(!!targetId, "createTarget returns a non-empty target id");
const {targetInfo} = await targetCreated;
is(targetId, targetInfo.targetId, "createTarget and targetCreated refers to the same target id");
is(browserContextId, targetInfo.browserContextId, "the created target is reported to be of the same browser context");
const { targetInfo } = await targetCreated;
is(
targetId,
targetInfo.targetId,
"createTarget and targetCreated refers to the same target id"
);
is(
browserContextId,
targetInfo.browserContextId,
"the created target is reported to be of the same browser context"
);
is(targetInfo.type, "page", "The target is a page");
// Releasing the browser context is going to remove the tab opened when calling createTarget

View file

@ -32,7 +32,7 @@ add_task(async function() {
info("Create a new tab and wait for the target to be created");
const otherTargetCreated = Target.targetCreated();
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URI);
const {targetInfo} = await otherTargetCreated;
const { targetInfo } = await otherTargetCreated;
is(targetInfo.type, "page");
const onTabClose = BrowserTestUtils.waitForEvent(tab, "TabClose");

View file

@ -3,8 +3,12 @@
"use strict";
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
const {RemoteAgentError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
const { RemoteAgent } = ChromeUtils.import(
"chrome://remote/content/RemoteAgent.jsm"
);
const { RemoteAgentError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
/**
* Override `add_task` in order to translate chrome-remote-interface exceptions
@ -27,7 +31,8 @@ this.add_task = function(test) {
});
};
const CRI_URI = "http://example.com/browser/remote/test/browser/chrome-remote-interface.js";
const CRI_URI =
"http://example.com/browser/remote/test/browser/chrome-remote-interface.js";
/**
* Create a test document in an invisible window.
@ -59,7 +64,7 @@ async function getCDP() {
script.setAttribute("src", CRI_URI);
document.documentElement.appendChild(script);
await new Promise(resolve => {
script.addEventListener("load", resolve, {once: true});
script.addEventListener("load", resolve, { once: true });
});
const window = document.defaultView.wrappedJSObject;
@ -68,7 +73,7 @@ async function getCDP() {
// library in order to do the cross-domain http request, which,
// in a regular Web page, is impossible.
window.criRequest = (options, callback) => {
const {host, port, path} = options;
const { host, port, path } = options;
const url = `http://${host}:${port}${path}`;
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);

View file

@ -13,7 +13,9 @@
const puppeteer = require("puppeteer");
console.log("Calling puppeteer.connect");
puppeteer.connect({ browserURL: "http://localhost:9000"}).then(async browser => {
puppeteer
.connect({ browserURL: "http://localhost:9000" })
.then(async browser => {
console.log("Connect success!");
const page = await browser.newPage();
@ -21,4 +23,4 @@ puppeteer.connect({ browserURL: "http://localhost:9000"}).then(async browser =>
await page.goto("https://www.mozilla.org/");
return browser.close();
});
});

View file

@ -3,8 +3,12 @@
"use strict";
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
const { Domain } = ChromeUtils.import(
"chrome://remote/content/domains/Domain.jsm"
);
const { Domains } = ChromeUtils.import(
"chrome://remote/content/domains/Domains.jsm"
);
class MockSession {
onEvent() {}
@ -20,7 +24,7 @@ add_test(function test_Domains_constructor() {
add_test(function test_Domains_domainSupportsMethod() {
const modules = {
"Foo": class extends Domain {
Foo: class extends Domain {
bar() {}
},
};
@ -35,7 +39,7 @@ add_test(function test_Domains_domainSupportsMethod() {
add_test(function test_Domains_get_invalidModule() {
Assert.throws(() => {
const domains = new Domains(noopSession, {Foo: undefined});
const domains = new Domains(noopSession, { Foo: undefined });
domains.get("Foo");
}, /UnknownMethodError/);
@ -44,7 +48,7 @@ add_test(function test_Domains_get_invalidModule() {
add_test(function test_Domains_get_missingConstructor() {
Assert.throws(() => {
const domains = new Domains(noopSession, {Foo: {}});
const domains = new Domains(noopSession, { Foo: {} });
domains.get("Foo");
}, /TypeError/);
@ -53,7 +57,7 @@ add_test(function test_Domains_get_missingConstructor() {
add_test(function test_Domain_get_superClassNotDomain() {
Assert.throws(() => {
const domains = new Domain(noopSession, {Foo: class {}});
const domains = new Domain(noopSession, { Foo: class {} });
domains.get("Foo");
}, /TypeError/);
@ -77,7 +81,7 @@ add_test(function test_Domains_get_constructs() {
}
const session = new Session();
const domains = new Domains(session, {Foo});
const domains = new Domains(session, { Foo });
const foo = domains.get("Foo");
ok(constructed);
@ -92,7 +96,7 @@ add_test(function test_Domains_get_constructs() {
add_test(function test_Domains_size() {
class Foo extends Domain {}
const domains = new Domains(noopSession, {Foo});
const domains = new Domains(noopSession, { Foo });
equal(domains.size, 0);
domains.get("Foo");
@ -109,7 +113,7 @@ add_test(function test_Domains_clear() {
}
}
const domains = new Domains(noopSession, {Foo});
const domains = new Domains(noopSession, { Foo });
equal(domains.size, 0);
domains.get("Foo");
@ -124,12 +128,20 @@ add_test(function test_Domains_clear() {
add_test(function test_Domains_splitMethod() {
for (const t of [42, null, true, {}, [], undefined]) {
Assert.throws(() => Domains.splitMethod(t), /TypeError/, `${typeof t} throws`);
Assert.throws(
() => Domains.splitMethod(t),
/TypeError/,
`${typeof t} throws`
);
}
for (const s of ["", ".", "foo.", ".bar", "foo.bar.baz"]) {
Assert.throws(() => Domains.splitMethod(s), /Invalid method format: ".*"/, `"${s}" throws`);
Assert.throws(
() => Domains.splitMethod(s),
/Invalid method format: ".*"/,
`"${s}" throws`
);
}
deepEqual(Domains.splitMethod("foo.bar"), {domain: "foo", command: "bar"});
deepEqual(Domains.splitMethod("foo.bar"), { domain: "foo", command: "bar" });
run_next_test();
});

View file

@ -37,16 +37,19 @@ add_test(function test_RemoteAgentError_notify() {
add_test(function test_RemoteAgentError_toString() {
const e = new RemoteAgentError("message");
equal(e.toString(), RemoteAgentError.format(e));
equal(e.toString({stack: true}), RemoteAgentError.format(e, {stack: true}));
equal(
e.toString({ stack: true }),
RemoteAgentError.format(e, { stack: true })
);
run_next_test();
});
add_test(function test_RemoteAgentError_format() {
const {format} = RemoteAgentError;
const { format } = RemoteAgentError;
equal(format({name: "HippoError"}), "HippoError");
equal(format({name: "HorseError", message: "neigh"}), "HorseError: neigh");
equal(format({ name: "HippoError" }), "HippoError");
equal(format({ name: "HorseError", message: "neigh" }), "HorseError: neigh");
const dog = {
name: "DogError",
@ -54,11 +57,13 @@ add_test(function test_RemoteAgentError_format() {
stack: " one\ntwo\nthree ",
};
equal(format(dog), "DogError: woof");
equal(format(dog, {stack: true}),
`DogError: woof:
equal(
format(dog, { stack: true }),
`DogError: woof:
one
two
three`);
three`
);
const cat = {
name: "CatError",
@ -67,23 +72,27 @@ add_test(function test_RemoteAgentError_format() {
cause: dog,
};
equal(format(cat), "CatError: meow");
equal(format(cat, {stack: true}),
`CatError: meow:
equal(
format(cat, { stack: true }),
`CatError: meow:
four
five
six
caused by: DogError: woof:
one
two
three`);
three`
);
run_next_test();
});
add_test(function test_RemoteAgentError_fromJSON() {
const cdpErr = {message: `TypeError: foo:
const cdpErr = {
message: `TypeError: foo:
bar
baz`};
baz`,
};
const err = RemoteAgentError.fromJSON(cdpErr);
equal(err.message, "TypeError: foo");
@ -101,6 +110,10 @@ add_test(function test_UnsupportedError() {
add_test(function test_UnknownMethodError() {
ok(new UnknownMethodError() instanceof RemoteAgentError);
ok(new UnknownMethodError("domain").message.endsWith("domain"));
ok(new UnknownMethodError("domain", "command").message.endsWith("domain.command"));
ok(
new UnknownMethodError("domain", "command").message.endsWith(
"domain.command"
)
);
run_next_test();
});

View file

@ -3,7 +3,9 @@
"use strict";
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
const { Session } = ChromeUtils.import(
"chrome://remote/content/sessions/Session.jsm"
);
const connection = {
registerSession: () => {},
@ -13,11 +15,10 @@ const connection = {
};
class MockTarget {
constructor() {
}
constructor() {}
get browsingContext() {
return {id: 42};
return { id: 42 };
}
get mm() {