Skip to content

Commit e05f6dc

Browse files
committed
Support ws:// to wss:// redirects.
Fix #1454.
1 parent 650d08c commit e05f6dc

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

src/websockets/legacy/client.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -558,21 +558,27 @@ def handle_redirect(self, uri: str) -> None:
558558
raise SecurityError("redirect from WSS to WS")
559559

560560
same_origin = (
561-
old_wsuri.host == new_wsuri.host and old_wsuri.port == new_wsuri.port
561+
old_wsuri.secure == new_wsuri.secure
562+
and old_wsuri.host == new_wsuri.host
563+
and old_wsuri.port == new_wsuri.port
562564
)
563565

564-
# Rewrite the host and port arguments for cross-origin redirects.
566+
# Rewrite secure, host, and port for cross-origin redirects.
565567
# This preserves connection overrides with the host and port
566568
# arguments if the redirect points to the same host and port.
567569
if not same_origin:
568-
# Replace the host and port argument passed to the protocol factory.
569570
factory = self._create_connection.args[0]
571+
# Support TLS upgrade.
572+
if not old_wsuri.secure and new_wsuri.secure:
573+
factory.keywords["secure"] = True
574+
self._create_connection.keywords.setdefault("ssl", True)
575+
# Replace secure, host, and port arguments of the protocol factory.
570576
factory = functools.partial(
571577
factory.func,
572578
*factory.args,
573579
**dict(factory.keywords, host=new_wsuri.host, port=new_wsuri.port),
574580
)
575-
# Replace the host and port argument passed to create_connection.
581+
# Replace secure, host, and port arguments of create_connection.
576582
self._create_connection = functools.partial(
577583
self._create_connection.func,
578584
*(factory, new_wsuri.host, new_wsuri.port),

tests/legacy/test_client_server.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ async def redirect_request(path, headers, test, status):
7575
location = "/"
7676
elif path == "/infinite":
7777
location = get_server_uri(test.server, test.secure, "/infinite")
78+
elif path == "/force_secure":
79+
location = get_server_uri(test.server, True, "/")
7880
elif path == "/force_insecure":
7981
location = get_server_uri(test.server, False, "/")
8082
elif path == "/missing_location":
@@ -1290,7 +1292,16 @@ def test_connection_error_during_closing_handshake(self, close):
12901292
class ClientServerTests(
12911293
CommonClientServerTests, ClientServerTestsMixin, AsyncioTestCase
12921294
):
1293-
pass
1295+
1296+
def test_redirect_secure(self):
1297+
with temp_test_redirecting_server(self):
1298+
# websockets doesn't support serving non-TLS and TLS connections
1299+
# from the same server and this test suite makes it difficult to
1300+
# run two servers. Therefore, we expect the redirect to create a
1301+
# TLS client connection to a non-TLS server, which will fail.
1302+
with self.assertRaises(ssl.SSLError):
1303+
with self.temp_client("/force_secure"):
1304+
self.fail("did not raise")
12941305

12951306

12961307
class SecureClientServerTests(

0 commit comments

Comments
 (0)