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.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index d343f05..55622a4 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -8438,6 +8438,10 @@
 			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 @@
 			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 88c3612..b2ceefe 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -391,30 +391,6 @@
 	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 @@
 	} 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 5dacc90..b07065d 100644
--- a/src/flt_http_comp.c
+++ b/src/flt_http_comp.c
@@ -108,13 +108,16 @@
 	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;
 }
@@ -146,19 +149,6 @@
 }
 
 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)
 {
 	struct comp_state *st = filter->ctx;
@@ -725,10 +715,9 @@
 	.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 ab608fe..fdb17b6 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -4191,7 +4191,7 @@
 			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 @@
 	 * 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 @@
 	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 f22c746..1c92e91 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -1164,6 +1164,11 @@
 		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 a274ea4..7c10158 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -755,6 +755,12 @@
 	}
 
 	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 @@
 					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 @@
 					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;