| 55 | import org.openqa.selenium.remote.http.Message; |
| 56 | |
| 57 | public class NettyServer implements Server<NettyServer> { |
| 58 | |
| 59 | private final EventLoopGroup bossGroup; |
| 60 | private final EventLoopGroup workerGroup; |
| 61 | private final int port; |
| 62 | private final String host; |
| 63 | private final boolean bindHost; |
| 64 | private final URL externalUrl; |
| 65 | private final HttpHandler handler; |
| 66 | private final BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> websocketHandler; |
| 67 | private final @Nullable SslContext sslCtx; |
| 68 | private final boolean allowCors; |
| 69 | private final @Nullable Function<String, Optional<URI>> tcpTunnelResolver; |
| 70 | |
| 71 | @Nullable private Channel channel; |
| 72 | |
| 73 | public NettyServer(BaseServerOptions options, HttpHandler handler) { |
| 74 | this(options, handler, (str, sink) -> Optional.empty()); |
| 75 | } |
| 76 | |
| 77 | public NettyServer( |
| 78 | BaseServerOptions options, |
| 79 | HttpHandler handler, |
| 80 | BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> websocketHandler) { |
| 81 | this(options, handler, websocketHandler, null); |
| 82 | } |
| 83 | |
| 84 | /** |
| 85 | * Creates a {@link NettyServer} with an optional TCP-level tunnel resolver for WebSocket |
| 86 | * connections. When {@code tcpTunnelResolver} is non-null, WebSocket upgrade requests that |
| 87 | * contain a Selenium session ID are intercepted before the normal WebSocket handler: the Router |
| 88 | * opens a raw TCP connection to the resolved Node URI and bridges the two sockets directly, |
| 89 | * removing itself from the WebSocket data path entirely. |
| 90 | * |
| 91 | * @param tcpTunnelResolver maps a request URI to the target Node URI. Return {@link |
| 92 | * Optional#empty()} to fall through to the normal WebSocket handler. |
| 93 | */ |
| 94 | public NettyServer( |
| 95 | BaseServerOptions options, |
| 96 | HttpHandler handler, |
| 97 | BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> websocketHandler, |
| 98 | @Nullable Function<String, Optional<URI>> tcpTunnelResolver) { |
| 99 | Require.nonNull("Server options", options); |
| 100 | Require.nonNull("Handler", handler); |
| 101 | this.websocketHandler = Require.nonNull("Factory for websocket connections", websocketHandler); |
| 102 | this.tcpTunnelResolver = tcpTunnelResolver; |
| 103 | |
| 104 | InternalLoggerFactory.setDefaultFactory(JdkLoggerFactory.INSTANCE); |
| 105 | |
| 106 | boolean secure = options.isSecure(); |
| 107 | if (secure) { |
| 108 | try { |
| 109 | sslCtx = |
| 110 | SslContextBuilder.forServer(options.getCertificate(), options.getPrivateKey()).build(); |
| 111 | } catch (SSLException e) { |
| 112 | throw new UncheckedIOException(new IOException("Certificate problem.", e)); |
| 113 | } |
| 114 | } else if (options.isSelfSigned()) { |
nothing calls this directly
no outgoing calls
no test coverage detected