Skip to content

Commit db80ceb

Browse files
committed
Revert "fix(websockets): Send close frame on ASGI return (#2769)"
This reverts commit 5692dfc.
1 parent 918dae6 commit db80ceb

4 files changed

Lines changed: 13 additions & 27 deletions

File tree

tests/protocols/test_websocket.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -451,27 +451,6 @@ async def app(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable
451451
assert websocket.close_code == 1006
452452

453453

454-
async def test_close_transport_on_asgi_return(
455-
ws_protocol_cls: WSProtocol, http_protocol_cls: HTTPProtocol, unused_tcp_port: int
456-
):
457-
"""The ASGI callable should call the `websocket.close` event.
458-
459-
If it doesn't, the server should still send a close frame to the client.
460-
"""
461-
462-
async def app(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable):
463-
message = await receive()
464-
if message["type"] == "websocket.connect":
465-
await send({"type": "websocket.accept"})
466-
467-
config = Config(app=app, ws=ws_protocol_cls, http=http_protocol_cls, lifespan="off", port=unused_tcp_port)
468-
async with run_server(config):
469-
async with websockets.client.connect(f"ws://127.0.0.1:{unused_tcp_port}") as websocket:
470-
with pytest.raises(websockets.exceptions.ConnectionClosed):
471-
await websocket.recv()
472-
assert websocket.close_code == 1006
473-
474-
475454
@pytest.mark.parametrize("code", [None, 1000, 1001])
476455
@pytest.mark.parametrize("reason", [None, "test", False], ids=["none_as_reason", "normal_reason", "without_reason"])
477456
async def test_app_close(

uvicorn/protocols/websockets/websockets_impl.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,22 +244,25 @@ async def run_asgi(self) -> None:
244244
result = await self.app(self.scope, self.asgi_receive, self.asgi_send) # type: ignore[func-returns-value]
245245
except ClientDisconnected: # pragma: full coverage
246246
self.closed_event.set()
247+
self.transport.close()
247248
except BaseException:
248249
self.closed_event.set()
249250
self.logger.exception("Exception in ASGI application\n")
250251
if not self.handshake_started_event.is_set():
251252
self.send_500_response()
252253
else:
253254
await self.handshake_completed_event.wait()
255+
self.transport.close()
254256
else:
255257
self.closed_event.set()
256258
if not self.handshake_started_event.is_set():
257259
self.logger.error("ASGI callable returned without sending handshake.")
258260
self.send_500_response()
261+
self.transport.close()
259262
elif result is not None:
260263
self.logger.error("ASGI callable should return None, but returned '%s'.", result)
261-
await self.handshake_completed_event.wait()
262-
self.transport.close()
264+
await self.handshake_completed_event.wait()
265+
self.transport.close()
263266

264267
async def asgi_send(self, message: ASGISendEvent) -> None:
265268
message_type = message["type"]

uvicorn/protocols/websockets/websockets_sansio_impl.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,17 +271,19 @@ async def run_asgi(self) -> None:
271271
try:
272272
result = await self.app(self.scope, self.receive, self.send)
273273
except ClientDisconnected:
274-
pass # pragma: full coverage
274+
self.transport.close() # pragma: no cover
275275
except BaseException:
276276
self.logger.exception("Exception in ASGI application\n")
277277
self.send_500_response()
278+
self.transport.close()
278279
else:
279280
if not self.handshake_complete:
280281
self.logger.error("ASGI callable returned without completing handshake.")
281282
self.send_500_response()
283+
self.transport.close()
282284
elif result is not None:
283285
self.logger.error("ASGI callable should return None, but returned '%s'.", result)
284-
self.transport.close()
286+
self.transport.close()
285287

286288
def send_500_response(self) -> None:
287289
if self.initial_response or self.handshake_complete:

uvicorn/protocols/websockets/wsproto_impl.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,17 +234,19 @@ async def run_asgi(self) -> None:
234234
try:
235235
result = await self.app(self.scope, self.receive, self.send) # type: ignore[func-returns-value]
236236
except ClientDisconnected:
237-
pass # pragma: full coverage
237+
self.transport.close() # pragma: full coverage
238238
except BaseException:
239239
self.logger.exception("Exception in ASGI application\n")
240240
self.send_500_response()
241+
self.transport.close()
241242
else:
242243
if not self.handshake_complete:
243244
self.logger.error("ASGI callable returned without completing handshake.")
244245
self.send_500_response()
246+
self.transport.close()
245247
elif result is not None:
246248
self.logger.error("ASGI callable should return None, but returned '%s'.", result)
247-
self.transport.close()
249+
self.transport.close()
248250

249251
async def send(self, message: ASGISendEvent) -> None:
250252
await self.writable.wait()

0 commit comments

Comments
 (0)