From: Christopher Faulet Date: Fri, 24 Mar 2023 08:26:16 +0000 (+0100) Subject: BUG/MEDIUM: mux-h1: Wakeup H1C on shutw if there is no I/O subscription X-Git-Tag: v2.8-dev6~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=551b89677249b2107a6e4c40a0b61d01c9da6831;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: mux-h1: Wakeup H1C on shutw if there is no I/O subscription This old bug was revealed because of the commit 407210a34 ("BUG/MEDIUM: stconn: Don't rearm the read expiration date if EOI was reached"). But it is still possible to hit it if there is no server timeout. At first glance, the 2.8 is not affected. But the fix remains valid. When a shutdown for writes if performed the H1 connection must be notified to be released. If it is subscribed for any I/O events, it is not an issue. But, if there is no subscription, no I/O event is reported to the H1 connection and it remains alive. If the message was already fully received, nothing more happens. On my side, I was able to trigger the bug by freezing the session. Some users reported a spinning loop on process_stream(). Not sure how to trigger the loop. To freeze the session, the client timeout must be reached while the server response was already fully received. On old version (< 2.6), it only happens if there is no server timeout. To fix the issue, we must wake up the H1 connection on shutdown for writes if there is no I/O subscription. This patch must be backported as far as 2.0. It should fix the issue #2090 and #2088. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 20f7a1239b..e277e8f787 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -1047,8 +1047,10 @@ static void h1_release(struct h1c *h1c) h1c->task = NULL; } - if (h1c->wait_event.tasklet) + if (h1c->wait_event.tasklet) { tasklet_free(h1c->wait_event.tasklet); + h1c->wait_event.tasklet = NULL; + } h1s_destroy(h1c->h1s); if (conn) { @@ -3590,6 +3592,10 @@ static void h1_shutw_conn(struct connection *conn) conn_xprt_shutw(conn); conn_sock_shutw(conn, !(h1c->flags & H1C_F_SILENT_SHUT)); + + if (h1c->wait_event.tasklet && !h1c->wait_event.events) + tasklet_wakeup(h1c->wait_event.tasklet); + TRACE_LEAVE(H1_EV_H1C_END, conn); }