]> git.kaiwu.me - haproxy.git/commitdiff
CLEANUP: cfgparse-listen: move "stick" to its own parser
authorWilly Tarreau <w@1wt.eu>
Thu, 8 Oct 2026 13:53:59 +0000 (15:53 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 9 Oct 2026 08:30:59 +0000 (10:30 +0200)
The stick rules are forbidden in a defaults section. They were moved
to a new proxy_parse_stick() function registered in cfg_kws, making
them discoverable via "-dKcfg".

The code is mostly the same, with error paths reworked to avoid chains of
free()+return calls in error paths.

src/cfgparse-listen.c

index 86f019a06dc1e6e0ed827f4f08ffd0b28948405f..e9aa319f76f5a197d235d084cc0540e61e15ab2d 100644 (file)
@@ -43,7 +43,7 @@ static const char *common_kw_list[] = {
        "listen", "frontend", "backend", "defaults", "server",
        "default-server", "server-template", "bind",
        "cookie", "email-alert",
-       "stick", "stats", "option",
+       "stats", "option",
        NULL /* must be last */
 };
 
@@ -910,126 +910,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                /* Indicate that the email_alert is at least partially configured */
                curproxy->email_alert.flags |= PR_EMAIL_ALERT_SET;
        }/* end else if (!strcmp(args[0], "email-alert"))  */
