MINOR: compression: maximum compression rate limit

This patch adds input and output rate calcutation on the HTTP compresion
feature.

Compression can be limited with a maximum rate value in kilobytes per
second. The rate is set with the global 'maxcomprate' option. You can
change this value dynamicaly with 'set rate-limit http-compression
global' on the UNIX socket.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 5f22b24..c601cbc 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -844,6 +844,14 @@
 		}
 		global.cps_lim = atol(args[1]);
 	}
+	else if (!strcmp(args[0], "maxcomprate")) {
+		if (*(args[1]) == 0) {
+			Alert("parsing [%s:%d] : '%s' expects an integer argument in kb/s.\n", file, linenum, args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		global.comp_rate_lim = atoi(args[1]) * 1024;
+	}
 	else if (!strcmp(args[0], "maxpipes")) {
 		if (global.maxpipes != 0) {
 			Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
diff --git a/src/compression.c b/src/compression.c
index 4c942aa..ae43cd3 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -31,6 +31,7 @@
 #include <types/compression.h>
 
 #include <proto/compression.h>
+#include <proto/freq_ctr.h>
 #include <proto/proto_http.h>
 
 
@@ -261,6 +262,10 @@
 
 	to_forward = ob->i;
 
+	/* update input rate */
+	if (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. */
 	if (ib->i > 0) {
 		left = ib->i - bi_contig_data(ib);
@@ -276,6 +281,9 @@
 	*in = ob;
 	*out = ib;
 
+	if (s->comp_ctx.cur_lvl > 0)
+		update_freq_ctr(&global.comp_bps_out, to_forward);
+
 	/* forward the new chunk without remaining data */
 	b_adv(ob, to_forward);
 
@@ -490,6 +498,23 @@
 	out_len = (out->size - buffer_len(out)) - strm->avail_out;
 	out->i += out_len;
 
+	/* compression rate limit */
+	if (global.comp_rate_lim > 0) {
+
+		if (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim) {
+			/* decrease level */
+			if (comp_ctx->cur_lvl > 0) {
+				comp_ctx->cur_lvl--;
+				deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
+			}
+
+		} else if (comp_ctx->cur_lvl < global.comp_rate_lim) {
+			/* increase level */
+			comp_ctx->cur_lvl++ ;
+			deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
+		}
+	}
+
 	return out_len;
 }
 
diff --git a/src/dumpstats.c b/src/dumpstats.c
index da84f2a..0ee6641 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -1246,8 +1246,21 @@
 					return 1;
 				}
 			}
+			else if (strcmp(args[2], "http-compression") == 0) {
+				if (strcmp(args[3], "global") == 0) {
+					int v;
+
+					v = atoi(args[4]);
+					global.comp_rate_lim = v * 1024; /* Kilo to bytes. */
+				}
+				else {
+					si->applet.ctx.cli.msg = "'set rate-limit http-compression' only supports 'global'.\n";
+					si->applet.st0 = STAT_CLI_PRINT;
+					return 1;
+				}
+			}
 			else {
-				si->applet.ctx.cli.msg = "'set rate-limit' only supports 'connections'.\n";
+				si->applet.ctx.cli.msg = "'set rate-limit' supports 'connections' and 'http-compression'.\n";
 				si->applet.st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1708,6 +1721,8 @@
 				     "ConnRate: %d\n"
 				     "ConnRateLimit: %d\n"
 				     "MaxConnRate: %d\n"
+				     "CompressBpsIn: %u\n"
+				     "CompressBpsOut: %u\n"
 				     "Tasks: %d\n"
 				     "Run_queue: %d\n"
 				     "Idle_pct: %d\n"
@@ -1724,6 +1739,7 @@
 				     global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes,
 				     actconn, pipes_used, pipes_free,
 				     read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
+				     read_freq_ctr(&global.comp_bps_in), read_freq_ctr(&global.comp_bps_out),
 				     nb_tasks_cur, run_queue_cur, idle_pct,
 				     global.node, global.desc?global.desc:""
 				     );
diff --git a/src/haproxy.c b/src/haproxy.c
index b322244..cfd6f84 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -113,6 +113,7 @@
 	.req_count = 0,
 	.logsrvs = LIST_HEAD_INIT(global.logsrvs),
 	.maxzlibmem = 0,
+	.comp_rate_lim = 0,
 	.unix_bind = {
 		 .ux = {
 			 .uid = -1,
diff --git a/src/proto_http.c b/src/proto_http.c
index 7f15107..d768b87 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2087,6 +2087,11 @@
 
 	ctx.idx = 0;
 
+	/* limit compression rate */
+	if (global.comp_rate_lim > 0)
+		if (read_freq_ctr(&global.comp_bps_in) > global.comp_rate_lim)
+			goto fail;
+
 	/* initialize compression */
 	if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0)
 		goto fail;