Skip to content

Commit edca8d0

Browse files
committed
Clarify logs when process_request sends an HTTP response.
Fix #1606.
1 parent 9bc515c commit edca8d0

3 files changed

Lines changed: 50 additions & 19 deletions

File tree

docs/project/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ Improvements
8383
when the handshake request exceeds a security limit, instead of closing
8484
the connection.
8585

86+
* Clarified logs when ``process_request`` sends a plain HTTP response, without
87+
attempting to open a WebSocket connection.
88+
8689
* Added the ``reconnect_delays`` argument for customizing the delays between
8790
reconnection attempts in :func:`~asyncio.client.connect`, beyond existing
8891
``WEBSOCKETS_BACKOFF_*`` environment variables.

src/websockets/server.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ def __init__(
113113
"select_subprotocol",
114114
select_subprotocol.__get__(self, self.__class__),
115115
)
116+
# True when a WebSocket handshake was attempted via accept();
117+
# False when a plain HTTP response sent by process_request().
118+
self.accept_called = False
116119

117120
def accept(self, request: Request) -> Response:
118121
"""
@@ -136,6 +139,7 @@ def accept(self, request: Request) -> Response:
136139
WebSocket handshake response or HTTP response to send to the client.
137140
138141
"""
142+
self.accept_called = True
139143
try:
140144
(
141145
accept_header,
@@ -550,8 +554,12 @@ def send_response(self, response: Response) -> None:
550554
self.logger.info("connection open")
551555

552556
else:
557+
if self.accept_called:
558+
log_message = "connection rejected (%d %s)"
559+
else:
560+
log_message = "HTTP response sent (%d %s)"
553561
self.logger.info(
554-
"connection rejected (%d %s)",
562+
log_message,
555563
response.status_code,
556564
response.reason_phrase,
557565
)

tests/test_server.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,13 @@ def test_receive_request(self, _formatdate):
7171
self.assertFalse(server.close_expected())
7272
self.assertEqual(server.state, CONNECTING)
7373

74-
def test_accept_and_send_successful_response(self, _formatdate):
74+
def test_send_response_after_accept(self, _formatdate):
7575
"""Server accepts a handshake request and sends a successful response."""
7676
server = ServerProtocol()
7777
request = make_request()
7878
response = server.accept(request)
79-
server.send_response(response)
79+
with self.assertLogs("websockets.server", logging.INFO) as logs:
80+
server.send_response(response)
8081

8182
self.assertEqual(
8283
server.data_to_send(),
@@ -91,14 +92,19 @@ def test_accept_and_send_successful_response(self, _formatdate):
9192
)
9293
self.assertFalse(server.close_expected())
9394
self.assertEqual(server.state, OPEN)
95+
self.assertEqual(
96+
[record.getMessage() for record in logs.records],
97+
["connection open"],
98+
)
9499

95-
def test_send_response_after_failed_accept(self, _formatdate):
100+
def test_send_response_after_accept_failed(self, _formatdate):
96101
"""Server accepts a handshake request but sends a failed response."""
97102
server = ServerProtocol()
98103
request = make_request()
99104
del request.headers["Sec-WebSocket-Key"]
100105
response = server.accept(request)
101-
server.send_response(response)
106+
with self.assertLogs("websockets.server", logging.INFO) as logs:
107+
server.send_response(response)
102108

103109
self.assertEqual(
104110
server.data_to_send(),
@@ -116,12 +122,17 @@ def test_send_response_after_failed_accept(self, _formatdate):
116122
)
117123
self.assertTrue(server.close_expected())
118124
self.assertEqual(server.state, CONNECTING)
125+
self.assertEqual(
126+
[record.getMessage() for record in logs.records],
127+
["connection rejected (400 Bad Request)"],
128+
)
119129

120130
def test_send_response_after_reject(self, _formatdate):
121131
"""Server rejects a handshake request and sends a failed response."""
122132
server = ServerProtocol()
123133
response = server.reject(http.HTTPStatus.NOT_FOUND, "Sorry folks.\n")
124-
server.send_response(response)
134+
with self.assertLogs("websockets.server", logging.INFO) as logs:
135+
server.send_response(response)
125136

126137
self.assertEqual(
127138
server.data_to_send(),
@@ -138,24 +149,29 @@ def test_send_response_after_reject(self, _formatdate):
138149
)
139150
self.assertTrue(server.close_expected())
140151
self.assertEqual(server.state, CONNECTING)
152+
self.assertEqual(
153+
[record.getMessage() for record in logs.records],
154+
["HTTP response sent (404 Not Found)"],
155+
)
141156

142157
def test_send_response_without_accept_or_reject(self, _formatdate):
143158
"""Server doesn't accept or reject and sends a failed response."""
144159
server = ServerProtocol()
145-
server.send_response(
146-
Response(
147-
410,
148-
"Gone",
149-
Headers(
150-
{
151-
"Connection": "close",
152-
"Content-Length": "6",
153-
"Content-Type": "text/plain",
154-
}
155-
),
156-
b"AWOL.\n",
157-
)
160+
response = Response(
161+
410,
162+
"Gone",
163+
Headers(
164+
{
165+
"Connection": "close",
166+
"Content-Length": "6",
167+
"Content-Type": "text/plain",
168+
}
169+
),
170+
b"AWOL.\n",
158171
)
172+
with self.assertLogs("websockets.server", logging.INFO) as logs:
173+
server.send_response(response)
174+
159175
self.assertEqual(
160176
server.data_to_send(),
161177
[
@@ -170,6 +186,10 @@ def test_send_response_without_accept_or_reject(self, _formatdate):
170186
)
171187
self.assertTrue(server.close_expected())
172188
self.assertEqual(server.state, CONNECTING)
189+
self.assertEqual(
190+
[record.getMessage() for record in logs.records],
191+
["HTTP response sent (410 Gone)"],
192+
)
173193

174194

175195
class RequestTests(unittest.TestCase):

0 commit comments

Comments
 (0)