-       else if (strcmp(args[0], "stick") == 0) {
-               struct sticking_rule *rule;
-               struct sample_expr *expr;
-               int myidx = 0;
-               const char *name = NULL;
-               int flags;
-
-               if (curproxy->cap & PR_CAP_DEF) {
-                       ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
-                       err_code |= ERR_WARN;
-                       goto out;
-               }
-
-               myidx++;
-               if ((strcmp(args[myidx], "store") == 0) ||
-                   (strcmp(args[myidx], "store-request") == 0)) {
-                       myidx++;
-                       flags = STK_IS_STORE;
-               }
-               else if (strcmp(args[myidx], "store-response") == 0) {
-                       myidx++;
-                       flags = STK_IS_STORE | STK_ON_RSP;
-               }
-               else if (strcmp(args[myidx], "match") == 0) {
-                       myidx++;
-                       flags = STK_IS_MATCH;
-               }
-               else if (strcmp(args[myidx], "on") == 0) {
-                       myidx++;
-                       flags = STK_IS_MATCH | STK_IS_STORE;
-               }
-               else {
-                       ha_alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               if (*(args[myidx]) == 0) {
-                       ha_alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               curproxy->conf.args.ctx = ARGC_STK;
-               expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args, NULL);
-               if (!expr) {
-                       ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               if (flags & STK_ON_RSP) {
-                       if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
-                               ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.\n",
-                                        file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               free(expr);
-                               goto out;
-                       }
-               } else {
-                       if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
-                               ha_alert("parsing [%s:%d] : '%s': fetch method '%s' extracts information from '%s', none of which is available during request.\n",
-                                        file, linenum, args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               free(expr);
-                               goto out;
-                       }
-               }
-
-               /* check if we need to allocate an http_txn struct for HTTP parsing */
-               curproxy->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
-
-               if (strcmp(args[myidx], "table") == 0) {
-                       myidx++;
-                       name = args[myidx++];
-               }
-
-               if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
-                       if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
-                               ha_alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
-                                        file, linenum, args[0], errmsg);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               free(expr);
-                               goto out;
-                       }
-               }
-               else if (*(args[myidx])) {
-                       ha_alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
-                                file, linenum, args[0], args[myidx]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       free(expr);
-                       goto out;
-               }
-               if (flags & STK_ON_RSP)
-                       err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, &errmsg);
-               else
-                       err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
-               if (errmsg)
-                       ha_warning("parsing [%s:%d] : '%s'.\n", file, linenum, errmsg);
-
-               rule = calloc(1, sizeof(*rule));
-               if (!rule) {
-                       free_acl_cond(cond);
-                       goto alloc_error;
-               }
-               rule->cond = cond;
-               rule->expr = expr;
-               rule->flags = flags;
-               rule->table.name = name ? strdup(name) : NULL;
-               LIST_INIT(&rule->list);
-               if (flags & STK_ON_RSP)
-                       LIST_APPEND(&curproxy->storersp_rules, &rule->list);
-               else
-                       LIST_APPEND(&curproxy->sticking_rules, &rule->list);
-       }
        else if (strcmp(args[0], "stats") == 0) {
                if (!(curproxy->cap & PR_CAP_DEF) && curproxy->uri_auth == curr_defproxy->uri_auth) {
                        /* we must detach from the default config */
@@ -3156,6 +3036,125 @@ static int proxy_parse_stick_table(char **args, int section_type, struct proxy *
        return -1;
 }
 
+/* Parses "stick" rules */
+static int proxy_parse_stick(char **args, int section_type, struct proxy *curpx,
+                             const struct proxy *defpx, const char *file, int line,
+                             char **err)
+{
+       struct sample_expr *expr = NULL;
+       struct acl_cond *cond = NULL;
+       struct sticking_rule *rule;
+       const char *name = NULL;
+       char *errmsg = NULL;
+       int myidx = 0;
+       int flags;
+
+       if (curpx->cap & PR_CAP_DEF) {
+               memprintf(err, "'%s' is not supported in 'defaults' section.", args[0]);
+               goto fail;
+       }
+
+       if (warnifnotcap(curpx, PR_CAP_BE, file, line, args[0], NULL))
+               return 0;
+
+       myidx++;
+       if ((strcmp(args[myidx], "store") == 0) ||
+           (strcmp(args[myidx], "store-request") == 0)) {
+               myidx++;
+               flags = STK_IS_STORE;
+       }
+       else if (strcmp(args[myidx], "store-response") == 0) {
+               myidx++;
+               flags = STK_IS_STORE | STK_ON_RSP;
+       }
+       else if (strcmp(args[myidx], "match") == 0) {
+               myidx++;
+               flags = STK_IS_MATCH;
+       }
+       else if (strcmp(args[myidx], "on") == 0) {
+               myidx++;
+               flags = STK_IS_MATCH | STK_IS_STORE;
+       }
+       else {
+               memprintf(err, "'%s' expects 'on', 'match', or 'store'.", args[0]);
+               goto fail;
+       }
+
+       if (*(args[myidx]) == 0) {
+               memprintf(err, "'%s' expects a fetch method.", args[0]);
+               goto fail;
+       }
+
+       curpx->conf.args.ctx = ARGC_STK;
+       expr = sample_parse_expr(args, &myidx, file, line, &errmsg, &curpx->conf.args, NULL);
+       if (!expr) {
+               memprintf(err, "'%s': %s", args[0], errmsg);
+               goto fail;
+       }
+
+       if (flags & STK_ON_RSP) {
+               if (!(expr->fetch->val & SMP_VAL_BE_STO_RUL)) {
+                       memprintf(err, "'%s': fetch method '%s' extracts information from '%s', none of which is available for 'store-response'.",
+                                 args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
+                       goto fail;
+               }
+       } else {
+               if (!(expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
+                       memprintf(err, "'%s': fetch method '%s' extracts information from '%s', none of which is available during request.",
+                                 args[0], expr->fetch->kw, sample_src_names(expr->fetch->use));
+                       goto fail;
+               }
+       }
+
+       /* check if we need to allocate an http_txn struct for HTTP parsing */
+       curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
+
+       if (strcmp(args[myidx], "table") == 0) {
+               myidx++;
+               name = args[myidx++];
+       }
+
+       if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
+               cond = build_acl_cond(file, line, &curpx->acl, curpx, (const char **)args + myidx, &errmsg);
+               if (!cond) {
+                       memprintf(err, "'%s': error detected while parsing sticking condition : %s.",
+                                 args[0], errmsg);
+                       goto fail;
+               }
+       }
+       else if (*(args[myidx])) {
+               memprintf(err, "'%s': unknown keyword '%s'.", args[0], args[myidx]);
+               goto fail;
+       }
+
+       if (warnif_cond_conflicts(cond, (flags & STK_ON_RSP) ? SMP_VAL_BE_STO_RUL : SMP_VAL_BE_SET_SRV, &errmsg))
+               ha_warning("parsing [%s:%d] : '%s'.\n", file, line, errmsg);
+       ha_free(&errmsg);
+
+       rule = calloc(1, sizeof(*rule));
+       if (!rule) {
+               memprintf(err, "out of memory.");
+               goto fail;
+       }
+
+       rule->cond = cond;
+       rule->expr = expr;
+       rule->flags = flags;
+       rule->table.name = name ? strdup(name) : NULL;
+       LIST_INIT(&rule->list);
+       if (flags & STK_ON_RSP)
+               LIST_APPEND(&curpx->storersp_rules, &rule->list);
+       else
+               LIST_APPEND(&curpx->sticking_rules, &rule->list);
+
+       return 0;
+ fail:
+       free(errmsg);
+       free_acl_cond(cond);
+       free(expr);
+       return -1;
+}
+
 static struct cfg_kw_list cfg_kws = {ILH, {
        { CFG_LISTEN, "acl", proxy_parse_acl },
        { CFG_LISTEN, "appsession", proxy_parse_removed_kw },
@@ -3223,6 +3222,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
        { CFG_LISTEN, "server-state-file-name", proxy_parse_be_opts },
        { CFG_LISTEN, "source", proxy_parse_source },
        { CFG_LISTEN, "srvexp", proxy_parse_removed_kw },
+       { CFG_LISTEN, "stick", proxy_parse_stick },
        { CFG_LISTEN, "stick-table", proxy_parse_stick_table },
        { CFG_LISTEN, "transparent", proxy_parse_removed_kw },
        { CFG_LISTEN, "unique-id-format", proxy_parse_logformat },