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
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 @Override
127 protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
128 HttpMethod method = req.method();
129 if (!GET.equals(method)) {
130 throw new WebSocketServerHandshakeException("Invalid WebSocket handshake method: " + method, req);
131 }
132
133
134 if (!req.headers().containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true)
135 || !HttpHeaderValues.WEBSOCKET.contentEqualsIgnoreCase(req.headers().get(HttpHeaderNames.UPGRADE))) {
136 throw new WebSocketServerHandshakeException("not a WebSocket handshake request: missing upgrade", req);
137 }
138
139
140 boolean isHixie76 = req.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_KEY1) &&
141 req.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_KEY2);
142
143 String origin = req.headers().get(HttpHeaderNames.ORIGIN);
144
145 if (origin == null && !isHixie76) {
146 throw new WebSocketServerHandshakeException("Missing origin header, got only " + req.headers().names(),
147 req);
148 }
149
150
151 FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
152 isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake"),
153 req.content().alloc().buffer(0));
154 if (headers != null) {
155 res.headers().add(headers);
156 }
157
158 res.headers().set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET)
159 .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE);
160
161
162 if (isHixie76) {
163
164 res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, origin);
165 res.headers().add(HttpHeaderNames.SEC_WEBSOCKET_LOCATION, uri());
166
167 String subprotocols = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
168 if (subprotocols != null) {
169 String selectedSubprotocol = selectSubprotocol(subprotocols);
170 if (selectedSubprotocol == null) {
171 if (logger.isDebugEnabled()) {
172 logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
173 }
174 } else {
175 res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
176 }
177 }
178
179
180 String key1 = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_KEY1);
181 String key2 = req.headers().get(HttpHeaderNames.SEC_WEBSOCKET_KEY2);
182 int a = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key1).replaceAll("")) /
183 BEGINNING_SPACE.matcher(key1).replaceAll("").length());
184 int b = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key2).replaceAll("")) /
185 BEGINNING_SPACE.matcher(key2).replaceAll("").length());
186 long c = req.content().readLong();
187 ByteBuf input = Unpooled.wrappedBuffer(new byte[16]).setIndex(0, 0);
188 input.writeInt(a);
189 input.writeInt(b);
190 input.writeLong(c);
191 res.content().writeBytes(WebSocketUtil.md5(input.array()));
192 } else {
193
194 res.headers().add(HttpHeaderNames.WEBSOCKET_ORIGIN, origin);
195 res.headers().add(HttpHeaderNames.WEBSOCKET_LOCATION, uri());
196
197 String protocol = req.headers().get(HttpHeaderNames.WEBSOCKET_PROTOCOL);
198 if (protocol != null) {
199 res.headers().set(HttpHeaderNames.WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
200 }
201 }
202 return res;
203 }
204
205
206
207
208
209
210
211
212
213
214
215 @Override
216 public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
217 return channel.writeAndFlush(frame, promise);
218 }
219
220
221
222
223
224
225
226
227
228
229
230 @Override
231 public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame,
232 ChannelPromise promise) {
233 return ctx.writeAndFlush(frame, promise);
234 }
235
236 @Override
237 protected WebSocketFrameDecoder newWebsocketDecoder() {
238 return new WebSocket00FrameDecoder(decoderConfig());
239 }
240
241 @Override
242 protected WebSocketFrameEncoder newWebSocketEncoder() {
243 return new WebSocket00FrameEncoder();
244 }
245 }