From 469477879c815dd2123201f5958e112b2693fae0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 19 Jan 2015 19:00:58 +0100 Subject: [PATCH] MINOR: args: implement a new arg type for regex : ARGT_REG This one will be used when a regex is expected. It is automatically resolved after the parsing and compiled into a regex. Some optional flags are supported in the type-specific flags that should be set by the optional arg checker. One is used during the regex compilation : ARGF_REG_ICASE to ignore case. --- include/types/arg.h | 7 +++++++ src/arg.c | 2 ++ src/haproxy.c | 7 +++++++ src/sample.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/types/arg.h b/include/types/arg.h index f429b8296d..c621025783 100644 --- a/include/types/arg.h +++ b/include/types/arg.h @@ -57,6 +57,7 @@ enum { ARGT_SRV, /* a pointer to a server */ ARGT_USR, /* a pointer to a user list */ ARGT_MAP, /* a pointer to a map descriptor */ + ARGT_REG, /* a pointer to a regex */ }; /* context where arguments are used, in order to help error reporting */ @@ -72,10 +73,15 @@ enum { ARGC_CAP, /* capture rule */ }; +/* flags used when compiling and executing regex */ +#define ARGF_REG_ICASE 1 +#define ARGF_REG_GLOB 2 + /* some types that are externally defined */ struct proxy; struct server; struct userlist; +struct my_regex; union arg_data { unsigned int uint; /* used for uint, time, size */ @@ -87,6 +93,7 @@ union arg_data { struct server *srv; struct userlist *usr; struct map_descriptor *map; + struct my_regex *reg; }; struct arg { diff --git a/src/arg.c b/src/arg.c index a0717380a0..e609ac5f57 100644 --- a/src/arg.c +++ b/src/arg.c @@ -34,6 +34,7 @@ static const char *arg_type_names[ARGT_NBTYPES] = { [ARGT_SRV] = "server", [ARGT_USR] = "user list", [ARGT_MAP] = "map", + [ARGT_REG] = "regex", /* Unassigned types must never happen. Better crash during parsing if they do. */ }; @@ -173,6 +174,7 @@ int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp, case ARGT_TAB: case ARGT_SRV: case ARGT_USR: + case ARGT_REG: /* These argument types need to be stored as strings during * parsing then resolved later. */ diff --git a/src/haproxy.c b/src/haproxy.c index 31447bf082..60a0ca26ac 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1086,6 +1086,13 @@ static void deinit_sample_arg(struct arg *p) p->data.str.str = NULL; p->unresolved = 0; } + else if (p->type == ARGT_REG) { + if (p->data.reg) { + regex_free(p->data.reg); + free(p->data.reg); + p->data.reg = NULL; + } + } p++; } diff --git a/src/sample.c b/src/sample.c index 377c4c8f3f..8fe341f399 100644 --- a/src/sample.c +++ b/src/sample.c @@ -983,13 +983,16 @@ int smp_resolve_args(struct proxy *p) const char *ctx, *where; const char *conv_ctx, *conv_pre, *conv_pos; struct userlist *ul; + struct my_regex *reg; struct arg *arg; int cfgerr = 0; + int rflags; list_for_each_entry_safe(cur, bak, &p->conf.args.list, list) { struct proxy *px; struct server *srv; char *pname, *sname; + char *err; arg = cur->arg; @@ -1004,7 +1007,7 @@ int smp_resolve_args(struct proxy *p) where = "in"; ctx = "sample fetch keyword"; switch (cur->ctx) { - case ARGC_STK:where = "in stick rule in"; break; + case ARGC_STK: where = "in stick rule in"; break; case ARGC_TRK: where = "in tracking rule in"; break; case ARGC_LOG: where = "in log-format string in"; break; case ARGC_HRQ: where = "in http-request header format string in"; break; @@ -1175,6 +1178,45 @@ int smp_resolve_args(struct proxy *p) arg->unresolved = 0; arg->data.usr = ul; break; + + case ARGT_REG: + if (!arg->data.str.len) { + Alert("parsing [%s:%d] : missing regex in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", + cur->file, cur->line, + cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id); + cfgerr++; + continue; + } + + reg = calloc(1, sizeof(*reg)); + if (!reg) { + Alert("parsing [%s:%d] : not enough memory to build regex in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", + cur->file, cur->line, + cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id); + cfgerr++; + continue; + } + + rflags = 0; + rflags |= (arg->type_flags & ARGF_REG_ICASE) ? REG_ICASE : 0; + err = NULL; + + if (!regex_comp(arg->data.str.str, reg, rflags, 1 /* capture substr */, &err)) { + Alert("parsing [%s:%d] : error in regex '%s' in arg %d of %s%s%s%s '%s' %s proxy '%s' : %s.\n", + cur->file, cur->line, + arg->data.str.str, + cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id, err); + cfgerr++; + continue; + } + + free(arg->data.str.str); + arg->data.str.str = NULL; + arg->unresolved = 0; + arg->data.reg = reg; + break; + + } LIST_DEL(&cur->list);