From: Christopher Faulet Date: Wed, 30 Sep 2026 16:10:21 +0000 (+0200) Subject: MINOR: filters: Inherit filter instances from defaults sections X-Git-Tag: v3.5-dev9~91 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=1530d03c5450ab3a2ba63c0c657506e02adc31e5;p=haproxy.git MINOR: filters: Inherit filter instances from defaults sections Deep-copy raw filter instances when a proxy references its defaults section, before parsing the proxy's own directives. Preserve the class, identifier, enabled state and source location, while marking the copy as inherited so a later local declaration can replace it. Add the helper that links a instance to its proxy's class references. Copies own their arguments and are released independently of the defaults proxy. On inheritance failure, release the partially copied instances. --- diff --git a/include/haproxy/filters.h b/include/haproxy/filters.h index 6b6b7bb79..69808e271 100644 --- a/include/haproxy/filters.h +++ b/include/haproxy/filters.h @@ -129,6 +129,7 @@ extern struct filter_class flt_fcgi_cls; void flt_deinit(struct proxy *p); 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); struct filter_instance *flt_find_instance(struct proxy *px, struct filter_class *cls, const char *id); diff --git a/src/filters.c b/src/filters.c index 4adcafbca..a56c5c0d6 100644 --- a/src/filters.c +++ b/src/filters.c @@ -1376,6 +1376,23 @@ static int flt_foreach_instance_side(struct proxy *px, unsigned int side, return 0; } +/* Finds the class reference of the class in the proxy for side + * . + * Returns the class reference, or NULL if not found for the given side. + */ +static struct filter_class_ref *flt_get_class_ref(struct proxy *px, struct filter_class *cls, + unsigned int side) +{ + struct list *refs = (side == FLT_SIDE_REQ ? &px->conf.filter_classes_req : &px->conf.filter_classes_res); + struct filter_class_ref *ref; + + list_for_each_entry(ref, refs, list) { + if (ref->class == cls) + return ref; + } + return NULL; +} + /* Context for flt_match_instance_cb() */ struct flt_match_instance_ctx { struct filter_class *cls; /* the class to match */ @@ -1450,6 +1467,41 @@ struct filter_instance *flt_find_instance(struct proxy *px, struct filter_class } +/* Initializes the lists of the filter instance and links it in the + * class references of the proxy , on each side the class is placed on. + * Returns 0 on success, -1 if the class is placed on no side (the + * instance cannot be evaluated). + */ +static int flt_init_instance(struct filter_instance *inst, struct proxy *px) +{ + struct filter_class_ref *ref; + int linked = 0; + + inst->px = px; + LIST_INIT(&inst->req.reordered_before); + LIST_INIT(&inst->req.reordered_after); + LIST_INIT(&inst->req.list); + LIST_INIT(&inst->res.reordered_before); + LIST_INIT(&inst->res.reordered_after); + LIST_INIT(&inst->res.list); + + if (LIST_INLIST(&inst->class->req.list)) { + ref = flt_get_class_ref(px, inst->class, FLT_SIDE_REQ); + if (!ref) + return -1; + LIST_APPEND(&ref->instances, &inst->req.list); + linked = 1; + } + if (LIST_INLIST(&inst->class->res.list)) { + ref = flt_get_class_ref(px, inst->class, FLT_SIDE_RES); + if (!ref) + return -1; + LIST_APPEND(&ref->instances, &inst->res.list); + linked = 1; + } + return linked ? 0 : -1; +} + /* Frees all filter instances of the proxy , its filter class * references, its filter-enable entries and its filter sequences. */ @@ -1476,6 +1528,86 @@ void flt_free_instances(struct proxy *px) } +/* Deep-copies the filter instances of the defaults proxy into the + * 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). + */ +static int flt_copy_instance(struct proxy *px, const struct filter_instance *inst) +{ + struct filter_instance *new_inst; + int i; + + new_inst = calloc(1, sizeof(*new_inst)); + if (!new_inst) + return -1; + + new_inst->class = inst->class; + new_inst->enabled = inst->enabled; + new_inst->flags = inst->flags | FLT_INST_F_INHERITED; + + if (inst->id) { + new_inst->id = strdup(inst->id); + if (!new_inst->id) + goto error; + } + new_inst->conf.file = strdup(inst->conf.file); + if (!new_inst->conf.file) + goto error; + new_inst->conf.line = inst->conf.line; + new_inst->conf.argc = inst->conf.argc; + new_inst->conf.argv = calloc(inst->conf.argc + 1, sizeof(*new_inst->conf.argv)); + if (!new_inst->conf.argv) + goto error; + for (i = 0; i < inst->conf.argc; i++) { + new_inst->conf.argv[i] = strdup(inst->conf.argv[i]); + if (!new_inst->conf.argv[i]) + goto error; + } + + if (flt_init_instance(new_inst, px) < 0) + goto error; + return 0; + + error: + flt_free_instance(new_inst); + return -1; +} + +/* Copy all filter deinitions of the defaults proxy into the proxy . + * Returns 0 on success, -1 on error (out of memory). + */ +int flt_copy_instances(struct proxy *px, const struct proxy *defpx) +{ + struct filter_class_ref *ref; + struct filter_instance *inst; + + /* iterate over all the instances of the defaults proxy: the request + * side first, then the instances of the classes with no request side + * from the response side + */ + list_for_each_entry(ref, &defpx->conf.filter_classes_req, list) { + list_for_each_entry(inst, &ref->instances, req.list) + if (flt_copy_instance(px, inst) < 0) + goto error; + } + list_for_each_entry(ref, &defpx->conf.filter_classes_res, list) { + list_for_each_entry(inst, &ref->instances, res.list) { + if (LIST_INLIST(&inst->req.list)) + continue; /* already copied from the request side */ + if (flt_copy_instance(px, inst) < 0) + goto error; + } + } + + return 0; + + error: + flt_free_instances(px); + return -1; +} + /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted, doing so helps diff --git a/src/proxy.c b/src/proxy.c index bb187722b..b5f3388de 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -3161,6 +3161,17 @@ int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg) defaults_px_ref(defpx, px); } + /* The proxy inherits the filter instances of its defaults section. It + * happens before its own directives are parsed, so that locally defined + * ones can replace the inherited ones. + */ + if (flt_copy_instances(px, defpx) < 0) { + memprintf(errmsg, "out of memory while inheriting filter instances from defaults section (at %s:%d)", + defpx->conf.file, defpx->conf.line); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if (defpx->tcpcheck.rs && (defpx->tcpcheck.rs->flags & TCPCHK_RULES_PROTO_CHK) && (px->cap & PR_CAP_LISTEN) == PR_CAP_BE) { /* If the current default proxy defines tcpcheck rules, the