mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-04 12:41:00 +02:00
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:
parent
2fb2880caf
commit
309c6418b0
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
|
||||
18
src/stream.c
18
src/stream.c
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user