Skip to content

Commit 5a813c8

Browse files
authored
Merge pull request #5613 from eclipse-vertx/encapsulate-http2-connection-handler
HTTP/2 multiplex implementation
2 parents 473c0ed + c336661 commit 5a813c8

106 files changed

Lines changed: 6238 additions & 2643 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

vertx-core/src/main/generated/io/vertx/core/http/HttpClientOptionsConverter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, HttpCli
3434
obj.setHttp2UpgradeMaxContentLength(((Number)member.getValue()).intValue());
3535
}
3636
break;
37+
case "http2MultiplexImplementation":
38+
if (member.getValue() instanceof Boolean) {
39+
obj.setHttp2MultiplexImplementation((Boolean)member.getValue());
40+
}
41+
break;
3742
case "keepAlive":
3843
if (member.getValue() instanceof Boolean) {
3944
obj.setKeepAlive((Boolean)member.getValue());
@@ -162,6 +167,7 @@ static void toJson(HttpClientOptions obj, java.util.Map<String, Object> json) {
162167
json.put("http2ConnectionWindowSize", obj.getHttp2ConnectionWindowSize());
163168
json.put("http2KeepAliveTimeout", obj.getHttp2KeepAliveTimeout());
164169
json.put("http2UpgradeMaxContentLength", obj.getHttp2UpgradeMaxContentLength());
170+
json.put("http2MultiplexImplementation", obj.getHttp2MultiplexImplementation());
165171
json.put("keepAlive", obj.isKeepAlive());
166172
json.put("keepAliveTimeout", obj.getKeepAliveTimeout());
167173
json.put("pipelining", obj.isPipelining());

vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, HttpSer
184184
obj.setStrictThreadMode((Boolean)member.getValue());
185185
}
186186
break;
187+
case "http2MultiplexImplementation":
188+
if (member.getValue() instanceof Boolean) {
189+
obj.setHttp2MultiplexImplementation((Boolean)member.getValue());
190+
}
191+
break;
187192
}
188193
}
189194
}
@@ -239,5 +244,6 @@ static void toJson(HttpServerOptions obj, java.util.Map<String, Object> json) {
239244
json.put("http2RstFloodWindowDurationTimeUnit", obj.getHttp2RstFloodWindowDurationTimeUnit().name());
240245
}
241246
json.put("strictThreadMode", obj.getStrictThreadMode());
247+
json.put("http2MultiplexImplementation", obj.getHttp2MultiplexImplementation());
242248
}
243249
}

