]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: pattern: add support for compiling patterns for lookups
authorThierry FOURNIER <tfournier@exceliance.fr>
Fri, 6 Dec 2013 19:33:50 +0000 (20:33 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 12 Dec 2013 14:44:02 +0000 (15:44 +0100)
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.

include/proto/pattern.h
include/types/acl.h
include/types/pattern.h
src/pattern.c
src/proto_http.c

index 80d4ee1fecc194f705badb7c23df433ee06168b8..ee193929a0dfda754a9467426b88268233b799d9 100644 (file)
@@ -68,7 +68,7 @@ enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *
 
 
 /* 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_len(struct sample *smp, struct pattern *pattern);
 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);
index 9692015ba179646c2790d815b71548fab84bce74..afce9393c133ff8def223d0656b13f5648d225dd 100644 (file)
@@ -92,7 +92,7 @@ struct acl_expr;
 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 */
index 7065b6b9c915b5a0af4bc945d9ad6ed7f9f43c13..4e893724f4cbcb36f5e7bd869788cc2a8617ce50 100644 (file)
@@ -61,6 +61,15 @@ enum pat_match_res {
        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 @@ struct pattern {
  * 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];
 
index 3ac8f0361b9dd7910ac17f3f1e43b5a33d028170..43011cd097467d9cabc0e83862b4d9b17d982053 100644 (file)
@@ -40,7 +40,7 @@ char *pat_match_names[PAT_MATCH_NUM] = {
        [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 @@ int pat_match_types[PAT_MATCH_NUM] = {
  */
 
 /* 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 @@ static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
 }
 
 /* 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 @@ static void pat_free_reg(void *ptr)
 }
 
 /* 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 @@ int pat_parse_reg(const char **text, struct pattern *pattern, int *opaque, char
  * 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 @@ int pat_parse_int(const char **text, struct pattern *pattern, int *opaque, char
        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 @@ int pat_parse_len(const char **text, struct pattern *pattern, int *opaque, char
  *    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 @@ int pat_parse_dotted_ver(const char **text, struct pattern *pattern, int *opaque
  * 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 @@ int pattern_register(struct pattern_expr *expr, const char **args,
                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;
 
index 2ce0d33a49dfe714f3674323050ca8251f12a654..b7982bce3100268cd7063c9a368842e3344c0325 100644 (file)
@@ -8735,21 +8735,33 @@ smp_prefetch_http(struct proxy *px, struct session *s, void *l7, unsigned int op
  * 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