Skip to content

Commit e60a2a4

Browse files
committed
Enable Http Server with two https ports
Enable http server with another alternative https port, this gives us the freedom that if the second port is needed.
1 parent e2f403b commit e60a2a4

File tree

6 files changed

+193
-72
lines changed

6 files changed

+193
-72
lines changed

http-server/src/main/java/com/facebook/airlift/http/server/HttpServer.java

Lines changed: 94 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public HttpServer(HttpServerInfo httpServerInfo,
170170
"http-server-timeout",
171171
config.getTimeoutConcurrency(),
172172
config.getTimeoutThreads());
173+
173174
// set up HTTP connector
174175
ServerConnector httpConnector;
175176
if (config.isHttpEnabled()) {
@@ -216,77 +217,20 @@ public HttpServer(HttpServerInfo httpServerInfo,
216217
server.addConnector(httpConnector);
217218
}
218219

219-
List<String> includedCipherSuites = config.getHttpsIncludedCipherSuites();
220-
List<String> excludedCipherSuites = config.getHttpsExcludedCipherSuites();
221-
222-
// set up NIO-based HTTPS connector
223-
ServerConnector httpsConnector;
220+
// Set up NIO-based HTTPS connector.
224221
if (config.isHttpsEnabled()) {
225-
HttpConfiguration httpsConfiguration = new HttpConfiguration(baseHttpConfiguration);
226-
httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
227-
228-
SslContextFactory sslContextFactory = new SslContextFactory();
229-
Optional<KeyStore> pemKeyStore = tryLoadPemKeyStore(config);
230-
if (pemKeyStore.isPresent()) {
231-
sslContextFactory.setKeyStore(pemKeyStore.get());
232-
sslContextFactory.setKeyStorePassword("");
233-
}
234-
else {
235-
sslContextFactory.setKeyStorePath(config.getKeystorePath());
236-
sslContextFactory.setKeyStorePassword(config.getKeystorePassword());
237-
if (config.getKeyManagerPassword() != null) {
238-
sslContextFactory.setKeyManagerPassword(config.getKeyManagerPassword());
239-
}
240-
}
241-
if (config.getTrustStorePath() != null) {
242-
Optional<KeyStore> pemTrustStore = tryLoadPemTrustStore(config);
243-
if (pemTrustStore.isPresent()) {
244-
sslContextFactory.setTrustStore(pemTrustStore.get());
245-
sslContextFactory.setTrustStorePassword("");
246-
}
247-
else {
248-
sslContextFactory.setTrustStorePath(config.getTrustStorePath());
249-
sslContextFactory.setTrustStorePassword(config.getTrustStorePassword());
250-
}
251-
}
252-
253-
sslContextFactory.setIncludeCipherSuites(includedCipherSuites.toArray(new String[0]));
254-
sslContextFactory.setExcludeCipherSuites(excludedCipherSuites.toArray(new String[0]));
255-
sslContextFactory.setSecureRandomAlgorithm(config.getSecureRandomAlgorithm());
256-
sslContextFactory.setWantClientAuth(true);
257-
sslContextFactory.setSslSessionTimeout((int) config.getSslSessionTimeout().getValue(SECONDS));
258-
sslContextFactory.setSslSessionCacheSize(config.getSslSessionCacheSize());
259-
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, "http/1.1");
260-
261-
Integer acceptors = config.getHttpsAcceptorThreads();
262-
Integer selectors = config.getHttpsSelectorThreads();
263-
httpsConnector = createServerConnector(
264-
httpServerInfo.getHttpsChannel(),
265-
server,
266-
null,
267-
concurrentScheduler,
268-
firstNonNull(acceptors, -1),
269-
firstNonNull(selectors, -1),
270-
sslConnectionFactory,
271-
new HttpConnectionFactory(httpsConfiguration));
272-
httpsConnector.setName("https");
273-
httpsConnector.setPort(httpServerInfo.getHttpsUri().getPort());
274-
httpsConnector.setIdleTimeout(config.getNetworkMaxIdleTime().toMillis());
275-
httpsConnector.setHost(nodeInfo.getBindIp().getHostAddress());
276-
httpsConnector.setAcceptQueueSize(config.getHttpAcceptQueueSize());
277-
278-
// track connection statistics
279-
ConnectionStatistics connectionStats = new ConnectionStatistics();
280-
httpsConnector.addBean(connectionStats);
281-
this.httpsConnectionStats = new ConnectionStats(connectionStats);
282-
283-
if (channelListener != null) {
284-
httpsConnector.addBean(channelListener);
285-
}
286-
222+
ServerConnector httpsConnector = createHttpsConnector(config, nodeInfo, baseHttpConfiguration, concurrentScheduler,
223+
channelListener, "https", httpServerInfo.getHttpsUri().getPort(), httpServerInfo.getHttpsChannel());
287224
server.addConnector(httpsConnector);
288225
}
289226

