]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: pattern: move functions for grouping pat_match_* and pat_parse_* and add docum...
authorThierry FOURNIER <tfournier@exceliance.fr>
Tue, 21 Jan 2014 10:25:41 +0000 (11:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 21 Jan 2014 21:14:21 +0000 (22:14 +0100)
include/proto/pattern.h
src/pattern.c

index 080b06223403a3390bb2c1231b0fdfa7826786d0..e5c1b42df6a8801b14024c1c326ee813ace371c1 100644 (file)
@@ -70,18 +70,6 @@ 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, 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);
-
-/* NB: For two binary buffers to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern);
-
-/* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern);
-
-/* Checks that the integer in <test> is included between min and max */
-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, enum pat_usage usage, int *opaque, char **err);
 
@@ -115,6 +103,18 @@ int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usa
  */
 int pat_parse_ip(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);
+
+/* NB: For two binary buffers to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern);
+
+/* Checks that the length of the pattern in <test> is included between min and max */
+enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern);
+
+/* Checks that the integer in <test> is included between min and max */
+enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
+
 /* always return false */
 enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
 
index b05320105ff7221c9cabcd8a95181a2b2564976d..ce12a0e3e9834b45c5e1a2393ee46433f04f9458 100644 (file)
@@ -90,46 +90,30 @@ int pat_match_types[PAT_MATCH_NUM] = {
 };
 
 /*
- * These functions are exported and may be used by any other component.
+ *
+ * The following functions are not exported and are used by internals process
+ * of pattern matching
+ *
  */
 
