LCOV - code coverage report
Current view: top level - pgm/http/jetty - JettyServer.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 177 240 73.8 %
Date: 2022-11-19 15:00:39 Functions: 37 40 92.5 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.pgm.http.jetty;
      16             : 
      17             : import static java.util.concurrent.TimeUnit.MILLISECONDS;
      18             : import static java.util.concurrent.TimeUnit.SECONDS;
      19             : 
      20             : import com.google.common.annotations.VisibleForTesting;
      21             : import com.google.common.base.Strings;
      22             : import com.google.gerrit.extensions.client.AuthType;
      23             : import com.google.gerrit.extensions.events.LifecycleListener;
      24             : import com.google.gerrit.pgm.http.jetty.HttpLog.HttpLogFactory;
      25             : import com.google.gerrit.server.config.GerritServerConfig;
      26             : import com.google.gerrit.server.config.SitePaths;
      27             : import com.google.gerrit.server.config.ThreadSettingsConfig;
      28             : import com.google.inject.Inject;
      29             : import com.google.inject.Injector;
      30             : import com.google.inject.Singleton;
      31             : import com.google.inject.servlet.GuiceFilter;
      32             : import com.google.inject.servlet.GuiceServletContextListener;
      33             : import java.lang.management.ManagementFactory;
      34             : import java.net.URI;
      35             : import java.net.URISyntaxException;
      36             : import java.nio.file.Files;
      37             : import java.nio.file.Path;
      38             : import java.util.ArrayList;
      39             : import java.util.EnumSet;
      40             : import java.util.HashMap;
      41             : import java.util.HashSet;
      42             : import java.util.List;
      43             : import java.util.Map;
      44             : import java.util.Set;
      45             : import java.util.concurrent.TimeUnit;
      46             : import java.util.concurrent.atomic.AtomicLong;
      47             : import javax.servlet.DispatcherType;
      48             : import javax.servlet.Filter;
      49             : import javax.servlet.http.HttpSessionEvent;
      50             : import javax.servlet.http.HttpSessionListener;
      51             : import org.eclipse.jetty.http.HttpScheme;
      52             : import org.eclipse.jetty.io.ConnectionStatistics;
      53             : import org.eclipse.jetty.jmx.MBeanContainer;
      54             : import org.eclipse.jetty.server.Connector;
      55             : import org.eclipse.jetty.server.ForwardedRequestCustomizer;
      56             : import org.eclipse.jetty.server.Handler;
      57             : import org.eclipse.jetty.server.HttpConfiguration;
      58             : import org.eclipse.jetty.server.HttpConnectionFactory;
      59             : import org.eclipse.jetty.server.SecureRequestCustomizer;
      60             : import org.eclipse.jetty.server.Server;
      61             : import org.eclipse.jetty.server.ServerConnector;
      62             : import org.eclipse.jetty.server.SslConnectionFactory;
      63             : import org.eclipse.jetty.server.handler.ContextHandler;
      64             : import org.eclipse.jetty.server.handler.ContextHandlerCollection;
      65             : import org.eclipse.jetty.server.handler.RequestLogHandler;
      66             : import org.eclipse.jetty.server.handler.StatisticsHandler;
      67             : import org.eclipse.jetty.server.session.SessionHandler;
      68             : import org.eclipse.jetty.servlet.DefaultServlet;
      69             : import org.eclipse.jetty.servlet.FilterHolder;
      70             : import org.eclipse.jetty.servlet.ServletContextHandler;
      71             : import org.eclipse.jetty.servlet.ServletHolder;
      72             : import org.eclipse.jetty.util.BlockingArrayQueue;
      73             : import org.eclipse.jetty.util.log.Log;
      74             : import org.eclipse.jetty.util.ssl.SslContextFactory;
      75             : import org.eclipse.jetty.util.thread.QueuedThreadPool;
      76             : import org.eclipse.jgit.lib.Config;
      77             : 
      78             : @Singleton
      79             : public class JettyServer {
      80             :   static class Lifecycle implements LifecycleListener {
      81             :     private final JettyServer server;
      82             :     private final Config cfg;
      83             : 
      84             :     @Inject
      85          99 :     Lifecycle(JettyServer server, @GerritServerConfig Config cfg) {
      86          99 :       this.server = server;
      87          99 :       this.cfg = cfg;
      88          99 :     }
      89             : 
      90             :     @Override
      91             :     public void start() {
      92             :       try {
      93          99 :         String origUrl = cfg.getString("httpd", null, "listenUrl");
      94          99 :         boolean rewrite = !Strings.isNullOrEmpty(origUrl) && origUrl.endsWith(":0/");
      95          99 :         server.httpd.start();
      96          99 :         if (rewrite) {
      97          99 :           Connector con = server.httpd.getConnectors()[0];
      98          99 :           if (con instanceof ServerConnector) {
      99             :             @SuppressWarnings("resource")
     100          99 :             ServerConnector serverCon = (ServerConnector) con;
     101          99 :             String host = serverCon.getHost();
     102          99 :             int port = serverCon.getLocalPort();
     103          99 :             String url = String.format("http://%s:%d", host, port);
     104          99 :             cfg.setString("gerrit", null, "canonicalWebUrl", url);
     105          99 :             cfg.setString("httpd", null, "listenUrl", url);
     106             :           }
     107             :         }
     108           0 :       } catch (Exception e) {
     109           0 :         throw new IllegalStateException("Cannot start HTTP daemon", e);
     110          99 :       }
     111          99 :     }
     112             : 
     113             :     @Override
     114             :     public void stop() {
     115             :       try {
     116          99 :         server.httpd.stop();
     117          99 :         server.httpd.join();
     118           0 :       } catch (Exception e) {
     119           0 :         throw new IllegalStateException("Cannot stop HTTP daemon", e);
     120          99 :       }
     121          99 :     }
     122             :   }
     123             : 
     124             :   static class Metrics {
     125             :     private final QueuedThreadPool threadPool;
     126             :     private ConnectionStatistics connStats;
     127             : 
     128          99 :     Metrics(QueuedThreadPool threadPool, ConnectionStatistics connStats) {
     129          99 :       this.threadPool = threadPool;
     130          99 :       this.connStats = connStats;
     131          99 :     }
     132             : 
     133             :     public int getIdleThreads() {
     134          15 :       return threadPool.getIdleThreads();
     135             :     }
     136             : 
     137             :     public int getBusyThreads() {
     138          15 :       return threadPool.getBusyThreads();
     139             :     }
     140             : 
     141             :     public int getReservedThreads() {
     142          15 :       return threadPool.getReservedThreads();
     143             :     }
     144             : 
     145             :     public int getMinThreads() {
     146          15 :       return threadPool.getMinThreads();
     147             :     }
     148             : 
     149             :     public int getMaxThreads() {
     150          15 :       return threadPool.getMaxThreads();
     151             :     }
     152             : 
     153             :     public int getThreads() {
     154          15 :       return threadPool.getThreads();
     155             :     }
     156             : 
     157             :     public int getQueueSize() {
     158          15 :       return threadPool.getQueueSize();
     159             :     }
     160             : 
     161             :     public boolean isLowOnThreads() {
     162          15 :       return threadPool.isLowOnThreads();
     163             :     }
     164             : 
     165             :     public long getConnections() {
     166          15 :       return connStats.getConnections();
     167             :     }
     168             : 
     169             :     public long getConnectionsTotal() {
     170          15 :       return connStats.getConnectionsTotal();
     171             :     }
     172             : 
     173             :     public long getConnectionDurationMax() {
     174          15 :       return connStats.getConnectionDurationMax();
     175             :     }
     176             : 
     177             :     public double getConnectionDurationMean() {
     178          15 :       return connStats.getConnectionDurationMean();
     179             :     }
     180             : 
     181             :     public double getConnectionDurationStdDev() {
     182          15 :       return connStats.getConnectionDurationStdDev();
     183             :     }
     184             : 
     185             :     public long getReceivedMessages() {
     186          15 :       return connStats.getReceivedMessages();
     187             :     }
     188             : 
     189             :     public long getSentMessages() {
     190          15 :       return connStats.getSentMessages();
     191             :     }
     192             : 
     193             :     public long getReceivedBytes() {
     194          15 :       return connStats.getReceivedBytes();
     195             :     }
     196             : 
     197             :     public long getSentBytes() {
     198          15 :       return connStats.getSentBytes();
     199             :     }
     200             :   }
     201             : 
     202             :   private final SitePaths site;
     203             :   private final Server httpd;
     204             :   private final Metrics metrics;
     205             :   private boolean reverseProxy;
     206             :   private ConnectionStatistics connStats;
     207             :   private final SessionHandler sessionHandler;
     208             :   private final AtomicLong sessionsCounter;
     209             : 
     210             :   @Inject
     211             :   JettyServer(
     212             :       @GerritServerConfig Config cfg,
     213             :       ThreadSettingsConfig threadSettingsConfig,
     214             :       SitePaths site,
     215             :       JettyEnv env,
     216          99 :       HttpLogFactory httpLogFactory) {
     217          99 :     this.site = site;
     218             : 
     219          99 :     QueuedThreadPool pool = threadPool(cfg, threadSettingsConfig);
     220          99 :     httpd = new Server(pool);
     221          99 :     httpd.setConnectors(listen(httpd, cfg));
     222          99 :     connStats = new ConnectionStatistics();
     223          99 :     for (Connector connector : httpd.getConnectors()) {
     224          99 :       connector.addBean(connStats);
     225             :     }
     226          99 :     metrics = new Metrics(pool, connStats);
     227          99 :     sessionHandler = new SessionHandler();
     228          99 :     sessionsCounter = new AtomicLong();
     229             : 
     230             :     /* Code used for testing purposes for making assertions
     231             :      * on the number of active HTTP sessions.
     232             :      */
     233          99 :     sessionHandler.addEventListener(
     234          99 :         new HttpSessionListener() {
     235             : 
     236             :           @Override
     237             :           public void sessionDestroyed(HttpSessionEvent se) {
     238           0 :             sessionsCounter.decrementAndGet();
     239           0 :           }
     240             : 
     241             :           @Override
     242             :           public void sessionCreated(HttpSessionEvent se) {
     243           0 :             sessionsCounter.incrementAndGet();
     244           0 :           }
     245             :         });
     246             : 
     247          99 :     Handler app = makeContext(env, cfg, sessionHandler);
     248          99 :     if (cfg.getBoolean("httpd", "requestLog", !reverseProxy)) {
     249          15 :       RequestLogHandler handler = new RequestLogHandler();
     250          15 :       handler.setRequestLog(httpLogFactory.get());
     251          15 :       handler.setHandler(app);
     252          15 :       app = handler;
     253             :     }
     254          99 :     if (cfg.getBoolean("httpd", "registerMBeans", false)) {
     255           0 :       MBeanContainer mbean = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
     256           0 :       httpd.addEventListener(mbean);
     257           0 :       httpd.addBean(Log.getRootLogger());
     258           0 :       httpd.addBean(mbean);
     259             :     }
     260             : 
     261          99 :     long gracefulStopTimeout =
     262          99 :         cfg.getTimeUnit("httpd", null, "gracefulStopTimeout", 0L, TimeUnit.MILLISECONDS);
     263          99 :     if (gracefulStopTimeout > 0) {
     264           0 :       StatisticsHandler statsHandler = new StatisticsHandler();
     265           0 :       statsHandler.setHandler(app);
     266           0 :       app = statsHandler;
     267           0 :       httpd.setStopTimeout(gracefulStopTimeout);
     268             :     }
     269             : 
     270          99 :     httpd.setHandler(app);
     271          99 :     httpd.setStopAtShutdown(false);
     272          99 :   }
     273             : 
     274             :   @VisibleForTesting
     275             :   public long numActiveSessions() {
     276           2 :     return sessionsCounter.longValue();
     277             :   }
     278             : 
     279             :   Metrics getMetrics() {
     280          99 :     return metrics;
     281             :   }
     282             : 
     283             :   private Connector[] listen(Server server, Config cfg) {
     284             :     // OpenID and certain web-based single-sign-on products can cause
     285             :     // some very long headers, especially in the Referer header. We
     286             :     // need to use a larger default header size to ensure we have
     287             :     // the space required.
     288             :     //
     289          99 :     final int requestHeaderSize = cfg.getInt("httpd", "requestheadersize", 16386);
     290          99 :     final URI[] listenUrls = listenURLs(cfg);
     291          99 :     final boolean reuseAddress = cfg.getBoolean("httpd", "reuseaddress", true);
     292          99 :     final int acceptors = cfg.getInt("httpd", "acceptorThreads", 2);
     293          99 :     final AuthType authType = cfg.getEnum("auth", null, "type", AuthType.OPENID);
     294             : 
     295          99 :     reverseProxy = isReverseProxied(listenUrls);
     296          99 :     final Connector[] connectors = new Connector[listenUrls.length];
     297          99 :     for (int idx = 0; idx < listenUrls.length; idx++) {
     298          99 :       final URI u = listenUrls[idx];
     299             :       final int defaultPort;
     300             :       final ServerConnector c;
     301          99 :       HttpConfiguration config = defaultConfig(requestHeaderSize);
     302             : 
     303          99 :       if (AuthType.CLIENT_SSL_CERT_LDAP.equals(authType) && !"https".equals(u.getScheme())) {
     304           0 :         throw new IllegalArgumentException(
     305             :             "Protocol '"
     306           0 :                 + u.getScheme()
     307             :                 + "' "
     308             :                 + " not supported in httpd.listenurl '"
     309             :                 + u
     310             :                 + "' when auth.type = '"
     311           0 :                 + AuthType.CLIENT_SSL_CERT_LDAP.name()
     312             :                 + "'; only 'https' is supported");
     313             :       }
     314             : 
     315          99 :       if ("http".equals(u.getScheme())) {
     316          99 :         defaultPort = 80;
     317          99 :         c = newServerConnector(server, acceptors, config);
     318             : 
     319           1 :       } else if ("https".equals(u.getScheme())) {
     320           0 :         SslContextFactory.Server ssl = new SslContextFactory.Server();
     321           0 :         final Path keystore = getFile(cfg, "sslkeystore", "etc/keystore");
     322           0 :         String password = cfg.getString("httpd", null, "sslkeypassword");
     323           0 :         if (password == null) {
     324           0 :           password = "gerrit";
     325             :         }
     326           0 :         ssl.setKeyStorePath(keystore.toAbsolutePath().toString());
     327           0 :         ssl.setTrustStorePath(keystore.toAbsolutePath().toString());
     328           0 :         ssl.setKeyStorePassword(password);
     329           0 :         ssl.setTrustStorePassword(password);
     330             : 
     331           0 :         if (AuthType.CLIENT_SSL_CERT_LDAP.equals(authType)) {
     332           0 :           ssl.setNeedClientAuth(true);
     333             : 
     334           0 :           Path crl = getFile(cfg, "sslCrl", "etc/crl.pem");
     335           0 :           if (Files.exists(crl)) {
     336           0 :             ssl.setCrlPath(crl.toAbsolutePath().toString());
     337           0 :             ssl.setValidatePeerCerts(true);
     338             :           }
     339             :         }
     340             : 
     341           0 :         defaultPort = 443;
     342             : 
     343           0 :         config.addCustomizer(new SecureRequestCustomizer());
     344           0 :         c =
     345             :             new ServerConnector(
     346             :                 server,
     347             :                 null,
     348             :                 null,
     349             :                 null,
     350             :                 0,
     351             :                 acceptors,
     352             :                 new SslConnectionFactory(ssl, "http/1.1"),
     353             :                 new HttpConnectionFactory(config));
     354             : 
     355           1 :       } else if ("proxy-http".equals(u.getScheme())) {
     356           0 :         defaultPort = 8080;
     357           0 :         config.addCustomizer(new ForwardedRequestCustomizer());
     358           0 :         c = newServerConnector(server, acceptors, config);
     359             : 
     360           1 :       } else if ("proxy-https".equals(u.getScheme())) {
     361           1 :         defaultPort = 8080;
     362           1 :         config.addCustomizer(new ForwardedRequestCustomizer());
     363           1 :         config.addCustomizer(
     364             :             (connector, channelConfig, request) -> {
     365           1 :               request.setScheme(HttpScheme.HTTPS.asString());
     366           1 :               request.setSecure(true);
     367           1 :             });
     368           1 :         c = newServerConnector(server, acceptors, config);
     369             : 
     370             :       } else {
     371           0 :         throw new IllegalArgumentException(
     372             :             "Protocol '"
     373           0 :                 + u.getScheme()
     374             :                 + "' "
     375             :                 + " not supported in httpd.listenurl '"
     376             :                 + u
     377             :                 + "';"
     378             :                 + " only 'http', 'https', 'proxy-http, 'proxy-https'"
     379             :                 + " are supported");
     380             :       }
     381             : 
     382             :       try {
     383          99 :         if (u.getHost() == null
     384           0 :             && (u.getAuthority().equals("*") //
     385           0 :                 || u.getAuthority().startsWith("*:"))) {
     386             :           // Bind to all local addresses. Port wasn't parsed right by URI
     387             :           // due to the illegal host of "*" so replace with a legal name
     388             :           // and parse the URI.
     389             :           //
     390           0 :           final URI r = new URI(u.toString().replace('*', 'A')).parseServerAuthority();
     391           0 :           c.setHost(null);
     392           0 :           c.setPort(0 < r.getPort() ? r.getPort() : defaultPort);
     393           0 :         } else {
     394          99 :           final URI r = u.parseServerAuthority();
     395          99 :           c.setHost(r.getHost());
     396          99 :           c.setPort(0 <= r.getPort() ? r.getPort() : defaultPort);
     397             :         }
     398           0 :       } catch (URISyntaxException e) {
     399           0 :         throw new IllegalArgumentException("Invalid httpd.listenurl " + u, e);
     400          99 :       }
     401          99 :       c.setInheritChannel(cfg.getBoolean("httpd", "inheritChannel", false));
     402          99 :       c.setReuseAddress(reuseAddress);
     403          99 :       c.setIdleTimeout(cfg.getTimeUnit("httpd", null, "idleTimeout", 30000L, MILLISECONDS));
     404          99 :       connectors[idx] = c;
     405             :     }
     406          99 :     return connectors;
     407             :   }
     408             : 
     409             :   private static ServerConnector newServerConnector(
     410             :       Server server, int acceptors, HttpConfiguration config) {
     411          99 :     return new ServerConnector(
     412             :         server, null, null, null, 0, acceptors, new HttpConnectionFactory(config));
     413             :   }
     414             : 
     415             :   private HttpConfiguration defaultConfig(int requestHeaderSize) {
     416          99 :     HttpConfiguration config = new HttpConfiguration();
     417          99 :     config.setRequestHeaderSize(requestHeaderSize);
     418          99 :     config.setSendServerVersion(false);
     419          99 :     config.setSendDateHeader(true);
     420          99 :     return config;
     421             :   }
     422             : 
     423             :   static boolean isReverseProxied(URI[] listenUrls) {
     424          99 :     for (URI u : listenUrls) {
     425          99 :       if ("http".equals(u.getScheme()) || "https".equals(u.getScheme())) {
     426          99 :         return false;
     427             :       }
     428             :     }
     429           1 :     return true;
     430             :   }
     431             : 
     432             :   static URI[] listenURLs(Config cfg) {
     433          99 :     String[] urls = cfg.getStringList("httpd", null, "listenurl");
     434          99 :     if (urls.length == 0) {
     435           0 :       urls = new String[] {"http://*:8080/"};
     436             :     }
     437             : 
     438          99 :     final URI[] r = new URI[urls.length];
     439          99 :     for (int i = 0; i < r.length; i++) {
     440          99 :       final String s = urls[i];
     441             :       try {
     442          99 :         r[i] = new URI(s);
     443           0 :       } catch (URISyntaxException e) {
     444           0 :         throw new IllegalArgumentException("Invalid httpd.listenurl " + s, e);
     445          99 :       }
     446             :     }
     447          99 :     return r;
     448             :   }
     449             : 
     450             :   private Path getFile(Config cfg, String name, String def) {
     451           0 :     String path = cfg.getString("httpd", null, name);
     452           0 :     if (path == null || path.length() == 0) {
     453           0 :       path = def;
     454             :     }
     455           0 :     return site.resolve(path);
     456             :   }
     457             : 
     458             :   private QueuedThreadPool threadPool(Config cfg, ThreadSettingsConfig threadSettingsConfig) {
     459          99 :     int maxThreads = threadSettingsConfig.getHttpdMaxThreads();
     460          99 :     int minThreads = cfg.getInt("httpd", null, "minthreads", 5);
     461          99 :     int maxQueued = cfg.getInt("httpd", null, "maxqueued", 200);
     462          99 :     int idleTimeout = (int) MILLISECONDS.convert(60, SECONDS);
     463          99 :     int maxCapacity = maxQueued == 0 ? Integer.MAX_VALUE : Math.max(minThreads, maxQueued);
     464          99 :     QueuedThreadPool pool =
     465             :         new QueuedThreadPool(
     466             :             maxThreads,
     467             :             minThreads,
     468             :             idleTimeout,
     469             :             new BlockingArrayQueue<>(
     470             :                 minThreads, // capacity,
     471             :                 minThreads, // growBy,
     472             :                 maxCapacity // maxCapacity
     473             :                 ));
     474          99 :     pool.setName("HTTP");
     475          99 :     return pool;
     476             :   }
     477             : 
     478             :   private Handler makeContext(JettyEnv env, Config cfg, SessionHandler sessionHandler) {
     479          99 :     final Set<String> paths = new HashSet<>();
     480          99 :     for (URI u : listenURLs(cfg)) {
     481          99 :       String p = u.getPath();
     482          99 :       if (p == null || p.isEmpty()) {
     483           2 :         p = "/";
     484             :       }
     485          99 :       while (1 < p.length() && p.endsWith("/")) {
     486           0 :         p = p.substring(0, p.length() - 1);
     487             :       }
     488          99 :       paths.add(p);
     489             :     }
     490             : 
     491          99 :     final List<ContextHandler> all = new ArrayList<>();
     492          99 :     for (String path : paths) {
     493          99 :       all.add(makeContext(path, env, cfg, sessionHandler));
     494          99 :     }
     495             : 
     496          99 :     if (all.size() == 1) {
     497             :       // If we only have one context path in our web space, return it
     498             :       // without any wrapping so Jetty has less work to do per-request.
     499             :       //
     500          99 :       return all.get(0);
     501             :     }
     502             :     // We have more than one path served out of this container so
     503             :     // combine them in a handler which supports dispatching to the
     504             :     // individual contexts.
     505             :     //
     506           0 :     final ContextHandlerCollection r = new ContextHandlerCollection();
     507           0 :     r.setHandlers(all.toArray(new Handler[0]));
     508           0 :     return r;
     509             :   }
     510             : 
     511             :   private ContextHandler makeContext(
     512             :       final String contextPath, JettyEnv env, Config cfg, SessionHandler sessionHandler) {
     513          99 :     final ServletContextHandler app = new ServletContextHandler();
     514             : 
     515             :     // This enables the use of sessions in Jetty, feature available
     516             :     // for Gerrit plug-ins to enable user-level sessions.
     517             :     //
     518          99 :     app.setSessionHandler(sessionHandler);
     519          99 :     app.setErrorHandler(new HiddenErrorHandler());
     520             : 
     521             :     // This is the path we are accessed by clients within our domain.
     522             :     //
     523          99 :     app.setContextPath(contextPath);
     524             : 
     525             :     // HTTP front-end filters to be used as surrogate of Apache HTTP
     526             :     // reverse-proxy filtering.
     527             :     // It is meant to be used as simpler tiny deployment of custom-made
     528             :     // security enforcement (Security tokens, IP-based security filtering, others)
     529          99 :     String[] filterClassNames = cfg.getStringList("httpd", null, "filterClass");
     530          99 :     for (String filterClassName : filterClassNames) {
     531             :       try {
     532             :         @SuppressWarnings("unchecked")
     533           1 :         Class<? extends Filter> filterClass =
     534           1 :             (Class<? extends Filter>) Class.forName(filterClassName);
     535           1 :         Filter filter = env.webInjector.getInstance(filterClass);
     536             : 
     537           1 :         Map<String, String> initParams = new HashMap<>();
     538           1 :         Set<String> initParamKeys = cfg.getNames("filterClass", filterClassName, true);
     539           1 :         initParamKeys.forEach(
     540             :             paramKey -> {
     541           1 :               String paramValue = cfg.getString("filterClass", filterClassName, paramKey);
     542           1 :               initParams.put(paramKey, paramValue);
     543           1 :             });
     544             : 
     545           1 :         FilterHolder filterHolder = new FilterHolder(filter);
     546           1 :         if (initParams.size() > 0) {
     547           1 :           filterHolder.setInitParameters(initParams);
     548             :         }
     549           1 :         app.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC));
     550           0 :       } catch (Exception e) {
     551           0 :         throw new IllegalArgumentException(
     552             :             "Unable to instantiate front-end HTTP Filter " + filterClassName, e);
     553           1 :       }
     554             :     }
     555             : 
     556             :     // Perform the same binding as our web.xml would do, but instead
     557             :     // of using the listener to create the injector pass the one we
     558             :     // already have built.
     559             :     //
     560          99 :     GuiceFilter filter = env.webInjector.getInstance(GuiceFilter.class);
     561          99 :     app.addFilter(
     562          99 :         new FilterHolder(filter), "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC));
     563          99 :     app.addEventListener(
     564          99 :         new GuiceServletContextListener() {
     565             :           @Override
     566             :           protected Injector getInjector() {
     567          99 :             return env.webInjector;
     568             :           }
     569             :         });
     570             : 
     571             :     // Jetty requires at least one servlet be bound before it will
     572             :     // bother running the filter above. Since the filter has all
     573             :     // of our URLs except the static resources, the only servlet
     574             :     // we need to bind is the default static resource servlet from
     575             :     // the Jetty container.
     576             :     //
     577          99 :     final ServletHolder ds = app.addServlet(DefaultServlet.class, "/");
     578          99 :     ds.setInitParameter("dirAllowed", "false");
     579          99 :     ds.setInitParameter("redirectWelcome", "false");
     580          99 :     ds.setInitParameter("useFileMappedBuffer", "false");
     581          99 :     ds.setInitParameter("gzip", "true");
     582             : 
     583          99 :     app.setWelcomeFiles(new String[0]);
     584          99 :     return app;
     585             :   }
     586             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750