MEDIUM: filters: Use macros to call filters callbacks to speed-up processing

When no filter is attached to the stream, the CPU footprint due to the calls to
filters_* functions is huge, especially for chunk-encoded messages. Using macros
to check if we have some filters or not is a great improvement.

Furthermore, instead of checking the filter list emptiness, we introduce a flag
to know if filters are attached or not to a stream.
This commit is contained in:
Christopher Faulet 2015-11-24 16:24:13 +01:00 committed by Willy Tarreau
parent 92d3638d2d
commit 3e34429515
5 changed files with 204 additions and 227 deletions

View File

@ -35,6 +35,50 @@
#define FLT_NXT(flt, chn) ((flt)->next[CHN_IDX(chn)]) #define FLT_NXT(flt, chn) ((flt)->next[CHN_IDX(chn)])
#define FLT_FWD(flt, chn) ((flt)->fwd[CHN_IDX(chn)]) #define FLT_FWD(flt, chn) ((flt)->fwd[CHN_IDX(chn)])
#define HAS_FILTERS(strm) ((strm)->strm_flt.has_filters)
#define FLT_STRM_CB_IMPL_0(strm, call) \
do { \
if (HAS_FILTERS(strm)) { call; } \
} while (0)
#define FLT_STRM_CB_IMPL_1(strm, call, default_ret, ...) \
(HAS_FILTERS(strm) ? call : default_ret)
#define FLT_STRM_CB_IMPL_2(strm, call, default_ret, on_error) \
({ \
int _ret; \
if (HAS_FILTERS(strm)) { \
_ret = call; \
if (_ret < 0) { on_error; } \
} \
else \
_ret = default_ret; \
_ret; \
})
#define FLT_STRM_CB_IMPL_3(strm, call, default_ret, on_error, on_wait) \
({ \
int _ret; \
if (HAS_FILTERS(strm)) { \
_ret = call; \
if (_ret < 0) { on_error; } \
if (!_ret) { on_wait; } \
} \
else \
_ret = default_ret; \
_ret; \
})
#define FLT_STRM_CB_IMPL_X(strm, call, A, B, C, CB_IMPL, ...) CB_IMPL
#define FLT_STRM_CB(strm, call, ...) \
FLT_STRM_CB_IMPL_X(strm, call, ##__VA_ARGS__, \
FLT_STRM_CB_IMPL_3(strm, call, ##__VA_ARGS__), \
FLT_STRM_CB_IMPL_2(strm, call, ##__VA_ARGS__), \
FLT_STRM_CB_IMPL_1(strm, call, ##__VA_ARGS__), \
FLT_STRM_CB_IMPL_0(strm, call))
#define CALL_FILTER_ANALYZER(analyzer, strm, chn, bit) \
if (!HAS_FILTERS(strm) || analyzer((strm), (chn), bit)) ; else break
extern struct pool_head *pool2_filter; extern struct pool_head *pool2_filter;
int flt_init(struct proxy *p); int flt_init(struct proxy *p);

View File

@ -128,6 +128,7 @@ struct stream {
struct { struct {
struct list filters; struct list filters;
struct filter *current[2]; /* 0: request, 1: response */ struct filter *current[2]; /* 0: request, 1: response */
char has_filters;
} strm_flt; } strm_flt;
struct task *task; /* the task associated with this stream */ struct task *task; /* the task associated with this stream */

View File

@ -295,6 +295,7 @@ flt_stream_add_filter(struct stream *s, struct filter *filter,
f->conf = filter->conf; f->conf = filter->conf;
f->is_backend_filter = is_backend; f->is_backend_filter = is_backend;
LIST_ADDQ(&s->strm_flt.filters, &f->list); LIST_ADDQ(&s->strm_flt.filters, &f->list);
s->strm_flt.has_filters = 1;
return 0; return 0;
} }
@ -309,6 +310,7 @@ flt_stream_init(struct stream *s)
LIST_INIT(&s->strm_flt.filters); LIST_INIT(&s->strm_flt.filters);
memset(s->strm_flt.current, 0, sizeof(s->strm_flt.current)); memset(s->strm_flt.current, 0, sizeof(s->strm_flt.current));
s->strm_flt.has_filters = 0;
list_for_each_entry(filter, &strm_fe(s)->filters, list) { list_for_each_entry(filter, &strm_fe(s)->filters, list) {
if (flt_stream_add_filter(s, filter, 0) < 0) if (flt_stream_add_filter(s, filter, 0) < 0)
return -1; return -1;
@ -333,6 +335,8 @@ flt_stream_release(struct stream *s, int only_backend)
pool_free2(pool2_filter, filter); pool_free2(pool2_filter, filter);
} }
} }
if (LIST_ISEMPTY(&s->strm_flt.filters))
s->strm_flt.has_filters = 0;
} }
/* /*
@ -393,9 +397,6 @@ flt_http_headers(struct stream *s, struct http_msg *msg)
struct filter *filter; struct filter *filter;
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops && filter->ops->http_headers) { if (filter->ops && filter->ops->http_headers) {
ret = filter->ops->http_headers(s, filter, msg); ret = filter->ops->http_headers(s, filter, msg);
@ -419,9 +420,6 @@ flt_http_start_chunk(struct stream *s, struct http_msg *msg)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops->http_start_chunk) { if (filter->ops->http_start_chunk) {
ret = filter->ops->http_start_chunk(s, filter, msg); ret = filter->ops->http_start_chunk(s, filter, msg);
@ -450,12 +448,6 @@ flt_http_data(struct stream *s, struct http_msg *msg)
unsigned int buf_i; unsigned int buf_i;
int ret = 0; int ret = 0;
/* No filter, consume all available data */
if (LIST_ISEMPTY(&s->strm_flt.filters)) {
ret = MIN(msg->chunk_len, msg->chn->buf->i - msg->next);
goto end;
}
/* Save buffer state */ /* Save buffer state */
buf_i = msg->chn->buf->i; buf_i = msg->chn->buf->i;
list_for_each_entry(filter, &s->strm_flt.filters, list) { list_for_each_entry(filter, &s->strm_flt.filters, list) {
@ -483,7 +475,6 @@ flt_http_data(struct stream *s, struct http_msg *msg)
} }
/* Restore the original buffer state */ /* Restore the original buffer state */
msg->chn->buf->i = buf_i; msg->chn->buf->i = buf_i;
end:
return ret; return ret;
} }
@ -492,9 +483,6 @@ flt_http_end_chunk(struct stream *s, struct http_msg *msg)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops->http_end_chunk) { if (filter->ops->http_end_chunk) {
ret = filter->ops->http_end_chunk(s, filter, msg); ret = filter->ops->http_end_chunk(s, filter, msg);
@ -513,9 +501,6 @@ flt_http_last_chunk(struct stream *s, struct http_msg *msg)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops->http_last_chunk) { if (filter->ops->http_last_chunk) {
ret = filter->ops->http_last_chunk(s, filter, msg); ret = filter->ops->http_last_chunk(s, filter, msg);
@ -543,9 +528,6 @@ flt_http_chunk_trailers(struct stream *s, struct http_msg *msg)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops->http_chunk_trailers) { if (filter->ops->http_chunk_trailers) {
ret = filter->ops->http_chunk_trailers(s, filter, msg); ret = filter->ops->http_chunk_trailers(s, filter, msg);
@ -570,9 +552,6 @@ flt_http_end(struct stream *s, struct http_msg *msg)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, msg->chn) { RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops->http_end) { if (filter->ops->http_end) {
ret = filter->ops->http_end(s, filter, msg); ret = filter->ops->http_end(s, filter, msg);
@ -594,9 +573,6 @@ flt_http_reset(struct stream *s, struct http_msg *msg)
{ {
struct filter *filter; struct filter *filter;
if (LIST_ISEMPTY(&s->strm_flt.filters))
return;
list_for_each_entry(filter, &s->strm_flt.filters, list) { list_for_each_entry(filter, &s->strm_flt.filters, list) {
if (filter->ops->http_reset) if (filter->ops->http_reset)
filter->ops->http_reset(s, filter, msg); filter->ops->http_reset(s, filter, msg);
@ -612,9 +588,6 @@ flt_http_reply(struct stream *s, short status, const struct chunk *msg)
{ {
struct filter *filter; struct filter *filter;
if (LIST_ISEMPTY(&s->strm_flt.filters))
return;
list_for_each_entry(filter, &s->strm_flt.filters, list) { list_for_each_entry(filter, &s->strm_flt.filters, list) {
if (filter->ops->http_reply) if (filter->ops->http_reply)
filter->ops->http_reply(s, filter, status, msg); filter->ops->http_reply(s, filter, status, msg);
@ -636,10 +609,6 @@ flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len)
struct filter *filter = NULL; struct filter *filter = NULL;
int ret = len; int ret = len;
/* No filter, forward all data */
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
list_for_each_entry(filter, &s->strm_flt.filters, list) { list_for_each_entry(filter, &s->strm_flt.filters, list) {
if (filter->ops->http_forward_data) { if (filter->ops->http_forward_data) {
/* Remove bytes that the current filter considered as /* Remove bytes that the current filter considered as
@ -719,9 +688,6 @@ flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
{ {
int ret = 1; int ret = 1;
if (LIST_ISEMPTY(&s->strm_flt.filters))
goto end;
RESUME_FILTER_LOOP(s, chn) { RESUME_FILTER_LOOP(s, chn) {
if (filter->ops->channel_analyze) { if (filter->ops->channel_analyze) {
ret = filter->ops->channel_analyze(s, filter, chn, an_bit); ret = filter->ops->channel_analyze(s, filter, chn, an_bit);
@ -732,7 +698,6 @@ flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
check_result: check_result:
ret = handle_analyzer_result(s, chn, 0, ret); ret = handle_analyzer_result(s, chn, 0, ret);
end:
return ret; return ret;
} }

View File

@ -935,7 +935,7 @@ int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ct
static void http_server_error(struct stream *s, struct stream_interface *si, static void http_server_error(struct stream *s, struct stream_interface *si,
int err, int finst, int status, const struct chunk *msg) int err, int finst, int status, const struct chunk *msg)
{ {
flt_http_reply(s, status, msg); FLT_STRM_CB(s, flt_http_reply(s, status, msg));
channel_auto_read(si_oc(si)); channel_auto_read(si_oc(si));
channel_abort(si_oc(si)); channel_abort(si_oc(si));
channel_auto_close(si_oc(si)); channel_auto_close(si_oc(si));
@ -970,7 +970,7 @@ void
http_reply_and_close(struct stream *s, short status, struct chunk *msg) http_reply_and_close(struct stream *s, short status, struct chunk *msg)
{ {
s->txn->flags &= ~TX_WAIT_NEXT_RQ; s->txn->flags &= ~TX_WAIT_NEXT_RQ;
flt_http_reply(s, status, msg); FLT_STRM_CB(s, flt_http_reply(s, status, msg));
stream_int_retnclose(&s->si[0], msg); stream_int_retnclose(&s->si[0], msg);
} }
@ -4027,7 +4027,7 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
} }
memcpy(trash.str + trash.len, "\r\n\r\n", 4); memcpy(trash.str + trash.len, "\r\n\r\n", 4);
trash.len += 4; trash.len += 4;
flt_http_reply(s, txn->status, &trash); FLT_STRM_CB(s, flt_http_reply(s, txn->status, &trash));
bo_inject(res->chn, trash.str, trash.len); bo_inject(res->chn, trash.str, trash.len);
/* "eat" the request */ /* "eat" the request */
bi_fast_delete(req->chn->buf, req->sov); bi_fast_delete(req->chn->buf, req->sov);
@ -5071,14 +5071,14 @@ void http_end_txn_clean_session(struct stream *s)
si_idle_conn(&s->si[1], &srv->idle_conns); si_idle_conn(&s->si[1], &srv->idle_conns);
} }
if (LIST_ISEMPTY(&s->strm_flt.filters)) { if (HAS_FILTERS(s)) {
s->req.analysers = strm_li(s) ? strm_li(s)->analysers : 0;
s->res.analysers = 0;
}
else {
s->req.analysers &= AN_FLT_END; s->req.analysers &= AN_FLT_END;
s->res.analysers &= AN_FLT_END; s->res.analysers &= AN_FLT_END;
} }
else {
s->req.analysers = strm_li(s) ? strm_li(s)->analysers : 0;
s->res.analysers = 0;
}
} }
@ -5442,7 +5442,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
struct session *sess = s->sess; struct session *sess = s->sess;
struct http_txn *txn = s->txn; struct http_txn *txn = s->txn;
struct http_msg *msg = &s->txn->req; struct http_msg *msg = &s->txn->req;
int ret, ret2; int ret;
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) if (unlikely(msg->msg_state < HTTP_MSG_BODY))
return 0; return 0;
@ -5462,25 +5462,16 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
* decide whether to return 100, 417 or anything else in return of * decide whether to return 100, 417 or anything else in return of
* an "Expect: 100-continue" header. * an "Expect: 100-continue" header.
*/ */
if (msg->msg_state == HTTP_MSG_BODY) { if (msg->msg_state == HTTP_MSG_BODY) {
/* we have msg->sov which points to the first byte of message /* we have msg->sov which points to the first byte of message
* body, and req->buf.p still points to the beginning of the * body, and req->buf.p still points to the beginning of the
* message. We forward the headers now, as we don't need them * message. We forward the headers now, as we don't need them
* anymore, and we want to flush them. * anymore, and we want to flush them.
*/ */
ret = flt_http_headers(s, msg); FLT_STRM_CB(s, flt_http_headers(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_req; /* on_error */ goto return_bad_req,
if (!ret) /* on_wait */ return 0);
return 0;
ret = flt_http_forward_data(s, msg, msg->sov);
if (ret < 0)
goto return_bad_req;
b_adv(req->buf, ret);
msg->next -= ret;
msg->sov -= ret;
/* The previous analysers guarantee that the state is somewhere /* The previous analysers guarantee that the state is somewhere
* between MSG_BODY and the first MSG_DATA. So msg->sol and * between MSG_BODY and the first MSG_DATA. So msg->sol and
@ -5526,10 +5517,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
if (msg->msg_state == HTTP_MSG_DATA) { if (msg->msg_state == HTTP_MSG_DATA) {
/* must still forward */ /* must still forward */
/* we may have some pending data starting at req->buf->p */ /* we may have some pending data starting at req->buf->p */
ret = flt_http_data(s, msg); ret = FLT_STRM_CB(s, flt_http_data(s, msg),
if (ret < 0) /* default_ret */ MIN(msg->chunk_len, req->buf->i - msg->next),
goto aborted_xfer; /* on_error */ goto aborted_xfer);
msg->next += ret; msg->next += ret;
msg->chunk_len -= ret; msg->chunk_len -= ret;
if (msg->chunk_len) { if (msg->chunk_len) {
@ -5561,13 +5552,16 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
goto return_bad_req; goto return_bad_req;
} }
} }
ret = (msg->chunk_len if (msg->chunk_len)
? flt_http_start_chunk(s, msg) FLT_STRM_CB(s, flt_http_start_chunk(s, msg),
: flt_http_last_chunk(s, msg)); /* default_ret */ 1,
if (ret < 0) /* on_error */ goto return_bad_req,
goto return_bad_req; /* on_wait */ goto missing_data);
if (!ret) else
goto missing_data; FLT_STRM_CB(s, flt_http_last_chunk(s, msg),
/* default_ret */ 1,
/* on_error */ goto return_bad_req,
/* on_wait */ goto missing_data);
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS; msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
@ -5586,11 +5580,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
goto return_bad_req; goto return_bad_req;
} }
} }
ret = flt_http_end_chunk(s, msg); FLT_STRM_CB(s, flt_http_end_chunk(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_req; /* on_error */ goto return_bad_req,
if (!ret) /* on_wait */ goto missing_data);
goto missing_data;
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
msg->msg_state = HTTP_MSG_CHUNK_SIZE; msg->msg_state = HTTP_MSG_CHUNK_SIZE;
@ -5607,11 +5600,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
goto return_bad_req; goto return_bad_req;
} }
} }
ret2 = flt_http_chunk_trailers(s, msg); FLT_STRM_CB(s, flt_http_chunk_trailers(s, msg),
if (ret2 < 0) /* default_ret */ 1,
goto return_bad_req; /* on_error */ goto return_bad_req,
if (!ret2) /* on_wait */ goto missing_data);
goto missing_data;
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
if (!ret) if (!ret)
@ -5627,22 +5619,20 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
/* we may have some pending data starting at req->buf->p /* we may have some pending data starting at req->buf->p
* such as last chunk of data or trailers. * such as last chunk of data or trailers.
*/ */
ret = flt_http_forward_data(s, msg, msg->next); ret = FLT_STRM_CB(s, flt_http_forward_data(s, msg, msg->next),
if (ret < 0) /* default_ret */ msg->next,
goto return_bad_req; /* on_error */ goto return_bad_req);
b_adv(req->buf, ret); b_adv(req->buf, ret);
msg->next -= ret; msg->next -= ret;
if (unlikely(!(s->req.flags & CF_WROTE_DATA) || msg->sov > 0)) if (unlikely(!(s->req.flags & CF_WROTE_DATA) || msg->sov > 0))
msg->sov -= ret; msg->sov -= ret;
if (msg->next) if (msg->next)
goto skip_resync_states; goto skip_resync_states;
ret = flt_http_end(s, msg); FLT_STRM_CB(s, flt_http_end(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_req; /* on_error */ goto return_bad_req,
if (!ret) /* on_wait */ goto skip_resync_states);
goto skip_resync_states;
msg->msg_state = HTTP_MSG_DONE; msg->msg_state = HTTP_MSG_DONE;
} }
else { else {
@ -5703,14 +5693,14 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
missing_data: missing_data:
/* we may have some pending data starting at req->buf->p */ /* we may have some pending data starting at req->buf->p */
ret = flt_http_forward_data(s, msg, msg->next); ret = FLT_STRM_CB(s, flt_http_forward_data(s, msg, msg->next),
if (ret < 0) /* default_ret */ msg->next,
goto return_bad_req; /* on_error */ goto return_bad_req);
b_adv(req->buf, ret); b_adv(req->buf, ret);
msg->next -= ret; msg->next -= ret;
if (unlikely(!(s->req.flags & CF_WROTE_DATA) || msg->sov > 0)) if (unlikely(!(s->req.flags & CF_WROTE_DATA) || msg->sov > 0))
msg->sov -= ret; msg->sov -= ret;
if (LIST_ISEMPTY(&s->strm_flt.filters)) if (!HAS_FILTERS(s))
msg->chunk_len -= channel_forward(req, msg->chunk_len); msg->chunk_len -= channel_forward(req, msg->chunk_len);
/* stop waiting for data if the input is closed before the end */ /* stop waiting for data if the input is closed before the end */
@ -6162,7 +6152,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
msg->msg_state = HTTP_MSG_RPBEFORE; msg->msg_state = HTTP_MSG_RPBEFORE;
txn->status = 0; txn->status = 0;
s->logs.t_data = -1; /* was not a response yet */ s->logs.t_data = -1; /* was not a response yet */
flt_http_reset(s, msg); FLT_STRM_CB(s, flt_http_reset(s, msg));
goto next_one; goto next_one;
case 200: case 200:
@ -6733,8 +6723,7 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
} }
skip_header_mangling: skip_header_mangling:
if ((msg->flags & HTTP_MSGF_XFER_LEN) || if ((msg->flags & HTTP_MSGF_XFER_LEN) || HAS_FILTERS(s) ||
!LIST_ISEMPTY(&s->strm_flt.filters) ||
(txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) { (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
rep->analysers &= ~AN_FLT_XFER_DATA; rep->analysers &= ~AN_FLT_XFER_DATA;
rep->analysers |= AN_RES_HTTP_XFER_BODY; rep->analysers |= AN_RES_HTTP_XFER_BODY;
@ -6782,12 +6771,13 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
* is performed at once on final states for all bytes parsed, or when leaving * is performed at once on final states for all bytes parsed, or when leaving
* on missing data. * on missing data.
*/ */
int http_response_forward_body(struct stream *s, struct channel *res, int an_bit) int http_response_forward_body(struct stream *s, struct channel *res, int an_bit)
{ {
struct session *sess = s->sess; struct session *sess = s->sess;
struct http_txn *txn = s->txn; struct http_txn *txn = s->txn;
struct http_msg *msg = &s->txn->rsp; struct http_msg *msg = &s->txn->rsp;
int ret, ret2; int ret;
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) if (unlikely(msg->msg_state < HTTP_MSG_BODY))
return 0; return 0;
@ -6812,18 +6802,10 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
* message. We forward the headers now, as we don't need them * message. We forward the headers now, as we don't need them
* anymore, and we want to flush them. * anymore, and we want to flush them.
*/ */
ret = flt_http_headers(s, msg); FLT_STRM_CB(s, flt_http_headers(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_res; /* on_error */ goto return_bad_res,
if (!ret) /* on_wait */ return 0);
return 0;
ret = flt_http_forward_data(s, msg, msg->sov);
if (ret < 0)
goto return_bad_res;
b_adv(res->buf, ret);
msg->next -= ret;
msg->sov -= ret;
/* The previous analysers guarantee that the state is somewhere /* The previous analysers guarantee that the state is somewhere
* between MSG_BODY and the first MSG_DATA. So msg->sol and * between MSG_BODY and the first MSG_DATA. So msg->sol and
@ -6852,11 +6834,14 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
* found, so we must read the body until the server * found, so we must read the body until the server
* connection is closed. In that case, we eat data as * connection is closed. In that case, we eat data as
* they come. */ * they come. */
if (!(msg->flags & HTTP_MSGF_XFER_LEN)) if (!(msg->flags & HTTP_MSGF_XFER_LEN)) {
msg->chunk_len = (res->buf->i - msg->next); unsigned long long len = (res->buf->i - msg->next);
ret = flt_http_data(s, msg); msg->chunk_len += len;
if (ret < 0) msg->body_len += len;
goto aborted_xfer; }
ret = FLT_STRM_CB(s, flt_http_data(s, msg),
/* default_ret */ MIN(msg->chunk_len, res->buf->i - msg->next),
/* on_error */ goto aborted_xfer);
msg->next += ret; msg->next += ret;
msg->chunk_len -= ret; msg->chunk_len -= ret;
if (msg->chunk_len) { if (msg->chunk_len) {
@ -6891,11 +6876,10 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
goto return_bad_res; goto return_bad_res;
} }
} }
ret = flt_http_end_chunk(s, msg); FLT_STRM_CB(s, flt_http_end_chunk(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_res; /* on_error */ goto return_bad_res,
if (!ret) /* on_wait */ goto missing_data);
goto missing_data;
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
msg->msg_state = HTTP_MSG_CHUNK_SIZE; msg->msg_state = HTTP_MSG_CHUNK_SIZE;
@ -6916,13 +6900,16 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
goto return_bad_res; goto return_bad_res;
} }
} }
ret = (msg->chunk_len if (msg->chunk_len)
? flt_http_start_chunk(s, msg) FLT_STRM_CB(s, flt_http_start_chunk(s, msg),
: flt_http_last_chunk(s, msg)); /* default_ret */ 1,
if (ret < 0) /* on_error */ goto return_bad_res,
goto return_bad_res; /* on_wait */ goto missing_data);
if (!ret) else
goto missing_data; FLT_STRM_CB(s, flt_http_last_chunk(s, msg),
/* default_ret */ 1,
/* on_error */ goto return_bad_res,
/* on_wait */ goto missing_data);
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS; msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
@ -6939,11 +6926,10 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
goto return_bad_res; goto return_bad_res;
} }
} }
ret2 = flt_http_chunk_trailers(s, msg); FLT_STRM_CB(s, flt_http_chunk_trailers(s, msg),
if (ret2 < 0) /* default_ret */ 1,
goto return_bad_res; /* on_error */ goto return_bad_res,
if (!ret2) /* on_wait */ goto missing_data);
goto missing_data;
msg->next += msg->sol; msg->next += msg->sol;
msg->sol = 0; msg->sol = 0;
if (!ret) if (!ret)
@ -6960,22 +6946,20 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
/* we may have some pending data starting at res->buf->p /* we may have some pending data starting at res->buf->p
* such as a last chunk of data or trailers. * such as a last chunk of data or trailers.
*/ */
ret = flt_http_forward_data(s, msg, msg->next); ret = FLT_STRM_CB(s, flt_http_forward_data(s, msg, msg->next),
if (ret < 0) /* default_ret */ msg->next,
goto return_bad_res; /* on_error */ goto return_bad_res);
b_adv(res->buf, ret); b_adv(res->buf, ret);
msg->next -= ret; msg->next -= ret;
if (msg->sov > 0) if (msg->sov > 0)
msg->sov -= ret; msg->sov -= ret;
if (msg->next) if (msg->next)
goto skip_resync_states; goto skip_resync_states;
ret = flt_http_end(s, msg); FLT_STRM_CB(s, flt_http_end(s, msg),
if (ret < 0) /* default_ret */ 1,
goto return_bad_res; /* on_error */ goto return_bad_res,
if (!ret) /* on_wait */ goto skip_resync_states);
goto skip_resync_states;
msg->msg_state = HTTP_MSG_DONE; msg->msg_state = HTTP_MSG_DONE;
/* fall through */ /* fall through */
@ -7013,15 +6997,14 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
missing_data: missing_data:
/* we may have some pending data starting at res->buf->p */ /* we may have some pending data starting at res->buf->p */
ret = flt_http_forward_data(s, msg, msg->next); ret = FLT_STRM_CB(s, flt_http_forward_data(s, msg, msg->next),
if (ret < 0) /* default_ret */ msg->next,
goto return_bad_res; /* on_error */ goto return_bad_res);
b_adv(res->buf, ret); b_adv(res->buf, ret);
msg->next -= ret; msg->next -= ret;
if (msg->sov > 0) if (msg->sov > 0)
msg->sov -= ret; msg->sov -= ret;
if (!HAS_FILTERS(s))
if (LIST_ISEMPTY(&s->strm_flt.filters))
msg->chunk_len -= channel_forward(res, msg->chunk_len); msg->chunk_len -= channel_forward(res, msg->chunk_len);
if (res->flags & CF_SHUTW) if (res->flags & CF_SHUTW)

View File

@ -1765,107 +1765,95 @@ struct task *process_stream(struct task *t)
} }
if (ana_list & AN_REQ_INSPECT_FE) { if (ana_list & AN_REQ_INSPECT_FE) {
if (!flt_analyze(s, req, AN_REQ_INSPECT_FE)) CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_INSPECT_FE);
break;
if (!tcp_inspect_request(s, req, AN_REQ_INSPECT_FE)) if (!tcp_inspect_request(s, req, AN_REQ_INSPECT_FE))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_INSPECT_FE); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_INSPECT_FE);
} }
if (ana_list & AN_REQ_WAIT_HTTP) { if (ana_list & AN_REQ_WAIT_HTTP) {
if (!flt_analyze(s, req, AN_REQ_WAIT_HTTP)) CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_WAIT_HTTP);
break;
if (!http_wait_for_request(s, req, AN_REQ_WAIT_HTTP)) if (!http_wait_for_request(s, req, AN_REQ_WAIT_HTTP))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_WAIT_HTTP); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_WAIT_HTTP);
} }
if (ana_list & AN_REQ_HTTP_BODY) { if (ana_list & AN_REQ_HTTP_BODY) {
if (!flt_analyze(s, req, AN_REQ_HTTP_BODY)) CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_HTTP_BODY);
break;
if (!http_wait_for_request_body(s, req, AN_REQ_HTTP_BODY)) if (!http_wait_for_request_body(s, req, AN_REQ_HTTP_BODY))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_BODY); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_BODY);
} }
if (ana_list & AN_REQ_HTTP_PROCESS_FE) { if (ana_list & AN_REQ_HTTP_PROCESS_FE) {
if (!flt_analyze(s, req, AN_REQ_HTTP_PROCESS_FE)) CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_HTTP_PROCESS_FE);
break;
if (!http_process_req_common(s, req, AN_REQ_HTTP_PROCESS_FE, sess->fe)) if (!http_process_req_common(s, req, AN_REQ_HTTP_PROCESS_FE, sess->fe))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_FE); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_FE);
} }
if (ana_list & AN_REQ_SWITCHING_RULES) { if (ana_list & AN_REQ_SWITCHING_RULES) {
if (!flt_analyze(s, req, AN_REQ_SWITCHING_RULES)) CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_SWITCHING_RULES);
break;
if (!process_switching_rules(s, req, AN_REQ_SWITCHING_RULES)) if (!process_switching_rules(s, req, AN_REQ_SWITCHING_RULES))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_SWITCHING_RULES); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_SWITCHING_RULES);
} }
if (ana_list & AN_REQ_INSPECT_BE) {
if (!flt_analyze(s, req, AN_REQ_INSPECT_BE))
break;
if (!tcp_inspect_request(s, req, AN_REQ_INSPECT_BE))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_INSPECT_BE);
}
if (ana_list & AN_REQ_HTTP_PROCESS_BE) {
if (!flt_analyze(s, req, AN_REQ_HTTP_PROCESS_BE))
break;
if (!http_process_req_common(s, req, AN_REQ_HTTP_PROCESS_BE, s->be))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_BE);
}
if (ana_list & AN_REQ_HTTP_TARPIT) {
if (!flt_analyze(s, req, AN_REQ_HTTP_TARPIT))
break;
if (!http_process_tarpit(s, req, AN_REQ_HTTP_TARPIT))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_TARPIT);
}
if (ana_list & AN_REQ_SRV_RULES) {
if (!flt_analyze(s, req, AN_REQ_SRV_RULES))
break;
if (!process_server_rules(s, req, AN_REQ_SRV_RULES))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_SRV_RULES);
}
if (ana_list & AN_REQ_HTTP_INNER) {
if (!flt_analyze(s, req, AN_REQ_HTTP_INNER))
break;
if (!http_process_request(s, req, AN_REQ_HTTP_INNER))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_INNER);
}
if (ana_list & AN_REQ_PRST_RDP_COOKIE) {
if (!flt_analyze(s, req, AN_REQ_PRST_RDP_COOKIE))
break;
if (!tcp_persist_rdp_cookie(s, req, AN_REQ_PRST_RDP_COOKIE))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_PRST_RDP_COOKIE);
}
if (ana_list & AN_REQ_STICKING_RULES) {
if (!flt_analyze(s, req, AN_REQ_STICKING_RULES))
break;
if (!process_sticking_rules(s, req, AN_REQ_STICKING_RULES))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_STICKING_RULES);
}
if (ana_list & AN_FLT_START_BE) { if (ana_list & AN_FLT_START_BE) {
if (!flt_start_analyze(s, req, AN_FLT_START_BE)) if (!flt_start_analyze(s, req, AN_FLT_START_BE))
break; break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_FLT_START_BE); UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_FLT_START_BE);
} }
if (ana_list & AN_REQ_INSPECT_BE) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_INSPECT_BE);
if (!tcp_inspect_request(s, req, AN_REQ_INSPECT_BE))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_INSPECT_BE);
}
if (ana_list & AN_REQ_HTTP_PROCESS_BE) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_HTTP_PROCESS_BE);
if (!http_process_req_common(s, req, AN_REQ_HTTP_PROCESS_BE, s->be))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_BE);
}
if (ana_list & AN_REQ_HTTP_TARPIT) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_HTTP_TARPIT);
if (!http_process_tarpit(s, req, AN_REQ_HTTP_TARPIT))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_TARPIT);
}
if (ana_list & AN_REQ_SRV_RULES) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_SRV_RULES);
if (!process_server_rules(s, req, AN_REQ_SRV_RULES))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_SRV_RULES);
}
if (ana_list & AN_REQ_HTTP_INNER) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_HTTP_INNER);
if (!http_process_request(s, req, AN_REQ_HTTP_INNER))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_HTTP_INNER);
}
if (ana_list & AN_REQ_PRST_RDP_COOKIE) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_PRST_RDP_COOKIE);
if (!tcp_persist_rdp_cookie(s, req, AN_REQ_PRST_RDP_COOKIE))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_PRST_RDP_COOKIE);
}
if (ana_list & AN_REQ_STICKING_RULES) {
CALL_FILTER_ANALYZER(flt_analyze, s, req, AN_REQ_STICKING_RULES);
if (!process_sticking_rules(s, req, AN_REQ_STICKING_RULES))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_STICKING_RULES);
}
if (ana_list & AN_FLT_XFER_DATA) { if (ana_list & AN_FLT_XFER_DATA) {
if (!flt_xfer_data(s, req, AN_FLT_XFER_DATA)) if (!flt_xfer_data(s, req, AN_FLT_XFER_DATA))
break; break;
@ -1958,44 +1946,40 @@ struct task *process_stream(struct task *t)
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_START_FE); UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_START_FE);
} }
if (ana_list & AN_RES_INSPECT) { if (ana_list & AN_FLT_START_BE) {
if (!flt_analyze(s, res, AN_RES_INSPECT)) if (!flt_start_analyze(s, res, AN_FLT_START_BE))
break; break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_START_BE);
}
if (ana_list & AN_RES_INSPECT) {
CALL_FILTER_ANALYZER(flt_analyze, s, res, AN_RES_INSPECT);
if (!tcp_inspect_response(s, res, AN_RES_INSPECT)) if (!tcp_inspect_response(s, res, AN_RES_INSPECT))
break; break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_INSPECT); UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_INSPECT);
} }
if (ana_list & AN_RES_WAIT_HTTP) { if (ana_list & AN_RES_WAIT_HTTP) {
if (!flt_analyze(s, res, AN_RES_WAIT_HTTP)) CALL_FILTER_ANALYZER(flt_analyze, s, res, AN_RES_WAIT_HTTP);
break;
if (!http_wait_for_response(s, res, AN_RES_WAIT_HTTP)) if (!http_wait_for_response(s, res, AN_RES_WAIT_HTTP))
break; break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_WAIT_HTTP); UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_WAIT_HTTP);
} }
if (ana_list & AN_RES_STORE_RULES) { if (ana_list & AN_RES_STORE_RULES) {
if (!flt_analyze(s, res, AN_RES_STORE_RULES)) CALL_FILTER_ANALYZER(flt_analyze, s, res, AN_RES_STORE_RULES);
break;
if (!process_store_rules(s, res, AN_RES_STORE_RULES)) if (!process_store_rules(s, res, AN_RES_STORE_RULES))
break; break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_STORE_RULES); UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_STORE_RULES);
} }
if (ana_list & AN_RES_HTTP_PROCESS_BE) { if (ana_list & AN_RES_HTTP_PROCESS_BE) {
if (!flt_analyze(s, res, AN_RES_HTTP_PROCESS_BE)) CALL_FILTER_ANALYZER(flt_analyze, s, res, AN_RES_HTTP_PROCESS_BE);
break;
if (!http_process_res_common(s, res, AN_RES_HTTP_PROCESS_BE, s->be)) if (!http_process_res_common(s, res, AN_RES_HTTP_PROCESS_BE, s->be))
break; break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_HTTP_PROCESS_BE); UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_HTTP_PROCESS_BE);
} }
if (ana_list & AN_FLT_START_BE) {
if (!flt_start_analyze(s, res, AN_FLT_START_BE))
break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_START_BE);
}
if (ana_list & AN_FLT_XFER_DATA) { if (ana_list & AN_FLT_XFER_DATA) {
if (!flt_xfer_data(s, res, AN_FLT_XFER_DATA)) if (!flt_xfer_data(s, res, AN_FLT_XFER_DATA))
break; break;