org.openqa.selenium.netty.server.NettyServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of selenium-grid Show documentation
Show all versions of selenium-grid Show documentation
Selenium automates browsers. That's it! What you do with that power is entirely up to you.
The newest version!
// 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.netty.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.logging.JdkLoggerFactory;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import javax.net.ssl.SSLException;
import org.openqa.selenium.grid.server.BaseServerOptions;
import org.openqa.selenium.grid.server.Server;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.remote.AddWebDriverSpecHeaders;
import org.openqa.selenium.remote.ErrorFilter;
import org.openqa.selenium.remote.http.HttpHandler;
import org.openqa.selenium.remote.http.Message;
public class NettyServer implements Server {
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private final int port;
private final String host;
private final boolean bindHost;
private final URL externalUrl;
private final HttpHandler handler;
private final BiFunction, Optional>> websocketHandler;
private final SslContext sslCtx;
private final boolean allowCors;
private Channel channel;
public NettyServer(BaseServerOptions options, HttpHandler handler) {
this(options, handler, (str, sink) -> Optional.empty());
}
public NettyServer(
BaseServerOptions options,
HttpHandler handler,
BiFunction, Optional>> websocketHandler) {
Require.nonNull("Server options", options);
Require.nonNull("Handler", handler);
this.websocketHandler = Require.nonNull("Factory for websocket connections", websocketHandler);
InternalLoggerFactory.setDefaultFactory(JdkLoggerFactory.INSTANCE);
boolean secure = options.isSecure();
if (secure) {
try {
sslCtx =
SslContextBuilder.forServer(options.getCertificate(), options.getPrivateKey()).build();
} catch (SSLException e) {
throw new UncheckedIOException(new IOException("Certificate problem.", e));
}
} else if (options.isSelfSigned()) {
try {
SelfSignedCertificate cert = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(cert.certificate(), cert.privateKey()).build();
} catch (CertificateException | SSLException e) {
throw new UncheckedIOException(new IOException("Self-signed certificate problem.", e));
}
} else {
sslCtx = null;
}
this.handler = handler.with(new ErrorFilter().andThen(new AddWebDriverSpecHeaders()));
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
port = options.getPort();
host = options.getHostname().orElse("0.0.0.0");
bindHost = options.getBindHost();
allowCors = options.getAllowCORS();
try {
externalUrl = options.getExternalUri().toURL();
} catch (MalformedURLException e) {
throw new UncheckedIOException(
"Server URI is not a valid URL: " + options.getExternalUri(), e);
}
}
@Override
public boolean isStarted() {
return channel != null;
}
@Override
public URL getUrl() {
return externalUrl;
}
@Override
public void stop() {
try {
bossGroup.shutdownGracefully().sync();
workerGroup.shutdownGracefully().sync();
channel.closeFuture().sync();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedIOException(new IOException("Shutdown interrupted", e));
} finally {
channel = null;
}
}
@SuppressWarnings("ConstantConditions")
public NettyServer start() {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new SeleniumHttpInitializer(sslCtx, handler, websocketHandler, allowCors));
try {
// Using a flag to avoid binding to the host, useful in environments like Docker,
// where the "host" value can be the IP of the Docker host machine, which cannot
// be bind inside the container.
channel =
bindHost
? b.bind(new InetSocketAddress(host, port)).sync().channel()
: b.bind(port).sync().channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedIOException(new IOException("Start up interrupted", e));
} catch (Exception e) {
if (e instanceof BindException) {
String errorMessage =
String.format(
"Could not bind to address or port is already in use. Host %s, Port %s",
host, port);
throw new ServerBindException(errorMessage, (BindException) e);
}
throw e;
}
return this;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy