Bug 1898719 - [remote] Use private properties and methods in Remote Agent and WebDriver BiDi classes. r=webdriver-reviewers,jdescottes

Differential Revision: https://phabricator.services.mozilla.com/D212668
This commit is contained in:
Henrik Skupin 2024-06-06 07:37:25 +00:00
parent e73a59312f
commit 0ac177013f
3 changed files with 124 additions and 117 deletions

View file

@ -97,6 +97,7 @@ export class CDP {
Cu.printStderr(`DevTools listening on ${this.address}\n`); Cu.printStderr(`DevTools listening on ${this.address}\n`);
try {
// Write connection details to DevToolsActivePort file within the profile. // Write connection details to DevToolsActivePort file within the profile.
this._activePortPath = PathUtils.join( this._activePortPath = PathUtils.join(
PathUtils.profileDir, PathUtils.profileDir,
@ -104,7 +105,7 @@ export class CDP {
); );
const data = `${this.agent.port}\n${this.mainTargetPath}`; const data = `${this.agent.port}\n${this.mainTargetPath}`;
try {
await IOUtils.write(this._activePortPath, lazy.textEncoder.encode(data)); await IOUtils.write(this._activePortPath, lazy.textEncoder.encode(data));
} catch (e) { } catch (e) {
lazy.logger.warn( lazy.logger.warn(

View file

@ -148,6 +148,59 @@ class RemoteAgentParentProcess {
return this.#webDriverBiDi; return this.#webDriverBiDi;
} }
/**
* Handle the --remote-debugging-port command line argument.
*
* @param {nsICommandLine} cmdLine
* Instance of the command line interface.
*
* @returns {boolean}
* Return `true` if the command line argument has been found.
*/
#handleRemoteDebuggingPortFlag(cmdLine) {
let enabled = false;
try {
// Catch cases when the argument, and a port have been specified.
const port = cmdLine.handleFlagWithParam("remote-debugging-port", false);
if (port !== null) {
enabled = true;
// In case of an invalid port keep the default port
const parsed = Number(port);
if (!isNaN(parsed)) {
this.#port = parsed;
}
}
} catch (e) {
// If no port has been given check for the existence of the argument.
enabled = cmdLine.handleFlag("remote-debugging-port", false);
}
return enabled;
}
#handleAllowHostsFlag(cmdLine) {
try {
const hosts = cmdLine.handleFlagWithParam("remote-allow-hosts", false);
return hosts.split(",");
} catch (e) {
return null;
}
}
#handleAllowOriginsFlag(cmdLine) {
try {
const origins = cmdLine.handleFlagWithParam(
"remote-allow-origins",
false
);
return origins.split(",");
} catch (e) {
return null;
}
}
/** /**
* Check if the provided URI's host is an IP address. * Check if the provided URI's host is an IP address.
* *
@ -165,17 +218,6 @@ class RemoteAgentParentProcess {
return false; return false;
} }
handle(cmdLine) {
// remote-debugging-port has to be consumed in nsICommandLineHandler:handle
// to avoid issues on macos. See Marionette.sys.mjs::handle() for more details.
// TODO: remove after Bug 1724251 is fixed.
try {
cmdLine.handleFlagWithParam("remote-debugging-port", false);
} catch (e) {
cmdLine.handleFlag("remote-debugging-port", false);
}
}
async #listen(port) { async #listen(port) {
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
throw Components.Exception( throw Components.Exception(
@ -317,56 +359,14 @@ class RemoteAgentParentProcess {
} }
} }
/** handle(cmdLine) {
* Handle the --remote-debugging-port command line argument. // remote-debugging-port has to be consumed in nsICommandLineHandler:handle
* // to avoid issues on macos. See Marionette.sys.mjs::handle() for more details.
* @param {nsICommandLine} cmdLine // TODO: remove after Bug 1724251 is fixed.
* Instance of the command line interface.
*
* @returns {boolean}
* Return `true` if the command line argument has been found.
*/
handleRemoteDebuggingPortFlag(cmdLine) {
let enabled = false;
try { try {
// Catch cases when the argument, and a port have been specified. cmdLine.handleFlagWithParam("remote-debugging-port", false);
const port = cmdLine.handleFlagWithParam("remote-debugging-port", false);
if (port !== null) {
enabled = true;
// In case of an invalid port keep the default port
const parsed = Number(port);
if (!isNaN(parsed)) {
this.#port = parsed;
}
}
} catch (e) { } catch (e) {
// If no port has been given check for the existence of the argument. cmdLine.handleFlag("remote-debugging-port", false);
enabled = cmdLine.handleFlag("remote-debugging-port", false);
}
return enabled;
}
handleAllowHostsFlag(cmdLine) {
try {
const hosts = cmdLine.handleFlagWithParam("remote-allow-hosts", false);
return hosts.split(",");
} catch (e) {
return null;
}
}
handleAllowOriginsFlag(cmdLine) {
try {
const origins = cmdLine.handleFlagWithParam(
"remote-allow-origins",
false
);
return origins.split(",");
} catch (e) {
return null;
} }
} }
@ -383,14 +383,13 @@ class RemoteAgentParentProcess {
case "command-line-startup": case "command-line-startup":
Services.obs.removeObserver(this, topic); Services.obs.removeObserver(this, topic);
this.#enabled = this.handleRemoteDebuggingPortFlag(subject); this.#enabled = this.#handleRemoteDebuggingPortFlag(subject);
if (this.#enabled) { if (this.#enabled) {
this.#allowHosts = this.#handleAllowHostsFlag(subject);
this.#allowOrigins = this.#handleAllowOriginsFlag(subject);
Services.obs.addObserver(this, "final-ui-startup"); Services.obs.addObserver(this, "final-ui-startup");
this.#allowHosts = this.handleAllowHostsFlag(subject);
this.#allowOrigins = this.handleAllowOriginsFlag(subject);
Services.obs.addObserver(this, "browser-idle-startup-tasks-finished"); Services.obs.addObserver(this, "browser-idle-startup-tasks-finished");
Services.obs.addObserver(this, "mail-idle-startup-tasks-finished"); Services.obs.addObserver(this, "mail-idle-startup-tasks-finished");
Services.obs.addObserver(this, "quit-application"); Services.obs.addObserver(this, "quit-application");

View file

@ -31,6 +31,12 @@ const RECOMMENDED_PREFS = new Map([
* @see https://w3c.github.io/webdriver-bidi * @see https://w3c.github.io/webdriver-bidi
*/ */
export class WebDriverBiDi { export class WebDriverBiDi {
#agent;
#bidiServerPath;
#running;
#session;
#sessionlessConnections;
/** /**
* Creates a new instance of the WebDriverBiDi class. * Creates a new instance of the WebDriverBiDi class.
* *
@ -38,19 +44,20 @@ export class WebDriverBiDi {
* Reference to the Remote Agent instance. * Reference to the Remote Agent instance.
*/ */
constructor(agent) { constructor(agent) {
this.agent = agent; this.#agent = agent;
this._running = false; this.#running = false;
this._session = null; this.#bidiServerPath;
this._sessionlessConnections = new Set(); this.#session = null;
this.#sessionlessConnections = new Set();
} }
get address() { get address() {
return `ws://${this.agent.host}:${this.agent.port}`; return `ws://${this.#agent.host}:${this.#agent.port}`;
} }
get session() { get session() {
return this._session; return this.#session;
} }
/** /**
@ -60,7 +67,7 @@ export class WebDriverBiDi {
* The connection without an accociated WebDriver session. * The connection without an accociated WebDriver session.
*/ */
addSessionlessConnection(connection) { addSessionlessConnection(connection) {
this._sessionlessConnections.add(connection); this.#sessionlessConnections.add(connection);
} }
/** /**
@ -82,7 +89,7 @@ export class WebDriverBiDi {
* If, for whatever reason, a session could not be created. * If, for whatever reason, a session could not be created.
*/ */
async createSession(capabilities, flags, sessionlessConnection) { async createSession(capabilities, flags, sessionlessConnection) {
if (this.session) { if (this.#session) {
throw new lazy.error.SessionNotCreatedError( throw new lazy.error.SessionNotCreatedError(
"Maximum number of active sessions" "Maximum number of active sessions"
); );
@ -98,7 +105,7 @@ export class WebDriverBiDi {
// has been requested, register a path handler for the session. // has been requested, register a path handler for the session.
let webSocketUrl = null; let webSocketUrl = null;
if ( if (
this.agent.running && this.#agent.running &&
(session.capabilities.get("webSocketUrl") || sessionlessConnection) (session.capabilities.get("webSocketUrl") || sessionlessConnection)
) { ) {
// Creating a WebDriver BiDi session too early can cause issues with // Creating a WebDriver BiDi session too early can cause issues with
@ -107,16 +114,16 @@ export class WebDriverBiDi {
// cause shutdown hangs. As such WebDriver BiDi will return a new session // cause shutdown hangs. As such WebDriver BiDi will return a new session
// once the initial application window has finished initializing. // once the initial application window has finished initializing.
lazy.logger.debug(`Waiting for initial application window`); lazy.logger.debug(`Waiting for initial application window`);
await this.agent.browserStartupFinished; await this.#agent.browserStartupFinished;
this.agent.server.registerPathHandler(session.path, session); this.#agent.server.registerPathHandler(session.path, session);
webSocketUrl = `${this.address}${session.path}`; webSocketUrl = `${this.address}${session.path}`;
lazy.logger.debug(`Registered session handler: ${session.path}`); lazy.logger.debug(`Registered session handler: ${session.path}`);
if (sessionlessConnection) { if (sessionlessConnection) {
// Remove temporary session-less connection // Remove temporary session-less connection
this._sessionlessConnections.delete(sessionlessConnection); this.#sessionlessConnections.delete(sessionlessConnection);
} }
} }
@ -124,11 +131,11 @@ export class WebDriverBiDi {
// a path handler has been registered. Otherwise set its value to null. // a path handler has been registered. Otherwise set its value to null.
session.capabilities.set("webSocketUrl", webSocketUrl); session.capabilities.set("webSocketUrl", webSocketUrl);
this._session = session; this.#session = session;
return { return {
sessionId: this.session.id, sessionId: this.#session.id,
capabilities: this.session.capabilities, capabilities: this.#session.capabilities,
}; };
} }
@ -136,19 +143,19 @@ export class WebDriverBiDi {
* Delete the current WebDriver session. * Delete the current WebDriver session.
*/ */
deleteSession() { deleteSession() {
if (!this.session) { if (!this.#session) {
return; return;
} }
// When the Remote Agent is listening, and a BiDi WebSocket is active, // When the Remote Agent is listening, and a BiDi WebSocket is active,
// unregister the path handler for the session. // unregister the path handler for the session.
if (this.agent.running && this.session.capabilities.get("webSocketUrl")) { if (this.#agent.running && this.#session.capabilities.get("webSocketUrl")) {
this.agent.server.registerPathHandler(this.session.path, null); this.#agent.server.registerPathHandler(this.#session.path, null);
lazy.logger.debug(`Unregistered session handler: ${this.session.path}`); lazy.logger.debug(`Unregistered session handler: ${this.#session.path}`);
} }
this.session.destroy(); this.#session.destroy();
this._session = null; this.#session = null;
} }
/** /**
@ -161,7 +168,7 @@ export class WebDriverBiDi {
* The readiness state. * The readiness state.
*/ */
getSessionReadinessStatus() { getSessionReadinessStatus() {
if (this.session) { if (this.#session) {
// We currently only support one session, see Bug 1720707. // We currently only support one session, see Bug 1720707.
return { return {
ready: false, ready: false,
@ -179,42 +186,42 @@ export class WebDriverBiDi {
* Starts the WebDriver BiDi support. * Starts the WebDriver BiDi support.
*/ */
async start() { async start() {
if (this._running) { if (this.#running) {
return; return;
} }
this._running = true; this.#running = true;
lazy.RecommendedPreferences.applyPreferences(RECOMMENDED_PREFS); lazy.RecommendedPreferences.applyPreferences(RECOMMENDED_PREFS);
// Install a HTTP handler for direct WebDriver BiDi connection requests. // Install a HTTP handler for direct WebDriver BiDi connection requests.
this.agent.server.registerPathHandler( this.#agent.server.registerPathHandler(
"/session", "/session",
new lazy.WebDriverNewSessionHandler(this) new lazy.WebDriverNewSessionHandler(this)
); );
Cu.printStderr(`WebDriver BiDi listening on ${this.address}\n`); Cu.printStderr(`WebDriver BiDi listening on ${this.address}\n`);
try {
// Write WebSocket connection details to the WebDriverBiDiServer.json file // Write WebSocket connection details to the WebDriverBiDiServer.json file
// located within the application's profile. // located within the application's profile.
this._bidiServerPath = PathUtils.join( this.#bidiServerPath = PathUtils.join(
PathUtils.profileDir, PathUtils.profileDir,
"WebDriverBiDiServer.json" "WebDriverBiDiServer.json"
); );
const data = { const data = {
ws_host: this.agent.host, ws_host: this.#agent.host,
ws_port: this.agent.port, ws_port: this.#agent.port,
}; };
try {
await IOUtils.write( await IOUtils.write(
this._bidiServerPath, this.#bidiServerPath,
lazy.textEncoder.encode(JSON.stringify(data, undefined, " ")) lazy.textEncoder.encode(JSON.stringify(data, undefined, " "))
); );
} catch (e) { } catch (e) {
lazy.logger.warn( lazy.logger.warn(
`Failed to create ${this._bidiServerPath} (${e.message})` `Failed to create ${this.#bidiServerPath} (${e.message})`
); );
} }
} }
@ -223,30 +230,30 @@ export class WebDriverBiDi {
* Stops the WebDriver BiDi support. * Stops the WebDriver BiDi support.
*/ */
async stop() { async stop() {
if (!this._running) { if (!this.#running) {
return; return;
} }
try { try {
await IOUtils.remove(this._bidiServerPath); await IOUtils.remove(this.#bidiServerPath);
} catch (e) { } catch (e) {
lazy.logger.warn( lazy.logger.warn(
`Failed to remove ${this._bidiServerPath} (${e.message})` `Failed to remove ${this.#bidiServerPath} (${e.message})`
); );
} }
try { try {
// Close open session // Close open session
this.deleteSession(); this.deleteSession();
this.agent.server.registerPathHandler("/session", null); this.#agent.server.registerPathHandler("/session", null);
// Close all open session-less connections // Close all open session-less connections
this._sessionlessConnections.forEach(connection => connection.close()); this.#sessionlessConnections.forEach(connection => connection.close());
this._sessionlessConnections.clear(); this.#sessionlessConnections.clear();
} catch (e) { } catch (e) {
lazy.logger.error("Failed to stop protocol", e); lazy.logger.error("Failed to stop protocol", e);
} finally { } finally {
this._running = false; this.#running = false;
} }
} }
} }