Skip to content

Commit eee9953

Browse files
committed
Websocket subprotocol updates.
Failure to select a subprotocol is not fatal, so rename method from validate_subprotocol to select_subprotocol. Subprotocols are a comma-separated list in the RFC version, but a single value in draft76.
1 parent 1cfcc4a commit eee9953

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

tornado/websocket.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,17 @@ def write_message(self, message, binary=False):
112112
message = tornado.escape.json_encode(message)
113113
self.ws_connection.write_message(message, binary=binary)
114114

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+
"""
117126
return None
118127

119128
def open(self, *args, **kwargs):
@@ -246,16 +255,14 @@ def accept_connection(self):
246255
return
247256
scheme = self.handler.get_websocket_scheme()
248257

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
259266

260267
# Write the initial headers before attempting to read the challenge.
261268
# This is necessary when using proxies (such as HAProxy), which
@@ -275,7 +282,7 @@ def accept_connection(self):
275282
scheme=scheme,
276283
host=self.request.host,
277284
uri=self.request.uri,
278-
subprotocol=subprotocol))))
285+
subprotocol=subprotocol_header))))
279286
self.stream.read_bytes(8, self._handle_challenge)
280287

281288
def challenge_response(self, challenge):
@@ -435,24 +442,22 @@ def _challenge_response(self):
435442
return tornado.escape.native_str(base64.b64encode(sha1.digest()))
436443

437444
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(',')]
439448
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
448453

449454
self.stream.write(tornado.escape.utf8(
450455
"HTTP/1.1 101 Switching Protocols\r\n"
451456
"Upgrade: websocket\r\n"
452457
"Connection: Upgrade\r\n"
453458
"Sec-WebSocket-Accept: %s\r\n"
454459
"%s"
455-
"\r\n" % (self._challenge_response(), subprotocol)))
460+
"\r\n" % (self._challenge_response(), subprotocol_header)))
456461

457462
self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)
458463
self._receive_frame()

0 commit comments

Comments
 (0)