From 545d18d84da18d08a7da89bdd785a90c18c723fc Mon Sep 17 00:00:00 2001 From: Jessie Murray Date: Sun, 1 Aug 2021 14:11:07 -0700 Subject: [PATCH] Send error messages to WS clients if triggered by Redis Also mark the WS client as closing before we close the Redis connection, to avoid its last error callback (if sent) trying to send out data while we're in the middle of freeing the client. --- src/formats/common.c | 4 +++- src/websocket.c | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/formats/common.c b/src/formats/common.c index 94f88e6..50e4780 100644 --- a/src/formats/common.c +++ b/src/formats/common.c @@ -46,12 +46,14 @@ format_send_error(struct cmd *cmd, short code, const char *msg) { resp->http_version = cmd->http_version; http_response_set_keep_alive(resp, cmd->keep_alive); http_response_write(resp, cmd->fd); + } else if(cmd->is_websocket && !cmd->http_client->ws->close_after_events) { + ws_frame_and_send_response(cmd->http_client->ws, WS_BINARY_FRAME, msg, strlen(msg)); } /* for pub/sub, remove command from client */ if(cmd->pub_sub_client) { cmd->pub_sub_client->self_cmd = NULL; - } else { + } else if (!cmd->is_websocket) { /* don't free persistent cmd */ cmd_free(cmd); } } diff --git a/src/websocket.c b/src/websocket.c index af31577..27358ea 100644 --- a/src/websocket.c +++ b/src/websocket.c @@ -123,11 +123,14 @@ ws_client_new(struct http_client *http_client) { static void ws_client_free(struct ws_client *ws) { + /* mark WS client as closing to skip the Redis callback */ + ws->close_after_events = 1; + pool_free_context(ws->ac); /* could trigger a cb via format_send_error */ + struct http_client *c = ws->http_client; c->ws = NULL; /* detach */ evbuffer_free(ws->rbuf); evbuffer_free(ws->wbuf); - pool_free_context(ws->ac); if(ws->cmd) { ws->cmd->ac = NULL; /* we've just free'd it */ cmd_free(ws->cmd); @@ -526,6 +529,7 @@ ws_frame_and_send_response(struct ws_client *ws, enum ws_frame_type frame_type, static void ws_close_if_able(struct ws_client *ws) { + ws->close_after_events = 1; /* note that we're closing */ if(ws->scheduled_read || ws->scheduled_write) { return; /* still waiting for these events to trigger */ }