From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- remote/shared/webdriver/Session.sys.mjs | 344 ++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 remote/shared/webdriver/Session.sys.mjs (limited to 'remote/shared/webdriver/Session.sys.mjs') diff --git a/remote/shared/webdriver/Session.sys.mjs b/remote/shared/webdriver/Session.sys.mjs new file mode 100644 index 0000000000..d09ad47e79 --- /dev/null +++ b/remote/shared/webdriver/Session.sys.mjs @@ -0,0 +1,344 @@ +/* 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/. */ + +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + accessibility: "chrome://remote/content/marionette/accessibility.sys.mjs", + allowAllCerts: "chrome://remote/content/marionette/cert.sys.mjs", + Capabilities: "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs", + error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", + generateUUID: "chrome://remote/content/shared/UUID.sys.mjs", + Log: "chrome://remote/content/shared/Log.sys.mjs", + registerProcessDataActor: + "chrome://remote/content/shared/webdriver/process-actors/WebDriverProcessDataParent.sys.mjs", + RootMessageHandler: + "chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs", + RootMessageHandlerRegistry: + "chrome://remote/content/shared/messagehandler/RootMessageHandlerRegistry.sys.mjs", + unregisterProcessDataActor: + "chrome://remote/content/shared/webdriver/process-actors/WebDriverProcessDataParent.sys.mjs", + WebDriverBiDiConnection: + "chrome://remote/content/webdriver-bidi/WebDriverBiDiConnection.sys.mjs", + WebSocketHandshake: + "chrome://remote/content/server/WebSocketHandshake.sys.mjs", +}); + +XPCOMUtils.defineLazyGetter(lazy, "logger", () => lazy.Log.get()); + +/** + * Representation of WebDriver session. + */ +export class WebDriverSession { + /** + * Construct a new WebDriver session. + * + * It is expected that the caller performs the necessary checks on + * the requested capabilities to be WebDriver conforming. The WebDriver + * service offered by Marionette does not match or negotiate capabilities + * beyond type- and bounds checks. + * + *

Capabilities

+ * + *
+ *
acceptInsecureCerts (boolean) + *
Indicates whether untrusted and self-signed TLS certificates + * are implicitly trusted on navigation for the duration of the session. + * + *
pageLoadStrategy (string) + *
The page load strategy to use for the current session. Must be + * one of "none", "eager", and "normal". + * + *
proxy (Proxy object) + *
Defines the proxy configuration. + * + *
setWindowRect (boolean) + *
Indicates whether the remote end supports all of the resizing + * and repositioning commands. + * + *
timeouts (Timeouts object) + *
Describes the timeouts imposed on certian session operations. + * + *
strictFileInteractability (boolean) + *
Defines the current session’s strict file interactability. + * + *
unhandledPromptBehavior (string) + *
Describes the current session’s user prompt handler. Must be one of + * "accept", "accept and notify", "dismiss", + * "dismiss and notify", and "ignore". Defaults to the + * "dismiss and notify" state. + * + *
moz:accessibilityChecks (boolean) + *
Run a11y checks when clicking elements. + * + *
moz:debuggerAddress (boolean) + *
Indicate that the Chrome DevTools Protocol (CDP) has to be enabled. + * + *
moz:useNonSpecCompliantPointerOrigin (boolean) + *
Use the not WebDriver conforming calculation of the pointer origin + * when the origin is an element, and the element center point is used. + * + *
moz:webdriverClick (boolean) + *
Use a WebDriver conforming WebDriver::ElementClick. + *
+ * + *

Timeouts object

+ * + *
+ *
script (number) + *
Determines when to interrupt a script that is being evaluates. + * + *
pageLoad (number) + *
Provides the timeout limit used to interrupt navigation of the + * browsing context. + * + *
implicit (number) + *
Gives the timeout of when to abort when locating an element. + *
+ * + *

Proxy object

+ * + *
+ *
proxyType (string) + *
Indicates the type of proxy configuration. Must be one + * of "pac", "direct", "autodetect", + * "system", or "manual". + * + *
proxyAutoconfigUrl (string) + *
Defines the URL for a proxy auto-config file if + * proxyType is equal to "pac". + * + *
httpProxy (string) + *
Defines the proxy host for HTTP traffic when the + * proxyType is "manual". + * + *
noProxy (string) + *
Lists the adress for which the proxy should be bypassed when + * the proxyType is "manual". Must be a JSON + * List containing any number of any of domains, IPv4 addresses, or IPv6 + * addresses. + * + *
sslProxy (string) + *
Defines the proxy host for encrypted TLS traffic when the + * proxyType is "manual". + * + *
socksProxy (string) + *
Defines the proxy host for a SOCKS proxy traffic when the + * proxyType is "manual". + * + *
socksVersion (string) + *
Defines the SOCKS proxy version when the proxyType is + * "manual". It must be any integer between 0 and 255 + * inclusive. + *
+ * + *

Example

+ * + * Input: + * + *

