From: Aurelien DARRAGON Date: Thu, 5 Feb 2026 19:36:23 +0000 (+0100) Subject: MINOR: filters: rework RESUME_FILTER_* macros as inline functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e88b219331ab3d8b62b1d244460747fe35abc72d;p=thirdparty%2Fhaproxy.git MINOR: filters: rework RESUME_FILTER_* macros as inline functions There is no need to have those helpers defined as macro, and since it is not mandatory, code maintenance is much easier using functions, thus let's switch to function definitions. Also, we change the way we iterate over the list so that the calling function now has a pseudo API to get and iterate over filter pointers while keeping control on how they implement the iterating logic. One benefit of this is that we will also be able to switch between lists depending on the channel type, which is a prerequisite for upcoming rework that split the filter list over request and response channels (commit will follow) No change of behavior is expected. --- diff --git a/src/filters.c b/src/filters.c index 3288e9afb..3e8db1572 100644 --- a/src/filters.c +++ b/src/filters.c @@ -34,61 +34,75 @@ DECLARE_STATIC_TYPED_POOL(pool_head_filter, "filter", struct filter); static int handle_analyzer_result(struct stream *s, struct channel *chn, unsigned int an_bit, int ret); -/* - RESUME_FILTER_LOOP and RESUME_FILTER_END must always be used together. - * The first one begins a loop and the seconds one ends it. +/* - resume_filter_list_start() and resume_filter_list_next() must always be used together. + * The first one sets the first filter value and the second one allows to get the + * next one until NULL is returned * - * - BREAK_EXECUTION must be used to break the loop and set the filter from - * which to resume the next time. + * - resume_filter_list_break() must be used to break the iteration and set the filter + * from which to resume the next time (that is, resume_filter_list_start() will allow + * to resume from value at the time of the break) * * Here is an example: * - * RESUME_FILTER_LOOP(stream, channel) { - * ... - * if (cond) - * BREAK_EXECUTION(stream, channel, label); - * ... - * } RESUME_FILTER_END; + * struct filter *filter; + * + * for (filter = resume_filter_list_start(stream, channel); filter + * filter = resume_filter_list_next(stream, channel, filter)) { + * ... + * if (cond) { + * resume_filter_list_break(stream, channel, filter, ret); + goto label; + * } + * } * ... * label: * ... * */ -#define RESUME_FILTER_LOOP(strm, chn) \ - do { \ - struct filter *filter; \ - \ - if (strm_flt(strm)->current[CHN_IDX(chn)]) { \ - filter = strm_flt(strm)->current[CHN_IDX(chn)]; \ - strm_flt(strm)->current[CHN_IDX(chn)] = NULL; \ - if (!(chn_prod(chn)->flags & SC_FL_ERROR) && \ - !(chn->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT))) { \ - (strm)->waiting_entity.type = STRM_ENTITY_NONE; \ - (strm)->waiting_entity.ptr = NULL; \ - } \ - goto resume_execution; \ - } \ - \ - list_for_each_entry(filter, &strm_flt(s)->filters, list) { \ - resume_execution: - -#define RESUME_FILTER_END \ - } \ - } while(0) - -#define BREAK_EXECUTION(strm, chn, label) \ - do { \ - if (ret == 0) { \ - s->waiting_entity.type = STRM_ENTITY_FILTER; \ - s->waiting_entity.ptr = filter; \ - } \ - else if (ret < 0) { \ - (strm)->last_entity.type = STRM_ENTITY_FILTER; \ - (strm)->last_entity.ptr = filter; \ - } \ - strm_flt(strm)->current[CHN_IDX(chn)] = filter; \ - goto label; \ - } while (0) +static inline struct filter *resume_filter_list_start(struct stream *strm, struct channel *chn) +{ + struct filter *filter; + + if (strm_flt(strm)->current[CHN_IDX(chn)]) { + filter = strm_flt(strm)->current[CHN_IDX(chn)]; + strm_flt(strm)->current[CHN_IDX(chn)] = NULL; + if (!(chn_prod(chn)->flags & SC_FL_ERROR) && + !(chn->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT))) { + (strm)->waiting_entity.type = STRM_ENTITY_NONE; + (strm)->waiting_entity.ptr = NULL; + } + } + else { + filter = LIST_NEXT(&strm_flt(strm)->filters, struct filter *, list); + if (&filter->list == &strm_flt(strm)->filters) + filter = NULL; /* empty list */ + } + return filter; +} + +static inline struct filter *resume_filter_list_next(struct stream *strm, struct channel *chn, + struct filter *filter) +{ + filter = LIST_NEXT(&filter->list, struct filter *, list); + if (&filter->list == &strm_flt(strm)->filters) + filter = NULL; /* end of list */ + return filter; +} + +static inline void resume_filter_list_break(struct stream *strm, struct channel *chn, + struct filter *filter, int ret) +{ + if (ret == 0) { + strm->waiting_entity.type = STRM_ENTITY_FILTER; + strm->waiting_entity.ptr = filter; + } + else if (ret < 0) { + strm->last_entity.type = STRM_ENTITY_FILTER; + strm->last_entity.ptr = filter; + } + strm_flt(strm)->current[CHN_IDX(chn)] = filter; +} /* List head of all known filter keywords */ static struct flt_kw_list flt_keywords = { @@ -599,12 +613,14 @@ flt_set_stream_backend(struct stream *s, struct proxy *be) int flt_http_end(struct stream *s, struct http_msg *msg) { + struct filter *filter; unsigned long long *strm_off = &FLT_STRM_OFF(s, msg->chn); unsigned int offset = 0; int ret = 1; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg); - RESUME_FILTER_LOOP(s, msg->chn) { + for (filter = resume_filter_list_start(s, msg->chn); filter; + filter = resume_filter_list_next(s, msg->chn, filter)) { unsigned long long flt_off = FLT_OFF(filter, msg->chn); offset = flt_off - *strm_off; @@ -618,10 +634,12 @@ flt_http_end(struct stream *s, struct http_msg *msg) DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s); filter->calls++; ret = FLT_OPS(filter)->http_end(s, filter, msg); - if (ret <= 0) - BREAK_EXECUTION(s, msg->chn, end); + if (ret <= 0) { + resume_filter_list_break(s, msg->chn, filter, ret); + goto end; + } } - } RESUME_FILTER_END; + } c_adv(msg->chn, offset); *strm_off += offset; @@ -750,6 +768,7 @@ flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len) int flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) { + struct filter *filter; int ret = 1; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_FLT_ANA, s); @@ -761,7 +780,8 @@ flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) chn->flags |= CF_FLT_ANALYZE; chn->analysers |= ((chn->flags & CF_ISRESP) ? AN_RES_FLT_END : AN_REQ_FLT_END); - RESUME_FILTER_LOOP(s, chn) { + for (filter = resume_filter_list_start(s, chn); filter; + filter = resume_filter_list_next(s, chn, filter)) { if (!(chn->flags & CF_ISRESP)) { if (an_bit == AN_REQ_FLT_START_BE && !(filter->flags & FLT_FL_IS_BACKEND_FILTER)) @@ -778,10 +798,12 @@ flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s); filter->calls++; ret = FLT_OPS(filter)->channel_start_analyze(s, filter, chn); - if (ret <= 0) - BREAK_EXECUTION(s, chn, end); + if (ret <= 0) { + resume_filter_list_break(s, chn, filter, ret); + goto end; + } } - } RESUME_FILTER_END; + } end: ret = handle_analyzer_result(s, chn, an_bit, ret); @@ -802,20 +824,24 @@ flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) int flt_pre_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) { + struct filter *filter; int ret = 1; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_FLT_ANA, s); - RESUME_FILTER_LOOP(s, chn) { + for (filter = resume_filter_list_start(s, chn); filter; + filter = resume_filter_list_next(s, chn, filter)) { if (FLT_OPS(filter)->channel_pre_analyze && (filter->pre_analyzers & an_bit)) { DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s); filter->calls++; ret = FLT_OPS(filter)->channel_pre_analyze(s, filter, chn, an_bit); - if (ret <= 0) - BREAK_EXECUTION(s, chn, check_result); + if (ret <= 0) { + resume_filter_list_break(s, chn, filter, ret); + goto check_result; + } filter->pre_analyzers &= ~an_bit; } - } RESUME_FILTER_END; + } check_result: ret = handle_analyzer_result(s, chn, 0, ret); @@ -867,20 +893,24 @@ int flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit) { struct http_msg *msg; + struct filter *filter; int ret = 1; msg = ((chn->flags & CF_ISRESP) ? &s->txn->rsp : &s->txn->req); DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg); - RESUME_FILTER_LOOP(s, chn) { + for (filter = resume_filter_list_start(s, chn); filter; + filter = resume_filter_list_next(s, chn, filter)) { if (FLT_OPS(filter)->http_headers) { DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s); filter->calls++; ret = FLT_OPS(filter)->http_headers(s, filter, msg); - if (ret <= 0) - BREAK_EXECUTION(s, chn, check_result); + if (ret <= 0) { + resume_filter_list_break(s, chn, filter, ret); + goto check_result; + } } - } RESUME_FILTER_END; + } if (HAS_DATA_FILTERS(s, chn)) { size_t data = http_get_hdrs_size(htxbuf(&chn->buf)); @@ -907,6 +937,7 @@ int flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) { int ret = 1; + struct filter *filter; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_FLT_ANA, s); @@ -915,7 +946,8 @@ flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) if (!(chn->flags & CF_FLT_ANALYZE)) goto sync; - RESUME_FILTER_LOOP(s, chn) { + for (filter = resume_filter_list_start(s, chn); filter; + filter = resume_filter_list_next(s, chn, filter)) { FLT_OFF(filter, chn) = 0; unregister_data_filter(s, chn, filter); @@ -923,10 +955,12 @@ flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s); filter->calls++; ret = FLT_OPS(filter)->channel_end_analyze(s, filter, chn); - if (ret <= 0) - BREAK_EXECUTION(s, chn, end); + if (ret <= 0) { + resume_filter_list_break(s, chn, filter, ret); + goto end; + } } - } RESUME_FILTER_END; + } end: /* We don't remove yet this analyzer because we need to synchronize the