227+
// Set up NIO-based alternative HTTPS connector.
228+
if (config.isHttpsEnabled() && config.isAlternativeHttpsEnabled()) {
229+
ServerConnector alternativeHttpsConnector = createHttpsConnector(config, nodeInfo, baseHttpConfiguration, concurrentScheduler,
230+
channelListener, "alternative-https", httpServerInfo.getAlternativeHttpsUri().getPort(), httpServerInfo.getAlternativeHttpsChannel());
231+
server.addConnector(alternativeHttpsConnector);
232+
}
233+
290234
// set up NIO-based Admin connector
291235
ServerConnector adminConnector;
292236
if (theAdminServlet != null && config.isAdminEnabled()) {
@@ -308,8 +252,8 @@ public HttpServer(HttpServerInfo httpServerInfo,
308252
}
309253
sslContextFactory.setSecureRandomAlgorithm(config.getSecureRandomAlgorithm());
310254
sslContextFactory.setWantClientAuth(true);
311-
sslContextFactory.setIncludeCipherSuites(includedCipherSuites.toArray(new String[0]));
312-
sslContextFactory.setExcludeCipherSuites(excludedCipherSuites.toArray(new String[0]));
255+
sslContextFactory.setIncludeCipherSuites(config.getHttpsIncludedCipherSuites().toArray(new String[0]));
256+
sslContextFactory.setExcludeCipherSuites(config.getHttpsExcludedCipherSuites().toArray(new String[0]));
313257
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, "http/1.1");
314258
adminConnector = createServerConnector(
315259
httpServerInfo.getAdminChannel(),
@@ -370,7 +314,7 @@ public HttpServer(HttpServerInfo httpServerInfo,
370314
handlers.addHandler(gzipHandler);
371315
}
372316

373-
handlers.addHandler(createServletContext(config, defaultServlet, servlets, parameters, filters, tokenManager, loginService, authorizer, "http", "https"));
317+
handlers.addHandler(createServletContext(config, defaultServlet, servlets, parameters, filters, tokenManager, loginService, authorizer, "http", "https", "alternative-https"));
374318

375319
if (config.isRequestStatsEnabled()) {
376320
RequestLogHandler statsRecorder = new RequestLogHandler();
@@ -649,4 +593,84 @@ private static ServerConnector createServerConnector(
649593
connector.open(channel);
650594
return connector;
651595
}
596+
597+
private ServerConnector createHttpsConnector(
598+
HttpServerConfig config,
599+
NodeInfo nodeInfo,
600+
HttpConfiguration baseHttpConfiguration,
601+
ConcurrentScheduler concurrentScheduler,
602+
HttpServerChannelListener channelListener,
603+
String httpsName,
604+
int httpsPort,
605+
ServerSocketChannel socketChannel)
606+
throws IOException
607+
{
608+
ServerConnector httpsConnector;
609+
List<String> includedCipherSuites = config.getHttpsIncludedCipherSuites();
610+
List<String> excludedCipherSuites = config.getHttpsExcludedCipherSuites();
611+
612+
HttpConfiguration httpsConfiguration = new HttpConfiguration(baseHttpConfiguration);
613+
httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
614+
615+
SslContextFactory sslContextFactory = new SslContextFactory();
616+
Optional<KeyStore> pemKeyStore = tryLoadPemKeyStore(config);
617+
if (pemKeyStore.isPresent()) {
618+
sslContextFactory.setKeyStore(pemKeyStore.get());
619+
sslContextFactory.setKeyStorePassword("");
620+
}
621+
else {
622+
sslContextFactory.setKeyStorePath(config.getKeystorePath());
623+
sslContextFactory.setKeyStorePassword(config.getKeystorePassword());
624+
if (config.getKeyManagerPassword() != null) {
625+
sslContextFactory.setKeyManagerPassword(config.getKeyManagerPassword());
626+
}
627+
}
628+
if (config.getTrustStorePath() != null) {
629+
Optional<KeyStore> pemTrustStore = tryLoadPemTrustStore(config);
630+
if (pemTrustStore.isPresent()) {
631+
sslContextFactory.setTrustStore(pemTrustStore.get());
632+
sslContextFactory.setTrustStorePassword("");
633+
}
634+
else {
635+
sslContextFactory.setTrustStorePath(config.getTrustStorePath());
636+
sslContextFactory.setTrustStorePassword(config.getTrustStorePassword());
637+
}
638+
}
639+
640+
sslContextFactory.setIncludeCipherSuites(includedCipherSuites.toArray(new String[0]));
641+
sslContextFactory.setExcludeCipherSuites(excludedCipherSuites.toArray(new String[0]));
642+
sslContextFactory.setSecureRandomAlgorithm(config.getSecureRandomAlgorithm());
643+
sslContextFactory.setWantClientAuth(true);
644+
sslContextFactory.setSslSessionTimeout((int) config.getSslSessionTimeout().getValue(SECONDS));
645+
sslContextFactory.setSslSessionCacheSize(config.getSslSessionCacheSize());
646+
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, "http/1.1");
647+
648+
Integer acceptors = config.getHttpsAcceptorThreads();
649+
Integer selectors = config.getHttpsSelectorThreads();
650+
httpsConnector = createServerConnector(
651+
socketChannel,
652+
server,
653+
null,
654+
concurrentScheduler,
655+
firstNonNull(acceptors, -1),
656+
firstNonNull(selectors, -1),
657+
sslConnectionFactory,
658+
new HttpConnectionFactory(httpsConfiguration));
659+
httpsConnector.setName(httpsName);
660+
httpsConnector.setPort(httpsPort);
661+
httpsConnector.setIdleTimeout(config.getNetworkMaxIdleTime().toMillis());
662+
httpsConnector.setHost(nodeInfo.getBindIp().getHostAddress());
663+
httpsConnector.setAcceptQueueSize(config.getHttpAcceptQueueSize());
664+
665+
// track connection statistics
666+
ConnectionStatistics connectionStats = new ConnectionStatistics();
667+
httpsConnector.addBean(connectionStats);
668+
this.httpsConnectionStats = new ConnectionStats(connectionStats);
669+
670+
if (channelListener != null) {
671+
httpsConnector.addBean(channelListener);
672+
}
673+
674+
return httpsConnector;
675+
}
652676
}

