Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/websockets/sync/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,12 @@ def protocol_select_subprotocol(
connection.recv_events_thread.join()
return

assert connection.protocol.state is OPEN
if connection.protocol.state is not OPEN:
# process_request or process_response rejected the handshake.
connection.close_socket()
connection.recv_events_thread.join()
return

try:
connection.start_keepalive()
handler(connection)
Expand Down
71 changes: 45 additions & 26 deletions tests/sync/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,29 +151,39 @@ def process_request(ws, request):
def handler(ws):
self.fail("handler must not run")

with run_server(handler, process_request=process_request) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 403",
)
with self.assertNoLogs("websockets", logging.ERROR):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at cdeb882, you'll see that it added assertNoLogs assertions to a bunch of tests in the asyncio implementation.

Likely, the same tests should have assertNoLogs in the threading implementation. Can you check and add where appropriate please?

with run_server(handler, process_request=process_request) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 403",
)

def test_process_request_raises_exception(self):
"""Server returns an error if process_request raises an exception."""

def process_request(ws, request):
raise RuntimeError
raise RuntimeError("BOOM")

with run_server(process_request=process_request) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 500",
)
with self.assertLogs("websockets", logging.ERROR) as logs:
with run_server(process_request=process_request) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 500",
)
self.assertEqual(
[record.getMessage() for record in logs.records],
["opening handshake failed"],
)
self.assertEqual(
[str(record.exc_info[1]) for record in logs.records],
["BOOM"],
)

def test_process_response_returns_none(self):
"""Server runs process_response but keeps the handshake response."""
Expand Down Expand Up @@ -213,16 +223,25 @@ def test_process_response_raises_exception(self):
"""Server returns an error if process_response raises an exception."""

def process_response(ws, request, response):
raise RuntimeError
raise RuntimeError("BOOM")

with run_server(process_response=process_response) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 500",
)
with self.assertLogs("websockets", logging.ERROR) as logs:
with run_server(process_response=process_response) as server:
with self.assertRaises(InvalidStatus) as raised:
with connect(get_uri(server)):
self.fail("did not raise")
self.assertEqual(
str(raised.exception),
"server rejected WebSocket connection: HTTP 500",
)
self.assertEqual(
[record.getMessage() for record in logs.records],
["opening handshake failed"],
)
self.assertEqual(
[str(record.exc_info[1]) for record in logs.records],
["BOOM"],
)

def test_override_server(self):
"""Server can override Server header with server_header."""
Expand Down