MINOR: sample: Add iif(<true>,<false>) converter

iif() 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)`.
This commit is contained in:
Tim Duesterhus 2020-09-11 14:25:23 +02:00 committed by Willy Tarreau
parent 00c363ba9d
commit 3943e4fc3e
3 changed files with 74 additions and 0 deletions

View File

@ -15150,6 +15150,13 @@ http_date([<offset],[<unit>])
microseconds since epoch. Offset is assumed to have the same unit as
input timestamp.
iif(<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,iff(https,http)]
in_table(<table>)
Uses the string representation of the input sample to perform a look up in
the specified table. If the key is not found in the table, a boolean false

View File

@ -0,0 +1,45 @@
varnishtest "iif 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.iif) req.hdr_cnt(count),iif(ok,ko)
http-response set-header iif %[var(txn.iif)]
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.iif == "ko"
txreq \
-hdr "count: 1"
rxresp
expect resp.status == 200
expect resp.http.iif == "ok"
txreq \
-hdr "count: 1,2"
rxresp
expect resp.status == 200
expect resp.http.iif == "ok"
} -run

View File

@ -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_iif(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 },
{ "iif", sample_conv_iif, 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 },