Skip to content

Commit

Permalink
Rework the SSLHelper class as being renamed to SslContextManager and …
Browse files Browse the repository at this point in the history
…decoupled from the Netty channel side. It is also moved to the internal package so it can be reused in other components.
  • Loading branch information
vietj committed Jun 19, 2024
1 parent 7562717 commit bee776d
Show file tree
Hide file tree
Showing 21 changed files with 357 additions and 365 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import io.vertx.core.net.NetSocket;
import io.vertx.core.net.impl.MessageWrite;
import io.vertx.core.net.impl.NetSocketImpl;
import io.vertx.core.net.impl.SSLHelper;
import io.vertx.core.internal.tls.SslContextManager;
import io.vertx.core.net.impl.VertxHandler;
import io.vertx.core.spi.metrics.HttpServerMetrics;
import io.vertx.core.spi.tracing.VertxTracer;
Expand Down Expand Up @@ -87,10 +87,10 @@ public class Http1xServerConnection extends Http1xConnection implements HttpServ
final HttpServerMetrics metrics;
final boolean handle100ContinueAutomatically;
final HttpServerOptions options;
final SSLHelper sslHelper;
final SslContextManager sslContextManager;

public Http1xServerConnection(Supplier<ContextInternal> streamContextSupplier,
SSLHelper sslHelper,
SslContextManager sslContextManager,
HttpServerOptions options,
ChannelHandlerContext chctx,
ContextInternal context,
Expand All @@ -100,7 +100,7 @@ public Http1xServerConnection(Supplier<ContextInternal> streamContextSupplier,
this.serverOrigin = serverOrigin;
this.streamContextSupplier = streamContextSupplier;
this.options = options;
this.sslHelper = sslHelper;
this.sslContextManager = sslContextManager;
this.metrics = metrics;
this.handle100ContinueAutomatically = options.isHandle100ContinueAutomatically();
this.tracingPolicy = options.getTracingPolicy();
Expand Down Expand Up @@ -380,7 +380,7 @@ void netSocket(Promise<NetSocket> promise) {
}

pipeline.replace("handler", "handler", VertxHandler.create(ctx -> {
NetSocketImpl socket = new NetSocketImpl(context, ctx, sslHelper, options.getSslOptions(), metrics, false) {
NetSocketImpl socket = new NetSocketImpl(context, ctx, sslContextManager, options.getSslOptions(), metrics, false) {
@Override
protected void handleClosed() {
if (metrics != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,17 @@

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http2.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.vertx.core.net.impl.SSLHelper;
import io.vertx.core.net.impl.SslChannelProvider;
import io.vertx.core.internal.tls.SslContextManager;
import io.vertx.core.internal.net.SslChannelProvider;
import io.vertx.core.net.impl.VertxHandler;

import java.util.Map;

import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
Expand All @@ -36,15 +32,15 @@ public class Http1xUpgradeToH2CHandler extends ChannelInboundHandlerAdapter {

private final HttpServerConnectionInitializer initializer;
private final SslChannelProvider sslChannelProvider;
private final SSLHelper sslHelper;
private final SslContextManager sslContextManager;
private VertxHttp2ConnectionHandler<Http2ServerConnection> handler;
private final boolean isCompressionSupported;
private final boolean isDecompressionSupported;

Http1xUpgradeToH2CHandler(HttpServerConnectionInitializer initializer, SslChannelProvider sslChannelProvider, SSLHelper sslHelper, boolean isCompressionSupported, boolean isDecompressionSupported) {
Http1xUpgradeToH2CHandler(HttpServerConnectionInitializer initializer, SslChannelProvider sslChannelProvider, SslContextManager sslContextManager, boolean isCompressionSupported, boolean isDecompressionSupported) {
this.initializer = initializer;
this.sslChannelProvider = sslChannelProvider;
this.sslHelper = sslHelper;
this.sslContextManager = sslContextManager;
this.isCompressionSupported = isCompressionSupported;
this.isDecompressionSupported = isDecompressionSupported;
}
Expand Down Expand Up @@ -120,7 +116,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
ctx.writeAndFlush(res);
}
} else {
initializer.configureHttp1Handler(ctx.pipeline(), sslChannelProvider, sslHelper);
initializer.configureHttp1Handler(ctx.pipeline(), sslChannelProvider, sslContextManager);
ctx.fireChannelRead(msg);
ctx.pipeline().remove(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.internal.ContextInternal;
import io.vertx.core.internal.VertxInternal;
import io.vertx.core.internal.tls.SslContextManager;
import io.vertx.core.internal.net.SslChannelProvider;
import io.vertx.core.net.impl.*;
import io.vertx.core.spi.metrics.HttpServerMetrics;

Expand Down Expand Up @@ -88,7 +90,7 @@ class HttpServerConnectionInitializer {
this.encodingDetector = compressionOptions != null ? new EncodingDetector(compressionOptions)::determineEncoding : null;
}

void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider, SSLHelper sslHelper) {
void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider, SslContextManager sslContextManager) {
ChannelPipeline pipeline = ch.pipeline();
if (options.isSsl()) {
SslHandler sslHandler = pipeline.get(SslHandler.class);
Expand All @@ -101,32 +103,32 @@ void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider, SSLHel
break;
case "http/1.1":
case "http/1.0":
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslContextManager);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslContextManager);
break;
}
} else {
// No alpn presented or OpenSSL
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslContextManager);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslContextManager);
}
} else {
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslContextManager);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslContextManager);
}
} else {
if (disableH2C) {
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Pipeline(ch.pipeline(), sslChannelProvider, sslContextManager);
configureHttp1Handler(ch.pipeline(), sslChannelProvider, sslContextManager);
} else {
Http1xOrH2CHandler handler = new Http1xOrH2CHandler() {
@Override
protected void configure(ChannelHandlerContext ctx, boolean h2c) {
if (h2c) {
configureHttp2(ctx.pipeline());
} else {
configureHttp1Pipeline(ctx.pipeline(), sslChannelProvider, sslHelper);
configureHttp1OrH2CUpgradeHandler(ctx.pipeline(), sslChannelProvider, sslHelper);
configureHttp1Pipeline(ctx.pipeline(), sslChannelProvider, sslContextManager);
configureHttp1OrH2CUpgradeHandler(ctx.pipeline(), sslChannelProvider, sslContextManager);
}
}
@Override
Expand Down Expand Up @@ -205,9 +207,9 @@ private VertxHttp2ConnectionHandler<Http2ServerConnection> buildHttp2ConnectionH
return handler;
}

private void configureHttp1OrH2CUpgradeHandler(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SSLHelper sslHelper) {
private void configureHttp1OrH2CUpgradeHandler(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SslContextManager sslContextManager) {
// DO WE NEED TO ADD SOMEWHERE BEFORE IDLE ?
pipeline.addAfter("httpEncoder", "h2c", new Http1xUpgradeToH2CHandler(this, sslChannelProvider, sslHelper, options.isCompressionSupported(), options.isDecompressionSupported()));
pipeline.addAfter("httpEncoder", "h2c", new Http1xUpgradeToH2CHandler(this, sslChannelProvider, sslContextManager, options.isCompressionSupported(), options.isDecompressionSupported()));
}

/**
Expand All @@ -226,7 +228,7 @@ private static String computeChannelName(ChannelPipeline pipeline) {
}
}

private void configureHttp1Pipeline(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SSLHelper sslHelper) {
private void configureHttp1Pipeline(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SslContextManager sslContextManager) {
String name = computeChannelName(pipeline);
pipeline.addBefore(name, "httpDecoder", new VertxHttpRequestDecoder(options));
pipeline.addBefore(name, "httpEncoder", new VertxHttpResponseEncoder());
Expand All @@ -238,7 +240,7 @@ private void configureHttp1Pipeline(ChannelPipeline pipeline, SslChannelProvider
}
}

void configureHttp1Handler(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SSLHelper sslHelper) {
void configureHttp1Handler(ChannelPipeline pipeline, SslChannelProvider sslChannelProvider, SslContextManager sslContextManager) {
if (!server.requestAccept()) {
sendServiceUnavailable(pipeline.channel());
return;
Expand All @@ -247,7 +249,7 @@ void configureHttp1Handler(ChannelPipeline pipeline, SslChannelProvider sslChann
VertxHandler<Http1xServerConnection> handler = VertxHandler.create(chctx -> {
Http1xServerConnection conn = new Http1xServerConnection(
streamContextSupplier,
sslHelper,
sslContextManager,
options,
chctx,
context,
Expand Down
83 changes: 83 additions & 0 deletions src/main/java/io/vertx/core/internal/net/SslChannelProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2011-2022 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.internal.net;

import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.handler.ssl.SniHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.ImmediateExecutor;
import io.vertx.core.internal.VertxInternal;
import io.vertx.core.internal.tls.SslContextProvider;
import io.vertx.core.net.SocketAddress;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
* Provider for Netty {@link SslHandler} and {@link SniHandler}.
* <br/>
* {@link SslContext} instances are cached and reused.
*/
public class SslChannelProvider {

private final Executor workerPool;
private final boolean sni;
private final SslContextProvider sslContextProvider;

public SslChannelProvider(VertxInternal vertx,
SslContextProvider sslContextProvider,
boolean sni) {
this.workerPool = vertx.getInternalWorkerPool().executor();
this.sni = sni;
this.sslContextProvider = sslContextProvider;
}

public SslContextProvider sslContextProvider() {
return sslContextProvider;
}

public SslHandler createClientSslHandler(SocketAddress peerAddress, String serverName, boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
SslContext sslContext = sslContextProvider.sslClientContext(serverName, useAlpn);
SslHandler sslHandler;
Executor delegatedTaskExec = sslContextProvider.useWorkerPool() ? workerPool : ImmediateExecutor.INSTANCE;
if (peerAddress != null && peerAddress.isInetSocket()) {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, peerAddress.host(), peerAddress.port(), delegatedTaskExec);
} else {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
}
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return sslHandler;
}

public ChannelHandler createServerHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
if (sni) {
return createSniHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit);
} else {
return createServerSslHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit);
}
}

private SslHandler createServerSslHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
SslContext sslContext = sslContextProvider.sslServerContext(useAlpn);
Executor delegatedTaskExec = sslContextProvider.useWorkerPool() ? workerPool : ImmediateExecutor.INSTANCE;
SslHandler sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return sslHandler;
}

private SniHandler createSniHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
Executor delegatedTaskExec = sslContextProvider.useWorkerPool() ? workerPool : ImmediateExecutor.INSTANCE;
return new VertxSniHandler(sslContextProvider.serverNameMapping(delegatedTaskExec, useAlpn), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.net.impl;
package io.vertx.core.internal.net;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.ssl.SniCompletionEvent;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.Promise;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;

/**
* An handler that waits for SSL handshake completion and dispatch it to the server handler.
* A handler that waits for SSL handshake completion and dispatch it to the server handler.
*
* @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
*/
public class SslHandshakeCompletionHandler extends ChannelInboundHandlerAdapter {

static AttributeKey<String> SERVER_NAME_ATTR = AttributeKey.valueOf("sniServerName");
/**
* The channel attribute providing the SNI server name, this name is set upon handshake completion when available.
*/
public static AttributeKey<String> SERVER_NAME_ATTR = AttributeKey.valueOf("sniServerName");

private final Promise<Void> promise;

public SslHandshakeCompletionHandler(Promise<Void> promise) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.net.impl;
package io.vertx.core.internal.net;

import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.ssl.SniHandler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.net.impl;
package io.vertx.core.internal.net;

import io.netty.handler.ssl.DelegatingSslContext;
import io.netty.handler.ssl.SslContext;
Expand Down
Loading

0 comments on commit bee776d

Please sign in to comment.