mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
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.
This commit is contained in:
parent
39e258fcee
commit
0b2fe4a5cd
@ -68,7 +68,7 @@ enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *
|
|||||||
|
|
||||||
|
|
||||||
/* ignore the current line */
|
/* 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 */
|
/* 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);
|
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);
|
enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
|
||||||
|
|
||||||
/* Parse an integer. It is put both in min and max. */
|
/* 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 */
|
/* 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. */
|
/* 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
|
/* Parse a range of integers delimited by either ':' or '-'. If only one
|
||||||
* integer is read, it is set as both min and max.
|
* 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. */
|
/* 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. */
|
/* 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. */
|
/* 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. */
|
/* 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].
|
/* 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
|
* 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,
|
* may either be a dotted mask or a number of bits. Returns 1 if OK,
|
||||||
* otherwise 0.
|
* 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 */
|
/* always return false */
|
||||||
enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
|
enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
|
||||||
|
@ -92,7 +92,7 @@ struct acl_expr;
|
|||||||
struct acl_keyword {
|
struct acl_keyword {
|
||||||
const char *kw;
|
const char *kw;
|
||||||
char *fetch_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);
|
enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
|
||||||
/* must be after the config params */
|
/* must be after the config params */
|
||||||
struct sample_fetch *smp; /* the sample fetch we depend on */
|
struct sample_fetch *smp; /* the sample fetch we depend on */
|
||||||
|
@ -61,6 +61,15 @@ enum pat_match_res {
|
|||||||
PAT_MATCH = 3, /* sample matched at least one pattern */
|
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 */
|
/* possible flags for expressions or patterns */
|
||||||
enum {
|
enum {
|
||||||
PAT_F_IGNORE_CASE = 1 << 0, /* ignore case */
|
PAT_F_IGNORE_CASE = 1 << 0, /* ignore case */
|
||||||
@ -151,14 +160,14 @@ struct pattern {
|
|||||||
* are grouped together in order to optimize caching.
|
* are grouped together in order to optimize caching.
|
||||||
*/
|
*/
|
||||||
struct pattern_expr {
|
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);
|
enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
|
||||||
struct list patterns; /* list of acl_patterns */
|
struct list patterns; /* list of acl_patterns */
|
||||||
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
|
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern char *pat_match_names[PAT_MATCH_NUM];
|
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 enum pat_match_res (*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern *);
|
||||||
extern int pat_match_types[PAT_MATCH_NUM];
|
extern int pat_match_types[PAT_MATCH_NUM];
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ char *pat_match_names[PAT_MATCH_NUM] = {
|
|||||||
[PAT_MATCH_REG] = "reg",
|
[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_FOUND] = pat_parse_nothing,
|
||||||
[PAT_MATCH_BOOL] = pat_parse_nothing,
|
[PAT_MATCH_BOOL] = pat_parse_nothing,
|
||||||
[PAT_MATCH_INT] = pat_parse_int,
|
[PAT_MATCH_INT] = pat_parse_int,
|
||||||
@ -94,7 +94,7 @@ int pat_match_types[PAT_MATCH_NUM] = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* ignore the current line */
|
/* 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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -419,45 +419,70 @@ static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a string. It is allocated and duplicated. */
|
/* 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->type = SMP_T_CSTR;
|
||||||
pattern->expect_type = SMP_T_CSTR;
|
pattern->expect_type = SMP_T_CSTR;
|
||||||
pattern->ptr.str = strdup(*text);
|
if (usage == PAT_U_COMPILE) {
|
||||||
if (!pattern->ptr.str) {
|
pattern->ptr.str = strdup(*text);
|
||||||
memprintf(err, "out of memory while loading string pattern");
|
if (!pattern->ptr.str) {
|
||||||
return 0;
|
memprintf(err, "out of memory while loading string pattern");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
pattern->ptr.str = (char *)*text;
|
||||||
pattern->len = strlen(*text);
|
pattern->len = strlen(*text);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a binary written in hexa. It is allocated. */
|
/* 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->type = SMP_T_CBIN;
|
||||||
pattern->expect_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);
|
return parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse and concatenate all further strings into one. */
|
/* Parse and concatenate all further strings into one. */
|
||||||
int
|
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;
|
int len = 0, i;
|
||||||
char *s;
|
char *s;
|
||||||
|
struct chunk *trash;
|
||||||
|
|
||||||
for (i = 0; *text[i]; i++)
|
for (i = 0; *text[i]; i++)
|
||||||
len += strlen(text[i])+1;
|
len += strlen(text[i])+1;
|
||||||
|
|
||||||
pattern->type = SMP_T_CSTR;
|
pattern->type = SMP_T_CSTR;
|
||||||
pattern->ptr.str = s = calloc(1, len);
|
if (usage == PAT_U_COMPILE) {
|
||||||
if (!pattern->ptr.str) {
|
pattern->ptr.str = calloc(1, len);
|
||||||
memprintf(err, "out of memory while loading pattern");
|
if (!pattern->ptr.str) {
|
||||||
return 0;
|
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++)
|
for (i = 0; *text[i]; i++)
|
||||||
s += sprintf(s, i?" %s":"%s", text[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. */
|
/* 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 my_regex *preg;
|
||||||
|
struct chunk *trash;
|
||||||
|
|
||||||
preg = calloc(1, sizeof(*preg));
|
if (usage == PAT_U_COMPILE) {
|
||||||
|
|
||||||
if (!preg) {
|
preg = calloc(1, sizeof(*preg));
|
||||||
memprintf(err, "out of memory while loading pattern");
|
if (!preg) {
|
||||||
return 0;
|
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)) {
|
trash = get_trash_chunk();
|
||||||
free(preg);
|
if (trash->size < sizeof(*preg)) {
|
||||||
return 0;
|
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->ptr.reg = preg;
|
||||||
pattern->freeptrbuf = &pat_free_reg;
|
|
||||||
pattern->expect_type = SMP_T_CSTR;
|
pattern->expect_type = SMP_T_CSTR;
|
||||||
return 1;
|
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.
|
* 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;
|
signed long long i;
|
||||||
unsigned int j, last, skip = 0;
|
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;
|
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;
|
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;
|
pattern->expect_type = SMP_T_CSTR;
|
||||||
return ret;
|
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
|
* 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;
|
signed long long i;
|
||||||
unsigned int j, last, skip = 0;
|
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,
|
* 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).
|
* 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;
|
pattern->expect_type = SMP_T_ADDR;
|
||||||
if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
|
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));
|
memset(*pattern, 0, sizeof(**pattern));
|
||||||
(*pattern)->flags = patflags;
|
(*pattern)->flags = patflags;
|
||||||
|
|
||||||
ret = expr->parse(args, *pattern, &opaque, err);
|
ret = expr->parse(args, *pattern, PAT_U_COMPILE, &opaque, err);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -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
|
* 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.
|
* 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;
|
int len, meth;
|
||||||
|
struct chunk *trash;
|
||||||
|
|
||||||
len = strlen(*text);
|
len = strlen(*text);
|
||||||
meth = find_http_meth(*text, len);
|
meth = find_http_meth(*text, len);
|
||||||
|
|
||||||
pattern->val.i = meth;
|
pattern->val.i = meth;
|
||||||
if (meth == HTTP_METH_OTHER) {
|
if (meth == HTTP_METH_OTHER) {
|
||||||
pattern->ptr.str = strdup(*text);
|
if (usage == PAT_U_COMPILE) {
|
||||||
pattern->expect_type = SMP_T_CSTR;
|
pattern->ptr.str = strdup(*text);
|
||||||
if (!pattern->ptr.str) {
|
if (!pattern->ptr.str) {
|
||||||
memprintf(err, "out of memory while loading pattern");
|
memprintf(err, "out of memory while loading pattern");
|
||||||
return 0;
|
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;
|
pattern->len = len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user