summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faulet <cfaulet@haproxy.com>2021-11-15 14:51:37 +0100
committerChristopher Faulet <cfaulet@haproxy.com>2021-11-15 15:03:21 +0100
commit7530830414d5b92a31cb327201f9bc4d50a6ea64 (patch)
tree662592e612bc1ae6eb071a635d8ea04005fd30e7
parent1ccbe12f4a6af471bdbc8b85f98eb16ae3e4a626 (diff)
downloadhaproxy-7530830414d5b92a31cb327201f9bc4d50a6ea64.tar.gz
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.
-rw-r--r--src/mux_h1.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 104b97f8f..5c36d58ec 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -54,7 +54,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 */
@@ -2807,11 +2807,19 @@ static int h1_process(struct h1c * h1c)
}
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_parsing_error(h1c))
h1_send(h1c);
h1c->flags = (h1c->flags & ~(H1C_F_ST_IDLE|H1C_F_WAIT_NEXT_REQ)) | H1C_F_ST_ERROR;