diff --git a/include/proto/filters.h b/include/proto/filters.h index 0eb69a2cd..8eaaf3ad8 100644 --- a/include/proto/filters.h +++ b/include/proto/filters.h @@ -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); diff --git a/include/types/channel.h b/include/types/channel.h index e43e8ebff..b31f493a0 100644 --- a/include/types/channel.h +++ b/include/types/channel.h @@ -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 diff --git a/include/types/filters.h b/include/types/filters.h index e3a091dd1..4bfa1c22b 100644 --- a/include/types/filters.h +++ b/include/types/filters.h @@ -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 */ diff --git a/src/cfgparse.c b/src/cfgparse.c index d343f0515..55622a425 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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; + } } } } diff --git a/src/filters.c b/src/filters.c index 88c361246..b2ceefe2c 100644 --- a/src/filters.c +++ b/src/filters.c @@ -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); } /* diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c index 5dacc90d7..b07065d7a 100644 --- a/src/flt_http_comp.c +++ b/src/flt_http_comp.c @@ -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 diff --git a/src/proto_http.c b/src/proto_http.c index ab608fedf..fdb17b6cc 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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. diff --git a/src/proxy.c b/src/proxy.c index f22c7462f..1c92e91f8 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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 */ diff --git a/src/stream.c b/src/stream.c index a274ea450..7c10158a0 100644 --- a/src/stream.c +++ b/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;