Skip to content

Commit 3144cc1

Browse files
authored
Merge pull request #6042 from eclipse-vertx/http-tls-test-improvements
HTTP/QUIC improvements
2 parents 5b2d601 + 817f707 commit 3144cc1

File tree

15 files changed

+246
-132
lines changed

15 files changed

+246
-132
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public interface HttpServer extends Measured {
9292

9393
/**
9494
* Set an exception handler called for socket errors happening before the HTTP connection
95-
* is established, e.g during the TLS handshake.
95+
* is established, e.g. during the TLS handshake.
9696
*
9797
* @param handler the handler to set
9898
* @return a reference to this, so the API can be used fluently

vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class QuicHttpServer implements HttpServerInternal {
4545
private final boolean manageMetrics;
4646
private volatile Handler<HttpServerRequest> requestHandler;
4747
private Handler<HttpConnection> connectionHandler;
48+
private Handler<Throwable> exceptionHandler;
4849
private QuicServerImpl quicServer;
4950
private HttpServerMetrics<?, ?> httpMetrics;
5051
private volatile int actualPort;
@@ -108,6 +109,7 @@ public HttpServer exceptionHandler(Handler<Throwable> handler) {
108109
if (actualPort > 0) {
109110
throw new IllegalStateException("Server already bound");
110111
}
112+
this.exceptionHandler = handler;
111113
return this;
112114
}
113115

@@ -241,6 +243,7 @@ public Future<HttpServer> listen(ContextInternal current, SocketAddress address)
241243
quicServer.connectHandler(new ConnectionHandler(quicServer, httpMetrics, requestHandler, connectionHandler,
242244
config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), config.getMaxFormFields(), config.getMaxFormBufferedBytes(),
243245
http3Config.getInitialSettings() != null ? http3Config.getInitialSettings().copy() : new Http3Settings(), logEnabled));
246+
quicServer.exceptionHandler(exceptionHandler);
244247
return quicServer
245248
.bind(current, address)
246249
.map(addr -> {

vertx-core/src/main/java/io/vertx/core/internal/tls/ServerSslContextProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public SslContext createServerContext(KeyManagerFactory keyManagerFactory,
106106
}
107107
try {
108108
SslContextFactory factory = provider.get()
109-
.forServer(SslContextManager.CLIENT_AUTH_MAPPING.get(clientAuth))
109+
.forServer(SslContextManager.mapClientAuth(clientAuth))
110110
.enabledProtocols(enabledProtocols)
111111
.enabledCipherSuites(enabledCipherSuites)
112112
.useAlpn(applicationProtocols != null)

vertx-core/src/main/java/io/vertx/core/internal/tls/SslContextManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@
3636
*/
3737
public abstract class SslContextManager<P extends SslContextProvider> {
3838

39+
public static io.netty.handler.ssl.ClientAuth mapClientAuth(ClientAuth auth) {
40+
return CLIENT_AUTH_MAPPING.get(auth);
41+
}
42+
3943
private static final Config NULL_CONFIG = new Config(null, null, null, null, null);
40-
static final EnumMap<ClientAuth, io.netty.handler.ssl.ClientAuth> CLIENT_AUTH_MAPPING = new EnumMap<>(ClientAuth.class);
44+
private static final EnumMap<ClientAuth, io.netty.handler.ssl.ClientAuth> CLIENT_AUTH_MAPPING = new EnumMap<>(ClientAuth.class);
4145

4246
static {
4347
CLIENT_AUTH_MAPPING.put(ClientAuth.REQUIRED, io.netty.handler.ssl.ClientAuth.REQUIRE);

vertx-core/src/main/java/io/vertx/core/net/QuicServer.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
*/
1111
package io.vertx.core.net;
1212

13+
import io.vertx.codegen.annotations.Fluent;
1314
import io.vertx.codegen.annotations.VertxGen;
1415
import io.vertx.core.Future;
1516
import io.vertx.core.Handler;
17+
import io.vertx.core.http.HttpServer;
1618
import io.vertx.core.net.impl.SocketAddressImpl;
1719

1820
/**
@@ -28,6 +30,7 @@ public interface QuicServer extends QuicEndpoint {
2830
* @param handler the connection handler
2931
* @return this object instance
3032
*/
33+
@Fluent
3134
QuicServer connectHandler(Handler<QuicConnection> handler);
3235

3336
/**
@@ -37,6 +40,7 @@ public interface QuicServer extends QuicEndpoint {
3740
* @param handler the handler processing streams
3841
* @return this object instance
3942
*/
43+
@Fluent
4044
default QuicServer streamHandler(Handler<QuicStream> handler) {
4145
if (handler != null) {
4246
return connectHandler(connection -> {
@@ -47,6 +51,16 @@ default QuicServer streamHandler(Handler<QuicStream> handler) {
4751
}
4852
}
4953

54+
/**
55+
* Set an exception handler called for socket errors happening before the QUIC connection
56+
* is established, e.g. during the TLS handshake.
57+
*
58+
* @param handler the handler to set
59+
* @return a reference to this, so the API can be used fluently
60+
*/
61+
@Fluent
62+
QuicServer exceptionHandler(Handler<Throwable> handler);
63+
5064
/**
5165
* Start listening on the {@code port} and {@code host} as configured in the {@link io.vertx.core.net.QuicServerConfig} used when
5266
* creating the server.

vertx-core/src/main/java/io/vertx/core/net/impl/quic/QuicClientImpl.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.netty.handler.logging.ByteBufFormat;
2424
import io.netty.util.Attribute;
2525
import io.netty.util.AttributeKey;
26+
import io.vertx.core.Completable;
2627
import io.vertx.core.Future;
2728
import io.vertx.core.internal.ContextInternal;
2829
import io.vertx.core.internal.PromiseInternal;
@@ -32,8 +33,6 @@
3233
import io.vertx.core.internal.resolver.NameResolver;
3334
import io.vertx.core.internal.tls.ClientSslContextManager;
3435
import io.vertx.core.internal.tls.ClientSslContextProvider;
35-
import io.vertx.core.internal.tls.SslContextManager;
36-
import io.vertx.core.internal.tls.SslContextProvider;
3736
import io.vertx.core.net.*;
3837
import io.vertx.core.net.impl.ConnectRetry;
3938
import io.vertx.core.spi.metrics.Metrics;
@@ -93,8 +92,7 @@ protected Future<QuicCodecBuilder<?>> codecBuilder(ContextInternal context, Tran
9392
Attribute<HostAndPort> peerAttr = q.attr(SSL_PEER_KEY);
9493
HostAndPort peer = peerAttr.get();
9594
return sslContext.newEngine(q.alloc(), peer.host(), peer.port());
96-
})
97-
.maxIdleTimeout(5000, TimeUnit.MILLISECONDS));
95+
}));
9896
}
9997

10098
@Override
@@ -207,9 +205,14 @@ protected void initChannel(Channel ch) {
207205
connectionGroup.add(ch);
208206
LogConfig logConfig = config.getLogConfig();
209207
ByteBufFormat activityLogging = logConfig != null && logConfig.isEnabled()? logConfig.getDataFormat() : null;
208+
Completable<QuicConnection> adapter = (result, failure) -> {
209+
if (failure == null) {
210+
promise.tryComplete(result);
211+
}
212+
};
210213
QuicConnectionHandler handler = new QuicConnectionHandler(context, metrics, config.getIdleTimeout(),
211214
config.getReadIdleTimeout(), config.getWriteIdleTimeout(), activityLogging, config.getMaxStreamBidiRequests(),
212-
config.getMaxStreamUniRequests(), remoteAddress, false, promise::tryComplete);
215+
config.getMaxStreamUniRequests(), remoteAddress, false, adapter);
213216
ch.pipeline().addLast("handler", handler);
214217
}
215218
})

vertx-core/src/main/java/io/vertx/core/net/impl/quic/QuicConnectionHandler.java

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
import io.netty.handler.codec.quic.QuicStreamLimitChangedEvent;
2121
import io.netty.handler.logging.ByteBufFormat;
2222
import io.netty.handler.ssl.SniCompletionEvent;
23-
import io.vertx.core.Handler;
23+
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
24+
import io.vertx.core.Completable;
2425
import io.vertx.core.buffer.Buffer;
2526
import io.vertx.core.internal.ContextInternal;
2627
import io.vertx.core.internal.net.SslHandshakeCompletionHandler;
@@ -51,15 +52,15 @@ private static long timeoutMillis(Duration timeout) {
5152
private final int maxStreamBidiRequests;
5253
private final int maxStreamUniRequests;
5354
private final boolean server;
54-
private Handler<QuicConnection> handler;
55-
private QuicChannel channel;
55+
private final SocketAddress remoteAddress;
56+
private Completable<QuicConnection> handler;
5657
private QuicConnectionImpl connection;
57-
private SocketAddress remoteAddress;
58+
private int maxDatagramLength;
5859

5960
public QuicConnectionHandler(ContextInternal context, TransportMetrics<?> metrics, Duration idleTimeout,
6061
Duration readIdleTimeout, Duration writeIdleTimeout, ByteBufFormat activityLogging,
6162
int maxStreamBidiRequests, int maxStreamUniRequests, SocketAddress remoteAddress,
62-
boolean server, Handler<QuicConnection> handler) {
63+
boolean server, Completable<QuicConnection> handler) {
6364
this.context = context;
6465
this.metrics = metrics;
6566
this.idleTimeout = timeoutMillis(idleTimeout);
@@ -73,29 +74,24 @@ public QuicConnectionHandler(ContextInternal context, TransportMetrics<?> metric
7374
this.server = server;
7475
}
7576

76-
@Override
77-
public void handlerAdded(ChannelHandlerContext ctx) {
78-
QuicChannel ch = (QuicChannel) ctx.channel();
79-
channel = ch;
80-
connection = new QuicConnectionImpl(context, metrics, idleTimeout, readIdleTimeout, writeIdleTimeout, activityLogging,
81-
maxStreamBidiRequests, maxStreamUniRequests, ch, remoteAddress, ctx, server);
82-
}
83-
8477
@Override
8578
public void channelActive(ChannelHandlerContext ctx) throws Exception {
86-
super.channelActive(ctx);
87-
activate();
79+
activate(ctx);
8880
}
8981

90-
private void activate() {
82+
private void activate(ChannelHandlerContext ctx) {
83+
QuicChannel ch = (QuicChannel) ctx.channel();
84+
QuicConnectionImpl c = new QuicConnectionImpl(context, metrics, idleTimeout, readIdleTimeout, writeIdleTimeout, activityLogging,
85+
maxStreamBidiRequests, maxStreamUniRequests, maxDatagramLength, ch, remoteAddress, ctx, server);
86+
connection = c;
9187
if (metrics != null) {
92-
Object metric = metrics.connected(connection.remoteAddress(), connection.remoteName());
93-
connection.metric(metric);
88+
Object metric = metrics.connected(c.remoteAddress(), c.remoteName());
89+
c.metric(metric);
9490
}
95-
Handler<QuicConnection> h = handler;
91+
Completable<QuicConnection> h = handler;
9692
if (h != null) {
9793
handler = null;
98-
context.dispatch(connection, h);
94+
h.succeed(c);
9995
}
10096
}
10197

@@ -131,22 +127,29 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
131127
c.shutdown(shutdown.timeout());
132128
}
133129
} else if (evt instanceof QuicStreamLimitChangedEvent) {
134-
connection.handleQuicStreamLimitChanged();
130+
QuicConnectionImpl c = connection;
131+
if (c != null) {
132+
c.handleQuicStreamLimitChanged();
133+
}
135134
} else if (evt instanceof QuicDatagramExtensionEvent) {
136135
QuicDatagramExtensionEvent datagramExtensionEvent = (QuicDatagramExtensionEvent) evt;
137-
QuicConnectionImpl c = connection;
138-
c.enableDatagramExtension(datagramExtensionEvent.maxLength());
139-
140-
// Activate at this moment, since the handler activation happens before we get relevant information
141-
// datagram extension event is last, see QuicheQuicChannel
142-
activate();
136+
this.maxDatagramLength = datagramExtensionEvent.maxLength();
137+
} else if (evt instanceof SslHandshakeCompletionEvent) {
138+
SslHandshakeCompletionEvent handshakeEvt = (SslHandshakeCompletionEvent)evt;
139+
if (!handshakeEvt.isSuccess()) {
140+
Completable<QuicConnection> h = handler;
141+
if (h != null) {
142+
h.fail(handshakeEvt.cause());
143+
}
144+
}
143145
}
144146
super.userEventTriggered(ctx, evt);
145147
}
146148

147149
@Override
148150
public void exceptionCaught(ChannelHandlerContext chctx, final Throwable t) {
149-
if (connection.handleException(t)) {
151+
QuicConnectionImpl c = connection;
152+
if (c != null && c.handleException(t)) {
150153
chctx.close();
151154
}
152155
}

vertx-core/src/main/java/io/vertx/core/net/impl/quic/QuicConnectionImpl.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ public class QuicConnectionImpl extends ConnectionBase implements QuicConnection
7878

7979
public QuicConnectionImpl(ContextInternal context, TransportMetrics metrics, long idleTimeout,
8080
long readIdleTimeout, long writeIdleTimeout, ByteBufFormat activityLogging, int maxStreamBidiRequests,
81-
int maxStreamUniRequests, QuicChannel channel, SocketAddress remoteAddress, ChannelHandlerContext chctx,
82-
boolean server) {
81+
int maxStreamUniRequests, int maxDatagramLength, QuicChannel channel, SocketAddress remoteAddress,
82+
ChannelHandlerContext chctx, boolean server) {
8383
super(context, chctx);
8484

8585
Map<QuicStreamType, StreamOpenRequestQueue> pendingStreamRequestsMap = new EnumMap<>(QuicStreamType.class);
@@ -96,7 +96,7 @@ public QuicConnectionImpl(ContextInternal context, TransportMetrics metrics, lon
9696
this.remoteAddress = remoteAddress;
9797
this.server = server;
9898
this.pendingStreamOpenRequestsMap = pendingStreamRequestsMap;
99-
this.maxDatagramLength = 0;
99+
this.maxDatagramLength = maxDatagramLength;
100100
this.streamGroup = new ConnectionGroup(context.nettyEventLoop()) {
101101
@Override
102102
protected void handleShutdown(Duration timeout, Completable<Void> completion) {
@@ -200,10 +200,6 @@ void handleDatagram(ByteBuf byteBuf) {
200200
}
201201
}
202202

203-
void enableDatagramExtension(int maxDatagramLength) {
204-
this.maxDatagramLength = Math.max(0, maxDatagramLength);
205-
}
206-
207203
void handleQuicStreamLimitChanged() {
208204
trySatisfyPendingStreamOpenRequests(QuicStreamType.BIDIRECTIONAL);
209205
trySatisfyPendingStreamOpenRequests(QuicStreamType.UNIDIRECTIONAL);

vertx-core/src/main/java/io/vertx/core/net/impl/quic/QuicEndpointImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public abstract class QuicEndpointImpl implements QuicEndpointInternal, MetricsP
5858
private final QuicEndpointConfig config;
5959
private final String protocol;
6060
protected final SslContextManager<?> manager;
61+
protected final BoringSSLKeylog keylog;
6162
protected final VertxInternal vertx;
6263
private TransportMetrics<?> metrics;
6364
private Channel channel;
@@ -100,6 +101,7 @@ public QuicEndpointImpl(VertxInternal vertx, QuicEndpointConfig config, String p
100101
this.protocol = protocol;
101102
this.vertx = Objects.requireNonNull(vertx);
102103
this.manager = sslContextManager(new BoringSslEngineOptions(keylog));
104+
this.keylog = keylog;
103105
}
104106

105107
abstract SslContextManager<?> sslContextManager(BoringSslEngineOptions engine);

0 commit comments

Comments
 (0)