Skip to content

Commit

Permalink
Merge branch 'trunk' into handle-knownerror-networkinterceptor-joeban
Browse files Browse the repository at this point in the history
  • Loading branch information
pujagani committed Apr 23, 2024
2 parents 09c6cf7 + ea73d44 commit 2a37565
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 140 deletions.
2 changes: 1 addition & 1 deletion java/src/org/openqa/selenium/bidi/module/Network.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void onResponseCompleted(Consumer<ResponseDetails> consumer) {
if (browsingContextIds.isEmpty()) {
this.bidi.addListener(responseCompleted, consumer);
} else {
this.bidi.addListener(browsingContextIds, responseStarted, consumer);
this.bidi.addListener(browsingContextIds, responseCompleted, consumer);
}
}

Expand Down
8 changes: 8 additions & 0 deletions java/src/org/openqa/selenium/grid/node/relay/RelayFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ public class RelayFlags implements HasRoles {
@ConfigValue(section = RELAY_SECTION, name = "status-endpoint", example = "\"/status\"")
private String serviceStatusEndpoint;

@Parameter(
names = {"--service-protocol-version"},
description =
"Enforce a specific protocol version in HttpClient when communicating with the endpoint"
+ " service status")
@ConfigValue(section = RELAY_SECTION, name = "protocol-version", example = "\"HTTP/1.1\"")
private String serviceProtocolVersion;

@Override
public Set<Role> getRoles() {
return Collections.singleton(NODE_ROLE);
Expand Down
23 changes: 23 additions & 0 deletions java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.common.collect.Multimap;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient.Version;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -103,6 +104,27 @@ public URI getServiceStatusUri() {
}
}

public String getServiceProtocolVersion() {
String rawProtocolVersion = config.get(RELAY_SECTION, "protocol-version").orElse("");
String protocolVersion = rawProtocolVersion;
if (protocolVersion.isEmpty()) {
return protocolVersion;
} else {
protocolVersion = normalizeProtocolVersion(protocolVersion);
}
try {
return Version.valueOf(protocolVersion).toString();
} catch (IllegalArgumentException e) {
LOG.info("Unsupported protocol version: " + protocolVersion);
throw new ConfigException("Unsupported protocol version provided: " + rawProtocolVersion, e);
}
}

private String normalizeProtocolVersion(String protocolVersion) {
// Support input in the form of "http/1.1" or "HTTP/1.1"
return protocolVersion.toUpperCase().replaceAll("/", "_").replaceAll("\\.", "_");
}

// Method being used in SessionSlot
@SuppressWarnings("unused")
private boolean isServiceUp(HttpClient client) {
Expand Down Expand Up @@ -160,6 +182,7 @@ public Map<Capabilities, Collection<SessionFactory>> getSessionFactories(
sessionTimeout,
getServiceUri(),
getServiceStatusUri(),
getServiceProtocolVersion(),
immutable));
}
LOG.info(String.format("Mapping %s, %d times", immutable, maxSessions));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class RelaySessionFactory implements SessionFactory {
private final Duration sessionTimeout;
private final URL serviceUrl;
private final URL serviceStatusUrl;
private final String serviceProtocolVersion;
private final Capabilities stereotype;

public RelaySessionFactory(
Expand All @@ -84,12 +85,15 @@ public RelaySessionFactory(
Duration sessionTimeout,
URI serviceUri,
URI serviceStatusUri,
String serviceProtocolVersion,
Capabilities stereotype) {
this.tracer = Require.nonNull("Tracer", tracer);
this.clientFactory = Require.nonNull("HTTP client", clientFactory);
this.sessionTimeout = Require.nonNull("Session timeout", sessionTimeout);
this.serviceUrl = createUrlFromUri(Require.nonNull("Service URL", serviceUri));
this.serviceStatusUrl = createUrlFromUri(serviceStatusUri);
this.serviceProtocolVersion =
Require.nonNull("Service protocol version", serviceProtocolVersion);
this.stereotype = ImmutableCapabilities.copyOf(Require.nonNull("Stereotype", stereotype));
}

Expand Down Expand Up @@ -209,7 +213,12 @@ public boolean isServiceUp() {
// If no status endpoint was configured, we assume the server is up.
return true;
}
try (HttpClient client = clientFactory.createClient(serviceStatusUrl)) {

ClientConfig clientConfig = ClientConfig.defaultConfig().baseUrl(serviceStatusUrl);
if (!serviceProtocolVersion.isEmpty()) {
clientConfig = clientConfig.version(serviceProtocolVersion);
}
try (HttpClient client = clientFactory.createClient(clientConfig)) {
HttpResponse response =
client.execute(new HttpRequest(HttpMethod.GET, serviceStatusUrl.toString()));
LOG.log(Debug.getDebugLogLevel(), () -> Contents.string(response));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,55 @@ void statusUrlIsParsedSuccessfully() {
.isEqualTo("http://127.0.0.1:8888/statusEndpoint");
}

@Test
void protocolVersionIsParsedSuccessfully() {
String[] rawConfig =
new String[] {
"[relay]",
"host = '127.0.0.1'",
"port = '8888'",
"status-endpoint = '/statusEndpoint'",
"protocol-version = 'HTTP/1.1'",
"configs = [\"5\", '{\"browserName\": \"firefox\"}']",
};
Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig)));
RelayOptions relayOptions = new RelayOptions(config);
assertThat(relayOptions.getServiceProtocolVersion()).isEqualTo("HTTP_1_1");
rawConfig =
new String[] {
"[relay]",
"host = '127.0.0.1'",
"port = '8888'",
"status-endpoint = '/statusEndpoint'",
"protocol-version = 'HTTP_1_1'",
"configs = [\"5\", '{\"browserName\": \"firefox\"}']",
};
config = new TomlConfig(new StringReader(String.join("\n", rawConfig)));
relayOptions = new RelayOptions(config);
assertThat(relayOptions.getServiceProtocolVersion()).isEqualTo("HTTP_1_1");
}

@Test
void protocolVersionThrowsConfigException() {
String[] rawConfig =
new String[] {
"[relay]",
"host = '127.0.0.1'",
"port = '8888'",
"status-endpoint = '/statusEndpoint'",
"protocol-version = 'HTTP/0.9'",
"configs = [\"5\", '{\"browserName\": \"firefox\"}']",
};
Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig)));
RelayOptions relayOptions = new RelayOptions(config);
assertThatExceptionOfType(ConfigException.class)
.isThrownBy(
() -> {
relayOptions.getServiceProtocolVersion();
})
.withMessageContaining("Unsupported protocol version provided: HTTP/0.9");
}

@Test
void missingConfigsThrowsConfigException() {
String[] rawConfig =
Expand Down
21 changes: 12 additions & 9 deletions javascript/node/selenium-webdriver/chromium.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const error = require('./lib/error')
const Symbols = require('./lib/symbols')
const webdriver = require('./lib/webdriver')
const remote = require('./remote')
const { getPath } = require('./common/driverFinder')
const { getBinaryPaths } = require('./common/driverFinder')

/**
* Custom command names supported by Chromium WebDriver.
Expand Down Expand Up @@ -622,14 +622,17 @@ class Driver extends webdriver.WebDriver {
} else {
let service = opt_serviceExecutor || this.getDefaultService()
if (!service.getExecutable()) {
const { driverPath, browserPath } = getPath(caps)
const { driverPath, browserPath } = getBinaryPaths(caps)
service.setExecutable(driverPath)
const vendorOptions = caps.get(vendorCapabilityKey)
if (vendorOptions) {
vendorOptions['binary'] = browserPath
caps.set(vendorCapabilityKey, vendorOptions)
} else {
caps.set(vendorCapabilityKey, { binary: browserPath })
if (browserPath) {
const vendorOptions = caps.get(vendorCapabilityKey)
if (vendorOptions) {
vendorOptions['binary'] = browserPath
caps.set(vendorCapabilityKey, vendorOptions)
} else {
caps.set(vendorCapabilityKey, { binary: browserPath })
}
caps.delete(Capability.BROWSER_VERSION)
}
}
onQuit = () => service.kill()
Expand Down Expand Up @@ -743,7 +746,7 @@ class Driver extends webdriver.WebDriver {
* Set a permission state to the given value.
*
* @param {string} name A name of the permission to update.
* @param {('granted'|'denied'|'prompt')} state State to set permission to.
* @param {("granted"|"denied"|"prompt")} state State to set permission to.
* @returns {!Promise<Object>} A promise that will be resolved when the
* command has finished.
* @see <https://w3c.github.io/permissions/#permission-registry> for valid
Expand Down
40 changes: 36 additions & 4 deletions javascript/node/selenium-webdriver/common/driverFinder.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@
* Utility to find if a given file is present and executable.
*/

const { driverLocation } = require('./seleniumManager')
const path = require('node:path')
const { binaryPaths } = require('./seleniumManager')

/**
* Determines the path of the correct Selenium Manager binary
* @param {Capabilities} capabilities browser options to fetch the driver
* @returns {{browserPath: string, driverPath: string}} path of the driver
* and browser location
*/
function getPath(capabilities) {
function getBinaryPaths(capabilities) {
try {
return driverLocation(capabilities)
const args = getArgs(capabilities)
return binaryPaths(args)
} catch (e) {
throw Error(
`Unable to obtain browser driver.
Expand All @@ -40,5 +43,34 @@ function getPath(capabilities) {
}
}

function getArgs(options) {
let args = ['--browser', options.getBrowserName(), '--language-binding', 'javascript', '--output', 'json']

if (options.getBrowserVersion() && options.getBrowserVersion() !== '') {
args.push('--browser-version', options.getBrowserVersion())
}

const vendorOptions =
options.get('goog:chromeOptions') || options.get('ms:edgeOptions') || options.get('moz:firefoxOptions')
if (vendorOptions && vendorOptions.binary && vendorOptions.binary !== '') {
args.push('--browser-path', path.resolve(vendorOptions.binary))
}

const proxyOptions = options.getProxy()

// Check if proxyOptions exists and has properties
if (proxyOptions && Object.keys(proxyOptions).length > 0) {
const httpProxy = proxyOptions['httpProxy']
const sslProxy = proxyOptions['sslProxy']

if (httpProxy !== undefined) {
args.push('--proxy', httpProxy)
} else if (sslProxy !== undefined) {
args.push('--proxy', sslProxy)
}
}
return args
}

// PUBLIC API
module.exports = { getPath }
module.exports = { getBinaryPaths }
38 changes: 3 additions & 35 deletions javascript/node/selenium-webdriver/common/seleniumManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const { platform } = require('node:process')
const path = require('node:path')
const fs = require('node:fs')
const spawnSync = require('node:child_process').spawnSync
const { Capability } = require('../lib/capabilities')
const logging = require('../lib/logging')

const log_ = logging.getLogger(logging.Type.DRIVER)
Expand Down Expand Up @@ -63,38 +62,12 @@ function getBinary() {

/**
* Determines the path of the correct driver
* @param {Capabilities} options browser options to fetch the driver
* @param {string[]} args arguments to invoke Selenium Manager
* @returns {{browserPath: string, driverPath: string}} path of the driver and
* browser location
*/

function driverLocation(options) {
let args = ['--browser', options.getBrowserName(), '--language-binding', 'javascript', '--output', 'json']

if (options.getBrowserVersion() && options.getBrowserVersion() !== '') {
args.push('--browser-version', options.getBrowserVersion())
}

const vendorOptions =
options.get('goog:chromeOptions') || options.get('ms:edgeOptions') || options.get('moz:firefoxOptions')
if (vendorOptions && vendorOptions.binary && vendorOptions.binary !== '') {
args.push('--browser-path', path.resolve(vendorOptions.binary))
}

const proxyOptions = options.getProxy()

// Check if proxyOptions exists and has properties
if (proxyOptions && Object.keys(proxyOptions).length > 0) {
const httpProxy = proxyOptions['httpProxy']
const sslProxy = proxyOptions['sslProxy']

if (httpProxy !== undefined) {
args.push('--proxy', httpProxy)
} else if (sslProxy !== undefined) {
args.push('--proxy', sslProxy)
}
}

function binaryPaths(args) {
const smBinary = getBinary()
const spawnResult = spawnSync(smBinary, args)
let output
Expand All @@ -120,11 +93,6 @@ function driverLocation(options) {
throw new Error(`Error executing command for ${smBinary} with ${args}: ${e.toString()}`)
}

// Once driverPath is available, delete browserVersion from payload
if (output.result.driver_path) {
options.delete(Capability.BROWSER_VERSION)
}

logOutput(output)
return {
driverPath: output.result.driver_path,
Expand All @@ -144,4 +112,4 @@ function logOutput(output) {
}

// PUBLIC API
module.exports = { driverLocation }
module.exports = { binaryPaths }
9 changes: 5 additions & 4 deletions javascript/node/selenium-webdriver/firefox.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ const io = require('./io')
const remote = require('./remote')
const webdriver = require('./lib/webdriver')
const zip = require('./io/zip')
const { Browser, Capabilities } = require('./lib/capabilities')
const { Browser, Capabilities, Capability } = require('./lib/capabilities')
const { Zip } = require('./io/zip')
const { getPath } = require('./common/driverFinder')
const { getBinaryPaths } = require('./common/driverFinder')
const FIREFOX_CAPABILITY_KEY = 'moz:firefoxOptions'

/**
Expand Down Expand Up @@ -541,7 +541,7 @@ class Driver extends webdriver.WebDriver {
configureExecutor(executor)
} else if (opt_executor instanceof remote.DriverService) {
if (!opt_executor.getExecutable()) {
const { driverPath, browserPath } = getPath(caps)
const { driverPath, browserPath } = getBinaryPaths(caps)
opt_executor.setExecutable(driverPath)
firefoxBrowserPath = browserPath
}
Expand All @@ -550,7 +550,7 @@ class Driver extends webdriver.WebDriver {
} else {
let service = new ServiceBuilder().build()
if (!service.getExecutable()) {
const { driverPath, browserPath } = getPath(caps)
const { driverPath, browserPath } = getBinaryPaths(caps)
service.setExecutable(driverPath)
firefoxBrowserPath = browserPath
}
Expand All @@ -566,6 +566,7 @@ class Driver extends webdriver.WebDriver {
} else {
caps.set(FIREFOX_CAPABILITY_KEY, { binary: firefoxBrowserPath })
}
caps.delete(Capability.BROWSER_VERSION)
}

return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit))
Expand Down

0 comments on commit 2a37565

Please sign in to comment.