Patch sample_conv_json_query in sample.c to return array values

2023-09-15 Thread Jens Popp
Hi,

currently the method sample_conv_query in sample.c returns an empty value, if 
the given json path leads to an json array. There are multiple use cases, where 
you need to check the content of an array, e.g., if the array contains a list 
of roles and you want to check, if the array contains a certain role (for 
OIDC). I propose the simple fix below, to copy the complete array (including 
brackets) in the result of the function:

...(Line 4162)
case MJSON_TOK_ARRAY:
// We copy the complete array, including square 
brackets into the return buffer
// result looks like: 
["manage-account","manage-account-links","view-profile"]
strncpy( trash->area, token, token_size);
trash->data = token_size;
trash->size = token_size;
smp->data.u.str = *trash;
smp->data.type = SMP_T_STR;
return 1;
case MJSON_TOK_NULL:

... (currently Line 4164)

If possible I would also like to fix this in current stable release 2.8.

Changes are also in my fork,

https://github.com/jenspopp/haproxy/blob/master/src/sample.c#L4162-L4171

Any comment / help is appreciated.

Best regards
Jens
[X]


An Elisa camLine Holding GmbH company - www.camline.com


camLine GmbH - Fraunhoferring 9, 85238 Petershausen, Germany
Amtsgericht München HRB 88821
Managing Directors: Frank Bölstler, Evelyn Tag, Bernhard Völker


The content of this message is CAMLINE CONFIDENTIAL. If you are not the 
intended recipient, please notify me, delete this email and do not use or 
distribute this email.






[PATCH 0/4] Support server-side sending and forwarding of arbitrary PPv2 TLVs

2023-09-15 Thread Stephan, Alexander
Hi all,



As a follow-up to my last patches that allow to fetch any TLV in the frontend, 
I have also implemented similar functionality in the backend that allows to 
send out TLVs of any type.

This is an addition to the existing proxy-protocol-v2-option constants like 
crc32c. Unlike the pre-defined TLVs, generic TLVs, indicated by their type 
number, have a common behavior.

I think the test I've added as well as the documentation should explain best 
how it works in more detail.



To update TLVs in-place in a connection, before forwarding, I have also added a 
corresponding TCP action. PPv2 is not quite TCP level, but it seems like the 
best fit.

I am very interested in what you think about the changes. Essentially, these 
are two commits split into four, for easier review (split by component).



I will be on vacation the next two weeks, but my colleague Christian Menges 
will jump in during that time and address your feedback.



Thanks and Best,

Alexander

SAP SE Germany


---

Alexander Stephan (4):
  MEDIUM: server: Parse generic type-value pairs as proxy-v2-options
  MEDIUM: connection: Send out generically allocated proxy-v2-options
  LOW: connection: Add TLV update function
  MEDIUM: tcp-act: Add new set-tlv TCP action for PPv2 TLVs

 doc/configuration.txt |  43 +++
 include/haproxy/connection.h  |  73 +++
 include/haproxy/server-t.h|  10 ++
 .../proxy_protocol_send_generic.vtc   |  66 ++
 src/connection.c  |  51 +++-
 src/server.c  |  76 ++-
 src/tcp_act.c | 120 --
 7 files changed, 417 insertions(+), 22 deletions(-)
 create mode 100644 reg-tests/connection/proxy_protocol_send_generic.vtc

--
2.35.3



RE: [PATCH 1/4] MEDIUM: server: Parse generic type-value pairs as proxy-v2-options

2023-09-15 Thread Stephan, Alexander
From fb8714c5aebd7fe957264d0f2234182f55f952fe Mon Sep 17 00:00:00 2001
From: Alexander Stephan 
mailto:alexander.step...@sap.com>>
Date: Fri, 15 Sep 2023 12:38:46 +0200
Subject: [PATCH 1/4] MEDIUM: server: Parse generic type-value pairs as
 proxy-v2-options

This commit introduces a generic server-side parsing of type-value pair
arguments and allocation of a TLV list. This allows to 1) forward any TLV
type, 2) generally send out any TLV type, and 3) allows to specify concrete
values via an '=' after the type and a log fmt expression. If there is no
TLV found in the remote connection, an empty TLV is sent out.
---
 include/haproxy/server-t.h | 10 +
 src/server.c   | 76 +++---
 2 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index 1175a470e..7b93bf48f 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -256,6 +256,15 @@ enum __attribute__((__packed__)) srv_ws_mode {
SRV_WS_H2,
 };

