MEDIUM: compression: use pool for comp_ctx

Use pool for comp_ctx, it is allocated during the comp_algo->init().
The allocation of comp_ctx is accounted for in the zlib_memory_available.
diff --git a/include/proto/compression.h b/include/proto/compression.h
index cfab62a..1614edd 100644
--- a/include/proto/compression.h
+++ b/include/proto/compression.h
@@ -33,22 +33,21 @@
 int http_compression_buffer_add_data(struct session *s, struct buffer *in, struct buffer *out);
 int http_compression_buffer_end(struct session *s, struct buffer **in, struct buffer **out, int end);
 
-int identity_init(struct comp_ctx *comp_ctx, int level);
+int identity_init(struct comp_ctx **comp_ctx, int level);
 int identity_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
 int identity_flush(struct comp_ctx *comp_ctx, struct buffer *out, int flag);
 int identity_reset(struct comp_ctx *comp_ctx);
-int identity_end(struct comp_ctx *comp_ctx);
+int identity_end(struct comp_ctx **comp_ctx);
 
 
 #ifdef USE_ZLIB
-
-int deflate_init(struct comp_ctx *comp_ctx, int level);
+int deflate_init(struct comp_ctx **comp_ctx, int level);
 int deflate_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
 int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out, int flag);
 int deflate_reset(struct comp_ctx *comp_ctx);
-int deflate_end(struct comp_ctx *comp_ctx);
+int deflate_end(struct comp_ctx **comp_ctx);
 
-int gzip_init(struct comp_ctx *comp_ctx, int level);
+int gzip_init(struct comp_ctx **comp_ctx, int level);
 #endif /* USE_ZLIB */
 
 #endif /* _PROTO_COMP_H */
