From: Willy Tarreau Date: Thu, 8 Oct 2026 13:53:59 +0000 (+0200) Subject: CLEANUP: cfgparse-listen: move "stick" to its own parser X-Git-Tag: v3.5-dev9~118 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=0ac9feb5a3de9f9af206434abab34e42b10da3d6;p=haproxy.git CLEANUP: cfgparse-listen: move "stick" to its own parser 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. --- diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 86f019a06..e9aa319f7 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -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 },