MAJOR: filters/http: Rewrite the HTTP compression as a filter

HTTP compression has been rewritten to use the filter API. This is more a PoC
than other thing for now. It allocates memory to work. So, if only for that, it
should be rewritten.

In the mean time, the implementation has been refactored to allow its use with
other filters. However, there are limitations that should be respected:

  - No filter placed after the compression one is allowed to change input data
    (in 'http_data' callback).
  - No filter placed before the compression one is allowed to change forwarded
    data (in 'http_forward_data' callback).

For now, these limitations are informal, so you should be careful when you use
several filters.

About the configuration, 'compression' keywords are still supported and must be
used to configure the HTTP compression behavior. In absence of a 'filter' line
for the compression filter, it is added in the filter chain when the first
compression' line is parsed. This is an easy way to do when you do not use other
filters. But another filter exists, an error is reported so that the user must
explicitly declare the filter.

For example:

  listen tst
      ...
      compression algo gzip
      compression offload
      ...
      filter flt_1
      filter compression
      filter flt_2
      ...
diff --git a/src/filters.c b/src/filters.c
index b4af33b..974c742 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -24,6 +24,7 @@
 
 #include <proto/compression.h>
 #include <proto/filters.h>
+#include <proto/flt_http_comp.h>
 #include <proto/proto_http.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
@@ -259,6 +260,7 @@
 		if (filter->ops->check)
 			err += filter->ops->check(proxy, filter);
 	}
+	err += check_legacy_http_comp_flt(proxy);
 	return err;
 }
 
@@ -279,6 +281,60 @@
 	}
 }
 
+/* Attaches a filter to a stream. Returns -1 if an error occurs, 0 otherwise. */
+static int
+flt_stream_add_filter(struct stream *s, struct filter *filter,
+			  int is_backend)
+{
+	struct filter *f = pool_alloc2(pool2_filter);
+	if (!f) /* not enough memory */
+		return -1;
+	memset(f, 0, sizeof(*f));
+	f->id    = filter->id;
+	f->ops   = filter->ops;
+	f->conf  = filter->conf;
+	f->is_backend_filter = is_backend;
+	LIST_ADDQ(&s->strm_flt.filters, &f->list);
+	return 0;
+}
+
+/*
+ * Called when a stream is created. It attaches all frontend filters to the
+ * stream. Returns -1 if an error occurs, 0 otherwise.
+ */
+int
+flt_stream_init(struct stream *s)
+{
+	struct filter *filter;
+
+	LIST_INIT(&s->strm_flt.filters);
+	memset(s->strm_flt.current, 0, sizeof(s->strm_flt.current));
+	list_for_each_entry(filter, &strm_fe(s)->filters, list) {
+		if (flt_stream_add_filter(s, filter, 0) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/*
+ * Called when a stream is closed or when analyze ends (For an HTTP stream, this
+ * happens after each request/response exchange). When analyze ends, backend
+ * filters are removed. When the stream is closed, all filters attached to the
+ * stream are removed.
+ */
+void
+flt_stream_release(struct stream *s, int only_backend)
+{
+	struct filter *filter, *back;
+
+	list_for_each_entry_safe(filter, back, &s->strm_flt.filters, list) {
+		if (!only_backend || filter->is_backend_filter) {
+			LIST_DEL(&filter->list);
+			pool_free2(pool2_filter, filter);
+		}
+	}
+}
+
 /*
  * Calls 'stream_start' for all filters attached to a stream. This happens when
  * the stream is created, just after calling flt_stream_init
@@ -311,6 +367,26 @@
 	}
 }
 
+/*
+ * Called when a backend is set for a stream. If the frontend and the backend
+ * are the same, this function does nothing. Else it attaches all backend
+ * filters to the stream. Returns -1 if an error occurs, 0 otherwise.
+ */
+int
+flt_set_stream_backend(struct stream *s, struct proxy *be)
+{
+	struct filter *filter;
+
+	if (strm_fe(s) == be)
+		return 0;
+
+	list_for_each_entry(filter, &be->filters, list) {
+		if (flt_stream_add_filter(s, filter, 1) < 0)
+			return -1;
+	}
+	return 0;
+}
+
 int
 flt_http_headers(struct stream *s, struct http_msg *msg)
 {
@@ -691,8 +767,6 @@
 	/* Check if 'channel_end_analyze' callback has been called for the
 	 * request and the response. */
 	if (!(s->req.analysers & AN_FLT_END) && !(s->res.analysers & AN_FLT_END)) {
-		struct filter *filter, *back;
-
 		/* When we are waiting for a new request, so we must reset
 		 * stream analyzers. The input must not be closed the request
 		 * channel, else it is useless to wait. */
@@ -701,12 +775,8 @@
 			s->res.analysers = 0;
 		}
 
-		list_for_each_entry_safe(filter, back, &s->strm_flt.filters, list) {
-			if (filter->is_backend_filter) {
-				LIST_DEL(&filter->list);
-				pool_free2(pool2_filter, filter);
-			}
-		}
+		/* Remove backend filters from the list */
+		flt_stream_release(s, 1);
 	}
 	else if (ret) {
 		/* Analyzer ends only for one channel. So wake up the stream to