Skip to content

Commit bd552e5

Browse files
fix: Handle client disconnection for HTTP and WebSocket according to ASGI spec
For HTTP connections: - If the app is sending data using the send callable, according to the ASGI spec, it should throw an exception in case of client disconnection. Previously, even if we processed the client_error message and set the http->closed state, it wouldn't throw an error because it wasn't handled. This change ensures that the exception is raised as per the ASGI spec. For WebSocket connections: - If the app is awaiting on receive, it would get a 'websocket.disconnect' event. However, if the app continues to send data using the send callable after receiving this event, it wouldn't raise an error because ws->state = NXT_WS_DISCONNECTED was never set in that case. According to the ASGI spec, if send is called after receiving a 'websocket.disconnect' event or on a closed client, it should raise an exception. This change ensures that the exception is raised as per the ASGI spec.
1 parent 6cd6fca commit bd552e5

File tree

3 files changed

+9
-4
lines changed

3 files changed

+9
-4
lines changed

Diff for: src/nxt_unit.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static int nxt_unit_request_check_response_port(nxt_unit_request_info_t *req,
7474
static int nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req);
7575
static int nxt_unit_process_websocket(nxt_unit_ctx_t *ctx,
7676
nxt_unit_recv_msg_t *recv_msg);
77-
static int nxt_unit_process_client_error(nxt_unit_ctx_t *ctx,
77+
static int nxt_unit_process_client_error(nxt_unit_ctx_t *ctx,
7878
nxt_unit_recv_msg_t *recv_msg);
7979
static int nxt_unit_process_shm_ack(nxt_unit_ctx_t *ctx);
8080
static nxt_unit_request_info_impl_t *nxt_unit_request_info_get(
@@ -1736,7 +1736,7 @@ nxt_unit_process_client_error(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg
17361736
if (req == NULL) {
17371737
return NXT_UNIT_OK;
17381738
}
1739-
1739+
17401740
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
17411741

17421742
if (lib->callbacks.close_handler) {

Diff for: src/python/nxt_python_asgi_http.c

+5
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
367367
"Unexpected ASGI message 'http.response.body' "
368368
"sent, after response already completed");
369369
}
370+
371+
if (nxt_slow_path(http->closed)) {
372+
return PyErr_Format(PyExc_RuntimeError,
373+
"Connection Closed ");
374+
}
370375

371376
if (nxt_slow_path(http->send_future != NULL)) {
372377
return PyErr_Format(PyExc_RuntimeError, "Concurrent send");

Diff for: src/python/nxt_python_asgi_websocket.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -984,9 +984,9 @@ nxt_py_asgi_websocket_close_handler(nxt_unit_request_info_t *req)
984984
return;
985985
}
986986

987-
if (ws->receive_future == NULL) {
988-
ws->state = NXT_WS_DISCONNECTED;
987+
ws->state = NXT_WS_DISCONNECTED;
989988

989+
if (ws->receive_future == NULL) {
990990
return;
991991
}
992992

0 commit comments

Comments
 (0)