import java.io.IOException;
import java.net.InetSocketAddress;
+import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
+import javax.net.ssl.SSLContext;
import javax.servlet.ServletException;
+import javax.websocket.server.ServerContainer;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsState;
import org.argeo.cms.CmsDeployProperty;
-import org.argeo.util.http.HttpServerUtils;
+import org.argeo.cms.http.server.HttpServerUtils;
+import org.eclipse.jetty.ee8.servlet.ServletContextHandler;
import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
public class JettyHttpServer extends HttpsServer {
private final static CmsLog log = CmsLog.getLog(JettyHttpServer.class);
- private static final int DEFAULT_IDLE_TIMEOUT = 30000;
+ /** Long timeout since our users may have poor connections. */
+ private static final int DEFAULT_IDLE_TIMEOUT = 120 * 1000;
private Server server;
private final Map<String, JettyHttpContext> contexts = new TreeMap<>();
+ private ServletContextHandler rootContextHandler;
protected final ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
private boolean started;
@Override
public void start() {
+ String httpPortStr = getDeployProperty(CmsDeployProperty.HTTP_PORT);
+ String httpsPortStr = getDeployProperty(CmsDeployProperty.HTTPS_PORT);
+ if (httpPortStr != null && httpsPortStr != null)
+ throw new IllegalArgumentException("Either an HTTP or an HTTPS port should be configured, not both");
+ if (httpPortStr == null && httpsPortStr == null) {
+ log.warn("Neither an HTTP or an HTTPS port was configured, not starting Jetty");
+ }
+
+ /// TODO make it more generic
+ String httpHost = getDeployProperty(CmsDeployProperty.HOST);
+
try {
ThreadPool threadPool = null;
server = new Server(threadPool);
- configureConnectors();
+ configureConnectors(httpPortStr, httpsPortStr, httpHost);
if (httpConnector != null) {
httpConnector.open();
// holder
// context
- ServletContextHandler rootContextHandler = createRootContextHandler();
+ rootContextHandler = createRootContextHandler();
// httpContext.addServlet(holder, "/*");
if (rootContextHandler != null)
configureRootContextHandler(rootContextHandler);
//
// Addresses
- String httpHost = getDeployProperty(CmsDeployProperty.HOST);
String fallBackHostname = cmsState != null ? cmsState.getHostname() : "::1";
if (httpConnector != null) {
httpAddress = new InetSocketAddress(httpHost != null ? httpHost : fallBackHostname,
}
}
+ protected void configureConnectors(String httpPortStr, String httpsPortStr, String httpHost) {
+
+ // try {
+ if (httpPortStr != null || httpsPortStr != null) {
+ // TODO deal with hostname resolving taking too much time
+// String fallBackHostname = InetAddress.getLocalHost().getHostName();
+
+ boolean httpEnabled = httpPortStr != null;
+ boolean httpsEnabled = httpsPortStr != null;
+
+ if (httpEnabled) {
+ HttpConfiguration httpConfiguration = new HttpConfiguration();
+
+ if (httpsEnabled) {// not supported anymore to have both http and https, but it may change again
+ int httpsPort = Integer.parseInt(httpsPortStr);
+ httpConfiguration.setSecureScheme("https");
+ httpConfiguration.setSecurePort(httpsPort);
+ }
+
+ int httpPort = Integer.parseInt(httpPortStr);
+ httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
+ httpConnector.setPort(httpPort);
+ httpConnector.setHost(httpHost);
+ httpConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
+
+ }
+
+ if (httpsEnabled) {
+ if (httpsConfigurator == null) {
+ // we make sure that an HttpSConfigurator is set, so that clients can detect
+ // whether this server is HTTP or HTTPS
+ try {
+ httpsConfigurator = new HttpsConfigurator(SSLContext.getDefault());
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Cannot initalise SSL Context", e);
+ }
+ }
+
+ SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
+ // sslContextFactory.setKeyStore(KeyS)
+
+ sslContextFactory.setKeyStoreType(getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE));
+ sslContextFactory.setKeyStorePath(getDeployProperty(CmsDeployProperty.SSL_KEYSTORE));
+ sslContextFactory.setKeyStorePassword(getDeployProperty(CmsDeployProperty.SSL_PASSWORD));
+ // sslContextFactory.setKeyManagerPassword(getFrameworkProp(CmsDeployProperty.SSL_KEYPASSWORD));
+ sslContextFactory.setProtocol("TLS");
+
+ sslContextFactory.setTrustStoreType(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE));
+ sslContextFactory.setTrustStorePath(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORE));
+ sslContextFactory.setTrustStorePassword(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
+
+ String wantClientAuth = getDeployProperty(CmsDeployProperty.SSL_WANTCLIENTAUTH);
+ if (wantClientAuth != null && wantClientAuth.equals(Boolean.toString(true)))
+ sslContextFactory.setWantClientAuth(true);
+ String needClientAuth = getDeployProperty(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
+ if (needClientAuth != null && needClientAuth.equals(Boolean.toString(true)))
+ sslContextFactory.setNeedClientAuth(true);
+
+ // HTTPS Configuration
+ HttpConfiguration httpsConfiguration = new HttpConfiguration();
+ httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
+ httpsConfiguration.setUriCompliance(UriCompliance.LEGACY);
+
+ // HTTPS connector
+ httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
+ new HttpConnectionFactory(httpsConfiguration));
+ int httpsPort = Integer.parseInt(httpsPortStr);
+ httpsConnector.setPort(httpsPort);
+ httpsConnector.setHost(httpHost);
+ httpsConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
+ }
+ }
+ }
+
@Override
public void stop(int delay) {
// TODO wait for processing to complete
server.stop();
// TODO delete temp dir
started = false;
+ log.debug(() -> "Stopped Jetty server");
} catch (Exception e) {
log.error("Cannot stop Jetty HTTP server", e);
}
@Override
public synchronized HttpContext createContext(String path) {
+ if (!path.endsWith("/"))
+ path = path + "/";
if (contexts.containsKey(path))
throw new IllegalArgumentException("Context " + path + " already exists");
- JettyHttpContext httpContext = new JettyHttpContext(this, path);
+
+ JettyHttpContext httpContext = new ServletHttpContext(this, path);
contexts.put(path, httpContext);
- contextHandlerCollection.addHandler(httpContext.getContextHandler());
+ contextHandlerCollection.addHandler(httpContext.getServletContextHandler());
return httpContext;
}
@Override
public synchronized void removeContext(String path) throws IllegalArgumentException {
+ if (!path.endsWith("/"))
+ path = path + "/";
if (!contexts.containsKey(path))
throw new IllegalArgumentException("Context " + path + " does not exist");
JettyHttpContext httpContext = contexts.remove(path);
- // TODO stop handler first?
- contextHandlerCollection.removeHandler(httpContext.getContextHandler());
+ if (httpContext instanceof ContextHandlerHttpContext contextHandlerHttpContext) {
+ // TODO stop handler first?
+ // FIXME understand compatibility with Jetty 12
+ // contextHandlerCollection.removeHandler(contextHandlerHttpContext.getServletContextHandler());
+ } else {
+ // FIXME apparently servlets cannot be removed in Jetty, we should replace the
+ // handler
+ }
}
@Override
return httpsConfigurator;
}
- protected void configureConnectors() {
- HttpConfiguration httpConfiguration = new HttpConfiguration();
-
- String httpPortStr = getDeployProperty(CmsDeployProperty.HTTP_PORT);
- String httpsPortStr = getDeployProperty(CmsDeployProperty.HTTPS_PORT);
- if (httpPortStr != null && httpsPortStr != null)
- throw new IllegalArgumentException("Either an HTTP or an HTTPS port should be configured, not both");
- if (httpPortStr == null && httpsPortStr == null)
- throw new IllegalArgumentException("Neither an HTTP or HTTPS port was configured");
-
- /// TODO make it more generic
- String httpHost = getDeployProperty(CmsDeployProperty.HOST);
-
- // try {
- if (httpPortStr != null || httpsPortStr != null) {
- // TODO deal with hostname resolving taking too much time
-// String fallBackHostname = InetAddress.getLocalHost().getHostName();
-
- boolean httpEnabled = httpPortStr != null;
- boolean httpsEnabled = httpsPortStr != null;
-
- if (httpsEnabled) {
- int httpsPort = Integer.parseInt(httpsPortStr);
- httpConfiguration.setSecureScheme("https");
- httpConfiguration.setSecurePort(httpsPort);
- }
-
- if (httpEnabled) {
- int httpPort = Integer.parseInt(httpPortStr);
- httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
- httpConnector.setPort(httpPort);
- httpConnector.setHost(httpHost);
- httpConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
-
- }
-
- if (httpsEnabled) {
-
- SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
- // sslContextFactory.setKeyStore(KeyS)
-
- sslContextFactory.setKeyStoreType(getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE));
- sslContextFactory.setKeyStorePath(getDeployProperty(CmsDeployProperty.SSL_KEYSTORE));
- sslContextFactory.setKeyStorePassword(getDeployProperty(CmsDeployProperty.SSL_PASSWORD));
- // sslContextFactory.setKeyManagerPassword(getFrameworkProp(CmsDeployProperty.SSL_KEYPASSWORD));
- sslContextFactory.setProtocol("TLS");
-
- sslContextFactory.setTrustStoreType(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE));
- sslContextFactory.setTrustStorePath(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORE));
- sslContextFactory.setTrustStorePassword(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
-
- String wantClientAuth = getDeployProperty(CmsDeployProperty.SSL_WANTCLIENTAUTH);
- if (wantClientAuth != null && wantClientAuth.equals(Boolean.toString(true)))
- sslContextFactory.setWantClientAuth(true);
- String needClientAuth = getDeployProperty(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
- if (needClientAuth != null && needClientAuth.equals(Boolean.toString(true)))
- sslContextFactory.setNeedClientAuth(true);
-
- // HTTPS Configuration
- HttpConfiguration https_config = new HttpConfiguration(httpConfiguration);
- https_config.addCustomizer(new SecureRequestCustomizer());
- https_config.setUriCompliance(UriCompliance.LEGACY);
-
- // HTTPS connector
- httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
- new HttpConnectionFactory(https_config));
- int httpsPort = Integer.parseInt(httpsPortStr);
- httpsConnector.setPort(httpsPort);
- httpsConnector.setHost(httpHost);
- }
-
- }
-
- }
-
protected String getDeployProperty(CmsDeployProperty deployProperty) {
return cmsState != null ? cmsState.getDeployProperty(deployProperty.getProperty())
: System.getProperty(deployProperty.getProperty());
}
private String httpPortsMsg() {
+ String hostStr = getHost();
+ hostStr = hostStr == null ? "*:" : hostStr + ":";
+ return (httpConnector != null ? "# HTTP " + hostStr + getHttpPort() + " " : "")
+ + (httpsConnector != null ? "# HTTPS " + hostStr + getHttpsPort() : "");
+ }
- return (httpConnector != null ? "HTTP " + getHttpPort() + " " : " ")
- + (httpsConnector != null ? "HTTPS " + getHttpsPort() : "");
+ public String getHost() {
+ if (httpConnector == null)
+ return null;
+ return httpConnector.getHost();
}
public Integer getHttpPort() {
this.cmsState = cmsState;
}
- public boolean isStarted() {
+ boolean isStarted() {
return started;
}
+ ServletContextHandler getRootContextHandler() {
+ return rootContextHandler;
+ }
+
+ ServerContainer getRootServerContainer() {
+ throw new UnsupportedOperationException();
+ }
+
public static void main(String... args) {
JettyHttpServer httpServer = new JettyHttpServer();
System.setProperty("argeo.http.port", "8080");