From 3fdc27f1e0e9d20789e5c53fdb5d51fc7a3a0e2f Mon Sep 17 00:00:00 2001 From: Nils Goroll Date: Wed, 21 May 2025 10:23:13 +0200 Subject: [PATCH] Start making vtest command arguments less positional Our common pattern of argument parsing is basically for (; *av != NULL; av++) { // parse first set of arguments if (unknown_argument) break; } for (; *av != NULL; av++) { // parse second set of arguments if (unknown_argument) break; } // ... This makes vtest command arguments "semi-positional": Within each set, they behave like named arguments, but once parsing progressed to the next set, they behave like positional arguments. This is explicitly mentioned in the documentation, for example for txreq/txresp: "These three switches can appear in any order but must come before the following ones." While properly documented, this is un-POLA behavior. This patch changes this behavior for the first set of txreq/txresp arguments in a simplistic way by filtering known arguments out of the argument vector. The drawback of the simplistic approach is that argument values of a "later stage" can not be the same string as argument names of an "earlier stage". For example, the following would no onger work: txreq -body -nouseragent --- src/vtc_http.c | 35 +++++++++++++++++++++++++++++++++-- tests/a00024.vtc | 3 ++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/vtc_http.c b/src/vtc_http.c index a5f70186..a9af69fb 100644 --- a/src/vtc_http.c +++ b/src/vtc_http.c @@ -1210,6 +1210,32 @@ cmd_http_rxchunk(CMD_ARGS) * Transmit a request */ +struct args { + char **argv; + int argc; +}; + +static void +args_init(struct args *args) +{ + memset(args, 0, sizeof *args); +} + +static void +args_add(struct args *args, char *arg) +{ + AN(args); + args->argv = realloc(args->argv, (args->argc + 1) * sizeof *args->argv); + AN(args->argv); + args->argv[args->argc++] = arg; +} + +static void +args_free(struct args *args) +{ + free(args->argv); +} + static void cmd_http_txreq(CMD_ARGS) { @@ -1218,6 +1244,7 @@ cmd_http_txreq(CMD_ARGS) const char *url = "/"; const char *proto = "HTTP/1.1"; const char *up = NULL; + struct args args; unsigned nohost; unsigned nouseragent = 0; @@ -1228,6 +1255,7 @@ cmd_http_txreq(CMD_ARGS) av++; VSB_clear(hp->vsb); + args_init(&args); hp->head_method = 0; for (; *av != NULL; av++) { @@ -1248,17 +1276,19 @@ cmd_http_txreq(CMD_ARGS) } else if (!strcmp(*av, "-nouseragent")) { nouseragent = 1; } else - break; + args_add(&args, *av); } VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl); + args_add(&args, NULL); + if (up) VSB_printf(hp->vsb, "Connection: Upgrade, HTTP2-Settings%s" "Upgrade: h2c%s" "HTTP2-Settings: %s%s", nl, nl, up, nl); nohost = strcmp(proto, "HTTP/1.1") != 0; - av = http_tx_parse_args(av, vl, hp, NULL, nohost, 1, 1, nouseragent); + av = http_tx_parse_args(args.argv, vl, hp, NULL, nohost, 1, 1, nouseragent); if (*av != NULL) vtc_fatal(hp->vl, "Unknown http txreq spec: %s\n", *av); http_write(hp, 4, "txreq"); @@ -1282,6 +1312,7 @@ cmd_http_txreq(CMD_ARGS) "} -start\n" ); } + args_free(&args); } /* SECTION: client-server.spec.recv diff --git a/tests/a00024.vtc b/tests/a00024.vtc index 89a11b43..f5296aef 100644 --- a/tests/a00024.vtc +++ b/tests/a00024.vtc @@ -17,6 +17,7 @@ server s2 { txresp rxreq # default User-Agent header is not included when -nouseragent is specified + expect req.http.foo == bar expect req.http.User-Agent == txresp -noserver } -start @@ -36,7 +37,7 @@ client c202 -connect ${s2_sock} { txreq rxresp expect resp.http.Server == "s2" - txreq -nouseragent + txreq -hdr "foo: bar" -nouseragent rxresp # default Server header is not included when -noserver is specified expect resp.http.Server ==