package de.rwth.idsg.steve; import lombok.extern.slf4j.Slf4j; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import static de.rwth.idsg.steve.SteveConfiguration.CONFIG; /** * @author Sevket Goekay <goekay@dbis.rwth-aachen.de> * @since 12.12.2014 */ @Slf4j public class JettyServer { private Server server; private static final int MIN_THREADS = 4; private static final int MAX_THREADS = 50; private static final long STOP_TIMEOUT = TimeUnit.SECONDS.toMillis(5); private static final long IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(1); /** * A fully configured Jetty Server instance */ public void prepare() throws Exception { // === jetty.xml === // Setup Threadpool QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setMinThreads(MIN_THREADS); threadPool.setMaxThreads(MAX_THREADS); // Server server = new Server(threadPool); // Scheduler server.addBean(new ScheduledExecutorScheduler()); // HTTP Configuration HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.setSecureScheme(HttpScheme.HTTPS.asString()); httpConfig.setSecurePort(CONFIG.getJetty().getHttpsPort()); httpConfig.setOutputBufferSize(32768); httpConfig.setRequestHeaderSize(8192); httpConfig.setResponseHeaderSize(8192); httpConfig.setSendServerVersion(false); httpConfig.setSendDateHeader(false); httpConfig.setSendXPoweredBy(false); // Extra options server.setDumpAfterStart(false); server.setDumpBeforeStop(false); server.setStopAtShutdown(true); server.setStopTimeout(STOP_TIMEOUT); if (CONFIG.getJetty().isHttpEnabled()) { server.addConnector(httpConnector(httpConfig)); } if (CONFIG.getJetty().isHttpsEnabled()) { server.addConnector(httpsConnector(httpConfig)); } SteveAppContext steveAppContext = new SteveAppContext(); server.setHandler(steveAppContext.getHandlers()); } private ServerConnector httpConnector(HttpConfiguration httpConfig) { // === jetty-http.xml === ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); http.setHost(CONFIG.getJetty().getServerHost()); http.setPort(CONFIG.getJetty().getHttpPort()); http.setIdleTimeout(IDLE_TIMEOUT); return http; } private ServerConnector httpsConnector(HttpConfiguration httpConfig) { // === jetty-https.xml === // SSL Context Factory SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(CONFIG.getJetty().getKeyStorePath()); sslContextFactory.setKeyStorePassword(CONFIG.getJetty().getKeyStorePassword()); sslContextFactory.setKeyManagerPassword(CONFIG.getJetty().getKeyStorePassword()); sslContextFactory.setExcludeCipherSuites( "SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); // SSL HTTP Configuration HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); httpsConfig.addCustomizer(new SecureRequestCustomizer()); // SSL Connector ServerConnector https = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(httpsConfig)); https.setHost(CONFIG.getJetty().getServerHost()); https.setPort(CONFIG.getJetty().getHttpsPort()); https.setIdleTimeout(IDLE_TIMEOUT); return https; } /** * Starts the Jetty Server instance */ public void start() throws Exception { if (server != null) { server.start(); } } /** * Join the server thread with the current thread */ public void join() throws Exception { if (server != null) { server.join(); } } public boolean isStarted() { return server != null && server.isStarted(); } public List<String> getConnectorPathList() { if (server == null) { return Collections.emptyList(); } Connector[] connectors = server.getConnectors(); List<String> list = new ArrayList<>(connectors.length); for (Connector c : connectors) { list.add(getConnectorPath((ServerConnector) c)); } return list; } private String getConnectorPath(ServerConnector sc) { String prefix = "http"; String host = sc.getHost(); int port = sc.getPort(); ConnectionFactory cf = sc.getDefaultConnectionFactory(); if (cf instanceof SslConnectionFactory) { prefix = "https"; } if (host == null || host.equals("0.0.0.0")) { try { host = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { // Well, we failed to read from system, fall back to main.properties. // Better than nothing host = CONFIG.getJetty().getServerHost(); } } String layout = "%s://%s:%d" + CONFIG.getContextPath(); return String.format(layout, prefix, host, port); } }