diff --git a/java/src/org/openqa/selenium/remote/BUILD.bazel b/java/src/org/openqa/selenium/remote/BUILD.bazel index b4e98e1f9561a..4556e6c86192e 100644 --- a/java/src/org/openqa/selenium/remote/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/BUILD.bazel @@ -55,7 +55,7 @@ java_library( "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/manager", "//java/src/org/openqa/selenium/os", - "//java/src/org/openqa/selenium/remote/http/netty", + "//java/src/org/openqa/selenium/remote/http/jdk", "//java/src/org/openqa/selenium/remote/tracing", "//java/src/org/openqa/selenium/remote/tracing/opentelemetry", "//java/src/org/openqa/selenium/support/decorators", diff --git a/java/src/org/openqa/selenium/remote/http/HttpClient.java b/java/src/org/openqa/selenium/remote/http/HttpClient.java index 926051306c07b..ce593c9b82132 100644 --- a/java/src/org/openqa/selenium/remote/http/HttpClient.java +++ b/java/src/org/openqa/selenium/remote/http/HttpClient.java @@ -71,7 +71,7 @@ static Factory create(String name) { *

{@see create} */ static Factory createDefault() { - return create(System.getProperty("webdriver.http.factory", "netty")); + return create("jdk-http-client"); } /** diff --git a/java/src/org/openqa/selenium/remote/http/jdk/BUILD.bazel b/java/src/org/openqa/selenium/remote/http/jdk/BUILD.bazel index 4679882dcdbc7..10ffa44fcb45d 100644 --- a/java/src/org/openqa/selenium/remote/http/jdk/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/http/jdk/BUILD.bazel @@ -1,17 +1,12 @@ -load("//java:defs.bzl", "java_export") -load("//java:version.bzl", "SE_VERSION") +load("@rules_jvm_external//:defs.bzl", "artifact") +load("//java:defs.bzl", "java_library") -java_export( +java_library( name = "jdk", srcs = glob(["*.java"]), - javacopts = [ - "--release", - "11", # Deliberately targeting Java 11 for widest possible support - ], - maven_coordinates = "org.seleniumhq.selenium:selenium-http-jdk-client:%s" % SE_VERSION, - pom_template = "//java/src/org/openqa/selenium:template-pom", visibility = [ - "//visibility:public", + "//java/src/org/openqa/selenium/remote:__pkg__", + "//java/test/org/openqa/selenium/remote/http:__subpackages__", ], deps = [ "//java:auto-service", diff --git a/java/src/org/openqa/selenium/remote/http/netty/BUILD.bazel b/java/src/org/openqa/selenium/remote/http/netty/BUILD.bazel deleted file mode 100644 index 21fbc3f7518cf..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/BUILD.bazel +++ /dev/null @@ -1,31 +0,0 @@ -load("@rules_jvm_external//:defs.bzl", "artifact") -load("//java:defs.bzl", "java_library") - -java_library( - name = "netty", - srcs = glob(["*.java"]), - visibility = [ - "//java/src/org/openqa/selenium/remote:__pkg__", - "//java/test/org/openqa/selenium/remote/http:__subpackages__", - ], - deps = [ - "//java:auto-service", - "//java/src/org/openqa/selenium:core", - "//java/src/org/openqa/selenium/remote/http", - artifact("com.google.guava:guava"), - # artifact("com.typesafe.netty:netty-reactive-streams"), - artifact("org.asynchttpclient:async-http-client"), - artifact("io.netty:netty-buffer"), - artifact("io.netty:netty-codec-http"), - artifact("io.netty:netty-transport"), - artifact("io.netty:netty-transport-classes-epoll"), - artifact("io.netty:netty-transport-classes-kqueue"), - artifact("io.netty:netty-transport-native-epoll"), - artifact("io.netty:netty-transport-native-epoll-linux-x86_64"), - artifact("io.netty:netty-transport-native-kqueue"), - artifact("io.netty:netty-transport-native-kqueue-osx-aarch_64"), - artifact("io.netty:netty-transport-native-kqueue-osx-x86_64"), - artifact("io.netty:netty-transport-native-unix-common"), - artifact("io.netty:netty-common"), - ], -) diff --git a/java/src/org/openqa/selenium/remote/http/netty/NettyClient.java b/java/src/org/openqa/selenium/remote/http/netty/NettyClient.java deleted file mode 100644 index 363690847da5b..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/NettyClient.java +++ /dev/null @@ -1,127 +0,0 @@ -// 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.remote.http.netty; - -import com.google.auto.service.AutoService; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; -import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.function.BiFunction; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.DefaultAsyncHttpClientConfig; -import org.asynchttpclient.Dsl; -import org.asynchttpclient.config.AsyncHttpClientConfigDefaults; -import org.openqa.selenium.internal.Require; -import org.openqa.selenium.remote.http.ClientConfig; -import org.openqa.selenium.remote.http.HttpClient; -import org.openqa.selenium.remote.http.HttpClientName; -import org.openqa.selenium.remote.http.HttpHandler; -import org.openqa.selenium.remote.http.HttpRequest; -import org.openqa.selenium.remote.http.HttpResponse; -import org.openqa.selenium.remote.http.WebSocket; - -public class NettyClient implements HttpClient { - - private static final Timer TIMER; - private static final AsyncHttpClient client = createHttpClient(ClientConfig.defaultConfig()); - - static { - ThreadFactory threadFactory = new DefaultThreadFactory("netty-client-timer", true); - TIMER = - new HashedWheelTimer( - threadFactory, - AsyncHttpClientConfigDefaults.defaultHashedWheelTimerTickDuration(), - TimeUnit.MILLISECONDS, - AsyncHttpClientConfigDefaults.defaultHashedWheelTimerSize()); - } - - private final ClientConfig config; - private final HttpHandler handler; - private final BiFunction toWebSocket; - - private NettyClient(ClientConfig config) { - this.config = Require.nonNull("HTTP client config", config); - this.handler = new NettyHttpHandler(config, client); - this.toWebSocket = NettyWebSocket.create(config, client); - } - - /** - * Converts a long to an int, clamping the maximum and minimum values to fit in an integer without - * overflowing. - */ - static int toClampedInt(long value) { - return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, value)); - } - - private static AsyncHttpClient createHttpClient(ClientConfig config) { - DefaultAsyncHttpClientConfig.Builder builder = - new DefaultAsyncHttpClientConfig.Builder() - .setThreadFactory(new DefaultThreadFactory("AsyncHttpClient", true)) - .setUseInsecureTrustManager(true) - .setAggregateWebSocketFrameFragments(true) - .setWebSocketMaxBufferSize(Integer.MAX_VALUE) - .setWebSocketMaxFrameSize(Integer.MAX_VALUE) - .setNettyTimer(TIMER) - .setRequestTimeout(toClampedInt(config.readTimeout().toMillis())) - .setConnectTimeout(toClampedInt(config.connectionTimeout().toMillis())) - .setReadTimeout(toClampedInt(config.readTimeout().toMillis())) - .setFollowRedirect(true) - .setMaxRedirects(100) - .setUseProxyProperties(true) - .setUseProxySelector(true) - .setMaxRequestRetry(0); - - return Dsl.asyncHttpClient(builder); - } - - @Override - public HttpResponse execute(HttpRequest request) { - return handler.execute(request); - } - - @Override - public WebSocket openSocket(HttpRequest request, WebSocket.Listener listener) { - Require.nonNull("Request to send", request); - Require.nonNull("WebSocket listener", listener); - - return toWebSocket.apply(request, listener); - } - - @Override - public void close() { - // no-op -- closing the client when the JVM shuts down - } - - @AutoService(HttpClient.Factory.class) - @HttpClientName("netty") - public static class Factory implements HttpClient.Factory { - - @Override - public HttpClient createClient(ClientConfig config) { - Require.nonNull("Client config", config); - - if (config.baseUri() != null && "unix".equals(config.baseUri().getScheme())) { - return new NettyDomainSocketClient(config); - } - - return new NettyClient(config); - } - } -} diff --git a/java/src/org/openqa/selenium/remote/http/netty/NettyDomainSocketClient.java b/java/src/org/openqa/selenium/remote/http/netty/NettyDomainSocketClient.java deleted file mode 100644 index 8bceb93195b69..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/NettyDomainSocketClient.java +++ /dev/null @@ -1,234 +0,0 @@ -// 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.remote.http.netty; - -import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.openqa.selenium.remote.http.Contents.bytes; -import static org.openqa.selenium.remote.http.Contents.utf8String; - -import com.google.common.base.Joiner; -import com.google.common.base.Throwables; -import com.google.common.io.ByteStreams; -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.channel.epoll.Epoll; -import io.netty.channel.epoll.EpollDomainSocketChannel; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.kqueue.KQueue; -import io.netty.channel.kqueue.KQueueDomainSocketChannel; -import io.netty.channel.kqueue.KQueueEventLoopGroup; -import io.netty.channel.unix.DomainSocketAddress; -import io.netty.channel.unix.UnixChannel; -import io.netty.handler.codec.http.DefaultFullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpContentDecompressor; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaderValues; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpVersion; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; -import org.openqa.selenium.internal.Require; -import org.openqa.selenium.remote.http.AddSeleniumUserAgent; -import org.openqa.selenium.remote.http.ClientConfig; -import org.openqa.selenium.remote.http.HttpClient; -import org.openqa.selenium.remote.http.HttpRequest; -import org.openqa.selenium.remote.http.HttpResponse; -import org.openqa.selenium.remote.http.RemoteCall; -import org.openqa.selenium.remote.http.WebSocket; - -class NettyDomainSocketClient extends RemoteCall implements HttpClient { - - private final EventLoopGroup eventLoopGroup; - private final Class channelClazz; - private final String path; - - public NettyDomainSocketClient(ClientConfig config) { - super(config); - URI uri = config.baseUri(); - Require.argument("URI scheme", uri.getScheme()).equalTo("unix"); - - if (Epoll.isAvailable()) { - this.eventLoopGroup = new EpollEventLoopGroup(); - this.channelClazz = EpollDomainSocketChannel.class; - } else if (KQueue.isAvailable()) { - this.eventLoopGroup = new KQueueEventLoopGroup(); - this.channelClazz = KQueueDomainSocketChannel.class; - } else { - throw new IllegalStateException("No native library for unix domain sockets is available"); - } - - this.path = uri.getPath(); - } - - @Override - public HttpResponse execute(HttpRequest req) throws UncheckedIOException { - Require.nonNull("Request to send", req); - - AtomicReference outRef = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - Channel channel = createChannel(outRef, latch); - - StringBuilder uri = new StringBuilder(req.getUri()); - List queryPairs = new ArrayList<>(); - req.getQueryParameterNames() - .forEach( - name -> - req.getQueryParameters(name) - .forEach( - value -> { - try { - queryPairs.add( - URLEncoder.encode(name, UTF_8.toString()) - + "=" - + URLEncoder.encode(value, UTF_8.toString())); - } catch (UnsupportedEncodingException e) { - Thread.currentThread().interrupt(); - throw new UncheckedIOException(e); - } - })); - if (!queryPairs.isEmpty()) { - uri.append("?"); - Joiner.on('&').appendTo(uri, queryPairs); - } - - byte[] bytes = bytes(req.getContent()); - - DefaultFullHttpRequest fullRequest = - new DefaultFullHttpRequest( - HttpVersion.HTTP_1_1, - HttpMethod.valueOf(req.getMethod().toString()), - uri.toString(), - Unpooled.wrappedBuffer(bytes)); - req.forEachHeader(fullRequest.headers()::add); - if (req.getHeader("User-Agent") == null) { - fullRequest.headers().set("User-Agent", AddSeleniumUserAgent.USER_AGENT); - } - fullRequest.headers().set(HttpHeaderNames.HOST, "localhost"); - fullRequest.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE); - fullRequest.headers().set(HttpHeaderNames.CONTENT_LENGTH, bytes.length); - - ChannelFuture future = channel.writeAndFlush(fullRequest); - - try { - future.get(); - channel.closeFuture().sync(); - } catch (InterruptedException | ExecutionException e) { - Thread.currentThread().interrupt(); - throw new UncheckedIOException(new IOException(e)); - } - - try { - if (!latch.await(getConfig().readTimeout().toMillis(), MILLISECONDS)) { - throw new UncheckedIOException(new IOException("Timed out waiting for response")); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - - return outRef.get(); - } - - @Override - public WebSocket openSocket(HttpRequest request, WebSocket.Listener listener) { - throw new UnsupportedOperationException("openSocket"); - } - - private Channel createChannel(AtomicReference outRef, CountDownLatch latch) { - Bootstrap bootstrap = - new Bootstrap() - .group(eventLoopGroup) - .channel(channelClazz) - .handler( - new ChannelInitializer() { - @Override - public void initChannel(UnixChannel ch) { - ch.pipeline() - .addLast(new HttpClientCodec()) - .addLast(new HttpContentDecompressor()) - .addLast(new HttpObjectAggregator(Integer.MAX_VALUE)) - .addLast( - new SimpleChannelInboundHandler() { - @Override - public void channelRead0( - ChannelHandlerContext ctx, FullHttpResponse msg) { - HttpResponse res = - new HttpResponse().setStatus(msg.status().code()); - msg.headers() - .forEach( - entry -> res.addHeader(entry.getKey(), entry.getValue())); - - try (InputStream is = new ByteBufInputStream(msg.content()); - ByteArrayOutputStream bos = new ByteArrayOutputStream()) { - ByteStreams.copy(is, bos); - res.setContent(bytes(bos.toByteArray())); - outRef.set(res); - latch.countDown(); - } catch (IOException e) { - outRef.set( - new HttpResponse() - .setStatus(HTTP_INTERNAL_ERROR) - .setContent( - utf8String(Throwables.getStackTraceAsString(e)))); - latch.countDown(); - } - } - - @Override - public void exceptionCaught( - ChannelHandlerContext ctx, Throwable cause) { - outRef.set( - new HttpResponse() - .setStatus(HTTP_INTERNAL_ERROR) - .setContent( - utf8String(Throwables.getStackTraceAsString(cause)))); - latch.countDown(); - } - }); - } - }); - try { - return bootstrap.connect(new DomainSocketAddress(path)).sync().channel(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } -} diff --git a/java/src/org/openqa/selenium/remote/http/netty/NettyHttpHandler.java b/java/src/org/openqa/selenium/remote/http/netty/NettyHttpHandler.java deleted file mode 100644 index b5fd588eeb22f..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/NettyHttpHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -// 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.remote.http.netty; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.Response; -import org.openqa.selenium.internal.Require; -import org.openqa.selenium.remote.http.ClientConfig; -import org.openqa.selenium.remote.http.HttpHandler; -import org.openqa.selenium.remote.http.HttpRequest; -import org.openqa.selenium.remote.http.HttpResponse; -import org.openqa.selenium.remote.http.RemoteCall; - -public class NettyHttpHandler extends RemoteCall { - - private final HttpHandler handler; - private final AsyncHttpClient client; - - public NettyHttpHandler(ClientConfig config, AsyncHttpClient client) { - super(config); - this.client = client; - this.handler = config.filter().andFinally(this::makeCall); - } - - @Override - public HttpResponse execute(HttpRequest request) { - return handler.execute(request); - } - - private HttpResponse makeCall(HttpRequest request) { - Require.nonNull("Request", request); - - Future whenResponse = - client.executeRequest(NettyMessages.toNettyRequest(getConfig(), request)); - - try { - Response response = - whenResponse.get(getConfig().readTimeout().toMillis(), TimeUnit.MILLISECONDS); - return NettyMessages.toSeleniumResponse(response); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("NettyHttpHandler request interrupted", e); - } catch (TimeoutException e) { - throw new org.openqa.selenium.TimeoutException(e); - } catch (ExecutionException e) { - Throwable cause = e.getCause(); - if (cause instanceof UncheckedIOException) { - throw (UncheckedIOException) cause; - } - - if (cause instanceof IOException) { - throw new UncheckedIOException((IOException) cause); - } - - throw new RuntimeException("NettyHttpHandler request execution error", e); - } - } -} diff --git a/java/src/org/openqa/selenium/remote/http/netty/NettyMessages.java b/java/src/org/openqa/selenium/remote/http/netty/NettyMessages.java deleted file mode 100644 index 14af46f076171..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/NettyMessages.java +++ /dev/null @@ -1,146 +0,0 @@ -// 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.remote.http.netty; - -import static org.asynchttpclient.Dsl.request; -import static org.openqa.selenium.remote.http.Contents.empty; -import static org.openqa.selenium.remote.http.Contents.memoize; -import static org.openqa.selenium.remote.http.netty.NettyClient.toClampedInt; - -import com.google.common.base.Strings; -import java.net.InetSocketAddress; -import java.net.URI; -import org.asynchttpclient.Dsl; -import org.asynchttpclient.Realm; -import org.asynchttpclient.Request; -import org.asynchttpclient.RequestBuilder; -import org.asynchttpclient.Response; -import org.asynchttpclient.proxy.ProxyServer; -import org.openqa.selenium.Credentials; -import org.openqa.selenium.UsernameAndPassword; -import org.openqa.selenium.remote.http.AddSeleniumUserAgent; -import org.openqa.selenium.remote.http.ClientConfig; -import org.openqa.selenium.remote.http.HttpMethod; -import org.openqa.selenium.remote.http.HttpRequest; -import org.openqa.selenium.remote.http.HttpResponse; - -class NettyMessages { - - private NettyMessages() { - // Utility classes. - } - - protected static Request toNettyRequest(ClientConfig config, HttpRequest request) { - - URI baseUrl = config.baseUri(); - int timeout = toClampedInt(config.readTimeout().toMillis()); - Credentials credentials = config.credentials(); - - String rawUrl = getRawUrl(baseUrl, request.getUri()); - - RequestBuilder builder = - request(request.getMethod().toString(), rawUrl) - .setReadTimeout(timeout) - .setRequestTimeout(timeout); - - for (String name : request.getQueryParameterNames()) { - for (String value : request.getQueryParameters(name)) { - builder.addQueryParam(name, value); - } - } - - // Netty tends to timeout when a GET request has a 'Content-Length' header - if (request.getMethod().equals(HttpMethod.GET) && request.getHeader("Content-Length") != null) { - request.removeHeader("Content-Length"); - } - - request.forEachHeader(builder::addHeader); - if (request.getHeader("User-Agent") == null) { - builder.addHeader("User-Agent", AddSeleniumUserAgent.USER_AGENT); - } - - Realm.Builder realmBuilder = null; - String info = baseUrl.getUserInfo(); - if (!Strings.isNullOrEmpty(info)) { - String[] parts = info.split(":", 2); - String user = parts[0]; - String pass = parts.length > 1 ? parts[1] : null; - realmBuilder = Dsl.basicAuthRealm(user, pass).setUsePreemptiveAuth(true); - builder.setRealm(realmBuilder); - } else if (credentials != null) { - if (!(credentials instanceof UsernameAndPassword)) { - throw new IllegalArgumentException("Credentials must be a user name and password"); - } - UsernameAndPassword uap = (UsernameAndPassword) credentials; - realmBuilder = Dsl.basicAuthRealm(uap.username(), uap.password()).setUsePreemptiveAuth(true); - builder.setRealm(realmBuilder); - } - - if (config.proxy() != null) { - InetSocketAddress address = (InetSocketAddress) config.proxy().address(); - ProxyServer.Builder proxyBuilder = - new ProxyServer.Builder(address.getHostName(), address.getPort()); - if (realmBuilder != null) { - proxyBuilder.setRealm(realmBuilder); - } - builder.setProxyServer(proxyBuilder); - } - - if (request.getMethod().equals(HttpMethod.POST)) { - builder.setBody(request.getContent().get()); - } - - return builder.build(); - } - - public static HttpResponse toSeleniumResponse(Response response) { - HttpResponse toReturn = new HttpResponse(); - - toReturn.setStatus(response.getStatusCode()); - - toReturn.setContent( - !response.hasResponseBody() ? empty() : memoize(response::getResponseBodyAsStream)); - - response - .getHeaders() - .names() - .forEach( - name -> response.getHeaders(name).forEach(value -> toReturn.addHeader(name, value))); - - return toReturn; - } - - private static String getRawUrl(URI baseUrl, String uri) { - String rawUrl; - if (uri.startsWith("ws://")) { - rawUrl = "http://" + uri.substring("ws://".length()); - } else if (uri.startsWith("wss://")) { - rawUrl = "https://" + uri.substring("wss://".length()); - } else if (uri.startsWith("http://") || uri.startsWith("https://")) { - rawUrl = uri; - } else { - String base = baseUrl.toString(); - if (base.endsWith("/")) { - rawUrl = base.substring(0, base.length() - 1) + uri; - } else { - rawUrl = base + uri; - } - } - return rawUrl; - } -} diff --git a/java/src/org/openqa/selenium/remote/http/netty/NettyWebSocket.java b/java/src/org/openqa/selenium/remote/http/netty/NettyWebSocket.java deleted file mode 100644 index 6e3f07f040208..0000000000000 --- a/java/src/org/openqa/selenium/remote/http/netty/NettyWebSocket.java +++ /dev/null @@ -1,174 +0,0 @@ -// 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.remote.http.netty; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.ListenableFuture; -import org.asynchttpclient.Request; -import org.asynchttpclient.ws.WebSocketListener; -import org.asynchttpclient.ws.WebSocketUpgradeHandler; -import org.openqa.selenium.internal.Require; -import org.openqa.selenium.remote.http.BinaryMessage; -import org.openqa.selenium.remote.http.ClientConfig; -import org.openqa.selenium.remote.http.CloseMessage; -import org.openqa.selenium.remote.http.ConnectionFailedException; -import org.openqa.selenium.remote.http.Filter; -import org.openqa.selenium.remote.http.HttpRequest; -import org.openqa.selenium.remote.http.HttpResponse; -import org.openqa.selenium.remote.http.Message; -import org.openqa.selenium.remote.http.TextMessage; -import org.openqa.selenium.remote.http.WebSocket; - -class NettyWebSocket implements WebSocket { - - private static final Logger LOG = Logger.getLogger(NettyWebSocket.class.getName()); - - private final org.asynchttpclient.ws.WebSocket socket; - - private NettyWebSocket(AsyncHttpClient client, Request request, Listener listener) { - Require.nonNull("HTTP client", client); - Require.nonNull("WebSocket listener", listener); - - try { - URL origUrl = new URL(request.getUrl()); - String wsScheme = "https".equalsIgnoreCase(origUrl.getProtocol()) ? "wss" : "ws"; - - URI wsUri = - new URI( - wsScheme, null, origUrl.getHost(), origUrl.getPort(), origUrl.getPath(), null, null); - ListenableFuture future = - client - .prepareGet(wsUri.toString()) - .execute( - new WebSocketUpgradeHandler.Builder() - .addWebSocketListener( - new WebSocketListener() { - @Override - public void onOpen(org.asynchttpclient.ws.WebSocket websocket) {} - - @Override - public void onClose( - org.asynchttpclient.ws.WebSocket websocket, - int code, - String reason) { - listener.onClose(code, reason); - } - - @Override - public void onError(Throwable t) { - listener.onError(t); - } - - @Override - public void onBinaryFrame( - byte[] payload, boolean finalFragment, int rsv) { - if (payload != null) { - listener.onBinary(payload); - } - } - - @Override - public void onTextFrame( - String payload, boolean finalFragment, int rsv) { - if (payload != null) { - listener.onText(payload); - } - } - }) - .build()); - socket = - future - .toCompletableFuture() - .exceptionally( - t -> { - LOG.log(Level.WARNING, t.getMessage(), t); - return null; - }) - .get(); - - if (socket == null) { - throw new ConnectionFailedException( - "Unable to establish websocket connection to " + request.getUrl()); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.log(Level.WARNING, "NettyWebSocket initial request interrupted", e); - throw new ConnectionFailedException("NettyWebSocket initial request interrupted", e); - } catch (ExecutionException | MalformedURLException | URISyntaxException e) { - throw new ConnectionFailedException("NettyWebSocket initial request execution error", e); - } - } - - static BiFunction create( - ClientConfig config, AsyncHttpClient client) { - Filter filter = config.filter(); - - Function filterRequest = - req -> { - AtomicReference ref = new AtomicReference<>(); - filter - .andFinally( - in -> { - ref.set(in); - return new HttpResponse(); - }) - .execute(req); - return ref.get(); - }; - - return (req, listener) -> { - HttpRequest filtered = filterRequest.apply(req); - Request nettyReq = NettyMessages.toNettyRequest(config, filtered); - return new NettyWebSocket(client, nettyReq, listener); - }; - } - - @Override - public WebSocket send(Message message) { - if (message instanceof BinaryMessage) { - socket.sendBinaryFrame(((BinaryMessage) message).data()); - } else if (message instanceof CloseMessage) { - socket.sendCloseFrame(((CloseMessage) message).code(), ((CloseMessage) message).reason()); - } else if (message instanceof TextMessage) { - socket.sendTextFrame(((TextMessage) message).text()); - } - - return this; - } - - @Override - public WebSocket sendText(CharSequence data) { - socket.sendTextFrame(data.toString()); - return this; - } - - @Override - public void close() { - socket.sendCloseFrame(1000, "WebDriver closing socket"); - } -} diff --git a/java/test/org/openqa/selenium/remote/http/BUILD.bazel b/java/test/org/openqa/selenium/remote/http/BUILD.bazel index d84861402521d..66bb20460f80e 100644 --- a/java/test/org/openqa/selenium/remote/http/BUILD.bazel +++ b/java/test/org/openqa/selenium/remote/http/BUILD.bazel @@ -14,7 +14,7 @@ java_test_suite( "//java:auto-service", "//java/src/org/openqa/selenium:core", "//java/src/org/openqa/selenium/remote/http", - "//java/src/org/openqa/selenium/remote/http/netty", + "//java/src/org/openqa/selenium/remote/http/jdk", "//java/test/org/openqa/selenium/environment", "//java/test/org/openqa/selenium/testing:annotations", artifact("org.assertj:assertj-core"), diff --git a/java/test/org/openqa/selenium/remote/http/netty/BUILD.bazel b/java/test/org/openqa/selenium/remote/http/netty/BUILD.bazel index 066f9cc836f08..3ac9dd14b4a72 100644 --- a/java/test/org/openqa/selenium/remote/http/netty/BUILD.bazel +++ b/java/test/org/openqa/selenium/remote/http/netty/BUILD.bazel @@ -7,7 +7,7 @@ java_test_suite( srcs = glob(["*.java"]), deps = [ "//java/src/org/openqa/selenium/remote/http", - "//java/src/org/openqa/selenium/remote/http/netty", + "//java/src/org/openqa/selenium/remote/http/jdk", "//java/test/org/openqa/selenium/remote/internal:test-lib", "//java/test/org/openqa/selenium/testing:annotations", artifact("org.junit.jupiter:junit-jupiter-api"),