1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http.websocketx;
17
18 import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*;
19 import static org.jboss.netty.handler.codec.http.HttpVersion.*;
20
21 import java.io.UnsupportedEncodingException;
22
23 import org.jboss.netty.channel.Channel;
24 import org.jboss.netty.channel.ChannelFuture;
25 import org.jboss.netty.channel.ChannelFutureListener;
26 import org.jboss.netty.channel.ChannelPipeline;
27 import org.jboss.netty.channel.Channels;
28 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
29 import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
30 import org.jboss.netty.handler.codec.http.HttpHeaders.Names;
31 import org.jboss.netty.handler.codec.http.HttpRequest;
32 import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
33 import org.jboss.netty.handler.codec.http.HttpResponse;
34 import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
35 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
36 import org.jboss.netty.logging.InternalLogger;
37 import org.jboss.netty.logging.InternalLoggerFactory;
38 import org.jboss.netty.util.CharsetUtil;
39
40
41
42
43
44
45
46
47 public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
48
49 private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker08.class);
50
51 public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
52
53 private final boolean allowExtensions;
54
55
56
57
58
59
60
61
62
63
64
65
66 public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) {
67 this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE);
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions,
85 long maxFramePayloadLength) {
86 super(WebSocketVersion.V08, webSocketURL, subprotocols, maxFramePayloadLength);
87 this.allowExtensions = allowExtensions;
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 @Override
130 public ChannelFuture handshake(Channel channel, HttpRequest req) {
131
132 if (logger.isDebugEnabled()) {
133 logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.getId()));
134 }
135
136 HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
137
138 String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
139 if (key == null) {
140 throw new WebSocketHandshakeException("not a WebSocket request: missing key");
141 }
142 String acceptSeed = key + WEBSOCKET_08_ACCEPT_GUID;
143 byte[] sha1;
144 try {
145 sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII.name()));
146 } catch (UnsupportedEncodingException e) {
147 return Channels.failedFuture(channel, e);
148 }
149 String accept = WebSocketUtil.base64(sha1);
150
151 if (logger.isDebugEnabled()) {
152 logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept));
153 }
154
155 res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
156 res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
157 res.addHeader(Names.CONNECTION, Names.UPGRADE);
158 res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
159 String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
160 if (subprotocols != null) {
161 String selectedSubprotocol = selectSubprotocol(subprotocols);
162 if (selectedSubprotocol == null) {
163 throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
164 } else {
165 res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
166 setSelectedSubprotocol(selectedSubprotocol);
167 }
168 }
169
170 ChannelFuture future = channel.write(res);
171
172
173 ChannelPipeline p = channel.getPipeline();
174 if (p.get(HttpChunkAggregator.class) != null) {
175 p.remove(HttpChunkAggregator.class);
176 }
177
178 p.replace(HttpRequestDecoder.class, "wsdecoder",
179 new WebSocket08FrameDecoder(true, allowExtensions, getMaxFramePayloadLength()));
180 p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket08FrameEncoder(false));
181
182 return future;
183 }
184
185
186
187
188
189
190
191
192
193 @Override
194 public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
195 ChannelFuture f = channel.write(frame);
196 f.addListener(ChannelFutureListener.CLOSE);
197 return f;
198 }
199
200 }