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;