mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1712902 - [remote] Conditionally start CDP when protocol is marked as active. r=remote-protocol-reviewers,jdescottes
Differential Revision: https://phabricator.services.mozilla.com/D116415
This commit is contained in:
parent
7543ddeb51
commit
555beb9ea5
71
remote/cdp/CDP.jsm
Normal file
71
remote/cdp/CDP.jsm
Normal file
@ -0,0 +1,71 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["CDP"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
|
||||
JSONHandler: "chrome://remote/content/cdp/JSONHandler.jsm",
|
||||
TargetList: "chrome://remote/content/cdp/targets/TargetList.jsm",
|
||||
});
|
||||
|
||||
/**
|
||||
* Entry class for the Chrome DevTools Protocol support.
|
||||
*
|
||||
* It holds the list of available targets (tabs, main browser), and also
|
||||
* sets up the necessary handlers for the HTTP server.
|
||||
*
|
||||
* @see https://chromedevtools.github.io/devtools-protocol
|
||||
*/
|
||||
class CDP {
|
||||
/**
|
||||
* Creates a new instance of the CDP class.
|
||||
*
|
||||
* @param {HttpServer} server
|
||||
* The HTTP server that handles new connection requests.
|
||||
*/
|
||||
constructor(server) {
|
||||
this.server = server;
|
||||
|
||||
this.server.registerPrefixHandler("/json/", new JSONHandler(this));
|
||||
|
||||
this.targetList = new TargetList();
|
||||
this.targetList.on("target-created", (eventName, target) => {
|
||||
this.server.registerPathHandler(target.path, target);
|
||||
});
|
||||
this.targetList.on("target-destroyed", (eventName, target) => {
|
||||
this.server.registerPathHandler(target.path, null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the CDP support.
|
||||
*/
|
||||
async start() {
|
||||
await this.targetList.watchForTargets();
|
||||
|
||||
// Immediatly instantiate the main process target in order
|
||||
// to be accessible via HTTP endpoint on startup
|
||||
const mainTarget = this.targetList.getMainProcessTarget();
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"remote-listening",
|
||||
`DevTools listening on ${mainTarget.wsDebuggerURL}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the CDP support.
|
||||
*/
|
||||
stop() {
|
||||
this.targetList.destructor();
|
||||
}
|
||||
}
|
@ -21,8 +21,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
});
|
||||
|
||||
class JSONHandler {
|
||||
constructor(agent) {
|
||||
this.agent = agent;
|
||||
constructor(cdp) {
|
||||
this.cdp = cdp;
|
||||
this.routes = {
|
||||
"/json/version": this.getVersion.bind(this),
|
||||
"/json/protocol": this.getProtocol.bind(this),
|
||||
@ -31,7 +31,7 @@ class JSONHandler {
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
const mainProcessTarget = this.agent.targetList.getMainProcessTarget();
|
||||
const mainProcessTarget = this.cdp.targetList.getMainProcessTarget();
|
||||
|
||||
const { userAgent } = Cc[
|
||||
"@mozilla.org/network/protocol;1?name=http"
|
||||
@ -52,7 +52,7 @@ class JSONHandler {
|
||||
}
|
||||
|
||||
getTargetList() {
|
||||
return [...this.agent.targetList];
|
||||
return [...this.cdp.targetList];
|
||||
}
|
||||
|
||||
// nsIHttpRequestHandler
|
||||
|
@ -22,7 +22,7 @@ add_task(async function json_version() {
|
||||
is(json["WebKit-Version"], "1.0", "Webkit version found");
|
||||
is(
|
||||
json.webSocketDebuggerUrl,
|
||||
RemoteAgent.targetList.getMainProcessTarget().wsDebuggerURL,
|
||||
RemoteAgent.cdp.targetList.getMainProcessTarget().wsDebuggerURL,
|
||||
"Websocket URL for main process target found"
|
||||
);
|
||||
});
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Test very basic CDP features.
|
||||
|
||||
add_task(async function({ CDP }) {
|
||||
const { mainProcessTarget } = RemoteAgent.targetList;
|
||||
const { mainProcessTarget } = RemoteAgent.cdp.targetList;
|
||||
ok(
|
||||
mainProcessTarget,
|
||||
"The main process target is instantiated after the call to `listen`"
|
||||
|
@ -6,30 +6,43 @@
|
||||
|
||||
var EXPORTED_SYMBOLS = ["RemoteAgent", "RemoteAgentFactory"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
|
||||
CDP: "chrome://remote/content/cdp/CDP.jsm",
|
||||
HttpServer: "chrome://remote/content/server/HTTPD.jsm",
|
||||
JSONHandler: "chrome://remote/content/cdp/JSONHandler.jsm",
|
||||
Log: "chrome://remote/content/shared/Log.jsm",
|
||||
Preferences: "resource://gre/modules/Preferences.jsm",
|
||||
RecommendedPreferences:
|
||||
"chrome://remote/content/cdp/RecommendedPreferences.jsm",
|
||||
TargetList: "chrome://remote/content/cdp/targets/TargetList.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
|
||||
|
||||
const FORCE_LOCAL = "remote.force-local";
|
||||
const PREF_ACTIVE_PROTOCOLS = "remote.active-protocols";
|
||||
const PREF_FORCE_LOCAL = "remote.force-local";
|
||||
|
||||
// const BIDI_ACTIVE = 0x1;
|
||||
const CDP_ACTIVE = 0x2;
|
||||
|
||||
const LOOPBACKS = ["localhost", "127.0.0.1", "[::1]"];
|
||||
|
||||
class RemoteAgentClass {
|
||||
constructor() {
|
||||
this.cdp = null;
|
||||
this.server = null;
|
||||
|
||||
this.alteredPrefs = new Set();
|
||||
|
||||
const protocols = Services.prefs.getIntPref(PREF_ACTIVE_PROTOCOLS);
|
||||
if (protocols < 1 || protocols > 3) {
|
||||
throw Error(`Invalid remote protocol identifier: ${protocols}`);
|
||||
}
|
||||
this.activeProtocols = protocols;
|
||||
}
|
||||
|
||||
get listening() {
|
||||
@ -61,7 +74,7 @@ class RemoteAgentClass {
|
||||
}
|
||||
|
||||
let { host, port } = url;
|
||||
if (Preferences.get(FORCE_LOCAL) && !LOOPBACKS.includes(host)) {
|
||||
if (Preferences.get(PREF_FORCE_LOCAL) && !LOOPBACKS.includes(host)) {
|
||||
throw Components.Exception(
|
||||
"Restricted to loopback devices",
|
||||
Cr.NS_ERROR_ILLEGAL_VALUE
|
||||
@ -82,33 +95,19 @@ class RemoteAgentClass {
|
||||
}
|
||||
|
||||
this.server = new HttpServer();
|
||||
this.server.registerPrefixHandler("/json/", new JSONHandler(this));
|
||||
|
||||
this.targetList = new TargetList();
|
||||
this.targetList.on("target-created", (eventName, target) => {
|
||||
this.server.registerPathHandler(target.path, target);
|
||||
});
|
||||
this.targetList.on("target-destroyed", (eventName, target) => {
|
||||
this.server.registerPathHandler(target.path, null);
|
||||
});
|
||||
if ((this.activeProtocols & CDP_ACTIVE) === CDP_ACTIVE) {
|
||||
this.cdp = new CDP(this.server);
|
||||
}
|
||||
|
||||
return this.asyncListen(host, port);
|
||||
}
|
||||
|
||||
async asyncListen(host, port) {
|
||||
try {
|
||||
await this.targetList.watchForTargets();
|
||||
|
||||
// Immediatly instantiate the main process target in order
|
||||
// to be accessible via HTTP endpoint on startup
|
||||
const mainTarget = this.targetList.getMainProcessTarget();
|
||||
|
||||
this.server._start(port, host);
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"remote-listening",
|
||||
`DevTools listening on ${mainTarget.wsDebuggerURL}`
|
||||
);
|
||||
|
||||
await this.cdp?.start();
|
||||
} catch (e) {
|
||||
await this.close();
|
||||
logger.error(`Unable to start remote agent: ${e.message}`, e);
|
||||
@ -123,11 +122,9 @@ class RemoteAgentClass {
|
||||
}
|
||||
this.alteredPrefs.clear();
|
||||
|
||||
// destroy targetList before stopping server,
|
||||
// otherwise the HTTP will fail to stop
|
||||
if (this.targetList) {
|
||||
this.targetList.destructor();
|
||||
}
|
||||
// Stop the CDP support before stopping the server.
|
||||
// Otherwise the HTTP server will fail to stop.
|
||||
this.cdp?.stop();
|
||||
|
||||
if (this.listening) {
|
||||
return this.server.stop();
|
||||
@ -136,8 +133,8 @@ class RemoteAgentClass {
|
||||
// this function must never fail
|
||||
logger.error("unable to stop listener", e);
|
||||
} finally {
|
||||
this.cdp = null;
|
||||
this.server = null;
|
||||
this.targetList = null;
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
|
@ -7,6 +7,13 @@ There are a couple of preferences associated with the Remote Agent:
|
||||
Configurable preferences
|
||||
------------------------
|
||||
|
||||
### `remote.active-protocols`
|
||||
|
||||
Defines the remote protocols that are active. Available protocols are,
|
||||
WebDriver BiDi (`1`), and CDP (`2`). Multiple protocols can be activated
|
||||
at the same time by using bitwise or with the values. Defaults to `3`
|
||||
in Nightly builds, and `2` otherwise.
|
||||
|
||||
### `remote.force-local`
|
||||
|
||||
Limits the Remote Agent to be allowed to listen on loopback devices,
|
||||
|
@ -76,7 +76,7 @@ This is what it looks like all put together:
|
||||
info("Current URL: " + tab.linkedBrowser.currentURI.spec);
|
||||
|
||||
// manually connect to a specific target
|
||||
const { mainProcessTarget } = RemoteAgent.targetList;
|
||||
const { mainProcessTarget } = RemoteAgent.cdp.targetList;
|
||||
const target = mainProcessTarget.wsDebuggerURL;
|
||||
const client = await CDP({ target });
|
||||
|
||||
|
@ -7,6 +7,7 @@ remote.jar:
|
||||
content/components/RemoteAgent.jsm (components/RemoteAgent.jsm)
|
||||
|
||||
## CDP ##
|
||||
content/cdp/CDP.jsm (cdp/CDP.jsm)
|
||||
content/cdp/Connection.jsm (cdp/Connection.jsm)
|
||||
content/cdp/Error.jsm (cdp/Error.jsm)
|
||||
content/cdp/JSONHandler.jsm (cdp/JSONHandler.jsm)
|
||||
|
Loading…
Reference in New Issue
Block a user