Skip to content

Commit 8eaa5a2

Browse files
committed
Document & test process_response modifying the response.
a78b554 inadvertently changed the test from "returning a new response" to "modifying the existing response". Both are supported..
1 parent 09b1d8d commit 8eaa5a2

File tree

4 files changed

+78
-44
lines changed

4 files changed

+78
-44
lines changed

src/websockets/asyncio/server.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,16 @@ class Server:
236236
handler: Connection handler. It receives the WebSocket connection,
237237
which is a :class:`ServerConnection`, in argument.
238238
process_request: Intercept the request during the opening handshake.
239-
Return an HTTP response to force the response or :obj:`None` to
239+
Return an HTTP response to force the response. Return :obj:`None` to
240240
continue normally. When you force an HTTP 101 Continue response, the
241241
handshake is successful. Else, the connection is aborted.
242242
``process_request`` may be a function or a coroutine.
243243
process_response: Intercept the response during the opening handshake.
244-
Return an HTTP response to force the response or :obj:`None` to
245-
continue normally. When you force an HTTP 101 Continue response, the
246-
handshake is successful. Else, the connection is aborted.
247-
``process_response`` may be a function or a coroutine.
244+
Modify the response or return a new HTTP response to force the
245+
response. Return :obj:`None` to continue normally. When you force an
246+
HTTP 101 Continue response, the handshake is successful. Else, the
247+
connection is aborted. ``process_response`` may be a function or a
248+
coroutine.
248249
server_header: Value of the ``Server`` response header.
249250
It defaults to ``"Python/x.y.z websockets/X.Y"``. Setting it to
250251
:obj:`None` removes the header.

src/websockets/sync/server.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,13 +401,14 @@ def handler(websocket):
401401
:meth:`ServerProtocol.select_subprotocol
402402
<websockets.server.ServerProtocol.select_subprotocol>` method.
403403
process_request: Intercept the request during the opening handshake.
404-
Return an HTTP response to force the response or :obj:`None` to
405-
continue normally. When you force an HTTP 101 Continue response,
406-
the handshake is successful. Else, the connection is aborted.
404+
Return an HTTP response to force the response. Return :obj:`None` to
405+
continue normally. When you force an HTTP 101 Continue response, the
406+
handshake is successful. Else, the connection is aborted.
407407
process_response: Intercept the response during the opening handshake.
408-
Return an HTTP response to force the response or :obj:`None` to
409-
continue normally. When you force an HTTP 101 Continue response,
410-
the handshake is successful. Else, the connection is aborted.
408+
Modify the response or return a new HTTP response to force the
409+
response. Return :obj:`None` to continue normally. When you force an
410+
HTTP 101 Continue response, the handshake is successful. Else, the
411+
connection is aborted.
411412
server_header: Value of the ``Server`` response header.
412413
It defaults to ``"Python/x.y.z websockets/X.Y"``. Setting it to
413414
:obj:`None` removes the header.

tests/asyncio/test_server.py

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import dataclasses
23
import http
34
import logging
45
import socket
@@ -117,8 +118,8 @@ def select_subprotocol(ws, subprotocols):
117118
"server rejected WebSocket connection: HTTP 500",
118119
)
119120

120-
async def test_process_request(self):
121-
"""Server runs process_request before processing the handshake."""
121+
async def test_process_request_returns_none(self):
122+
"""Server runs process_request and continues the handshake."""
122123

123124
def process_request(ws, request):
124125
self.assertIsInstance(request, Request)
@@ -128,8 +129,8 @@ def process_request(ws, request):
128129
async with run_client(server) as client:
129130
await self.assertEval(client, "ws.process_request_ran", "True")
130131

131-
async def test_async_process_request(self):
132-
"""Server runs async process_request before processing the handshake."""
132+
async def test_async_process_request_returns_none(self):
133+
"""Server runs async process_request and continues the handshake."""
133134

134135
async def process_request(ws, request):
135136
self.assertIsInstance(request, Request)
@@ -139,7 +140,7 @@ async def process_request(ws, request):
139140
async with run_client(server) as client:
140141
await self.assertEval(client, "ws.process_request_ran", "True")
141142

142-
async def test_process_request_abort_handshake(self):
143+
async def test_process_request_returns_response(self):
143144
"""Server aborts handshake if process_request returns a response."""
144145

145146
def process_request(ws, request):
@@ -154,7 +155,7 @@ def process_request(ws, request):
154155
"server rejected WebSocket connection: HTTP 403",
155156
)
156157

157-
async def test_async_process_request_abort_handshake(self):
158+
async def test_async_process_request_returns_response(self):
158159
"""Server aborts handshake if async process_request returns a response."""
159160

160161
async def process_request(ws, request):
@@ -199,8 +200,8 @@ async def process_request(ws, request):
199200
"server rejected WebSocket connection: HTTP 500",
200201
)
201202

202-
async def test_process_response(self):
203-
"""Server runs process_response after processing the handshake."""
203+
async def test_process_response_returns_none(self):
204+
"""Server runs process_response but keeps the handshake response."""
204205

205206
def process_response(ws, request, response):
206207
self.assertIsInstance(request, Request)
@@ -211,8 +212,8 @@ def process_response(ws, request, response):
211212
async with run_client(server) as client:
212213
await self.assertEval(client, "ws.process_response_ran", "True")
213214