+   *     {"capabilities": {"acceptInsecureCerts": true}}
+   * 
+ * + * @param {Object=} capabilities + * JSON Object containing any of the recognised capabilities listed + * above. + * + * @param {WebDriverBiDiConnection=} connection + * An optional existing WebDriver BiDi connection to associate with the + * new session. + * + * @throws {SessionNotCreatedError} + * If, for whatever reason, a session could not be created. + */ + constructor(capabilities, connection) { + // WebSocket connections that use this session. This also accounts for + // possible disconnects due to network outages, which require clients + // to reconnect. + this._connections = new Set(); + + this.id = lazy.generateUUID(); + + // Define the HTTP path to query this session via WebDriver BiDi + this.path = `/session/${this.id}`; + + try { + this.capabilities = lazy.Capabilities.fromJSON(capabilities, this.path); + } catch (e) { + throw new lazy.error.SessionNotCreatedError(e); + } + + if (this.capabilities.get("acceptInsecureCerts")) { + lazy.logger.warn( + "TLS certificate errors will be ignored for this session" + ); + lazy.allowAllCerts.enable(); + } + + if (this.proxy.init()) { + lazy.logger.info( + `Proxy settings initialised: ${JSON.stringify(this.proxy)}` + ); + } + + // If we are testing accessibility with marionette, start a11y service in + // chrome first. This will ensure that we do not have any content-only + // services hanging around. + if (this.a11yChecks && lazy.accessibility.service) { + lazy.logger.info("Preemptively starting accessibility service in Chrome"); + } + + // If a connection without an associated session has been specified + // immediately register the newly created session for it. + if (connection) { + connection.registerSession(this); + this._connections.add(connection); + } + + lazy.registerProcessDataActor(); + } + + destroy() { + lazy.allowAllCerts.disable(); + + // Close all open connections which unregister themselves. + this._connections.forEach(connection => connection.close()); + if (this._connections.size > 0) { + lazy.logger.warn( + `Failed to close ${this._connections.size} WebSocket connections` + ); + } + + // Destroy the dedicated MessageHandler instance if we created one. + if (this._messageHandler) { + this._messageHandler.off( + "message-handler-protocol-event", + this._onMessageHandlerProtocolEvent + ); + this._messageHandler.destroy(); + } + + lazy.unregisterProcessDataActor(); + } + + async execute(module, command, params) { + // XXX: At the moment, commands do not describe consistently their destination, + // so we will need a translation step based on a specific command and its params + // in order to extract a destination that can be understood by the MessageHandler. + // + // For now, an option is to send all commands to ROOT, and all BiDi MessageHandler + // modules will therefore need to implement this translation step in the root + // implementation of their module. + const destination = { + type: lazy.RootMessageHandler.type, + }; + if (!this.messageHandler.supportsCommand(module, command, destination)) { + throw new lazy.error.UnknownCommandError(`${module}.${command}`); + } + + return this.messageHandler.handleCommand({ + moduleName: module, + commandName: command, + params, + destination, + }); + } + + get a11yChecks() { + return this.capabilities.get("moz:accessibilityChecks"); + } + + get messageHandler() { + if (!this._messageHandler) { + this._messageHandler = + lazy.RootMessageHandlerRegistry.getOrCreateMessageHandler(this.id); + this._onMessageHandlerProtocolEvent = + this._onMessageHandlerProtocolEvent.bind(this); + this._messageHandler.on( + "message-handler-protocol-event", + this._onMessageHandlerProtocolEvent + ); + } + + return this._messageHandler; + } + + get pageLoadStrategy() { + return this.capabilities.get("pageLoadStrategy"); + } + + get proxy() { + return this.capabilities.get("proxy"); + } + + get strictFileInteractability() { + return this.capabilities.get("strictFileInteractability"); + } + + get timeouts() { + return this.capabilities.get("timeouts"); + } + + set timeouts(timeouts) { + this.capabilities.set("timeouts", timeouts); + } + + get unhandledPromptBehavior() { + return this.capabilities.get("unhandledPromptBehavior"); + } + + /** + * Remove the specified WebDriver BiDi connection. + * + * @param {WebDriverBiDiConnection} connection + */ + removeConnection(connection) { + if (this._connections.has(connection)) { + this._connections.delete(connection); + } else { + lazy.logger.warn("Trying to remove a connection that doesn't exist."); + } + } + + toString() { + return `[object ${this.constructor.name} ${this.id}]`; + } + + // nsIHttpRequestHandler + + /** + * Handle new WebSocket connection requests. + * + * WebSocket clients will attempt to connect to this session at + * `/session/:id`. Hereby a WebSocket upgrade will automatically + * be performed. + * + * @param {Request} request + * HTTP request (httpd.js) + * @param {Response} response + * Response to an HTTP request (httpd.js) + */ + async handle(request, response) { + const webSocket = await lazy.WebSocketHandshake.upgrade(request, response); + const conn = new lazy.WebDriverBiDiConnection( + webSocket, + response._connection + ); + conn.registerSession(this); + this._connections.add(conn); + } + + _onMessageHandlerProtocolEvent(eventName, messageHandlerEvent) { + const { name, data } = messageHandlerEvent; + this._connections.forEach(connection => connection.sendEvent(name, data)); + } + + // XPCOM + + get QueryInterface() { + return ChromeUtils.generateQI(["nsIHttpRequestHandler"]); + } +} -- cgit v1.2.3