+/* Server-side TLV list, contains the types of the TLVs that should be sent 
out.
+ * Additionally, it can contain data, if specified in the config.
+ */
+struct srv_pp_tlv_list {
+   struct list list;
+   struct list fmt;
+   unsigned char type;
+};
+
 struct proxy;
 struct server {
/* mostly config or admin stuff, doesn't change often */
@@ -421,6 +430,7 @@ struct server {
struct list srv_rec_item;   /* to attach server to a srv record item */
struct list ip_rec_item;/* to attach server to a A or  record 
item */
struct ebpt_node host_dn;   /* hostdn store for srvrq and state file 
matching*/
+   struct list pp_tlvs;/* to send out PROXY protocol v2 TLVs */
struct task *srvrq_check;   /* Task testing SRV record 
expiration date for this server */
struct {
const char *file;   /* file where the section appears */
diff --git a/src/server.c b/src/server.c
index 3673340d1..08f86d030 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1036,7 +1036,13 @@ static int srv_parse_proto(char **args, int *cur_arg,
 static int srv_parse_proxy_v2_options(char **args, int *cur_arg,
  struct proxy *px, struct server *newsrv, char **err)
 {
-   char *p, *n;
+   char *p = NULL, *n = NULL, *m = NULL;
+   char *key = NULL, *val = NULL;
+   char *endp = NULL;
+   unsigned char idx = 0;
+   size_t key_length = 0, val_length = 0;
+   struct srv_pp_tlv_list *srv_tlv = NULL;
+
for (p = args[*cur_arg+1]; p; p = n) {
n = strchr(p, ',');
if (n)
@@ -1061,13 +1067,61 @@ static int srv_parse_proxy_v2_options(char **args, int 
*cur_arg,
newsrv->pp_opts |= SRV_PP_V2_CRC32C;
} else if (strcmp(p, "unique-id") == 0) {
newsrv->pp_opts |= SRV_PP_V2_UNIQUE_ID;
-   } else
-   goto fail;
+   } else {
+   /* reset val in case it was set before */
+   val = NULL;
+
+   /* try to split by '=' into generic pair key value pair 
(=) */
+   m = strchr(p, '=');
+   if (m) {
+   key_length = m - p;
+   key = (char *) malloc(key_length + 1);
+   if (unlikely(!key))
+   goto fail;
+   snprintf(key, key_length + 1, "%s", p);
+
+   val_length = strlen(p) - key_length;
+   val = (char *) malloc(val_length + 1);
+   if (unlikely(!val))
+   goto fail;
+   snprintf(val, val_length + 1, "%s", m + 1);
+   }
+   else {
+   key = (char *) malloc(strlen(p) + 1);
+   if (unlikely(!key))
+   goto fail;
+   snprintf(key, strlen(p) + 1, "%s", p);
+   }
+
+   errno = 0;
+   idx = strtoul(key, &endp, 0);
+   if (unlikely((endp && *endp) != '\0' || (key == endp) || (errno != 
0)))
+   goto fail;
+
+   /* processing is done in connection.c */
+   srv_tlv = malloc(sizeof(struct srv_pp_tlv_list));
+   if (unlikely(!srv_tlv))
+   goto fail;
+
+   srv_tlv->type = idx;
+   LIST_INIT(&srv_tlv->fmt);
+   if (val && unlikely(!parse_logformat_string(val, px, &srv_tlv->fmt, 
LOG_OPT_HTTP, PR_CAP_LISTEN, err)))
+   goto fail;
+
+   LIST_APPEND(&newsrv->pp_tlvs, &srv_tlv->list);
+   free(key);
+   free(val);
+   }
}
return 0;
- fail:
+fail:
+   free(key);
+   free(val);
+   free(srv_tlv);
+   errno = 0;
+
if (err)
-   memprintf(err, "'%s' : proxy v2 option not implemented", p);
+   memprintf(err, "'%s' : failed to set proxy v2 option", p);
return ERR_ALERT | ERR_FATAL;
 }

@@ -2428,6 +2482,7 @@ struct server *new_server(struct proxy *proxy)
LIST_APPEND(&servers_list, &srv->global_list);
LIST_INIT(&srv->srv_rec_item);
LIST_INIT(&srv->ip_rec_item);
+   LIST_INIT(&srv->pp_tlvs);
MT_LIST_INIT(&srv

RE: [PATCH 2/4] MEDIUM: connection: Send out generically allocated proxy-v2-options

2023-09-15 Thread Stephan, Alexander
From 84608ed754c1a92e85e03036e8b0cd0949721ffb Mon Sep 17 00:00:00 2001
From: Alexander Stephan 
Date: Fri, 15 Sep 2023 12:42:36 +0200
Subject: [PATCH 2/4] MEDIUM: connection: Send out generically allocated
 proxy-v2-options

This commit removes the previous limitations on the existing, fixed PPv2 TLV 
types
that can be sent out. This is done by leveraging the previously implemented
parsing. We iterate over the server TLV list and either forward or send a new
TLV, depending on whether a TLV exists in the remote connection.
---
 doc/configuration.txt | 20 
 .../proxy_protocol_send_generic.vtc   | 35 +
 src/connection.c  | 51 +--
 3 files changed, 103 insertions(+), 3 deletions(-)
 create mode 100644 reg-tests/connection/proxy_protocol_send_generic.vtc

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 14f6b906d..aeff9e4db 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -16671,6 +16671,26 @@ proxy-v2-options [,]*
 generated unique ID is also used for the first HTTP request
 within a Keep-Alive connection.

+  Besides, you can specify the type of TLV numerically instead.
+
+  Example 1:
+  server example 127.0.0.1:2319 send-proxy-v2 proxy-v2-options crc32c,0xEE
+
+  The following logic applies: By default, the remote frontend connection is
+  searched for the value 0xEE. If found, it is simply forwarded. Otherwise,
+  a TLV with the ID "0xEE" and empty payload is sent out. In addition, crc32c
+  is also set here.
+
+  You can also specify a key-value pair = syntax.  represents the
+  8 bit TLV type field in the range of 0 to 255. It can be expressed in decimal
+  or hexadecimal format (prefixed by "0x").
+
+  Example 2:
+  server example_server 127.0.0.1:2319 send-proxy-v2 proxy-v2-options 
0xEE=%[str("foo")]
+
+  This will always send out the value "foo". Another common use case would be 
to
+  reference a variable.
+
 send-proxy-v2-ssl
   The "send-proxy-v2-ssl" parameter enforces use of the PROXY protocol version
   2 over any connection established to this server. The PROXY protocol informs
diff --git a/reg-tests/connection/proxy_protocol_send_generic.vtc 
b/reg-tests/connection/proxy_protocol_send_generic.vtc
new file mode 100644
index 0..e0bd15a1b
--- /dev/null
+++ b/reg-tests/connection/proxy_protocol_send_generic.vtc
@@ -0,0 +1,35 @@
+varnishtest "Check that generic TLV IDs are sent properly"
+
+#REQUIRE_VERSION=2.2
+
+feature ignore_unknown_macro
+
+haproxy h1 -conf {
+defaults
+mode http
+log global
+
+listen sender
+bind "fd@${feS}"
+server example ${h1_feR_addr}:${h1_feR_port} send-proxy-v2 
proxy-v2-options 0xE1=%[str("foo")],0xE2
+
+listen receiver
+bind "fd@${feR}" accept-proxy
+
+# Check that the TLV value is set in the backend.
+http-request set-var(txn.custom_tlv_a) fc_pp_tlv(0xE1)
+http-after-response set-header proxy_custom_tlv_a 
%[var(txn.custom_tlv_a)]
+
+# Check that TLVs without an value are sent out.
+http-request set-var(txn.custom_tlv_b) fc_pp_tlv(0xE2)
+http-after-response set-header proxy_custom_tlv_b 
%[var(txn.custom_tlv_b)]
+
+http-request return status 200
+} -start
+
+client c1 -connect ${h1_feS_sock} {
+txreq -url "/"
+rxresp
+expect resp.http.proxy_custom_tlv_a == "foo"
+expect resp.http.proxy_custom_tlv_b == ""
+} -run
diff --git a/src/connection.c b/src/connection.c
index 5f7226aae..51584b1ed 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -548,7 +549,7 @@ struct connection *conn_new(void *target)
 /* Releases a connection previously allocated by conn_new() */
 void conn_free(struct connection *conn)
 {
-   struct conn_tlv_list *tlv, *tlv_back = NULL;
+   struct conn_tlv_list *tlv = NULL, *tlv_back = NULL;

if (conn_is_back(conn))
conn_backend_deinit(conn);
@@ -1920,10 +1921,12 @@ static int make_proxy_line_v2(char *buf, int buf_len, 
struct server *srv, struct
int ret = 0;
struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf;
struct sockaddr_storage null_addr = { .ss_family = 0 };
+   struct srv_pp_tlv_list *srv_tlv = NULL;
const struct sockaddr_storage *src = &null_addr;
const struct sockaddr_storage *dst = &null_addr;
-   const char *value;
-   int value_len;
+   const char *value = "";
+   int value_len = 0;
+   int found = 0;

if (buf_len < PP2_HEADER_LEN)
return 0;
@@ -1993,6 +1996,48 @@ static int make_proxy_line_v2(char *buf, int buf_len, 
struct server *srv, struct
}
}

+   if (strm) {
+   struct buffer *replace = NULL;
+
+   list_for_each_entry(srv_tlv, &srv->pp_tlvs, list) {
+   replace = NULL;
+
+   if (!LIST_ISEMPTY(&srv_tlv->fmt)) {
+   replace = alloc_trash_chunk();
+  

RE: [PATCH 3/4] LOW: connection: Add TLV update function

2023-09-15 Thread Stephan, Alexander
From cc8fe58a8d2f8d47b03d03fd1048fe1b9babca70 Mon Sep 17 00:00:00 2001
From: Alexander Stephan 
Date: Fri, 15 Sep 2023 12:18:10 +0200
Subject: [PATCH 3/4] LOW: connection: Add TLV update function

Until now, it was not possible to deliberatily change received TLVs
that are stored within a connection. An HAProxy backend server reads
TLVs out the (remote) connection. This function allows us to update
TLVs in-place before they are forwarded, given that the new and the
old value map to the same pool. Besides, if a TLV does not already
exist, it is created and added to the list. As TLV values often have
similiar length this is more efficient than allocating a new TLV for
each value.
---
 include/haproxy/connection.h | 73 
 1 file changed, 73 insertions(+)

diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h
index fb14eed12..b775996ba 100644
--- a/include/haproxy/connection.h
+++ b/include/haproxy/connection.h
@@ -451,6 +451,79 @@ static inline void conn_set_tos(const struct connection 
*conn, int tos)
 #endif
 }

+/* Adds or updates a TLV item on an existing connection.
+ * The connection is tested and if it is null, nothing is done.
+ */
+static inline int conn_set_tlv(struct connection *conn, int type, void *value, 
int len)
+{
+ struct conn_tlv_list *tlv = NULL, *tlv_back = NULL;
+ int reuse = 0, found = 0;
+
+ if (!conn || !conn_ctrl_ready(conn) || len > HA_PP2_MAX_ALLOC)
+   return -1;
+ /* search whether we already have a TLV of the requested type */
+ list_for_each_entry(tlv, &conn->tlv_list, list) {
+   if (tlv->type != type)
+ continue;
+   /* Set reuse flag according to whether both, new and old TLV,
+* are in the same interval.
+*/
+   if (len >= 0) {
+ if (tlv->len <= HA_PP2_TLV_VALUE_128 && len <= HA_PP2_TLV_VALUE_128)
+   reuse = 1;
+ else if (tlv->len > HA_PP2_TLV_VALUE_128 && len > HA_PP2_TLV_VALUE_128) {
+   if ((tlv->len <= HA_PP2_TLV_VALUE_256 && len <= HA_PP2_TLV_VALUE_256) ||
+   (tlv->len > HA_PP2_TLV_VALUE_256 && len > HA_PP2_TLV_VALUE_256))
+ reuse = 1;
+ }
+   }
+   found = 1;
+   break;
+ }
+ if (found && reuse) {
+   /* We have found the TLV and it fits in the already allocated
+* memory, in-place editing is enough. freeing logic stays
+* identical since the length still maps to the old pool.
+*/
+   memcpy(tlv->value, value, len);
+   tlv->len = len;
+   return 0;
+ }
+
+ if (found) {
+   /* first, we need to free the previous TLV item */
+   list_for_each_entry_safe(tlv, tlv_back, &conn->tlv_list, list) {
+ if (tlv->type != type)
+   continue;
+
+ LIST_DELETE(&tlv->list);
+ if (tlv->len > HA_PP2_TLV_VALUE_256)
+   free(tlv);
+ else if (tlv->len < HA_PP2_TLV_VALUE_128)
+   pool_free(pool_head_pp_tlv_128, tlv);
+ else
+   pool_free(pool_head_pp_tlv_256, tlv);
+   }
+ }
+
+ if (len > HA_PP2_TLV_VALUE_256)
+   tlv = malloc(len + sizeof(struct conn_tlv_list));
+ else if (len <= HA_PP2_TLV_VALUE_128)
+   tlv = pool_alloc(pool_head_pp_tlv_128);
+ else
+   tlv = pool_alloc(pool_head_pp_tlv_256);
+
+ if (unlikely(!tlv))
+   return -1;
+
+ tlv->len = len;
+ tlv->type = type;
+ memcpy(tlv->value, value, len);
+
+ LIST_APPEND(&conn->tlv_list, &tlv->list);
+ return 0;
+}
+
 /* Sets the netfilter mark on the connection's socket. The connection is tested
  * and if it is null, nothing is done.
  */
--
2.35.3




RE: [PATCH 4/4] MEDIUM: tcp-act: Add new set-tlv TCP action for PPv2 TLVs

2023-09-15 Thread Stephan, Alexander
From da4dc50153fe6cc7e562b63439dd8be4846e0dcf Mon Sep 17 00:00:00 2001
From: Alexander Stephan 
Date: Fri, 15 Sep 2023 12:25:03 +0200
Subject: [PATCH 4/4] MEDIUM: tcp-act: Add new set-tlv TCP action for PPv2 TLVs

This commit adds an action called set-tlv()  that allows to directly
update the TLV data structure within a connection for all type of connection
events. It can be used to modify TLVs before they are forwarded (if specified
in proxy-v2-options) while keeping the previously allocated memory, if the new
and the old value map to the same pool. This function can also be used to
enhance readability if setting many TLVs at once, as an alternative to 
specifying
type and value directly in the server.
---
 doc/configuration.txt |  25 +++-
 .../proxy_protocol_send_generic.vtc   |  31 +
 src/tcp_act.c | 120 --
 3 files changed, 161 insertions(+), 15 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index aeff9e4db..a0317f005 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7011,6 +7011,7 @@ http-request  [options...] [ { if | unless } 
 ]
 - set-src 
 - set-src-port 
 - set-timeout { server | tunnel } {  |  }
+- set-tlv() 
 - set-tos 
 - set-uri 
 - set-var([,...]) 
@@ -7943,6 +7944,22 @@ http-request set-timeout { server | tunnel } {  
|  }
 http-request set-timeout tunnel 5s
 http-request set-timeout server req.hdr(host),map_int(host.lst)

+http-request set-tlv()  [ { if | unless }  ]
+
+  This is used to alter a PROXY protocol v2 TLV that has been sent by the 
client.
+  It can be used to efficiently alter already allocated TLVs in-place. If no 
TLV with
+  the specified TLV ID has been received yet, a new TLV with  and the 
current
+  value of  is added.
+
+  The parameter  represents the 8 bit TLV type field in the range 0 to 255.
+  It can be expressed in decimal, hexadecimal format (prefixed by "0x") or 
octal
+  (prefixed by "0").
+
+  Typically, it is used together with generic proxy-v2-options.
+
+  Example:
+http-request set-tlv(0xE1) str("foo")
+
 http-request set-tos  [ { if | unless }  ]

   This is used to set the TOS or DSCP field value of packets sent to the client
@@ -13502,6 +13519,7 @@ tcp-request content  [{if | unless} ]
 - set-priority-offset 
 - set-src 
 - set-src-port 
+- set-tlv() 
 - set-tos 
 - set-var([,...]) 
 - set-var-fmt([,...]) 
@@ -13741,6 +13759,11 @@ tcp-request content set-src-port  [ { if | 
unless }  ]
   specified expression. Please refer to "http-request set-src" and
   "http-request set-src-port" for a complete description.

+tcp-request content set-tlv()  [ { if | unless }  ]
+
+  This is used to alter a PROXY protocol v2 TLV that has been sent by the 
client.
+  Please refer to "http-request set-tlv" for a complete description.
+
 tcp-request content set-tos  [ { if | unless }  ]

   This is used to set the TOS or DSCP field value of packets sent to the client
@@ -16686,7 +16709,7 @@ proxy-v2-options [,]*
   or hexadecimal format (prefixed by "0x").

   Example 2:
-  server example_server 127.0.0.1:2319 send-proxy-v2 proxy-v2-options 
0xEE=%[str("foo")]
+  server example 127.0.0.1:2319 send-proxy-v2 proxy-v2-options 
0xEE=%[str("foo")]

   This will always send out the value "foo". Another common use case would be 
to
   reference a variable.
diff --git a/reg-tests/connection/proxy_protocol_send_generic.vtc 
b/reg-tests/connection/proxy_protocol_send_generic.vtc
index e0bd15a1b..1c48964be 100644
--- a/reg-tests/connection/proxy_protocol_send_generic.vtc
+++ b/reg-tests/connection/proxy_protocol_send_generic.vtc
@@ -24,6 +24,33 @@ haproxy h1 -conf {
 http-request set-var(txn.custom_tlv_b) fc_pp_tlv(0xE2)
 http-after-response set-header proxy_custom_tlv_b 
%[var(txn.custom_tlv_b)]

+http-request set-tlv(0xE3) str("bar")
+http-request set-var(txn.custom_tlv_c) fc_pp_tlv(0xE3)
+http-after-response set-header proxy_custom_tlv_c 
%[var(txn.custom_tlv_c)]
+
+# Check that we can alter the TLV in the connection on http-request 
level.
+http-request set-tlv(0xE3) str("bar")
+http-request set-var(txn.custom_tlv_c) fc_pp_tlv(0xE3)
+http-after-response set-header proxy_custom_tlv_c 
%[var(txn.custom_tlv_c)]
+
+# Check that we can alter the TLV in the connection on tcp-content 
level.
+tcp-request content set-tlv(0xE4) str("bar")
+http-request set-var(txn.custom_tlv_d) fc_pp_tlv(0xE4)
+http-after-response set-header proxy_custom_tlv_d 
%[var(txn.custom_tlv_d)]
+
+# Check that we can overwrite an existing TLV.
+tcp-request content set-tlv(0xE5) str("bar")
+http-request set-var(txn.custom_tlv_e) fc_pp_tlv(0xE5)
+http-after-response set-header proxy_custom_tlv_e 
%[var(txn.custom_tlv_e)]
+
+# Check that we can move from a small to a medium pool wi

Re: Patch sample_conv_json_query in sample.c to return array values

2023-09-15 Thread Aleksandar Lazic

Dear Jens.

Please can you create a patch as mentioned in 
https://github.com/haproxy/haproxy/blob/master/CONTRIBUTING as suggested 
in https://github.com/haproxy/haproxy/issues/2281#issuecomment-1721014384


Regards
Alex

On 2023-09-15 (Fr.) 14:57, Jens Popp wrote:

Hi,

currently the method sample_conv_query in sample.c returns an empty value, if 
the given json path leads to an json array. There are multiple use cases, where 
you need to check the content of an array, e.g., if the array contains a list 
of roles and you want to check, if the array contains a certain role (for 
OIDC). I propose the simple fix below, to copy the complete array (including 
brackets) in the result of the function:

...(Line 4162)
 case MJSON_TOK_ARRAY:
 // We copy the complete array, including square 
brackets into the return buffer
 // result looks like: 
["manage-account","manage-account-links","view-profile"]
 strncpy( trash->area, token, token_size);
 trash->data = token_size;
 trash->size = token_size;
 smp->data.u.str = *trash;
 smp->data.type = SMP_T_STR;
 return 1;
 case MJSON_TOK_NULL:

... (currently Line 4164)

If possible I would also like to fix this in current stable release 2.8.

Changes are also in my fork,

https://github.com/jenspopp/haproxy/blob/master/src/sample.c#L4162-L4171

Any comment / help is appreciated.

Best regards
Jens
[X]


An Elisa camLine Holding GmbH company - www.camline.com


camLine GmbH - Fraunhoferring 9, 85238 Petershausen, Germany
Amtsgericht München HRB 88821
Managing Directors: Frank Bölstler, Evelyn Tag, Bernhard Völker


The content of this message is CAMLINE CONFIDENTIAL. If you are not the 
intended recipient, please notify me, delete this email and do not use or 
distribute this email.








[PATCH] MINOR: support for http-request set-timeout client

2023-09-15 Thread Vladimir Vdovin
Added set-timeout for frontend side of session, so it can be used to set
dynamically per-client timeouts if needed.
---
 doc/configuration.txt  | 12 ++--
 include/haproxy/action-t.h |  1 +
 src/action.c   |  5 -
 src/http_act.c |  5 +
 src/stream.c   |  4 
 5 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index d49d359a2..d46765b65 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7010,7 +7010,7 @@ http-request  [options...] [ { if | unless } 
 ]
 - set-query 
 - set-src 
 - set-src-port 
-- set-timeout { server | tunnel } {  |  }
+- set-timeout { client | server | tunnel } {  |  }
 - set-tos 
 - set-uri 
 - set-var([,...]) 
@@ -7925,10 +7925,10 @@ http-request set-src-port  [ { if | unless } 
 ]
   the address family supports a port, otherwise it forces the source address to
   IPv4 "0.0.0.0" before rewriting the port.
 
-http-request set-timeout { server | tunnel } {  |  }
+http-request set-timeout { client | server | tunnel } {  |  }
[ { if | unless }  ]
 
-  This action overrides the specified "server" or "tunnel" timeout for the
+  This action overrides the specified "client", "server" or "tunnel" timeout 
for the
   current stream only. The timeout can be specified in millisecond or with any
   other unit if the number is suffixed by the unit as explained at the top of
   this document. It is also possible to write an expression which must returns
@@ -7936,8 +7936,8 @@ http-request set-timeout { server | tunnel } {  
|  }
 
   Note that the server/tunnel timeouts are only relevant on the backend side
   and thus this rule is only available for the proxies with backend
-  capabilities. Also the timeout value must be non-null to obtain the expected
-  results.
+  capabilities. As well as client timeout is only relevant for frontend side.
+  Also the timeout value must be non-null to obtain the expected results.
 
   Example:
 http-request set-timeout tunnel 5s
@@ -20339,7 +20339,7 @@ fe_name : string
 
 fe_client_timeout : integer
   Returns the configuration value in millisecond for the client timeout of the
-  current frontend.
+  current frontend. This timeout can be overwritten by a "set-timeout" rule.
 
 res.timer.data : integer
   this is the total transfer time of the response payload till the last byte
diff --git a/include/haproxy/action-t.h b/include/haproxy/action-t.h
index 7fafd612a..f77bdce5f 100644
--- a/include/haproxy/action-t.h
+++ b/include/haproxy/action-t.h
@@ -99,6 +99,7 @@ enum act_name {
 enum act_timeout_name {
ACT_TIMEOUT_SERVER,
ACT_TIMEOUT_TUNNEL,
+   ACT_TIMEOUT_CLIENT,
 };
 
 enum act_normalize_uri {
diff --git a/src/action.c b/src/action.c
index 9d3bfe4b9..b8ee4a185 100644
--- a/src/action.c
+++ b/src/action.c
@@ -195,9 +195,12 @@ int cfg_parse_rule_set_timeout(const char **args, int idx, 
int *out_timeout,
else if (strcmp(timeout_name, "tunnel") == 0) {
*name = ACT_TIMEOUT_TUNNEL;
}
+   else if (strcmp(timeout_name, "client") == 0) {
+   *name = ACT_TIMEOUT_CLIENT;
+   }
else {
memprintf(err,
- "'set-timeout' rule supports 'server'/'tunnel' (got 
'%s')",
+ "'set-timeout' rule supports 
'server'/'tunnel'/'client' (got '%s')",
  timeout_name);
return -1;
}
diff --git a/src/http_act.c b/src/http_act.c
index d168cf5e0..22cccaf2c 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -2192,6 +2192,11 @@ static enum act_parse_ret parse_http_set_timeout(const 
char **args,
return ACT_RET_PRS_ERR;
}
 
+   if (!(px->cap & PR_CAP_FE)) {
+   memprintf(err, "proxy '%s' has no frontend capability", px->id);
+   return ACT_RET_PRS_ERR;
+   }
+
if (!(px->cap & PR_CAP_BE)) {
memprintf(err, "proxy '%s' has no backend capability", px->id);
return ACT_RET_PRS_ERR;
diff --git a/src/stream.c b/src/stream.c
index 45b0c56d9..2c1c7aae3 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -867,6 +867,10 @@ void stream_retnclose(struct stream *s, const struct 
buffer *msg)
 int stream_set_timeout(struct stream *s, enum act_timeout_name name, int 
timeout)
 {
switch (name) {
+   case ACT_TIMEOUT_CLIENT:
+   s->scf->ioto = timeout;
+   return 1;
+
case ACT_TIMEOUT_SERVER:
s->scb->ioto = timeout;
return 1;
-- 
2.42.0