From ea880e5a8b25e10b3b72e1a4068a92d54d986ca5 Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Fri, 7 Oct 2022 14:54:01 +0200 Subject: Create separate Jetty handler chain for each connector Use connector name and virtual hosts configuration to route requests between handler chains. --- .../jdisc/http/server/jetty/JettyHttpServer.java | 109 +++++++++++++-------- 1 file changed, 67 insertions(+), 42 deletions(-) (limited to 'container-core/src/main/java/com/yahoo/jdisc/http/server') diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java index dd5181d2bb5..c0b3a336a39 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java @@ -14,11 +14,13 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.jmx.ConnectorServer; import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.handler.gzip.GzipHttpOutputInterceptor; @@ -83,20 +85,13 @@ public class JettyHttpServer extends AbstractServerProvider { listenedPorts.add(connectorConfig.listenPort()); } - JDiscContext jDiscContext = new JDiscContext(filterBindings, - container, - janitor, - metric, - serverConfig); + JDiscContext jDiscContext = new JDiscContext(filterBindings, container, janitor, metric, serverConfig); ServletHolder jdiscServlet = new ServletHolder(new JDiscHttpServlet(jDiscContext)); List connectors = Arrays.stream(server.getConnectors()) .map(JDiscServerConnector.class::cast) .collect(toList()); - - server.setHandler(getHandlerCollection(serverConfig, - connectors, - jdiscServlet)); + server.setHandler(createRootHandler(serverConfig, connectors, jdiscServlet)); this.metricsReporter = new ServerMetricReporter(metric, server); } @@ -136,38 +131,37 @@ public class JettyHttpServer extends AbstractServerProvider { } } - private HandlerCollection getHandlerCollection(ServerConfig serverConfig, - List connectors, - ServletHolder jdiscServlet) { - ServletContextHandler servletContextHandler = createServletContextHandler(); - servletContextHandler.addServlet(jdiscServlet, "/*"); - - var proxyHandler = new HealthCheckProxyHandler(connectors); - proxyHandler.setHandler(servletContextHandler); - - List connectorConfigs = connectors.stream().map(JDiscServerConnector::connectorConfig).collect(toList()); - var authEnforcer = new TlsClientAuthenticationEnforcer(connectorConfigs); - authEnforcer.setHandler(proxyHandler); - - GzipHandler gzipHandler = newGzipHandler(serverConfig); - gzipHandler.setHandler(authEnforcer); - - var statisticsCollector = new HttpResponseStatisticsCollector(serverConfig.metric()); - statisticsCollector.setHandler(gzipHandler); - - StatisticsHandler statisticsHandler = newStatisticsHandler(); - statisticsHandler.setHandler(statisticsCollector); - - HandlerCollection handlerCollection = new HandlerCollection(); - handlerCollection.setHandlers(new Handler[] { statisticsHandler }); - return handlerCollection; + private HandlerCollection createRootHandler( + ServerConfig serverCfg, List connectors, ServletHolder jdiscServlet) { + List connectorCfgs = connectors.stream().map(JDiscServerConnector::connectorConfig).toList(); + List perConnectorHandlers = new ArrayList<>(); + for (JDiscServerConnector connector : connectors) { + ConnectorConfig connectorCfg = connector.connectorConfig(); + List chain = new ArrayList<>(); + chain.add(newGenericStatisticsHandler()); + chain.add(newResponseStatisticsHandler(serverCfg)); + chain.add(newGzipHandler(serverCfg)); + if (connectorCfg.tlsClientAuthEnforcer().enable()) { + chain.add(newTlsClientAuthEnforcerHandler(connectorCfgs)); + } + if (connectorCfg.healthCheckProxy().enable()) { + chain.add(newHealthCheckProxyHandler(connectors)); + } else { + chain.add(newServletHandler(jdiscServlet)); + } + ContextHandler connectorRoot = newConnectorContextHandler(connector, connectorCfg); + addChainToRoot(connectorRoot, chain); + perConnectorHandlers.add(connectorRoot); + } + return new ContextHandlerCollection(perConnectorHandlers.toArray(new ContextHandler[0])); } - private ServletContextHandler createServletContextHandler() { - ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS); - servletContextHandler.setContextPath("/"); - servletContextHandler.setDisplayName(getDisplayName(listenedPorts)); - return servletContextHandler; + private static void addChainToRoot(ContextHandler root, List chain) { + HandlerWrapper parent = root; + for (HandlerWrapper h : chain) { + parent.setHandler(h); + parent = h; + } } private static String getDisplayName(List ports) { @@ -229,13 +223,44 @@ public class JettyHttpServer extends AbstractServerProvider { Server server() { return server; } - private StatisticsHandler newStatisticsHandler() { + private ServletContextHandler newServletHandler(ServletHolder servlet) { + var h = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS); + h.setContextPath("/"); + h.setDisplayName(getDisplayName(listenedPorts)); + h.addServlet(servlet, "/*"); + return h; + } + + private static ContextHandler newConnectorContextHandler(JDiscServerConnector connector, ConnectorConfig connectorCfg) { + ContextHandler ctxHandler = new ContextHandler(); + List allowedServerNames = connectorCfg.serverName().allowed(); + if (allowedServerNames.isEmpty()) { + ctxHandler.setVirtualHosts(new String[]{"@%s".formatted(connector.getName())}); + } else { + ctxHandler.setVirtualHosts(allowedServerNames.toArray(new String[0])); + } + return ctxHandler; + } + + private static HealthCheckProxyHandler newHealthCheckProxyHandler(List connectors) { + return new HealthCheckProxyHandler(connectors); + } + + private static TlsClientAuthenticationEnforcer newTlsClientAuthEnforcerHandler(List connectorCfgs) { + return new TlsClientAuthenticationEnforcer(connectorCfgs); + } + + private static HttpResponseStatisticsCollector newResponseStatisticsHandler(ServerConfig cfg) { + return new HttpResponseStatisticsCollector(cfg.metric()); + } + + private static StatisticsHandler newGenericStatisticsHandler() { StatisticsHandler statisticsHandler = new StatisticsHandler(); statisticsHandler.statsReset(); return statisticsHandler; } - private GzipHandler newGzipHandler(ServerConfig serverConfig) { + private static GzipHandler newGzipHandler(ServerConfig serverConfig) { GzipHandler gzipHandler = new GzipHandlerWithVaryHeaderFixed(); gzipHandler.setCompressionLevel(serverConfig.responseCompressionLevel()); gzipHandler.setInflateBufferSize(8 * 1024); -- cgit v1.2.3