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 org.jboss.netty.buffer.ChannelBuffer;
22 import org.jboss.netty.buffer.ChannelBuffers;
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.handler.codec.http.DefaultHttpResponse;
28 import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
29 import org.jboss.netty.handler.codec.http.HttpHeaders.Names;
30 import org.jboss.netty.handler.codec.http.HttpRequest;
31 import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
32 import org.jboss.netty.handler.codec.http.HttpResponse;
33 import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
34 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
35 import org.jboss.netty.logging.InternalLogger;
36 import org.jboss.netty.logging.InternalLoggerFactory;
37 import org.jboss.netty.util.CharsetUtil;
38
39
40
41
42
43
44
45
46 public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
47
48 private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker08.class);
49
50 public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
51
52 private final boolean allowExtensions;
53
54
55
56
57
58
59
60
61
62
63
64
65 public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) {
66 this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE);
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions,
84 long maxFramePayloadLength) {
85 super(WebSocketVersion.V08, webSocketURL, subprotocols, maxFramePayloadLength);
86 this.allowExtensions = allowExtensions;
87 }
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 @Override
129 public ChannelFuture handshake(Channel channel, HttpRequest req) {
130
131 if (logger.isDebugEnabled()) {
132 logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.getId()));
133 }
134
135 HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
136
137 String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
138 if (key == null) {
139 throw new WebSocketHandshakeException("not a WebSocket request: missing key");
140 }
141 String acceptSeed = key + WEBSOCKET_08_ACCEPT_GUID;
142 ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII));
143
144 String accept = WebSocketUtil.base64(sha1);
145
146 if (logger.isDebugEnabled()) {
147 logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept));
148 }
149
150 res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
151 res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
152 res.addHeader(Names.CONNECTION, Names.UPGRADE);
153 res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
154 String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
155 if (subprotocols != null) {
156 String selectedSubprotocol = selectSubprotocol(subprotocols);
157 if (selectedSubprotocol == null) {
158 throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
159 } else {
160 res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
161 setSelectedSubprotocol(selectedSubprotocol);
162 }
163 }
164
165 ChannelFuture future = channel.write(res);
166
167
168 future.addListener(new ChannelFutureListener() {
169 public void operationComplete(ChannelFuture future) {
170 ChannelPipeline p = future.getChannel().getPipeline();
171 if (p.get(HttpChunkAggregator.class) != null) {
172 p.remove(HttpChunkAggregator.class);
173 }
174
175 p.replace(HttpRequestDecoder.class, "wsdecoder",
176 new WebSocket08FrameDecoder(true, allowExtensions, getMaxFramePayloadLength()));
177 p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket08FrameEncoder(false));
178 }
179 });
180
181 return future;
182 }
183
184
185
186
187
188
189
190
191
192 @Override
193 public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
194 ChannelFuture f = channel.write(frame);
195 f.addListener(ChannelFutureListener.CLOSE);
196 return f;
197 }
198
199 }