Skip to content

Commit 1c4a214

Browse files
committed
[java] Reworking NettyClient to start a client per session and close the client when quit is called. This also allows to use different ClientConfig-s for different client instances
1 parent 8fcd01a commit 1c4a214

File tree

3 files changed

+41
-33
lines changed

3 files changed

+41
-33
lines changed

java/client/src/org/openqa/selenium/remote/HttpCommandExecutor.java

+1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ public Response execute(Command command) throws IOException {
195195
}
196196
}
197197
if (QUIT.equals(command.getName())) {
198+
client.close();
198199
httpClientFactory.cleanupIdleClients();
199200
}
200201
return response;

java/client/src/org/openqa/selenium/remote/http/HttpClient.java

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.openqa.selenium.remote.http;
1919

20+
import java.io.IOException;
2021
import java.net.URL;
2122
import java.util.ServiceLoader;
2223
import java.util.Set;
@@ -34,6 +35,8 @@ public interface HttpClient extends HttpHandler {
3435

3536
WebSocket openSocket(HttpRequest request, WebSocket.Listener listener);
3637

38+
default void close() throws IOException {}
39+
3740
interface Factory {
3841

3942
/**

java/client/src/org/openqa/selenium/remote/http/netty/NettyClient.java

+37-33
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,42 @@
3232
import org.openqa.selenium.remote.http.HttpResponse;
3333
import org.openqa.selenium.remote.http.WebSocket;
3434

35-
import java.util.concurrent.atomic.AtomicBoolean;
36-
import java.util.function.BiFunction;
3735
import java.io.IOException;
36+
import java.util.function.BiFunction;
3837

3938
public class NettyClient implements HttpClient {
4039

41-
private static final AsyncHttpClient httpClient =
42-
Dsl.asyncHttpClient(
43-
new DefaultAsyncHttpClientConfig.Builder()
44-
.setThreadFactory(new DefaultThreadFactory("AsyncHttpClient", true))
45-
.setUseInsecureTrustManager(true)
46-
.setAggregateWebSocketFrameFragments(true)
47-
.setWebSocketMaxBufferSize(Integer.MAX_VALUE)
48-
.setWebSocketMaxFrameSize(Integer.MAX_VALUE));
49-
40+
private final ClientConfig config;
41+
private final AsyncHttpClient client;
5042
private final HttpHandler handler;
51-
private BiFunction<HttpRequest, WebSocket.Listener, WebSocket> toWebSocket;
43+
private final BiFunction<HttpRequest, WebSocket.Listener, WebSocket> toWebSocket;
5244

53-
private NettyClient(HttpHandler handler, BiFunction<HttpRequest, WebSocket.Listener, WebSocket> toWebSocket) {
54-
this.handler = Require.nonNull("Handler", handler);
55-
this.toWebSocket = Require.nonNull("WebSocket creation function", toWebSocket);
45+
private NettyClient(ClientConfig config) {
46+
this.config = Require.nonNull("HTTP client config", config);
47+
this.client = createHttpClient(config);
48+
this.handler = new NettyHttpHandler(config, this.client).with(config.filter());
49+
this.toWebSocket = NettyWebSocket.create(config, this.client);
50+
}
51+
52+
private AsyncHttpClient createHttpClient(ClientConfig config) {
53+
DefaultAsyncHttpClientConfig.Builder builder =
54+
new DefaultAsyncHttpClientConfig.Builder()
55+
.setThreadFactory(new DefaultThreadFactory("AsyncHttpClient", true))
56+
.setUseInsecureTrustManager(true)
57+
.setAggregateWebSocketFrameFragments(true)
58+
.setWebSocketMaxBufferSize(Integer.MAX_VALUE)
59+
.setWebSocketMaxFrameSize(Integer.MAX_VALUE)
60+
.setConnectTimeout((int) config.connectionTimeout().toMillis());
61+
62+
String info = config.baseUrl().getUserInfo();
63+
if (info != null && !info.equals("")) {
64+
String[] parts = info.split(":", 2);
65+
String user = parts[0];
66+
String pass = parts.length > 1 ? parts[1] : null;
67+
builder.setRealm(Dsl.basicAuthRealm(user, pass).setUsePreemptiveAuth(true).build());
68+
}
69+
70+
return Dsl.asyncHttpClient(builder);
5671
}
5772

5873
@Override
@@ -73,29 +88,18 @@ public HttpClient with(Filter filter) {
7388
Require.nonNull("Filter", filter);
7489

7590
// TODO: We should probably ensure that websocket requests are run through the filter.
76-
return new NettyClient(handler.with(filter), toWebSocket);
91+
return new NettyClient(config.withFilter(filter));
92+
}
93+
94+
@Override
95+
public void close() throws IOException {
96+
client.close();
7797
}
7898

7999
@AutoService(HttpClient.Factory.class)
80100
@HttpClientName("netty")
81101
public static class Factory implements HttpClient.Factory {
82102

83-
private static final AtomicBoolean addedHook = new AtomicBoolean();
84-
85-
public Factory() {
86-
if (!addedHook.get()) {
87-
Runtime.getRuntime().addShutdownHook(new Thread(this::callAsyncClientShutdown));
88-
addedHook.set(true);
89-
}
90-
}
91-
92-
private void callAsyncClientShutdown() {
93-
try {
94-
httpClient.close();
95-
} catch (IOException ignore) {
96-
}
97-
}
98-
99103
@Override
100104
public HttpClient createClient(ClientConfig config) {
101105
Require.nonNull("Client config", config);
@@ -104,7 +108,7 @@ public HttpClient createClient(ClientConfig config) {
104108
return new NettyDomainSocketClient(config);
105109
}
106110

107-
return new NettyClient(new NettyHttpHandler(config, httpClient).with(config.filter()), NettyWebSocket.create(config, httpClient));
111+
return new NettyClient(config);
108112
}
109113
}
110114
}

0 commit comments

Comments
 (0)