/*
 * Copyright 2015 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.handler.ssl;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

Configures a ChannelPipeline depending on the application-level protocol negotiation result of SslHandler. For example, you could configure your HTTP pipeline depending on the result of ALPN:
public class MyInitializer extends ChannelInitializer<Channel> { private final SslContext sslCtx; public MyInitializer(SslContext sslCtx) { this.sslCtx = sslCtx; } protected void initChannel(Channel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(sslCtx.newHandler(...)); // Adds SslHandler p.addLast(new MyNegotiationHandler()); } } public class MyNegotiationHandler extends ApplicationProtocolNegotiationHandler { public MyNegotiationHandler() { super(ApplicationProtocolNames.HTTP_1_1); } protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { if (ApplicationProtocolNames.HTTP_2.equals(protocol) { configureHttp2(ctx); } else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { configureHttp1(ctx); } else { throw new IllegalStateException("unknown protocol: " + protocol); } } } 
/** * Configures a {@link ChannelPipeline} depending on the application-level protocol negotiation result of * {@link SslHandler}. For example, you could configure your HTTP pipeline depending on the result of ALPN: * <pre> * public class MyInitializer extends {@link ChannelInitializer}&lt;{@link Channel}&gt; { * private final {@link SslContext} sslCtx; * * public MyInitializer({@link SslContext} sslCtx) { * this.sslCtx = sslCtx; * } * * protected void initChannel({@link Channel} ch) { * {@link ChannelPipeline} p = ch.pipeline(); * p.addLast(sslCtx.newHandler(...)); // Adds {@link SslHandler} * p.addLast(new MyNegotiationHandler()); * } * } * * public class MyNegotiationHandler extends {@link ApplicationProtocolNegotiationHandler} { * public MyNegotiationHandler() { * super({@link ApplicationProtocolNames}.HTTP_1_1); * } * * protected void configurePipeline({@link ChannelHandlerContext} ctx, String protocol) { * if ({@link ApplicationProtocolNames}.HTTP_2.equals(protocol) { * configureHttp2(ctx); * } else if ({@link ApplicationProtocolNames}.HTTP_1_1.equals(protocol)) { * configureHttp1(ctx); * } else { * throw new IllegalStateException("unknown protocol: " + protocol); * } * } * } * </pre> */
public abstract class ApplicationProtocolNegotiationHandler extends ChannelInboundHandlerAdapter { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ApplicationProtocolNegotiationHandler.class); private final String fallbackProtocol;
Creates a new instance with the specified fallback protocol name.
Params:
  • fallbackProtocol – the name of the protocol to use when ALPN/NPN negotiation fails or the client does not support ALPN/NPN
/** * Creates a new instance with the specified fallback protocol name. * * @param fallbackProtocol the name of the protocol to use when * ALPN/NPN negotiation fails or the client does not support ALPN/NPN */
protected ApplicationProtocolNegotiationHandler(String fallbackProtocol) { this.fallbackProtocol = ObjectUtil.checkNotNull(fallbackProtocol, "fallbackProtocol"); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof SslHandshakeCompletionEvent) { ctx.pipeline().remove(this); SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt; if (handshakeEvent.isSuccess()) { SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); if (sslHandler == null) { throw new IllegalStateException("cannot find a SslHandler in the pipeline (required for " + "application-level protocol negotiation)"); } String protocol = sslHandler.applicationProtocol(); configurePipeline(ctx, protocol != null? protocol : fallbackProtocol); } else { handshakeFailure(ctx, handshakeEvent.cause()); } } ctx.fireUserEventTriggered(evt); }
Invoked on successful initial SSL/TLS handshake. Implement this method to configure your pipeline for the negotiated application-level protocol.
Params:
  • protocol – the name of the negotiated application-level protocol, or the fallback protocol name specified in the constructor call if negotiation failed or the client isn't aware of ALPN/NPN extension
/** * Invoked on successful initial SSL/TLS handshake. Implement this method to configure your pipeline * for the negotiated application-level protocol. * * @param protocol the name of the negotiated application-level protocol, or * the fallback protocol name specified in the constructor call if negotiation failed or the client * isn't aware of ALPN/NPN extension */
protected abstract void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception;
Invoked on failed initial SSL/TLS handshake.
/** * Invoked on failed initial SSL/TLS handshake. */
protected void handshakeFailure(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.warn("{} TLS handshake failed:", ctx.channel(), cause); ctx.close(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.warn("{} Failed to select the application-level protocol:", ctx.channel(), cause); ctx.close(); } }