MEDIUM: filters: Replace filter_http_headers callback by an analyzer

This new analyzer will be called for each HTTP request/response, before the
parsing of the body. It is identified by AN_FLT_HTTP_HDRS.

Special care was taken about the following condition :

  * the frontend is a TCP proxy
  * filters are defined in the frontend section
  * the selected backend is a HTTP proxy

So, this patch explicitly add AN_FLT_HTTP_HDRS analyzer on the request and the
response channels when the backend is a HTTP proxy and when there are filters
attatched on the stream.
This patch simplifies http_request_forward_body and http_response_forward_body
functions.
This commit is contained in:
Christopher Faulet 2015-12-02 09:57:32 +01:00 committed by Willy Tarreau
parent 2fb2880caf
commit 309c6418b0
9 changed files with 85 additions and 82 deletions

View File

@ -91,17 +91,17 @@ int flt_set_stream_backend(struct stream *s, struct proxy *be);
int flt_stream_init(struct stream *s);
void flt_stream_release(struct stream *s, int only_backend);
int flt_http_headers(struct stream *s, struct http_msg *msg);
int flt_http_data(struct stream *s, struct http_msg *msg);
int flt_http_chunk_trailers(struct stream *s, struct http_msg *msg);
int flt_http_end(struct stream *s, struct http_msg *msg);
void flt_http_reset(struct stream *s, struct http_msg *msg);
void flt_http_reply(struct stream *s, short status, const struct chunk *msg);
int flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len);
void flt_http_reset(struct stream *s, struct http_msg *msg);
void flt_http_reply(struct stream *s, short status, const struct chunk *msg);
int flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
int flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
int flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit);
int flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
int flt_xfer_data(struct stream *s, struct channel *chn, unsigned int an_bit);

View File

@ -161,6 +161,7 @@
#define AN_FLT_START_BE 0x02000000
#define AN_FLT_END 0x04000000
#define AN_FLT_XFER_DATA 0x08000000
#define AN_FLT_HTTP_HDRS 0x10000000
#define AN_FLT_ALL_FE 0x0d000000
#define AN_FLT_ALL_BE 0x0e000000

View File

@ -99,12 +99,6 @@ struct flt_kw_list {
* it needs to wait, any other value otherwise.
*
*
* - http_headers : Called just before headers sending and parsing of
* the body. At this step, headers are fully parsed
* and the processing on it is finished.
* Returns a negative value if an error occurs, 0 if
* it needs to read more data (or to wait for some
* reason), any other value otherwise.
* - http_data : Called when unparsed body data are available.
* Returns a negative value if an error occurs, else
* the number of consumed bytes.
@ -160,17 +154,16 @@ struct flt_ops {
/*
* 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, struct http_msg *msg);
int (*http_end) (struct stream *s, struct filter *f, struct http_msg *msg);
void (*http_reset) (struct stream *s, struct filter *f, struct http_msg *msg);
void (*http_reply) (struct stream *s, struct filter *f, short status,
const struct chunk *msg);
int (*http_forward_data) (struct stream *s, struct filter *f, struct http_msg *msg,
unsigned int len);
void (*http_reset) (struct stream *s, struct filter *f, struct http_msg *msg);
void (*http_reply) (struct stream *s, struct filter *f, short status,
const struct chunk *msg);
/*
* TCP callbacks
*/

View File

@ -8438,6 +8438,10 @@ out_uri_auth_compat:
if (!LIST_ISEMPTY(&curproxy->filters)) {
curproxy->fe_req_ana |= AN_FLT_ALL_FE;
curproxy->fe_rsp_ana |= AN_FLT_ALL_FE;
if (curproxy->mode == PR_MODE_HTTP) {
curproxy->fe_req_ana |= AN_FLT_HTTP_HDRS;
curproxy->fe_rsp_ana |= AN_FLT_HTTP_HDRS;
}
}
}
@ -8464,6 +8468,10 @@ out_uri_auth_compat:
if (!LIST_ISEMPTY(&curproxy->filters)) {
curproxy->be_req_ana |= AN_FLT_ALL_BE;
curproxy->be_rsp_ana |= AN_FLT_ALL_BE;
if (curproxy->mode == PR_MODE_HTTP) {
curproxy->be_req_ana |= AN_FLT_HTTP_HDRS;
curproxy->be_rsp_ana |= AN_FLT_HTTP_HDRS;
}
}
}
}