-/* ignore the current line */
-int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
-       return 1;
-}
-
-/* always return false */
-enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern)
-{
-       return PAT_NOMATCH;
-}
-
-
-/* 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)
+/* Lookup an IPv4 address in the expression's pattern tree using the longest
+ * match method. The node is returned if it exists, otherwise NULL.
+ */
+static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
 {
-       int icase;
+       struct in_addr *s;
 
-       if (pattern->len != smp->data.str.len)
+       if (smp->type != SMP_T_IPV4)
                return PAT_NOMATCH;
 
-       icase = pattern->flags & PAT_F_IGNORE_CASE;
-       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
-           (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
-               return PAT_MATCH;
-       return PAT_NOMATCH;
+       s = &smp->data.ipv4;
+       return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
 }
 
-/* NB: For two binaries buf to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern)
+/* Free data allocated by pat_parse_reg */
+static void pat_free_reg(void *ptr)
 {
-       if (pattern->len != smp->data.str.len)
-               return PAT_NOMATCH;
-
-       if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
-               return PAT_MATCH;
-       return PAT_NOMATCH;
+       regex_free(ptr);
 }
 
 /* Lookup a string in the expression's pattern tree. The node is returned if it
@@ -151,77 +135,6 @@ static void *pat_lookup_str(struct sample *smp, struct pattern_expr *expr)
        return node;
 }
 
-/* Executes a regex. It temporarily changes the data to add a trailing zero,
- * and restores the previous character when leaving.
- */
-enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern)
-{
-       if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
-               return PAT_MATCH;
-       return PAT_NOMATCH;
-}
-
-/* Checks that the pattern matches the beginning of the tested string. */
-enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern)
-{
-       int icase;
-
-       if (pattern->len > smp->data.str.len)
-               return PAT_NOMATCH;
-
-       icase = pattern->flags & PAT_F_IGNORE_CASE;
-       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
-           (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
-               return PAT_NOMATCH;
-       return PAT_MATCH;
-}
-
-/* Checks that the pattern matches the end of the tested string. */
-enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern)
-{
-       int icase;
-
-       if (pattern->len > smp->data.str.len)
-               return PAT_NOMATCH;
-       icase = pattern->flags & PAT_F_IGNORE_CASE;
-       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
-           (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
-               return PAT_NOMATCH;
-       return PAT_MATCH;
-}
-
-/* Checks that the pattern is included inside the tested string.
- * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
- */
-enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern)
-{
-       int icase;
-       char *end;
-       char *c;
-
-       if (pattern->len > smp->data.str.len)
-               return PAT_NOMATCH;
-
-       end = smp->data.str.str + smp->data.str.len - pattern->len;
-       icase = pattern->flags & PAT_F_IGNORE_CASE;
-       if (icase) {
-               for (c = smp->data.str.str; c <= end; c++) {
-                       if (tolower(*c) != tolower(*pattern->ptr.str))
-                               continue;
-                       if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
-                               return PAT_MATCH;
-               }
-       } else {
-               for (c = smp->data.str.str; c <= end; c++) {
-                       if (*c != *pattern->ptr.str)
-                               continue;
-                       if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
-                               return PAT_MATCH;
-               }
-       }
-       return PAT_NOMATCH;
-}
-
 /* Background: Fast way to find a zero byte in a word
  * http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
  * hasZeroByte = (v - 0x01010101UL) & ~v & 0x80808080UL;
@@ -244,228 +157,98 @@ static inline unsigned int make_4delim(unsigned char d1, unsigned char d2, unsig
        return d1 << 24 | d2 << 16 | d3 << 8 | d4;
 }
 
-/* This one is used by other real functions. It checks that the pattern is
- * included inside the tested string, but enclosed between the specified
- * delimiters or at the beginning or end of the string. The delimiters are
- * provided as an unsigned int made by make_4delim() and match up to 4 different
- * delimiters. Delimiters are stripped at the beginning and end of the pattern.
- */
-static int match_word(struct sample *smp, struct pattern *pattern, unsigned int delimiters)
-{
-       int may_match, icase;
-       char *c, *end;
-       char *ps;
-       int pl;
-
-       pl = pattern->len;
-       ps = pattern->ptr.str;
-
-       while (pl > 0 && is_delimiter(*ps, delimiters)) {
-               pl--;
-               ps++;
-       }
-
-       while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
-               pl--;
-
-       if (pl > smp->data.str.len)
-               return PAT_NOMATCH;
 
-       may_match = 1;
-       icase = pattern->flags & PAT_F_IGNORE_CASE;
-       end = smp->data.str.str + smp->data.str.len - pl;
-       for (c = smp->data.str.str; c <= end; c++) {
-               if (is_delimiter(*c, delimiters)) {
-                       may_match = 1;
-                       continue;
-               }
+/*
+ *
+ * These functions are exported and may be used by any other component.
+ *
+ * The following functions are used for parsing pattern matching
+ * input value. The <text> contain a list of word. The last entry
+ * must be one NULL character. the <text> contain the string to be
+ * parsed. <pattern> must be a preallocated pattern. The pat_parse_*
+ * functions fill this structure with the parsed value. <usage> can
+ * be PAT_U_COMPILE or PAT_U_LOOKUP. If the value PAT_U_COMPILE is
+ * used memory is allocated for filling the pattern. If the value
+ * PAT_U_LOOKUP is set, the parser use "trash" or return pointers
+ * to the input strings. In both cases, the caller must use the
+ * value PAT_U_LOOKUP with caution. <opaque> is used to pass value
+ * between two calls to the parser. the interger must ben initilized
+ * to 0 (see note below). <err> is filled with an error message built
+ * with memprintf() function.
+ *
+ * In succes case, the pat_parse_* function return the number of
+ * <text> eated. If the function fail, it returns 0 and <err> is
+ * filled.
+ *
+ * NOTE: <opaque>iIt is used with integer range parser. The following 
+ * configuration line is processed with this method:
+ *
+ *    acl ... -m int eq 10 20
+ *
+ * The first call to the parser eat 2 elements: "eq" and "10". The
+ * pattern is filled with "eq 10" content. The <opaque> contain
+ * coded value value that represent "eq".
+ *
+ * The second call to the parser just eat 1 element: "20". The opaque
+ * contain the value of the operator. The parser returns pattern filled
+ * with "eq 20".
+ *
+ */
 
-               if (!may_match)
-                       continue;
+/* ignore the current line */
+int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
+{
+       return 1;
+}
 
-               if (icase) {
-                       if ((tolower(*c) == tolower(*ps)) &&
-                           (strncasecmp(ps, c, pl) == 0) &&
-                           (c == end || is_delimiter(c[pl], delimiters)))
-                               return PAT_MATCH;
-               } else {
-                       if ((*c == *ps) &&
-                           (strncmp(ps, c, pl) == 0) &&
-                           (c == end || is_delimiter(c[pl], delimiters)))
-                               return PAT_MATCH;
+/* Parse a string. It is allocated and duplicated. */
+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;
+       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;
                }
-               may_match = 0;
        }
-       return PAT_NOMATCH;
+       else
+               pattern->ptr.str = (char *)*text;
+       pattern->len = strlen(*text);
+       return 1;
 }
 
