blob: 9be070b71f0b7a861c467949d64f90371e8c3361 [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 Tarreau6be78492020-06-05 00:00:29 +02005#include <haproxy/cfgparse.h>
Willy Tarreau4aa573d2020-06-04 18:21:56 +02006#include <haproxy/check.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +02007#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +02008#include <haproxy/http.h>
Willy Tarreauc761f842020-06-04 11:40:28 +02009#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020010#include <haproxy/list.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020011#include <haproxy/log.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020012#include <haproxy/sample.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020013#include <haproxy/stream-t.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020014#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020015#include <haproxy/tcpcheck.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020016#include <haproxy/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020017
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020018
19/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010020DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020021
22/* This array contain all the names of all the HAProxy vars.
23 * This permits to identify two variables name with
24 * only one pointer. It permits to not using strdup() for
25 * each variable name used during the runtime.
26 */
27static char **var_names = NULL;
28static int var_names_nb = 0;
29
30/* This array of int contains the system limits per context. */
31static unsigned int var_global_limit = 0;
32static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010033static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020034static unsigned int var_sess_limit = 0;
35static unsigned int var_txn_limit = 0;
36static unsigned int var_reqres_limit = 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +010037static unsigned int var_check_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020038
Willy Tarreau86abe442018-11-25 20:12:18 +010039__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020040
Willy Tarreauf37b1402019-06-04 16:27:36 +020041/* returns the struct vars pointer for a session, stream and scope, or NULL if
42 * it does not exist.
43 */
44static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
45{
46 switch (scope) {
47 case SCOPE_PROC:
48 return &global.vars;
49 case SCOPE_SESS:
Willy Tarreaua07d61b2021-03-26 11:27:59 +010050 return sess ? &sess->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010051 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020052 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010053
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020054 return check ? &check->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010055 }
Willy Tarreauf37b1402019-06-04 16:27:36 +020056 case SCOPE_TXN:
57 return strm ? &strm->vars_txn : NULL;
58 case SCOPE_REQ:
59 case SCOPE_RES:
60 default:
61 return strm ? &strm->vars_reqres : NULL;
62 }
63}
64
Willy Tarreau72330982015-06-19 11:21:56 +020065/* This function adds or remove memory size from the accounting. The inner
66 * pointers may be null when setting the outer ones only.
67 */
Miroslav Zagorac6deab792020-12-09 16:34:29 +010068void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020069{
70 switch (vars->scope) {
71 case SCOPE_REQ:
72 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020073 if (strm)
74 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010075 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020076 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020077 if (strm)
78 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010079 goto scope_sess;
80 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020081 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010082
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020083 if (check)
84 _HA_ATOMIC_ADD(&check->vars.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010085 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010086 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +010087scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020088 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010089 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010090 /* fall through */
91 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010092 _HA_ATOMIC_ADD(&global.vars.size, size);
93 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020094 }
95}
96
97/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080098 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020099 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +0100100 * the outer ones only. The accounting uses either <sess> or <strm>
101 * depending on the scope. <strm> may be NULL when no stream is known
102 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200103 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100104static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200105{
106 switch (vars->scope) {
107 case SCOPE_REQ:
108 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200109 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200110 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100111 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200113 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200114 return 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +0100115 goto scope_sess;
116 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200117 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +0100118
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200119 if (var_check_limit && check && check->vars.size + size > var_check_limit)
Gaetan Rivet13a50432020-02-21 18:13:44 +0100120 return 0;
121 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100122 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100123scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200124 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100125 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200126 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100127 /* fall through */
128 case SCOPE_PROC:
129 if (var_proc_limit && global.vars.size + size > var_proc_limit)
130 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200131 if (var_global_limit && var_global_size + size > var_global_limit)
132 return 0;
133 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100134 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200135 return 1;
136}
137
Christopher Faulet85d79c92016-11-09 16:54:56 +0100138/* This fnuction remove a variable from the list and free memory it used */
139unsigned int var_clear(struct var *var)
140{
141 unsigned int size = 0;
142
143 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100144 ha_free(&var->data.u.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200145 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100146 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200147 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100148 ha_free(&var->data.u.meth.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200149 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100150 }
151 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100152 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100153 size += sizeof(struct var);
154 return size;
155}
156
Joseph Herlant07676892018-11-15 09:19:50 -0800157/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200158 * in the list.
159 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100160void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200161{
162 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200163 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200164
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100165 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200166 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100167 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200168 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100169 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100170 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200171}
172
Willy Tarreauebcd4842015-06-19 11:59:02 +0200173/* This function frees all the memory used by all the session variables in the
174 * list starting at <vars>.
175 */
176void vars_prune_per_sess(struct vars *vars)
177{
178 struct var *var, *tmp;
179 unsigned int size = 0;
180
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100181 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200182 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100183 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200184 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100185 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200186
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100187 _HA_ATOMIC_SUB(&vars->size, size);
188 _HA_ATOMIC_SUB(&global.vars.size, size);
189 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200190}
191
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500192/* This function init a list of variables. */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200193void vars_init(struct vars *vars, enum vars_scope scope)
194{
195 LIST_INIT(&vars->head);
196 vars->scope = scope;
197 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100198 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200199}
200
201/* This function declares a new variable name. It returns a pointer
202 * on the string identifying the name. This function assures that
203 * the same name exists only once.
204 *
205 * This function check if the variable name is acceptable.
206 *
207 * The function returns NULL if an error occurs, and <err> is filled.
208 * In this case, the HAProxy must be stopped because the structs are
209 * left inconsistent. Otherwise, it returns the pointer on the global
210 * name.
211 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100212static char *register_name(const char *name, int len, enum vars_scope *scope,
213 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200214{
215 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200216 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200217 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200218 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200219
220 /* Check length. */
221 if (len == 0) {
222 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100223 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200224 }
225
226 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100227 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
228 name += 5;
229 len -= 5;
230 *scope = SCOPE_PROC;
231 }
232 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200233 name += 5;
234 len -= 5;
235 *scope = SCOPE_SESS;
236 }
237 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
238 name += 4;
239 len -= 4;
240 *scope = SCOPE_TXN;
241 }
242 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
243 name += 4;
244 len -= 4;
245 *scope = SCOPE_REQ;
246 }
247 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
248 name += 4;
249 len -= 4;
250 *scope = SCOPE_RES;
251 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100252 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
253 name += 6;
254 len -= 6;
255 *scope = SCOPE_CHECK;
256 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200257 else {
258 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Gaetan Rivet13a50432020-02-21 18:13:44 +0100259 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100260 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200261 }
262
Christopher Faulete95f2c32017-07-24 16:30:34 +0200263 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100264 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200265 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100266 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200267
268
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200269 /* Look for existing variable name. */
270 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200271 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
272 res = var_names[i];
273 goto end;
274 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200275
Christopher Faulete95f2c32017-07-24 16:30:34 +0200276 if (!alloc) {
277 res = NULL;
278 goto end;
279 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100280
Hubert Verstraete831962e2016-06-28 22:44:26 +0200281 /* Store variable name. If realloc fails, var_names remains valid */
282 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
283 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200284 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200285 res = NULL;
286 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200287 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200288 var_names_nb++;
289 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200290 var_names[var_names_nb - 1] = malloc(len + 1);
291 if (!var_names[var_names_nb - 1]) {
292 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200293 res = NULL;
294 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200295 }
296 memcpy(var_names[var_names_nb - 1], name, len);
297 var_names[var_names_nb - 1][len] = '\0';
298
299 /* Check variable name syntax. */
300 tmp = var_names[var_names_nb - 1];
301 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100302 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200303 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200304 res = NULL;
305 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200306 }
307 tmp++;
308 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200309 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200310
Christopher Faulete95f2c32017-07-24 16:30:34 +0200311 end:
312 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100313 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200314 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100315 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200316
317 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200318}
319
320/* This function returns an existing variable or returns NULL. */
321static inline struct var *var_get(struct vars *vars, const char *name)
322{
323 struct var *var;
324
325 list_for_each_entry(var, &vars->head, l)
326 if (var->name == name)
327 return var;
328 return NULL;
329}
330
331/* Returns 0 if fails, else returns 1. */
332static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
333{
334 const struct var_desc *var_desc = &args[0].data.var;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200335
Dragan Dosenec0a6042021-02-22 17:39:02 +0100336 return vars_get_by_desc(var_desc, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200337}
338
339/* This function search in the <head> a variable with the same
340 * pointer value that the <name>. If the variable doesn't exists,
341 * create it. The function stores a copy of smp> if the variable.
342 * It returns 0 if fails, else returns 1.
343 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100344static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200345{
346 struct var *var;
347
348 /* Look for existing variable name. */
349 var = var_get(vars, name);
350
351 if (var) {
352 /* free its used memory. */
353 if (var->data.type == SMP_T_STR ||
354 var->data.type == SMP_T_BIN) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100355 ha_free(&var->data.u.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200356 var_accounting_diff(vars, smp->sess, smp->strm,
357 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200358 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200359 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau5b52b002021-02-26 21:19:53 +0100360 ha_free(&var->data.u.meth.str.area);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200361 var_accounting_diff(vars, smp->sess, smp->strm,
362 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200363 }
364 } else {
365
Joseph Herlant07676892018-11-15 09:19:50 -0800366 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100367 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200368 return 0;
369
370 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100371 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200372 if (!var)
373 return 0;
374 LIST_ADDQ(&vars->head, &var->l);
375 var->name = name;
376 }
377
378 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200379 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200380
381 /* Copy data. If the data needs memory, the function can fail. */
382 switch (var->data.type) {
383 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200384 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200385 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200386 break;
387 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200388 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200389 break;
390 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200391 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200392 break;
393 case SMP_T_STR:
394 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200395 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200396 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
397 return 0;
398 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200399 var->data.u.str.area = malloc(smp->data.u.str.data);
400 if (!var->data.u.str.area) {
401 var_accounting_diff(vars, smp->sess, smp->strm,
402 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200403 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
404 return 0;
405 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200406 var->data.u.str.data = smp->data.u.str.data;
407 memcpy(var->data.u.str.area, smp->data.u.str.area,
408 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200409 break;
410 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200411 var->data.u.meth.meth = smp->data.u.meth.meth;
412 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
413 break;
414
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200415 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200416 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
417 return 0;
418 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200419 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
420 if (!var->data.u.meth.str.area) {
421 var_accounting_diff(vars, smp->sess, smp->strm,
422 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200423 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
424 return 0;
425 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200426 var->data.u.meth.str.data = smp->data.u.meth.str.data;
427 var->data.u.meth.str.size = smp->data.u.meth.str.data;
428 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
429 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200430 break;
431 }
432 return 1;
433}
434
Willy Tarreau620408f2016-10-21 16:37:51 +0200435/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100436static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200437{
438 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200439 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200440
Willy Tarreauf37b1402019-06-04 16:27:36 +0200441 vars = get_vars(smp->sess, smp->strm, scope);
442 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200443 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200444
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100445 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200446 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100447 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200448 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200449}
450
Christopher Faulet85d79c92016-11-09 16:54:56 +0100451/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
452static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
453{
454 struct vars *vars;
455 struct var *var;
456 unsigned int size = 0;
457
Willy Tarreauf37b1402019-06-04 16:27:36 +0200458 vars = get_vars(smp->sess, smp->strm, scope);
459 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100460 return 0;
461
462 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100463 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100464 var = var_get(vars, name);
465 if (var) {
466 size = var_clear(var);
467 var_accounting_diff(vars, smp->sess, smp->strm, -size);
468 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100470 return 1;
471}
472
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200473/* Returns 0 if fails, else returns 1. */
474static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
475{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100476 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200477}
478
Christopher Faulet85d79c92016-11-09 16:54:56 +0100479/* Returns 0 if fails, else returns 1. */
480static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
481{
482 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
483}
484
Joseph Herlant07676892018-11-15 09:19:50 -0800485/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200486 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800487 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200488 */
489int vars_check_arg(struct arg *arg, char **err)
490{
491 char *name;
492 enum vars_scope scope;
493
494 /* Check arg type. */
495 if (arg->type != ARGT_STR) {
496 memprintf(err, "unexpected argument type");
497 return 0;
498 }
499
500 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200501 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
502 1,
503 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200504 if (!name)
505 return 0;
506
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200507 /* properly destroy the chunk */
508 chunk_destroy(&arg->data.str);
509
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200510 /* Use the global variable name pointer. */
511 arg->type = ARGT_VAR;
512 arg->data.var.name = name;
513 arg->data.var.scope = scope;
514 return 1;
515}
516
Christopher Faulet09c9df22016-10-31 11:05:37 +0100517/* This function store a sample in a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200518 * Returns zero on failure and non-zero otherwise. The variable not being
519 * defined is treated as a failure.
Christopher Faulet09c9df22016-10-31 11:05:37 +0100520 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200521int vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet09c9df22016-10-31 11:05:37 +0100522{
523 enum vars_scope scope;
524
525 /* Resolve name and scope. */
526 name = register_name(name, len, &scope, 0, NULL);
527 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200528 return 0;
Christopher Faulet09c9df22016-10-31 11:05:37 +0100529
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200530 return sample_store_stream(name, scope, smp);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100531}
532
533
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200534/* This function store a sample in a variable.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200535 * Returns zero on failure and non-zero otherwise.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200536 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200537int vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200538{
539 enum vars_scope scope;
540
541 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100542 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200543 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200544 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200545
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200546 return sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200547}
548
Christopher Faulet85d79c92016-11-09 16:54:56 +0100549/* This function unset a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200550 * Returns zero on failure and non-zero otherwise.
Christopher Faulet85d79c92016-11-09 16:54:56 +0100551 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200552int vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +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 Faulet85d79c92016-11-09 16:54:56 +0100560
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200561 return sample_clear_stream(name, scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100562}
563
564
Dragan Dosen14518f22021-02-22 17:20:01 +0100565/* This function fills a sample with the variable content.
566 *
567 * Keep in mind that a sample content is duplicated by using smp_dup()
568 * and it therefore uses a pre-allocated trash chunk as returned by
569 * get_trash_chunk().
570 *
571 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200572 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100573int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200574{
575 struct vars *vars;
576 struct var *var;
577 enum vars_scope scope;
578
579 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100580 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200581 if (!name)
582 return 0;
583
584 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200585 vars = get_vars(smp->sess, smp->strm, scope);
586 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200587 return 0;
588
589 /* Get the variable entry. */
Dragan Dosen14518f22021-02-22 17:20:01 +0100590 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200591 var = var_get(vars, name);
Dragan Dosen14518f22021-02-22 17:20:01 +0100592 if (!var) {
593 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200594 return 0;
Dragan Dosen14518f22021-02-22 17:20:01 +0100595 }
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200596
597 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200598 smp->data = var->data;
Dragan Dosen14518f22021-02-22 17:20:01 +0100599 smp_dup(smp);
600
601 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200602 return 1;
603}
604
Dragan Dosen14518f22021-02-22 17:20:01 +0100605/* This function fills a sample with the content of the variable described
606 * by <var_desc>.
607 *
608 * Keep in mind that a sample content is duplicated by using smp_dup()
609 * and it therefore uses a pre-allocated trash chunk as returned by
610 * get_trash_chunk().
611 *
612 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200613 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100614int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200615{
616 struct vars *vars;
617 struct var *var;
618
619 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200620 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200621
Joseph Herlant07676892018-11-15 09:19:50 -0800622 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200623 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200624 return 0;
625
626 /* Get the variable entry. */
Dragan Dosen14518f22021-02-22 17:20:01 +0100627 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200628 var = var_get(vars, var_desc->name);
Dragan Dosen14518f22021-02-22 17:20:01 +0100629 if (!var) {
630 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200631 return 0;
Dragan Dosen14518f22021-02-22 17:20:01 +0100632 }
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200633
634 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200635 smp->data = var->data;
Dragan Dosen14518f22021-02-22 17:20:01 +0100636 smp_dup(smp);
637
638 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200639 return 1;
640}
641
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200642/* Always returns ACT_RET_CONT even if an error occurs. */
643static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200644 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200645{
646 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200647 int dir;
648
649 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200650 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200651 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
652 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
653 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
654 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100655 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Willy Tarreau01d580a2021-03-26 11:11:34 +0100656 case ACT_F_CFG_PARSER: dir = SMP_OPT_DIR_REQ; break; /* not used anyway */
Willy Tarreau2f836de2021-03-26 15:36:44 +0100657 case ACT_F_CLI_PARSER: dir = SMP_OPT_DIR_REQ; break; /* not used anyway */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200658 default:
659 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
660 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100661 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200662 return ACT_RET_CONT;
663 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200664
665 /* Process the expression. */
666 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200667 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200668 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200669 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200670
671 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100672 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200673 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200674}
675
Christopher Faulet85d79c92016-11-09 16:54:56 +0100676/* Always returns ACT_RET_CONT even if an error occurs. */
677static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
678 struct session *sess, struct stream *s, int flags)
679{
680 struct sample smp;
681
682 memset(&smp, 0, sizeof(smp));
683 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
684
685 /* Clear the variable using the sample context, and ignore errors. */
686 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
687 return ACT_RET_CONT;
688}
689
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200690static void release_store_rule(struct act_rule *rule)
691{
692 release_sample_expr(rule->arg.vars.expr);
693}
694
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200695/* This two function checks the variable name and replace the
696 * configuration string name by the global string name. its
697 * the same string, but the global pointer can be easy to
698 * compare.
699 *
700 * The first function checks a sample-fetch and the second
701 * checks a converter.
702 */
703static int smp_check_var(struct arg *args, char **err)
704{
705 return vars_check_arg(&args[0], err);
706}
707
708static int conv_check_var(struct arg *args, struct sample_conv *conv,
709 const char *file, int line, char **err_msg)
710{
711 return vars_check_arg(&args[0], err_msg);
712}
713
714/* This function is a common parser for using variables. It understands
715 * the format:
716 *
717 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200718 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200719 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200720 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
721 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100722 * is filled with the pointer to the expression to execute. The proxy is
723 * only used to retrieve the ->conf entries.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200724 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200725static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
726 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200727{
728 const char *var_name = args[*arg-1];
729 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200730 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100731 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200732
Christopher Faulet85d79c92016-11-09 16:54:56 +0100733 if (!strncmp(var_name, "set-var", 7)) {
734 var_name += 7;
735 set_var = 1;
736 }
737 if (!strncmp(var_name, "unset-var", 9)) {
738 var_name += 9;
739 set_var = 0;
740 }
741
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200742 if (*var_name != '(') {
Willy Tarreau3d1d1782021-03-12 11:53:19 +0100743 memprintf(err, "invalid or incomplete action '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
Christopher Faulet85d79c92016-11-09 16:54:56 +0100744 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200745 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200746 }
747 var_name++; /* jump the '(' */
748 var_len = strlen(var_name);
749 var_len--; /* remove the ')' */
750 if (var_name[var_len] != ')') {
Willy Tarreau3d1d1782021-03-12 11:53:19 +0100751 memprintf(err, "incomplete expression after action '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
Christopher Faulet85d79c92016-11-09 16:54:56 +0100752 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200753 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200754 }
755
Christopher Faulet09c9df22016-10-31 11:05:37 +0100756 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200757 if (!rule->arg.vars.name)
758 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200759
Christopher Faulet85d79c92016-11-09 16:54:56 +0100760 /* There is no fetch method when variable is unset. Just set the right
761 * action and return. */
762 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100763 rule->action = ACT_CUSTOM;
764 rule->action_ptr = action_clear;
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200765 rule->release_ptr = release_store_rule;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100766 return ACT_RET_PRS_OK;
767 }
768
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200769 kw_name = args[*arg-1];
770
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200771 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +0100772 px->conf.args.line, err, &px->conf.args, NULL);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200773 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200774 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200775
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200776 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200777 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200778 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
779 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
780 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
781 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100782 case ACT_F_TCP_CHK: flags = SMP_VAL_BE_CHK_RUL; break;
Willy Tarreau01d580a2021-03-26 11:11:34 +0100783 case ACT_F_CFG_PARSER: flags = SMP_VAL_CFG_PARSER; break;
Willy Tarreau2f836de2021-03-26 15:36:44 +0100784 case ACT_F_CLI_PARSER: flags = SMP_VAL_CLI_PARSER; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200785 default:
786 memprintf(err,
787 "internal error, unexpected rule->from=%d, please report this bug!",
788 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200789 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200790 }
791 if (!(rule->arg.vars.expr->fetch->val & flags)) {
792 memprintf(err,
793 "fetch method '%s' extracts information from '%s', none of which is available here",
794 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
795 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200796 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200797 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200798
Thierry FOURNIER42148732015-09-02 17:17:33 +0200799 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200800 rule->action_ptr = action_store;
Tim Duesterhus01a0ce32020-06-14 17:27:36 +0200801 rule->release_ptr = release_store_rule;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200802 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200803}
804
Willy Tarreau13d2ba22021-03-26 11:38:08 +0100805
806/* parses a global "set-var" directive. It will create a temporary rule and
807 * expression that are parsed, processed, and released on the fly so that we
808 * respect the real set-var syntax. These directives take the following format:
809 * set-var <name> <expression>
810 * Note that parse_store() expects "set-var(name) <expression>" so we have to
811 * temporarily replace the keyword here.
812 */
813static int vars_parse_global_set_var(char **args, int section_type, struct proxy *curpx,
814 const struct proxy *defpx, const char *file, int line,
815 char **err)
816{
817 struct proxy px = {
818 .id = "CLI",
819 .conf.args.file = file,
820 .conf.args.line = line,
821 };
822 struct act_rule rule = {
823 .arg.vars.scope = SCOPE_PROC,
824 .from = ACT_F_CFG_PARSER,
825 };
826 enum act_parse_ret p_ret;
827 char *old_arg1;
828 char *tmp_arg1;
829 int arg = 2; // variable name
830 int ret = -1;
831
832 LIST_INIT(&px.conf.args.list);
833
834 if (!*args[1] || !*args[2]) {
835 memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a sample expression.", args[0]);
836 goto end;
837 }
838
839 tmp_arg1 = NULL;
840 if (!memprintf(&tmp_arg1, "set-var(%s)", args[1]))
841 goto end;
842
843 /* parse_store() will always return a message in <err> on error */
844 old_arg1 = args[1]; args[1] = tmp_arg1;
845 p_ret = parse_store((const char **)args, &arg, &px, &rule, err);
846 free(args[1]); args[1] = old_arg1;
847
848 if (p_ret != ACT_RET_PRS_OK)
849 goto end;
850
851 if (rule.arg.vars.scope != SCOPE_PROC) {
852 memprintf(err, "'%s': cannot set variable '%s', only scope 'proc' is permitted in the global section.", args[0], args[1]);
853 goto end;
854 }
855
856 if (smp_resolve_args(&px, err) != 0) {
857 release_sample_expr(rule.arg.vars.expr);
858 indent_msg(err, 2);
859 goto end;
860 }
861
862 action_store(&rule, &px, NULL, NULL, 0);
863 release_sample_expr(rule.arg.vars.expr);
864
865 ret = 0;
866 end:
867 return ret;
868}
869
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200870static int vars_max_size(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100871 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200872 char **err, unsigned int *limit)
873{
874 char *error;
875
876 *limit = strtol(args[1], &error, 10);
877 if (*error != 0) {
878 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
879 return -1;
880 }
881 return 0;
882}
883
884static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100885 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200886 char **err)
887{
888 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
889}
890
Christopher Fauletff2613e2016-11-09 11:36:17 +0100891static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100892 const struct proxy *defpx, const char *file, int line,
Christopher Fauletff2613e2016-11-09 11:36:17 +0100893 char **err)
894{
895 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
896}
897
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200898static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100899 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200900 char **err)
901{
902 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
903}
904
905static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100906 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200907 char **err)
908{
909 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
910}
911
912static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100913 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200914 char **err)
915{
916 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
917}
918
Gaetan Rivet13a50432020-02-21 18:13:44 +0100919static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +0100920 const struct proxy *defpx, const char *file, int line,
Gaetan Rivet13a50432020-02-21 18:13:44 +0100921 char **err)
922{
923 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
924}
925
Tim Duesterhusbbdd5b82020-07-04 11:53:25 +0200926static void vars_deinit()
927{
928 while (var_names_nb-- > 0)
929 free(var_names[var_names_nb]);
930 free(var_names);
931}
932
933REGISTER_POST_DEINIT(vars_deinit);
934
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200935static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
936
Willy Tarreau0209c972021-03-26 12:03:11 +0100937 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_CONST },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200938 { /* END */ },
939}};
940
Willy Tarreau0108d902018-11-25 19:14:37 +0100941INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
942
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200943static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100944 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
945 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200946 { /* END */ },
947}};
948
Willy Tarreau0108d902018-11-25 19:14:37 +0100949INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
950
Willy Tarreau620408f2016-10-21 16:37:51 +0200951static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100952 { "set-var", parse_store, 1 },
953 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200954 { /* END */ }
955}};
956
Willy Tarreau0108d902018-11-25 19:14:37 +0100957INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
958
Willy Tarreau620408f2016-10-21 16:37:51 +0200959static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100960 { "set-var", parse_store, 1 },
961 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200962 { /* END */ }
963}};
964
Willy Tarreau0108d902018-11-25 19:14:37 +0100965INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
966
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200967static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100968 { "set-var", parse_store, 1 },
969 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200970 { /* END */ }
971}};
972
Willy Tarreau0108d902018-11-25 19:14:37 +0100973INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
974
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100975static struct action_kw_list tcp_check_kws = {ILH, {
976 { "set-var", parse_store, 1 },
977 { "unset-var", parse_store, 1 },
978 { /* END */ }
979}};
980
981INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
982
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200983static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100984 { "set-var", parse_store, 1 },
985 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200986 { /* END */ }
987}};
988
Willy Tarreau0108d902018-11-25 19:14:37 +0100989INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
990
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200991static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100992 { "set-var", parse_store, 1 },
993 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200994 { /* END */ }
995}};
996
Willy Tarreau0108d902018-11-25 19:14:37 +0100997INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
998
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100999static struct action_kw_list http_after_res_kws = { { }, {
1000 { "set-var", parse_store, 1 },
1001 { "unset-var", parse_store, 1 },
1002 { /* END */ }
1003}};
1004
1005INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
1006
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001007static struct cfg_kw_list cfg_kws = {{ },{
Willy Tarreau13d2ba22021-03-26 11:38:08 +01001008 { CFG_GLOBAL, "set-var", vars_parse_global_set_var },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001009 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +01001010 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001011 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
1012 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
1013 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +01001014 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001015 { /* END */ }
1016}};
1017
Willy Tarreau0108d902018-11-25 19:14:37 +01001018INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);