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.handler.codec.http.DefaultFullHttpResponse;
19 import io.netty.handler.codec.http.FullHttpRequest;
20 import io.netty.handler.codec.http.FullHttpResponse;
21 import io.netty.handler.codec.http.HttpHeaderNames;
22 import io.netty.handler.codec.http.HttpHeaderValues;
23 import io.netty.handler.codec.http.HttpHeaders;
24 import io.netty.handler.codec.http.HttpMethod;
25 import io.netty.handler.codec.http.HttpResponseStatus;
26
27 import java.nio.charset.StandardCharsets;
28 import java.security.MessageDigest;
29
30 import static io.netty.handler.codec.http.HttpMethod.GET;
31 import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
32
33
34
35
36
37
38
39 public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
40
41 public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
42 private static final byte[] GUID_BYTES = WEBSOCKET_13_ACCEPT_GUID.getBytes(StandardCharsets.US_ASCII);
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public WebSocketServerHandshaker13(
59 String webSocketURL, String subprotocols, boolean allowExtensions, int maxFramePayloadLength) {
60 this(webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength, false);
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public WebSocketServerHandshaker13(
81 String webSocketURL, String subprotocols, boolean allowExtensions, int maxFramePayloadLength,
82 boolean allowMaskMismatch) {
83 this(webSocketURL, subprotocols, WebSocketDecoderConfig.newBuilder()
84 .allowExtensions(allowExtensions)
85 .maxFramePayloadLength(maxFramePayloadLength)
86 .allowMaskMismatch(allowMaskMismatch)
87 .build());
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101 public WebSocketServerHandshaker13(
102 String webSocketURL, String subprotocols, WebSocketDecoderConfig decoderConfig) {
103 super(WebSocketVersion.V13, webSocketURL, subprotocols, decoderConfig);
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
132
133
134
135
136
137
138
139
140 @Override
141 protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
142 HttpMethod method = req.method();
143 if (!GET.equals(method)) {
144 throw new WebSocketServerHandshakeException("Invalid WebSocket handshake method: " + method, req);
145 }
146
147 HttpHeaders reqHeaders = req.headers();
148 if (!reqHeaders.containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true)) {
149 throw new WebSocketServerHandshakeException(
150 "not a WebSocket request: a |Connection| header must includes a token 'Upgrade'", req);
151 }
152
153 if (!reqHeaders.contains(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET, true)) {
154 throw new WebSocketServerHandshakeException(
155 "not a WebSocket request: a |Upgrade| header must containing the value 'websocket'", req);
156 }
157
158 String key = reqHeaders.get(HttpHeaderNames.SEC_WEBSOCKET_KEY);
159 if (key == null) {
160 throw new WebSocketServerHandshakeException("not a WebSocket request: missing key", req);
161 }
162
163 FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS,
164 req.content().alloc().buffer(0));
165 if (headers != null) {
166 res.headers().add(headers);
167 }
168
169 MessageDigest digestSha1 = WebSocketUtil.sha1();
170 digestSha1.update(key.getBytes(StandardCharsets.US_ASCII));
171 digestSha1.update(GUID_BYTES);
172 String accept = WebSocketUtil.base64(digestSha1.digest());
173
174 if (logger.isDebugEnabled()) {
175 logger.debug("WebSocket version 13 server handshake key: {}, response: {}", key, accept);
176 }
177
178 res.headers().set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET)
179 .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE)
180 .set(HttpHeaderNames.SEC_WEBSOCKET_ACCEPT, accept);
181
182 String subprotocols = reqHeaders.get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
183 if (subprotocols != null) {
184 String selectedSubprotocol = selectSubprotocol(subprotocols);
185 if (selectedSubprotocol == null) {
186 if (logger.isDebugEnabled()) {
187 logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
188 }
189 } else {
190 res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
191 }
192 }
193 return res;
194 }
195
196 @Override
197 protected WebSocketFrameDecoder newWebsocketDecoder() {
198 return new WebSocket13FrameDecoder(decoderConfig());
199 }
200
201 @Override
202 protected WebSocketFrameEncoder newWebSocketEncoder() {
203 return new WebSocket13FrameEncoder(false);
204 }
205 }