MAJOR: filters: Adapt filters API to be compatible with the HTX represenation

First, to be called on HTX streams, a filter must explicitly be declared as
compatible by setting the flag STRM_FLT_FL_HAS_FILTERS on the filter's config at
HAProxy startup. This flag is checked when a filter implementation is attached
to a stream.

Then, some changes have been made on HTTP callbacks. The callback http_payload
has been added to filter HTX data. It will be called on HTX streams only. It
replaces the callbacks http_data, http_chunk_trailers and http_forward_data,
called on legacy HTTP streams only and marked as deprecated. The documention
(once updated)) will give all information to implement this new callback. Other
HTTP callbacks will be called for HTX and HTTP legacy streams. So it is the
filter's responsibility to known which kind of data it handles. The macro
IS_HTX_STRM should be used in such cases.

There is at least a noticeable changes in the way data are forwarded. In HTX,
after the call to the callback http_headers, all the headers are considered as
forwarded. So, in http_payload, only the body and eventually the trailers will
be filtered.
diff --git a/include/proto/filters.h b/include/proto/filters.h
index 2ad0f49..346d8a0 100644
--- a/include/proto/filters.h
+++ b/include/proto/filters.h
@@ -36,6 +36,9 @@
 /* Useful macros to access per-channel values. It can be safely used inside
  * filters. */
 #define CHN_IDX(chn)     (((chn)->flags & CF_ISRESP) == CF_ISRESP)
+#define FLT_STRM_OFF(s, chn) (strm_flt(s)->offset[CHN_IDX(chn)])
+#define FLT_OFF(flt, chn) ((flt)->offset[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_req_nxt(flt) ((flt)->next[0])
@@ -103,9 +106,11 @@
 void flt_stream_release(struct stream *s, int only_backend);
 void flt_stream_check_timeouts(struct stream *s);
 
+int  flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len);
+int  flt_http_end(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);
 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);
@@ -219,5 +224,26 @@
 	}
 }
 
+/* This function must be called when a filter alter payload data. It updates
+ * offsets of all previous filters and the offset of the stream. Do not call
+ * this function when a filter change the size of payload data leads to an
+ * undefined behavior.
+ *
+ * This is the filter's responsiblitiy to update data itself..
+ */
+static inline void
+flt_update_offsets(struct filter *filter, struct channel *chn, int len)
+{
+	struct stream *s = chn_strm(chn);
+	struct filter *f;
+
+	list_for_each_entry(f, &strm_flt(s)->filters, list) {
+		if (f == filter)
+			break;
+		if (IS_DATA_FILTER(filter, chn))
+			FLT_OFF(f, chn) += len;
+	}
+}
+
 
 #endif /* _PROTO_FILTERS_H */
diff --git a/include/types/filters.h b/include/types/filters.h
index c460e79..f52592d 100644
--- a/include/types/filters.h
+++ b/include/types/filters.h
@@ -120,14 +120,17 @@
  *                          headers was parsed and analyzed.
  *                          Returns a negative value if an error occurs, 0 if
  *                          it needs to wait, any other value otherwise.
+ *  - http_payload        : Called when some data can be consumed.
+ *                          Returns a negative value if an error occurs, else
+ *                          the number of forwarded bytes.
  *  - http_data           : Called when unparsed body data are available.
  *                          Returns a negative value if an error occurs, else
- *                          the number of consumed bytes.
+ *                          the number of consumed bytes. [DEPRECATED]
  *  - http_chunk_trailers : Called when part of trailer headers of a
  *                          chunk-encoded request/response are ready to be
  *                          processed.
  *                          Returns a negative value if an error occurs, any
- *                          other value otherwise.
+ *                          other value otherwise. [DEPRECATED]
  *  - http_end            : Called when all the request/response has been
  *                          processed and all body data has been forwarded.
  *                          Returns a negative value if an error occurs, 0 if
@@ -143,7 +146,7 @@
  *                          Returns nothing.
  *  - http_forward_data   : Called when some data can be consumed.
  *                          Returns a negative value if an error occurs, else
- *                          the number of forwarded bytes.
+ *                          the number of forwarded bytes. [DEPRECATED]
  *  - tcp_data            : Called when unparsed data are available.
  *                          Returns a negative value if an error occurs, else
  *                          the number of consumed bytes.
@@ -181,10 +184,12 @@
 	 * 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_payload)       (struct stream *s, struct filter *f, struct http_msg *msg,
+				    unsigned int offset, unsigned int len);
 	int  (*http_end)           (struct stream *s, struct filter *f, struct http_msg *msg);
-	int  (*http_forward_data)  (struct stream *s, struct filter *f, struct http_msg *msg,
+	int  (*http_data)          (struct stream *s, struct filter *f, struct http_msg *msg); // DEPRECATED
+	int  (*http_chunk_trailers)(struct stream *s, struct filter *f, struct http_msg *msg); // DEPRECATED
+	int  (*http_forward_data)  (struct stream *s, struct filter *f, struct http_msg *msg,  // DEPRECATED
 				    unsigned int len);
 
 	void (*http_reset)         (struct stream *s, struct filter *f, struct http_msg *msg);
@@ -199,12 +204,14 @@
 				 unsigned int len);
 };
 
