]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stream: refactor switching-rules processing
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 8 Jan 2026 14:01:55 +0000 (15:01 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 15 Jan 2026 08:08:18 +0000 (09:08 +0100)
This commit rewrites process_switching_rules() function. The objective
is to simplify backend selection so that a single unified
stream_set_backend() call is kept, both for regular and default backends
case.

This patch will be useful to add new capabilities on backends, in the
context of dynamic backend support implementation.

src/stream.c

index 6daffdd947805c3c69cd0b8b7580dd60918061b7..8941b1e19cc2b48a23f2240db73b7cce2a7d1e22 100644 (file)
@@ -1125,9 +1125,11 @@ enum act_return process_use_service(struct act_rule *rule, struct proxy *px,
  */
 static int process_switching_rules(struct stream *s, struct channel *req, int an_bit)
 {
+       struct switching_rule *rule;
        struct persist_rule *prst_rule;
        struct session *sess = s->sess;
        struct proxy *fe = sess->fe;
+       struct proxy *backend = NULL;
 
        req->analysers &= ~an_bit;
        req->analyse_exp = TICK_ETERNITY;
@@ -1136,19 +1138,10 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
 
        /* now check whether we have some switching rules for this request */
        if (!(s->flags & SF_BE_ASSIGNED)) {
-               struct switching_rule *rule;
-
                list_for_each_entry(rule, &fe->switching_rules, list) {
-                       struct proxy *backend = NULL;
-
                        if (!acl_match_cond(rule->cond, fe, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL))
                                continue;
 
-                       /* If the backend name is dynamic, try to resolve the name.
-                        * If we can't resolve the name, or if any error occurs, break
-                        * the loop and fallback to the default backend.
-                        */
-
                        if (rule->dynamic) {
                                struct buffer *tmp;
 
@@ -1161,36 +1154,35 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
 
                                free_trash_chunk(tmp);
                                tmp = NULL;
-
-                               if (!backend)
-                                       break;
                        }
-                       else
+                       else {
                                backend = rule->be.backend;
+                       }
 
-                       if (!stream_set_backend(s, backend))
-                               goto sw_failed;
+                       /* Break the loop at the first matching rule found. If
+                        * the dynamic name resolution has fail, fallback will
+                        * be performed on the default backend.
+                        */
                        break;
                }
 
                /* To ensure correct connection accounting on the backend, we
-                * have to assign one if it was not set (eg: a listen). This
-                * measure also takes care of correctly setting the default
-                * backend if any. Don't do anything if an upgrade is already in
-                * progress.
+                * have to assign one if it was not set. Default backend may be
+                * used if set, else it will stay on the current proxy. Also,
+                * don't do anything if an upgrade is already in progress.
                 */
-               if (!(s->flags & (SF_BE_ASSIGNED|SF_IGNORE)))
-                       if (!stream_set_backend(s, fe->defbe.be ? fe->defbe.be : s->be))
-                               goto sw_failed;
+               if (!backend) {
+                       if ((s->flags & SF_IGNORE)) {
+                               /* TCP stream upgrade to HTTP/2. */
+                               DBG_TRACE_DEVEL("leaving with no backend because of a destructive upgrade", STRM_EV_STRM_ANA, s);
+                               return 0;
+                       }
 
-               /* No backend assigned but no error reported. It happens when a
-                * TCP stream is upgraded to HTTP/2.
-                */
-               if ((s->flags & (SF_BE_ASSIGNED|SF_IGNORE)) == SF_IGNORE) {
-                       DBG_TRACE_DEVEL("leaving with no backend because of a destructive upgrade", STRM_EV_STRM_ANA, s);
-                       return 0;
+                       backend = fe->defbe.be ? fe->defbe.be : s->be;
                }
 
+               if (!stream_set_backend(s, backend))
+                       goto sw_failed;
        }
 
        /* Se the max connection retries for the stream. may be overwritten later */