summaryrefslogtreecommitdiffstats
path: root/container-core
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-04-08 18:26:41 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-04-09 18:51:20 +0200
commitf42e9f86f83c3aa594891b835bcf6c14566cec92 (patch)
tree9c9bc7d899744d19206aea4b393162ae9ad836c9 /container-core
parent228cf930871bcd5174bf1b848007a5f76effe0b1 (diff)
Add HTTP/2.0 configuration of connector and connection factories
Diffstat (limited to 'container-core')
-rw-r--r--container-core/abi-spec.json4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java92
-rw-r--r--container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def3
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/TestDrivers.java1
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)