DOC: filters: Update the filters documentation accordingly to recent changes
This commit is contained in:
parent
3a394fa7cd
commit
f34b28aa6e
|
@ -1,6 +1,6 @@
|
|||
-----------------------------------------
|
||||
Filters Guide - version 1.7
|
||||
( Last update: 2016-04-18 )
|
||||
( Last update: 2016-05-11 )
|
||||
------------------------------------------
|
||||
Author : Christopher Faulet
|
||||
Contact : christopher dot faulet at capflam dot org
|
||||
|
@ -193,8 +193,11 @@ existing callbacks. Available callbacks are listed in the following structure:
|
|||
* Channel callbacks
|
||||
*/
|
||||
int (*channel_start_analyze)(struct stream *s, struct filter *f,
|
||||
struct channel *chn);
|
||||
int (*channel_analyze) (struct stream *s, struct filter *f,
|
||||
struct channel *chn);
|
||||
int (*channel_pre_analyze) (struct stream *s, struct filter *f,
|
||||
struct channel *chn,
|
||||
unsigned int an_bit);
|
||||
int (*channel_post_analyze) (struct stream *s, struct filter *f,
|
||||
struct channel *chn,
|
||||
unsigned int an_bit);
|
||||
int (*channel_end_analyze) (struct stream *s, struct filter *f,
|
||||
|
@ -203,6 +206,8 @@ existing callbacks. Available callbacks are listed in the following structure:
|
|||
/*
|
||||
* HTTP callbacks
|
||||
*/
|
||||
int (*http_headers) (struct stream *s, struct filter *f,
|
||||
struct http_msg *msg);
|
||||
int (*http_data) (struct stream *s, struct filter *f,
|
||||
struct http_msg *msg);
|
||||
int (*http_chunk_trailers)(struct stream *s, struct filter *f,
|
||||
|
@ -309,6 +314,10 @@ Filter instances attached to a stream are stored in the field
|
|||
unsigned int fwd[2]; /* Offset, relative to buf->p, to the next
|
||||
* byte to forward for a specific 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 */
|
||||
};
|
||||
|
||||
|
@ -318,6 +327,9 @@ Filter instances attached to a stream are stored in the field
|
|||
* 'filter.ctx' is an opaque context. It is managed by the filter, so it is its
|
||||
responsibility to free it.
|
||||
|
||||
* 'filter.pre_analyzers and 'filter.post_analyzers will be described later
|
||||
(See § 3.5).
|
||||
|
||||
* 'filter.next' and 'filter.fwd' will be described later (See § 3.6).
|
||||
|
||||
|
||||
|
@ -330,8 +342,8 @@ line:
|
|||
|
||||
/* Declare the filter parser for "my_filter" keyword */
|
||||
static struct flt_kw_list flt_kws = { "MY_FILTER_SCOPE", { }, {
|
||||
{ "my_filter", parse_my_filter_cfg },
|
||||
{ NULL, NULL },
|
||||
{ "my_filter", parse_my_filter_cfg, NULL /* private data */ },
|
||||
{ NULL, NULL, NULL },
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -372,7 +384,7 @@ filter line:
|
|||
/* Return -1 on error, else 0 */
|
||||
static int
|
||||
parse_my_filter_cfg(char **args, int *cur_arg, struct proxy *px,
|
||||
struct flt_conf *flt_conf, char **err)
|
||||
struct flt_conf *flt_conf, char **err, void *private)
|
||||
{
|
||||
struct my_filter_config *my_conf;
|
||||
int pos = *cur_arg;
|
||||
|
@ -544,10 +556,11 @@ WARNING: Handling the streams creation and destuction is only possible for
|
|||
------------------------------------
|
||||
|
||||
The main purpose of filters is to take part in the channels analyzing. To do so,
|
||||
there is a callback, 'flt_ops.channel_analyze', called before each analyzer
|
||||
attached to a channel, execpt analyzers responsible for the data
|
||||
parsing/forwarding (TCP data or HTTP body). Concretely, on the request channel,
|
||||
'flt_ops.channel_analyze' could be called before following analyzers:
|
||||
there is 2 callbacks, 'flt_ops.channel_pre_analyze' and
|
||||
'flt_ops.channel_post_analyze', called respectively before and after each
|
||||
analyzer attached to a channel, execpt analyzers responsible for the data
|
||||
parsing/forwarding (TCP or HTTP data). Concretely, on the request channel, these
|
||||
callbacks could be called before following analyzers:
|
||||
|
||||
* tcp_inspect_request (AN_REQ_INSPECT_FE and AN_REQ_INSPECT_BE)
|
||||
* http_wait_for_request (AN_REQ_WAIT_HTTP)
|
||||
|
@ -560,7 +573,6 @@ parsing/forwarding (TCP data or HTTP body). Concretely, on the request channel,
|
|||
* http_process_request (AN_REQ_HTTP_INNER)
|
||||
* tcp_persist_rdp_cookie (AN_REQ_PRST_RDP_COOKIE)
|
||||
* process_sticking_rules (AN_REQ_STICKING_RULES)
|
||||
* flt_analyze_http_headers (AN_FLT_HTTP_HDRS)
|
||||
|
||||
And on the response channel:
|
||||
|
||||
|
@ -568,26 +580,23 @@ And on the response channel:
|
|||
* http_wait_for_response (AN_RES_WAIT_HTTP)
|
||||
* process_store_rules (AN_RES_STORE_RULES)
|
||||
* http_process_res_common (AN_RES_HTTP_PROCESS_BE)
|
||||
* flt_analyze_http_headers (AN_FLT_HTTP_HDRS)
|
||||
|
||||
Note that 'flt_analyze_http_headers' (AN_FLT_HTTP_HDRS) is a new analyzer. It
|
||||
has been added to let filters analyze HTTP headers after all processing, just
|
||||
before the data parsing/forwarding.
|
||||
|
||||
Unlike the other callbacks previously seen before, 'flt_ops.channel_analyze' can
|
||||
interrupt the stream processing. So a filter can decide to not execute the
|
||||
Unlike the other callbacks previously seen before, 'flt_ops.channel_pre_analyze'
|
||||
can interrupt the stream processing. So a filter can decide to not execute the
|
||||
analyzer that follows and wait the next iteration. If there are more than one
|
||||
filter, following ones are skipped. On the next iteration, the filtering resumes
|
||||
where it was stopped, i.e. on the filter that has previously stopped the
|
||||
processing. So it is possible for a filter to stop the stream processing for a
|
||||
while before continuing. For example:
|
||||
processing. So it is possible for a filter to stop the stream processing on a
|
||||
specific analyzer for a while before continuing. Moreover, this callback can be
|
||||
called many times for the same analyzer, until it finishes its processing. For
|
||||
example:
|
||||
|
||||
/* Called before a processing happens on a given channel.
|
||||
* Returns a negative value if an error occurs, 0 if it needs to wait,
|
||||
* any other value otherwise. */
|
||||
static int
|
||||
my_filter_chn_analyze(struct stream *s, struct filter *filter,
|
||||
struct channel *chn, unsigned an_bit)
|
||||
my_filter_chn_pre_analyze(struct stream *s, struct filter *filter,
|
||||
struct channel *chn, unsigned an_bit)
|
||||
{
|
||||
struct my_filter_config *my_conf = FLT_CONF(filter);
|
||||
|
||||
|
@ -613,6 +622,61 @@ while before continuing. For example:
|
|||
In previous example, the stream processing is blocked before receipt of the HTTP
|
||||
request until a condition is verified.
|
||||
|
||||
'flt_ops.channel_post_analyze', for its part, is not resumable. It returns a
|
||||
negative value if an error occurs, any other value otherwise. It is called when
|
||||
a filterable analyzer finishes its processing. So it called once for the same
|
||||
analyzer. For example:
|
||||
|
||||
/* Called after a processing happens on a given channel.
|
||||
* Returns a negative value if an error occurs, any other
|
||||
* value otherwise. */
|
||||
static int
|
||||
my_filter_chn_post_analyze(struct stream *s, struct filter *filter,
|
||||
struct channel *chn, unsigned an_bit)
|
||||
{
|
||||
struct my_filter_config *my_conf = FLT_CONF(filter);
|
||||
struct http_msg *msg;
|
||||
|
||||
switch (an_bit) {
|
||||
case AN_REQ_WAIT_HTTP:
|
||||
if (/* A test on received headers before any other treatment */) {
|
||||
msg = ((chn->flags & CF_ISRESP) ? &s->txn->rsp : &s->txn->req);
|
||||
txn->status = 400;
|
||||
msg->msg_state = HTTP_MSG_ERROR;
|
||||
http_reply_and_close(s, s->txn->status,
|
||||
http_error_message(s, HTTP_ERR_400));
|
||||
return -1; /* This is an error ! */
|
||||
}
|
||||
break;
|
||||
/* ... * /
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Pre and post analyzer callbacks of a filter are not automatically called. You
|
||||
must register it explicitly on analyzers, updating the value of
|
||||
'filter.pre_analyzers' and 'filter.post_analyzers' bit fields. All analyzer bits
|
||||
are listed in 'include/types/channels.h'. Here is an example:
|
||||
|
||||
static int
|
||||
my_filter_stream_start(struct stream *s, struct filter *filter)
|
||||
{
|
||||
/* ... * /
|
||||
|
||||
/* Register the pre analyzer callback on all request and response
|
||||
* analyzers */
|
||||
filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL)
|
||||
|
||||
/* Register the post analyzer callback of only on AN_REQ_WAIT_HTTP and
|
||||
* AN_RES_WAIT_HTTP analyzers */
|
||||
filter->post_analyzers |= (AN_REQ_WAIT_HTTP | AN_RES_WAIT_HTTP)
|
||||
|
||||
/* ... * /
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
To surround activity of a filter during the channel analyzing, two new analyzers
|
||||
has been added:
|
||||
|
||||
|
@ -680,15 +744,17 @@ Workflow on channels can be summarized as following:
|
|||
|(flt_ops.channel_start_analyze)| | F | |(flt_ops.channel_start_analyze)| |
|
||||
+---------------+---------------+ | R | +---------------+---------------+ |
|
||||
| | O | | |
|
||||
+------<--------+ | N ^ +--------<-------+ | B
|
||||
| | | T | | | | A
|
||||
+---------------+----------+ | | E | +---------------+----------+ | | C
|
||||
|+--------------V-----------+ | | N | |+--------------V-----------+ | | K
|
||||
||+--------------------------+ | | D | ||+--------------------------+ | | E
|
||||
||| flt_ops.channel_analyze | | | | ||| flt_ops.channel_analyze | | | N
|
||||
+|| V +--+ | | +|| V +---+ | D
|
||||
+| analyzer | | | +| analyzer | |
|
||||
+-------------+------------+ | | +-------------+------------+ |
|
||||
+------<---------+ | N ^ +--------<-------+ | B
|
||||
| | | T | | | | A
|
||||
+---------------+------------+ | | E | +---------------+------------+ | | C
|
||||
|+--------------V-------------+ | | N | |+--------------V-------------+ | | K
|
||||
||+----------------------------+ | | D | ||+----------------------------+ | | E
|
||||
|||flt_ops.channel_pre_analyze | | | | |||flt_ops.channel_pre_analyze | | | N
|
||||
||| V | | | | ||| V | | | D
|
||||
||| analyzer +-+ | | ||| analyzer +-+ |
|
||||
+|| V | | | +|| V | |
|
||||
+|flt_ops.channel_post_analyze| | | +|flt_ops.channel_post_analyze| |
|
||||
+-------------+--------------+ | | +-------------+--------------+ |
|
||||
| --+ | | |
|
||||
+------------>------------+ ... |
|
||||
| |
|
||||
|
@ -714,9 +780,34 @@ Workflow on channels can be summarized as following:
|
|||
|
|
||||
V
|
||||
|
||||
By zooming on an analyzer box we have:
|
||||
|
||||
TODO: Add pre/post analyzer callbacks with a mask. So, this part will be
|
||||
massively refactored very soon.
|
||||
...
|
||||
|
|
||||
V
|
||||
|
|
||||
+-----------<-----------+
|
||||
| |
|
||||
+-----------------+--------------------+ |
|
||||
| | | |
|
||||
| +--------<---------+ | |
|
||||
| | | | |
|
||||
| V | | |
|
||||
| flt_ops.channel_pre_analyze ->-+ | ^
|
||||
| | | |
|
||||
| | | |
|
||||
| V | |
|
||||
| analyzer --------->-----+--+
|
||||
| | |
|
||||
| | |
|
||||
| V |
|
||||
| flt_ops.channel_post_analyze |
|
||||
| | |
|
||||
| | |
|
||||
+-----------------+--------------------+
|
||||
|
|
||||
V
|
||||
...
|
||||
|
||||
|
||||
3.6. FILTERING THE DATA EXCHANGED
|
||||
|
@ -737,15 +828,14 @@ So, to enable the data filtering on a channel, at any time, in one of previous
|
|||
callbacks, you should call 'register_data_filter' function. And conversely, to
|
||||
disable it, you should call 'unregister_data_filter' function. For example:
|
||||
|
||||
my_filter_chn_analyze(struct stream *s, struct filter *filter,
|
||||
struct channel *chn, unsigned an_bit)
|
||||
my_filter_http_headers(struct stream *s, struct filter *filter,
|
||||
struct http_msg *msg)
|
||||
{
|
||||
struct my_filter_config *my_conf = FLT_CONF(filter);
|
||||
|
||||
/* 'chn' must be the request channel */
|
||||
if (!(chn->flags & CF_ISRESP) && an_bit == AN_FLT_HTTP_HDRS) {
|
||||
if (!(msg->chn->flags & CF_ISRESP)) {
|
||||
struct http_txn *txn = s->txn;
|
||||
struct http_msg *msg = &txn->req;
|
||||
struct buffer *req = msg->chn->buf;
|
||||
struct hdr_ctx ctx;
|
||||
|
||||
|
@ -753,7 +843,7 @@ disable it, you should call 'unregister_data_filter' function. For example:
|
|||
* is set to 'true'. */
|
||||
if (http_find_header2("X-Filter", 8, req->p, &txn->hdr_idx, &ctx) &&
|
||||
ctx.vlen >= 3 && memcmp(ctx.line + ctx.val, "true", 4) == 0)
|
||||
register_data_filter(s, chn_filter);
|
||||
register_data_filter(s, chn, filter);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -916,7 +1006,12 @@ But in your filter, you need to recompute it:
|
|||
Bytes = MIN(msg->chunk_len + msg->next, chn->buf->i) - FLT_NXT(flt, chn);
|
||||
|
||||
|
||||
In addition to these callbacks, there are two other:
|
||||
In addition to these callbacks, there are three others:
|
||||
|
||||
* 'flt_ops.http_headers': This callback is called just before the HTTP body
|
||||
parsing and after any processing on the request/response HTTP headers. When
|
||||
defined, this callback is always called for HTTP streams (i.e. without needs
|
||||
of a registration on data filtering).
|
||||
|
||||
* 'flt_ops.http_end': This callback is called when the whole HTTP
|
||||
request/response is processed. It can interrupt the stream processing. So,
|
||||
|
|
Loading…
Reference in New Issue