]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: sample: Add iif(<true>,<false>) converter
authorTim Duesterhus <duesterhus@woltlab.com>
Fri, 11 Sep 2020 12:25:23 +0000 (14:25 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 11 Sep 2020 14:59:27 +0000 (16:59 +0200)
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)`.

doc/configuration.txt
reg-tests/converter/iif.vtc [new file with mode: 0644]
src/sample.c

index c1f6f821970d0ccd05ccb5808103d37d97f4b5b0..dd8d5889a3f29366dd813dfb637a2b2ba86a7d0c 100644 (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
diff --git a/reg-tests/converter/iif.vtc b/reg-tests/converter/iif.vtc
new file mode 100644 (file)
index 0000000..360b63f
--- /dev/null
@@ -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
index 3a1534865989a3b71c7b086b87bc242121255633..a9c08ef54abb7936962bcfb0070ec9d8a45ac78f 100644 (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  },