+/* Flags set on a filter config */
+#define FLT_CFG_FL_HTX    0x00000001  /* The filter can filter HTX streams */
+
 /* Flags set on a filter instance */
 #define FLT_FL_IS_BACKEND_FILTER  0x0001 /* The filter is a backend filter */
 #define FLT_FL_IS_REQ_DATA_FILTER 0x0002 /* The filter will parse data on the request channel */
 #define FLT_FL_IS_RSP_DATA_FILTER 0x0004 /* The filter will parse data on the response channel */
 
-
 /* Flags set on the stream, common to all filters attached to its stream */
 #define STRM_FLT_FL_HAS_FILTERS          0x0001 /* The stream has at least one filter */
 
@@ -217,6 +224,7 @@
 	struct flt_ops *ops;  /* The filter callbacks */
 	void           *conf; /* The filter configuration */
 	struct list     list; /* Next filter for the same proxy */
+	unsigned int    flags; /* FLT_CFG_FL_* */
 };
 
 /*
@@ -236,6 +244,7 @@
 	                                    * 0: request channel, 1: response channel */
 	unsigned int    fwd[2];            /* Offset, relative to buf->p, to the next byte to forward for a specific channel
 	                                    * 0: request channel, 1: response channel */
+	unsigned long long offset[2];
 	unsigned int    pre_analyzers;     /* bit field indicating analyzers to pre-process */
 	unsigned int    post_analyzers;    /* bit field indicating analyzers to post-process */
 	struct list     list;              /* Next filter for the same proxy/stream */
@@ -253,6 +262,7 @@
 	unsigned short flags;                 /* STRM_FL_* */
 	unsigned char  nb_req_data_filters;   /* Number of data filters registered on the request channel */
 	unsigned char  nb_rsp_data_filters;   /* Number of data filters registered on the response channel */
+	unsigned long long offset[2];
 };
 
 #endif /* _TYPES_FILTERS_H */
diff --git a/src/filters.c b/src/filters.c
index d29a0c0..2b82389 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -27,6 +27,8 @@
 #include <proto/compression.h>
 #include <proto/filters.h>
 #include <proto/flt_http_comp.h>
+#include <proto/http_htx.h>
+#include <proto/htx.h>
 #include <proto/proto_http.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
@@ -335,15 +337,6 @@
 			err += fconf->ops->check(proxy, fconf);
 	}
 	err += check_legacy_http_comp_flt(proxy);
-
-	if (!LIST_ISEMPTY(&proxy->filter_configs) &&
-	    (proxy->options2 & PR_O2_USE_HTX)) {
-		ha_alert("config: %s '%s' : filters cannot be used when "
-			 "the HTX internal representation is enabled.\n",
-			 proxy_type_str(proxy), proxy->id);
-		err++;
-	}
-
 	return err;
 }
 
@@ -394,8 +387,12 @@
 static int
 flt_stream_add_filter(struct stream *s, struct flt_conf *fconf, unsigned int flags)
 {
-	struct filter *f = pool_alloc(pool_head_filter);
+	struct filter *f;
 
+	if ((strm_fe(s)->options2 & PR_O2_USE_HTX) && !(fconf->flags & FLT_CFG_FL_HTX))
+		return 0;
+
+	f = pool_alloc(pool_head_filter);
 	if (!f) /* not enough memory */
 		return -1;
 	memset(f, 0, sizeof(*f));
@@ -540,6 +537,8 @@
  * filters and adjusts available data to be sure that a filter cannot parse more
  * data than its predecessors. A filter can choose to not consume all available
  * data. Returns -1 if an error occurs, the number of consumed bytes otherwise.
+ *
+ * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS
  */
 int
 flt_http_data(struct stream *s, struct http_msg *msg)
@@ -602,6 +601,8 @@
  * analyzers. Filters can know how much data were parsed by the HTTP parsing
  * until the last call with the msg->sol value. Returns a negative value if an
  * error occurs, any other value otherwise.
+ *
+ * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS
  */
 int
 flt_http_chunk_trailers(struct stream *s, struct http_msg *msg)
@@ -640,6 +641,10 @@
  * functions is called when all data were parsed and forwarded. 'http_end'
  * callback is resumable, so this function returns a negative value if an error
  * occurs, 0 if it needs to wait for some reason, any other value otherwise.
+ *
+ * Be carefull, this function can be called from the HTTP legacy analyzers or
+ * from HTX analyzers. If your filter is compatible with the two modes, use
+ * IS_HTX_STRM macro on the stream.
  */
 int
 flt_http_end(struct stream *s, struct http_msg *msg)
@@ -660,6 +665,10 @@
 /*
  * Calls 'http_reset' callback for all filters attached to a stream. This
  * happens when a 100-continue response is received.
+ *
+ * Be carefull, this function can be called from the HTTP legacy analyzers or
+ * from HTX analyzers. If your filter is compatible with the two modes, use
+ * IS_HTX_STRM macro on the stream.
  */
 void
 flt_http_reset(struct stream *s, struct http_msg *msg)
@@ -675,6 +684,10 @@
 /*
  * Calls 'http_reply' callback for all filters attached to a stream when HA
  * decides to stop the HTTP message processing.
+ *
+ * Be carefull, this function can be called from the HTTP legacy analyzers or
+ * from HTX analyzers. If your filter is compatible with the two modes, use
+ * IS_HTX_STRM macro on the stream.
  */
 void
 flt_http_reply(struct stream *s, short status, const struct buffer *msg)
@@ -688,13 +701,15 @@
 }
 
 /*
- * Calls 'http_forward_data' callback for all "data" filters attached to a
- * stream. This function is called when some data can be forwarded in the
+ * Calls 'http_forward_data' callback for all "data" filters attached to a HTTP
+ * legacy stream. This function is called when some data can be forwarded in the
  * AN_REQ_HTTP_XFER_BODY and AN_RES_HTTP_XFER_BODY analyzers. It takes care to
  * update the forward offset of filters and adjusts "forwardable" data to be
  * sure that a filter cannot forward more data than its predecessors. A filter
  * can choose to not forward all parsed data. Returns a negative value if an
  * error occurs, else the number of forwarded bytes.
+ *
+ * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS
  */
 int
 flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len)
