@@ -112,8 +112,17 @@ def write_message(self, message, binary=False):
112
112
message = tornado .escape .json_encode (message )
113
113
self .ws_connection .write_message (message , binary = binary )
114
114
115
- def validate_subprotocol (self , subprotocols ):
116
- """Invoked when a new WebSocket requests specific subprotocols."""
115
+ def select_subprotocol (self , subprotocols ):
116
+ """Invoked when a new WebSocket requests specific subprotocols.
117
+
118
+ ``subprotocols`` is a list of strings identifying the
119
+ subprotocols proposed by the client. This method may be
120
+ overridden to return one of those strings to select it, or
121
+ ``None`` to not select a subprotocol. Failure to select a
122
+ subprotocol does not automatically abort the connection,
123
+ although clients may close the connection if none of their
124
+ proposed subprotocols was selected.
125
+ """
117
126
return None
118
127
119
128
def open (self , * args , ** kwargs ):
@@ -246,16 +255,14 @@ def accept_connection(self):
246
255
return
247
256
scheme = self .handler .get_websocket_scheme ()
248
257
249
- subprotocols = self .request .headers .get ("Sec-WebSocket-Protocol" , None )
250
- if subprotocols :
251
- subprotocol = self .handler .validate_subprotocol (subprotocols )
252
- if not subprotocol :
253
- logging .debug ("Subprotocol rejected by handler." )
254
- self ._abort ()
255
- return
256
- subprotocol = "Sec-WebSocket-Protocol: %s\r \n " % subprotocol
257
- else :
258
- subprotocol = ''
258
+ # draft76 only allows a single subprotocol
259
+ subprotocol_header = ''
260
+ subprotocol = self .request .headers .get ("Sec-WebSocket-Protocol" , None )
261
+ if subprotocol :
262
+ selected = self .handler .select_subprotocol ([subprotocol ])
263
+ if selected :
264
+ assert selected == subprotocol
265
+ subprotocol_header = "Sec-WebSocket-Protocol: %s\r \n " % selected
259
266
260
267
# Write the initial headers before attempting to read the challenge.
261
268
# This is necessary when using proxies (such as HAProxy), which
@@ -275,7 +282,7 @@ def accept_connection(self):
275
282
scheme = scheme ,
276
283
host = self .request .host ,
277
284
uri = self .request .uri ,
278
- subprotocol = subprotocol ))))
285
+ subprotocol = subprotocol_header ))))
279
286
self .stream .read_bytes (8 , self ._handle_challenge )
280
287
281
288
def challenge_response (self , challenge ):
@@ -435,24 +442,22 @@ def _challenge_response(self):
435
442
return tornado .escape .native_str (base64 .b64encode (sha1 .digest ()))
436
443
437
444
def _accept_connection (self ):
438
- subprotocols = self .request .headers .get ("Sec-WebSocket-Protocol" , None )
445
+ subprotocol_header = ''
446
+ subprotocols = self .request .headers .get ("Sec-WebSocket-Protocol" , '' )
447
+ subprotocols = [s .strip () for s in subprotocols .split (',' )]
439
448
if subprotocols :
440
- subprotocol = self .handler .validate_subprotocol (subprotocols )
441
- if not subprotocol :
442
- logging .debug ("Subprotocol rejected by handler." )
443
- self ._abort ()
444
- return
445
- subprotocol = "Sec-WebSocket-Protocol: %s\r \n " % subprotocol
446
- else :
447
- subprotocol = ''
449
+ selected = self .handler .select_subprotocol (subprotocols )
450
+ if selected :
451
+ assert selected in subprotocols
452
+ subprotocol_header = "Sec-WebSocket-Protocol: %s\r \n " % selected
448
453
449
454
self .stream .write (tornado .escape .utf8 (
450
455
"HTTP/1.1 101 Switching Protocols\r \n "
451
456
"Upgrade: websocket\r \n "
452
457
"Connection: Upgrade\r \n "
453
458
"Sec-WebSocket-Accept: %s\r \n "
454
459
"%s"
455
- "\r \n " % (self ._challenge_response (), subprotocol )))
460
+ "\r \n " % (self ._challenge_response (), subprotocol_header )))
456
461
457
462
self .async_callback (self .handler .open )(* self .handler .open_args , ** self .handler .open_kwargs )
458
463
self ._receive_frame ()
0 commit comments