Fixed WebSocket connection hang issue after listener reconfigure.

Because the configuration values were read from the listener's configuration,
an established WebSocket connection was unable to work properly (i. e. stuck)
if the listener was removed.  The correct source of configuration values is the
request config joint.

This is related to issue #581 on GitHub.
This commit is contained in:
Max Romanov
2021-09-20 09:01:08 +03:00
parent d21ebcce83
commit c07f3d3ff6
3 changed files with 39 additions and 29 deletions

View File

@@ -37,6 +37,13 @@ fixed building with glibc 2.34, notably Fedora 35.
</para>
</change>
<change type="bugfix">
<para>
established WebSocket connections could stop reading frames from the client
after the corresponding listener had been reconfigured.
</para>
</change>
</changes>

View File

@@ -76,7 +76,7 @@ nxt_h1p_websocket_first_frame_start(nxt_task_t *task, nxt_http_request_t *r,
nxt_conn_t *c;
nxt_timer_t *timer;
nxt_h1proto_t *h1p;
nxt_socket_conf_joint_t *joint;
nxt_websocket_conf_t *websocket_conf;
nxt_debug(task, "h1p ws first frame start");
@@ -87,11 +87,9 @@ nxt_h1p_websocket_first_frame_start(nxt_task_t *task, nxt_http_request_t *r,
nxt_conn_tcp_nodelay_on(task, c);
}
joint = c->listen->socket.data;
websocket_conf = &r->conf->socket_conf->websocket_conf;
if (nxt_slow_path(joint != NULL
&& joint->socket_conf->websocket_conf.keepalive_interval != 0))
{
if (nxt_slow_path(websocket_conf->keepalive_interval != 0)) {
h1p->websocket_timer = nxt_mp_zget(c->mem_pool,
sizeof(nxt_h1p_websocket_timer_t));
if (nxt_slow_path(h1p->websocket_timer == NULL)) {
@@ -100,7 +98,7 @@ nxt_h1p_websocket_first_frame_start(nxt_task_t *task, nxt_http_request_t *r,
}
h1p->websocket_timer->keepalive_interval =
joint->socket_conf->websocket_conf.keepalive_interval;
websocket_conf->keepalive_interval;
h1p->websocket_timer->h1p = h1p;
timer = &h1p->websocket_timer->timer;
@@ -225,7 +223,6 @@ nxt_h1p_conn_ws_frame_header_read(nxt_task_t *task, void *obj, void *data)
nxt_http_request_t *r;
nxt_event_engine_t *engine;
nxt_websocket_header_t *wsh;
nxt_socket_conf_joint_t *joint;
c = obj;
h1p = data;
@@ -265,17 +262,6 @@ nxt_h1p_conn_ws_frame_header_read(nxt_task_t *task, void *obj, void *data)
r->ws_frame = c->read;
joint = c->listen->socket.data;
if (nxt_slow_path(joint == NULL)) {
/*
* Listening socket had been closed while
* connection was in keep-alive state.
*/
c->read_state = &nxt_h1p_idle_close_state;
return;
}
if (nxt_slow_path(wsh->mask == 0)) {
hxt_h1p_send_ws_error(task, r, &nxt_ws_err_not_masked);
return;
@@ -330,7 +316,7 @@ nxt_h1p_conn_ws_frame_header_read(nxt_task_t *task, void *obj, void *data)
h1p->websocket_cont_expected = !wsh->fin;
}
max_frame_size = joint->socket_conf->websocket_conf.max_frame_size;
max_frame_size = r->conf->socket_conf->websocket_conf.max_frame_size;
payload_len = nxt_websocket_frame_payload_len(wsh);

View File

@@ -1481,3 +1481,20 @@ class TestASGIWebsockets(TestApplicationPython):
self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame
sock.close()
def test_asgi_websockets_client_locks_app(self):
self.load('websockets/mirror')
message = 'blah'
_, sock, _ = self.ws.upgrade()
assert 'success' in self.conf({}), 'remove app'
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
frame = self.ws.frame_read(sock)
assert message == frame['data'].decode('utf-8'), 'client'
sock.close()