diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-04-08 18:26:41 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-04-09 18:51:20 +0200 |
commit | f42e9f86f83c3aa594891b835bcf6c14566cec92 (patch) | |
tree | 9c9bc7d899744d19206aea4b393162ae9ad836c9 /container-core | |
parent | 228cf930871bcd5174bf1b848007a5f76effe0b1 (diff) |
Add HTTP/2.0 configuration of connector and connection factories
Diffstat (limited to 'container-core')
4 files changed, 82 insertions, 18 deletions
diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index da8ed609dfc..10183535ce1 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -907,6 +907,7 @@ "public com.yahoo.jdisc.http.ConnectorConfig$Builder secureRedirect(com.yahoo.jdisc.http.ConnectorConfig$SecureRedirect$Builder)", "public com.yahoo.jdisc.http.ConnectorConfig$Builder maxRequestsPerConnection(int)", "public com.yahoo.jdisc.http.ConnectorConfig$Builder maxConnectionLife(double)", + "public com.yahoo.jdisc.http.ConnectorConfig$Builder http2Enabled(boolean)", "public final boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)", "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", @@ -1228,7 +1229,8 @@ "public com.yahoo.jdisc.http.ConnectorConfig$ProxyProtocol proxyProtocol()", "public com.yahoo.jdisc.http.ConnectorConfig$SecureRedirect secureRedirect()", "public int maxRequestsPerConnection()", - "public double maxConnectionLife()" + "public double maxConnectionLife()", + "public boolean http2Enabled()" ], "fields": [ "public static final java.lang.String CONFIG_DEF_MD5", diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index d7ad12a5c64..753afdaf052 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java @@ -7,6 +7,8 @@ import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.ssl.SslContextFactoryProvider; import com.yahoo.security.tls.MixedMode; import com.yahoo.security.tls.TransportSecurityUtils; +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.DetectorConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; @@ -18,6 +20,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; +import java.util.Collection; import java.util.List; /** @@ -76,41 +79,72 @@ public class ConnectorFactory { } private List<ConnectionFactory> createConnectionFactories(Metric metric) { - HttpConnectionFactory httpFactory = newHttpConnectionFactory(); if (!isSslEffectivelyEnabled(connectorConfig)) { - return List.of(httpFactory); + return List.of(newHttp1ConnectionFactory()); } else if (connectorConfig.ssl().enabled()) { - return connectionFactoriesForHttps(metric, httpFactory); + return connectionFactoriesForHttps(metric); } else if (TransportSecurityUtils.isTransportSecurityEnabled()) { switch (TransportSecurityUtils.getInsecureMixedMode()) { case TLS_CLIENT_MIXED_SERVER: case PLAINTEXT_CLIENT_MIXED_SERVER: - return List.of(new DetectorConnectionFactory(newSslConnectionFactory(metric, httpFactory)), httpFactory); + return connectionFactoriesForHttpsMixedMode(metric); case DISABLED: - return connectionFactoriesForHttps(metric, httpFactory); + return connectionFactoriesForHttps(metric); default: throw new IllegalStateException(); } } else { - return List.of(httpFactory); + return List.of(newHttp1ConnectionFactory()); } } - private List<ConnectionFactory> connectionFactoriesForHttps(Metric metric, HttpConnectionFactory httpFactory) { + private List<ConnectionFactory> connectionFactoriesForHttps(Metric metric) { ConnectorConfig.ProxyProtocol proxyProtocolConfig = connectorConfig.proxyProtocol(); - SslConnectionFactory sslFactory = newSslConnectionFactory(metric, httpFactory); - if (proxyProtocolConfig.enabled()) { - if (proxyProtocolConfig.mixedMode()) { - return List.of(new DetectorConnectionFactory(sslFactory, new ProxyConnectionFactory(sslFactory.getProtocol())), sslFactory, httpFactory); + HttpConnectionFactory http1Factory = newHttp1ConnectionFactory(); + if (connectorConfig.http2Enabled()) { + HTTP2ServerConnectionFactory http2Factory = newHttp2ConnectionFactory(); + ALPNServerConnectionFactory alpnFactory = newAlpnConnectionFactory(List.of(http1Factory, http2Factory), http1Factory); + SslConnectionFactory sslFactory = newSslConnectionFactory(metric, alpnFactory); + if (proxyProtocolConfig.enabled()) { + if (proxyProtocolConfig.mixedMode()) { + ProxyConnectionFactory proxyProtocolFactory = newProxyProtocolConnectionFactory(alpnFactory); + DetectorConnectionFactory detectorFactory = newDetectorConnectionFactory(sslFactory, proxyProtocolFactory); + return List.of(detectorFactory, proxyProtocolFactory, sslFactory, alpnFactory, http1Factory, http2Factory); + } else { + ProxyConnectionFactory proxyProtocolFactory = newProxyProtocolConnectionFactory(alpnFactory); + return List.of(proxyProtocolFactory, sslFactory, alpnFactory, http1Factory, http2Factory); + } } else { - return List.of(new ProxyConnectionFactory(sslFactory.getProtocol()), sslFactory, httpFactory); + return List.of(sslFactory, alpnFactory, http1Factory, http2Factory); } } else { - return List.of(sslFactory, httpFactory); + SslConnectionFactory sslFactory = newSslConnectionFactory(metric, http1Factory); + if (proxyProtocolConfig.enabled()) { + if (proxyProtocolConfig.mixedMode()) { + ProxyConnectionFactory proxyProtocolFactory = newProxyProtocolConnectionFactory(sslFactory); + DetectorConnectionFactory detectorFactory = newDetectorConnectionFactory(sslFactory, proxyProtocolFactory); + return List.of(detectorFactory, proxyProtocolFactory, sslFactory, http1Factory); + } else { + ProxyConnectionFactory proxyProtocolFactory = newProxyProtocolConnectionFactory(sslFactory); + return List.of(proxyProtocolFactory, sslFactory, newHttp1ConnectionFactory()); + } + } else { + return List.of(sslFactory, http1Factory); + } } } - private HttpConnectionFactory newHttpConnectionFactory() { + private List<ConnectionFactory> connectionFactoriesForHttpsMixedMode(Metric metric) { + // No support for proxy-protocol/http2 when using HTTP with TLS mixed mode + HttpConnectionFactory httpFactory = newHttp1ConnectionFactory(); + SslConnectionFactory sslFactory = newSslConnectionFactory(metric, httpFactory); + // Detector connection factory with single alternative will fallback to next protocol in list (httpFactory in this case) + // Cannot specify HttpConnectionFactory as alternative it does not implement ConnectionFactory.Detecting + DetectorConnectionFactory detectorFactory = newDetectorConnectionFactory(sslFactory); + return List.of(detectorFactory, httpFactory, sslFactory); + } + + private HttpConfiguration newHttpConfiguration() { HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.setSendDateHeader(true); httpConfig.setSendServerVersion(false); @@ -122,16 +156,40 @@ public class ConnectorFactory { if (isSslEffectivelyEnabled(connectorConfig)) { httpConfig.addCustomizer(new SecureRequestCustomizer()); } - return new HttpConnectionFactory(httpConfig); + return httpConfig; + } + + private HttpConnectionFactory newHttp1ConnectionFactory() { + return new HttpConnectionFactory(newHttpConfiguration()); } - private SslConnectionFactory newSslConnectionFactory(Metric metric, HttpConnectionFactory httpFactory) { + private HTTP2ServerConnectionFactory newHttp2ConnectionFactory() { + return new HTTP2ServerConnectionFactory(newHttpConfiguration()); + } + + private SslConnectionFactory newSslConnectionFactory(Metric metric, ConnectionFactory wrappedFactory) { SslContextFactory ctxFactory = sslContextFactoryProvider.getInstance(connectorConfig.name(), connectorConfig.listenPort()); - SslConnectionFactory connectionFactory = new SslConnectionFactory(ctxFactory, httpFactory.getProtocol()); + SslConnectionFactory connectionFactory = new SslConnectionFactory(ctxFactory, wrappedFactory.getProtocol()); connectionFactory.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort())); return connectionFactory; } + private ALPNServerConnectionFactory newAlpnConnectionFactory(Collection<ConnectionFactory> alternatives, + ConnectionFactory defaultFactory) { + String[] protocols = alternatives.stream().map(ConnectionFactory::getProtocol).toArray(String[]::new); + ALPNServerConnectionFactory factory = new ALPNServerConnectionFactory(protocols); + factory.setDefaultProtocol(defaultFactory.getProtocol()); + return factory; + } + + private DetectorConnectionFactory newDetectorConnectionFactory(ConnectionFactory.Detecting... alternatives) { + return new DetectorConnectionFactory(alternatives); + } + + private ProxyConnectionFactory newProxyProtocolConnectionFactory(ConnectionFactory wrappedFactory) { + return new ProxyConnectionFactory(wrappedFactory.getProtocol()); + } + private static boolean isSslEffectivelyEnabled(ConnectorConfig config) { return config.ssl().enabled() || (config.implicitTlsEnabled() && TransportSecurityUtils.isTransportSecurityEnabled()); diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def index 055e5ad62d2..cb1e366f843 100644 --- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def +++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def @@ -125,3 +125,6 @@ maxRequestsPerConnection int default=0 # Maximum number of seconds a connection can live before it's marked as non-persistent. Set to '0' to disable. maxConnectionLife double default=0.0 + +# Enable HTTP/2 (in addition to HTTP/1.1 using ALPN) +http2Enabled bool default=false diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java index 7d7530c32e0..cfa71ec68f7 100644 --- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java +++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java @@ -55,6 +55,7 @@ public class TestDrivers { newConfigModule( new ServerConfig.Builder().connectionLog(new ServerConfig.ConnectionLog.Builder().enabled(true)), new ConnectorConfig.Builder() + .http2Enabled(true) .tlsClientAuthEnforcer( new ConnectorConfig.TlsClientAuthEnforcer.Builder() .enable(true) |