-/* Checks that the pattern is included inside the tested string, but enclosed
- * between the delimiters '?' or '/' or at the beginning or end of the string.
- * Delimiters at the beginning or end of the pattern are ignored.
- */
-enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern)
+/* Parse a binary written in hexa. It is allocated. */
+int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
-       return match_word(smp, pattern, make_4delim('/', '?', '?', '?'));
-}
+       struct chunk *trash;
 
-/* Checks that the pattern is included inside the tested string, but enclosed
- * between the delmiters '/', '?', '.' or ":" or at the beginning or end of
- * the string. Delimiters at the beginning or end of the pattern are ignored.
- */
-enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern)
-{
-       return match_word(smp, pattern, make_4delim('/', '?', '.', ':'));
-}
+       pattern->type = SMP_T_CBIN;
+       pattern->expect_type = SMP_T_CBIN;
 
-/* Checks that the integer in <test> is included between min and max */
-enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern)
-{
-       if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
-           (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
-               return PAT_MATCH;
-       return PAT_NOMATCH;
-}
+       if (usage == PAT_U_COMPILE)
+               /* If the parse_binary fails, it returns 0. In succes case, it returns
+                * the length of the arsed binary content. The functions pat_parse_* 
+                * must return 0 if fail and the number of elements eated from **text
+                * if not fail. In succes case, this function eat always 1 elements.
+                * The double operator "!" converts the range "1-n" to "1".
+                */
+               return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
 
-/* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern)
-{
-       if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
-           (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
-               return PAT_MATCH;
-       return PAT_NOMATCH;
+       trash = get_trash_chunk();
+       pattern->len = trash->size;
+       pattern->ptr.str = trash->str;
+       return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
 }
 
-enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern)
+/* Parse and concatenate all further strings into one. */
+int
+pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
-       unsigned int v4; /* in network byte order */
-       struct in6_addr *v6;
-       int bits, pos;
-       struct in6_addr tmp6;
-
-       if (pattern->type == SMP_T_IPV4) {
-               if (smp->type == SMP_T_IPV4) {
-                       v4 = smp->data.ipv4.s_addr;
-               }
-               else if (smp->type == SMP_T_IPV6) {
-                       /* v4 match on a V6 sample. We want to check at least for
-                        * the following forms :
-                        *   - ::ffff:ip:v4 (ipv4 mapped)
-                        *   - ::0000:ip:v4 (old ipv4 mapped)
-                        *   - 2002:ip:v4:: (6to4)
-                        */
-                       if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
-                           *(uint32_t*)&smp->data.ipv6.s6_addr[4]  == 0 &&
-                           (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
-                            *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
-                               v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
-                       }
-                       else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
-                               v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
-                                           ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
-                       }
-                       else
-                               return PAT_NOMATCH;
-               }
-               else
-                       return PAT_NOMATCH;
-
-               if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
-                       return PAT_MATCH;
-               else
-                       return PAT_NOMATCH;
-       }
-       else if (pattern->type == SMP_T_IPV6) {
-               if (smp->type == SMP_T_IPV4) {
-                       /* Convert the IPv4 sample address to IPv4 with the
-                        * mapping method using the ::ffff: prefix.
-                        */
-                       memset(&tmp6, 0, 10);
-                       *(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
-                       *(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
-                       v6 = &tmp6;
-               }
-               else if (smp->type == SMP_T_IPV6) {
-                       v6 = &smp->data.ipv6;
-               }
-               else {
-                       return PAT_NOMATCH;
-               }
-
-               bits = pattern->val.ipv6.mask;
-               for (pos = 0; bits > 0; pos += 4, bits -= 32) {
-                       v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
-                       if (bits < 32)
-                               v4 &= htonl((~0U) << (32-bits));
-                       if (v4)
-                               return PAT_NOMATCH;
-               }
-               return PAT_MATCH;
-       }
-       return PAT_NOMATCH;
-}
-
-/* Lookup an IPv4 address in the expression's pattern tree using the longest
- * match method. The node is returned if it exists, otherwise NULL.
- */
-static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
-{
-       struct in_addr *s;
-
-       if (smp->type != SMP_T_IPV4)
-               return PAT_NOMATCH;
-
-       s = &smp->data.ipv4;
-       return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
-}
-
-/* Parse a string. It is allocated and duplicated. */
-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;
-       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, 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)
-               /* If the parse_binary fails, it returns 0. In succes case, it returns
-                * the length of the arsed binary content. The function pat_parse_* 
-                * must return 0 if fail and the number of elements eated from **text
-                * if not fail. In succes case, this function eat always 1 elements.
-                * The double operator "!" converts the range "1-n" to "1".
-                */
-               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, enum pat_usage usage, int *opaque, char **err)
-{
-       int len = 0, i;
-       char *s;
-       struct chunk *trash;
+       int len = 0, i;
+       char *s;
+       struct chunk *trash;
 
        for (i = 0; *text[i]; i++)
                len += strlen(text[i])+1;
@@ -498,12 +281,6 @@ pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usag
        return i;
 }
 
