Skip to content

Commit 9a7b473

Browse files
authored
Allow H1, H2, and H2C protocol for HttpClient (#2659)
Enable H1, H2, and H2C protocols for HttpClient by dropping H2C protocol when handling HTTPS urls, and by dropping H2 protocol when handling HTTP urls when another protocol is present Signed-off-by: TaiYau Chan <[email protected]>
1 parent 168475e commit 9a7b473

File tree

2 files changed

+65
-16
lines changed

2 files changed

+65
-16
lines changed

reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClientConnect.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,20 @@ public void subscribe(CoreSubscriber<? super Connection> actual) {
214214
if (handler.toURI.isSecure()) {
215215
if (_config.sslProvider == null) {
216216
_config = new HttpClientConfig(config);
217-
if (_config.checkProtocol(HttpClientConfig.h2c) && _config.protocols.length > 1) {
218-
removeIncompatibleProtocol(_config, HttpProtocol.H2C);
219-
}
220217
_config.sslProvider = HttpClientSecure.defaultSslProvider(_config);
221218
}
222219

223220
if (_config.checkProtocol(HttpClientConfig.h2c)) {
224-
sink.error(new IllegalArgumentException(
225-
"Configured H2 Clear-Text protocol with TLS. " +
226-
"Use the non Clear-Text H2 protocol via HttpClient#protocol or disable TLS " +
227-
"via HttpClient#noSSL()"));
228-
return;
221+
if (_config.protocols.length > 1) {
222+
removeIncompatibleProtocol(_config, HttpProtocol.H2C);
223+
}
224+
else {
225+
sink.error(new IllegalArgumentException(
226+
"Configured H2 Clear-Text protocol with TLS. " +
227+
"Use the non Clear-Text H2 protocol via HttpClient#protocol or disable TLS " +
228+
"via HttpClient#noSSL()"));
229+
return;
230+
}
229231
}
230232

231233
if (_config.sslProvider.getDefaultConfigurationType() == null) {
@@ -242,17 +244,19 @@ public void subscribe(CoreSubscriber<? super Connection> actual) {
242244
else {
243245
if (_config.sslProvider != null) {
244246
_config = new HttpClientConfig(config);
245-
if (_config.checkProtocol(HttpClientConfig.h2) && _config.protocols.length > 1) {
246-
removeIncompatibleProtocol(_config, HttpProtocol.H2);
247-
}
248247
_config.sslProvider = null;
249248
}
250249

251250
if (_config.checkProtocol(HttpClientConfig.h2)) {
252-
sink.error(new IllegalArgumentException(
253-
"Configured H2 protocol without TLS. Use H2 Clear-Text " +
254-
"protocol via HttpClient#protocol or configure TLS via HttpClient#secure"));
255-
return;
251+
if (_config.protocols.length > 1) {
252+
removeIncompatibleProtocol(_config, HttpProtocol.H2);
253+
}
254+
else {
255+
sink.error(new IllegalArgumentException(
256+
"Configured H2 protocol without TLS. Use H2 Clear-Text " +
257+
"protocol via HttpClient#protocol or configure TLS via HttpClient#secure"));
258+
return;
259+
}
256260
}
257261
}
258262

reactor-netty-http/src/test/java/reactor/netty/http/Http2Tests.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020-2022 VMware, Inc. or its affiliates, All Rights Reserved.
2+
* Copyright (c) 2020-2023 VMware, Inc. or its affiliates, All Rights Reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -580,4 +580,49 @@ private void testTooManyPermitsReturned(HttpClient client) {
580580
void testIssue1789() throws Exception {
581581
doTestMaxActiveStreams(HttpClient.create(), 1, 1, 1, 2, 0);
582582
}
583+
584+
@Test
585+
void testPR2659_SchemeHttpConfiguredNoSsl() {
586+
doTestPR2659_SchemeHttp("1");
587+
}
588+
589+
private void doTestPR2659_SchemeHttp(String expectedStreamId) {
590+
disposableServer =
591+
createServer()
592+
.host("localhost")
593+
.protocol(HttpProtocol.HTTP11, HttpProtocol.H2C)
594+
.handle((req, res) -> res.sendString(Mono.just("testPR2659")))
595+
.bindNow(Duration.ofSeconds(30));
596+
597+
HttpClient.create()
598+
.protocol(HttpProtocol.HTTP11, HttpProtocol.H2, HttpProtocol.H2C)
599+
.wiretap(true)
600+
.get()
601+
.uri("http://localhost:" + disposableServer.port() + "/")
602+
.responseSingle((res, bytes) -> Mono.just(res.responseHeaders().get("x-http2-stream-id", "null")))
603+
.as(StepVerifier::create)
604+
.expectNext(expectedStreamId)
605+
.expectComplete()
606+
.verify(Duration.ofSeconds(30));
607+
}
608+
609+
@Test
610+
void testPR2659_SchemeHttpsConfiguredWithSsl() {
611+
doTestPR2659_SchemeHttps(s -> !"null".equals(s));
612+
}
613+
614+
private void doTestPR2659_SchemeHttps(Predicate<String> predicate) {
615+
HttpClient.create()
616+
.protocol(HttpProtocol.HTTP11, HttpProtocol.H2, HttpProtocol.H2C)
617+
.secure(sslContextSpec -> sslContextSpec.sslContext(Http2SslContextSpec.forClient()))
618+
.wiretap(true)
619+
.get()
620+
.uri("https://example.com")
621+
.responseSingle((res, bytes) -> Mono.just(res.responseHeaders().get("x-http2-stream-id", "null")))
622+
.as(StepVerifier::create)
623+
.expectNextMatches(predicate)
624+
.expectComplete()
625+
.verify(Duration.ofSeconds(30));
626+
}
627+
583628
}

0 commit comments

Comments
 (0)