1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.channel.ChannelInboundHandlerAdapter;
21 import io.netty.channel.ChannelInitializer;
22 import io.netty.channel.ChannelPipeline;
23 import io.netty.channel.socket.ChannelInputShutdownEvent;
24 import io.netty.handler.codec.DecoderException;
25 import io.netty.util.internal.ObjectUtil;
26 import io.netty.util.internal.RecyclableArrayList;
27 import io.netty.util.internal.logging.InternalLogger;
28 import io.netty.util.internal.logging.InternalLoggerFactory;
29
30 import javax.net.ssl.SSLException;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public abstract class ApplicationProtocolNegotiationHandler extends ChannelInboundHandlerAdapter {
68
69 private static final InternalLogger logger =
70 InternalLoggerFactory.getInstance(ApplicationProtocolNegotiationHandler.class);
71
72 private final String fallbackProtocol;
73 private final RecyclableArrayList bufferedMessages = RecyclableArrayList.newInstance();
74 private ChannelHandlerContext ctx;
75 private boolean sslHandlerChecked;
76
77
78
79
80
81
82
83 protected ApplicationProtocolNegotiationHandler(String fallbackProtocol) {
84 this.fallbackProtocol = ObjectUtil.checkNotNull(fallbackProtocol, "fallbackProtocol");
85 }
86
87 @Override
88 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
89 this.ctx = ctx;
90 super.handlerAdded(ctx);
91 }
92
93 @Override
94 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
95 fireBufferedMessages();
96 bufferedMessages.recycle();
97 super.handlerRemoved(ctx);
98 }
99
100 @Override
101 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
102
103 bufferedMessages.add(msg);
104 if (!sslHandlerChecked) {
105 sslHandlerChecked = true;
106 if (ctx.pipeline().get(SslHandler.class) == null) {
107
108
109 removeSelfIfPresent(ctx);
110 }
111 }
112 }
113
114
115
116
117 private void fireBufferedMessages() {
118 if (!bufferedMessages.isEmpty()) {
119 for (int i = 0; i < bufferedMessages.size(); i++) {
120 ctx.fireChannelRead(bufferedMessages.get(i));
121 }
122 ctx.fireChannelReadComplete();
123 bufferedMessages.clear();
124 }
125 }
126
127 @Override
128 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
129 if (evt instanceof SslHandshakeCompletionEvent) {
130 SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
131 try {
132 if (handshakeEvent.isSuccess()) {
133 SslHandler sslHandler = ctx.pipeline().get(SslHandler.class);
134 if (sslHandler == null) {
135 throw new IllegalStateException("cannot find an SslHandler in the pipeline (required for "
136 + "application-level protocol negotiation)");
137 }
138 String protocol = sslHandler.applicationProtocol();
139 configurePipeline(ctx, protocol != null ? protocol : fallbackProtocol);
140 } else {
141
142
143
144
145
146 }
147 } catch (Throwable cause) {
148 exceptionCaught(ctx, cause);
149 } finally {
150
151 if (handshakeEvent.isSuccess()) {
152 removeSelfIfPresent(ctx);
153 }
154 }
155 }
156
157 if (evt instanceof ChannelInputShutdownEvent) {
158 fireBufferedMessages();
159 }
160
161 ctx.fireUserEventTriggered(evt);
162 }
163
164 @Override
165 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
166 fireBufferedMessages();
167 super.channelInactive(ctx);
168 }
169
170 private void removeSelfIfPresent(ChannelHandlerContext ctx) {
171 ChannelPipeline pipeline = ctx.pipeline();
172 if (!ctx.isRemoved()) {
173 pipeline.remove(this);
174 }
175 }
176
177
178
179
180
181
182
183
184
185 protected abstract void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception;
186
187
188
189
190 protected void handshakeFailure(ChannelHandlerContext ctx, Throwable cause) throws Exception {
191 logger.warn("{} TLS handshake failed:", ctx.channel(), cause);
192 ctx.close();
193 }
194
195 @Override
196 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
197 Throwable wrapped;
198 if (cause instanceof DecoderException && ((wrapped = cause.getCause()) instanceof SSLException)) {
199 try {
200 handshakeFailure(ctx, wrapped);
201 return;
202 } finally {
203 removeSelfIfPresent(ctx);
204 }
205 }
206 logger.warn("{} Failed to select the application-level protocol:", ctx.channel(), cause);
207 ctx.fireExceptionCaught(cause);
208 ctx.close();
209 }
210 }