From 3638bd6b5433d34a0efed685e0cd5f8a8d0f6c8a 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 | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 tests/a00024.vtc diff --git a/src/vtc_http.c b/src/vtc_http.c index 827c20d..fb71d30 100644 --- a/src/vtc_http.c +++ b/src/vtc_http.c @@ -1172,6 +1172,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) { @@ -1180,6 +1206,7 @@ cmd_http_txreq(CMD_ARGS) const char *url = "/"; const char *proto = "HTTP/1.1"; const char *up = NULL; + struct args args; unsigned nohost; (void)vl; @@ -1189,6 +1216,7 @@ cmd_http_txreq(CMD_ARGS) av++; VSB_clear(hp->vsb); + args_init(&args); hp->head_method = 0; for (; *av != NULL; av++) { @@ -1207,17 +1235,19 @@ cmd_http_txreq(CMD_ARGS) up = av[1]; av++; } 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); + av = http_tx_parse_args(args.argv, vl, hp, NULL, nohost); if (*av != NULL) vtc_fatal(hp->vl, "Unknown http txreq spec: %s\n", *av); http_write(hp, 4, "txreq"); @@ -1241,6 +1271,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 new file mode 100644 index 0000000..f5296ae --- /dev/null +++ b/tests/a00024.vtc @@ -0,0 +1,44 @@ +vtest "test -nouseragent and -noserver" + +server s1 { + rxreq + # by default, User-Agent header is set to cNAME + expect req.http.User-Agent == "c101" + txresp + rxreq + # when specified with -hdr, it overrides the default + expect req.http.User-Agent == "not-c101" + txresp -hdr "Server: not-s1" +} -start + +server s2 { + rxreq + expect req.http.User-Agent == "c202" + 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 + +client c101 -connect ${s1_sock} { + txreq -url "/home" + rxresp + # by default, Server header is set to sNAME + expect resp.http.Server == "s1" + txreq -url "/home" -hdr "User-Agent: not-c101" + rxresp + # when specified with -hdr, it overrides the default + expect resp.http.Server == "not-s1" +} -run + +client c202 -connect ${s2_sock} { + txreq + rxresp + expect resp.http.Server == "s2" + txreq -hdr "foo: bar" -nouseragent + rxresp + # default Server header is not included when -noserver is specified + expect resp.http.Server == +} -run