mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-11 03:31:36 +00:00
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the case with sample fetch args because they're almost everywhere now. The issue is that ACLs now solely rely on sample fetches, so their args resolving doesn't work anymore. And many fetches involving a server, a proxy or a userlist don't work at all. The real issue is that at the bottom layers we have no information about proxies, line numbers, even ACLs in order to report understandable errors, and that at the top layers we have no visibility over the locations where fetches are referenced (think log node). After failing multiple unsatisfying solutions attempts, we now have a new concept of args list. The principle is that every proxy has a list head which contains a number of indications such as the config keyword, the context where it's used, the file and line number, etc... and a list of arguments. This list head is of the same type as the elements, so it serves as a template for adding new elements. This way, it is filled from top to bottom by the callers with the information they have (eg: line numbers, ACL name, ...) and the lower layers just have to duplicate it and add an element when they face an argument they cannot resolve yet. Then at the end of the configuration parsing, a loop passes over each proxy's list and resolves all the args in sequence. And this way there is all necessary information to report verbose errors. The first immediate benefit is that for the first time we got very precise location of issues (arg number in a keyword in its context, ...). Second, in order to do this we had to parse log-format and unique-id-format a bit earlier, so that was a great opportunity for doing so when the directives are encountered (unless it's a default section). This way, the recorded line numbers for these args are the ones of the place where the log format is declared, not the end of the file. Userlists report slightly more information now. They're the only remaining ones in the ACL resolving function.
This commit is contained in:
parent
0a0daecbb2
commit
a4312fa28e
@ -59,7 +59,7 @@ struct acl_keyword *find_acl_kw(const char *kw);
|
||||
* Right now, the only accepted syntax is :
|
||||
* <subject> [<value>...]
|
||||
*/
|
||||
struct acl_expr *parse_acl_expr(const char **args, char **err);
|
||||
struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *al);
|
||||
|
||||
/* Purge everything in the acl <acl>, then return <acl>. */
|
||||
struct acl *prune_acl(struct acl *acl);
|
||||
@ -70,7 +70,7 @@ struct acl *prune_acl(struct acl *acl);
|
||||
*
|
||||
* args syntax: <aclname> <acl_expr>
|
||||
*/
|
||||
struct acl *parse_acl(const char **args, struct list *known_acl, char **err);
|
||||
struct acl *parse_acl(const char **args, struct list *known_acl, char **err, struct arg_list *al);
|
||||
|
||||
/* Purge everything in the acl_cond <cond>, then return <cond>. */
|
||||
struct acl_cond *prune_acl_cond(struct acl_cond *cond);
|
||||
@ -79,7 +79,7 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond);
|
||||
* known ACLs passed in <known_acl>. The new condition is returned (or NULL in
|
||||
* case of low memory). Supports multiple conditions separated by "or".
|
||||
*/
|
||||
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err);
|
||||
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err, struct arg_list *al);
|
||||
|
||||
/* Builds an ACL condition starting at the if/unless keyword. The complete
|
||||
* condition is returned. NULL is returned in case of error or if the first
|
||||
|
@ -59,8 +59,11 @@
|
||||
*/
|
||||
extern struct arg empty_arg_list[8];
|
||||
|
||||
struct arg_list *arg_list_clone(const struct arg_list *orig);
|
||||
struct arg_list *arg_list_add(struct arg_list *orig, struct arg *arg, int pos);
|
||||
int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
char **err_msg, const char **err_ptr, int *err_arg);
|
||||
char **err_msg, const char **err_ptr, int *err_arg,
|
||||
struct arg_list *al);
|
||||
|
||||
#endif /* _PROTO_ARG_H */
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <types/sample.h>
|
||||
#include <types/stick_table.h>
|
||||
|
||||
struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size);
|
||||
struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size, struct arg_list *al);
|
||||
struct sample *sample_process(struct proxy *px, struct session *l4,
|
||||
void *l7, unsigned int dir, struct sample_expr *expr,
|
||||
struct sample *p);
|
||||
@ -37,5 +37,6 @@ void sample_register_convs(struct sample_conv_kw_list *psl);
|
||||
const char *sample_src_names(unsigned int use);
|
||||
const char *sample_ckp_names(unsigned int use);
|
||||
struct sample_fetch *find_sample_fetch(const char *kw, int len);
|
||||
int smp_resolve_args(struct proxy *p);
|
||||
|
||||
#endif /* _PROTO_SAMPLE_H */
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <common/chunk.h>
|
||||
#include <common/mini-clist.h>
|
||||
|
||||
enum {
|
||||
ARGT_STOP = 0, /* end of the arg list */
|
||||
@ -47,6 +48,16 @@ enum {
|
||||
ARGT_NBTYPES /* no more values past 15 */
|
||||
};
|
||||
|
||||
/* context where arguments are used, in order to help error reporting */
|
||||
enum {
|
||||
ARGC_ACL = 0, /* ACL */
|
||||
ARGC_STK, /* sticking rule */
|
||||
ARGC_TRK, /* tracking rule */
|
||||
ARGC_LOG, /* log-format */
|
||||
ARGC_HDR, /* add-header */
|
||||
ARGC_UIF, /* unique-id-format */
|
||||
};
|
||||
|
||||
/* some types that are externally defined */
|
||||
struct proxy;
|
||||
struct server;
|
||||
@ -69,6 +80,21 @@ struct arg {
|
||||
union arg_data data; /* argument data */
|
||||
};
|
||||
|
||||
/* arg lists are used to store information about arguments that could not be
|
||||
* resolved when parsing the configuration. The head is an arg_list which
|
||||
* serves as a template to create new entries. Nothing here is allocated,
|
||||
* so plain copies are OK.
|
||||
*/
|
||||
struct arg_list {
|
||||
struct list list; /* chaining with other arg_list, or list head */
|
||||
struct arg *arg; /* pointer to the arg, NULL on list head */
|
||||
int arg_pos; /* argument position */
|
||||
int ctx; /* context where the arg is used (ARGC_*) */
|
||||
const char *kw; /* keyword making use of these args */
|
||||
const char *conv; /* conv keyword when in conv, otherwise NULL */
|
||||
const char *file; /* file name where the args are referenced */
|
||||
int line; /* line number where the args are referenced */
|
||||
};
|
||||
|
||||
#endif /* _TYPES_ARG_H */
|
||||
|
||||
|
@ -350,6 +350,7 @@ struct proxy {
|
||||
struct eb_root used_server_id; /* list of server IDs in use */
|
||||
struct list bind; /* list of bind settings */
|
||||
struct list listeners; /* list of listeners belonging to this frontend */
|
||||
struct arg_list args; /* sample arg list that need to be resolved */
|
||||
} conf; /* config information */
|
||||
void *parent; /* parent of the proxy when applicable */
|
||||
struct comp *comp; /* http compression */
|
||||
|
238
src/acl.c
238
src/acl.c
@ -1024,12 +1024,13 @@ static int acl_read_patterns_from_file(struct acl_expr *expr,
|
||||
|
||||
/* Parse an ACL expression starting at <args>[0], and return it. If <err> is
|
||||
* not NULL, it will be filled with a pointer to an error message in case of
|
||||
* error. This pointer must be freeable or NULL.
|
||||
* error. This pointer must be freeable or NULL. <al> is an arg_list serving
|
||||
* as a list head to report missing dependencies.
|
||||
*
|
||||
* Right now, the only accepted syntax is :
|
||||
* <subject> [<value>...]
|
||||
*/
|
||||
struct acl_expr *parse_acl_expr(const char **args, char **err)
|
||||
struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *al)
|
||||
{
|
||||
__label__ out_return, out_free_expr, out_free_pattern;
|
||||
struct acl_expr *expr;
|
||||
@ -1088,10 +1089,14 @@ struct acl_expr *parse_acl_expr(const char **args, char **err)
|
||||
/* Parse the arguments. Note that currently we have no way to
|
||||
* report parsing errors, hence the NULL in the error pointers.
|
||||
* An error is also reported if some mandatory arguments are
|
||||
* missing.
|
||||
* missing. We prepare the args list to report unresolved
|
||||
* dependencies.
|
||||
*/
|
||||
al->ctx = ARGC_ACL;
|
||||
al->kw = expr->kw;
|
||||
al->conv = NULL;
|
||||
nbargs = make_arg_list(arg, end - arg, expr->smp->arg_mask, &expr->args,
|
||||
err, NULL, NULL);
|
||||
err, NULL, NULL, al);
|
||||
if (nbargs < 0) {
|
||||
/* note that make_arg_list will have set <err> here */
|
||||
memprintf(err, "in argument to '%s', %s", expr->kw, *err);
|
||||
@ -1273,11 +1278,12 @@ struct acl *prune_acl(struct acl *acl) {
|
||||
* A pointer to that ACL is returned. If the ACL has an empty name, then it's
|
||||
* an anonymous one and it won't be merged with any other one. If <err> is not
|
||||
* NULL, it will be filled with an appropriate error. This pointer must be
|
||||
* freeable or NULL.
|
||||
* freeable or NULL. <al> is the arg_list serving as a head for unresolved
|
||||
* dependencies.
|
||||
*
|
||||
* args syntax: <aclname> <acl_expr>
|
||||
*/
|
||||
struct acl *parse_acl(const char **args, struct list *known_acl, char **err)
|
||||
struct acl *parse_acl(const char **args, struct list *known_acl, char **err, struct arg_list *al)
|
||||
{
|
||||
__label__ out_return, out_free_acl_expr, out_free_name;
|
||||
struct acl *cur_acl;
|
||||
@ -1290,7 +1296,7 @@ struct acl *parse_acl(const char **args, struct list *known_acl, char **err)
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
acl_expr = parse_acl_expr(args + 1, err);
|
||||
acl_expr = parse_acl_expr(args + 1, err, al);
|
||||
if (!acl_expr) {
|
||||
/* parse_acl_expr will have filled <err> here */
|
||||
goto out_return;
|
||||
@ -1381,9 +1387,11 @@ const struct {
|
||||
* except when default ACLs are broken, in which case it will return NULL.
|
||||
* If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
|
||||
* not NULL, it will be filled with an error message if an error occurs. This
|
||||
* pointer must be freeable or NULL.
|
||||
* pointer must be freeable or NULL. <al> is an arg_list serving as a list head
|
||||
* to report missing dependencies.
|
||||
*/
|
||||
struct acl *find_acl_default(const char *acl_name, struct list *known_acl, char **err)
|
||||
static struct acl *find_acl_default(const char *acl_name, struct list *known_acl,
|
||||
char **err, struct arg_list *al)
|
||||
{
|
||||
__label__ out_return, out_free_acl_expr, out_free_name;
|
||||
struct acl *cur_acl;
|
||||
@ -1401,7 +1409,7 @@ struct acl *find_acl_default(const char *acl_name, struct list *known_acl, char
|
||||
return NULL;
|
||||
}
|
||||
|
||||
acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err);
|
||||
acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err, al);
|
||||
if (!acl_expr) {
|
||||
/* parse_acl_expr must have filled err here */
|
||||
goto out_return;
|
||||
@ -1458,9 +1466,11 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond)
|
||||
* case of low memory). Supports multiple conditions separated by "or". If
|
||||
* <err> is not NULL, it will be filled with a pointer to an error message in
|
||||
* case of error, that the caller is responsible for freeing. The initial
|
||||
* location must either be freeable or NULL.
|
||||
* location must either be freeable or NULL. The list <al> serves as a list head
|
||||
* for unresolved dependencies.
|
||||
*/
|
||||
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err)
|
||||
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl,
|
||||
int pol, char **err, struct arg_list *al)
|
||||
{
|
||||
__label__ out_return, out_free_suite, out_free_term;
|
||||
int arg, neg;
|
||||
@ -1533,7 +1543,7 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
|
||||
args_new[0] = "";
|
||||
memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
|
||||
args_new[arg_end - arg] = "";
|
||||
cur_acl = parse_acl(args_new, known_acl, err);
|
||||
cur_acl = parse_acl(args_new, known_acl, err, al);
|
||||
free(args_new);
|
||||
|
||||
if (!cur_acl) {
|
||||
@ -1551,7 +1561,7 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
|
||||
*/
|
||||
cur_acl = find_acl_by_name(word, known_acl);
|
||||
if (cur_acl == NULL) {
|
||||
cur_acl = find_acl_default(word, known_acl, err);
|
||||
cur_acl = find_acl_default(word, known_acl, err, al);
|
||||
if (cur_acl == NULL) {
|
||||
/* note that find_acl_default() must have filled <err> here */
|
||||
goto out_free_suite;
|
||||
@ -1635,7 +1645,7 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, co
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cond = parse_acl_cond(args, &px->acl, pol, err);
|
||||
cond = parse_acl_cond(args, &px->acl, pol, err, &px->conf.args);
|
||||
if (!cond) {
|
||||
/* note that parse_acl_cond must have filled <err> here */
|
||||
return NULL;
|
||||
@ -1838,191 +1848,29 @@ int acl_cond_kw_conflicts(const struct acl_cond *cond, unsigned int where, struc
|
||||
|
||||
/*
|
||||
* Find targets for userlist and groups in acl. Function returns the number
|
||||
* of errors or OK if everything is fine.
|
||||
* of errors or OK if everything is fine. It must be called only once sample
|
||||
* fetch arguments have been resolved (after smp_resolve_args()).
|
||||
*/
|
||||
int
|
||||
acl_find_targets(struct proxy *p)
|
||||
int acl_find_targets(struct proxy *p)
|
||||
{
|
||||
|
||||
struct acl *acl;
|
||||
struct acl_expr *expr;
|
||||
struct acl_pattern *pattern;
|
||||
struct userlist *ul;
|
||||
struct arg *arg;
|
||||
int cfgerr = 0;
|
||||
|
||||
list_for_each_entry(acl, &p->acl, list) {
|
||||
list_for_each_entry(expr, &acl->expr, list) {
|
||||
for (arg = expr->args; arg && arg->type != ARGT_STOP; arg++) {
|
||||
if (!arg->unresolved)
|
||||
continue;
|
||||
else if (arg->type == ARGT_SRV) {
|
||||
struct proxy *px;
|
||||
struct server *srv;
|
||||
char *pname, *sname;
|
||||
|
||||
if (!arg->data.str.len) {
|
||||
Alert("proxy %s: acl '%s' %s(): missing server name.\n",
|
||||
p->id, acl->name, expr->kw);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
pname = arg->data.str.str;
|
||||
sname = strrchr(pname, '/');
|
||||
|
||||
if (sname)
|
||||
*sname++ = '\0';
|
||||
else {
|
||||
sname = pname;
|
||||
pname = NULL;
|
||||
}
|
||||
|
||||
px = p;
|
||||
if (pname) {
|
||||
px = findproxy(pname, PR_CAP_BE);
|
||||
if (!px) {
|
||||
Alert("proxy %s: acl '%s' %s(): unable to find proxy '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
srv = findserver(px, sname);
|
||||
if (!srv) {
|
||||
Alert("proxy %s: acl '%s' %s(): unable to find server '%s'.\n",
|
||||
p->id, acl->name, expr->kw, sname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.srv = srv;
|
||||
}
|
||||
else if (arg->type == ARGT_FE) {
|
||||
struct proxy *prx = p;
|
||||
char *pname = p->id;
|
||||
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
prx = findproxy(pname, PR_CAP_FE);
|
||||
}
|
||||
|
||||
if (!prx) {
|
||||
Alert("proxy %s: acl '%s' %s(): unable to find frontend '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(prx->cap & PR_CAP_FE)) {
|
||||
Alert("proxy %s: acl '%s' %s(): proxy '%s' has no frontend capability.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = prx;
|
||||
}
|
||||
else if (arg->type == ARGT_BE) {
|
||||
struct proxy *prx = p;
|
||||
char *pname = p->id;
|
||||
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
prx = findproxy(pname, PR_CAP_BE);
|
||||
}
|
||||
|
||||
if (!prx) {
|
||||
Alert("proxy %s: acl '%s' %s(): unable to find backend '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(prx->cap & PR_CAP_BE)) {
|
||||
Alert("proxy %s: acl '%s' %s(): proxy '%s' has no backend capability.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = prx;
|
||||
}
|
||||
else if (arg->type == ARGT_TAB) {
|
||||
struct proxy *prx = p;
|
||||
char *pname = p->id;
|
||||
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
prx = find_stktable(pname);
|
||||
}
|
||||
|
||||
if (!prx) {
|
||||
Alert("proxy %s: acl '%s' %s(): unable to find table '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!prx->table.size) {
|
||||
Alert("proxy %s: acl '%s' %s(): no table in proxy '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pname);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = prx;
|
||||
}
|
||||
else if (arg->type == ARGT_USR) {
|
||||
if (!arg->data.str.len) {
|
||||
Alert("proxy %s: acl '%s' %s(): missing userlist name.\n",
|
||||
p->id, acl->name, expr->kw);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->uri_auth && p->uri_auth->userlist &&
|
||||
!strcmp(p->uri_auth->userlist->name, arg->data.str.str))
|
||||
ul = p->uri_auth->userlist;
|
||||
else
|
||||
ul = auth_find_userlist(arg->data.str.str);
|
||||
|
||||
if (!ul) {
|
||||
Alert("proxy %s: acl '%s' %s(%s): unable to find userlist.\n",
|
||||
p->id, acl->name, expr->kw, arg->data.str.str);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.usr = ul;
|
||||
}
|
||||
} /* end of args processing */
|
||||
|
||||
/* don't try to resolve groups if we're not certain of having
|
||||
* resolved userlists first.
|
||||
*/
|
||||
if (cfgerr)
|
||||
break;
|
||||
|
||||
if (!strcmp(expr->kw, "http_auth_group")) {
|
||||
/* note: argument resolved above thanks to ARGT_USR */
|
||||
/* Note: the ARGT_USR argument may only have been resolved earlier
|
||||
* by smp_resolve_args().
|
||||
*/
|
||||
if (expr->args->unresolved) {
|
||||
Alert("Internal bug in proxy %s: %sacl %s %s() makes use of unresolved userlist '%s'. Please report this.\n",
|
||||
p->id, *acl->name ? "" : "anonymous ", acl->name, expr->kw, expr->args->data.str.str);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LIST_ISEMPTY(&expr->patterns)) {
|
||||
Alert("proxy %s: acl %s %s(): no groups specified.\n",
|
||||
@ -2035,16 +1883,14 @@ acl_find_targets(struct proxy *p)
|
||||
/* this keyword only has one argument */
|
||||
pattern->val.group_mask = auth_resolve_groups(expr->args->data.usr, pattern->ptr.str);
|
||||
|
||||
if (!pattern->val.group_mask) {
|
||||
Alert("proxy %s: acl %s %s(): invalid group '%s'.\n",
|
||||
p->id, acl->name, expr->kw, pattern->ptr.str);
|
||||
cfgerr++;
|
||||
}
|
||||
free(pattern->ptr.str);
|
||||
pattern->ptr.str = NULL;
|
||||
pattern->len = 0;
|
||||
|
||||
if (!pattern->val.group_mask) {
|
||||
Alert("proxy %s: acl %s %s(): invalid group(s).\n",
|
||||
p->id, acl->name, expr->kw);
|
||||
cfgerr++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
58
src/arg.c
58
src/arg.c
@ -41,6 +41,41 @@ static const char *arg_type_names[ARGT_NBTYPES] = {
|
||||
*/
|
||||
struct arg empty_arg_list[8] = { };
|
||||
|
||||
/* This function clones a struct arg_list template into a new one which is
|
||||
* returned.
|
||||
*/
|
||||
struct arg_list *arg_list_clone(const struct arg_list *orig)
|
||||
{
|
||||
struct arg_list *new;
|
||||
|
||||
if ((new = calloc(1, sizeof(*new))) != NULL) {
|
||||
/* ->list will be set by the caller when inserting the element.
|
||||
* ->arg and ->arg_pos will be set by the caller.
|
||||
*/
|
||||
new->ctx = orig->ctx;
|
||||
new->kw = orig->kw;
|
||||
new->conv = orig->conv;
|
||||
new->file = orig->file;
|
||||
new->line = orig->line;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
/* This function clones a struct <arg_list> template into a new one which is
|
||||
* set to point to arg <arg> at pos <pos>, and which is returned if the caller
|
||||
* wants to apply further changes.
|
||||
*/
|
||||
struct arg_list *arg_list_add(struct arg_list *orig, struct arg *arg, int pos)
|
||||
{
|
||||
struct arg_list *new;
|
||||
|
||||
new = arg_list_clone(orig);
|
||||
new->arg = arg;
|
||||
new->arg_pos = pos;
|
||||
LIST_ADDQ(&orig->list, &new->list);
|
||||
return new;
|
||||
}
|
||||
|
||||
/* This function builds an argument list from a config line. It returns the
|
||||
* number of arguments found, or <0 in case of any error. Everything needed
|
||||
* it automatically allocated. A pointer to an error message might be returned
|
||||
@ -48,21 +83,26 @@ struct arg empty_arg_list[8] = { };
|
||||
* will have to check it and free it. The output arg list is returned in argp
|
||||
* which must be valid. The returned array is always terminated by an arg of
|
||||
* type ARGT_STOP (0), unless the mask indicates that no argument is supported.
|
||||
* The mask is composed of a number of mandatory arguments in its lower 4 bits,
|
||||
* and a concatenation of each argument type in each subsequent 4-bit block. If
|
||||
* <err_msg> is not NULL, it must point to a freeable or NULL pointer.
|
||||
* Unresolved arguments are appended to arg list <al>, which also serves as a
|
||||
* template to create new entries. The mask is composed of a number of
|
||||
* mandatory arguments in its lower 4 bits, and a concatenation of each
|
||||
* argument type in each subsequent 4-bit block. If <err_msg> is not NULL, it
|
||||
* must point to a freeable or NULL pointer.
|
||||
*/
|
||||
int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
char **err_msg, const char **err_ptr, int *err_arg)
|
||||
char **err_msg, const char **err_ptr, int *err_arg,
|
||||
struct arg_list *al)
|
||||
{
|
||||
int nbarg;
|
||||
int pos;
|
||||
struct arg *arg, *arg_list = NULL;
|
||||
struct arg *arg;
|
||||
const char *beg;
|
||||
char *word = NULL;
|
||||
const char *ptr_err = NULL;
|
||||
int min_arg;
|
||||
|
||||
*argp = NULL;
|
||||
|
||||
min_arg = mask & 15;
|
||||
mask >>= 4;
|
||||
|
||||
@ -79,7 +119,7 @@ int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
if (!len && !min_arg)
|
||||
goto end_parse;
|
||||
|
||||
arg = arg_list = calloc(nbarg + 1, sizeof(*arg));
|
||||
arg = *argp = calloc(nbarg + 1, sizeof(*arg));
|
||||
|
||||
/* Note: empty arguments after a comma always exist. */
|
||||
while (pos < nbarg) {
|
||||
@ -136,6 +176,8 @@ int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
* parsing then resolved later.
|
||||
*/
|
||||
arg->unresolved = 1;
|
||||
arg_list_add(al, arg, pos);
|
||||
|
||||
/* fall through */
|
||||
case ARGT_STR:
|
||||
/* all types that must be resolved are stored as strings
|
||||
@ -239,8 +281,6 @@ int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
/* note that pos might be < nbarg and this is not an error, it's up to the
|
||||
* caller to decide what to do with optional args.
|
||||
*/
|
||||
*argp = arg_list;
|
||||
|
||||
if (err_arg)
|
||||
*err_arg = pos;
|
||||
if (err_ptr)
|
||||
@ -249,7 +289,7 @@ int make_arg_list(const char *in, int len, unsigned int mask, struct arg **argp,
|
||||
|
||||
err:
|
||||
free(word);
|
||||
free(arg_list);
|
||||
free(*argp);
|
||||
if (err_arg)
|
||||
*err_arg = pos;
|
||||
if (err_ptr)
|
||||
|
@ -1572,8 +1572,8 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
|
||||
curpeers->peers_fe->timeout.connect = 5000;
|
||||
curpeers->peers_fe->accept = peer_accept;
|
||||
curpeers->peers_fe->options2 |= PR_O2_INDEPSTR | PR_O2_SMARTCON | PR_O2_SMARTACC;
|
||||
curpeers->peers_fe->conf.file = strdup(file);
|
||||
curpeers->peers_fe->conf.line = linenum;
|
||||
curpeers->peers_fe->conf.args.file = curpeers->peers_fe->conf.file = strdup(file);
|
||||
curpeers->peers_fe->conf.args.line = curpeers->peers_fe->conf.line = linenum;
|
||||
|
||||
bind_conf = bind_conf_alloc(&curpeers->peers_fe->conf.bind, file, linenum, args[2]);
|
||||
|
||||
@ -1692,8 +1692,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
init_new_proxy(curproxy);
|
||||
curproxy->next = proxy;
|
||||
proxy = curproxy;
|
||||
curproxy->conf.file = strdup(file);
|
||||
curproxy->conf.line = linenum;
|
||||
curproxy->conf.args.file = curproxy->conf.file = strdup(file);
|
||||
curproxy->conf.args.line = curproxy->conf.line = linenum;
|
||||
curproxy->last_change = now.tv_sec;
|
||||
curproxy->id = strdup(args[1]);
|
||||
curproxy->cap = rc;
|
||||
@ -1925,6 +1925,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
/* we cannot free uri_auth because it might already be used */
|
||||
init_default_instance();
|
||||
curproxy = &defproxy;
|
||||
curproxy->conf.args.file = curproxy->conf.file = strdup(file);
|
||||
curproxy->conf.args.line = curproxy->conf.line = linenum;
|
||||
defproxy.cap = PR_CAP_LISTEN; /* all caps for now */
|
||||
goto out;
|
||||
}
|
||||
@ -1933,7 +1935,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
/* update the current file and line being parsed */
|
||||
curproxy->conf.args.file = curproxy->conf.file;
|
||||
curproxy->conf.args.line = linenum;
|
||||
|
||||
/* Now let's parse the proxy-specific keywords */
|
||||
if (!strcmp(args[0], "bind")) { /* new listen addresses */
|
||||
@ -2225,7 +2230,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg) == NULL) {
|
||||
if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg, &curproxy->conf.args) == NULL) {
|
||||
Alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
|
||||
file, linenum, args[1], errmsg);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
@ -3023,7 +3028,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
goto out;
|
||||
}
|
||||
|
||||
expr = sample_parse_expr(args, &myidx, trash.str, trash.size);
|
||||
curproxy->conf.args.ctx = ARGC_STK;
|
||||
expr = sample_parse_expr(args, &myidx, trash.str, trash.size, &curproxy->conf.args);
|
||||
if (!expr) {
|
||||
Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], trash.str);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
@ -4825,6 +4831,18 @@ stats_error_parsing:
|
||||
}
|
||||
free(curproxy->uniqueid_format_string);
|
||||
curproxy->uniqueid_format_string = strdup(args[1]);
|
||||
|
||||
/* get a chance to improve log-format error reporting by
|
||||
* reporting the correct line-number when possible.
|
||||
*/
|
||||
if (curproxy != &defproxy) {
|
||||
curproxy->conf.args.ctx = ARGC_UIF;
|
||||
if (curproxy->uniqueid_format_string)
|
||||
parse_logformat_string(curproxy->uniqueid_format_string, curproxy, &curproxy->format_unique_id, 0,
|
||||
(proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||
free(curproxy->uniqueid_format_string);
|
||||
curproxy->uniqueid_format_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(args[0], "unique-id-header") == 0) {
|
||||
@ -4854,6 +4872,23 @@ stats_error_parsing:
|
||||
curproxy->logformat_string != clf_http_log_format)
|
||||
free(curproxy->logformat_string);
|
||||
curproxy->logformat_string = strdup(args[1]);
|
||||
|
||||
/* get a chance to improve log-format error reporting by
|
||||
* reporting the correct line-number when possible.
|
||||
*/
|
||||
if (curproxy != &defproxy && !(curproxy->cap & PR_CAP_FE)) {
|
||||
Warning("parsing [%s:%d] : backend '%s' : 'log-format' directive is ignored in backends.\n",
|
||||
file, linenum, curproxy->id);
|
||||
err_code |= ERR_WARN;
|
||||
}
|
||||
else if (curproxy->cap & PR_CAP_FE) {
|
||||
curproxy->conf.args.ctx = ARGC_LOG;
|
||||
if (curproxy->logformat_string)
|
||||
parse_logformat_string(curproxy->logformat_string, curproxy, &curproxy->logformat, LOG_OPT_MANDATORY,
|
||||
SMP_VAL_FE_LOG_END);
|
||||
free(curproxy->logformat_string);
|
||||
curproxy->logformat_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!strcmp(args[0], "log") && kwm == KWM_NO) {
|
||||
@ -6434,7 +6469,29 @@ int check_config_validity()
|
||||
}
|
||||
out_uri_auth_compat:
|
||||
|
||||
cfgerr += acl_find_targets(curproxy);
|
||||
/* compile the log format */
|
||||
if (!(curproxy->cap & PR_CAP_FE)) {
|
||||
if (curproxy->logformat_string != default_http_log_format &&
|
||||
curproxy->logformat_string != default_tcp_log_format &&
|
||||
curproxy->logformat_string != clf_http_log_format)
|
||||
free(curproxy->logformat_string);
|
||||
curproxy->logformat_string = NULL;
|
||||
}
|
||||
|
||||
curproxy->conf.args.ctx = ARGC_LOG;
|
||||
if (curproxy->logformat_string)
|
||||
parse_logformat_string(curproxy->logformat_string, curproxy, &curproxy->logformat, LOG_OPT_MANDATORY,
|
||||
SMP_VAL_FE_LOG_END);
|
||||
|
||||
curproxy->conf.args.ctx = ARGC_UIF;
|
||||
if (curproxy->uniqueid_format_string)
|
||||
parse_logformat_string(curproxy->uniqueid_format_string, curproxy, &curproxy->format_unique_id, 0,
|
||||
(proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||
|
||||
/* only now we can check if some args remain unresolved */
|
||||
cfgerr += smp_resolve_args(curproxy);
|
||||
if (!cfgerr)
|
||||
cfgerr += acl_find_targets(curproxy);
|
||||
|
||||
if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
|
||||
(((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) ||
|
||||
@ -6524,23 +6581,6 @@ out_uri_auth_compat:
|
||||
}
|
||||
}
|
||||
|
||||
/* compile the log format */
|
||||
if (!(curproxy->cap & PR_CAP_FE)) {
|
||||
if (curproxy->logformat_string != default_http_log_format &&
|
||||
curproxy->logformat_string != default_tcp_log_format &&
|
||||
curproxy->logformat_string != clf_http_log_format)
|
||||
free(curproxy->logformat_string);
|
||||
curproxy->logformat_string = NULL;
|
||||
}
|
||||
|
||||
if (curproxy->logformat_string)
|
||||
parse_logformat_string(curproxy->logformat_string, curproxy, &curproxy->logformat, LOG_OPT_MANDATORY,
|
||||
SMP_VAL_FE_LOG_END);
|
||||
|
||||
if (curproxy->uniqueid_format_string)
|
||||
parse_logformat_string(curproxy->uniqueid_format_string, curproxy, &curproxy->format_unique_id, 0,
|
||||
(proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||
|
||||
/* first, we will invert the servers list order */
|
||||
newsrv = NULL;
|
||||
while (curproxy->srv) {
|
||||
|
@ -307,7 +307,7 @@ void add_to_logformat_list(char *start, char *end, int type, struct list *list_f
|
||||
/*
|
||||
* Parse the sample fetch expression <text> and add a node to <list_format> upon
|
||||
* success. At the moment, sample converters are not yet supported but fetch arguments
|
||||
* should work.
|
||||
* should work. The curpx->conf.args.ctx must be set by the caller.
|
||||
*/
|
||||
void add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap)
|
||||
{
|
||||
@ -320,7 +320,7 @@ void add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct pro
|
||||
cmd[1] = "";
|
||||
cmd_arg = 0;
|
||||
|
||||
expr = sample_parse_expr(cmd, &cmd_arg, trash.str, trash.size);
|
||||
expr = sample_parse_expr(cmd, &cmd_arg, trash.str, trash.size, &curpx->conf.args);
|
||||
if (!expr) {
|
||||
Warning("log-format: sample fetch <%s> failed with : %s\n", text, trash.str);
|
||||
return;
|
||||
@ -360,7 +360,8 @@ void add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct pro
|
||||
/*
|
||||
* Parse the log_format string and fill a linked list.
|
||||
* Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
|
||||
* You can set arguments using { } : %{many arguments}varname
|
||||
* You can set arguments using { } : %{many arguments}varname.
|
||||
* The curproxy->conf.args.ctx must be set by the caller.
|
||||
*
|
||||
* str: the string to parse
|
||||
* curproxy: the proxy affected
|
||||
|
@ -8139,6 +8139,8 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
||||
rule->arg.hdr_add.name = strdup(args[cur_arg]);
|
||||
rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
|
||||
LIST_INIT(&rule->arg.hdr_add.fmt);
|
||||
|
||||
proxy->conf.args.ctx = ARGC_HDR;
|
||||
parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, 0,
|
||||
(proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||
cur_arg += 2;
|
||||
|
@ -1112,7 +1112,8 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
|
||||
|
||||
arg++;
|
||||
|
||||
expr = sample_parse_expr(args, &arg, trash.str, trash.size);
|
||||
curpx->conf.args.ctx = ARGC_TRK;
|
||||
expr = sample_parse_expr(args, &arg, trash.str, trash.size, &curpx->conf.args);
|
||||
if (!expr) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : %s",
|
||||
|
@ -449,6 +449,7 @@ void init_new_proxy(struct proxy *p)
|
||||
LIST_INIT(&p->format_unique_id);
|
||||
LIST_INIT(&p->conf.bind);
|
||||
LIST_INIT(&p->conf.listeners);
|
||||
LIST_INIT(&p->conf.args.list);
|
||||
|
||||
/* Timeouts are defined as -1 */
|
||||
proxy_reset_timeouts(p);
|
||||
|
224
src/sample.c
224
src/sample.c
@ -19,9 +19,14 @@
|
||||
|
||||
#include <common/chunk.h>
|
||||
#include <common/standard.h>
|
||||
#include <common/uri_auth.h>
|
||||
|
||||
#include <proto/arg.h>
|
||||
#include <proto/auth.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/proxy.h>
|
||||
#include <proto/sample.h>
|
||||
#include <proto/stick_table.h>
|
||||
|
||||
/* static sample used in sample_process() when <p> is NULL */
|
||||
static struct sample temp_smp;
|
||||
@ -525,8 +530,9 @@ static sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
|
||||
* Parse a sample expression configuration:
|
||||
* fetch keyword followed by format conversion keywords.
|
||||
* Returns a pointer on allocated sample expression structure.
|
||||
* The caller must have set al->ctx.
|
||||
*/
|
||||
struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size)
|
||||
struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size, struct arg_list *al)
|
||||
{
|
||||
const char *endw;
|
||||
const char *end;
|
||||
@ -598,7 +604,9 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_s
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (make_arg_list(endw + 1, end - endw - 2, fetch->arg_mask, &expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
|
||||
al->kw = expr->fetch->kw;
|
||||
al->conv = NULL;
|
||||
if (make_arg_list(endw + 1, end - endw - 2, fetch->arg_mask, &expr->arg_p, &err_msg, NULL, &err_arg, al) < 0) {
|
||||
p = my_strndup(str[*idx], endw - str[*idx]);
|
||||
if (p) {
|
||||
snprintf(err, err_size, "invalid arg %d in fetch method '%s' : %s.", err_arg+1, p, err_msg);
|
||||
@ -693,7 +701,9 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_s
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (make_arg_list(endw + 1, end - endw - 2, conv->arg_mask, &conv_expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
|
||||
al->kw = expr->fetch->kw;
|
||||
al->conv = conv_expr->conv->kw;
|
||||
if (make_arg_list(endw + 1, end - endw - 2, conv->arg_mask, &conv_expr->arg_p, &err_msg, NULL, &err_arg, al) < 0) {
|
||||
p = my_strndup(str[*idx], endw - str[*idx]);
|
||||
if (p) {
|
||||
snprintf(err, err_size, "invalid arg %d in conv method '%s' : %s.", err_arg+1, p, err_msg);
|
||||
@ -786,6 +796,214 @@ struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve all remaining arguments in proxy <p>. Returns the number of
|
||||
* errors or 0 if everything is fine.
|
||||
*/
|
||||
int smp_resolve_args(struct proxy *p)
|
||||
{
|
||||
struct arg_list *cur, *bak;
|
||||
const char *ctx, *where;
|
||||
const char *conv_ctx, *conv_pre, *conv_pos;
|
||||
struct userlist *ul;
|
||||
struct arg *arg;
|
||||
int cfgerr = 0;
|
||||
|
||||
list_for_each_entry_safe(cur, bak, &p->conf.args.list, list) {
|
||||
struct proxy *px;
|
||||
struct server *srv;
|
||||
char *pname, *sname;
|
||||
|
||||
arg = cur->arg;
|
||||
|
||||
/* prepare output messages */
|
||||
conv_pre = conv_pos = conv_ctx = "";
|
||||
if (cur->conv) {
|
||||
conv_ctx = cur->conv;
|
||||
conv_pre = "conversion keyword '";
|
||||
conv_pos = "' for ";
|
||||
}
|
||||
|
||||
where = "in";
|
||||
ctx = "sample fetch keyword";
|
||||
switch (cur->ctx) {
|
||||
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_HDR: where = "in HTTP header format string in"; break;
|
||||
case ARGC_UIF: where = "in unique-id-format string in"; break;
|
||||
case ARGC_ACL: ctx = "ACL keyword"; break;
|
||||
}
|
||||
|
||||
/* set a few default settings */
|
||||
px = p;
|
||||
pname = p->id;
|
||||
|
||||
switch (arg->type) {
|
||||
case ARGT_SRV:
|
||||
if (!arg->data.str.len) {
|
||||
Alert("parsing [%s:%d] : missing server name 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;
|
||||
}
|
||||
|
||||
/* we support two formats : "bck/srv" and "srv" */
|
||||
sname = strrchr(arg->data.str.str, '/');
|
||||
|
||||
if (sname) {
|
||||
*sname++ = '\0';
|
||||
pname = arg->data.str.str;
|
||||
|
||||
px = findproxy(pname, PR_CAP_BE);
|
||||
if (!px) {
|
||||
Alert("parsing [%s:%d] : unable to find proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
sname = arg->data.str.str;
|
||||
|
||||
srv = findserver(px, sname);
|
||||
if (!srv) {
|
||||
Alert("parsing [%s:%d] : unable to find server '%s' in proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, sname, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.srv = srv;
|
||||
break;
|
||||
|
||||
case ARGT_FE:
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
px = findproxy(pname, PR_CAP_FE);
|
||||
}
|
||||
|
||||
if (!px) {
|
||||
Alert("parsing [%s:%d] : unable to find frontend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(px->cap & PR_CAP_FE)) {
|
||||
Alert("parsing [%s:%d] : proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not frontend capability.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = px;
|
||||
break;
|
||||
|
||||
case ARGT_BE:
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
px = findproxy(pname, PR_CAP_BE);
|
||||
}
|
||||
|
||||
if (!px) {
|
||||
Alert("parsing [%s:%d] : unable to find backend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(px->cap & PR_CAP_BE)) {
|
||||
Alert("parsing [%s:%d] : proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not backend capability.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = px;
|
||||
break;
|
||||
|
||||
case ARGT_TAB:
|
||||
if (arg->data.str.len) {
|
||||
pname = arg->data.str.str;
|
||||
px = find_stktable(pname);
|
||||
}
|
||||
|
||||
if (!px) {
|
||||
Alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!px->table.size) {
|
||||
Alert("parsing [%s:%d] : no table in proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
||||
cur->file, cur->line, pname,
|
||||
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.prx = px;
|
||||
break;
|
||||
|
||||
case ARGT_USR:
|
||||
if (!arg->data.str.len) {
|
||||
Alert("parsing [%s:%d] : missing userlist name 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++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p->uri_auth && p->uri_auth->userlist &&
|
||||
!strcmp(p->uri_auth->userlist->name, arg->data.str.str))
|
||||
ul = p->uri_auth->userlist;
|
||||
else
|
||||
ul = auth_find_userlist(arg->data.str.str);
|
||||
|
||||
if (!ul) {
|
||||
Alert("parsing [%s:%d] : unable to find userlist '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%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);
|
||||
cfgerr++;
|
||||
break;
|
||||
}
|
||||
|
||||
free(arg->data.str.str);
|
||||
arg->data.str.str = NULL;
|
||||
arg->unresolved = 0;
|
||||
arg->data.usr = ul;
|
||||
break;
|
||||
}
|
||||
|
||||
LIST_DEL(&cur->list);
|
||||
free(cur);
|
||||
} /* end of args processing */
|
||||
|
||||
return cfgerr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a fetch + format conversion as defined by the sample expression <expr>
|
||||
* on request or response considering the <opt> parameter. The output is always of
|
||||
|
Loading…
Reference in New Issue
Block a user