/* * Copyright (c) 2011-2014 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.core.net.impl; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.ssl.SniHandler; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslHandler; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import io.vertx.core.impl.VertxInternal; import javax.net.ssl.SSLEngine; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ public class VertxSniHandler extends SniHandler { public static AttributeKey<String> SERVER_NAME_ATTR = AttributeKey.valueOf("sniServerName"); private final SSLHelper helper; private ChannelHandlerContext context; private final Promise<Channel> handshakeFuture; public VertxSniHandler(SSLHelper helper, VertxInternal vertx) { super(input -> { return helper.getContext(vertx, input); }); this.helper = helper; this.handshakeFuture = new DefaultPromise<Channel>() { @Override protected EventExecutor executor() { ChannelHandlerContext ctx = context; if (ctx == null) { throw new IllegalStateException(); } return ctx.executor(); } }; } public Future<Channel> handshakeFuture() { return handshakeFuture; } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { context = ctx; } @Override protected void replaceHandler(ChannelHandlerContext ctx, String hostname, SslContext sslContext) throws Exception { SslHandler sslHandler = null; try { SSLEngine engine = helper.createEngine(sslContext); sslHandler = new SslHandler(engine); ctx.pipeline().replace(this, "ssl", sslHandler); Future<Channel> fut = sslHandler.handshakeFuture(); fut.addListener(future -> { if (future.isSuccess()) { Attribute<String> val = ctx.channel().attr(SERVER_NAME_ATTR); val.set(hostname); handshakeFuture.setSuccess(ctx.channel()); } else { handshakeFuture.setFailure(future.cause()); } }); sslHandler = null; } finally { // Since the SslHandler was not inserted into the pipeline the ownership of the SSLEngine was not // transferred to the SslHandler. // See https://github.com/netty/netty/issues/5678 if (sslHandler != null) { ReferenceCountUtil.safeRelease(sslHandler.engine()); } } } }