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.Names.*;
19 import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*;
20 import static org.jboss.netty.handler.codec.http.HttpVersion.*;
21
22 import org.jboss.netty.buffer.ChannelBuffer;
23 import org.jboss.netty.buffer.ChannelBuffers;
24 import org.jboss.netty.channel.Channel;
25 import org.jboss.netty.channel.ChannelFuture;
26 import org.jboss.netty.channel.ChannelFutureListener;
27 import org.jboss.netty.channel.ChannelPipeline;
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.HttpHeaders.Values;
32 import org.jboss.netty.handler.codec.http.HttpRequest;
33 import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
34 import org.jboss.netty.handler.codec.http.HttpResponse;
35 import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
36 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
37 import org.jboss.netty.logging.InternalLogger;
38 import org.jboss.netty.logging.InternalLoggerFactory;
39
40
41
42
43
44
45
46
47
48
49
50 public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
51
52 private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker00.class);
53
54
55
56
57
58
59
60
61
62
63 public WebSocketServerHandshaker00(String webSocketURL, String subprotocols) {
64 this(webSocketURL, subprotocols, Long.MAX_VALUE);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public WebSocketServerHandshaker00(String webSocketURL, String subprotocols, long maxFramePayloadLength) {
80 super(WebSocketVersion.V00, webSocketURL, subprotocols, maxFramePayloadLength);
81 }
82
83
84
85
86
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 00 server handshake", channel.getId()));
133 }
134
135
136 if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
137 || !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {
138 throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
139 }
140
141
142 boolean isHixie76 = req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2);
143
144
145 HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
146 isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake"));
147 res.addHeader(Names.UPGRADE, WEBSOCKET);
148 res.addHeader(CONNECTION, Values.UPGRADE);
149
150
151 if (isHixie76) {
152
153 res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
154 res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
155 String subprotocols = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
156 if (subprotocols != null) {
157 String selectedSubprotocol = selectSubprotocol(subprotocols);
158 if (selectedSubprotocol == null) {
159 throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
160 } else {
161 res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
162 setSelectedSubprotocol(selectedSubprotocol);
163 }
164 }
165
166
167 String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
168 String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
169 int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length());
170 int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length());
171 long c = req.getContent().readLong();
172 ChannelBuffer input = ChannelBuffers.buffer(16);
173 input.writeInt(a);
174 input.writeInt(b);
175 input.writeLong(c);
176 res.setContent(WebSocketUtil.md5(input));
177 } else {
178
179 res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
180 res.addHeader(WEBSOCKET_LOCATION, getWebSocketUrl());
181 String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
182 if (protocol != null) {
183 res.addHeader(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
184 }
185 }
186
187
188 ChannelFuture future = channel.write(res);
189
190
191 future.addListener(new ChannelFutureListener() {
192 public void operationComplete(ChannelFuture future) {
193 ChannelPipeline p = future.getChannel().getPipeline();
194 if (p.get(HttpChunkAggregator.class) != null) {
195 p.remove(HttpChunkAggregator.class);
196 }
197 p.replace(HttpRequestDecoder.class, "wsdecoder",
198 new WebSocket00FrameDecoder(getMaxFramePayloadLength()));
199
200 p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket00FrameEncoder());
201 }
202 });
203
204 return future;
205 }
206
207
208
209
210
211
212
213
214
215 @Override
216 public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
217 return channel.write(frame);
218 }
219 }