diff --git a/include/types/compression.h b/include/types/compression.h
index cf56e45..e4b1f27 100644
--- a/include/types/compression.h
+++ b/include/types/compression.h
@@ -50,11 +50,11 @@
 struct comp_algo {
 	char *name;
 	int name_len;
-	int (*init)(struct comp_ctx *comp_ctx, int level);
+	int (*init)(struct comp_ctx **comp_ctx, int level);
 	int (*add_data)(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
 	int (*flush)(struct comp_ctx *comp_ctx, struct buffer *out, int flag);
 	int (*reset)(struct comp_ctx *comp_ctx);
-	int (*end)(struct comp_ctx *comp_ctx);
+	int (*end)(struct comp_ctx **comp_ctx);
 	struct comp_algo *next;
 };
 
diff --git a/include/types/session.h b/include/types/session.h
index 284b7e8..e0d3c22 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -159,7 +159,7 @@
 	void (*srv_error)(struct session *s,	/* the function to call upon unrecoverable server errors (or NULL) */
 			  struct stream_interface *si);
 	unsigned int uniq_id;			/* unique ID used for the traces */
-	struct comp_ctx comp_ctx;		/* HTTP compression context */
+	struct comp_ctx *comp_ctx;		/* HTTP compression context */
 	struct comp_algo *comp_algo;		/* HTTP compression algorithm if not NULL */
 	char *unique_id;			/* custom unique ID */
 };
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 10fc4a6..d4b3d91 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -5442,7 +5442,7 @@
 
 		if (!strcmp(args[1], "algo")) {
 			int cur_arg;
-			struct comp_ctx ctx;
+			struct comp_ctx *ctx;
 
 			cur_arg = 2;
 			if (!*args[cur_arg]) {
diff --git a/src/compression.c b/src/compression.c
index 72c9996..c1e1afd 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -37,6 +37,9 @@
 
 #ifdef USE_ZLIB
 
+static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size);
+static void free_zlib(void *opaque, void *ptr);
+
 /* zlib allocation  */
 static struct pool_head *zlib_pool_deflate_state = NULL;
 static struct pool_head *zlib_pool_window = NULL;
@@ -46,9 +49,10 @@
 
 static long long zlib_memory_available = -1;
 
-
 #endif
 
+static struct pool_head *pool_comp_ctx = NULL;
+
 
 const struct comp_algo comp_algos[] =
 {
@@ -187,15 +191,15 @@
 
 	left = data_process_len - bi_contig_data(in);
 	if (left <= 0) {
-		consumed_data += ret = s->comp_algo->add_data(&s->comp_ctx, bi_ptr(in), data_process_len, out);
+		consumed_data += ret = s->comp_algo->add_data(s->comp_ctx, bi_ptr(in), data_process_len, out);
 		if (ret < 0)
 			return -1;
 
 	} else {
-		consumed_data += ret = s->comp_algo->add_data(&s->comp_ctx, bi_ptr(in), bi_contig_data(in), out);
+		consumed_data += ret = s->comp_algo->add_data(s->comp_ctx, bi_ptr(in), bi_contig_data(in), out);
 		if (ret < 0)
 			return -1;
-		consumed_data += ret = s->comp_algo->add_data(&s->comp_ctx, in->data, left, out);
+		consumed_data += ret = s->comp_algo->add_data(s->comp_ctx, in->data, left, out);
 		if (ret < 0)
 			return -1;
 	}
@@ -223,9 +227,9 @@
 	/* flush data here */
 
 	if (end)
-		ret = s->comp_algo->flush(&s->comp_ctx, ob, Z_FINISH); /* end of data */
+		ret = s->comp_algo->flush(s->comp_ctx, ob, Z_FINISH); /* end of data */
 	else
-		ret = s->comp_algo->flush(&s->comp_ctx, ob, Z_SYNC_FLUSH); /* end of buffer */
+		ret = s->comp_algo->flush(s->comp_ctx, ob, Z_SYNC_FLUSH); /* end of buffer */
 
 	if (ret < 0)
 		return -1; /* flush failed */
@@ -257,9 +261,8 @@
 	}
 
 	to_forward = ob->i;
-
 	/* update input rate */
-	if (s->comp_ctx.cur_lvl > 0)
+	if (s->comp_ctx && s->comp_ctx->cur_lvl > 0)
 		update_freq_ctr(&global.comp_bps_in, ib->o - ob->o);
 
 	/* copy the remaining data in the tmp buffer. */
@@ -277,7 +280,7 @@
 	*in = ob;
 	*out = ib;
 
-	if (s->comp_ctx.cur_lvl > 0)
+	if (s->comp_ctx && s->comp_ctx->cur_lvl > 0)
 		update_freq_ctr(&global.comp_bps_out, to_forward);
 
 	/* forward the new chunk without remaining data */
@@ -290,6 +293,56 @@
 	return to_forward;
 }
 
+/*
+ * Alloc the comp_ctx
+ */
+static inline int init_comp_ctx(struct comp_ctx **comp_ctx)
+{
+#ifdef USE_ZLIB
+	z_stream *strm;
+
+	if (global.maxzlibmem > 0 && zlib_memory_available < 0)
+		zlib_memory_available = global.maxzlibmem * 1024 * 1024;  /*  Megabytes to bytes */
+
+	if (global.maxzlibmem > 0 && zlib_memory_available < sizeof(struct comp_ctx))
+		return -1;
+#endif
+
+	if (unlikely(pool_comp_ctx == NULL))
+		pool_comp_ctx = create_pool("comp_ctx", sizeof(struct comp_ctx), MEM_F_SHARED);
+
+	*comp_ctx = pool_alloc2(pool_comp_ctx);
+	if (*comp_ctx == NULL)
+		return -1;
+#ifdef USE_ZLIB
+	zlib_memory_available -= sizeof(struct comp_ctx);
+
+	strm = &(*comp_ctx)->strm;
+	strm->zalloc = alloc_zlib;
+	strm->zfree = free_zlib;
+	strm->opaque = *comp_ctx;
+#endif
+	return 0;
+}
+
+/*
+ * Dealloc the comp_ctx
+ */
+static inline int deinit_comp_ctx(struct comp_ctx **comp_ctx)
+{
+	if (!*comp_ctx)
+		return 0;
+
+	pool_free2(pool_comp_ctx, *comp_ctx);
+	*comp_ctx = NULL;
+
+#ifdef USE_ZLIB
+	zlib_memory_available += sizeof(struct comp_ctx);
+#endif
+
+	return 0;
+}
+
 
 /****************************
  **** Identity algorithm ****
@@ -298,7 +351,7 @@
 /*
  * Init the identity algorithm
  */
