BUG/MEDIUM: mux-h1: Handle delayed silent shut in h1_process() to release H1C

The commit a85c522d4 ("BUG/MINOR: mux-h1: Save shutdown mode if the shutdown
is delayed") revealed several hidden bugs in connection's shutdown
handling. One of them is about delayed silent shudown.

If outgoing data are not fully sent, we delayed the shutdown. However, in
h1_process(), only normal (or clean) shutdown are really detected. If a
silent (or dirty) shutdown is performed, the H1 connection is not
immediately released. Of course, in this situation, the client never
acknowledged the shutdown. Thus, the H1 connection remains open till the
client timeout.

This patch should fix the issues #1448 and #1453. It must be backported as
far as 2.0.

(cherry picked from commit 7530830414d5b92a31cb327201f9bc4d50a6ea64)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 16aa2ba..3974e53 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -53,7 +53,7 @@
 #define H1C_F_ST_READY       0x00002000 /* Set in ATTACHED state with a READY conn-stream. A conn-stream is not ready when
 					 * a TCP>H1 upgrade is in progress Thus this flag is only set if ATTACHED is also set */
 #define H1C_F_ST_ALIVE       (H1C_F_ST_IDLE|H1C_F_ST_EMBRYONIC|H1C_F_ST_ATTACHED)
-#define H1C_F_ST_SILENT_SHUT 0x00004000 /* silent (or dirty) shutdown must be performed */
+#define H1C_F_ST_SILENT_SHUT 0x00004000 /* silent (or dirty) shutdown must be performed (implied ST_SHUTDOWN) */
 /* 0x00008000 unused */
 
 #define H1C_F_WANT_SPLICE    0x00010000 /* Don't read into a buffer because we want to use or we are using splicing */
@@ -2756,11 +2756,19 @@
 	}
 	h1_send(h1c);
 
-	if ((conn->flags & CO_FL_ERROR) || conn_xprt_read0_pending(conn) || (h1c->flags & H1C_F_ST_ERROR)) {
+	/* H1 connection must be released ASAP if:
+	 *  - an error occurred on the connection or the H1C or
+	 *  - a read0 was received or
+	 *  - a silent shutdown was emitted and all outgoing data sent
+	 */
+	if ((conn->flags & CO_FL_ERROR) ||
+	    conn_xprt_read0_pending(conn) ||
+	    (h1c->flags & H1C_F_ST_ERROR) ||
+	    ((h1c->flags & H1C_F_ST_SILENT_SHUT) && !b_data(&h1c->obuf))) {
 		if (!(h1c->flags & H1C_F_ST_READY)) {
 			/* No conn-stream or not ready */
 			/* shutdown for reads and error on the frontend connection: Send an error */
-			if (!(h1c->flags & (H1C_F_IS_BACK|H1C_F_ST_ERROR))) {
+			if (!(h1c->flags & (H1C_F_IS_BACK|H1C_F_ST_ERROR|H1C_F_ST_SHUTDOWN))) {
 				if (h1_handle_bad_req(h1c))
 					h1_send(h1c);
 				h1c->flags = (h1c->flags & ~(H1C_F_ST_IDLE|H1C_F_WAIT_NEXT_REQ)) | H1C_F_ST_ERROR;