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.

(cherry picked from commit 551b89677249b2107a6e4c40a0b61d01c9da6831)
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
(cherry picked from commit 3c9806b04c8bfb64d8febf982b1942007c18b02e)
 [ad: adjusted context]
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
(cherry picked from commit 668890b8618c50632738309f85f34295677c7bf3)
[cf: context adjustment]
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit ea9b08d82c7d958a1b0bde14876d0bde0c622461)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 739148e..1324c20 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -935,8 +935,10 @@
 			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) {
@@ -3340,6 +3342,10 @@
 	TRACE_ENTER(H1_EV_H1C_END, conn);
 	conn_xprt_shutw(conn);
 	conn_sock_shutw(conn, (h1c && !(h1c->flags & H1C_F_ST_SILENT_SHUT)));
+
+	if (h1c->wait_event.tasklet && !h1c->wait_event.events)
+		tasklet_wakeup(h1c->wait_event.tasklet);
+
 	TRACE_LEAVE(H1_EV_H1C_END, conn);
 }