MEDIUM: pattern: Extract the index process from the pat_parse_*() functions
Now, the pat_parse_*() functions parses the incoming data. The input
"pattern" struct can be preallocated. If the parser needs to add some
buffers, it allocates memory.
The function pattern_register() runs the call to the parser, process
the key indexation and associate the "sample_storage" used by maps.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 91bb335..80d4ee1 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -28,7 +28,7 @@
#include <common/standard.h>
#include <types/pattern.h>
-/* parse the <text> with <expr> compliant parser. <pattern> is a context for
+/* parse the <args> with <expr> compliant parser. <pattern> is a context for
* the current parsed acl. It must initialized at NULL:
*
* struct pattern *pattern = NULL
@@ -37,11 +37,10 @@
* patflag are a lot of 'PAT_F_*' flags pattern compatible. see
* <types/acl.h>.
*
- * The function returns 1 if the processing is ok, return -1 if the parser
- * fails, with <err> message filled. It returns -2 in "out of memory"
- * error case.
+ * The function returns 1 if the processing is ok, return 0
+ * if the parser fails, with <err> message filled.
*/
-int pattern_register(struct pattern_expr *expr, char *text, struct sample_storage *smp, struct pattern **pattern, int patflags, char **err);
+int pattern_register(struct pattern_expr *expr, const char **args, struct sample_storage *smp, struct pattern **pattern, int patflags, char **err);
/* return the PAT_MATCH_* index for match name "name", or < 0 if not found */
static inline int pat_find_match_name(const char *name)
@@ -69,7 +68,7 @@
/* ignore the current line */
-int pat_parse_nothing(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_nothing(const char **text, struct pattern *pattern, 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);
@@ -84,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, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_int(const char **text, struct pattern *pattern, int *opaque, char **err);
/* Parse len like an integer, but specify expected string type */
-int pat_parse_len(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_len(const char **text, struct pattern *pattern, 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, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_dotted_ver(const char **text, struct pattern *pattern, 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, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_range(const char **text, struct pattern *pattern, int *opaque, char **err);
/* Parse a string. It is allocated and duplicated. */
-int pat_parse_str(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_str(const char **text, struct pattern *pattern, int *opaque, char **err);
/* Parse a hexa binary definition. It is allocated and duplicated. */
-int pat_parse_bin(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_bin(const char **text, struct pattern *pattern, 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, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_strcat(const char **text, struct pattern *pattern, int *opaque, char **err);
/* Parse a regex. It is allocated. */
-int pat_parse_reg(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_reg(const char **text, struct pattern *pattern, 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, struct sample_storage *smp, int *opaque, char **err);
+int pat_parse_ip(const char **text, struct pattern *pattern, 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 e8c3e08..9692015 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, struct sample_storage *smp, int *opaque, char **err);
+ int (*parse)(const char **text, struct pattern *pattern, 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 d6136c2..ca3cf1f 100644
--- a/include/types/pattern.h
+++ b/include/types/pattern.h
@@ -65,8 +65,7 @@
enum {
PAT_F_IGNORE_CASE = 1 << 0, /* ignore case */
PAT_F_FROM_FILE = 1 << 1, /* pattern comes from a file */
- PAT_F_TREE_OK = 1 << 2, /* the pattern parser is allowed to build a tree */
- PAT_F_TREE = 1 << 3, /* some patterns are arranged in a tree */
+ PAT_F_TREE = 1 << 2, /* some patterns are arranged in a tree */
};
/* ACL match methods */
@@ -152,14 +151,14 @@
* are grouped together in order to optimize caching.
*/
struct pattern_expr {
- int (*parse)(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+ int (*parse)(const char **text, struct pattern *pattern, 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 *, struct sample_storage *, int *, char **);
+extern int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, 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/acl.c b/src/acl.c
index 974e919..ef6b4a3 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -133,7 +133,7 @@
struct acl_expr *expr;
struct acl_keyword *aclkw;
struct pattern *pattern;
- int opaque, patflags;
+ int patflags;
const char *arg;
struct sample_expr *smp = NULL;
const char *p;
@@ -497,23 +497,9 @@
}
/* now parse all patterns */
- opaque = 0;
- while (**args) {
- int ret;
- pattern = (struct pattern *)calloc(1, sizeof(*pattern));
- if (!pattern) {
- memprintf(err, "out of memory when parsing ACL pattern");
- goto out_free_expr;
- }
- pattern->flags = patflags;
-
- ret = expr->pat.parse(args, pattern, NULL, &opaque, err);
- if (!ret)
- goto out_free_pattern;
-
- LIST_ADDQ(&expr->pat.patterns, &pattern->list);
- args += ret;
- }
+ pattern = NULL;
+ if (!pattern_register(&expr->pat, args, NULL, &pattern, patflags, err))
+ goto out_free_pattern;
return expr;
diff --git a/src/map.c b/src/map.c
index fc961e7..a13c5b7 100644
--- a/src/map.c
+++ b/src/map.c
@@ -306,6 +306,7 @@
char **err)
{
struct sample_storage *smp;
+ const char *args[2];
/* use new smp for storing value */
smp = calloc(1, sizeof(*smp));
@@ -319,8 +320,10 @@
return 0;
}
- /* read and convert key */
- if (!pattern_register(desc->pat, ent->key, smp, pattern, patflags, err))
+ /* register key */
+ args[0] = ent->key;
+ args[1] = "";
+ if (!pattern_register(desc->pat, args, smp, pattern, patflags, err))
return 0;
return 1;
diff --git a/src/pattern.c b/src/pattern.c
index 6c2a5ba..6d7de52 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 *, struct sample_storage *, int *, char **) = {
+int (*pat_parse_fcts[PAT_MATCH_NUM])(const char **, struct pattern *, 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, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_nothing(const char **text, struct pattern *pattern, int *opaque, char **err)
{
return 1;
}
@@ -419,56 +419,31 @@
}
/* Parse a string. It is allocated and duplicated. */
-int pat_parse_str(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_str(const char **text, struct pattern *pattern, int *opaque, char **err)
{
- int len;
-
- len = strlen(*text);
pattern->type = SMP_T_CSTR;
pattern->expect_type = SMP_T_CSTR;
-
- if (pattern->flags & PAT_F_TREE_OK) {
- /* we're allowed to put the data in a tree whose root is pointed
- * to by val.tree.
- */
- struct pat_idx_elt *node;
-
- node = calloc(1, sizeof(*node) + len + 1);
- if (!node) {
- memprintf(err, "out of memory while loading string pattern");
- return 0;
- }
- node->smp = smp;
- memcpy(node->node.key, *text, len + 1);
- if (ebst_insert(pattern->val.tree, &node->node) != &node->node)
- free(node); /* was a duplicate */
- pattern->flags |= PAT_F_TREE; /* this pattern now contains a tree */
- return 1;
- }
-
pattern->ptr.str = strdup(*text);
- pattern->smp = smp;
if (!pattern->ptr.str) {
memprintf(err, "out of memory while loading string pattern");
return 0;
}
- pattern->len = len;
+ 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, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_bin(const char **text, struct pattern *pattern, int *opaque, char **err)
{
pattern->type = SMP_T_CBIN;
pattern->expect_type = SMP_T_CBIN;
- pattern->smp = smp;
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, struct sample_storage *smp, int *opaque, char **err)
+pat_parse_strcat(const char **text, struct pattern *pattern, int *opaque, char **err)
{
int len = 0, i;
@@ -479,7 +454,6 @@
pattern->type = SMP_T_CSTR;
pattern->ptr.str = s = calloc(1, len);
- pattern->smp = smp;
if (!pattern->ptr.str) {
memprintf(err, "out of memory while loading pattern");
return 0;
@@ -500,7 +474,7 @@
}
/* Parse a regex. It is allocated. */
-int pat_parse_reg(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_reg(const char **text, struct pattern *pattern, int *opaque, char **err)
{
regex *preg;
@@ -518,7 +492,6 @@
pattern->ptr.reg = preg;
pattern->freeptrbuf = &pat_free_reg;
- pattern->smp = smp;
pattern->expect_type = SMP_T_CSTR;
return 1;
}
@@ -537,7 +510,7 @@
* the caller will have to free it.
*
*/
-int pat_parse_int(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_int(const char **text, struct pattern *pattern, int *opaque, char **err)
{
signed long long i;
unsigned int j, last, skip = 0;
@@ -545,7 +518,7 @@
pattern->type = SMP_T_UINT;
pattern->expect_type = SMP_T_UINT;
- pattern->smp = smp;
+
while (!isdigit((unsigned char)*ptr)) {
switch (get_std_op(ptr)) {
case STD_OP_EQ: *opaque = 0; break;
@@ -610,11 +583,11 @@
return skip + 1;
}
-int pat_parse_len(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_len(const char **text, struct pattern *pattern, int *opaque, char **err)
{
int ret;
- ret = pat_parse_int(text, pattern, smp, opaque, err);
+ ret = pat_parse_int(text, pattern, opaque, err);
pattern->expect_type = SMP_T_CSTR;
return ret;
}
@@ -639,7 +612,7 @@
* acl valid_ssl ssl_req_proto 3.0-3.1
*
*/
-int pat_parse_dotted_ver(const char **text, struct pattern *pattern, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_dotted_ver(const char **text, struct pattern *pattern, int *opaque, char **err)
{
signed long long i;
unsigned int j, last, skip = 0;
@@ -698,7 +671,6 @@
return 0;
}
- pattern->smp = smp;
pattern->expect_type = SMP_T_CSTR;
if (!last)
@@ -731,38 +703,11 @@
* 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, struct sample_storage *smp, int *opaque, char **err)
+int pat_parse_ip(const char **text, struct pattern *pattern, int *opaque, char **err)
{
- struct eb_root *tree = NULL;
- if (pattern->flags & PAT_F_TREE_OK)
- tree = pattern->val.tree;
-
pattern->expect_type = SMP_T_ADDR;
if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
- unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
- struct pat_idx_elt *node;
- /* check if the mask is contiguous so that we can insert the
- * network into the tree. A continuous mask has only ones on
- * the left. This means that this mask + its lower bit added
- * once again is null.
- */
pattern->type = SMP_T_IPV4;
- if (mask + (mask & -mask) == 0 && tree) {
- mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
- /* FIXME: insert <addr>/<mask> into the tree here */
- node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */
- if (!node) {
- memprintf(err, "out of memory while loading IPv4 pattern");
- return 0;
- }
- node->smp = smp;
- memcpy(node->node.key, &pattern->val.ipv4.addr, 4); /* network byte order */
- node->node.node.pfx = mask;
- if (ebmb_insert_prefix(tree, &node->node, 4) != &node->node)
- free(node); /* was a duplicate */
- pattern->flags |= PAT_F_TREE;
- return 1;
- }
return 1;
}
else if (str62net(*text, &pattern->val.ipv6.addr, &pattern->val.ipv6.mask)) {
@@ -831,42 +776,152 @@
* return -1 if the parser fail. The err message is filled.
* return -2 if out of memory
*/
-int pattern_register(struct pattern_expr *expr, char *text,
+int pattern_register(struct pattern_expr *expr, const char **args,
struct sample_storage *smp,
struct pattern **pattern,
int patflags, char **err)
{
- const char *args[2];
int opaque = 0;
+ unsigned int mask = 0;
+ struct pat_idx_elt *node;
+ int len;
+ int ret;
- args[0] = text;
- args[1] = "";
+ /* eat args */
+ while (**args) {
- /* we keep the previous pattern along iterations as long as it's not used */
- if (!*pattern)
- *pattern = (struct pattern *)malloc(sizeof(**pattern));
- if (!*pattern)
- return -1;
+ /* we keep the previous pattern along iterations as long as it's not used */
+ if (!*pattern)
+ *pattern = (struct pattern *)malloc(sizeof(**pattern));
+ if (!*pattern) {
+ memprintf(err, "out of memory while loading pattern");
+ return 0;
+ }
- memset(*pattern, 0, sizeof(**pattern));
- (*pattern)->flags = patflags;
+ memset(*pattern, 0, sizeof(**pattern));
+ (*pattern)->flags = patflags;
- if (!((*pattern)->flags & PAT_F_IGNORE_CASE) &&
- (expr->match == pat_match_str || expr->match == pat_match_ip)) {
- /* we pre-set the data pointer to the tree's head so that functions
- * which are able to insert in a tree know where to do that.
+ ret = expr->parse(args, *pattern, &opaque, err);
+ if (!ret)
+ return 0;
+
+ /* each parser return the number of args eated */
+ args += ret;
+
+ /*
+ *
+ * SMP_T_CSTR tree indexation
+ *
+ * The match "pat_match_str()" can use tree.
+ *
*/
- (*pattern)->flags |= PAT_F_TREE_OK;
- (*pattern)->val.tree = &expr->pattern_tree;
- }
+ if (expr->match == pat_match_str) {
+
+ /* If the flag PAT_F_IGNORE_CASE is set, we cannot use trees */
+ if ((*pattern)->flags & PAT_F_IGNORE_CASE)
+ goto just_chain_the_pattern;
+
+ /* Process the key len */
+ len = strlen((*pattern)->ptr.str) + 1;
+
+ /* node memory allocation */
+ node = calloc(1, sizeof(*node) + len);
+ if (!node) {
+ memprintf(err, "out of memory while loading pattern");
+ return 0;
+ }
- if (!expr->parse(args, *pattern, smp, &opaque, err))
- return -1;
+ /* copy the pointer to sample associated to this node */
+ node->smp = smp;
+
+ /* copy the string */
+ memcpy(node->node.key, (*pattern)->ptr.str, len);
+
+ /* the "map_parser_str()" function always duplicate string information */
+ free((*pattern)->ptr.str);
+
+ /* we pre-set the data pointer to the tree's head so that functions
+ * which are able to insert in a tree know where to do that.
+ *
+ * because "val" is an "union", the previous data are crushed.
+ */
+ (*pattern)->flags |= PAT_F_TREE;
+ (*pattern)->val.tree = &expr->pattern_tree;
+
+ /* index the new node */
+ if (ebst_insert((*pattern)->val.tree, &node->node) != &node->node)
+ free(node); /* was a duplicate */
+ }
+
+ /*
+ *
+ * SMP_T_IPV4 tree indexation
+ *
+ * The match "pat_match_ip()" can use tree.
+ *
+ */
+ else if (expr->match == pat_match_ip) {
+
+ /* Only IPv4 can be indexed */
+ if ((*pattern)->type != SMP_T_IPV4)
+ goto just_chain_the_pattern;
+
+ /* in IPv4 case, check if the mask is contiguous so that we can
+ * insert the network into the tree. A continuous mask has only
+ * ones on the left. This means that this mask + its lower bit
+ * added once again is null.
+ */
+ mask = ntohl((*pattern)->val.ipv4.mask.s_addr);
+ if (mask + (mask & -mask) != 0)
+ goto just_chain_the_pattern;
+ mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
+
+ /* node memory allocation */
+ node = calloc(1, sizeof(*node) + 4);
+ if (!node) {
+ memprintf(err, "out of memory while loading pattern");
+ return 0;
+ }
+
+ /* copy the pointer to sample associated to this node */
+ node->smp = smp;
+
+ /* FIXME: insert <addr>/<mask> into the tree here */
+ memcpy(node->node.key, &(*pattern)->val.ipv4.addr, 4); /* network byte order */
+
+ /* we pre-set the data pointer to the tree's head so that functions
+ * which are able to insert in a tree know where to do that.
+ *
+ * because "val" is an "union", the previous data are crushed.
+ */
+ (*pattern)->flags |= PAT_F_TREE;
+ (*pattern)->val.tree = &expr->pattern_tree;
+
+ /* Index the new node
+ * FIXME: insert <addr>/<mask> into the tree here
+ */
+ node->node.node.pfx = mask;
+ if (ebmb_insert_prefix((*pattern)->val.tree, &node->node, 4) != &node->node)
+ free(node); /* was a duplicate */
+ }
- /* if the parser did not feed the tree, let's chain the pattern to the list */
- if (!((*pattern)->flags & PAT_F_TREE)) {
- LIST_ADDQ(&expr->patterns, &(*pattern)->list);
- *pattern = NULL; /* get a new one */
+ /*
+ *
+ * if the parser did not feed the tree, let's chain the pattern to the list
+ *
+ */
+ else {
+
+just_chain_the_pattern:
+
+ LIST_ADDQ(&expr->patterns, &(*pattern)->list);
+
+ /* copy the pointer to sample associated to this node */
+ (*pattern)->smp = smp;
+
+ /* get a new one */
+ *pattern = NULL;
+ }
}
return 1;
@@ -886,6 +941,7 @@
int ret = 0;
int line = 0;
int code;
+ const char *args[2];
file = fopen(filename, "r");
if (!file) {
@@ -920,7 +976,10 @@
if (c == arg)
continue;
- code = pattern_register(expr, arg, NULL, &pattern, patflags, err);
+ args[0] = arg;
+ args[1] = "";
+
+ code = pattern_register(expr, args, NULL, &pattern, patflags, err);
if (code == -2) {
memprintf(err, "out of memory when loading patterns from file <%s>", filename);
goto out_close;
diff --git a/src/proto_http.c b/src/proto_http.c
index 41561c5..2ce0d33 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -8735,14 +8735,13 @@
* 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, struct sample_storage *smp, int *opaque, char **err)
+static int pat_parse_meth(const char **text, struct pattern *pattern, int *opaque, char **err)
{
int len, meth;
len = strlen(*text);
meth = find_http_meth(*text, len);
- pattern->smp = smp;
pattern->val.i = meth;
if (meth == HTTP_METH_OTHER) {
pattern->ptr.str = strdup(*text);