From: Christopher Faulet Date: Wed, 30 Sep 2026 16:10:22 +0000 (+0200) Subject: MINOR: filters: Mirror implicit filters as filter instances X-Git-Tag: v3.5-dev9~86 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=d390381b53c3d6e7928848790e36e9b302c25a3e;p=haproxy.git MINOR: filters: Mirror implicit filters as filter instances Add a helper to record an enabled implicit instance without replacing an existing instance of the same class and id. Copy its raw arguments and source location, and mark it as implicit so an explicit declaration can replace it. Create these instances alongside legacy filters for cache rules, use-fcgi-app, and implicit compression/decompression. Cache and FCGI use the cache/application name as the id; compression and decompression need none. Allow the legacy FCGI configuration and a instance to refer to the same application even though their configuration pointers differ. Legacy filters are deliberately retained: reconciling the two models and selecting which one is attached to streams remain unfinished. --- diff --git a/include/haproxy/filters.h b/include/haproxy/filters.h index 707561b9f..3355b2c93 100644 --- a/include/haproxy/filters.h +++ b/include/haproxy/filters.h @@ -153,6 +153,8 @@ int flt_check(struct proxy *p); int flt_copy_instances(struct proxy *px, const struct proxy *defpx); void flt_free_instances(struct proxy *px); int flt_init_class_refs(struct proxy *px); +int flt_add_implicit_instance(struct proxy *px, struct filter_class *cls, const char *id, + char **args, const char *file, int line); struct filter_instance *flt_find_instance(struct proxy *px, struct filter_class *cls, const char *id); int flt_stream_start(struct stream *s); diff --git a/src/cache.c b/src/cache.c index aeb17735f..cf672ac78 100644 --- a/src/cache.c +++ b/src/cache.c @@ -2320,6 +2320,7 @@ static void http_cache_io_handler(struct appctx *appctx) static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_rule *rule, char **err) { + struct filter_class *cls; struct flt_conf *fconf; struct cache_flt_conf *cconf = NULL; @@ -2362,6 +2363,19 @@ static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_ru fconf->id = cache_store_flt_id; fconf->conf = cconf; fconf->ops = &cache_ops; + + /* also create the corresponding implicit filter instance. The cache + * name is used as the instance id, there is no argument. + */ + cls = filter_find_class(cache_store_filter_cls_name); + if (!cls || flt_add_implicit_instance(proxy, cls, name, NULL, + rule->conf.file ? rule->conf.file : proxy->conf.file, + rule->conf.file ? rule->conf.line : proxy->conf.line) < 0) { + memprintf(err, "out of memory\n"); + free(fconf); + goto err; + } + LIST_APPEND(&proxy->filter_configs, &fconf->list); rule->arg.act.p[0] = cconf; diff --git a/src/fcgi-app.c b/src/fcgi-app.c index a9fb115b7..050857a7d 100644 --- a/src/fcgi-app.c +++ b/src/fcgi-app.c @@ -239,7 +239,9 @@ static int fcgi_flt_check(struct proxy *px, struct flt_conf *fconf) if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id || f->id == cache_store_flt_id) continue; - else if ((f->id == fconf->id) && f->conf != fcgi_conf) { + else if ((f->id == fconf->id) && f->conf != fcgi_conf && + strcmp(((struct fcgi_flt_conf *)f->conf)->name, fcgi_conf->name) != 0) { + /* another fcgi filter with a different app */ ha_alert("proxy '%s' : only one fcgi-app supported per backend.\n", px->id); goto err; @@ -614,6 +616,7 @@ static int proxy_parse_use_fcgi_app(char **args, int section, struct proxy *curp const struct proxy *defpx, const char *file, int line, char **err) { + struct filter_class *cls; struct flt_conf *fconf = NULL; struct fcgi_flt_conf *fcgi_conf = NULL; int retval = 0; @@ -661,6 +664,16 @@ static int proxy_parse_use_fcgi_app(char **args, int section, struct proxy *curp fconf->id = fcgi_flt_id; fconf->conf = fcgi_conf; fconf->ops = &fcgi_flt_ops; + + /* also create the corresponding implicit filter instance. The + * fcgi-app name is used as the instance id, there is no argument. + */ + cls = filter_find_class(fcgi_filter_cls_name); + if (!cls || flt_add_implicit_instance(curpx, cls, args[1], NULL, file, line) < 0) { + free(fconf); + goto err; + } + LIST_APPEND(&curpx->filter_configs, &fconf->list); end: diff --git a/src/filters.c b/src/filters.c index 2e1a7d1da..376f24c09 100644 --- a/src/filters.c +++ b/src/filters.c @@ -1713,7 +1713,7 @@ void flt_free_instances(struct proxy *px) * proxy , so that proxies inherit the filter instances of their * defaults section. It must be called before any instance is added to , * so that locally defined ones can replace the inherited ones. - * Returns 0 on success, -1 on error (out of memory). + * Returns 0 on success, -1 on error. */ static int flt_copy_instance(struct proxy *px, const struct filter_instance *inst) { @@ -1829,6 +1829,70 @@ int flt_copy_instances(struct proxy *px, const struct proxy *defpx) return -1; } +/* Adds an implicit filter instance for the class to the proxy , + * with the id (may be NULL) and the arguments (terminated by an + * empty string). It is used when a filter is implicitly configured by + * another directive (e.g. with the cache-store action). The instance is + * marked with FLT_INST_F_IMPLICIT and is enabled, since the directive + * implies the filter usage. + * + * If a instance with the same class and id already exists, nothing is + * done: an explicit declaration always wins over an implicit one, and the + * first implicit declaration wins. Returns 0 on success, -1 on error (out + * of memory). + */ +int flt_add_implicit_instance(struct proxy *px, struct filter_class *cls, const char *id, + char **args, const char *file, int line) +{ + struct filter_instance *inst; + int argc = 0; + int i; + + /* a instance already exists for this class and id: explicit or + * implicit, it wins over a new implicit one. + */ + if (flt_find_instance(px, cls, id)) + return 0; + + inst = calloc(1, sizeof(*inst)); + if (!inst) + return -1; + + inst->class = cls; + inst->enabled = 1; /* the directive implies the filter usage */ + inst->flags = FLT_INST_F_IMPLICIT; + + if (id) { + inst->id = strdup(id); + if (!inst->id) + goto error; + } + inst->conf.file = strdup(file); + if (!inst->conf.file) + goto error; + inst->conf.line = line; + + for (argc = 0; args && *args[argc]; argc++) + ; + inst->conf.argc = argc; + inst->conf.argv = calloc(argc + 1, sizeof(*inst->conf.argv)); + if (!inst->conf.argv) + goto error; + for (i = 0; i < argc; i++) { + inst->conf.argv[i] = strdup(args[i]); + if (!inst->conf.argv[i]) + goto error; + } + + if (flt_init_instance(inst, px) < 0) + goto error; + return 0; + + error: + flt_free_instance(inst); + return -1; +} + /* * Parses the "filter-config" keyword. A filter instance is created for the * given filter class and attached to the current proxy. The instance diff --git a/src/flt_decomp.c b/src/flt_decomp.c index 0f0af55e2..1a6c5f45d 100644 --- a/src/flt_decomp.c +++ b/src/flt_decomp.c @@ -1164,6 +1164,28 @@ parse_decompression_options(char **args, int section, struct proxy *proxy, goto end; } + if (decomp->req.algos) { + struct filter_class *cls; + + cls = filter_find_class(decomp_req_filter_cls_name); + if (!cls || flt_add_implicit_instance(proxy, cls, NULL, NULL, file, line) < 0) { + memprintf(err, "'%s' : out of memory.", args[0]); + ret = -1; + goto end; + } + } + + if (decomp->res.algos) { + struct filter_class *cls; + + cls = filter_find_class(decomp_res_filter_cls_name); + if (!cls || flt_add_implicit_instance(proxy, cls, NULL, NULL, file, line) < 0) { + memprintf(err, "'%s' : out of memory.", args[0]); + ret = -1; + goto end; + } + } + end: return ret; } @@ -1321,6 +1343,7 @@ int decomp_res_flt_parse_instance(char **args, struct proxy *px, struct filter_i int check_implicit_decomp_flt(struct proxy *proxy) { + struct filter_class *cls; struct flt_conf *fconf; struct flt_conf *fconf_req = NULL; struct flt_conf *fconf_res = NULL; diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c index 299f7ba59..7364bed69 100644 --- a/src/flt_http_comp.c +++ b/src/flt_http_comp.c @@ -1035,6 +1035,34 @@ parse_compression_options(char **args, int section, struct proxy *proxy, goto end; } + if (comp->flags & COMP_FL_DIR_REQ) { + struct filter_class *cls; + + /* also create the corresponding implicit filter instance. + * There is no id nor argument. + */ + cls = filter_find_class(http_comp_req_filter_cls_name); + if (!cls || flt_add_implicit_instance(proxy, cls, NULL, NULL, file, line) < 0) { + memprintf(err, "'%s' : out of memory.", args[0]); + ret = -1; + goto end; + } + } + + if (comp->flags & COMP_FL_DIR_RES) { + struct filter_class *cls; + + /* also create the corresponding implicit filter instance. + * There is no id nor argument. + */ + cls = filter_find_class(http_comp_res_filter_cls_name); + if (!cls || flt_add_implicit_instance(proxy, cls, NULL, NULL, file, line) < 0) { + memprintf(err, "'%s' : out of memory.", args[0]); + ret = -1; + goto end; + } + } + end: return ret; }