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 WebSocketServerHandshaker13(boolean isSecure, String host, String path,
107 String subprotocols, WebSocketDecoderConfig decoderConfig) {
108 super(WebSocketVersion.V13, isSecure, host, path, subprotocols, decoderConfig);
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
141
142
143
144
145 @Override
146 protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
147 HttpMethod method = req.method();
148 if (!GET.equals(method)) {
149 throw new WebSocketServerHandshakeException("Invalid WebSocket handshake method: " + method, req);
150 }
151
152 HttpHeaders reqHeaders = req.headers();
153 if (!reqHeaders.containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true)) {
154 throw new WebSocketServerHandshakeException(
155 "not a WebSocket request: a |Connection| header must include a token 'Upgrade'", req);
156 }
157
158 if (!reqHeaders.contains(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET, true)) {
159 throw new WebSocketServerHandshakeException(
160 "not a WebSocket request: an |Upgrade| header must containing the value 'websocket'", req);
161 }
162
163 String key = reqHeaders.get(HttpHeaderNames.SEC_WEBSOCKET_KEY);
164 if (key == null) {
165 throw new WebSocketServerHandshakeException("not a WebSocket request: missing key", req);
166 }
167
168 FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS,
169 req.content().alloc().buffer(0));
170 if (headers != null) {
171 res.headers().add(headers);
172 }
173
174 MessageDigest digestSha1 = WebSocketUtil.sha1();
175 digestSha1.update(key.getBytes(StandardCharsets.US_ASCII));
176 digestSha1.update(GUID_BYTES);
177 String accept = WebSocketUtil.base64(digestSha1.digest());
178
179 if (logger.isDebugEnabled()) {
180 logger.debug("WebSocket version 13 server handshake key: {}, response: {}", key, accept);
181 }
182
183 res.headers().set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET)
184 .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE)
185 .set(HttpHeaderNames.SEC_WEBSOCKET_ACCEPT, accept);
186
187 String subprotocols = reqHeaders.get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
188 if (subprotocols != null) {
189 String selectedSubprotocol = selectSubprotocol(subprotocols);
190 if (selectedSubprotocol == null) {
191 if (logger.isDebugEnabled()) {
192 logger.debug("Requested subprotocol(s) not supported: {}", subprotocols);
193 }
194 } else {
195 res.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
196 }
197 }
198 return res;
199 }
200
201 @Override
202 protected WebSocketFrameDecoder newWebsocketDecoder() {
203 return new WebSocket13FrameDecoder(decoderConfig());
204 }
205
206 @Override
207 protected WebSocketFrameEncoder newWebSocketEncoder() {
208 return new WebSocket13FrameEncoder(false);
209 }
210 }