MINOR: pattern: add support for compiling patterns for lookups

With this patch, patterns can be compiled for two modes :
  - match
  - lookup

The match mode is used for example in ACLs or maps. The lookup mode
is used to lookup a key for pattern maintenance. For example, looking
up a network is different from looking up one address belonging to
this network.

A special case is made for regex. In lookup mode they return the input
regex string and do not compile the regex.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 80d4ee1..ee19392 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -68,7 +68,7 @@
 
 
 /* ignore the current line */
-int pat_parse_nothing(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* NB: For two strings to be identical, it is required that their lengths match */
 enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern);
@@ -83,37 +83,37 @@
 enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
 
 /* Parse an integer. It is put both in min and max. */
-int pat_parse_int(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_int(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse len like an integer, but specify expected string type */
-int pat_parse_len(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_len(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse an version. It is put both in min and max. */
-int pat_parse_dotted_ver(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_dotted_ver(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse a range of integers delimited by either ':' or '-'. If only one
  * integer is read, it is set as both min and max.
  */
-int pat_parse_range(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_range(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse a string. It is allocated and duplicated. */
-int pat_parse_str(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_str(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse a hexa binary definition. It is allocated and duplicated. */
-int pat_parse_bin(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse and concatenate strings into one. It is allocated and duplicated. */
-int pat_parse_strcat(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse a regex. It is allocated. */
-int pat_parse_reg(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* Parse an IP address and an optional mask in the form addr[/mask].
  * The addr may either be an IPv4 address or a hostname. The mask
  * may either be a dotted mask or a number of bits. Returns 1 if OK,
  * otherwise 0.
  */
-int pat_parse_ip(const char **text, struct pattern *pattern, int *opaque, char **err);
+int pat_parse_ip(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 
 /* always return false */
 enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
diff --git a/include/types/acl.h b/include/types/acl.h
index 9692015..afce939 100644
--- a/include/types/acl.h
+++ b/include/types/acl.h
@@ -92,7 +92,7 @@
 struct acl_keyword {
 	const char *kw;
 	char *fetch_kw;
-	int (*parse)(const char **text, struct pattern *pattern, int *opaque, char **err);
+	int (*parse)(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 	enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
 	/* must be after the config params */
 	struct sample_fetch *smp; /* the sample fetch we depend on */
diff --git a/include/types/pattern.h b/include/types/pattern.h
index 7065b6b..4e89372 100644
--- a/include/types/pattern.h
+++ b/include/types/pattern.h
@@ -61,6 +61,15 @@
 	PAT_MATCH = 3,           /* sample matched at least one pattern */
 };
 
+/* This enum describe the running mode of the function pat_parse_*().
+ * The lookup mode does not allocate memory. The compile mode allocate
+ * memory and create any data
+ */
+enum pat_usage {
+	PAT_U_LOOKUP,
+	PAT_U_COMPILE,
+};
+
 /* possible flags for expressions or patterns */
 enum {
 	PAT_F_IGNORE_CASE = 1 << 0,       /* ignore case */
@@ -151,14 +160,14 @@
  * are grouped together in order to optimize caching.
  */
 struct pattern_expr {
-	int (*parse)(const char **text, struct pattern *pattern, int *opaque, char **err);
+	int (*parse)(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
 	enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
 	struct list patterns;         /* list of acl_patterns */
 	struct eb_root pattern_tree;  /* may be used for lookup in large datasets */
 };
 
 extern char *pat_match_names[PAT_MATCH_NUM];
-extern int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, int *, char **);
+extern int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, enum pat_usage, int *, char **);
 extern enum pat_match_res (*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern *);
 extern int pat_match_types[PAT_MATCH_NUM];
 
diff --git a/src/pattern.c b/src/pattern.c
index 3ac8f03..43011cd 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -40,7 +40,7 @@
 	[PAT_MATCH_REG]   = "reg",
 };
 
-int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, int *, char **) = {
+int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, enum pat_usage, int *, char **) = {
 	[PAT_MATCH_FOUND] = pat_parse_nothing,
 	[PAT_MATCH_BOOL]  = pat_parse_nothing,
 	[PAT_MATCH_INT]   = pat_parse_int,
@@ -94,7 +94,7 @@
  */
 
 /* ignore the current line */
-int pat_parse_nothing(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	return 1;
 }
@@ -419,46 +419,71 @@
 }
 
 /* Parse a string. It is allocated and duplicated. */
-int pat_parse_str(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_str(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	pattern->type = SMP_T_CSTR;
 	pattern->expect_type = SMP_T_CSTR;
-	pattern->ptr.str = strdup(*text);
-	if (!pattern->ptr.str) {
-		memprintf(err, "out of memory while loading string pattern");
-		return 0;
+	if (usage == PAT_U_COMPILE) {
+		pattern->ptr.str = strdup(*text);
+		if (!pattern->ptr.str) {
+			memprintf(err, "out of memory while loading string pattern");
+			return 0;
+		}
 	}
+	else
+		pattern->ptr.str = (char *)*text;
 	pattern->len = strlen(*text);
 	return 1;
 }
 
 /* Parse a binary written in hexa. It is allocated. */
-int pat_parse_bin(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
+	struct chunk *trash;
+
 	pattern->type = SMP_T_CBIN;
 	pattern->expect_type = SMP_T_CBIN;
 
+	if (usage == PAT_U_COMPILE)
+		return parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
+
+	trash = get_trash_chunk();
+	pattern->len = trash->size;
+	pattern->ptr.str = trash->str;
 	return parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
 }
 
 /* Parse and concatenate all further strings into one. */
 int
-pat_parse_strcat(const char **text, struct pattern *pattern, int *opaque, char **err)
+pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
-
 	int len = 0, i;
 	char *s;
+	struct chunk *trash;
 
 	for (i = 0; *text[i]; i++)
 		len += strlen(text[i])+1;
 
 	pattern->type = SMP_T_CSTR;
-	pattern->ptr.str = s = calloc(1, len);
-	if (!pattern->ptr.str) {
-		memprintf(err, "out of memory while loading pattern");
-		return 0;
+	if (usage == PAT_U_COMPILE) {
+		pattern->ptr.str = calloc(1, len);
+		if (!pattern->ptr.str) {
+			memprintf(err, "out of memory while loading pattern");
+			return 0;
+		}
+	}
+	else {
+		trash = get_trash_chunk();
+		if (trash->size < len) {
+			memprintf(err, "no space avalaible in the buffer. expect %d, provides %d",
+			          len, trash->size);
+			return 0;
+		}
+		pattern->ptr.str = trash->str;
 	}
 
+	s = pattern->ptr.str;
+
 	for (i = 0; *text[i]; i++)
 		s += sprintf(s, i?" %s":"%s", text[i]);
 
@@ -474,24 +499,40 @@
 }
 
 /* Parse a regex. It is allocated. */
-int pat_parse_reg(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	struct my_regex *preg;
+	struct chunk *trash;
 
-	preg = calloc(1, sizeof(*preg));
+	if (usage == PAT_U_COMPILE) {
 
-	if (!preg) {
-		memprintf(err, "out of memory while loading pattern");
-		return 0;
+		preg = calloc(1, sizeof(*preg));
+		if (!preg) {
+			memprintf(err, "out of memory while loading pattern");
+			return 0;
+		}
+
+		if (!regex_comp(*text, preg, !(pattern->flags & PAT_F_IGNORE_CASE), 0, err)) {
+			free(preg);
+			return 0;
+		}
+		pattern->freeptrbuf = &pat_free_reg;
 	}
+	else {
 
-	if (!regex_comp(*text, preg, !(pattern->flags & PAT_F_IGNORE_CASE), 0, err)) {
-		free(preg);
-		return 0;
+		trash = get_trash_chunk();
+		if (trash->size < sizeof(*preg)) {
+			memprintf(err, "no space avalaible in the buffer. expect %d, provides %d",
+			          (int)sizeof(*preg), trash->size);
+			return 0;
+		}
+
+		preg = (struct my_regex *)trash->str;
+		preg->regstr = (char *)*text;
+		pattern->freeptrbuf = NULL;
 	}
 
 	pattern->ptr.reg = preg;
-	pattern->freeptrbuf = &pat_free_reg;
 	pattern->expect_type = SMP_T_CSTR;
 	return 1;
 }
@@ -510,7 +551,7 @@
  * the caller will have to free it.
  *
  */
-int pat_parse_int(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_int(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	signed long long i;
 	unsigned int j, last, skip = 0;
@@ -583,11 +624,11 @@
 	return skip + 1;
 }
 
-int pat_parse_len(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_len(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	int ret;
 
-	ret = pat_parse_int(text, pattern, opaque, err);
+	ret = pat_parse_int(text, pattern, usage, opaque, err);
 	pattern->expect_type = SMP_T_CSTR;
 	return ret;
 }
@@ -612,7 +653,7 @@
  *    acl valid_ssl       ssl_req_proto 3.0-3.1
  *
  */
-int pat_parse_dotted_ver(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_dotted_ver(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	signed long long i;
 	unsigned int j, last, skip = 0;
@@ -703,7 +744,7 @@
  * may either be a dotted mask or a number of bits. Returns 1 if OK,
  * otherwise 0. NOTE: IP address patterns are typed (IPV4/IPV6).
  */
-int pat_parse_ip(const char **text, struct pattern *pattern, int *opaque, char **err)
+int pat_parse_ip(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	pattern->expect_type = SMP_T_ADDR;
 	if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
@@ -801,7 +842,7 @@
 		memset(*pattern, 0, sizeof(**pattern));
 		(*pattern)->flags = patflags;
 
-		ret = expr->parse(args, *pattern, &opaque, err);
+		ret = expr->parse(args, *pattern, PAT_U_COMPILE, &opaque, err);
 		if (!ret)
 			return 0;
 
diff --git a/src/proto_http.c b/src/proto_http.c
index 2ce0d33..b7982bc 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -8735,21 +8735,33 @@
  * We use the pre-parsed method if it is known, and store its number as an
  * integer. If it is unknown, we use the pointer and the length.
  */
-static int pat_parse_meth(const char **text, struct pattern *pattern, int *opaque, char **err)
+static int pat_parse_meth(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
 	int len, meth;
+	struct chunk *trash;
 
 	len  = strlen(*text);
 	meth = find_http_meth(*text, len);
 
 	pattern->val.i = meth;
 	if (meth == HTTP_METH_OTHER) {
-		pattern->ptr.str = strdup(*text);
-		pattern->expect_type = SMP_T_CSTR;
-		if (!pattern->ptr.str) {
-			memprintf(err, "out of memory while loading pattern");
-			return 0;
+		if (usage == PAT_U_COMPILE) {
+			pattern->ptr.str = strdup(*text);
+			if (!pattern->ptr.str) {
+				memprintf(err, "out of memory while loading pattern");
+				return 0;
+			}
 		}
+		else {
+			trash = get_trash_chunk();
+			if (trash->size < len) {
+				memprintf(err, "no space avalaible in the buffer. expect %d, provides %d",
+				          len, trash->size);
+				return 0;
+			}
+			pattern->ptr.str = trash->str;
+		}
+		pattern->expect_type = SMP_T_CSTR;
 		pattern->len = len;
 	}
 	else