4141import org .apache .zookeeper .metrics .MetricsProviderLifeCycleException ;
4242import org .apache .zookeeper .metrics .Summary ;
4343import org .apache .zookeeper .metrics .SummarySet ;
44+ import org .apache .zookeeper .server .admin .UnifiedConnectionFactory ;
45+ import org .eclipse .jetty .http .HttpVersion ;
46+ import org .eclipse .jetty .server .HttpConfiguration ;
47+ import org .eclipse .jetty .server .HttpConnectionFactory ;
48+ import org .eclipse .jetty .server .SecureRequestCustomizer ;
4449import org .eclipse .jetty .server .Server ;
4550import org .eclipse .jetty .server .ServerConnector ;
4651import org .eclipse .jetty .servlet .ServletContextHandler ;
@@ -84,6 +89,7 @@ public class PrometheusMetricsProvider implements MetricsProvider {
8489 private boolean wantClientAuth = true ; // Secure default
8590 private String enabledProtocols ;
8691 private String cipherSuites ;
92+ private int httpVersion ;
8793
8894 // Constants for configuration
8995 public static final String HTTP_HOST = "httpHost" ;
@@ -101,7 +107,10 @@ public class PrometheusMetricsProvider implements MetricsProvider {
101107 public static final String SSL_WANT_CLIENT_AUTH = "ssl.want.client.auth" ;
102108 public static final String SSL_ENABLED_PROTOCOLS = "ssl.enabledProtocols" ;
103109 public static final String SSL_ENABLED_CIPHERS = "ssl.ciphersuites" ;
110+ public static final String HTTP_VERSION = "httpVersion" ;
104111 public static final int SCAN_INTERVAL = 60 * 10 ; // 10 minutes
112+ public static final int DEFAULT_HTTP_VERSION = 11 ; // based on HttpVersion.java in jetty
113+ public static final int DEFAULT_STS_MAX_AGE = 1 * 24 * 60 * 60 ; // seconds in a day
105114
106115 /**
107116 * Custom servlet to disable the TRACE method for security reasons.
@@ -139,6 +148,7 @@ public void configure(Properties configuration) throws MetricsProviderLifeCycleE
139148 this .wantClientAuth = Boolean .parseBoolean (configuration .getProperty (SSL_WANT_CLIENT_AUTH , "true" ));
140149 this .enabledProtocols = configuration .getProperty (SSL_ENABLED_PROTOCOLS );
141150 this .cipherSuites = configuration .getProperty (SSL_ENABLED_CIPHERS );
151+ this .httpVersion = Integer .getInteger (HTTP_VERSION , DEFAULT_HTTP_VERSION );
142152 }
143153
144154 // Validate that at least one port is configured.
@@ -171,23 +181,47 @@ public void start() throws MetricsProviderLifeCycleException {
171181 int acceptors = 1 ;
172182 int selectors = 1 ;
173183
174- // Configure HTTP connector if enabled
175- if (this .httpPort != -1 ) {
176- ServerConnector httpConnector = new ServerConnector (server , acceptors , selectors );
177- httpConnector .setPort (this .httpPort );
178- httpConnector .setHost (this .host );
179- server .addConnector (httpConnector );
180- }
184+ ServerConnector connector = null ;
185+
186+ if (this .httpPort != -1 && this .httpsPort != -1 && this .httpPort == this .httpsPort ) {
187+ SecureRequestCustomizer customizer = new SecureRequestCustomizer ();
188+ customizer .setStsMaxAge (DEFAULT_STS_MAX_AGE );
189+ customizer .setStsIncludeSubDomains (true );
190+
191+ HttpConfiguration config = new HttpConfiguration ();
192+ config .setSecureScheme ("https" );
193+ config .addCustomizer (customizer );
181194
182- // Configure HTTPS connector if enabled
183- if (this .httpsPort != -1 ) {
184195 SslContextFactory .Server sslContextFactory = createSslContextFactory ();
185- KeyStoreScanner keystoreScanner = new KeyStoreScanner (sslContextFactory );
186- keystoreScanner .setScanInterval (SCAN_INTERVAL );
187- server .addBean (keystoreScanner );
188- server .addConnector (createSslConnector (server , acceptors , selectors , sslContextFactory ));
196+ setKeyStoreScanner (sslContextFactory );
197+
198+ String nextProtocol = HttpVersion .fromVersion (httpVersion ).asString ();
199+ connector = new ServerConnector (server ,
200+ new UnifiedConnectionFactory (sslContextFactory , nextProtocol ),
201+ new HttpConnectionFactory (config ));
202+ connector .setPort (this .httpPort );
203+ connector .setHost (this .host );
204+ LOG .debug ("Created unified ServerConnector for host: {}, httpPort: {}" , host , httpPort );
205+ } else {
206+ // Configure HTTP connector if enabled
207+ if (this .httpPort != -1 ) {
208+ connector = new ServerConnector (server , acceptors , selectors );
209+ connector .setPort (this .httpPort );
210+ connector .setHost (this .host );
211+ LOG .debug ("Created ServerConnector for host: {}, httpPort: {}" , host , httpPort );
212+ }
213+
214+ // Configure HTTPS connector if enabled
215+ if (this .httpsPort != -1 ) {
216+ SslContextFactory .Server sslContextFactory = createSslContextFactory ();
217+ setKeyStoreScanner (sslContextFactory );
218+ connector = createSslConnector (server , acceptors , selectors , sslContextFactory );
219+ LOG .debug ("Created HTTPS ServerConnector for host: {}, httpsPort: {}" , host , httpsPort );
220+ }
189221 }
190222
223+ server .addConnector (connector );
224+
191225 // Set up the servlet context handler
192226 ServletContextHandler context = new ServletContextHandler ();
193227 context .setContextPath ("/" );
@@ -207,6 +241,12 @@ public void start() throws MetricsProviderLifeCycleException {
207241 }
208242 }
209243
244+ private void setKeyStoreScanner (SslContextFactory .Server sslContextFactory ) {
245+ KeyStoreScanner keystoreScanner = new KeyStoreScanner (sslContextFactory );
246+ keystoreScanner .setScanInterval (SCAN_INTERVAL );
247+ server .addBean (keystoreScanner );
248+ }
249+
210250 /**
211251 * Creates and configures the SslContextFactory for the server.
212252 *
0 commit comments