-int identity_init(struct comp_ctx *comp_ctx, int level)
+int identity_init(struct comp_ctx **comp_ctx, int level)
 {
 	return 0;
 }
@@ -336,7 +389,7 @@
 /*
  * Deinit the algorithm
  */
-int identity_end(struct comp_ctx *comp_ctx)
+int identity_end(struct comp_ctx **comp_ctx)
 {
 	return 0;
 }
@@ -425,23 +478,24 @@
 		zlib_memory_available += pool->size;
 }
 
-
 /**************************
 ****  gzip algorithm   ****
 ***************************/
-int gzip_init(struct comp_ctx *comp_ctx, int level)
+int gzip_init(struct comp_ctx **comp_ctx, int level)
 {
-	z_stream *strm = &comp_ctx->strm;
+	z_stream *strm;
 
-	if (global.maxzlibmem > 0 && zlib_memory_available < 0)
-		zlib_memory_available = global.maxzlibmem * 1024 * 1024;  /*  Megabytes to bytes */
+	if (init_comp_ctx(comp_ctx) < 0)
+		return -1;
 
-	strm->zalloc = alloc_zlib;
-	strm->zfree = free_zlib;
-	strm->opaque = comp_ctx;
+	strm = &(*comp_ctx)->strm;
 
-	if (deflateInit2(&comp_ctx->strm, level, Z_DEFLATED, global.tune.zlibwindowsize + 16, global.tune.zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK)
+	if (deflateInit2(strm, level, Z_DEFLATED, global.tune.zlibwindowsize + 16, global.tune.zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
+		deinit_comp_ctx(comp_ctx);
 		return -1;
+	}
+
+	(*comp_ctx)->cur_lvl = level;
 
 	return 0;
 }
@@ -449,16 +503,21 @@
 **** Deflate algorithm ****
 ***************************/
 
-int deflate_init(struct comp_ctx *comp_ctx, int level)
+int deflate_init(struct comp_ctx **comp_ctx, int level)
 {
-	z_stream *strm = &comp_ctx->strm;
+	z_stream *strm;
 
-	strm->zalloc = alloc_zlib;
-	strm->zfree = free_zlib;
-	strm->opaque = comp_ctx;
+	if (init_comp_ctx(comp_ctx) < 0)
+		return -1;
+
+	strm = &(*comp_ctx)->strm;
 
-	if (deflateInit(&comp_ctx->strm, level) != Z_OK)
+	if (deflateInit(strm, level) != Z_OK) {
+		deinit_comp_ctx(comp_ctx);
 		return -1;
+	}
+
+	(*comp_ctx)->cur_lvl = level;
 
 	return 0;
 }
@@ -538,14 +597,16 @@
 	return -1;
 }
 
-int deflate_end(struct comp_ctx *comp_ctx)
+int deflate_end(struct comp_ctx **comp_ctx)
 {
-	z_stream *strm = &comp_ctx->strm;
+	z_stream *strm = &(*comp_ctx)->strm;
+	int ret;
 
-	if (deflateEnd(strm) != Z_OK)
-		return -1;
+	ret = deflateEnd(strm);
 
-	return 0;
+	deinit_comp_ctx(comp_ctx);
+
+	return ret;
 }
 
 #endif /* USE_ZLIB */
diff --git a/src/proto_http.c b/src/proto_http.c
index e410b6d..8588b50 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2105,8 +2105,6 @@
 
 	s->flags |= SN_COMP_READY;
 
-	s->comp_ctx.cur_lvl = global.tune.comp_maxlevel;
-
 	/* remove Content-Length header */
 	if ((msg->flags & HTTP_MSGF_CNT_LEN) && http_find_header2("Content-Length", 14, res->p, &txn->hdr_idx, &ctx))
 		http_remove_header2(msg, &txn->hdr_idx, &ctx);