Skip to content

Commit 65c9664

Browse files
authored
Unblock ASGI ws receive on close without accept (#819)
1 parent a288cc3 commit 65c9664

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

src/asgi/io.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,16 +476,18 @@ impl ASGIWebsocketProtocol {
476476

477477
#[inline(always)]
478478
fn close<'p>(&self, py: Python<'p>, frame: Option<wsframe::CloseFrame>) -> PyResult<Bound<'p, PyAny>> {
479-
let closed = self.closed.clone();
479+
let init_ev = self.init_event.clone();
480480
let ws_rx = self.ws_rx.clone();
481481
let ws_tx = self.ws_tx.clone();
482+
self.closed.store(true, atomic::Ordering::Release);
482483

483484
future_into_py_futlike(self.rt.clone(), py, async move {
484485
if let Some(tx) = ws_tx.lock().await.take() {
485-
closed.store(true, atomic::Ordering::Release);
486486
WebsocketDetachedTransport::new(true, ws_rx.lock().await.take(), Some(tx), frame)
487487
.close()
488488
.await;
489+
} else {
490+
init_ev.notify_one();
489491
}
490492
FutureResultToPy::None
491493
})

tests/apps/asgi.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ async def ws_reject(scope, receive, send):
7070
return
7171

7272

73+
async def ws_reject_explicit(scope, receive, send):
74+
await receive()
75+
await send({'type': 'websocket.close'})
76+
await receive()
77+
78+
7379
async def ws_reject_custom(scope, receive, send):
7480
await receive()
7581
await send(
@@ -216,6 +222,7 @@ def app(scope, receive, send):
216222
'/echo': echo,
217223
'/file': pathsend,
218224
'/ws_reject': ws_reject,
225+
'/ws_rejecte': ws_reject_explicit,
219226
'/ws_rejectc': ws_reject_custom,
220227
'/ws_info': ws_info,
221228
'/ws_echo': ws_echo,

tests/test_ws.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import pytest
66
import websockets
7+
import websockets.exceptions
78

89

910
@pytest.mark.asyncio
@@ -52,6 +53,17 @@ async def test_asgi_server_close(asgi_server, runtime_mode, tmp_path):
5253
assert target.exists()
5354

5455

56+
@pytest.mark.asyncio
57+
@pytest.mark.parametrize('runtime_mode', ['mt', 'st'])
58+
async def test_asgi_reject_explicit(asgi_server, runtime_mode):
59+
async with asgi_server(runtime_mode) as port:
60+
with pytest.raises(websockets.exceptions.InvalidStatus) as exc:
61+
async with websockets.connect(f'ws://localhost:{port}/ws_rejecte'):
62+
pass
63+
64+
assert exc.value.response.status_code == 403
65+
66+
5567
@pytest.mark.asyncio
5668
@pytest.mark.parametrize('runtime_mode', ['mt', 'st'])
5769
async def test_asgi_reject_custom(asgi_server, runtime_mode):

0 commit comments

Comments
 (0)