Refactor CMS UUID factory
[lgpl/argeo-commons.git] / org.argeo.cms.lib.jetty / src / org / argeo / cms / jetty / JettyHttpServer.java
index 363bbaebe498362973675995c4c63e7c18e20ab6..4e91ea41c734a51f739a1d82d2d030000788fb38 100644 (file)
@@ -2,11 +2,13 @@ package org.argeo.cms.jetty;
 
 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;
 
@@ -14,6 +16,7 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
 import org.argeo.cms.CmsDeployProperty;
 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;
@@ -22,7 +25,6 @@ import org.eclipse.jetty.server.Server;
 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;
@@ -30,6 +32,7 @@ import org.eclipse.jetty.util.thread.ThreadPool;
 
 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;
 
@@ -37,7 +40,8 @@ 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;
 
@@ -67,6 +71,17 @@ public class JettyHttpServer extends HttpsServer {
 
        @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;
@@ -79,7 +94,7 @@ public class JettyHttpServer extends HttpsServer {
 
                        server = new Server(threadPool);
 
-                       configureConnectors();
+                       configureConnectors(httpPortStr, httpsPortStr, httpHost);
 
                        if (httpConnector != null) {
                                httpConnector.open();
@@ -110,7 +125,6 @@ public class JettyHttpServer extends HttpsServer {
                        //
 
                        // Addresses
-                       String httpHost = getDeployProperty(CmsDeployProperty.HOST);
                        String fallBackHostname = cmsState != null ? cmsState.getHostname() : "::1";
                        if (httpConnector != null) {
                                httpAddress = new InetSocketAddress(httpHost != null ? httpHost : fallBackHostname,
@@ -130,16 +144,7 @@ public class JettyHttpServer extends HttpsServer {
                }
        }
 
-       protected void configureConnectors() {
-               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);
+       protected void configureConnectors(String httpPortStr, String httpsPortStr, String httpHost) {
 
                // try {
                if (httpPortStr != null || httpsPortStr != null) {
@@ -167,6 +172,16 @@ public class JettyHttpServer extends HttpsServer {
                        }
 
                        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)
 
@@ -198,6 +213,7 @@ public class JettyHttpServer extends HttpsServer {
                                int httpsPort = Integer.parseInt(httpsPortStr);
                                httpsConnector.setPort(httpsPort);
                                httpsConnector.setHost(httpHost);
+                               httpsConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
                        }
                }
        }
@@ -214,6 +230,7 @@ public class JettyHttpServer extends HttpsServer {
                        server.stop();
                        // TODO delete temp dir
                        started = false;
+                       log.debug(() -> "Stopped Jetty server");
                } catch (Exception e) {
                        log.error("Cannot stop Jetty HTTP server", e);
                }
@@ -255,12 +272,18 @@ public class JettyHttpServer extends HttpsServer {
 
        @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);
                if (httpContext instanceof ContextHandlerHttpContext contextHandlerHttpContext) {
                        // TODO stop handler first?
-                       contextHandlerCollection.removeHandler(contextHandlerHttpContext.getServletContextHandler());
+                       // FIXME understand compatibility with Jetty 12
+                       // contextHandlerCollection.removeHandler(contextHandlerHttpContext.getServletContextHandler());
+               } else {
+                       // FIXME apparently servlets cannot be removed in Jetty, we should replace the
+                       // handler
                }
        }
 
@@ -293,9 +316,16 @@ public class JettyHttpServer extends HttpsServer {
        }
 
        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() {