Skip to content

Commit

Permalink
Merge branch 'trunk' into https
Browse files Browse the repository at this point in the history
Signed-off-by: Viet Nguyen Duc <[email protected]>
  • Loading branch information
VietND96 committed Jan 9, 2024
2 parents c9d4440 + 4b6af2e commit 10d83bb
Show file tree
Hide file tree
Showing 23 changed files with 2,868 additions and 2,419 deletions.
75 changes: 47 additions & 28 deletions java/src/org/openqa/selenium/bidi/script/RemoteValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,38 +193,57 @@ private Map<String, Object> toJson() {
}

private static Object deserializeValue(Object value, Type type) {

if (Type.ARRAY.equals(type) || Type.SET.equals(type)) {
try (StringReader reader = new StringReader(JSON.toJson(value));
JsonInput input = JSON.newInput(reader)) {
value = input.read(new TypeToken<List<RemoteValue>>() {}.getType());
}
} else if (Type.MAP.equals(type) || Type.OBJECT.equals(type)) {
List<List<Object>> result = (List<List<Object>>) value;
Map<Object, RemoteValue> map = new HashMap<>();

for (List<Object> list : result) {
Object key = list.get(0);
if (!(key instanceof String)) {
try (StringReader reader = new StringReader(JSON.toJson(key));
JsonInput keyInput = JSON.newInput(reader)) {
key = keyInput.read(RemoteValue.class);
Object finalValue;

switch (type) {
case ARRAY:
case SET:
try (StringReader reader = new StringReader(JSON.toJson(value));
JsonInput input = JSON.newInput(reader)) {
finalValue = input.read(new TypeToken<List<RemoteValue>>() {}.getType());
}
break;

case MAP:
case OBJECT:
List<List<Object>> result = (List<List<Object>>) value;
Map<Object, RemoteValue> map = new HashMap<>();

for (List<Object> list : result) {
Object key = list.get(0);
if (!(key instanceof String)) {
try (StringReader reader = new StringReader(JSON.toJson(key));
JsonInput keyInput = JSON.newInput(reader)) {
key = keyInput.read(RemoteValue.class);
}
}
try (StringReader reader = new StringReader(JSON.toJson(list.get(1)));
JsonInput valueInput = JSON.newInput(reader)) {
RemoteValue value1 = valueInput.read(RemoteValue.class);
map.put(key, value1);
}
}
try (StringReader reader = new StringReader(JSON.toJson(list.get(1)));
JsonInput valueInput = JSON.newInput(reader)) {
RemoteValue value1 = valueInput.read(RemoteValue.class);
map.put(key, value1);
finalValue = map;
break;

case REGULAR_EXPRESSION:
try (StringReader reader = new StringReader(JSON.toJson(value));
JsonInput input = JSON.newInput(reader)) {
finalValue = input.read(RegExpValue.class);
}
}
value = map;
} else if (Type.REGULAR_EXPRESSION.equals(type)) {
try (StringReader reader = new StringReader(JSON.toJson(value));
JsonInput input = JSON.newInput(reader)) {
value = input.read(RegExpValue.class);
}
break;

case WINDOW:
try (StringReader reader = new StringReader(JSON.toJson(value));
JsonInput input = JSON.newInput(reader)) {
finalValue = input.read(WindowProxyProperties.class);
}
break;

default:
finalValue = value;
}

return value;
return finalValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.openqa.selenium.bidi.script;

import org.openqa.selenium.json.JsonInput;

public class WindowProxyProperties {

private final String browsingContext;

private WindowProxyProperties(String browsingContext) {
this.browsingContext = browsingContext;
}

public static WindowProxyProperties fromJson(JsonInput input) {
String browsingContext = null;

input.beginObject();
while (input.hasNext()) {
switch (input.nextName()) {
case "context":
browsingContext = input.read(String.class);
break;

default:
input.skipValue();
break;
}
}

input.endObject();

return new WindowProxyProperties(browsingContext);
}

public String getBrowsingContext() {
return browsingContext;
}
}
2 changes: 1 addition & 1 deletion java/src/org/openqa/selenium/grid/commands/Standalone.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ protected Handlers createHandlers(Config config) {
httpHandler = combine(httpHandler, Route.get("/readyz").to(() -> readinessCheck));
Node node = createNode(config, bus, distributor, combinedHandler);

return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node));
return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node, subPath));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ java_library(
"//java/src/org/openqa/selenium/grid/data",
"//java/src/org/openqa/selenium/grid/distributor",
"//java/src/org/openqa/selenium/grid/distributor/selector",
"//java/src/org/openqa/selenium/grid/server",
artifact("com.beust:jcommander"),
],
)
12 changes: 7 additions & 5 deletions java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,20 @@ public class ProxyNodeWebsockets
ImmutableSet.of("goog:chromeOptions", "moz:debuggerAddress", "ms:edgeOptions");
private final HttpClient.Factory clientFactory;
private final Node node;
private final String gridSubPath;

public ProxyNodeWebsockets(HttpClient.Factory clientFactory, Node node) {
public ProxyNodeWebsockets(HttpClient.Factory clientFactory, Node node, String gridSubPath) {
this.clientFactory = Objects.requireNonNull(clientFactory);
this.node = Objects.requireNonNull(node);
this.gridSubPath = gridSubPath;
}

@Override
public Optional<Consumer<Message>> apply(String uri, Consumer<Message> downstream) {
UrlTemplate.Match fwdMatch = FWD_TEMPLATE.match(uri);
UrlTemplate.Match cdpMatch = CDP_TEMPLATE.match(uri);
UrlTemplate.Match bidiMatch = BIDI_TEMPLATE.match(uri);
UrlTemplate.Match vncMatch = VNC_TEMPLATE.match(uri);
UrlTemplate.Match fwdMatch = FWD_TEMPLATE.match(uri, gridSubPath);
UrlTemplate.Match cdpMatch = CDP_TEMPLATE.match(uri, gridSubPath);
UrlTemplate.Match bidiMatch = BIDI_TEMPLATE.match(uri, gridSubPath);
UrlTemplate.Match vncMatch = VNC_TEMPLATE.match(uri, gridSubPath);

if (bidiMatch == null && cdpMatch == null && vncMatch == null && fwdMatch == null) {
return Optional.empty();
Expand Down
15 changes: 15 additions & 0 deletions java/src/org/openqa/selenium/grid/node/config/NodeOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,21 @@ public boolean isManagedDownloadsEnabled() {
return config.getBool(NODE_SECTION, "enable-managed-downloads").orElse(Boolean.FALSE);
}

public String getGridSubPath() {
return normalizeSubPath(getPublicGridUri().map(URI::getPath).orElse(""));
}

public static String normalizeSubPath(String prefix) {
prefix = prefix.trim();
if (!prefix.startsWith("/")) {
prefix = "/" + prefix; // Prefix with a '/' if absent.
}
if (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length() - 1); // Remove the trailing '/' if present.
}
return prefix;
}

public Node getNode() {
return config.getClass(NODE_SECTION, "implementation", Node.class, DEFAULT_NODE_IMPLEMENTATION);
}
Expand Down
3 changes: 2 additions & 1 deletion java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ protected Handlers createHandlers(Config config) {

Route httpHandler = Route.combine(node, get("/readyz").to(() -> readinessCheck));

return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node));
return new Handlers(
httpHandler, new ProxyNodeWebsockets(clientFactory, node, nodeOptions.getGridSubPath()));
}

@Override
Expand Down
4 changes: 1 addition & 3 deletions java/src/org/openqa/selenium/grid/node/local/LocalNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -838,9 +838,7 @@ private Session createExternalSession(
private URI rewrite(String path) {
try {
String scheme = "https".equals(gridUri.getScheme()) ? "wss" : "ws";
if (gridUri.getPath() != null && !gridUri.getPath().equals("/")) {
path = gridUri.getPath() + path;
}
path = NodeOptions.normalizeSubPath(gridUri.getPath()) + path;
return new URI(
scheme, gridUri.getUserInfo(), gridUri.getHost(), gridUri.getPort(), path, null, null);
} catch (URISyntaxException e) {
Expand Down
13 changes: 10 additions & 3 deletions java/src/org/openqa/selenium/grid/security/SecretOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.grid.config.Config;
import org.openqa.selenium.grid.config.ConfigException;
import org.openqa.selenium.grid.server.BaseServerOptions;

public class SecretOptions {

Expand All @@ -42,8 +41,7 @@ public SecretOptions(Config config) {

public Secret getRegistrationSecret() {
String secret = "";
BaseServerOptions serverOptions = new BaseServerOptions(config);
if ((serverOptions.isSecure() || serverOptions.isSelfSigned())
if ((isSecure() || isSelfSigned())
&& !config.get(SERVER_SECTION, "registration-secret").isPresent()) {
try {
secret =
Expand Down Expand Up @@ -72,6 +70,15 @@ public UsernameAndPassword getServerAuthentication() {
return new UsernameAndPassword(username.get(), password.get());
}

private boolean isSecure() {
return config.get(SERVER_SECTION, "https-private-key").isPresent()
&& config.get(SERVER_SECTION, "https-certificate").isPresent();
}

private boolean isSelfSigned() {
return config.getBool(SERVER_SECTION, "https-self-signed").orElse(false);
}

private File getCertificate() {
String certificatePath = config.get(SERVER_SECTION, "https-certificate").orElse(null);
if (certificatePath != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ java_library(
"//java:auto-service",
"//java/src/org/openqa/selenium/grid/config",
"//java/src/org/openqa/selenium/grid/sessionmap",
"//java/src/org/openqa/selenium/grid/server",
artifact("com.beust:jcommander"),
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ java_library(
"//java/src/org/openqa/selenium/grid/config",
"//java/src/org/openqa/selenium/grid/jmx",
"//java/src/org/openqa/selenium/grid/sessionqueue",
"//java/src/org/openqa/selenium/grid/server",
artifact("com.beust:jcommander"),
],
)
14 changes: 14 additions & 0 deletions java/src/org/openqa/selenium/remote/http/UrlTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ public UrlTemplate.Match match(String matchAgainst) {
return compiled.apply(matchAgainst);
}

/**
* @return A {@link Match} with all parameters filled if successful, null otherwise. Remove
* subPath from matchAgainst before matching.
*/
public UrlTemplate.Match match(String matchAgainst, String prefix) {
if (matchAgainst == null || prefix == null) {
return null;
}
if (!prefix.isEmpty() && !prefix.equals("/")) {
matchAgainst = matchAgainst.replaceFirst(prefix, "");
}
return match(matchAgainst);
}

@SuppressWarnings("InnerClassMayBeStatic")
public class Match {
private final String url;
Expand Down
38 changes: 38 additions & 0 deletions java/test/org/openqa/selenium/bidi/script/ScriptCommandsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.LogInspector;
Expand Down Expand Up @@ -114,6 +115,43 @@ void canCallFunctionWithArguments() {
assertThat(((List<Object>) successResult.getResult().getValue().get()).size()).isEqualTo(2);
}

@Test
@NotYetImplemented(SAFARI)
@NotYetImplemented(IE)
@NotYetImplemented(EDGE)
@NotYetImplemented(CHROME)
void canCallFunctionToGetIFrameBrowsingContext() {
String url = appServer.whereIs("click_too_big_in_frame.html");
driver.get(url);

driver.findElement(By.id("iframe1"));

String id = driver.getWindowHandle();
Script script = new Script(id, driver);

List<LocalValue> arguments = new ArrayList<>();

EvaluateResult result =
script.callFunctionInBrowsingContext(
id,
"() => document.querySelector('iframe[id=\"iframe1\"]').contentWindow",
false,
Optional.of(arguments),
Optional.empty(),
Optional.empty());

assertThat(result.getResultType()).isEqualTo(EvaluateResult.Type.SUCCESS);
assertThat(result.getRealmId()).isNotNull();

EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
assertThat(successResult.getResult().getType()).isEqualTo("window");
assertThat(successResult.getResult().getValue().isPresent()).isTrue();
assertThat(
((WindowProxyProperties) successResult.getResult().getValue().get())
.getBrowsingContext())
.isNotNull();
}

@Test
@NotYetImplemented(SAFARI)
@NotYetImplemented(IE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,28 @@ void settingTheHubWithDefaultValueSetsTheGridUrlToTheNonLoopbackAddress() {
.isEqualTo(Optional.of(URI.create(nonLoopbackAddressUrl)));
}

@Test
void settingSubPathForNodeServerExtractFromGridUrl() {
String[] rawConfig =
new String[] {
"[node]", "grid-url = \"http://localhost:4444/mySubPath\"",
};
Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig)));
NodeOptions nodeOptions = new NodeOptions(config);
assertThat(nodeOptions.getGridSubPath()).isEqualTo("/mySubPath");
}

@Test
void settingSubPathForNodeServerExtractFromHub() {
String[] rawConfig =
new String[] {
"[node]", "hub = \"http://0.0.0.0:4444/mySubPath\"",
};
Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig)));
NodeOptions nodeOptions = new NodeOptions(config);
assertThat(nodeOptions.getGridSubPath()).isEqualTo("/mySubPath");
}

@Test
void notSettingSlotMatcherAvailable() {
String[] rawConfig =
Expand Down
Loading

0 comments on commit 10d83bb

Please sign in to comment.