Willy, [keep this email in CC, it's not subscribed to the list]
"either() takes a boolean as input and returns one of the two argument strings depending on whether the boolean is true." Find the full details in the attached patch. --- We've had a bit of discussion regarding the naming of the converter. I wanted to avoid calling it `if`, because then we could have stuff like this: http-request set-var(txn.foo) bool(1),if(bar,baz) which can easily be confused with: http-request set-var(txn.foo) bool(1) if bar Some other naming suggestions that came up: - choice (my initial choice) - ifor / if_or - ifelse / if_else - iftrue (with the <false> argument being optional) I'm happy to adjust the patch based on your preferences. I'd also appreciate if this one could make a backport into 2.2. But I would fully understand if you refuse to backport this into a LTS branch. November is not too far away :-) Best regards Tim Düsterhus Developer WoltLab GmbH -- WoltLab GmbH Nedlitzer Str. 27B 14469 Potsdam Tel.: +49 331 96784338 [email protected] www.woltlab.com Managing director: Marcel Werk AG Potsdam HRB 26795 P
>From 52e50548f97a795cb891adf0f18a8ebc1e38b188 Mon Sep 17 00:00:00 2001 From: Tim Duesterhus <[email protected]> Date: Fri, 11 Sep 2020 14:25:23 +0200 Subject: [PATCH] MINOR: Add either(<true>,<false>) converter To: [email protected] Cc: [email protected] either() takes a boolean as input and returns one of the two argument strings depending on whether the boolean is true. This converter most likely is most useful to return the proper scheme depending on the value returned by the `ssl_fc` fetch, e.g. for use within the `x-forwarded-proto` request header. However it can also be useful for use within a template that is sent to the client using `http-request return` with a `lf-file`. It allows the administrator to implement a simple condition, without needing to prefill variables within the regular configuration using `http-request set-var(req.foo)`. --- doc/configuration.txt | 7 ++++++ reg-tests/converter/either.vtc | 45 ++++++++++++++++++++++++++++++++++ src/sample.c | 22 +++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 reg-tests/converter/either.vtc diff --git a/doc/configuration.txt b/doc/configuration.txt index c1f6f8219..197b5cec5 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -15094,6 +15094,13 @@ djb2([<avalanche>]) 32-bit hash is trivial to break. See also "crc32", "sdbm", "wt6", "crc32c", and the "hash-type" directive. +either(<true>,<false>) + Returns the <true> string if the input value is true. Returns the <false> + string otherwise. + + Example: + http-request set-header x-forwarded-proto %[ssl_fc,either(https,http)] + even Returns a boolean TRUE if the input value of type signed integer is even otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool". diff --git a/reg-tests/converter/either.vtc b/reg-tests/converter/either.vtc new file mode 100644 index 000000000..8a155c356 --- /dev/null +++ b/reg-tests/converter/either.vtc @@ -0,0 +1,45 @@ +varnishtest "either converter Test" + +feature ignore_unknown_macro + +server s1 { + rxreq + txresp +} -repeat 3 -start + +haproxy h1 -conf { + defaults + mode http + timeout connect 1s + timeout client 1s + timeout server 1s + + frontend fe + bind "fd@${fe}" + + #### requests + http-request set-var(txn.either) req.hdr_cnt(count),either(ok,ko) + http-response set-header either %[var(txn.either)] + + default_backend be + + backend be + server s1 ${s1_addr}:${s1_port} +} -start + +client c1 -connect ${h1_fe_sock} { + txreq + rxresp + expect resp.status == 200 + expect resp.http.either == "ko" + txreq \ + -hdr "count: 1" + rxresp + expect resp.status == 200 + expect resp.http.either == "ok" + txreq \ + -hdr "count: 1,2" + rxresp + expect resp.status == 200 + expect resp.http.either == "ok" +} -run diff --git a/src/sample.c b/src/sample.c index 3a1534865..d6baf6c89 100644 --- a/src/sample.c +++ b/src/sample.c @@ -3121,6 +3121,26 @@ static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp } #endif +/* Takes a boolean as input. Returns the first argument if that boolean is true and + * the second argument otherwise. + */ +static int sample_conv_either(const struct arg *arg_p, struct sample *smp, void *private) +{ + smp->data.type = SMP_T_STR; + smp->flags |= SMP_F_CONST; + + if (smp->data.u.sint) { + smp->data.u.str.data = arg_p[0].data.str.data; + smp->data.u.str.area = arg_p[0].data.str.area; + } + else { + smp->data.u.str.data = arg_p[1].data.str.data; + smp->data.u.str.area = arg_p[1].data.str.area; + } + + return 1; +} + #define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */ #define GRPC_MSG_LENGTH_SZ 4 /* 4 bytes */ #define GRPC_MSG_HEADER_SZ (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ) @@ -3782,6 +3802,8 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, { { "ungrpc", sample_conv_ungrpc, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN }, { "protobuf", sample_conv_protobuf, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN }, + { "either", sample_conv_either, ARG2(2, STR, STR), NULL, SMP_T_BOOL, SMP_T_STR }, + { "and", sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, { "or", sample_conv_binary_or, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, { "xor", sample_conv_binary_xor, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, -- 2.28.0

