diff --git a/include/haproxy/filters.h b/include/haproxy/filters.h index 4a32c21cc..6a3a7e35b 100644 --- a/include/haproxy/filters.h +++ b/include/haproxy/filters.h @@ -165,6 +165,44 @@ unregister_data_filter(struct stream *s, struct channel *chn, struct filter *fil } } +/* + * flt_list_start() and flt_list_next() can be used to iterate over the list of filters + * for a given and combination. It will automatically choose the proper + * list to iterate from depending on the context. + * + * flt_list_start() has to be called exactly once to get the first value from the list + * to get the following values, use flt_list_next() until NULL is returned. + * + * Example: + * + * struct filter *filter; + * + * for (filter = flt_list_start(stream, channel); filter; + * filter = flt_list_next(stream, channel, filter)) { + * ... + * } + */ +static inline struct filter *flt_list_start(struct stream *strm, struct channel *chn) +{ + struct filter *filter; + + 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 *flt_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; +} + /* This function must be called when a filter alter payload data. It updates * offsets of all previous filters. Do not call this function when a filter * change the size of payload data leads to an undefined behavior. @@ -177,7 +215,8 @@ flt_update_offsets(struct filter *filter, struct channel *chn, int len) struct stream *s = chn_strm(chn); struct filter *f; - list_for_each_entry(f, &strm_flt(s)->filters, list) { + for (f = flt_list_start(s, chn); f; + f = flt_list_next(s, chn, f)) { if (f == filter) break; FLT_OFF(f, chn) += len; diff --git a/src/filters.c b/src/filters.c index 3e8db1572..0596d9a38 100644 --- a/src/filters.c +++ b/src/filters.c @@ -34,7 +34,11 @@ 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_list_start() and resume_filter_list_next() must always be used together. +/* + * The API below is similar to flt_list_start() and flt_list_next() except that it can be + * interrupted and resumed! + * + * - 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 * @@ -72,11 +76,8 @@ static inline struct filter *resume_filter_list_start(struct stream *strm, struc (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 */ - } + else + filter = flt_list_start(strm, chn); return filter; } @@ -84,10 +85,8 @@ static inline struct filter *resume_filter_list_start(struct stream *strm, struc 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; + /* simply an alias to flt_list_next() */ + return flt_list_next(strm, chn, filter); } static inline void resume_filter_list_break(struct stream *strm, struct channel *chn, @@ -659,7 +658,8 @@ flt_http_reset(struct stream *s, struct http_msg *msg) struct filter *filter; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg); - list_for_each_entry(filter, &strm_flt(s)->filters, list) { + for (filter = flt_list_start(s, msg->chn); filter; + filter = flt_list_next(s, msg->chn, filter)) { if (FLT_OPS(filter)->http_reset) { DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s); filter->calls++; @@ -710,7 +710,8 @@ flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len) ret = data = len - out; DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg); - list_for_each_entry(filter, &strm_flt(s)->filters, list) { + for (filter = flt_list_start(s, msg->chn); filter; + filter = flt_list_next(s, msg->chn, filter)) { unsigned long long *flt_off = &FLT_OFF(filter, msg->chn); unsigned int offset = *flt_off - *strm_off; @@ -866,7 +867,8 @@ flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_FLT_ANA, s); - list_for_each_entry(filter, &strm_flt(s)->filters, list) { + for (filter = flt_list_start(s, chn); filter; + filter = flt_list_next(s, chn, filter)) { if (FLT_OPS(filter)->channel_post_analyze && (filter->post_analyzers & an_bit)) { DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s); filter->calls++; @@ -916,7 +918,8 @@ flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_ size_t data = http_get_hdrs_size(htxbuf(&chn->buf)); struct filter *f; - list_for_each_entry(f, &strm_flt(s)->filters, list) + for (f = flt_list_start(s, chn); f; + f = flt_list_next(s, chn, f)) FLT_OFF(f, chn) = data; } @@ -1019,7 +1022,8 @@ flt_tcp_payload(struct stream *s, struct channel *chn, unsigned int len) ret = data = len - out; DBG_TRACE_ENTER(STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s); - list_for_each_entry(filter, &strm_flt(s)->filters, list) { + for (filter = flt_list_start(s, chn); filter; + filter = flt_list_next(s, chn, filter)) { unsigned long long *flt_off = &FLT_OFF(filter, chn); unsigned int offset = *flt_off - *strm_off;