214-
async def test_async_process_response(self):
215-
"""Server runs async process_response after processing the handshake."""
215+
async def test_async_process_response_returns_none(self):
216+
"""Server runs async process_response but keeps the handshake response."""
216217

217218
async def process_response(ws, request, response):
218219
self.assertIsInstance(request, Request)
@@ -223,29 +224,49 @@ async def process_response(ws, request, response):
223224
async with run_client(server) as client:
224225
await self.assertEval(client, "ws.process_response_ran", "True")
225226

226-
async def test_process_response_override_response(self):
227-
"""Server runs process_response and overrides the handshake response."""
227+
async def test_process_response_modifies_response(self):
228+
"""Server runs process_response and modifies the handshake response."""
228229

229230
def process_response(ws, request, response):
230-
response.headers["X-ProcessResponse-Ran"] = "true"
231+
response.headers["X-ProcessResponse"] = "OK"
231232

232233
async with run_server(process_response=process_response) as server:
233234
async with run_client(server) as client:
234-
self.assertEqual(
235-
client.response.headers["X-ProcessResponse-Ran"], "true"
236-
)
235+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
237236

238-
async def test_async_process_response_override_response(self):
239-
"""Server runs async process_response and overrides the handshake response."""
237+
async def test_async_process_response_modifies_response(self):
238+
"""Server runs async process_response and modifies the handshake response."""
240239

241240
async def process_response(ws, request, response):
242-
response.headers["X-ProcessResponse-Ran"] = "true"
241+
response.headers["X-ProcessResponse"] = "OK"
243242

244243
async with run_server(process_response=process_response) as server:
245244
async with run_client(server) as client:
246-
self.assertEqual(
247-
client.response.headers["X-ProcessResponse-Ran"], "true"
248-
)
245+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
246+
247+
async def test_process_response_replaces_response(self):
248+
"""Server runs process_response and replaces the handshake response."""
249+
250+
def process_response(ws, request, response):
251+
headers = response.headers.copy()
252+
headers["X-ProcessResponse"] = "OK"
253+
return dataclasses.replace(response, headers=headers)
254+
255+
async with run_server(process_response=process_response) as server:
256+
async with run_client(server) as client:
257+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
258+
259+
async def test_async_process_response_replaces_response(self):
260+
"""Server runs async process_response and replaces the handshake response."""
261+
262+
async def process_response(ws, request, response):
263+
headers = response.headers.copy()
264+
headers["X-ProcessResponse"] = "OK"
265+
return dataclasses.replace(response, headers=headers)
266+
267+
async with run_server(process_response=process_response) as server:
268+
async with run_client(server) as client:
269+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
249270

250271
async def test_process_response_raises_exception(self):
251272
"""Server returns an error if process_response raises an exception."""

tests/sync/test_server.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dataclasses
12
import http
23
import logging
34
import socket
@@ -115,8 +116,8 @@ def select_subprotocol(ws, subprotocols):
115116
"server rejected WebSocket connection: HTTP 500",
116117
)
117118

118-
def test_process_request(self):
119-
"""Server runs process_request before processing the handshake."""
119+
def test_process_request_returns_none(self):
120+
"""Server runs process_request and continues the handshake."""
120121

121122
def process_request(ws, request):
122123
self.assertIsInstance(request, Request)
@@ -126,7 +127,7 @@ def process_request(ws, request):
126127
with run_client(server) as client:
127128
self.assertEval(client, "ws.process_request_ran", "True")
128129

129-
def test_process_request_abort_handshake(self):
130+
def test_process_request_returns_response(self):
130131
"""Server aborts handshake if process_request returns a response."""
131132

132133
def process_request(ws, request):
@@ -156,8 +157,8 @@ def process_request(ws, request):
156157
"server rejected WebSocket connection: HTTP 500",
157158
)
158159

159-
def test_process_response(self):
160-
"""Server runs process_response after processing the handshake."""
160+
def test_process_response_returns_none(self):
161+
"""Server runs process_response but keeps the handshake response."""
161162

162163
def process_response(ws, request, response):
163164
self.assertIsInstance(request, Request)
@@ -168,17 +169,27 @@ def process_response(ws, request, response):
168169
with run_client(server) as client:
169170
self.assertEval(client, "ws.process_response_ran", "True")
170171

171-
def test_process_response_override_response(self):
172-
"""Server runs process_response and overrides the handshake response."""
172+
def test_process_response_modifies_response(self):
173+
"""Server runs process_response and modifies the handshake response."""
173174

174175
def process_response(ws, request, response):
175-
response.headers["X-ProcessResponse-Ran"] = "true"
176+
response.headers["X-ProcessResponse"] = "OK"
176177

177178
with run_server(process_response=process_response) as server:
178179
with run_client(server) as client:
179-
self.assertEqual(
180-
client.response.headers["X-ProcessResponse-Ran"], "true"
181-
)
180+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
181+
182+
def test_process_response_replaces_response(self):
183+
"""Server runs process_response and replaces the handshake response."""
184+
185+
def process_response(ws, request, response):
186+
headers = response.headers.copy()
187+
headers["X-ProcessResponse"] = "OK"
188+
return dataclasses.replace(response, headers=headers)
189+
190+
with run_server(process_response=process_response) as server:
191+
with run_client(server) as client:
192+
self.assertEqual(client.response.headers["X-ProcessResponse"], "OK")
182193

183194
def test_process_response_raises_exception(self):
184195
"""Server returns an error if process_response raises an exception."""

0 commit comments

Comments
 (0)