Skip to content

Commit e59c7ba

Browse files
committed
tests: verify and describe edge case bug with websocket protocol
1 parent b5aa703 commit e59c7ba

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

tests/resources/websocket.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,34 @@ def on_message(self, message):
6868

6969

7070
class SubprotocolWebSocket(tornado.websocket.WebSocketHandler):
71-
"""Echoes back incoming requested subprotocols."""
71+
"""
72+
Echoes back requested subprotocols and selected subprotocol as a JSON
73+
encoded message, and selects subprotocols in a very particular way to help
74+
us test things.
75+
"""
7276

7377
def __init__(self, *args, **kwargs):
74-
self._subprotocols = None
78+
self._requested_subprotocols = None
7579
super().__init__(*args, **kwargs)
7680

7781
def select_subprotocol(self, subprotocols):
78-
self._subprotocols = subprotocols
79-
return None
82+
self._requested_subprotocols = subprotocols if subprotocols else None
83+
84+
if not subprotocols:
85+
return None
86+
if "please_select_no_protocol" in subprotocols:
87+
return None
88+
if "favored" in subprotocols:
89+
return "favored"
90+
else:
91+
return subprotocols[0]
8092

8193
def on_message(self, message):
82-
self.write_message(json.dumps(self._subprotocols))
94+
response = {
95+
"requested_subprotocols": self._requested_subprotocols,
96+
"selected_subprotocol": self.selected_subprotocol,
97+
}
98+
self.write_message(json.dumps(response))
8399

84100

85101
def main():

tests/test_proxies.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,68 @@ async def test_server_proxy_websocket_headers(a_server_port_and_token: Tuple[int
354354
assert headers["X-Custom-Header"] == "pytest-23456"
355355

356356

357+
@pytest.mark.parametrize(
358+
"client_requested,server_received,server_responded,proxy_responded",
359+
[
360+
(None, None, None, None),
361+
(["first"], ["first"], "first", "first"),
362+
# IMPORTANT: The tests below verify current bugged behavior, and the
363+
# commented out tests is what we want to succeed!
364+
#
365+
# The proxy websocket should actually respond the handshake
366+
# with a subprotocol based on a the server handshake
367+
# response, but we are finalizing the client/proxy handshake
368+
# before the proxy/server handshake, and that makes it
369+
# impossible. We currently instead just pick the first
370+
# requested protocol no matter what what subprotocol the
371+
# server picks.
372+
#
373+
# Bug 1 - server wasn't passed all subprotocols:
374+
(["first", "second"], ["first"], "first", "first"),
375+
# (["first", "second"], ["first", "second"], "first", "first"),
376+
#
377+
# Bug 2 - server_responded doesn't match proxy_responded:
378+
(["first", "favored"], ["first"], "first", "first"),
379+
# (["first", "favored"], ["first", "favored"], "favored", "favored"),
380+
(
381+
["please_select_no_protocol"],
382+
["please_select_no_protocol"],
383+
None,
384+
"please_select_no_protocol",
385+
),
386+
# (["please_select_no_protocol"], ["please_select_no_protocol"], None, None),
387+
],
388+
)
357389
async def test_server_proxy_websocket_subprotocols(
358-
a_server_port_and_token: Tuple[int, str]
390+
a_server_port_and_token: Tuple[int, str],
391+
client_requested,
392+
server_received,
393+
server_responded,
394+
proxy_responded,
359395
):
360396
PORT, TOKEN = a_server_port_and_token
361397
url = f"ws://{LOCALHOST}:{PORT}/python-websocket/subprotocolsocket"
362-
conn = await websocket_connect(url, subprotocols=["protocol_1", "protocol_2"])
398+
conn = await websocket_connect(url, subprotocols=client_requested)
363399
await conn.write_message("Hello, world!")
400+
401+
# verify understanding of websocket_connect that this test relies on
402+
if client_requested:
403+
assert "Sec-Websocket-Protocol" in conn.request.headers
404+
else:
405+
assert "Sec-Websocket-Protocol" not in conn.request.headers
406+
364407
msg = await conn.read_message()
365-
assert json.loads(msg) == ["protocol_1"]
408+
info = json.loads(msg)
409+
410+
assert info["requested_subprotocols"] == server_received
411+
assert info["selected_subprotocol"] == server_responded
412+
assert conn.selected_subprotocol == proxy_responded
413+
414+
# verify proxy response headers directly
415+
if proxy_responded is None:
416+
assert "Sec-Websocket-Protocol" not in conn.headers
417+
else:
418+
assert "Sec-Websocket-Protocol" in conn.headers
366419

367420

368421
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)