]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: Don't add private connections in available connection list
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 1 Jul 2020 13:45:41 +0000 (15:45 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 15 Jul 2020 12:08:14 +0000 (14:08 +0200)
When a stream is detached from a backend private connection, we must not insert
it in the available connection list. In addition, we must be sure to remove it
from this list. To ensure it is properly performed, this part has been slightly
refactored to clearly split processing of private connections from the others.

This patch should probably be backported to 2.2.

src/mux_h2.c

index 6ec8d27cabe9a0b7d926f28e63d2af91c2401c37..fc35c66a272fdf73cf2cf02b88d0edea356c52b9 100644 (file)
@@ -3945,25 +3945,32 @@ static void h2_detach(struct conn_stream *cs)
                        /* Never ever allow to reuse a connection from a non-reuse backend */
                        if ((h2c->proxy->options & PR_O_REUSE_MASK) == PR_O_REUSE_NEVR)
                                h2c->conn->flags |= CO_FL_PRIVATE;
-                       if (!h2c->conn->owner && (h2c->conn->flags & CO_FL_PRIVATE)) {
-                               h2c->conn->owner = sess;
-                               if (!session_add_conn(sess, h2c->conn, h2c->conn->target)) {
-                                       h2c->conn->owner = NULL;
-                                       if (eb_is_empty(&h2c->streams_by_id)) {
-                                               h2c->conn->mux->destroy(h2c);
-                                               TRACE_DEVEL("leaving on error after killing outgoing connection", H2_EV_STRM_END|H2_EV_H2C_ERR);
+                       if (h2c->conn->flags & CO_FL_PRIVATE) {
+                               if (!h2c->conn->owner) {
+                                       h2c->conn->owner = sess;
+                                       if (!session_add_conn(sess, h2c->conn, h2c->conn->target)) {
+                                               h2c->conn->owner = NULL;
+                                               if (eb_is_empty(&h2c->streams_by_id)) {
+                                                       h2c->conn->mux->destroy(h2c);
+                                                       TRACE_DEVEL("leaving on error after killing outgoing connection", H2_EV_STRM_END|H2_EV_H2C_ERR);
+                                                       return;
+                                               }
+                                       }
+                               }
+                               if (eb_is_empty(&h2c->streams_by_id) && h2c->conn->owner == sess) {
+                                       if (session_check_idle_conn(h2c->conn->owner, h2c->conn) != 0) {
+                                               /* At this point either the connection is destroyed, or it's been added to the server idle list, just stop */
+                                               TRACE_DEVEL("leaving without reusable idle connection", H2_EV_STRM_END);
                                                return;
                                        }
                                }
+
+                               /* Be sure to remove the connection from the available_conns list */
+                               if (!MT_LIST_ISEMPTY(&h2c->conn->list))
+                                       MT_LIST_DEL(&h2c->conn->list);
                        }
-                       if (eb_is_empty(&h2c->streams_by_id)) {
-                               if (sess && h2c->conn->owner == sess &&
-                                   session_check_idle_conn(h2c->conn->owner, h2c->conn) != 0) {
-                                       /* At this point either the connection is destroyed, or it's been added to the server idle list, just stop */
-                                       TRACE_DEVEL("leaving without reusable idle connection", H2_EV_STRM_END);
-                                       return;
-                               }
-                               if (!(h2c->conn->flags & CO_FL_PRIVATE)) {
+                       else {
+                               if (eb_is_empty(&h2c->streams_by_id)) {
                                        if (!srv_add_to_idle_list(objt_server(h2c->conn->target), h2c->conn, 1)) {
                                                /* The server doesn't want it, let's kill the connection right away */
                                                h2c->conn->mux->destroy(h2c);
@@ -3978,9 +3985,10 @@ static void h2_detach(struct conn_stream *cs)
                                        return;
 
                                }
-                       } else if (MT_LIST_ISEMPTY(&h2c->conn->list) &&
-                                  h2_avail_streams(h2c->conn) > 0 && objt_server(h2c->conn->target)) {
-                               LIST_ADD(&__objt_server(h2c->conn->target)->available_conns[tid], mt_list_to_list(&h2c->conn->list));
+                               else if (MT_LIST_ISEMPTY(&h2c->conn->list) &&
+                                        h2_avail_streams(h2c->conn) > 0 && objt_server(h2c->conn->target)) {
+                                       LIST_ADD(&__objt_server(h2c->conn->target)->available_conns[tid], mt_list_to_list(&h2c->conn->list));
+                               }
                        }
                }
        }