Skip to content

Commit 739762d

Browse files
committed
Added Http2 support
1 parent 60e907d commit 739762d

File tree

11 files changed

+141
-12
lines changed

11 files changed

+141
-12
lines changed

driver/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@
175175
<artifactId>netty-codec-http</artifactId>
176176
<version>${netty.version}</version>
177177
</dependency>
178+
<dependency>
179+
<groupId>io.netty</groupId>
180+
<artifactId>netty-codec-http2</artifactId>
181+
<version>${netty.version}</version>
182+
</dependency>
178183
<dependency>
179184
<groupId>io.netty</groupId>
180185
<artifactId>netty-handler</artifactId>

driver/src/main/java/oracle/nosql/driver/NoSQLHandleConfig.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ public class NoSQLHandleConfig implements Cloneable {
142142
*/
143143
private int maxChunkSize = 0;
144144

145+
/**
146+
* Use http2 protocol
147+
*
148+
* Default: false (use http_1_1)
149+
*/
150+
private boolean http2 = false;
151+
145152
/**
146153
* A RetryHandler, or null if not configured by the user.
147154
*/
@@ -553,6 +560,14 @@ public int getDefaultRequestTimeout() {
553560
return timeout == 0 ? DEFAULT_TIMEOUT : timeout;
554561
}
555562

563+
/**
564+
*
565+
* @return http2 setting
566+
*/
567+
public boolean useHttp2() {
568+
return http2;
569+
}
570+
556571
/**
557572
* Returns the configured table request timeout value, in milliseconds.
558573
* The table request timeout default can be specified independently to allow
@@ -788,6 +803,15 @@ public NoSQLHandleConfig setMaxContentLength(int maxContentLength) {
788803
return this;
789804
}
790805

806+
/**
807+
* Enables http2 protocol
808+
* @return this
809+
*/
810+
public NoSQLHandleConfig useHttp2(boolean enable) {
811+
this.http2 = enable;
812+
return this;
813+
}
814+
791815
/**
792816
* Returns the maximum size, in bytes, of a request operation payload.
793817
* On-premise only. This value is ignored for cloud operations.

driver/src/main/java/oracle/nosql/driver/http/Client.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ public Client(Logger logger,
244244
httpConfig.getNumThreads(),
245245
httpConfig.getConnectionPoolMinSize(),
246246
httpConfig.getConnectionPoolInactivityPeriod(),
247+
httpConfig.useHttp2(),
247248
httpConfig.getMaxContentLength(),
248249
httpConfig.getMaxChunkSize(),
249250
sslCtx,

driver/src/main/java/oracle/nosql/driver/http/NoSQLHandleImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
import javax.net.ssl.SSLException;
1414

15+
import io.netty.handler.codec.http2.Http2SecurityUtil;
16+
import io.netty.handler.ssl.ApplicationProtocolConfig;
17+
import io.netty.handler.ssl.ApplicationProtocolNames;
18+
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
1519
import oracle.nosql.driver.AuthorizationProvider;
1620
import oracle.nosql.driver.NoSQLHandle;
1721
import oracle.nosql.driver.NoSQLHandleConfig;
@@ -124,6 +128,14 @@ private void configSslContext(NoSQLHandleConfig config) {
124128
}
125129
builder.sessionTimeout(config.getSSLSessionTimeout());
126130
builder.sessionCacheSize(config.getSSLSessionCacheSize());
131+
if (config.useHttp2()) {
132+
builder.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE);
133+
builder.applicationProtocolConfig(
134+
new ApplicationProtocolConfig(ApplicationProtocolConfig.Protocol.ALPN,
135+
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
136+
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
137+
ApplicationProtocolNames.HTTP_2));
138+
}
127139
config.setSslContext(builder.build());
128140
} catch (SSLException se) {
129141
throw new IllegalStateException(
@@ -137,6 +149,7 @@ private void configAuthProvider(Logger logger, NoSQLHandleConfig config) {
137149
if (ap instanceof StoreAccessTokenProvider) {
138150
final StoreAccessTokenProvider stProvider =
139151
(StoreAccessTokenProvider) ap;
152+
stProvider.useHttp2(config.useHttp2());
140153
if (stProvider.getLogger() == null) {
141154
stProvider.setLogger(logger);
142155
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package oracle.nosql.driver.httpclient;
2+
3+
import io.netty.channel.ChannelHandlerContext;
4+
import io.netty.channel.ChannelPromise;
5+
import io.netty.channel.SimpleChannelInboundHandler;
6+
import io.netty.handler.codec.http2.Http2Settings;
7+
8+
import java.util.concurrent.TimeUnit;
9+
10+
public class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
11+
private final ChannelPromise promise;
12+
13+
public Http2SettingsHandler(ChannelPromise promise) {
14+
this.promise = promise;
15+
}
16+
17+
public void awaitSettings(long timeout, TimeUnit unit) throws Exception {
18+
if (!promise.awaitUninterruptibly(timeout, unit)) {
19+
throw new IllegalStateException("Timed out waiting for settings");
20+
}
21+
}
22+
23+
@Override
24+
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Http2Settings http2Settings) throws Exception {
25+
promise.setSuccess();
26+
channelHandlerContext.pipeline().remove(this);
27+
}
28+
}

driver/src/main/java/oracle/nosql/driver/httpclient/HttpClient.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public class HttpClient {
9696
private final String host;
9797
private final int port;
9898
private final String name;
99+
private final boolean http2;
99100

100101
/*
101102
* Amount of time to wait for acquiring a channel before timing
@@ -130,13 +131,15 @@ public class HttpClient {
130131
*
131132
* @param host the hostname for the HTTP server
132133
* @param port the port for the HTTP server
134+
* @param useHttp2 if set to true, use http2 connections.
133135
* @param sslCtx if non-null, SSL context to use for connections.
134136
* @param handshakeTimeoutMs if not zero, timeout to use for SSL handshake
135137
* @param name A name to use in logging messages for this client.
136138
* @param logger A logger to use for logging messages.
137139
*/
138140
public static HttpClient createMinimalClient(String host,
139141
int port,
142+
boolean useHttp2,
140143
SslContext sslCtx,
141144
int handshakeTimeoutMs,
142145
String name,
@@ -147,6 +150,7 @@ public static HttpClient createMinimalClient(String host,
147150
0, /* pool min */
148151
0, /* pool inactivity period */
149152
true, /* minimal client */
153+
useHttp2,
150154
DEFAULT_MAX_CONTENT_LENGTH,
151155
DEFAULT_MAX_CHUNK_SIZE,
152156
sslCtx, handshakeTimeoutMs, name, logger);
@@ -184,6 +188,7 @@ public HttpClient(String host,
184188
int numThreads,
185189
int connectionPoolMinSize,
186190
int inactivityPeriodSeconds,
191+
boolean isHttp2,
187192
int maxContentLength,
188193
int maxChunkSize,
189194
SslContext sslCtx,
@@ -192,7 +197,7 @@ public HttpClient(String host,
192197
Logger logger) {
193198

194199
this(host, port, numThreads, connectionPoolMinSize,
195-
inactivityPeriodSeconds, false /* not minimal */,
200+
inactivityPeriodSeconds, false /* not minimal */, isHttp2,
196201
maxContentLength, maxChunkSize, sslCtx, handshakeTimeoutMs, name, logger);
197202
}
198203

@@ -205,6 +210,7 @@ private HttpClient(String host,
205210
int connectionPoolMinSize,
206211
int inactivityPeriodSeconds,
207212
boolean isMinimalClient,
213+
boolean isHttp2,
208214
int maxContentLength,
209215
int maxChunkSize,
210216
SslContext sslCtx,
@@ -217,6 +223,7 @@ private HttpClient(String host,
217223
this.host = host;
218224
this.port = port;
219225
this.name = name;
226+
this.http2 = isHttp2;
220227

221228
this.maxContentLength = (maxContentLength == 0 ?
222229
DEFAULT_MAX_CONTENT_LENGTH : maxContentLength);
@@ -292,6 +299,10 @@ String getName() {
292299
return name;
293300
}
294301

302+
boolean isHttp2() {
303+
return http2;
304+
}
305+
295306
Logger getLogger() {
296307
return logger;
297308
}

driver/src/main/java/oracle/nosql/driver/httpclient/HttpClientChannelPoolHandler.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77

88
package oracle.nosql.driver.httpclient;
99

10+
import static io.netty.handler.logging.LogLevel.DEBUG;
1011
import static oracle.nosql.driver.util.LogUtil.logFine;
1112

1213
import java.net.InetSocketAddress;
14+
1315
import javax.net.ssl.SSLEngine;
1416
import javax.net.ssl.SSLParameters;
1517

@@ -23,6 +25,7 @@
2325
import io.netty.channel.pool.ChannelPoolHandler;
2426
import io.netty.handler.codec.http.HttpClientCodec;
2527
import io.netty.handler.codec.http.HttpObjectAggregator;
28+
import io.netty.handler.codec.http2.*;
2629
import io.netty.handler.proxy.HttpProxyHandler;
2730
import io.netty.handler.ssl.SslHandler;
2831
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
@@ -37,6 +40,8 @@
3740
public class HttpClientChannelPoolHandler implements ChannelPoolHandler,
3841
ChannelHealthChecker {
3942

43+
private static final Http2FrameLogger logger = new Http2FrameLogger(DEBUG, HttpClientChannelPoolHandler.class);
44+
4045
private static final String CODEC_HANDLER_NAME = "http-codec";
4146
private static final String AGG_HANDLER_NAME = "http-aggregator";
4247
private static final String HTTP_HANDLER_NAME = "http-response-handler";
@@ -81,12 +86,30 @@ public void channelCreated(Channel ch) {
8186
p.addLast(sslHandler);
8287
p.addLast(new ChannelLoggingHandler(client));
8388
}
84-
p.addLast(CODEC_HANDLER_NAME, new HttpClientCodec
85-
(4096, // initial line
86-
8192, // header size
87-
client.getMaxChunkSize()));
88-
p.addLast(AGG_HANDLER_NAME, new HttpObjectAggregator(
89-
client.getMaxContentLength()));
89+
if (client.isHttp2()) {
90+
Http2Connection connection = new DefaultHttp2Connection(false);
91+
HttpToHttp2ConnectionHandler connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
92+
.frameListener(new DelegatingDecompressorFrameListener(
93+
connection,
94+
new InboundHttp2ToHttpAdapterBuilder(connection)
95+
.maxContentLength(client.getMaxContentLength())
96+
.propagateSettings(true)
97+
.build()))
98+
.frameLogger(logger)
99+
.connection(connection)
100+
.build();
101+
Http2SettingsHandler settingsHandler = new Http2SettingsHandler(ch.newPromise());
102+
103+
p.addLast(connectionHandler);
104+
p.addLast(settingsHandler);
105+
} else { // http_1_1
106+
p.addLast(CODEC_HANDLER_NAME, new HttpClientCodec
107+
(4096, // initial line
108+
8192, // header size
109+
client.getMaxChunkSize()));
110+
p.addLast(AGG_HANDLER_NAME, new HttpObjectAggregator(
111+
client.getMaxContentLength()));
112+
}
90113
p.addLast(HTTP_HANDLER_NAME,
91114
new HttpClientHandler(client.getLogger()));
92115

driver/src/main/java/oracle/nosql/driver/iam/InstancePrincipalsProvider.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class InstancePrincipalsProvider
5757
protected final SecurityTokenSupplier tokenSupplier;
5858
protected final DefaultSessionKeySupplier sessionKeySupplier;
5959
private final Region region;
60+
private boolean useHttp2 = false;
6061

6162
public InstancePrincipalsProvider(SecurityTokenSupplier tokenSupplier,
6263
SessionKeyPairSupplier keyPairSupplier,
@@ -72,6 +73,7 @@ public InstancePrincipalsProvider(SecurityTokenSupplier tokenSupplier,
7273
*/
7374
public void prepare(NoSQLHandleConfig config) {
7475
tokenSupplier.prepare(config);
76+
useHttp2 = config.useHttp2();
7577
}
7678

7779
public void close() {
@@ -295,6 +297,7 @@ private void autoDetectEndpointUsingMetadataUrl() {
295297
try {
296298
client = HttpClient.createMinimalClient(METADATA_SERVICE_HOST,
297299
80,
300+
false,
298301
null,
299302
0,
300303
"InstanceMDClient",

driver/src/main/java/oracle/nosql/driver/iam/SecurityTokenSupplier.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,16 @@ synchronized void prepare(NoSQLHandleConfig config) {
104104
federationClient = buildHttpClient(
105105
federationURL,
106106
config.getSslContext(),
107-
config.getSSLHandshakeTimeout(), logger);
107+
config.getSSLHandshakeTimeout(),
108+
config.useHttp2(),
109+
logger);
108110
}
109111
}
110112

111113
private static HttpClient buildHttpClient(URI endpoint,
112114
SslContext sslCtx,
113115
int sslHandshakeTimeout,
116+
boolean useHttp2,
114117
Logger logger) {
115118
String scheme = endpoint.getScheme();
116119
if (scheme == null) {
@@ -119,7 +122,7 @@ private static HttpClient buildHttpClient(URI endpoint,
119122
endpoint.toString());
120123
}
121124
if (scheme.equalsIgnoreCase("http")) {
122-
return HttpClient.createMinimalClient(endpoint.getHost(), endpoint.getPort(),
125+
return HttpClient.createMinimalClient(endpoint.getHost(), endpoint.getPort(), useHttp2,
123126
null, 0, "FederationClient", logger);
124127
}
125128

@@ -132,7 +135,7 @@ private static HttpClient buildHttpClient(URI endpoint,
132135
}
133136
}
134137

135-
return HttpClient.createMinimalClient(endpoint.getHost(), 443,
138+
return HttpClient.createMinimalClient(endpoint.getHost(), 443, useHttp2,
136139
sslCtx, sslHandshakeTimeout,
137140
"FederationClient", logger);
138141
}
@@ -338,8 +341,8 @@ void validate(long minTokenLifetime) {
338341

339342
/**
340343
* Checks if two public keys are equal
341-
* @param a one public key
342-
* @param b the other one
344+
* @param actual one public key
345+
* @param expect the other one
343346
* @return true if the same
344347
*/
345348
private boolean isEqualPublicKey(RSAPublicKey actual,

driver/src/main/java/oracle/nosql/driver/kv/StoreAccessTokenProvider.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public class StoreAccessTokenProvider implements AuthorizationProvider {
112112
*/
113113
private boolean autoRenew = true;
114114

115+
/*
116+
* Whether use http2 connection, default use http1.1
117+
*/
118+
private boolean useHttp2 = false;
119+
115120
/*
116121
* Whether this is a secure store token provider.
117122
*/
@@ -375,6 +380,16 @@ public StoreAccessTokenProvider setLogger(Logger logger) {
375380
return this;
376381
}
377382

383+
/**
384+
* Sets useHttp2 state
385+
* @param enable set to true to use Http2 connection
386+
* @return this
387+
*/
388+
public StoreAccessTokenProvider useHttp2(boolean enable) {
389+
this.useHttp2 = enable;
390+
return this;
391+
}
392+
378393
public String getEndpoint() {
379394
return endpoint;
380395
}
@@ -483,6 +498,7 @@ private HttpResponse sendRequest(String authHeader,
483498
client = HttpClient.createMinimalClient
484499
(loginHost,
485500
loginPort,
501+
useHttp2,
486502
(isSecure && !disableSSLHook) ? sslContext : null,
487503
sslHandshakeTimeoutMs,
488504
serviceName,

0 commit comments

Comments
 (0)