]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: filters: Mirror implicit filters as filter instances
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 30 Sep 2026 16:10:22 +0000 (18:10 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 9 Oct 2026 14:17:35 +0000 (16:17 +0200)
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.

include/haproxy/filters.h
src/cache.c
src/fcgi-app.c
src/filters.c
src/flt_decomp.c
src/flt_http_comp.c

index 707561b9f0e98255a7bb4c2e4755b70fb1bcb7aa..3355b2c93549fc5d189af262ab4495c16ebaf1a7 100644 (file)
@@ -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);
index aeb17735f2deb079f7dc87debb8a83c257bc52b4..cf672ac78dcbfdd5ae6cd0f57e34fe15601f8532 100644 (file)
@@ -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;
index a9fb115b725f9d5718ff7a0065a0386ae2a5ca15..050857a7d03bcbe62a4aac35f1fe6832b396ace5 100644 (file)
@@ -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:
index 2e1a7d1daec70212f54355f548dc200699a3228a..376f24c09e6672b2f46e068583a73a4c4e619e82 100644 (file)
@@ -1713,7 +1713,7 @@ void flt_free_instances(struct proxy *px)
  * proxy <px>, so that proxies inherit the filter instances of their
  * defaults section. It must be called before any instance is added to <px>,
  * 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 <cls> to the proxy <px>,
+ * with the id <id> (may be NULL) and the arguments <args> (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
index 0f0af55e2e774a58c755c0cb54d17642fdbe34bd..1a6c5f45df32dfd8161c4248f764d30c637a8991 100644 (file)
@@ -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;
index 299f7ba59f7ef90ee8b9f9bb852566feefd603f4..7364bed69b830c7e20f10a702b031dc1921442ba 100644 (file)
@@ -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;
 }