Skip to content

Commit b3dee91

Browse files
authored
HTTP/2 in netty-http4 (#45793)
HTTP/2 in netty-http4
1 parent e6d3f16 commit b3dee91

21 files changed

+1125
-994
lines changed

sdk/clientcore/http-netty4/checkstyle-suppressions.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
<!-- This file is generated by the /eng/scripts/linting_suppression_generator.py script. -->
44

55
<suppressions>
6+
<suppress files="io.clientcore.http.netty4.implementation.Netty4StreamingHttp2Adapter.java" checks="com.azure.tools.checkstyle.checks.ExceptionCreatedButNotThrownCheck" />
67
<suppress files="io.clientcore.http.netty4.NettyHttpClientBuilder.java" checks="com.azure.tools.checkstyle.checks.ExternalDependencyExposedCheck" />
78
<suppress files="io.clientcore.http.netty4.implementation.Netty4ChannelBinaryData.java" checks="com.azure.tools.checkstyle.checks.RawExceptionThrowCheck" />
89
<suppress files="io.clientcore.http.netty4.implementation.Netty4ChannelInputStream.java" checks="com.azure.tools.checkstyle.checks.RawExceptionThrowCheck" />
9-
<suppress files="io.clientcore.http.netty4.implementation.WrappedHttpHeaders.java" checks="com.azure.tools.checkstyle.checks.RawExceptionThrowCheck" />
10+
<suppress files="io.clientcore.http.netty4.implementation.WrappedHttp11Headers.java" checks="com.azure.tools.checkstyle.checks.RawExceptionThrowCheck" />
1011
<suppress files="io.clientcore.http.netty4.NettyHttpClientBuilder.java" checks="com.azure.tools.checkstyle.checks.ServiceClientBuilderCheck" />
1112
</suppressions>

sdk/clientcore/http-netty4/spotbugs-exclude.xml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<Class name="io.clientcore.http.netty4.NettyHttpClient" />
99
<Class name="io.clientcore.http.netty4.implementation.Netty4ChannelBinaryData" />
1010
<Class name="io.clientcore.http.netty4.implementation.Netty4HttpProxyHandler" />
11+
<Class name="io.clientcore.http.netty4.implementation.Netty4StreamingHttp2Adapter" />
1112
</Or>
1213
</Match>
1314
<Match>
@@ -20,19 +21,19 @@
2021
</Match>
2122
<Match>
2223
<Bug pattern="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS" />
23-
<Class name="io.clientcore.http.netty4.implementation.WrappedHttpHeadersTests" />
24+
<Class name="io.clientcore.http.netty4.implementation.WrappedHttp11HeadersTests" />
2425
</Match>
2526
<Match>
2627
<Bug pattern="NP_NULL_PARAM_DEREF_NONVIRTUAL" />
27-
<Class name="io.clientcore.http.netty4.implementation.WrappedHttpHeadersTests" />
28+
<Class name="io.clientcore.http.netty4.implementation.WrappedHttp11HeadersTests" />
2829
</Match>
2930
<Match>
3031
<Bug pattern="OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE" />
3132
<Class name="io.clientcore.http.netty4.NettyHttpClientTests" />
3233
</Match>
3334
<Match>
3435
<Bug pattern="OS_OPEN_STREAM" />
35-
<Class name="io.clientcore.http.netty4.implementation.Netty4ChannelInputStreamTests" />
36+
<Class name="io.clientcore.http.netty4.implementation.Netty4Http11ChannelInputStreamTests" />
3637
</Match>
3738
<Match>
3839
<Bug pattern="OS_OPEN_STREAM_EXCEPTION_PATH" />
@@ -42,7 +43,7 @@
4243
<Bug pattern="RR_NOT_CHECKED" />
4344
<Or>
4445
<Class name="io.clientcore.http.netty4.implementation.HttpResponseDrainsBufferTests" />
45-
<Class name="io.clientcore.http.netty4.implementation.Netty4ChannelInputStreamTests" />
46+
<Class name="io.clientcore.http.netty4.implementation.Netty4Http11ChannelInputStreamTests" />
4647
</Or>
4748
</Match>
4849
<Match>

sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClient.java

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import io.netty.channel.ChannelFutureListener;
3434
import io.netty.channel.ChannelInitializer;
3535
import io.netty.channel.EventLoopGroup;
36-
import io.netty.handler.codec.http.HttpClientCodec;
3736
import io.netty.handler.codec.http2.Http2SecurityUtil;
3837
import io.netty.handler.proxy.ProxyHandler;
3938
import io.netty.handler.ssl.ApplicationProtocolConfig;
@@ -55,6 +54,8 @@
5554

5655
import static io.clientcore.core.utils.ServerSentEventUtils.attemptRetry;
5756
import static io.clientcore.core.utils.ServerSentEventUtils.processTextEventStream;
57+
import static io.clientcore.http.netty4.implementation.Netty4HandlerNames.HTTP_RESPONSE;
58+
import static io.clientcore.http.netty4.implementation.Netty4HandlerNames.PROGRESS_AND_TIMEOUT;
5859
import static io.clientcore.http.netty4.implementation.Netty4Utility.awaitLatch;
5960
import static io.clientcore.http.netty4.implementation.Netty4Utility.createCodec;
6061
import static io.clientcore.http.netty4.implementation.Netty4Utility.sendHttp11Request;
@@ -166,11 +167,10 @@ protected void initChannel(Channel channel) throws SSLException {
166167
channel.pipeline().addLast(Netty4HandlerNames.SSL, ssl.newHandler(channel.alloc(), host, port));
167168
channel.pipeline()
168169
.addLast(Netty4HandlerNames.SSL_INITIALIZER, new Netty4SslInitializationHandler());
169-
}
170170

171-
if (isHttps) {
172171
channel.pipeline()
173-
.addLast(new Netty4AlpnHandler(request, addProgressAndTimeoutHandler, errorReference, latch));
172+
.addLast(Netty4HandlerNames.ALPN,
173+
new Netty4AlpnHandler(request, responseReference, errorReference, latch));
174174
}
175175
}
176176
});
@@ -198,14 +198,10 @@ protected void initChannel(Channel channel) throws SSLException {
198198
// effectively be a no-op.
199199
if (addProgressAndTimeoutHandler) {
200200
channel.pipeline()
201-
.addLast(Netty4HandlerNames.PROGRESS_AND_TIMEOUT, new Netty4ProgressAndTimeoutHandler(
202-
progressReporter, writeTimeoutMillis, responseTimeoutMillis, readTimeoutMillis));
201+
.addLast(PROGRESS_AND_TIMEOUT, new Netty4ProgressAndTimeoutHandler(progressReporter,
202+
writeTimeoutMillis, responseTimeoutMillis, readTimeoutMillis));
203203
}
204204

205-
Netty4ResponseHandler responseHandler
206-
= new Netty4ResponseHandler(request, responseReference, errorReference, latch);
207-
channel.pipeline().addLast(Netty4HandlerNames.RESPONSE, responseHandler);
208-
209205
Throwable earlyError = errorReference.get();
210206
if (earlyError != null) {
211207
// If an error occurred between the connect and the request being sent, don't proceed with sending
@@ -237,15 +233,14 @@ protected void initChannel(Channel channel) throws SSLException {
237233
} else {
238234
// If there isn't an SslHandler, we can send the request immediately.
239235
// Add the HTTP/1.1 codec, as we only support HTTP/2 when using SSL ALPN.
240-
HttpClientCodec codec = createCodec();
241-
if (addProgressAndTimeoutHandler) {
242-
channel.pipeline()
243-
.addBefore(Netty4HandlerNames.PROGRESS_AND_TIMEOUT, Netty4HandlerNames.HTTP_1_1_CODEC, codec);
244-
} else {
245-
channel.pipeline().addBefore(Netty4HandlerNames.RESPONSE, Netty4HandlerNames.HTTP_1_1_CODEC, codec);
246-
}
236+
Netty4ResponseHandler responseHandler
237+
= new Netty4ResponseHandler(request, responseReference, errorReference, latch);
238+
channel.pipeline().addLast(HTTP_RESPONSE, responseHandler);
239+
240+
String addBefore = addProgressAndTimeoutHandler ? PROGRESS_AND_TIMEOUT : HTTP_RESPONSE;
241+
channel.pipeline().addBefore(addBefore, Netty4HandlerNames.HTTP_CODEC, createCodec());
247242

248-
sendHttp11Request(request, channel, addProgressAndTimeoutHandler, errorReference)
243+
sendHttp11Request(request, channel, errorReference)
249244
.addListener((ChannelFutureListener) sendListener -> {
250245
if (!sendListener.isSuccess()) {
251246
setOrSuppressError(errorReference, sendListener.cause());
@@ -288,7 +283,7 @@ protected void initChannel(Channel channel) throws SSLException {
288283
// We're ignoring the response content.
289284
CountDownLatch drainLatch = new CountDownLatch(1);
290285
channel.pipeline().addLast(new Netty4EagerConsumeChannelHandler(drainLatch, ignored -> {
291-
}));
286+
}, info.isHttp2()));
292287
channel.config().setAutoRead(true);
293288
awaitLatch(drainLatch);
294289
} else if (bodyHandling == ResponseBodyHandling.STREAM) {
@@ -306,7 +301,7 @@ protected void initChannel(Channel channel) throws SSLException {
306301
}
307302
}
308303

309-
body = new Netty4ChannelBinaryData(info.getEagerContent(), channel, length);
304+
body = new Netty4ChannelBinaryData(info.getEagerContent(), channel, length, info.isHttp2());
310305
} else {
311306
// All cases otherwise assume BUFFER.
312307
CountDownLatch drainLatch = new CountDownLatch(1);
@@ -316,7 +311,7 @@ protected void initChannel(Channel channel) throws SSLException {
316311
} catch (IOException ex) {
317312
throw LOGGER.throwableAtError().log(ex, CoreException::from);
318313
}
319-
}));
314+
}, info.isHttp2()));
320315
channel.config().setAutoRead(true);
321316
awaitLatch(drainLatch);
322317

sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClientBuilder.java

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ private static Class<? extends SocketChannel> getChannelClass(String className)
133133
private Duration readTimeout;
134134
private Duration responseTimeout;
135135
private Duration writeTimeout;
136-
// private HttpProtocolVersion maximumHttpVersion = HttpProtocolVersion.HTTP_2;
136+
private HttpProtocolVersion maximumHttpVersion = HttpProtocolVersion.HTTP_2;
137137

138138
/**
139139
* Creates a new instance of {@link NettyHttpClientBuilder}.
@@ -260,26 +260,26 @@ public NettyHttpClientBuilder proxy(ProxyOptions proxyOptions) {
260260
return this;
261261
}
262262

263-
// /**
264-
// * Sets the maximum {@link HttpProtocolVersion HTTP protocol version} that the HTTP client will support.
265-
// * <p>
266-
// * By default, the maximum HTTP protocol version is set to {@link HttpProtocolVersion#HTTP_2 HTTP_2}.
267-
// * <p>
268-
// * If {@code httpVersion} is null, it will reset the maximum HTTP protocol version to
269-
// * {@link HttpProtocolVersion#HTTP_2 HTTP_2}.
270-
// *
271-
// * @param httpVersion The maximum HTTP protocol version that the HTTP client will support.
272-
// * @return The updated {@link JdkHttpClientBuilder} object.
273-
// */
274-
// public NettyHttpClientBuilder maximumHttpVersion(HttpProtocolVersion httpVersion) {
275-
// if (httpVersion != null) {
276-
// this.maximumHttpVersion = httpVersion;
277-
// } else {
278-
// this.maximumHttpVersion = HttpProtocolVersion.HTTP_2;
279-
// }
280-
//
281-
// return this;
282-
// }
263+
/**
264+
* Sets the maximum {@link HttpProtocolVersion HTTP protocol version} that the HTTP client will support.
265+
* <p>
266+
* By default, the maximum HTTP protocol version is set to {@link HttpProtocolVersion#HTTP_2 HTTP_2}.
267+
* <p>
268+
* If {@code httpVersion} is null, it will reset the maximum HTTP protocol version to
269+
* {@link HttpProtocolVersion#HTTP_2 HTTP_2}.
270+
*
271+
* @param httpVersion The maximum HTTP protocol version that the HTTP client will support.
272+
* @return The updated builder.
273+
*/
274+
public NettyHttpClientBuilder maximumHttpVersion(HttpProtocolVersion httpVersion) {
275+
if (httpVersion != null) {
276+
this.maximumHttpVersion = httpVersion;
277+
} else {
278+
this.maximumHttpVersion = HttpProtocolVersion.HTTP_2;
279+
}
280+
281+
return this;
282+
}
283283

284284
/**
285285
* Builds the NettyHttpClient.
@@ -312,7 +312,7 @@ public HttpClient build() {
312312
ProxyOptions buildProxyOptions
313313
= (proxyOptions == null) ? ProxyOptions.fromConfiguration(buildConfiguration, true) : proxyOptions;
314314

315-
return new NettyHttpClient(bootstrap, sslContextModifier, HttpProtocolVersion.HTTP_1_1,
315+
return new NettyHttpClient(bootstrap, sslContextModifier, maximumHttpVersion,
316316
new ChannelInitializationProxyHandler(buildProxyOptions), getTimeoutMillis(readTimeout),
317317
getTimeoutMillis(responseTimeout), getTimeoutMillis(writeTimeout));
318318
}

0 commit comments

Comments
 (0)