View File

@ -391,30 +391,6 @@ flt_set_stream_backend(struct stream *s, struct proxy *be)
return 0;
}
int
flt_http_headers(struct stream *s, struct http_msg *msg)
{
struct filter *filter;
int ret = 1;
RESUME_FILTER_LOOP(s, msg->chn) {
if (filter->ops && filter->ops->http_headers) {
ret = filter->ops->http_headers(s, filter, msg);
if (ret <= 0)
BREAK_EXECUTION(s, msg->chn, end);
}
} RESUME_FILTER_END;
/* We increase FLT_NXT offset after all processing on headers because
* any filter can alter them. So the definitive size of headers
* (msg->sov) is only known when all filters have been called. */
list_for_each_entry(filter, &s->strm_flt.filters, list) {
FLT_NXT(filter, msg->chn) = msg->sov;
}
end:
return ret;
}
/*
* Calls 'http_data' callback for all "data" filters attached to a stream. This
* function is called when incoming data are available (excluding chunks
@ -659,8 +635,41 @@ flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
} RESUME_FILTER_END;
check_result:
ret = handle_analyzer_result(s, chn, 0, ret);
return ret;
return handle_analyzer_result(s, chn, 0, ret);
}
/*
* This function do the same that the previsous one, but for the
* AN_FLT_HTTP_HDRS analyzer. The difference is what is done when all filters
* have been called. Returns 0 if an error occurs or if it needs to wait, any
* other value otherwise.
*/
int
flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit)
{
struct filter *filter;
struct http_msg *msg;
int ret = 1;
RESUME_FILTER_LOOP(s, chn) {
if (filter->ops->channel_analyze) {
ret = filter->ops->channel_analyze(s, filter, chn, an_bit);
if (ret <= 0)
BREAK_EXECUTION(s, chn, check_result);
}
} RESUME_FILTER_END;
/* We increase next offset of all "data" filters after all processing on
* headers because any filter can alter them. So the definitive size of
* headers (msg->sov) is only known when all filters have been
* called. */
msg = ((chn->flags & CF_ISRESP) ? &s->txn->rsp : &s->txn->req);
list_for_each_entry(filter, &s->strm_flt.filters, list) {
FLT_NXT(filter, msg->chn) = msg->sov;
}
check_result:
return handle_analyzer_result(s, chn, an_bit, ret);
}
/*

View File

@ -108,13 +108,16 @@ comp_analyze(struct stream *s, struct filter *filter, struct channel *chn,
if (!strm_fe(s)->comp && !s->be->comp)
goto end;
switch (an_bit) {
case AN_RES_HTTP_PROCESS_BE:
if (an_bit == AN_FLT_HTTP_HDRS) {
if (!(chn->flags & CF_ISRESP))
select_compression_request_header(st, s, &s->txn->req);
else {
select_compression_response_header(st, s, &s->txn->rsp);
if (st->comp_algo)
st->sov = s->txn->rsp.sov;
break;
}
}
end:
return 1;
}
@ -145,19 +148,6 @@ comp_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
return 1;
}
static int
comp_http_headers(struct stream *s, struct filter *filter,
struct http_msg *msg)
{
struct comp_state *st = filter->ctx;
if (strm_fe(s)->comp || s->be->comp) {
if (!(msg->chn->flags & CF_ISRESP))
select_compression_request_header(st, s, msg);
}
return 1;
}
static int
comp_http_data(struct stream *s, struct filter *filter, struct http_msg *msg)
{
@ -725,10 +715,9 @@ struct flt_ops comp_ops = {
.channel_analyze = comp_analyze,
.channel_end_analyze = comp_end_analyze,
.http_headers = comp_http_headers,
.http_data = comp_http_data,
.http_chunk_trailers = comp_http_chunk_trailers,
.http_forward_data = comp_http_forward_data,
.http_data = comp_http_data,
.http_chunk_trailers = comp_http_chunk_trailers,
.http_forward_data = comp_http_forward_data,
};
static int

View File

@ -4191,7 +4191,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
s->flags |= SF_FINST_R;
/* enable the minimally required analyzers to handle keep-alive and compression on the HTTP response */
req->analysers &= (AN_REQ_HTTP_BODY | AN_FLT_END);
req->analysers &= (AN_REQ_HTTP_BODY | AN_FLT_HTTP_HDRS | AN_FLT_END);
req->analysers &= ~AN_FLT_XFER_DATA;
req->analysers |= AN_REQ_HTTP_XFER_BODY;
goto done;
@ -5462,16 +5462,6 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
* an "Expect: 100-continue" header.
*/
if (msg->msg_state == HTTP_MSG_BODY) {
/* we have msg->sov which points to the first byte of message
* body, and req->buf.p still points to the beginning of the
* message. We forward the headers now, as we don't need them
* anymore, and we want to flush them.
*/
FLT_STRM_CB(s, flt_http_headers(s, msg),
/* default_ret */ 1,
/* on_error */ goto return_bad_req,
/* on_wait */ return 0);
/* The previous analysers guarantee that the state is somewhere
* between MSG_BODY and the first MSG_DATA. So msg->sol and
* msg->next are always correct.
@ -6774,16 +6764,6 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
channel_auto_close(res);
if (msg->msg_state == HTTP_MSG_BODY) {
/* we have msg->sov which points to the first byte of message
* body, and res->buf.p still points to the beginning of the
* message. We forward the headers now, as we don't need them
* anymore, and we want to flush them.
*/
FLT_STRM_CB(s, flt_http_headers(s, msg),
/* default_ret */ 1,
/* on_error */ goto return_bad_res,
/* on_wait */ return 0);
/* The previous analysers guarantee that the state is somewhere
* between MSG_BODY and the first MSG_DATA. So msg->sol and
* msg->next are always correct.

View File

@ -1164,6 +1164,11 @@ int stream_set_backend(struct stream *s, struct proxy *be)
http_init_txn(s);
}
/* Be sure to filter request headers if the backend is an HTTP proxy and
* if there are filters attached to the stream. */
if (s->be->mode == PR_MODE_HTTP && HAS_FILTERS(s))
s->req.analysers |= AN_FLT_HTTP_HDRS;
if (s->txn) {
if (be->options2 & PR_O2_RSPBUG_OK)
s->txn->rsp.err_pos = -1; /* let buggy responses pass */

View File

@ -755,6 +755,12 @@ static void sess_establish(struct stream *s)
}
rep->analysers |= strm_fe(s)->fe_rsp_ana | s->be->be_rsp_ana;
/* Be sure to filter response headers if the backend is an HTTP proxy
* and if there are filters attached to the stream. */
if (s->be->mode == PR_MODE_HTTP && HAS_FILTERS(s))
rep->analysers |= AN_FLT_HTTP_HDRS;
rep->flags |= CF_READ_ATTACHED; /* producer is now attached */
if (req->flags & CF_WAKE_CONNECT) {
req->flags |= CF_WAKE_ONCE;
@ -1854,6 +1860,12 @@ struct task *process_stream(struct task *t)
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_STICKING_RULES);
}
if (ana_list & AN_FLT_HTTP_HDRS) {
if (!flt_analyze_http_headers(s, req, AN_FLT_HTTP_HDRS))
break;
UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_FLT_HTTP_HDRS);
}
if (ana_list & AN_FLT_XFER_DATA) {
if (!flt_xfer_data(s, req, AN_FLT_XFER_DATA))
break;
@ -1980,6 +1992,12 @@ struct task *process_stream(struct task *t)
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_HTTP_PROCESS_BE);
}
if (ana_list & AN_FLT_HTTP_HDRS) {
if (!flt_analyze_http_headers(s, res, AN_FLT_HTTP_HDRS))
break;
UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_HTTP_HDRS);
}
if (ana_list & AN_FLT_XFER_DATA) {
if (!flt_xfer_data(s, res, AN_FLT_XFER_DATA))
break;