1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.spdy;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelHandler;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.ChannelPipeline;
23 import io.netty.handler.codec.ByteToMessageDecoder;
24 import io.netty.handler.codec.http.HttpServerCodec;
25 import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
26 import io.netty.handler.ssl.SslHandler;
27 import io.netty.util.internal.logging.InternalLogger;
28 import io.netty.util.internal.logging.InternalLoggerFactory;
29
30 import java.util.List;
31
32
33
34
35 public abstract class SpdyOrHttpChooser extends ByteToMessageDecoder {
36
37 private static final InternalLogger logger = InternalLoggerFactory.getInstance(SpdyOrHttpChooser.class);
38
39 public enum SelectedProtocol {
40 SPDY_3_1("spdy/3.1"),
41 HTTP_1_1("http/1.1"),
42 HTTP_1_0("http/1.0");
43
44 private final String name;
45
46 SelectedProtocol(String defaultName) {
47 name = defaultName;
48 }
49
50 public String protocolName() {
51 return name;
52 }
53
54
55
56
57
58
59
60 public static SelectedProtocol protocol(String name) {
61 for (SelectedProtocol protocol : SelectedProtocol.values()) {
62 if (protocol.protocolName().equals(name)) {
63 return protocol;
64 }
65 }
66 return null;
67 }
68 }
69
70 protected SpdyOrHttpChooser() { }
71
72 @Override
73 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
74 if (configurePipeline(ctx)) {
75
76
77
78
79 ctx.pipeline().remove(this);
80 }
81 }
82
83 private boolean configurePipeline(ChannelHandlerContext ctx) {
84
85
86 SslHandler handler = ctx.pipeline().get(SslHandler.class);
87 if (handler == null) {
88
89 throw new IllegalStateException("cannot find a SslHandler in the pipeline (required for SPDY)");
90 }
91
92 if (!handler.handshakeFuture().isDone()) {
93 return false;
94 }
95
96 SelectedProtocol protocol;
97 try {
98 protocol = selectProtocol(handler);
99 } catch (Exception e) {
100 throw new IllegalStateException("failed to get the selected protocol", e);
101 }
102
103 if (protocol == null) {
104 throw new IllegalStateException("unknown protocol");
105 }
106
107 switch (protocol) {
108 case SPDY_3_1:
109 try {
110 configureSpdy(ctx, SpdyVersion.SPDY_3_1);
111 } catch (Exception e) {
112 throw new IllegalStateException("failed to configure a SPDY pipeline", e);
113 }
114 break;
115 case HTTP_1_0:
116 case HTTP_1_1:
117 try {
118 configureHttp1(ctx);
119 } catch (Exception e) {
120 throw new IllegalStateException("failed to configure a HTTP/1 pipeline", e);
121 }
122 break;
123 }
124 return true;
125 }
126
127
128
129
130
131
132
133
134 protected SelectedProtocol selectProtocol(SslHandler sslHandler) throws Exception {
135 final String appProto = sslHandler.applicationProtocol();
136 return appProto != null? SelectedProtocol.protocol(appProto) : SelectedProtocol.HTTP_1_1;
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 protected abstract void configureSpdy(ChannelHandlerContext ctx, SpdyVersion version) throws Exception;
155
156
157
158
159
160
161
162
163
164
165
166
167 protected abstract void configureHttp1(ChannelHandlerContext ctx) throws Exception;
168
169 @Override
170 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
171 logger.warn("{} Failed to select the application-level protocol:", ctx.channel(), cause);
172 ctx.close();
173 }
174 }