@@ -750,6 +765,48 @@
 }
 
 /*
+ * Calls 'http_payload' callback for all "data" filters attached to a
+ * stream. This function is called when some data can be forwarded in the
+ * AN_REQ_HTTP_XFER_BODY and AN_RES_HTTP_XFER_BODY analyzers. It takes care to
+ * update the filters and the stream offset to be sure that a filter cannot
+ * forward more data than its predecessors. A filter can choose to not forward
+ * all data. Returns a negative value if an error occurs, else the number of
+ * forwarded bytes.
+ *
+ * Be carefull, this callback is only called from HTX analyzers. So the
+ * channel's buffer must be considered as an HTX structured. Of course, your
+ * filter must support HTX streams.
+ */
+int
+flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len)
+{
+	struct filter *filter;
+	unsigned long long *strm_off = &FLT_STRM_OFF(s, msg->chn);
+	unsigned int out = co_data(msg->chn);
+	int ret = len - out;
+
+	list_for_each_entry(filter, &strm_flt(s)->filters, list) {
+		/* Call "data" filters only */
+		if (!IS_DATA_FILTER(filter, msg->chn))
+			continue;
+		if (FLT_OPS(filter)->http_payload) {
+			unsigned long long *flt_off = &FLT_OFF(filter, msg->chn);
+			unsigned int offset = *flt_off - *strm_off;
+
+			ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, ret - offset);
+			if (ret < 0)
+				goto end;
+			*flt_off += ret;
+			ret += offset;
+		}
+	}
+	*strm_off += ret;
+
+ end:
+	return ret;
+}
+
+/*
  * Calls 'channel_start_analyze' callback for all filters attached to a
  * stream. This function is called when we start to analyze a request or a
  * response. For frontend filters, it is called before all other analyzers. For
@@ -851,6 +908,10 @@
  * This function is the AN_REQ/RES_FLT_HTTP_HDRS analyzer, used to filter HTTP
  * headers or a request or a response. Returns 0 if an error occurs or if it
  * needs to wait, any other value otherwise.
+ *
+ * Be carefull, this function can be called from the HTTP legacy analyzers or
+ * from HTX analyzers. If your filter is compatible with the two modes, use
+ * IS_HTX_STRM macro on the stream.
  */
 int
 flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit)
@@ -868,15 +929,28 @@
 		}
 	} 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. */
-	list_for_each_entry(filter, &strm_flt(s)->filters, list) {
-		/* Handle "data" filters only */
-		if (!IS_DATA_FILTER(filter, chn))
-			continue;
-		FLT_NXT(filter, chn) = msg->sov;
+	if (IS_HTX_STRM(s)) {
+		struct htx *htx = htx_from_buf(&chn->buf);
+		int32_t pos;
+
+		for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) {
+			struct htx_blk *blk = htx_get_blk(htx, pos);
+			c_adv(chn, htx_get_blksz(blk));
+			if (htx_get_blk_type(blk) == HTX_BLK_EOH)
+				break;
+		}
+	}
+	else {
+		/* 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. */
+		list_for_each_entry(filter, &strm_flt(s)->filters, list) {
+			/* Handle "data" filters only */
+			if (!IS_DATA_FILTER(filter, chn))
+				continue;
+			FLT_NXT(filter, chn) = msg->sov;
+		}
 	}
 
  check_result: