diff --git a/java/src/org/openqa/selenium/grid/node/relay/RelayFlags.java b/java/src/org/openqa/selenium/grid/node/relay/RelayFlags.java index d0b8a4ca927b0..70450c777e1b3 100644 --- a/java/src/org/openqa/selenium/grid/node/relay/RelayFlags.java +++ b/java/src/org/openqa/selenium/grid/node/relay/RelayFlags.java @@ -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 getRoles() { return Collections.singleton(NODE_ROLE); diff --git a/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java b/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java index 9325942aeb90e..28cbef2cd2c8d 100644 --- a/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java +++ b/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java @@ -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; @@ -103,6 +104,21 @@ public URI getServiceStatusUri() { } } + public String getServiceProtocolVersion() { + String protocolVersion = config.get(RELAY_SECTION, "protocol-version").orElse(""); + if (protocolVersion.isEmpty()) { + return protocolVersion; + } else { + // Support input in the form of "http/1.1" or "HTTP/1.1" + protocolVersion = protocolVersion.toUpperCase().replaceAll("/", "_").replaceAll("\\.", "_"); + } + try { + return Version.valueOf(protocolVersion).toString(); + } catch (IllegalArgumentException e) { + throw new ConfigException("Unable to determine the service protocol version", e); + } + } + // Method being used in SessionSlot @SuppressWarnings("unused") private boolean isServiceUp(HttpClient client) { @@ -160,6 +176,7 @@ public Map> getSessionFactories( sessionTimeout, getServiceUri(), getServiceStatusUri(), + getServiceProtocolVersion(), immutable)); } LOG.info(String.format("Mapping %s, %d times", immutable, maxSessions)); diff --git a/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java b/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java index 4312b6b379dc4..5818335af3cdd 100644 --- a/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java +++ b/java/src/org/openqa/selenium/grid/node/relay/RelaySessionFactory.java @@ -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( @@ -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)); } @@ -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)); diff --git a/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java b/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java index fe6783745fcc0..c48f79f54d888 100644 --- a/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java +++ b/java/test/org/openqa/selenium/grid/node/relay/RelayOptionsTest.java @@ -95,6 +95,54 @@ 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(); + }); + } + @Test void missingConfigsThrowsConfigException() { String[] rawConfig =