#include <haproxy/api-t.h>
#include <haproxy/buf-t.h>
+#include <haproxy/filters-t.h>
#include <haproxy/show_flags-t.h>
/* The CF_* macros designate Channel Flags, which may be ORed in the bit field
unsigned char xfer_large; /* number of consecutive large xfers */
unsigned char xfer_small; /* number of consecutive small xfers */
int analyse_exp; /* expiration date for current analysers (if set) */
+ struct chn_flt flt; /* current state of filters active on this channel */
};
* 0: request channel, 1: response channel */
unsigned int pre_analyzers; /* bit field indicating analyzers to pre-process */
unsigned int post_analyzers; /* bit field indicating analyzers to post-process */
- struct list list; /* Next filter for the same proxy/stream */
+ struct list list; /* Filter list for the stream */
+ /* req_list and res_list are exactly equivalent, except the order may differ */
+ struct list req_list; /* Filter list for request channel */
+ struct list res_list; /* Filter list for response channel */
};
/*
* Structure reprensenting the "global" state of filters attached to a stream.
+ * Doesn't hold much information, as the channel themselves hold chn_flt struct
+ * which contains the per-channel members.
*/
struct strm_flt {
struct list filters; /* List of filters attached to a stream */
- struct filter *current[2]; /* From which filter resume processing, for a specific channel.
- * This is used for resumable callbacks only,
- * If NULL, we start from the first filter.
- * 0: request channel, 1: response channel */
unsigned short flags; /* STRM_FL_* */
- unsigned char nb_req_data_filters; /* Number of data filters registered on the request channel */
- unsigned char nb_rsp_data_filters; /* Number of data filters registered on the response channel */
- unsigned long long offset[2];
+};
+
+/* structure holding filter state for some members that are channel oriented */
+struct chn_flt {
+ struct list filters; /* List of filters attached to a channel */
+ struct filter *current; /* From which filter resume processing, for a specific channel. */
+ unsigned char nb_data_filters; /* Number of data filters registered on channel */
+ unsigned long long offset;
};
#endif /* _HAPROXY_FILTERS_T_H */
/* Useful macros to access per-channel values. It can be safely used inside
* filters. */
#define CHN_IDX(chn) (((chn)->flags & CF_ISRESP) == CF_ISRESP)
-#define FLT_STRM_OFF(s, chn) (strm_flt(s)->offset[CHN_IDX(chn)])
+#define FLT_STRM_OFF(s, chn) (chn->flt.offset)
#define FLT_OFF(flt, chn) ((flt)->offset[CHN_IDX(chn)])
#define HAS_FILTERS(strm) ((strm)->strm_flt.flags & STRM_FLT_FL_HAS_FILTERS)
-#define HAS_REQ_DATA_FILTERS(strm) ((strm)->strm_flt.nb_req_data_filters != 0)
-#define HAS_RSP_DATA_FILTERS(strm) ((strm)->strm_flt.nb_rsp_data_filters != 0)
+#define HAS_REQ_DATA_FILTERS(strm) ((strm)->req.flt.nb_data_filters != 0)
+#define HAS_RSP_DATA_FILTERS(strm) ((strm)->res.flt.nb_data_filters != 0)
#define HAS_DATA_FILTERS(strm, chn) (((chn)->flags & CF_ISRESP) ? HAS_RSP_DATA_FILTERS(strm) : HAS_REQ_DATA_FILTERS(strm))
#define IS_REQ_DATA_FILTER(flt) ((flt)->flags & FLT_FL_IS_REQ_DATA_FILTER)
register_data_filter(struct stream *s, struct channel *chn, struct filter *filter)
{
if (!IS_DATA_FILTER(filter, chn)) {
- if (chn->flags & CF_ISRESP) {
+ if (chn->flags & CF_ISRESP)
filter->flags |= FLT_FL_IS_RSP_DATA_FILTER;
- strm_flt(s)->nb_rsp_data_filters++;
- }
- else {
+ else
filter->flags |= FLT_FL_IS_REQ_DATA_FILTER;
- strm_flt(s)->nb_req_data_filters++;
- }
+ chn->flt.nb_data_filters++;
}
}
unregister_data_filter(struct stream *s, struct channel *chn, struct filter *filter)
{
if (IS_DATA_FILTER(filter, chn)) {
- if (chn->flags & CF_ISRESP) {
+ if (chn->flags & CF_ISRESP)
filter->flags &= ~FLT_FL_IS_RSP_DATA_FILTER;
- strm_flt(s)->nb_rsp_data_filters--;
-
- }
- else {
+ else
filter->flags &= ~FLT_FL_IS_REQ_DATA_FILTER;
- strm_flt(s)->nb_req_data_filters--;
- }
+ chn->flt.nb_data_filters--;
}
}
{
struct filter *filter;
- filter = LIST_NEXT(&strm_flt(strm)->filters, struct filter *, list);
- if (&filter->list == &strm_flt(strm)->filters)
- filter = NULL; /* empty list */
+ if (chn->flags & CF_ISRESP) {
+ filter = LIST_NEXT(&chn->flt.filters, struct filter *, res_list);
+ if (&filter->res_list == &chn->flt.filters)
+ filter = NULL; /* empty list */
+ }
+ else {
+ filter = LIST_NEXT(&chn->flt.filters, struct filter *, req_list);
+ if (&filter->req_list == &chn->flt.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 */
+ if (chn->flags & CF_ISRESP) {
+ filter = LIST_NEXT(&filter->res_list, struct filter *, res_list);
+ if (&filter->res_list == &chn->flt.filters)
+ filter = NULL; /* end of list */
+ }
+ else {
+ filter = LIST_NEXT(&filter->req_list, struct filter *, req_list);
+ if (&filter->req_list == &chn->flt.filters)
+ filter = NULL; /* end of list */
+ }
return filter;
}
{
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->flt.current) {
+ filter = chn->flt.current;
+ chn->flt.current = 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->last_entity.type = STRM_ENTITY_FILTER;
strm->last_entity.ptr = filter;
}
- strm_flt(strm)->current[CHN_IDX(chn)] = filter;
+ chn->flt.current = filter;
}
/* List head of all known filter keywords */
}
LIST_APPEND(&strm_flt(s)->filters, &f->list);
+
+ /* for now f->req_list == f->res_list to preserve
+ * historical behavior, but the ordering will change
+ * in the future
+ */
+ LIST_APPEND(&s->req.flt.filters, &f->req_list);
+ LIST_APPEND(&s->res.flt.filters, &f->res_list);
+
strm_flt(s)->flags |= STRM_FLT_FL_HAS_FILTERS;
return 0;
}
memset(strm_flt(s), 0, sizeof(*strm_flt(s)));
LIST_INIT(&strm_flt(s)->filters);
+ memset(&s->req.flt, 0, sizeof(s->req.flt));
+ LIST_INIT(&s->req.flt.filters);
+ memset(&s->res.flt, 0, sizeof(s->res.flt));
+ LIST_INIT(&s->res.flt.filters);
list_for_each_entry(fconf, &strm_fe(s)->filter_configs, list) {
if (flt_stream_add_filter(s, fconf, 0) < 0)
return -1;
if (FLT_OPS(filter)->detach)
FLT_OPS(filter)->detach(s, filter);
LIST_DELETE(&filter->list);
+ LIST_DELETE(&filter->req_list);
+ LIST_DELETE(&filter->res_list);
pool_free(pool_head_filter, filter);
}
}
htx, htx->flags, htx->size, htx->data, htx_nbblks(htx),
(htx->tail >= htx->head) ? "NO" : "YES");
}
- if (HAS_FILTERS(strm) && strm->strm_flt.current[0]) {
- const struct filter *flt = strm->strm_flt.current[0];
+ if (HAS_FILTERS(strm) && strm->req.flt.current) {
+ const struct filter *flt = strm->req.flt.current;
chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x) \n", pfx,
flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers);
(htx->tail >= htx->head) ? "NO" : "YES");
}
- if (HAS_FILTERS(strm) && strm->strm_flt.current[1]) {
- const struct filter *flt = strm->strm_flt.current[1];
+ if (HAS_FILTERS(strm) && strm->res.flt.current) {
+ const struct filter *flt = strm->res.flt.current;
chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x) \n", pfx,
flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers);