blob: 0fa3397c761eb8dad6423b7496850564434bf4db [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#include <ctype.h>
2
3#include <common/cfgparse.h>
Willy Tarreau35b51c62018-09-10 15:38:55 +02004#include <common/http.h>
Willy Tarreau0108d902018-11-25 19:14:37 +01005#include <common/initcall.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02006#include <common/mini-clist.h>
7
8#include <types/vars.h>
9
10#include <proto/arg.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020011#include <proto/http_rules.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020012#include <proto/http_ana.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020013#include <proto/sample.h>
14#include <proto/stream.h>
Willy Tarreau39713102016-11-25 15:49:32 +010015#include <proto/tcp_rules.h>
Willy Tarreauebcd4842015-06-19 11:59:02 +020016#include <proto/vars.h>
Gaetan Rivet13a50432020-02-21 18:13:44 +010017#include <proto/checks.h>
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:
50 return &sess->vars;
Gaetan Rivet13a50432020-02-21 18:13:44 +010051 case SCOPE_CHECK: {
52 struct server *srv = objt_server(sess->origin);
53
54 return srv ? &srv->check.vars : NULL;
55 }
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 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010068static void 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: {
81 struct server *srv = objt_server(sess->origin);
82
83 if (srv != NULL)
84 _HA_ATOMIC_ADD(&srv->check.vars.size, size);
85 }
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: {
117 struct server *srv = objt_server(sess->origin);
118
119 if (var_check_limit && srv &&
120 srv->check.vars.size + size > var_check_limit)
121 return 0;
122 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100123 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100124scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200125 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100126 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200127 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100128 /* fall through */
129 case SCOPE_PROC:
130 if (var_proc_limit && global.vars.size + size > var_proc_limit)
131 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200132 if (var_global_limit && var_global_size + size > var_global_limit)
133 return 0;
134 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100135 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200136 return 1;
137}
138
Christopher Faulet85d79c92016-11-09 16:54:56 +0100139/* This fnuction remove a variable from the list and free memory it used */
140unsigned int var_clear(struct var *var)
141{
142 unsigned int size = 0;
143
144 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200145 free(var->data.u.str.area);
146 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100147 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200148 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200149 free(var->data.u.meth.str.area);
150 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100151 }
152 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100153 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100154 size += sizeof(struct var);
155 return size;
156}
157
Joseph Herlant07676892018-11-15 09:19:50 -0800158/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200159 * in the list.
160 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100161void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200162{
163 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200164 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200165
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100166 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200167 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100168 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200169 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100170 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100171 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200172}
173
Willy Tarreauebcd4842015-06-19 11:59:02 +0200174/* This function frees all the memory used by all the session variables in the
175 * list starting at <vars>.
176 */
177void vars_prune_per_sess(struct vars *vars)
178{
179 struct var *var, *tmp;
180 unsigned int size = 0;
181
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100182 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200183 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100184 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200185 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100186 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200187
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100188 _HA_ATOMIC_SUB(&vars->size, size);
189 _HA_ATOMIC_SUB(&global.vars.size, size);
190 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200191}
192
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200193/* This function init a list of variabes. */
194void vars_init(struct vars *vars, enum vars_scope scope)
195{
196 LIST_INIT(&vars->head);
197 vars->scope = scope;
198 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100199 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200200}
201
202/* This function declares a new variable name. It returns a pointer
203 * on the string identifying the name. This function assures that
204 * the same name exists only once.
205 *
206 * This function check if the variable name is acceptable.
207 *
208 * The function returns NULL if an error occurs, and <err> is filled.
209 * In this case, the HAProxy must be stopped because the structs are
210 * left inconsistent. Otherwise, it returns the pointer on the global
211 * name.
212 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100213static char *register_name(const char *name, int len, enum vars_scope *scope,
214 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200215{
216 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200217 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200218 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200219 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200220
221 /* Check length. */
222 if (len == 0) {
223 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100224 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200225 }
226
227 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100228 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
229 name += 5;
230 len -= 5;
231 *scope = SCOPE_PROC;
232 }
233 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200234 name += 5;
235 len -= 5;
236 *scope = SCOPE_SESS;
237 }
238 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
239 name += 4;
240 len -= 4;
241 *scope = SCOPE_TXN;
242 }
243 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
244 name += 4;
245 len -= 4;
246 *scope = SCOPE_REQ;
247 }
248 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
249 name += 4;
250 len -= 4;
251 *scope = SCOPE_RES;
252 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100253 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
254 name += 6;
255 len -= 6;
256 *scope = SCOPE_CHECK;
257 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200258 else {
259 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Gaetan Rivet13a50432020-02-21 18:13:44 +0100260 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100261 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200262 }
263
Christopher Faulete95f2c32017-07-24 16:30:34 +0200264 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100265 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200266 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100267 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200268
269
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200270 /* Look for existing variable name. */
271 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200272 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
273 res = var_names[i];
274 goto end;
275 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200276
Christopher Faulete95f2c32017-07-24 16:30:34 +0200277 if (!alloc) {
278 res = NULL;
279 goto end;
280 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100281
Hubert Verstraete831962e2016-06-28 22:44:26 +0200282 /* Store variable name. If realloc fails, var_names remains valid */
283 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
284 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200285 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200286 res = NULL;
287 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200288 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200289 var_names_nb++;
290 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200291 var_names[var_names_nb - 1] = malloc(len + 1);
292 if (!var_names[var_names_nb - 1]) {
293 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200294 res = NULL;
295 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200296 }
297 memcpy(var_names[var_names_nb - 1], name, len);
298 var_names[var_names_nb - 1][len] = '\0';
299
300 /* Check variable name syntax. */
301 tmp = var_names[var_names_nb - 1];
302 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100303 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200304 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200305 res = NULL;
306 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200307 }
308 tmp++;
309 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200310 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200311
Christopher Faulete95f2c32017-07-24 16:30:34 +0200312 end:
313 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100314 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200315 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100316 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200317
318 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200319}
320
321/* This function returns an existing variable or returns NULL. */
322static inline struct var *var_get(struct vars *vars, const char *name)
323{
324 struct var *var;
325
326 list_for_each_entry(var, &vars->head, l)
327 if (var->name == name)
328 return var;
329 return NULL;
330}
331
332/* Returns 0 if fails, else returns 1. */
333static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
334{
335 const struct var_desc *var_desc = &args[0].data.var;
336 struct var *var;
337 struct vars *vars;
338
339 /* Check the availibity of the variable. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200340 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
341 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200342 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200343
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100344 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200345 var = var_get(vars, var_desc->name);
346
347 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200348 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100349 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200350 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200351 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200352
Christopher Faulete95f2c32017-07-24 16:30:34 +0200353 /* Duplicate the sample data because it could modified by another
354 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200355 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200356 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200357 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200358
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100359 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200360 return 1;
361}
362
363/* This function search in the <head> a variable with the same
364 * pointer value that the <name>. If the variable doesn't exists,
365 * create it. The function stores a copy of smp> if the variable.
366 * It returns 0 if fails, else returns 1.
367 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100368static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200369{
370 struct var *var;
371
372 /* Look for existing variable name. */
373 var = var_get(vars, name);
374
375 if (var) {
376 /* free its used memory. */
377 if (var->data.type == SMP_T_STR ||
378 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200379 free(var->data.u.str.area);
380 var_accounting_diff(vars, smp->sess, smp->strm,
381 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200382 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200383 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200384 free(var->data.u.meth.str.area);
385 var_accounting_diff(vars, smp->sess, smp->strm,
386 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200387 }
388 } else {
389
Joseph Herlant07676892018-11-15 09:19:50 -0800390 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100391 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200392 return 0;
393
394 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100395 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200396 if (!var)
397 return 0;
398 LIST_ADDQ(&vars->head, &var->l);
399 var->name = name;
400 }
401
402 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200403 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200404
405 /* Copy data. If the data needs memory, the function can fail. */
406 switch (var->data.type) {
407 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200408 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200409 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200410 break;
411 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200412 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200413 break;
414 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200415 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200416 break;
417 case SMP_T_STR:
418 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200419 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200420 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
421 return 0;
422 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200423 var->data.u.str.area = malloc(smp->data.u.str.data);
424 if (!var->data.u.str.area) {
425 var_accounting_diff(vars, smp->sess, smp->strm,
426 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200427 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
428 return 0;
429 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200430 var->data.u.str.data = smp->data.u.str.data;
431 memcpy(var->data.u.str.area, smp->data.u.str.area,
432 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200433 break;
434 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200435 var->data.u.meth.meth = smp->data.u.meth.meth;
436 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
437 break;
438
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200439 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200440 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
441 return 0;
442 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200443 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
444 if (!var->data.u.meth.str.area) {
445 var_accounting_diff(vars, smp->sess, smp->strm,
446 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200447 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
448 return 0;
449 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200450 var->data.u.meth.str.data = smp->data.u.meth.str.data;
451 var->data.u.meth.str.size = smp->data.u.meth.str.data;
452 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
453 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200454 break;
455 }
456 return 1;
457}
458
Willy Tarreau620408f2016-10-21 16:37:51 +0200459/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100460static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200461{
462 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200463 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200464
Willy Tarreauf37b1402019-06-04 16:27:36 +0200465 vars = get_vars(smp->sess, smp->strm, scope);
466 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200467 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200468
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200470 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100471 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200472 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200473}
474
Christopher Faulet85d79c92016-11-09 16:54:56 +0100475/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
476static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
477{
478 struct vars *vars;
479 struct var *var;
480 unsigned int size = 0;
481
Willy Tarreauf37b1402019-06-04 16:27:36 +0200482 vars = get_vars(smp->sess, smp->strm, scope);
483 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100484 return 0;
485
486 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100487 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100488 var = var_get(vars, name);
489 if (var) {
490 size = var_clear(var);
491 var_accounting_diff(vars, smp->sess, smp->strm, -size);
492 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100493 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100494 return 1;
495}
496
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200497/* Returns 0 if fails, else returns 1. */
498static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
499{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100500 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200501}
502
Christopher Faulet85d79c92016-11-09 16:54:56 +0100503/* Returns 0 if fails, else returns 1. */
504static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
505{
506 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
507}
508
Joseph Herlant07676892018-11-15 09:19:50 -0800509/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200510 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800511 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200512 */
513int vars_check_arg(struct arg *arg, char **err)
514{
515 char *name;
516 enum vars_scope scope;
517
518 /* Check arg type. */
519 if (arg->type != ARGT_STR) {
520 memprintf(err, "unexpected argument type");
521 return 0;
522 }
523
524 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200525 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
526 1,
527 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200528 if (!name)
529 return 0;
530
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200531 /* properly destroy the chunk */
532 chunk_destroy(&arg->data.str);
533
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200534 /* Use the global variable name pointer. */
535 arg->type = ARGT_VAR;
536 arg->data.var.name = name;
537 arg->data.var.scope = scope;
538 return 1;
539}
540
Christopher Faulet09c9df22016-10-31 11:05:37 +0100541/* This function store a sample in a variable if it was already defined.
542 * In error case, it fails silently.
543 */
544void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
545{
546 enum vars_scope scope;
547
548 /* Resolve name and scope. */
549 name = register_name(name, len, &scope, 0, NULL);
550 if (!name)
551 return;
552
553 sample_store_stream(name, scope, smp);
554}
555
556
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200557/* This function store a sample in a variable.
558 * In error case, it fails silently.
559 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100560void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200561{
562 enum vars_scope scope;
563
564 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100565 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200566 if (!name)
567 return;
568
Willy Tarreau6204cd92016-03-10 16:33:04 +0100569 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200570}
571
Christopher Faulet85d79c92016-11-09 16:54:56 +0100572/* This function unset a variable if it was already defined.
573 * In error case, it fails silently.
574 */
575void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
576{
577 enum vars_scope scope;
578
579 /* Resolve name and scope. */
580 name = register_name(name, len, &scope, 0, NULL);
581 if (!name)
582 return;
583
584 sample_clear_stream(name, scope, smp);
585}
586
587
588/* This function unset a variable.
589 * In error case, it fails silently.
590 */
591void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
592{
593 enum vars_scope scope;
594
595 /* Resolve name and scope. */
596 name = register_name(name, len, &scope, 1, NULL);
597 if (!name)
598 return;
599
600 sample_clear_stream(name, scope, smp);
601}
602
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200603/* this function fills a sample with the
604 * variable content. Returns 1 if the sample
605 * is filled, otherwise it returns 0.
606 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100607int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200608{
609 struct vars *vars;
610 struct var *var;
611 enum vars_scope scope;
612
613 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100614 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200615 if (!name)
616 return 0;
617
618 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200619 vars = get_vars(smp->sess, smp->strm, scope);
620 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200621 return 0;
622
623 /* Get the variable entry. */
624 var = var_get(vars, name);
625 if (!var)
626 return 0;
627
628 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200629 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200630 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200631 return 1;
632}
633
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200634/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800635 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200636 * if the sample is filled, otherwise it returns 0.
637 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100638int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200639{
640 struct vars *vars;
641 struct var *var;
642
643 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200644 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200645
Joseph Herlant07676892018-11-15 09:19:50 -0800646 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200647 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200648 return 0;
649
650 /* Get the variable entry. */
651 var = var_get(vars, var_desc->name);
652 if (!var)
653 return 0;
654
655 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200656 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200657 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200658 return 1;
659}
660
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200661/* Always returns ACT_RET_CONT even if an error occurs. */
662static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200663 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200664{
665 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200666 int dir;
667
668 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200669 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200670 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
671 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
672 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
673 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100674 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200675 default:
676 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
677 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100678 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200679 return ACT_RET_CONT;
680 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200681
682 /* Process the expression. */
683 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200684 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200685 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200686 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200687
688 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100689 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200690 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200691}
692
Christopher Faulet85d79c92016-11-09 16:54:56 +0100693/* Always returns ACT_RET_CONT even if an error occurs. */
694static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
695 struct session *sess, struct stream *s, int flags)
696{
697 struct sample smp;
698
699 memset(&smp, 0, sizeof(smp));
700 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
701
702 /* Clear the variable using the sample context, and ignore errors. */
703 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
704 return ACT_RET_CONT;
705}
706
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200707/* This two function checks the variable name and replace the
708 * configuration string name by the global string name. its
709 * the same string, but the global pointer can be easy to
710 * compare.
711 *
712 * The first function checks a sample-fetch and the second
713 * checks a converter.
714 */
715static int smp_check_var(struct arg *args, char **err)
716{
717 return vars_check_arg(&args[0], err);
718}
719
720static int conv_check_var(struct arg *args, struct sample_conv *conv,
721 const char *file, int line, char **err_msg)
722{
723 return vars_check_arg(&args[0], err_msg);
724}
725
726/* This function is a common parser for using variables. It understands
727 * the format:
728 *
729 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200730 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200731 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200732 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
733 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
734 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200735 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200736static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
737 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200738{
739 const char *var_name = args[*arg-1];
740 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200741 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100742 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200743
Christopher Faulet85d79c92016-11-09 16:54:56 +0100744 if (!strncmp(var_name, "set-var", 7)) {
745 var_name += 7;
746 set_var = 1;
747 }
748 if (!strncmp(var_name, "unset-var", 9)) {
749 var_name += 9;
750 set_var = 0;
751 }
752
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200753 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100754 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
755 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200756 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200757 }
758 var_name++; /* jump the '(' */
759 var_len = strlen(var_name);
760 var_len--; /* remove the ')' */
761 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100762 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
763 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200764 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200765 }
766
Christopher Faulet09c9df22016-10-31 11:05:37 +0100767 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200768 if (!rule->arg.vars.name)
769 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200770
Christopher Faulet85d79c92016-11-09 16:54:56 +0100771 /* There is no fetch method when variable is unset. Just set the right
772 * action and return. */
773 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100774 rule->action = ACT_CUSTOM;
775 rule->action_ptr = action_clear;
776 return ACT_RET_PRS_OK;
777 }
778
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200779 kw_name = args[*arg-1];
780
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200781 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +0100782 px->conf.args.line, err, &px->conf.args, NULL);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200783 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200784 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200785
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200786 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200787 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200788 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
789 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
790 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
791 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100792 case ACT_F_TCP_CHK: flags = SMP_VAL_BE_CHK_RUL; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200793 default:
794 memprintf(err,
795 "internal error, unexpected rule->from=%d, please report this bug!",
796 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200797 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200798 }
799 if (!(rule->arg.vars.expr->fetch->val & flags)) {
800 memprintf(err,
801 "fetch method '%s' extracts information from '%s', none of which is available here",
802 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
803 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200804 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200805 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200806
Thierry FOURNIER42148732015-09-02 17:17:33 +0200807 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200808 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200809 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200810}
811
812static int vars_max_size(char **args, int section_type, struct proxy *curpx,
813 struct proxy *defpx, const char *file, int line,
814 char **err, unsigned int *limit)
815{
816 char *error;
817
818 *limit = strtol(args[1], &error, 10);
819 if (*error != 0) {
820 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
821 return -1;
822 }
823 return 0;
824}
825
826static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
827 struct proxy *defpx, const char *file, int line,
828 char **err)
829{
830 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
831}
832
Christopher Fauletff2613e2016-11-09 11:36:17 +0100833static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
834 struct proxy *defpx, const char *file, int line,
835 char **err)
836{
837 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
838}
839
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200840static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
841 struct proxy *defpx, const char *file, int line,
842 char **err)
843{
844 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
845}
846
847static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
848 struct proxy *defpx, const char *file, int line,
849 char **err)
850{
851 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
852}
853
854static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
855 struct proxy *defpx, const char *file, int line,
856 char **err)
857{
858 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
859}
860
Gaetan Rivet13a50432020-02-21 18:13:44 +0100861static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
862 struct proxy *defpx, const char *file, int line,
863 char **err)
864{
865 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
866}
867
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200868static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
869
Christopher Fauletff2613e2016-11-09 11:36:17 +0100870 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200871 { /* END */ },
872}};
873
Willy Tarreau0108d902018-11-25 19:14:37 +0100874INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
875
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200876static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100877 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
878 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200879 { /* END */ },
880}};
881
Willy Tarreau0108d902018-11-25 19:14:37 +0100882INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
883
Willy Tarreau620408f2016-10-21 16:37:51 +0200884static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100885 { "set-var", parse_store, 1 },
886 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200887 { /* END */ }
888}};
889
Willy Tarreau0108d902018-11-25 19:14:37 +0100890INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
891
Willy Tarreau620408f2016-10-21 16:37:51 +0200892static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100893 { "set-var", parse_store, 1 },
894 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200895 { /* END */ }
896}};
897
Willy Tarreau0108d902018-11-25 19:14:37 +0100898INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
899
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200900static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100901 { "set-var", parse_store, 1 },
902 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200903 { /* END */ }
904}};
905
Willy Tarreau0108d902018-11-25 19:14:37 +0100906INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
907
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100908static struct action_kw_list tcp_check_kws = {ILH, {
909 { "set-var", parse_store, 1 },
910 { "unset-var", parse_store, 1 },
911 { /* END */ }
912}};
913
914INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
915
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200916static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100917 { "set-var", parse_store, 1 },
918 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200919 { /* END */ }
920}};
921
Willy Tarreau0108d902018-11-25 19:14:37 +0100922INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
923
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200924static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100925 { "set-var", parse_store, 1 },
926 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200927 { /* END */ }
928}};
929
Willy Tarreau0108d902018-11-25 19:14:37 +0100930INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
931
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100932static struct action_kw_list http_after_res_kws = { { }, {
933 { "set-var", parse_store, 1 },
934 { "unset-var", parse_store, 1 },
935 { /* END */ }
936}};
937
938INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
939
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200940static struct cfg_kw_list cfg_kws = {{ },{
941 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100942 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200943 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
944 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
945 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +0100946 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200947 { /* END */ }
948}};
949
Willy Tarreau0108d902018-11-25 19:14:37 +0100950INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);