MINOR: proxy: custom capture declaration

This patch adds a new keyword called "declare". This keyword
allow to declare some capture slots in requests and response.
It is useful for sharing capture between frontend and backends.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index fdb0ddc..1d9e3a5 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1504,6 +1504,7 @@
 compression                               X          X         X         X
 contimeout                  (deprecated)  X          -         X         X
 cookie                                    X          -         X         X
+declare capture                           -          X         X         -
 default-server                            X          -         X         X
 default_backend                           X          X         X         -
 description                               -          X         X         X
@@ -2619,6 +2620,22 @@
              and "ignore-persist".
 
 
+declare capture [ request | response ] len <length>
+  Declares a capture slot.
+  May be used in sections :   defaults | frontend | listen | backend
+                                 no    |    yes   |   yes  |   no
+  Arguments:
+    <length> is the length allowed for the capture.
+
+  This declaration is only available in the frontend or listen section, but the
+  reserved slot can be used in the backends. The "request" keyword allocates a
+  capture slot for use in the request, and "response" allocates a capture slot
+  for use in the response.
+
+  See also: "capture-req", "capture-res" (sample converters),
+            "http-request capture" and "http-response capture".
+
+
 default-server [param*]
   Change default options for a server in a backend
   May be used in sections :   defaults | frontend | listen | backend
diff --git a/src/proxy.c b/src/proxy.c
index b6d870b..90d1313 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -28,6 +28,7 @@
 #include <eb32tree.h>
 #include <ebistree.h>
 
+#include <types/capture.h>
 #include <types/global.h>
 #include <types/obj_type.h>
 #include <types/peers.h>
@@ -337,6 +338,106 @@
 	return retval;
 }
 
+/* This function parses a "declare" statement in a proxy section. It returns -1
+ * if there is any error, 1 for warning, otherwise 0. If it does not return zero,
+ * it will write an error or warning message into a preallocated buffer returned
+ * at <err>. The function must be called with <args> pointing to the first command
+ * line word, with <proxy> pointing to the proxy being parsed, and <defpx> to the
+ * default proxy or NULL.
+ */
+static int proxy_parse_declare(char **args, int section, struct proxy *curpx,
+                               struct proxy *defpx, const char *file, int line,
+                               char **err)
+{
+	/* Capture keyword wannot be declared in a default proxy. */
+	if (curpx == defpx) {
+		memprintf(err, "'%s' not avalaible in default section", args[0]);
+		return -1;
+	}
+
+	/* Capture keywork is only avalaible in frontend. */
+	if (!(curpx->cap & PR_CAP_FE)) {
+		memprintf(err, "'%s' only avalaible in frontend or listen section", args[0]);
+		return -1;
+	}
+
+	/* Check mandatory second keyword. */
+	if (!args[1] || !*args[1]) {
+		memprintf(err, "'%s' needs a second keyword that specify the type of declaration ('capture')", args[0]);
+		return -1;
+	}
+
+	/* Actually, declare is only avalaible for declaring capture
+	 * slot, but in the future it can declare maps or variables.
+	 * So, this section permits to check and switch acording with
+	 * the second keyword.
+	 */
+	if (strcmp(args[1], "capture") == 0) {
+		char *error = NULL;
+		long len;
+		struct cap_hdr *hdr;
+
+		/* Check the next keyword. */
+		if (!args[2] || !*args[2] ||
+		    (strcmp(args[2], "response") != 0 &&
+		     strcmp(args[2], "request") != 0)) {
+			memprintf(err, "'%s %s' requires a direction ('request' or 'response')", args[0], args[1]);
+			return -1;
+		}
+
+		/* Check the 'len' keyword. */
+		if (!args[3] || !*args[3] || strcmp(args[3], "len") != 0) {
+			memprintf(err, "'%s %s' requires a capture length ('len')", args[0], args[1]);
+			return -1;
+		}
+
+		/* Check the length value. */
+		if (!args[4] || !*args[4]) {
+			memprintf(err, "'%s %s': 'len' requires a numeric value that represents the "
+			               "capture length",
+			          args[0], args[1]);
+			return -1;
+		}
+
+		/* convert the length value. */
+		len = strtol(args[4], &error, 10);
+		if (*error != '\0') {
+			memprintf(err, "'%s %s': cannot parse the length '%s'.",
+			          args[0], args[1], args[3]);
+			return -1;
+		}
+
+		/* check length. */
+		if (len <= 0) {
+			memprintf(err, "length must be > 0");
+			return -1;
+		}
+
+		/* register the capture. */
+		hdr = calloc(sizeof(struct cap_hdr), 1);
+		hdr->name = NULL; /* not a header capture */
+		hdr->namelen = 0;
+		hdr->len = len;
+		hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
+
+		if (strcmp(args[2], "request") == 0) {
+			hdr->next = curpx->req_cap;
+			hdr->index = curpx->nb_req_cap++;
+			curpx->req_cap = hdr;
+		}
+		if (strcmp(args[2], "response") == 0) {
+			hdr->next = curpx->rsp_cap;
+			hdr->index = curpx->nb_rsp_cap++;
+			curpx->rsp_cap = hdr;
+		}
+		return 0;
+	}
+	else {
+		memprintf(err, "unknown declaration type '%s' (supports 'capture')", args[1]);
+		return -1;
+	}
+}
+
 /* This function inserts proxy <px> into the tree of known proxies. The proxy's
  * name is used as the storing key so it must already have been initialized.
  */
@@ -1093,6 +1194,7 @@
 	{ CFG_LISTEN, "srvtimeout", proxy_parse_timeout },
 	{ CFG_LISTEN, "rate-limit", proxy_parse_rate_limit },
 	{ CFG_LISTEN, "max-keep-alive-queue", proxy_parse_max_ka_queue },
+	{ CFG_LISTEN, "declare", proxy_parse_declare },
 	{ 0, NULL, NULL },
 }};