blob: 30aff97e8aa4a7157bc5f5bbd06d1f4551a7bef2 [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#include <ctype.h>
2
Willy Tarreau4c7e4b72020-05-27 12:58:42 +02003#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +02004#include <haproxy/arg.h>
Willy Tarreauc35eb382021-03-26 14:51:31 +01005#include <haproxy/buf.h>
Willy Tarreau6be78492020-06-05 00:00:29 +02006#include <haproxy/cfgparse.h>
Willy Tarreau4aa573d2020-06-04 18:21:56 +02007#include <haproxy/check.h>
Willy Tarreauc35eb382021-03-26 14:51:31 +01008#include <haproxy/cli.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +02009#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020010#include <haproxy/http.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020011#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020012#include <haproxy/list.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020013#include <haproxy/log.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020014#include <haproxy/sample.h>
Willy Tarreau753d4db2021-09-03 09:02:47 +020015#include <haproxy/session.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020016#include <haproxy/stream-t.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020017#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020018#include <haproxy/tcpcheck.h>
Willy Tarreau67046bf2021-05-08 13:56:31 +020019#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020020#include <haproxy/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020021
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020022
23/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010024DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020025
Willy Tarreaucfc4f242021-05-08 11:41:28 +020026/* list of variables for the process scope. */
27struct vars proc_vars THREAD_ALIGNED(64);
28
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020029/* This array contain all the names of all the HAProxy vars.
30 * This permits to identify two variables name with
31 * only one pointer. It permits to not using strdup() for
32 * each variable name used during the runtime.
33 */
34static char **var_names = NULL;
35static int var_names_nb = 0;
36
37/* This array of int contains the system limits per context. */
38static unsigned int var_global_limit = 0;
39static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010040static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020041static unsigned int var_sess_limit = 0;
42static unsigned int var_txn_limit = 0;
43static unsigned int var_reqres_limit = 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +010044static unsigned int var_check_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020045
Willy Tarreau86abe442018-11-25 20:12:18 +010046__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020047
Willy Tarreauf37b1402019-06-04 16:27:36 +020048/* returns the struct vars pointer for a session, stream and scope, or NULL if
49 * it does not exist.
50 */
51static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
52{
53 switch (scope) {
54 case SCOPE_PROC:
Willy Tarreaucfc4f242021-05-08 11:41:28 +020055 return &proc_vars;
Willy Tarreauf37b1402019-06-04 16:27:36 +020056 case SCOPE_SESS:
Willy Tarreaua07d61b2021-03-26 11:27:59 +010057 return sess ? &sess->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010058 case SCOPE_CHECK: {
Christopher Fauletc4439f72021-06-02 11:48:42 +020059 struct check *check = sess ? objt_check(sess->origin) : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010060
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020061 return check ? &check->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010062 }
Willy Tarreauf37b1402019-06-04 16:27:36 +020063 case SCOPE_TXN:
64 return strm ? &strm->vars_txn : NULL;
65 case SCOPE_REQ:
66 case SCOPE_RES:
67 default:
68 return strm ? &strm->vars_reqres : NULL;
69 }
70}
71
Willy Tarreau72330982015-06-19 11:21:56 +020072/* This function adds or remove memory size from the accounting. The inner
73 * pointers may be null when setting the outer ones only.
74 */
Miroslav Zagorac6deab792020-12-09 16:34:29 +010075void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020076{
77 switch (vars->scope) {
78 case SCOPE_REQ:
79 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020080 if (strm)
81 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010082 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020083 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020084 if (strm)
85 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010086 goto scope_sess;
87 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020088 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010089
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020090 if (check)
91 _HA_ATOMIC_ADD(&check->vars.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010092 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010093 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +010094scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020095 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010096 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010097 /* fall through */
98 case SCOPE_PROC:
Willy Tarreaucfc4f242021-05-08 11:41:28 +020099 _HA_ATOMIC_ADD(&proc_vars.size, size);
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100100 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200101 }
102}
103
104/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -0800105 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +0200106 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +0100107 * the outer ones only. The accounting uses either <sess> or <strm>
108 * depending on the scope. <strm> may be NULL when no stream is known
109 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200110 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100111static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112{
113 switch (vars->scope) {
114 case SCOPE_REQ:
115 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200116 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200117 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100118 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200119 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200120 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200121 return 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +0100122 goto scope_sess;
123 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200124 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +0100125
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200126 if (var_check_limit && check && check->vars.size + size > var_check_limit)
Gaetan Rivet13a50432020-02-21 18:13:44 +0100127 return 0;
128 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100129 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100130scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200131 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100132 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200133 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100134 /* fall through */
135 case SCOPE_PROC:
Willy Tarreaucfc4f242021-05-08 11:41:28 +0200136 if (var_proc_limit && proc_vars.size + size > var_proc_limit)
Christopher Fauletff2613e2016-11-09 11:36:17 +0100137 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200138 if (var_global_limit && var_global_size + size > var_global_limit)
139 return 0;
140 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100141 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200142 return 1;
143}
144
Christopher Faulet85d79c92016-11-09 16:54:56 +0100145/* This fnuction remove a variable from the list and free memory it used */
146unsigned int var_clear(struct var *var)
147{
148 unsigned int size = 0;
149
150 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100151 ha_free(&var->data.u.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200152 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100153 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200154 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100155 ha_free(&var->data.u.meth.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200156 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100157 }
Willy Tarreau2b718102021-04-21 07:32:39 +0200158 LIST_DELETE(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100159 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100160 size += sizeof(struct var);
161 return size;
162}
163
Joseph Herlant07676892018-11-15 09:19:50 -0800164/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200165 * in the list.
166 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100167void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200168{
169 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200170 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200171
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100172 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200173 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100174 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200175 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100176 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100177 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200178}
179
Willy Tarreauebcd4842015-06-19 11:59:02 +0200180/* This function frees all the memory used by all the session variables in the
181 * list starting at <vars>.
182 */
183void vars_prune_per_sess(struct vars *vars)
184{
185 struct var *var, *tmp;
186 unsigned int size = 0;
187
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100188 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200189 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100190 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200191 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100192 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200193
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100194 _HA_ATOMIC_SUB(&vars->size, size);
Willy Tarreaucfc4f242021-05-08 11:41:28 +0200195 _HA_ATOMIC_SUB(&proc_vars.size, size);
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100196 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200197}
198
Willy Tarreaub7bfcb32021-08-31 08:13:25 +0200199/* This function initializes a variables list head */
200void vars_init_head(struct vars *vars, enum vars_scope scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200201{
202 LIST_INIT(&vars->head);
203 vars->scope = scope;
204 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100205 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200206}
207
208/* This function declares a new variable name. It returns a pointer
209 * on the string identifying the name. This function assures that
210 * the same name exists only once.
211 *
212 * This function check if the variable name is acceptable.
213 *
214 * The function returns NULL if an error occurs, and <err> is filled.
215 * In this case, the HAProxy must be stopped because the structs are
216 * left inconsistent. Otherwise, it returns the pointer on the global
217 * name.
218 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100219static char *register_name(const char *name, int len, enum vars_scope *scope,
220 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200221{
222 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200223 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200224 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200225 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200226
227 /* Check length. */
228 if (len == 0) {
229 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100230 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200231 }
232
233 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100234 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
235 name += 5;
236 len -= 5;
237 *scope = SCOPE_PROC;
238 }
239 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200240 name += 5;
241 len -= 5;
242 *scope = SCOPE_SESS;
243 }
244 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
245 name += 4;
246 len -= 4;
247 *scope = SCOPE_TXN;
248 }
249 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
250 name += 4;
251 len -= 4;
252 *scope = SCOPE_REQ;
253 }
254 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
255 name += 4;
256 len -= 4;
257 *scope = SCOPE_RES;
258 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100259 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
260 name += 6;
261 len -= 6;
262 *scope = SCOPE_CHECK;
263 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200264 else {
Willy Tarreau1402fef2021-09-03 10:12:55 +0200265 memprintf(err, "invalid variable name '%.*s'. A variable name must be start by its scope. "
266 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", len, name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100267 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200268 }
269
Christopher Faulete95f2c32017-07-24 16:30:34 +0200270 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100271 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200272 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100273 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200274
275
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200276 /* Look for existing variable name. */
277 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200278 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
279 res = var_names[i];
280 goto end;
281 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200282
Christopher Faulete95f2c32017-07-24 16:30:34 +0200283 if (!alloc) {
284 res = NULL;
285 goto end;
286 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100287
Hubert Verstraete831962e2016-06-28 22:44:26 +0200288 /* Store variable name. If realloc fails, var_names remains valid */
289 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
290 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200291 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200292 res = NULL;
293 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200294 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200295 var_names_nb++;
296 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200297 var_names[var_names_nb - 1] = malloc(len + 1);
298 if (!var_names[var_names_nb - 1]) {
299 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200300 res = NULL;
301 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302 }
303 memcpy(var_names[var_names_nb - 1], name, len);
304 var_names[var_names_nb - 1][len] = '\0';
305
306 /* Check variable name syntax. */
307 tmp = var_names[var_names_nb - 1];
308 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100309 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200310 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200311 res = NULL;
312 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200313 }
314 tmp++;
315 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200316 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200317
Christopher Faulete95f2c32017-07-24 16:30:34 +0200318 end:
319 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100320 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200321 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100322 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200323
324 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200325}
326
327/* This function returns an existing variable or returns NULL. */
328static inline struct var *var_get(struct vars *vars, const char *name)
329{
330 struct var *var;
331
332 list_for_each_entry(var, &vars->head, l)
333 if (var->name == name)
334 return var;
335 return NULL;
336}
337
338/* Returns 0 if fails, else returns 1. */
339static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
340{
341 const struct var_desc *var_desc = &args[0].data.var;
Willy Tarreau54496a62021-09-03 12:00:13 +0200342 const struct buffer *def = NULL;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200343
Willy Tarreau54496a62021-09-03 12:00:13 +0200344 if (args[1].type == ARGT_STR)
345 def = &args[1].data.str;
346
347 return vars_get_by_desc(var_desc, smp, def);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200348}
349
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200350/* This function tries to create variable <name> in scope <scope> and store
351 * sample <smp> as its value. The stream and session are extracted from <smp>,
352 * and the stream may be NULL when scope is SCOPE_SESS. In case there wouldn't
353 * be enough memory to store the sample while the variable was already created,
354 * it would be changed to a bool (which is memory-less).
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200355 *
356 * Flags is a bitfield that may contain one of the following flags:
357 * - VF_UPDATEONLY: if the scope is SCOPE_PROC, the variable may only be
358 * updated but not created.
Willy Tarreau4994b572021-09-08 11:38:25 +0200359 * - VF_CREATEONLY: do nothing if the variable already exists (success).
Willy Tarreau3dc6dc32021-09-08 11:07:32 +0200360 * - VF_PERMANENT: this flag will be passed to the variable upon creation
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200361 *
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200362 * It returns 0 on failure, non-zero on success.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200363 */
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200364static int var_set(const char *name, enum vars_scope scope, struct sample *smp, uint flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200365{
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200366 struct vars *vars;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200367 struct var *var;
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200368 int ret = 0;
369
370 vars = get_vars(smp->sess, smp->strm, scope);
371 if (!vars || vars->scope != scope)
372 return 0;
373
374 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200375
376 /* Look for existing variable name. */
377 var = var_get(vars, name);
378
379 if (var) {
Willy Tarreau4994b572021-09-08 11:38:25 +0200380 if (flags & VF_CREATEONLY) {
381 ret = 1;
382 goto unlock;
383 }
384
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200385 /* free its used memory. */
386 if (var->data.type == SMP_T_STR ||
387 var->data.type == SMP_T_BIN) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100388 ha_free(&var->data.u.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200389 var_accounting_diff(vars, smp->sess, smp->strm,
390 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200391 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200392 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100393 ha_free(&var->data.u.meth.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200394 var_accounting_diff(vars, smp->sess, smp->strm,
395 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200396 }
397 } else {
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200398 /* creation permitted for proc ? */
399 if (flags & VF_UPDATEONLY && scope == SCOPE_PROC)
400 goto unlock;
401
Joseph Herlant07676892018-11-15 09:19:50 -0800402 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100403 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200404 goto unlock;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200405
406 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100407 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200408 if (!var)
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200409 goto unlock;
Willy Tarreau2b718102021-04-21 07:32:39 +0200410 LIST_APPEND(&vars->head, &var->l);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200411 var->name = name;
Willy Tarreau3dc6dc32021-09-08 11:07:32 +0200412 var->flags = flags & VF_PERMANENT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200413 }
414
415 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200416 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200417
418 /* Copy data. If the data needs memory, the function can fail. */
419 switch (var->data.type) {
420 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200421 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200422 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200423 break;
424 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200425 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200426 break;
427 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200428 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200429 break;
430 case SMP_T_STR:
431 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200432 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200433 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200434 goto unlock;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200435 }
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200436
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200437 var->data.u.str.area = malloc(smp->data.u.str.data);
438 if (!var->data.u.str.area) {
439 var_accounting_diff(vars, smp->sess, smp->strm,
440 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200441 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200442 goto unlock;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200443 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200444 var->data.u.str.data = smp->data.u.str.data;
445 memcpy(var->data.u.str.area, smp->data.u.str.area,
446 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200447 break;
448 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200449 var->data.u.meth.meth = smp->data.u.meth.meth;
450 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
451 break;
452
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200453 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200454 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200455 goto unlock;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200456 }
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200457
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200458 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
459 if (!var->data.u.meth.str.area) {
460 var_accounting_diff(vars, smp->sess, smp->strm,
461 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200462 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200463 goto unlock;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200464 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200465 var->data.u.meth.str.data = smp->data.u.meth.str.data;
466 var->data.u.meth.str.size = smp->data.u.meth.str.data;
467 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
468 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200469 break;
470 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200471
Willy Tarreauf1cb0eb2021-09-07 11:37:37 +0200472 /* OK, now done */
473 ret = 1;
474 unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100475 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200476 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200477}
478
Willy Tarreaud378eb82021-09-07 11:44:41 +0200479/* This unsets variable <name> from scope <scope>, using the session and stream
480 * found in <smp>. Note that stream may be null for SCOPE_SESS. Returns 0 if
481 * the scope was not found otherwise 1.
482 */
483static int var_unset(const char *name, enum vars_scope scope, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100484{
485 struct vars *vars;
486 struct var *var;
487 unsigned int size = 0;
488
Willy Tarreauf37b1402019-06-04 16:27:36 +0200489 vars = get_vars(smp->sess, smp->strm, scope);
490 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100491 return 0;
492
493 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100494 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100495 var = var_get(vars, name);
496 if (var) {
497 size = var_clear(var);
498 var_accounting_diff(vars, smp->sess, smp->strm, -size);
499 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100500 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100501 return 1;
502}
503
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200504/* Returns 0 if fails, else returns 1. */
505static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
506{
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200507 return var_set(args[0].data.var.name, args[0].data.var.scope, smp, 0);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200508}
509
Christopher Faulet85d79c92016-11-09 16:54:56 +0100510/* Returns 0 if fails, else returns 1. */
511static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
512{
Willy Tarreaud378eb82021-09-07 11:44:41 +0200513 return var_unset(args[0].data.var.name, args[0].data.var.scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100514}
515
Joseph Herlant07676892018-11-15 09:19:50 -0800516/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200517 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800518 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200519 */
520int vars_check_arg(struct arg *arg, char **err)
521{
522 char *name;
523 enum vars_scope scope;
524
525 /* Check arg type. */
526 if (arg->type != ARGT_STR) {
527 memprintf(err, "unexpected argument type");
528 return 0;
529 }
530
531 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200532 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
533 1,
534 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200535 if (!name)
536 return 0;
537
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200538 /* properly destroy the chunk */
539 chunk_destroy(&arg->data.str);
540
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200541 /* Use the global variable name pointer. */
542 arg->type = ARGT_VAR;
543 arg->data.var.name = name;
544 arg->data.var.scope = scope;
545 return 1;
546}
547
Christopher Faulet09c9df22016-10-31 11:05:37 +0100548/* This function store a sample in a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200549 * Returns zero on failure and non-zero otherwise. The variable not being
550 * defined is treated as a failure.
Christopher Faulet09c9df22016-10-31 11:05:37 +0100551 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200552int vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet09c9df22016-10-31 11:05:37 +0100553{
554 enum vars_scope scope;
555
556 /* Resolve name and scope. */
557 name = register_name(name, len, &scope, 0, NULL);
558 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200559 return 0;
Christopher Faulet09c9df22016-10-31 11:05:37 +0100560
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200561 return var_set(name, scope, smp, VF_UPDATEONLY);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100562}
563
564
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200565/* This function store a sample in a variable.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200566 * Returns zero on failure and non-zero otherwise.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200567 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200568int vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200569{
570 enum vars_scope scope;
571
572 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100573 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200574 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200575 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200576
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200577 return var_set(name, scope, smp, 0);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200578}
579
Christopher Faulet85d79c92016-11-09 16:54:56 +0100580/* This function unset a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200581 * Returns zero on failure and non-zero otherwise.
Christopher Faulet85d79c92016-11-09 16:54:56 +0100582 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200583int vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100584{
585 enum vars_scope scope;
586
587 /* Resolve name and scope. */
588 name = register_name(name, len, &scope, 0, NULL);
589 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200590 return 0;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100591
Willy Tarreaud378eb82021-09-07 11:44:41 +0200592 return var_unset(name, scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100593}
594
595
Willy Tarreau63c30662021-09-08 13:58:19 +0200596/* This retrieves variable <name> from variables <vars>, and if found and not
597 * empty, duplicates the result into sample <smp>. smp_dup() is used in order
598 * to release the variables lock ASAP (so a pre-allocated chunk is obtained
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200599 * via get_trash_shunk()). The variables' lock is used for reads.
600 *
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200601 * The function returns 0 if the variable was not found and no default
602 * value was provided in <def>, otherwise 1 with the sample filled.
603 * Default values are always returned as strings.
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200604 */
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200605static int var_to_smp(struct vars *vars, const char *name, struct sample *smp, const struct buffer *def)
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200606{
607 struct var *var;
608
609 /* Get the variable entry. */
610 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
611 var = var_get(vars, name);
Willy Tarreau63c30662021-09-08 13:58:19 +0200612 if (!var || !var->data.type) {
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200613 if (!def) {
614 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
615 return 0;
616 }
617
618 /* not found but we have a default value */
619 smp->data.type = SMP_T_STR;
620 smp->data.u.str = *def;
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200621 }
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200622 else
623 smp->data = var->data;
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200624
625 /* Copy sample. */
Willy Tarreaube7e00d2021-09-03 11:40:58 +0200626 smp_dup(smp);
627
628 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
629 return 1;
630}
631
Dragan Dosen14518f22021-02-22 17:20:01 +0100632/* This function fills a sample with the variable content.
633 *
634 * Keep in mind that a sample content is duplicated by using smp_dup()
635 * and it therefore uses a pre-allocated trash chunk as returned by
636 * get_trash_chunk().
637 *
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200638 * If the variable is not valid in this scope, 0 is always returned.
639 * If the variable is valid but not found, either the default value
640 * <def> is returned if not NULL, or zero is returned.
641 *
Dragan Dosen14518f22021-02-22 17:20:01 +0100642 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200643 */
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200644int vars_get_by_name(const char *name, size_t len, struct sample *smp, const struct buffer *def)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200645{
646 struct vars *vars;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200647 enum vars_scope scope;
648
649 /* Resolve name and scope. */
Willy Tarreau89f6ded2021-05-13 13:30:12 +0200650 name = register_name(name, len, &scope, 0, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200651 if (!name)
652 return 0;
653
654 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200655 vars = get_vars(smp->sess, smp->strm, scope);
656 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200657 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200658
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200659
660 return var_to_smp(vars, name, smp, def);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200661}
662
Dragan Dosen14518f22021-02-22 17:20:01 +0100663/* This function fills a sample with the content of the variable described
664 * by <var_desc>.
665 *
666 * Keep in mind that a sample content is duplicated by using smp_dup()
667 * and it therefore uses a pre-allocated trash chunk as returned by
668 * get_trash_chunk().
669 *
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200670 * If the variable is not valid in this scope, 0 is always returned.
671 * If the variable is valid but not found, either the default value
672 * <def> is returned if not NULL, or zero is returned.
673 *
Dragan Dosen14518f22021-02-22 17:20:01 +0100674 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200675 */
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200676int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp, const struct buffer *def)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200677{
678 struct vars *vars;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200679
680 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200681 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200682
Joseph Herlant07676892018-11-15 09:19:50 -0800683 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200684 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200685 return 0;
686
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200687 return var_to_smp(vars, var_desc->name, smp, def);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200688}
689
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200690/* Always returns ACT_RET_CONT even if an error occurs. */
691static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200692 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200693{
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200694 struct buffer *fmtstr = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200695 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200696 int dir;
697
698 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200699 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200700 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
701 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
702 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
703 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100704 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Willy Tarreau01d580a2021-03-26 11:11:34 +0100705 case ACT_F_CFG_PARSER: dir = SMP_OPT_DIR_REQ; break; /* not used anyway */
Willy Tarreau2f836de2021-03-26 15:36:44 +0100706 case ACT_F_CLI_PARSER: dir = SMP_OPT_DIR_REQ; break; /* not used anyway */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200707 default:
708 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
709 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100710 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200711 return ACT_RET_CONT;
712 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200713
714 /* Process the expression. */
715 memset(&smp, 0, sizeof(smp));
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200716
717 if (!LIST_ISEMPTY(&rule->arg.vars.fmt)) {
718 /* a format-string is used */
719
720 fmtstr = alloc_trash_chunk();
721 if (!fmtstr) {
722 send_log(px, LOG_ERR, "Vars: memory allocation failure while processing store rule.");
723 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
724 ha_alert("Vars: memory allocation failure while processing store rule.\n");
725 return ACT_RET_CONT;
726 }
727
728 /* execute the log-format expression */
729 fmtstr->data = sess_build_logline(sess, s, fmtstr->area, fmtstr->size, &rule->arg.vars.fmt);
730
731 /* convert it to a sample of type string as it's what the vars
732 * API consumes, and store it.
733 */
734 smp_set_owner(&smp, px, sess, s, 0);
735 smp.data.type = SMP_T_STR;
736 smp.data.u.str = *fmtstr;
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200737 var_set(rule->arg.vars.name, rule->arg.vars.scope, &smp, 0);
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200738 }
739 else {
740 /* an expression is used */
741 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
742 rule->arg.vars.expr, &smp))
743 return ACT_RET_CONT;
744 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200745
746 /* Store the sample, and ignore errors. */
Willy Tarreau7978c5c2021-09-07 14:24:07 +0200747 var_set(rule->arg.vars.name, rule->arg.vars.scope, &smp, 0);
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200748 free_trash_chunk(fmtstr);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200749 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200750}
751
Christopher Faulet85d79c92016-11-09 16:54:56 +0100752/* Always returns ACT_RET_CONT even if an error occurs. */
753static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
754 struct session *sess, struct stream *s, int flags)
755{
756 struct sample smp;
757
758 memset(&smp, 0, sizeof(smp));
759 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
760
761 /* Clear the variable using the sample context, and ignore errors. */
Willy Tarreaud378eb82021-09-07 11:44:41 +0200762 var_unset(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100763 return ACT_RET_CONT;
764}
765
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200766static void release_store_rule(struct act_rule *rule)
767{
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200768 struct logformat_node *lf, *lfb;
Willy Tarreauc77bad22021-09-03 10:58:07 +0200769
770 list_for_each_entry_safe(lf, lfb, &rule->arg.vars.fmt, list) {
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200771 LIST_DELETE(&lf->list);
772 release_sample_expr(lf->expr);
773 free(lf->arg);
774 free(lf);
775 }
776
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200777 release_sample_expr(rule->arg.vars.expr);
778}
779
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200780/* This two function checks the variable name and replace the
781 * configuration string name by the global string name. its
782 * the same string, but the global pointer can be easy to
Willy Tarreaue352b9d2021-09-03 11:52:38 +0200783 * compare. They return non-zero on success, zero on failure.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200784 *
785 * The first function checks a sample-fetch and the second
786 * checks a converter.
787 */
788static int smp_check_var(struct arg *args, char **err)
789{
790 return vars_check_arg(&args[0], err);
791}
792
793static int conv_check_var(struct arg *args, struct sample_conv *conv,
794 const char *file, int line, char **err_msg)
795{
796 return vars_check_arg(&args[0], err_msg);
797}
798
799/* This function is a common parser for using variables. It understands
800 * the format:
801 *
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200802 * set-var-fmt(<variable-name>) <format-string>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200803 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200804 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200805 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200806 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
807 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100808 * is filled with the pointer to the expression to execute. The proxy is
809 * only used to retrieve the ->conf entries.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200810 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200811static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
812 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200813{
814 const char *var_name = args[*arg-1];
815 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200816 const char *kw_name;
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200817 int flags, set_var = 0; /* 0=unset-var, 1=set-var, 2=set-var-fmt */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200818
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200819 if (strncmp(var_name, "set-var-fmt", 11) == 0) {
820 var_name += 11;
821 set_var = 2;
822 }
823 else if (strncmp(var_name, "set-var", 7) == 0) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100824 var_name += 7;
825 set_var = 1;
826 }
Willy Tarreau28192102021-09-02 18:46:22 +0200827 else if (strncmp(var_name, "unset-var", 9) == 0) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100828 var_name += 9;
829 set_var = 0;
830 }
831
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200832 if (*var_name != '(') {
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200833 memprintf(err, "invalid or incomplete action '%s'. Expects 'set-var(<var-name>)', 'set-var-fmt(<var-name>)' or 'unset-var(<var-name>)'",
Christopher Faulet85d79c92016-11-09 16:54:56 +0100834 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200835 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200836 }
837 var_name++; /* jump the '(' */
838 var_len = strlen(var_name);
839 var_len--; /* remove the ')' */
840 if (var_name[var_len] != ')') {
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200841 memprintf(err, "incomplete argument after action '%s'. Expects 'set-var(<var-name>)', 'set-var-fmt(<var-name>)' or 'unset-var(<var-name>)'",
Christopher Faulet85d79c92016-11-09 16:54:56 +0100842 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200843 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200844 }
845
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200846 LIST_INIT(&rule->arg.vars.fmt);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100847 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200848 if (!rule->arg.vars.name)
849 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200850
Christopher Faulet85d79c92016-11-09 16:54:56 +0100851 /* There is no fetch method when variable is unset. Just set the right
852 * action and return. */
853 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100854 rule->action = ACT_CUSTOM;
855 rule->action_ptr = action_clear;
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200856 rule->release_ptr = release_store_rule;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100857 return ACT_RET_PRS_OK;
858 }
859
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200860 kw_name = args[*arg-1];
861
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200862 switch (rule->from) {
Willy Tarreau843096d2021-09-02 19:03:07 +0200863 case ACT_F_TCP_REQ_SES:
864 flags = SMP_VAL_FE_SES_ACC;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200865 px->conf.args.ctx = ARGC_TSE;
Willy Tarreau843096d2021-09-02 19:03:07 +0200866 break;
867 case ACT_F_TCP_REQ_CNT:
868 flags = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_REQ_CNT : SMP_VAL_BE_REQ_CNT;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200869 px->conf.args.ctx = ARGC_TRQ;
Willy Tarreau843096d2021-09-02 19:03:07 +0200870 break;
871 case ACT_F_TCP_RES_CNT:
872 flags = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_RES_CNT : SMP_VAL_BE_RES_CNT;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200873 px->conf.args.ctx = ARGC_TRS;
Willy Tarreau843096d2021-09-02 19:03:07 +0200874 break;
875 case ACT_F_HTTP_REQ:
876 flags = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200877 px->conf.args.ctx = ARGC_HRQ;
Willy Tarreau843096d2021-09-02 19:03:07 +0200878 break;
879 case ACT_F_HTTP_RES:
880 flags = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200881 px->conf.args.ctx = ARGC_HRS;
Willy Tarreau843096d2021-09-02 19:03:07 +0200882 break;
883 case ACT_F_TCP_CHK:
884 flags = SMP_VAL_BE_CHK_RUL;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200885 px->conf.args.ctx = ARGC_TCK;
Willy Tarreau843096d2021-09-02 19:03:07 +0200886 break;
887 case ACT_F_CFG_PARSER:
888 flags = SMP_VAL_CFG_PARSER;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200889 px->conf.args.ctx = ARGC_CFG;
Willy Tarreau843096d2021-09-02 19:03:07 +0200890 break;
891 case ACT_F_CLI_PARSER:
892 flags = SMP_VAL_CLI_PARSER;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200893 px->conf.args.ctx = ARGC_CLI;
Willy Tarreau843096d2021-09-02 19:03:07 +0200894 break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200895 default:
896 memprintf(err,
897 "internal error, unexpected rule->from=%d, please report this bug!",
898 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200899 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200900 }
Willy Tarreau54b96d92021-09-02 19:46:08 +0200901
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200902 if (set_var == 2) { /* set-var-fmt */
903 if (!parse_logformat_string(args[*arg], px, &rule->arg.vars.fmt, 0, flags, err))
904 return ACT_RET_PRS_ERR;
Willy Tarreau54b96d92021-09-02 19:46:08 +0200905
Willy Tarreau9a621ae2021-09-02 21:00:38 +0200906 (*arg)++;
907
908 /* for late error reporting */
909 free(px->conf.lfs_file);
910 px->conf.lfs_file = strdup(px->conf.args.file);
911 px->conf.lfs_line = px->conf.args.line;
912 } else {
913 /* set-var */
914 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
915 px->conf.args.line, err, &px->conf.args, NULL);
916 if (!rule->arg.vars.expr)
917 return ACT_RET_PRS_ERR;
918
919 if (!(rule->arg.vars.expr->fetch->val & flags)) {
920 memprintf(err,
921 "fetch method '%s' extracts information from '%s', none of which is available here",
922 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
923 free(rule->arg.vars.expr);
924 return ACT_RET_PRS_ERR;
925 }
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200926 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200927
Thierry FOURNIER42148732015-09-02 17:17:33 +0200928 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200929 rule->action_ptr = action_store;
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200930 rule->release_ptr = release_store_rule;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200931 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200932}
933
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100934
935/* parses a global "set-var" directive. It will create a temporary rule and
936 * expression that are parsed, processed, and released on the fly so that we
937 * respect the real set-var syntax. These directives take the following format:
938 * set-var <name> <expression>
Willy Tarreau753d4db2021-09-03 09:02:47 +0200939 * set-var-fmt <name> <fmt>
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100940 * Note that parse_store() expects "set-var(name) <expression>" so we have to
941 * temporarily replace the keyword here.
942 */
943static int vars_parse_global_set_var(char **args, int section_type, struct proxy *curpx,
944 const struct proxy *defpx, const char *file, int line,
945 char **err)
946{
947 struct proxy px = {
Willy Tarreau9c204332021-09-03 08:19:43 +0200948 .id = "CFG",
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100949 .conf.args.file = file,
950 .conf.args.line = line,
951 };
952 struct act_rule rule = {
953 .arg.vars.scope = SCOPE_PROC,
954 .from = ACT_F_CFG_PARSER,
955 };
Willy Tarreau753d4db2021-09-03 09:02:47 +0200956 enum obj_type objt = OBJ_TYPE_NONE;
957 struct session *sess = NULL;
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100958 enum act_parse_ret p_ret;
959 char *old_arg1;
960 char *tmp_arg1;
961 int arg = 2; // variable name
962 int ret = -1;
Willy Tarreau753d4db2021-09-03 09:02:47 +0200963 int use_fmt = 0;
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100964
965 LIST_INIT(&px.conf.args.list);
966
Willy Tarreau753d4db2021-09-03 09:02:47 +0200967 use_fmt = strcmp(args[0], "set-var-fmt") == 0;
968
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100969 if (!*args[1] || !*args[2]) {
Willy Tarreau753d4db2021-09-03 09:02:47 +0200970 if (use_fmt)
971 memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a format string.", args[0]);
972 else
973 memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a sample expression.", args[0]);
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100974 goto end;
975 }
976
977 tmp_arg1 = NULL;
Willy Tarreau753d4db2021-09-03 09:02:47 +0200978 if (!memprintf(&tmp_arg1, "set-var%s(%s)", use_fmt ? "-fmt" : "", args[1]))
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100979 goto end;
980
981 /* parse_store() will always return a message in <err> on error */
982 old_arg1 = args[1]; args[1] = tmp_arg1;
983 p_ret = parse_store((const char **)args, &arg, &px, &rule, err);
984 free(args[1]); args[1] = old_arg1;
985
986 if (p_ret != ACT_RET_PRS_OK)
987 goto end;
988
989 if (rule.arg.vars.scope != SCOPE_PROC) {
990 memprintf(err, "'%s': cannot set variable '%s', only scope 'proc' is permitted in the global section.", args[0], args[1]);
991 goto end;
992 }
993
994 if (smp_resolve_args(&px, err) != 0) {
995 release_sample_expr(rule.arg.vars.expr);
996 indent_msg(err, 2);
997 goto end;
998 }
999
Willy Tarreau753d4db2021-09-03 09:02:47 +02001000 if (use_fmt && !(sess = session_new(&px, NULL, &objt))) {
1001 release_sample_expr(rule.arg.vars.expr);
1002 memprintf(err, "'%s': out of memory when trying to set variable '%s' in the global section.", args[0], args[1]);
1003 goto end;
1004 }
1005
1006 action_store(&rule, &px, sess, NULL, 0);
Willy Tarreau13d2ba22021-03-26 11:38:08 +01001007 release_sample_expr(rule.arg.vars.expr);
Willy Tarreau753d4db2021-09-03 09:02:47 +02001008 if (sess)
1009 session_free(sess);
Willy Tarreau13d2ba22021-03-26 11:38:08 +01001010
1011 ret = 0;
1012 end:
1013 return ret;
1014}
1015
Willy Tarreauc35eb382021-03-26 14:51:31 +01001016/* parse CLI's "get var <name>" */
1017static int vars_parse_cli_get_var(char **args, char *payload, struct appctx *appctx, void *private)
1018{
1019 struct vars *vars;
Willy Tarreau374edc72021-04-01 17:01:43 +02001020 struct sample smp = { };
Willy Tarreauc35eb382021-03-26 14:51:31 +01001021 int i;
1022
1023 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
1024 return 1;
1025
1026 if (!*args[2])
1027 return cli_err(appctx, "Missing process-wide variable identifier.\n");
1028
1029 vars = get_vars(NULL, NULL, SCOPE_PROC);
1030 if (!vars || vars->scope != SCOPE_PROC)
1031 return 0;
1032
Willy Tarreaue352b9d2021-09-03 11:52:38 +02001033 if (!vars_get_by_name(args[2], strlen(args[2]), &smp, NULL))
Willy Tarreauc35eb382021-03-26 14:51:31 +01001034 return cli_err(appctx, "Variable not found.\n");
1035
1036 /* the sample returned by vars_get_by_name() is allocated into a trash
1037 * chunk so we have no constraint to manipulate it.
1038 */
1039 chunk_printf(&trash, "%s: type=%s value=", args[2], smp_to_type[smp.data.type]);
1040
1041 if (!sample_casts[smp.data.type][SMP_T_STR] ||
1042 !sample_casts[smp.data.type][SMP_T_STR](&smp)) {
1043 chunk_appendf(&trash, "(undisplayable)");
1044 } else {
1045 /* Display the displayable chars*. */
1046 b_putchr(&trash, '<');
1047 for (i = 0; i < smp.data.u.str.data; i++) {
1048 if (isprint((unsigned char)smp.data.u.str.area[i]))
1049 b_putchr(&trash, smp.data.u.str.area[i]);
1050 else
1051 b_putchr(&trash, '.');
1052 }
1053 b_putchr(&trash, '>');
1054 b_putchr(&trash, 0);
1055 }
1056 return cli_msg(appctx, LOG_INFO, trash.area);
1057}
1058
Willy Tarreaue93bff42021-09-03 09:47:37 +02001059/* parse CLI's "set var <name>". It accepts:
1060 * - set var <name> <expression>
1061 * - set var <name> expr <expression>
1062 * - set var <name> fmt <format>
1063 */
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001064static int vars_parse_cli_set_var(char **args, char *payload, struct appctx *appctx, void *private)
1065{
1066 struct proxy px = {
1067 .id = "CLI",
1068 .conf.args.file = "CLI",
1069 .conf.args.line = 0,
1070 };
1071 struct act_rule rule = {
1072 .arg.vars.scope = SCOPE_PROC,
1073 .from = ACT_F_CLI_PARSER,
1074 };
Willy Tarreaue93bff42021-09-03 09:47:37 +02001075 enum obj_type objt = OBJ_TYPE_NONE;
1076 struct session *sess = NULL;
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001077 enum act_parse_ret p_ret;
Willy Tarreaue93bff42021-09-03 09:47:37 +02001078 const char *tmp_args[3];
1079 int tmp_arg;
1080 char *tmp_act;
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001081 char *err = NULL;
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001082 int nberr;
Willy Tarreaue93bff42021-09-03 09:47:37 +02001083 int use_fmt = 0;
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001084
1085 LIST_INIT(&px.conf.args.list);
1086
1087 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
1088 return 1;
1089
Willy Tarreaue93bff42021-09-03 09:47:37 +02001090 if (!*args[2])
1091 return cli_err(appctx, "Missing process-wide variable identifier.\n");
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001092
Willy Tarreaue93bff42021-09-03 09:47:37 +02001093 if (!*args[3])
1094 return cli_err(appctx, "Missing either 'expr', 'fmt' or expression.\n");
1095
1096 if (*args[4]) {
1097 /* this is the long format */
1098 if (strcmp(args[3], "fmt") == 0)
1099 use_fmt = 1;
1100 else if (strcmp(args[3], "expr") != 0) {
1101 memprintf(&err, "'%s %s': arg type must be either 'expr' or 'fmt' but got '%s'.", args[0], args[1], args[3]);
1102 goto fail;
1103 }
1104 }
1105
1106 tmp_act = NULL;
1107 if (!memprintf(&tmp_act, "set-var%s(%s)", use_fmt ? "-fmt" : "", args[2])) {
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001108 memprintf(&err, "memory allocation error.");
1109 goto fail;
1110 }
1111
1112 /* parse_store() will always return a message in <err> on error */
Willy Tarreaue93bff42021-09-03 09:47:37 +02001113 tmp_args[0] = tmp_act;
1114 tmp_args[1] = (*args[4]) ? args[4] : args[3];
1115 tmp_args[2] = "";
1116 tmp_arg = 1; // must point to the first arg after the action
1117 p_ret = parse_store(tmp_args, &tmp_arg, &px, &rule, &err);
1118 free(tmp_act);
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001119
1120 if (p_ret != ACT_RET_PRS_OK)
1121 goto fail;
1122
1123 if (rule.arg.vars.scope != SCOPE_PROC) {
Willy Tarreauc767eeb2021-09-03 10:23:26 +02001124 memprintf(&err, "'%s %s': cannot set variable '%s', only scope 'proc' is permitted here.", args[0], args[1], args[2]);
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001125 goto fail;
1126 }
1127
1128 err = NULL;
1129 nberr = smp_resolve_args(&px, &err);
1130 if (nberr) {
1131 release_sample_expr(rule.arg.vars.expr);
1132 indent_msg(&err, 2);
1133 goto fail;
1134 }
1135
Willy Tarreaue93bff42021-09-03 09:47:37 +02001136 if (use_fmt && !(sess = session_new(&px, NULL, &objt))) {
1137 release_sample_expr(rule.arg.vars.expr);
1138 memprintf(&err, "memory allocation error.");
1139 goto fail;
1140 }
1141
1142 action_store(&rule, &px, sess, NULL, 0);
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001143 release_sample_expr(rule.arg.vars.expr);
Willy Tarreaue93bff42021-09-03 09:47:37 +02001144 if (sess)
1145 session_free(sess);
1146
Willy Tarreaub8bd1ee2021-03-26 15:19:50 +01001147 appctx->st0 = CLI_ST_PROMPT;
1148 return 0;
1149 fail:
1150 return cli_dynerr(appctx, err);
1151}
1152
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001153static int vars_max_size(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001154 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001155 char **err, unsigned int *limit)
1156{
1157 char *error;
1158
1159 *limit = strtol(args[1], &error, 10);
1160 if (*error != 0) {
1161 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
1162 return -1;
1163 }
1164 return 0;
1165}
1166
1167static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001168 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001169 char **err)
1170{
1171 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
1172}
1173
Christopher Fauletff2613e2016-11-09 11:36:17 +01001174static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001175 const struct proxy *defpx, const char *file, int line,
Christopher Fauletff2613e2016-11-09 11:36:17 +01001176 char **err)
1177{
1178 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
1179}
1180
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001181static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001182 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001183 char **err)
1184{
1185 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
1186}
1187
1188static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001189 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001190 char **err)
1191{
1192 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
1193}
1194
1195static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001196 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001197 char **err)
1198{
1199 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
1200}
1201
Gaetan Rivet13a50432020-02-21 18:13:44 +01001202static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01001203 const struct proxy *defpx, const char *file, int line,
Gaetan Rivet13a50432020-02-21 18:13:44 +01001204 char **err)
1205{
1206 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
1207}
1208
Tim Duesterhusbbdd5b82020-07-04 11:53:25 +02001209static void vars_deinit()
1210{
1211 while (var_names_nb-- > 0)
1212 free(var_names[var_names_nb]);
1213 free(var_names);
1214}
1215
1216REGISTER_POST_DEINIT(vars_deinit);
1217
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001218static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
1219
Willy Tarreau54496a62021-09-03 12:00:13 +02001220 { "var", smp_fetch_var, ARG2(1,STR,STR), smp_check_var, SMP_T_STR, SMP_USE_CONST },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001221 { /* END */ },
1222}};
1223
Willy Tarreau0108d902018-11-25 19:14:37 +01001224INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
1225
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001226static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +01001227 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
1228 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001229 { /* END */ },
1230}};
1231
Willy Tarreau0108d902018-11-25 19:14:37 +01001232INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
1233
Willy Tarreau620408f2016-10-21 16:37:51 +02001234static struct action_kw_list tcp_req_sess_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001235 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001236 { "set-var", parse_store, KWF_MATCH_PREFIX },
1237 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Willy Tarreau620408f2016-10-21 16:37:51 +02001238 { /* END */ }
1239}};
1240
Willy Tarreau0108d902018-11-25 19:14:37 +01001241INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
1242
Willy Tarreau620408f2016-10-21 16:37:51 +02001243static struct action_kw_list tcp_req_cont_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001244 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001245 { "set-var", parse_store, KWF_MATCH_PREFIX },
1246 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001247 { /* END */ }
1248}};
1249
Willy Tarreau0108d902018-11-25 19:14:37 +01001250INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
1251
Thierry FOURNIER36481b82015-08-19 09:01:53 +02001252static struct action_kw_list tcp_res_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001253 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001254 { "set-var", parse_store, KWF_MATCH_PREFIX },
1255 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001256 { /* END */ }
1257}};
1258
Willy Tarreau0108d902018-11-25 19:14:37 +01001259INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
1260
Gaetan Rivet707b52f2020-02-21 18:14:59 +01001261static struct action_kw_list tcp_check_kws = {ILH, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001262 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001263 { "set-var", parse_store, KWF_MATCH_PREFIX },
1264 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Gaetan Rivet707b52f2020-02-21 18:14:59 +01001265 { /* END */ }
1266}};
1267
1268INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
1269
Thierry FOURNIER36481b82015-08-19 09:01:53 +02001270static struct action_kw_list http_req_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001271 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001272 { "set-var", parse_store, KWF_MATCH_PREFIX },
1273 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001274 { /* END */ }
1275}};
1276
Willy Tarreau0108d902018-11-25 19:14:37 +01001277INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
1278
Thierry FOURNIER36481b82015-08-19 09:01:53 +02001279static struct action_kw_list http_res_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001280 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001281 { "set-var", parse_store, KWF_MATCH_PREFIX },
1282 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001283 { /* END */ }
1284}};
1285
Willy Tarreau0108d902018-11-25 19:14:37 +01001286INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
1287
Christopher Faulet6d0c3df2020-01-22 09:26:35 +01001288static struct action_kw_list http_after_res_kws = { { }, {
Willy Tarreau9a621ae2021-09-02 21:00:38 +02001289 { "set-var-fmt", parse_store, KWF_MATCH_PREFIX },
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02001290 { "set-var", parse_store, KWF_MATCH_PREFIX },
1291 { "unset-var", parse_store, KWF_MATCH_PREFIX },
Christopher Faulet6d0c3df2020-01-22 09:26:35 +01001292 { /* END */ }
1293}};
1294
1295INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
1296
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001297static struct cfg_kw_list cfg_kws = {{ },{
Willy Tarreau13d2ba22021-03-26 11:38:08 +01001298 { CFG_GLOBAL, "set-var", vars_parse_global_set_var },
Willy Tarreau753d4db2021-09-03 09:02:47 +02001299 { CFG_GLOBAL, "set-var-fmt", vars_parse_global_set_var },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001300 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +01001301 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001302 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
1303 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
1304 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +01001305 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001306 { /* END */ }
1307}};
1308
Willy Tarreau0108d902018-11-25 19:14:37 +01001309INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
Willy Tarreauc35eb382021-03-26 14:51:31 +01001310
1311
1312/* register cli keywords */
1313static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02001314 { { "get", "var", NULL }, "get var <name> : retrieve contents of a process-wide variable", vars_parse_cli_get_var, NULL },
Willy Tarreaue93bff42021-09-03 09:47:37 +02001315 { { "set", "var", NULL }, "set var <name> [fmt|expr] {<fmt>|<expr>}: set variable from an expression or a format", vars_parse_cli_set_var, NULL, NULL, NULL, ACCESS_EXPERIMENTAL },
Willy Tarreauc35eb382021-03-26 14:51:31 +01001316 { { NULL }, NULL, NULL, NULL }
1317}};
1318INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);