21
21
22
22
WS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
23
23
WS_HDRS = ('UPGRADE' , 'CONNECTION' ,
24
- 'SEC-WEBSOCKET-VERSION' , 'SEC-WEBSOCKET-KEY' )
24
+ 'SEC-WEBSOCKET-VERSION' , 'SEC-WEBSOCKET-KEY' , 'SEC-WEBSOCKET-PROTOCOL' )
25
25
26
26
Message = collections .namedtuple ('Message' , ['tp' , 'data' , 'extra' ])
27
27
@@ -182,10 +182,14 @@ def close(self, code=1000, message=b''):
182
182
opcode = OPCODE_CLOSE )
183
183
184
184
185
- def do_handshake (method , headers , transport ):
185
+ def do_handshake (method , headers , transport , protocols = () ):
186
186
"""Prepare WebSocket handshake. It return http response code,
187
187
response headers, websocket parser, websocket writer. It does not
188
- perform any IO."""
188
+ perform any IO.
189
+
190
+ `protocols` is a sequence of known protocols. On successful handshake,
191
+ the returned response headers contain the first protocol in this list
192
+ which the server also knows."""
189
193
190
194
# WebSocket accepts only GET
191
195
if method .upper () != 'GET' :
@@ -201,6 +205,21 @@ def do_handshake(method, headers, transport):
201
205
raise errors .HttpBadRequest (
202
206
'No CONNECTION upgrade hdr: {}' .format (
203
207
headers .get ('CONNECTION' )))
208
+
209
+ # find common sub-protocol between client and server
210
+ protocol = None
211
+ if 'SEC-WEBSOCKET-PROTOCOL' in headers :
212
+ req_protocols = {str (proto .strip ()) for proto in
213
+ headers ['SEC-WEBSOCKET-PROTOCOL' ].split (',' )}
214
+
215
+ for proto in protocols :
216
+ if proto in req_protocols :
217
+ protocol = proto
218
+ break
219
+ else :
220
+ raise errors .HttpBadRequest (
221
+ 'Client protocols {!r} don’t overlap server-known ones {!r}'
222
+ .format (protocols , req_protocols ))
204
223
205
224
# check supported version
206
225
version = headers .get ('SEC-WEBSOCKET-VERSION' )
@@ -218,12 +237,18 @@ def do_handshake(method, headers, transport):
218
237
raise errors .HttpBadRequest (
219
238
'Handshake error: {!r}' .format (key )) from None
220
239
221
- # response code, headers, parser, writer
222
- return (101 ,
223
- (('UPGRADE' , 'websocket' ),
240
+ response_headers = [('UPGRADE' , 'websocket' ),
224
241
('CONNECTION' , 'upgrade' ),
225
242
('TRANSFER-ENCODING' , 'chunked' ),
226
243
('SEC-WEBSOCKET-ACCEPT' , base64 .b64encode (
227
- hashlib .sha1 (key .encode () + WS_KEY ).digest ()).decode ())),
244
+ hashlib .sha1 (key .encode () + WS_KEY ).digest ()).decode ())]
245
+
246
+ if protocol :
247
+ response_headers .append (('SEC-WEBSOCKET-PROTOCOL' , protocol ))
248
+
249
+ # response code, headers, parser, writer, protocol
250
+ return (101 ,
251
+ response_headers ,
228
252
WebSocketParser ,
229
- WebSocketWriter (transport ))
253
+ WebSocketWriter (transport ),
254
+ protocol )
0 commit comments