From e3b57bf92f279b56ed78d8ca55ff0b637e46755c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 14 Feb 2020 16:50:14 +0100 Subject: [PATCH] MINOR: sample: make sample_parse_expr() able to return an end pointer When an end pointer is passed, instead of complaining that a comma is missing after a keyword, sample_parse_expr() will silently return the pointer to the current location into this return pointer so that the caller can continue its parsing. This will be used by more complex expressions which embed sample expressions, and may even permit to embed sample expressions into arguments of other expressions. --- include/proto/sample.h | 2 +- src/acl.c | 2 +- src/cfgparse-listen.c | 2 +- src/dns.c | 2 +- src/flt_spoe.c | 2 +- src/http_act.c | 6 +++--- src/log.c | 2 +- src/proto_tcp.c | 2 +- src/queue.c | 4 ++-- src/sample.c | 18 ++++++++++++++++-- src/server.c | 2 +- src/stick_table.c | 2 +- src/tcp_rules.c | 4 ++-- src/vars.c | 2 +- 14 files changed, 33 insertions(+), 19 deletions(-) diff --git a/include/proto/sample.h b/include/proto/sample.h index f0be3fd20..b4d52c5ea 100644 --- a/include/proto/sample.h +++ b/include/proto/sample.h @@ -28,7 +28,7 @@ extern const char *smp_to_type[SMP_TYPES]; -struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err, struct arg_list *al); +struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err, struct arg_list *al, char **endptr); struct sample_conv *find_sample_conv(const char *kw, int len); struct sample *sample_process(struct proxy *px, struct session *sess, struct stream *strm, unsigned int opt, diff --git a/src/acl.c b/src/acl.c index 4b8a6d49a..1e32271be 100644 --- a/src/acl.c +++ b/src/acl.c @@ -321,7 +321,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list * * so, we retrieve a completely parsed expression with args and * convs already done. */ - smp = sample_parse_expr((char **)args, &idx, file, line, err, al); + smp = sample_parse_expr((char **)args, &idx, file, line, err, al, NULL); if (!smp) { memprintf(err, "%s in ACL expression '%s'", *err, *args); goto out_return; diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 6d9c1f52e..3c2978c8a 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -1727,7 +1727,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } curproxy->conf.args.ctx = ARGC_STK; - expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args); + expr = sample_parse_expr(args, &myidx, file, linenum, &errmsg, &curproxy->conf.args, NULL); if (!expr) { ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/dns.c b/src/dns.c index f82301857..86147a417 100644 --- a/src/dns.c +++ b/src/dns.c @@ -2572,7 +2572,7 @@ enum act_parse_ret dns_parse_do_resolve(const char **args, int *orig_arg, struct cur_arg = cur_arg + 1; - expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); if (!expr) goto do_resolve_parse_error; diff --git a/src/flt_spoe.c b/src/flt_spoe.c index 4e448dd11..a78e6159e 100644 --- a/src/flt_spoe.c +++ b/src/flt_spoe.c @@ -3968,7 +3968,7 @@ cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm) } arg->expr = sample_parse_expr((char*[]){delim, NULL}, &idx, file, linenum, &errmsg, - &curproxy->conf.args); + &curproxy->conf.args, NULL); if (arg->expr == NULL) { ha_alert("parsing [%s:%d] : '%s': %s.\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/http_act.c b/src/http_act.c index 4c0c5c406..718501416 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -558,7 +558,7 @@ static enum act_parse_ret parse_http_req_capture(const char **args, int *orig_ar } cur_arg = *orig_arg; - expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); if (!expr) return ACT_RET_PRS_ERR; @@ -743,7 +743,7 @@ static enum act_parse_ret parse_http_res_capture(const char **args, int *orig_ar } cur_arg = *orig_arg; - expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); if (!expr) return ACT_RET_PRS_ERR; @@ -1730,7 +1730,7 @@ static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg, cur_arg = *orig_arg; expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, - err, &px->conf.args); + err, &px->conf.args, NULL); if (!expr) return ACT_RET_PRS_ERR; diff --git a/src/log.c b/src/log.c index 23e6c4757..51d684d6e 100644 --- a/src/log.c +++ b/src/log.c @@ -488,7 +488,7 @@ int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct prox cmd[1] = ""; cmd_arg = 0; - expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args); + expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args, NULL); if (!expr) { memprintf(err, "failed to parse sample expression <%s> : %s", text, *err); goto error_free; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 7668ec29c..8486863a2 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1287,7 +1287,7 @@ enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struc unsigned int where; cur_arg = *orig_arg; - expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); if (!expr) return ACT_RET_PRS_ERR; diff --git a/src/queue.c b/src/queue.c index 1bb08a513..9fd3e9d15 100644 --- a/src/queue.c +++ b/src/queue.c @@ -544,7 +544,7 @@ static enum act_parse_ret parse_set_priority_class(const char **args, int *arg, unsigned int where = 0; rule->arg.expr = sample_parse_expr((char **)args, arg, px->conf.args.file, - px->conf.args.line, err, &px->conf.args); + px->conf.args.line, err, &px->conf.args, NULL); if (!rule->arg.expr) return ACT_RET_PRS_ERR; @@ -572,7 +572,7 @@ static enum act_parse_ret parse_set_priority_offset(const char **args, int *arg, unsigned int where = 0; rule->arg.expr = sample_parse_expr((char **)args, arg, px->conf.args.file, - px->conf.args.line, err, &px->conf.args); + px->conf.args.line, err, &px->conf.args, NULL); if (!rule->arg.expr) return ACT_RET_PRS_ERR; diff --git a/src/sample.c b/src/sample.c index d82451fc3..ef0f7b00c 100644 --- a/src/sample.c +++ b/src/sample.c @@ -824,8 +824,11 @@ sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = { * fetch keyword followed by format conversion keywords. * Returns a pointer on allocated sample expression structure. * The caller must have set al->ctx. + * If is non-nul, it will be set to the first unparsed character + * (which may be the final '\0') on success. If it is nul, the expression + * must be properly terminated by a '\0' otherwise an error is reported. */ -struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err_msg, struct arg_list *al) +struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err_msg, struct arg_list *al, char **endptr) { const char *begw; /* beginning of word */ const char *endw; /* end of word */ @@ -917,6 +920,10 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, in int argcnt; if (*endt && *endt != ',') { + if (endptr) { + /* end found, let's stop here */ + break; + } if (ckw) memprintf(err_msg, "missing comma after converter '%s'", ckw); else @@ -949,8 +956,10 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, in conv = find_sample_conv(begw, endw - begw); if (!conv) { /* we found an isolated keyword that we don't know, it's not ours */ - if (begw == str[*idx]) + if (begw == str[*idx]) { + endt = begw; break; + } memprintf(err_msg, "unknown converter '%s'", ckw); goto out_error; } @@ -996,6 +1005,11 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, in } } + if (endptr) { + /* end found, let's stop here */ + *endptr = (char *)endt; + } + out: free(fkw); free(ckw); diff --git a/src/server.c b/src/server.c index d7cb97d9a..959fb22e7 100644 --- a/src/server.c +++ b/src/server.c @@ -1538,7 +1538,7 @@ static struct sample_expr *srv_sni_sample_parse_expr(struct server *srv, struct idx = 0; px->conf.args.ctx = ARGC_SRV; - return sample_parse_expr((char **)args, &idx, file, linenum, err, &px->conf.args); + return sample_parse_expr((char **)args, &idx, file, linenum, err, &px->conf.args, NULL); } static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err) diff --git a/src/stick_table.c b/src/stick_table.c index 1e7d4f3a8..9937f115f 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -2118,7 +2118,7 @@ static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct pro rule->arg.gpt.value = strtol(args[*arg], &error, 10); if (*error != '\0') { rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file, - px->conf.args.line, err, &px->conf.args); + px->conf.args.line, err, &px->conf.args, NULL); if (!rule->arg.gpt.expr) return ACT_RET_PRS_ERR; diff --git a/src/tcp_rules.c b/src/tcp_rules.c index 7eb565914..fc8b4aed9 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -766,7 +766,7 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, arg++; curpx->conf.args.ctx = ARGC_CAP; - expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args); + expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args, NULL); if (!expr) { memprintf(err, "'%s %s %s' : %s", @@ -847,7 +847,7 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, } curpx->conf.args.ctx = ARGC_TRK; - expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args); + expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args, NULL); if (!expr) { memprintf(err, "'%s %s %s' : %s", diff --git a/src/vars.c b/src/vars.c index ff6baf5dc..63e210331 100644 --- a/src/vars.c +++ b/src/vars.c @@ -749,7 +749,7 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy kw_name = args[*arg-1]; rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file, - px->conf.args.line, err, &px->conf.args); + px->conf.args.line, err, &px->conf.args, NULL); if (!rule->arg.vars.expr) return ACT_RET_PRS_ERR;