-/* Free data allocated by pat_parse_reg */
-static void pat_free_reg(void *ptr)
-{
-       regex_free(ptr);
-}
-
 /* Parse a regex. It is allocated. */
 int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
 {
@@ -768,6 +545,280 @@ int pat_parse_ip(const char **text, struct pattern *pattern, enum pat_usage usag
        }
 }
 
+/*
+ *
+ * These functions are exported and may be used by any other component.
+ *
+ * This fucntion just take a sample <smp> and check if this sample match
+ * with the pattern <pattern>. This fucntion return just PAT_MATCH or
+ * PAT_NOMATCH.
+ *
+ */
+
+/* always return false */
+enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern)
+{
+       return PAT_NOMATCH;
+}
+
+
+/* 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)
+{
+       int icase;
+
+       if (pattern->len != smp->data.str.len)
+               return PAT_NOMATCH;
+
+       icase = pattern->flags & PAT_F_IGNORE_CASE;
+       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
+           (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
+               return PAT_MATCH;
+       return PAT_NOMATCH;
+}
+
+/* NB: For two binaries buf to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern)
+{
+       if (pattern->len != smp->data.str.len)
+               return PAT_NOMATCH;
+
+       if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
+               return PAT_MATCH;
+       return PAT_NOMATCH;
+}
+
+/* Executes a regex. It temporarily changes the data to add a trailing zero,
+ * and restores the previous character when leaving.
+ */
+enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern)
+{
+       if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
+               return PAT_MATCH;
+       return PAT_NOMATCH;
+}
+
+/* Checks that the pattern matches the beginning of the tested string. */
+enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern)
+{
+       int icase;
+
+       if (pattern->len > smp->data.str.len)
+               return PAT_NOMATCH;
+
+       icase = pattern->flags & PAT_F_IGNORE_CASE;
+       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
+           (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
+               return PAT_NOMATCH;
+       return PAT_MATCH;
+}
+
+/* Checks that the pattern matches the end of the tested string. */
+enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern)
+{
+       int icase;
+
+       if (pattern->len > smp->data.str.len)
+               return PAT_NOMATCH;
+       icase = pattern->flags & PAT_F_IGNORE_CASE;
+       if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
+           (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
+               return PAT_NOMATCH;
+       return PAT_MATCH;
+}
+
+/* Checks that the pattern is included inside the tested string.
+ * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
+ */
+enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern)
+{
+       int icase;
+       char *end;
+       char *c;
+
+       if (pattern->len > smp->data.str.len)
+               return PAT_NOMATCH;
+
+       end = smp->data.str.str + smp->data.str.len - pattern->len;
+       icase = pattern->flags & PAT_F_IGNORE_CASE;
+       if (icase) {
+               for (c = smp->data.str.str; c <= end; c++) {
+                       if (tolower(*c) != tolower(*pattern->ptr.str))
+                               continue;
+                       if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
+                               return PAT_MATCH;
+               }
+       } else {
+               for (c = smp->data.str.str; c <= end; c++) {
+                       if (*c != *pattern->ptr.str)
+                               continue;
+                       if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
+                               return PAT_MATCH;
+               }
+       }
+       return PAT_NOMATCH;
+}
+
+/* This one is used by other real functions. It checks that the pattern is
+ * included inside the tested string, but enclosed between the specified
+ * delimiters or at the beginning or end of the string. The delimiters are
+ * provided as an unsigned int made by make_4delim() and match up to 4 different
+ * delimiters. Delimiters are stripped at the beginning and end of the pattern.
+ */
+static int match_word(struct sample *smp, struct pattern *pattern, unsigned int delimiters)
+{
+       int may_match, icase;
+       char *c, *end;
+       char *ps;
+       int pl;
+
+       pl = pattern->len;
+       ps = pattern->ptr.str;
+
+       while (pl > 0 && is_delimiter(*ps, delimiters)) {
+               pl--;
+               ps++;
+       }
+
+       while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
+               pl--;
+
+       if (pl > smp->data.str.len)
+               return PAT_NOMATCH;
+
+       may_match = 1;
+       icase = pattern->flags & PAT_F_IGNORE_CASE;
+       end = smp->data.str.str + smp->data.str.len - pl;
+       for (c = smp->data.str.str; c <= end; c++) {
+               if (is_delimiter(*c, delimiters)) {
+                       may_match = 1;
+                       continue;
+               }
+
+               if (!may_match)
+                       continue;
+
+               if (icase) {
+                       if ((tolower(*c) == tolower(*ps)) &&
+                           (strncasecmp(ps, c, pl) == 0) &&
+                           (c == end || is_delimiter(c[pl], delimiters)))
+                               return PAT_MATCH;
+               } else {
+                       if ((*c == *ps) &&
+                           (strncmp(ps, c, pl) == 0) &&
+                           (c == end || is_delimiter(c[pl], delimiters)))
+                               return PAT_MATCH;
+               }
+               may_match = 0;
+       }
+       return PAT_NOMATCH;
+}
+
+/* Checks that the pattern is included inside the tested string, but enclosed
+ * between the delimiters '?' or '/' or at the beginning or end of the string.
+ * Delimiters at the beginning or end of the pattern are ignored.
+ */
+enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern)
+{
+       return match_word(smp, pattern, make_4delim('/', '?', '?', '?'));
+}
+
+/* Checks that the pattern is included inside the tested string, but enclosed
+ * between the delmiters '/', '?', '.' or ":" or at the beginning or end of
+ * the string. Delimiters at the beginning or end of the pattern are ignored.
+ */
+enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern)
+{
+       return match_word(smp, pattern, make_4delim('/', '?', '.', ':'));
+}
+
+/* Checks that the integer in <test> is included between min and max */
+enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern)
+{
+       if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
+           (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
+               return PAT_MATCH;
+       return PAT_NOMATCH;
+}
+
+/* Checks that the length of the pattern in <test> is included between min and max */
+enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern)
+{
+       if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
+           (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
+               return PAT_MATCH;
+       return PAT_NOMATCH;
+}
+
+enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern)
+{
+       unsigned int v4; /* in network byte order */
+       struct in6_addr *v6;
+       int bits, pos;
+       struct in6_addr tmp6;
+
+       if (pattern->type == SMP_T_IPV4) {
+               if (smp->type == SMP_T_IPV4) {
+                       v4 = smp->data.ipv4.s_addr;
+               }
+               else if (smp->type == SMP_T_IPV6) {
+                       /* v4 match on a V6 sample. We want to check at least for
+                        * the following forms :
+                        *   - ::ffff:ip:v4 (ipv4 mapped)
+                        *   - ::0000:ip:v4 (old ipv4 mapped)
+                        *   - 2002:ip:v4:: (6to4)
+                        */
+                       if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
+                           *(uint32_t*)&smp->data.ipv6.s6_addr[4]  == 0 &&
+                           (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
+                            *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
+                               v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
+                       }
+                       else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
+                               v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
+                                           ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
+                       }
+                       else
+                               return PAT_NOMATCH;
+               }
+               else
+                       return PAT_NOMATCH;
+
+               if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
+                       return PAT_MATCH;
+               else
+                       return PAT_NOMATCH;
+       }
+       else if (pattern->type == SMP_T_IPV6) {
+               if (smp->type == SMP_T_IPV4) {
+                       /* Convert the IPv4 sample address to IPv4 with the
+                        * mapping method using the ::ffff: prefix.
+                        */
+                       memset(&tmp6, 0, 10);
+                       *(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
+                       *(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
+                       v6 = &tmp6;
+               }
+               else if (smp->type == SMP_T_IPV6) {
+                       v6 = &smp->data.ipv6;
+               }
+               else {
+                       return PAT_NOMATCH;
+               }
+
+               bits = pattern->val.ipv6.mask;
+               for (pos = 0; bits > 0; pos += 4, bits -= 32) {
+                       v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
+                       if (bits < 32)
+                               v4 &= htonl((~0U) << (32-bits));
+                       if (v4)
+                               return PAT_NOMATCH;
+               }
+               return PAT_MATCH;
+       }
+       return PAT_NOMATCH;
+}
+
 /* NB: does nothing if <pat> is NULL */
 void pattern_free(struct pattern *pat)
 {