1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.websocketx;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.Channel;
21 import io.netty.channel.ChannelFuture;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.channel.ChannelPromise;
24 import io.netty.handler.codec.http.DefaultFullHttpResponse;
25 import io.netty.handler.codec.http.FullHttpRequest;
26 import io.netty.handler.codec.http.FullHttpResponse;
27 import io.netty.handler.codec.http.HttpHeaderNames;
28 import io.netty.handler.codec.http.HttpHeaderValues;
29 import io.netty.handler.codec.http.HttpHeaders;
30 import io.netty.handler.codec.http.HttpMethod;
31 import io.netty.handler.codec.http.HttpResponseStatus;
32
33 import java.util.regex.Pattern;
34
35 import static io.netty.handler.codec.http.HttpMethod.GET;
36 import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
37
38
39
40
41
42
43
44
45
46
47
48 public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
49
50 private static final Pattern BEGINNING_DIGIT = Pattern.compile("[^0-9]");
51 private static final Pattern BEGINNING_SPACE = Pattern.compile("[^ ]");
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public WebSocketServerHandshaker00(String webSocketURL, String subprotocols, int maxFramePayloadLength) {
66 this(webSocketURL, subprotocols, WebSocketDecoderConfig.newBuilder()
67 .maxFramePayloadLength(maxFramePayloadLength)
68 .build());
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82 public WebSocketServerHandshaker00(String webSocketURL, String subprotocols, WebSocketDecoderConfig decoderConfig) {
83 super(WebSocketVersion.V00, webSocketURL, subprotocols, decoderConfig);
84 }
85
86 WebSocketServerHandshaker00(boolean isSecure, String host, String path,
87 String subprotocols, WebSocketDecoderConfig decoderConfig) {
88 super(WebSocketVersion.V00, isSecure, host, path, subprotocols, decoderConfig);
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
130
131 @Override
132 protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
133 HttpMethod method = req.method();
134 if (!GET.equals(method)) {
135 throw new WebSocketServerHandshakeException("Invalid WebSocket handshake method: " + method, req);
136 }
137
138
139 if (!req.headers().containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true)
140 || !HttpHeaderValues.WEBSOCKET.contentEqualsIgnoreCase(req.headers().get(HttpHeaderNames.UPGRADE))) {
141 throw new WebSocketServerHandshakeException("not a WebSocket handshake request: missing upgrade", req);
142 }
143
144
145 boolean isHixie76 = req.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_KEY1) &&
146 req.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_KEY2);
147
148 String origin = req.headers().get(HttpHeaderNames.ORIGIN);
149
150 if (origin == null && !isHixie76) {
151 throw new WebSocketServerHandshakeException("Missing origin header, got only " + req.headers().names(),
152 req);
153 }
154
155
156 FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
157 isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake"),
158 req.content().alloc().buffer(0));
159 if (headers != null) {
160 res.headers().add(headers);
161 }
162
163 res.headers().set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET)
164 .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE);
165
166
167 if (isHixie76) {
168
169 res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, origin);
170 res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_LOCATION, uri());
171
172 String subprotocols = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
173 if (subprotocols != null) {
174 String selectedSubprotocol = selectSubprotocol(subprotocols);
175 if (selectedSubprotocol == null) {
176 if (logger.isDebugEnabled()) {
177 logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
178 }
179 } else {
180 res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
181 }
182 }
183
184
185 String key1 = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_KEY1);
186 String key2 = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_KEY2);
187 int a = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key1).replaceAll("")) /
188 BEGINNING_SPACE.matcher(key1).replaceAll("").length());
189 int b = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key2).replaceAll("")) /
190 BEGINNING_SPACE.matcher(key2).replaceAll("").length());
191 long c = req.content().readLong();
192 ByteBuf input = Unpooled.wrappedBuffer(new byte[16]).setIndex(0, 0);
193 input.writeInt(a);
194 input.writeInt(b);
195 input.writeLong(c);
196 res.content().writeBytes(WebSocketUtil.md5(input.array()));
197 } else {
198
199 res.headers().add(HttpHeaderNames.WEBSOCKET_ORIGIN, origin);
200 res.headers().add(HttpHeaderNames.WEBSOCKET_LOCATION, uri());
201
202 String protocol = req.headers().get(HttpHeaderNames.WEBSOCKET_PROTOCOL);
203 if (protocol != null) {
204 res.headers().set(HttpHeaderNames.WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
205 }
206 }
207 return res;
208 }
209
210
211
212
213
214
215
216
217
218
219
220 @Override
221 public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
222 return channel.writeAndFlush(frame, promise);
223 }
224
225
226
227
228
229
230
231
232
233
234
235 @Override
236 public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame,
237 ChannelPromise promise) {
238 return ctx.writeAndFlush(frame, promise);
239 }
240
241 @Override
242 protected WebSocketFrameDecoder newWebsocketDecoder() {
243 return new WebSocket00FrameDecoder(decoderConfig());
244 }
245
246 @Override
247 protected WebSocketFrameEncoder newWebSocketEncoder() {
248 return new WebSocket00FrameEncoder();
249 }
250 }