http-server/src/main/java/com/facebook/airlift/http/server/HttpServerConfig.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ public enum AuthorizationPolicy
7272
private int httpAcceptQueueSize = 8000;
7373

7474
private boolean httpsEnabled;
75+
private boolean alternativeHttpsEnabled;
7576
private int httpsPort = 8443;
77+
private int alternativeHttpsPort = 8444;
7678
private String keystorePath;
7779
private String keystorePassword;
7880
private String keyManagerPassword;
@@ -178,18 +180,42 @@ public HttpServerConfig setHttpsEnabled(boolean httpsEnabled)
178180
return this;
179181
}
180182

183+
public boolean isAlternativeHttpsEnabled()
184+
{
185+
return alternativeHttpsEnabled;
186+
}
187+
188+
@Config("http-server.https.alternative.enabled")
189+
public HttpServerConfig setAlternativeHttpsEnabled(boolean alternativeHttpsEnabled)
190+
{
191+
this.alternativeHttpsEnabled = alternativeHttpsEnabled;
192+
return this;
193+
}
194+
181195
public int getHttpsPort()
182196
{
183197
return httpsPort;
184198
}
185199

200+
public int getAlternativeHttpsPort()
201+
{
202+
return alternativeHttpsPort;
203+
}
204+
186205
@Config("http-server.https.port")
187206
public HttpServerConfig setHttpsPort(int httpsPort)
188207
{
189208
this.httpsPort = httpsPort;
190209
return this;
191210
}
192211

212+
@Config("http-server.https.alternative-port")
213+
public HttpServerConfig setAlternativeHttpsPort(int httpsPort)
214+
{
215+
this.alternativeHttpsPort = httpsPort;
216+
return this;
217+
}
218+
193219
@MinDuration("1s")
194220
public Duration getSslSessionTimeout()
195221
{

http-server/src/main/java/com/facebook/airlift/http/server/HttpServerInfo.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ public class HttpServerInfo
3535
private final URI httpUri;
3636
private final URI httpExternalUri;
3737
private final URI httpsUri;
38+
private final URI alternativeHttpsUri;
3839
private final URI httpsExternalUri;
40+
private final URI alternativeHttpsExternalUri;
3941
private final URI adminUri;
4042
private final URI adminExternalUri;
4143

4244
private final ServerSocketChannel httpChannel;
4345
private final ServerSocketChannel httpsChannel;
46+
private final ServerSocketChannel alternativeHttpsChannel;
4447
private final ServerSocketChannel adminChannel;
4548

4649
@Inject
@@ -61,11 +64,25 @@ public HttpServerInfo(HttpServerConfig config, NodeInfo nodeInfo)
6164
httpsChannel = createChannel(nodeInfo.getBindIp(), config.getHttpsPort(), config.getHttpAcceptQueueSize());
6265
httpsUri = buildUri("https", nodeInfo.getInternalAddress(), port(httpsChannel));
6366
httpsExternalUri = buildUri("https", nodeInfo.getExternalAddress(), httpsUri.getPort());
67+
68+
if (config.isAlternativeHttpsEnabled()) {
69+
alternativeHttpsChannel = createChannel(nodeInfo.getBindIp(), config.getAlternativeHttpsPort(), config.getHttpAcceptQueueSize());
70+
alternativeHttpsUri = buildUri("https", nodeInfo.getInternalAddress(), port(alternativeHttpsChannel));
71+
alternativeHttpsExternalUri = buildUri("https", nodeInfo.getExternalAddress(), alternativeHttpsUri.getPort());
72+
}
73+
else {
74+
alternativeHttpsChannel = null;
75+
alternativeHttpsUri = null;
76+
alternativeHttpsExternalUri = null;
77+
}
6478
}
6579
else {
6680
httpsChannel = null;
6781
httpsUri = null;
6882
httpsExternalUri = null;
83+
alternativeHttpsChannel = null;
84+
alternativeHttpsUri = null;
85+
alternativeHttpsExternalUri = null;
6986
}
7087