vertx-core/src/main/java/io/vertx/core/http/HttpClientOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ public class HttpClientOptions extends ClientOptionsBase {
157157
*/
158158
public static final String DEFAULT_NAME = "__vertx.DEFAULT";
159159

160+
/**
161+
* Use HTTP/2 multiplex implementation = {@code false}
162+
*/
163+
public static final boolean DEFAULT_HTTP_2_MULTIPLEX_IMPLEMENTATION = false;
164+
160165
private boolean verifyHost = true;
161166
private boolean keepAlive;
162167
private int keepAliveTimeout;
@@ -166,6 +171,7 @@ public class HttpClientOptions extends ClientOptionsBase {
166171
private int http2ConnectionWindowSize;
167172
private int http2KeepAliveTimeout;
168173
private int http2UpgradeMaxContentLength;
174+
private boolean http2MultiplexImplementation;
169175

170176
private boolean decompressionSupported;
171177
private String defaultHost;
@@ -221,6 +227,7 @@ public HttpClientOptions(HttpClientOptions other) {
221227
this.http2ConnectionWindowSize = other.http2ConnectionWindowSize;
222228
this.http2KeepAliveTimeout = other.getHttp2KeepAliveTimeout();
223229
this.http2UpgradeMaxContentLength = other.getHttp2UpgradeMaxContentLength();
230+
this.http2MultiplexImplementation = other.getHttp2MultiplexImplementation();
224231
this.decompressionSupported = other.decompressionSupported;
225232
this.defaultHost = other.defaultHost;
226233
this.defaultPort = other.defaultPort;
@@ -272,6 +279,7 @@ private void init() {
272279
http2ConnectionWindowSize = DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE;
273280
http2KeepAliveTimeout = DEFAULT_HTTP2_KEEP_ALIVE_TIMEOUT;
274281
http2UpgradeMaxContentLength = DEFAULT_HTTP2_UPGRADE_MAX_CONTENT_LENGTH;
282+
http2MultiplexImplementation = DEFAULT_HTTP_2_MULTIPLEX_IMPLEMENTATION;
275283
decompressionSupported = DEFAULT_DECOMPRESSION_SUPPORTED;
276284
defaultHost = DEFAULT_DEFAULT_HOST;
277285
defaultPort = DEFAULT_DEFAULT_PORT;
@@ -559,6 +567,24 @@ public HttpClientOptions setHttp2UpgradeMaxContentLength(int http2UpgradeMaxCont
559567
return this;
560568
}
561569

570+
/**
571+
* @return whether to use the HTTP/2 implementation based on multiplexed channel
572+
*/
573+
public boolean getHttp2MultiplexImplementation() {
574+
return http2MultiplexImplementation;
575+
}
576+
577+
/**
578+
* Set which HTTP/2 implementation to use
579+
*
580+
* @param http2MultiplexImplementation whether to use the HTTP/2 multiplex implementation
581+
* @return a reference to this, so the API can be used fluently
582+
*/
583+
public HttpClientOptions setHttp2MultiplexImplementation(boolean http2MultiplexImplementation) {
584+
this.http2MultiplexImplementation = http2MultiplexImplementation;
585+
return this;
586+
}
587+
562588
/**
563589
* Is keep alive enabled on the client?
564590
*

vertx-core/src/main/java/io/vertx/core/http/HttpHeaders.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import io.vertx.codegen.annotations.VertxGen;
2121
import io.vertx.core.MultiMap;
2222
import io.vertx.core.http.impl.headers.HeadersMultiMap;
23-
import io.vertx.core.http.impl.headers.Http2HeadersAdaptor;
23+
import io.vertx.core.http.impl.http2.Http2HeadersMultiMap;
2424

2525
/**
2626
* Contains a bunch of useful HTTP headers stuff:
@@ -507,7 +507,7 @@ static MultiMap headers(HttpVersion version) {
507507
case HTTP_1_1:
508508
return HeadersMultiMap.httpHeaders();
509509
case HTTP_2:
510-
return new Http2HeadersAdaptor(new DefaultHttp2Headers());
510+
return new Http2HeadersMultiMap(new DefaultHttp2Headers());
511511
default:
512512
throw new AssertionError();
513513
}

vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ public class HttpServerOptions extends NetServerOptions {
206206
*/
207207
public static final boolean DEFAULT_STRICT_THREAD_MODE_STRICT = false;
208208

209+
/**
210+
* Use HTTP/2 multiplex implementation = {@code false}
211+
*/
212+
public static final boolean DEFAULT_HTTP_2_MULTIPLEX_IMPLEMENTATION = false;
213+
209214
private boolean compressionSupported;
210215
private int compressionLevel;
211216
private int compressionContentSizeThreshold;
@@ -239,6 +244,7 @@ public class HttpServerOptions extends NetServerOptions {
239244
private int http2RstFloodWindowDuration;
240245
private TimeUnit http2RstFloodWindowDurationTimeUnit;
241246
private boolean strictThreadMode;
247+
private boolean http2MultiplexImplementation;
242248

243249
/**
244250
* Default constructor
@@ -289,6 +295,7 @@ public HttpServerOptions(HttpServerOptions other) {
289295
this.http2RstFloodWindowDuration = other.http2RstFloodWindowDuration;
290296
this.http2RstFloodWindowDurationTimeUnit = other.http2RstFloodWindowDurationTimeUnit;
291297
this.strictThreadMode = other.strictThreadMode;
298+
this.http2MultiplexImplementation = other.http2MultiplexImplementation;
292299
}
293300

294301
/**
@@ -346,6 +353,7 @@ private void init() {
346353
http2RstFloodMaxRstFramePerWindow = DEFAULT_HTTP2_RST_FLOOD_MAX_RST_FRAME_PER_WINDOW;
347354
http2RstFloodWindowDuration = DEFAULT_HTTP2_RST_FLOOD_WINDOW_DURATION;
348355
http2RstFloodWindowDurationTimeUnit = DEFAULT_HTTP2_RST_FLOOD_WINDOW_DURATION_TIME_UNIT;
356+
http2MultiplexImplementation = DEFAULT_HTTP_2_MULTIPLEX_IMPLEMENTATION;
349357
}
350358

351359
/**
@@ -1285,4 +1293,22 @@ public HttpServerOptions setStrictThreadMode(boolean strictThreadMode) {
12851293
this.strictThreadMode = strictThreadMode;
12861294
return this;
12871295
}
1296+
1297+
/**
1298+
* @return whether to use the HTTP/2 implementation based on multiplexed channel
1299+
*/
1300+
public boolean getHttp2MultiplexImplementation() {
1301+
return http2MultiplexImplementation;
1302+
}
1303+
1304+
/**
1305+
* Set which HTTP/2 implementation to use
1306+
*
1307+
* @param http2MultiplexImplementation whether to use the HTTP/2 multiplex implementation
1308+
* @return a reference to this, so the API can be used fluently
1309+
*/
1310+
public HttpServerOptions setHttp2MultiplexImplementation(boolean http2MultiplexImplementation) {
1311+
this.http2MultiplexImplementation = http2MultiplexImplementation;
1312+
return this;
1313+
}
12881314
}

vertx-core/src/main/java/io/vertx/core/http/impl/CleanableHttpClient.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212

1313
import io.vertx.core.Completable;
1414
import io.vertx.core.Future;
15-
import io.vertx.core.http.*;
15+
import io.vertx.core.http.HttpClient;
16+
import io.vertx.core.http.HttpClientConnection;
17+
import io.vertx.core.http.HttpClientOptions;
18+
import io.vertx.core.http.HttpClientRequest;
19+
import io.vertx.core.http.HttpClientResponse;
20+
import io.vertx.core.http.HttpConnectOptions;
21+
import io.vertx.core.http.RequestOptions;
1622
import io.vertx.core.internal.VertxInternal;
1723
import io.vertx.core.internal.http.HttpClientInternal;
1824
import io.vertx.core.net.ClientSSLOptions;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.core.http.impl;
12+
13+
import io.netty.handler.codec.Headers;
14+
import io.netty.handler.codec.compression.CompressionOptions;
15+
import io.netty.handler.codec.http.HttpContentCompressor;
16+
import io.netty.handler.codec.http.HttpHeaderNames;
17+
18+
import static io.vertx.core.http.HttpHeaders.CONTENT_ENCODING;
19+
import static io.vertx.core.http.HttpHeaders.IDENTITY;
20+
21+
/**
22+
*
23+
*/
24+
public class CompressionManager {
25+
26+
private final EncodingDetector encodingDetector;
27+
private final CompressionOptions[] options;
28+
29+
public CompressionManager(int contentSizeThreshold, CompressionOptions[] options) {
30+
this.options = options;
31+
this.encodingDetector = new EncodingDetector(contentSizeThreshold, options);
32+
}
33+
34+
public CompressionOptions[] options() {
35+
return options;
36+
}
37+
38+
public String determineEncoding(String acceptEncoding) {
39+
return encodingDetector.determineEncoding(acceptEncoding);
40+
}
41+
42+
/**
43+
* Set the {@code responseHeaders} content-encoding header.
44+
*
45+
* @param requestHeaders
46+
* @param responseHeaders
47+
*/
48+
public void setContentEncoding(Headers<CharSequence, CharSequence, ?> requestHeaders, Headers<CharSequence, CharSequence, ?> responseHeaders) {
49+
String contentEncodingToApply = determineContentEncodingToApply(requestHeaders, responseHeaders);
50+
if (contentEncodingToApply == null || contentEncodingToApply.equalsIgnoreCase(IDENTITY.toString())) {
51+
if (responseHeaders.contains(CONTENT_ENCODING, IDENTITY)) {
52+
responseHeaders.remove(CONTENT_ENCODING);
53+
}
54+
} else {
55+
responseHeaders.set(CONTENT_ENCODING, contentEncodingToApply);
56+
}
57+
}
58+
59+
private String determineContentEncodingToApply(Headers<CharSequence, CharSequence, ?> requestHeaders, Headers<CharSequence, CharSequence, ?> responseHeaders) {
60+
if (responseHeaders.contains(CONTENT_ENCODING)) {
61+
return null;
62+
}
63+
return determineContentEncoding(requestHeaders);
64+
}
65+
66+
private String determineContentEncoding(Headers<CharSequence, CharSequence, ?> headers) {
67+
String acceptEncoding = headers.get(HttpHeaderNames.ACCEPT_ENCODING) != null ? headers.get(HttpHeaderNames.ACCEPT_ENCODING).toString() : null;
68+
if (acceptEncoding != null) {
69+
return determineEncoding(acceptEncoding);
70+
}
71+
return null;
72+
}
73+
74+
private static class EncodingDetector extends HttpContentCompressor {
75+
76+
private EncodingDetector(int contentSizeThreshold, CompressionOptions[] compressionOptions) {
77+
super(contentSizeThreshold, compressionOptions);
78+
}
79+
80+
@Override
81+
protected String determineEncoding(String acceptEncoding) {
82+
return super.determineEncoding(acceptEncoding);
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)