7188
if (config.isAdminEnabled()) {
@@ -101,11 +118,21 @@ public URI getHttpsUri()
101118
return httpsUri;
102119
}
103120

121+
public URI getAlternativeHttpsUri()
122+
{
123+
return alternativeHttpsUri;
124+
}
125+
104126
public URI getHttpsExternalUri()
105127
{
106128
return httpsExternalUri;
107129
}
108130

131+
public URI getAlternativeHttpsExternalUri()
132+
{
133+
return alternativeHttpsExternalUri;
134+
}
135+
109136
public URI getAdminUri()
110137
{
111138
return adminUri;
@@ -131,6 +158,11 @@ ServerSocketChannel getAdminChannel()
131158
return adminChannel;
132159
}
133160

161+
ServerSocketChannel getAlternativeHttpsChannel()
162+
{
163+
return alternativeHttpsChannel;
164+
}
165+
134166
private static URI buildUri(String scheme, String host, int port)
135167
{
136168
try {

http-server/src/test/java/com/facebook/airlift/http/server/TestHttpServerConfig.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ public void testDefaults()
8787
.setAuthorizationEnabled(false)
8888
.setDefaultAuthorizationPolicy(HttpServerConfig.AuthorizationPolicy.ALLOW)
8989
.setDefaultAllowedRoles("")
90-
.setAllowUnsecureRequestsInAuthorizer(false));
90+
.setAllowUnsecureRequestsInAuthorizer(false)
91+
.setAlternativeHttpsEnabled(false)
92+
.setAlternativeHttpsPort(8444));
9193
}
9294

9395
@Test
@@ -143,6 +145,8 @@ public void testExplicitPropertyMappings()
143145
.put("http-server.authorization.default-policy", "DENY")
144146
.put("http-server.authorization.default-allowed-roles", "user, internal, admin")
145147
.put("http-server.authorization.allow-unsecured-requests", "true")
148+
.put("http-server.https.alternative.enabled", "true")
149+
.put("http-server.https.alternative-port", "4")
146150
.build();
147151

148152
HttpServerConfig expected = new HttpServerConfig()
@@ -194,7 +198,9 @@ public void testExplicitPropertyMappings()
194198
.setAuthorizationEnabled(true)
195199
.setDefaultAuthorizationPolicy(HttpServerConfig.AuthorizationPolicy.DENY)
196200
.setDefaultAllowedRoles("user, internal, admin")
197-
.setAllowUnsecureRequestsInAuthorizer(true);
201+
.setAllowUnsecureRequestsInAuthorizer(true)
202+
.setAlternativeHttpsEnabled(true)
203+
.setAlternativeHttpsPort(4);
198204

199205
ConfigAssertions.assertFullMapping(properties, expected);
200206
}

http-server/src/test/java/com/facebook/airlift/http/server/TestHttpServerInfo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public void testIPv6Url()
4343
serverConfig.setHttpsEnabled(true);
4444
serverConfig.setHttpsPort(0);
4545
serverConfig.setAdminEnabled(true);
46+
serverConfig.setAlternativeHttpsEnabled(true);
47+
serverConfig.setAlternativeHttpsPort(0);
4648

4749
HttpServerInfo httpServerInfo = new HttpServerInfo(serverConfig, nodeInfo);
4850

@@ -58,6 +60,10 @@ public void testIPv6Url()
5860
assertEquals(httpServerInfo.getAdminUri(), new URI("https://[::1]:" + adminPort));
5961
assertEquals(httpServerInfo.getAdminExternalUri(), new URI("https://[2001:db8::2:1]:" + adminPort));
6062

63+
int proxygenPort = httpServerInfo.getAlternativeHttpsUri().getPort();
64+
assertEquals(httpServerInfo.getAlternativeHttpsUri(), new URI("https://[::1]:" + proxygenPort));
65+
assertEquals(httpServerInfo.getAlternativeHttpsExternalUri(), new URI("https://[2001:db8::2:1]:" + proxygenPort));
66+
6167
closeChannels(httpServerInfo);
6268
}
6369

0 commit comments

Comments
 (0)