blob: d959b5b40920a94d1803750c0a05be10ef3b5f0c [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>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020012#include <proto/proto_http.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>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020017
18/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010019DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020020
21/* This array contain all the names of all the HAProxy vars.
22 * This permits to identify two variables name with
23 * only one pointer. It permits to not using strdup() for
24 * each variable name used during the runtime.
25 */
26static char **var_names = NULL;
27static int var_names_nb = 0;
28
29/* This array of int contains the system limits per context. */
30static unsigned int var_global_limit = 0;
31static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010032static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020033static unsigned int var_sess_limit = 0;
34static unsigned int var_txn_limit = 0;
35static unsigned int var_reqres_limit = 0;
36
Willy Tarreau86abe442018-11-25 20:12:18 +010037__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020038
Willy Tarreauf37b1402019-06-04 16:27:36 +020039/* returns the struct vars pointer for a session, stream and scope, or NULL if
40 * it does not exist.
41 */
42static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
43{
44 switch (scope) {
45 case SCOPE_PROC:
46 return &global.vars;
47 case SCOPE_SESS:
48 return &sess->vars;
49 case SCOPE_TXN:
50 return strm ? &strm->vars_txn : NULL;
51 case SCOPE_REQ:
52 case SCOPE_RES:
53 default:
54 return strm ? &strm->vars_reqres : NULL;
55 }
56}
57
Willy Tarreau72330982015-06-19 11:21:56 +020058/* This function adds or remove memory size from the accounting. The inner
59 * pointers may be null when setting the outer ones only.
60 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010061static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020062{
63 switch (vars->scope) {
64 case SCOPE_REQ:
65 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020066 if (strm)
67 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010068 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020069 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020070 if (strm)
71 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010072 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020073 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010074 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010075 /* fall through */
76 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010077 _HA_ATOMIC_ADD(&global.vars.size, size);
78 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020079 }
80}
81
82/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080083 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020084 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010085 * the outer ones only. The accounting uses either <sess> or <strm>
86 * depending on the scope. <strm> may be NULL when no stream is known
87 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020088 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010089static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020090{
91 switch (vars->scope) {
92 case SCOPE_REQ:
93 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020094 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020095 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010096 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020097 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020098 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020099 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100100 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200101 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100102 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200103 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100104 /* fall through */
105 case SCOPE_PROC:
106 if (var_proc_limit && global.vars.size + size > var_proc_limit)
107 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200108 if (var_global_limit && var_global_size + size > var_global_limit)
109 return 0;
110 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100111 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112 return 1;
113}
114
Christopher Faulet85d79c92016-11-09 16:54:56 +0100115/* This fnuction remove a variable from the list and free memory it used */
116unsigned int var_clear(struct var *var)
117{
118 unsigned int size = 0;
119
120 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200121 free(var->data.u.str.area);
122 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100123 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200124 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200125 free(var->data.u.meth.str.area);
126 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100127 }
128 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100129 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100130 size += sizeof(struct var);
131 return size;
132}
133
Joseph Herlant07676892018-11-15 09:19:50 -0800134/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200135 * in the list.
136 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100137void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200138{
139 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200140 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200141
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100142 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200143 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100144 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200145 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100146 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100147 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200148}
149
Willy Tarreauebcd4842015-06-19 11:59:02 +0200150/* This function frees all the memory used by all the session variables in the
151 * list starting at <vars>.
152 */
153void vars_prune_per_sess(struct vars *vars)
154{
155 struct var *var, *tmp;
156 unsigned int size = 0;
157
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100158 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200159 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100160 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200161 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100162 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200163
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100164 _HA_ATOMIC_SUB(&vars->size, size);
165 _HA_ATOMIC_SUB(&global.vars.size, size);
166 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200167}
168
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200169/* This function init a list of variabes. */
170void vars_init(struct vars *vars, enum vars_scope scope)
171{
172 LIST_INIT(&vars->head);
173 vars->scope = scope;
174 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100175 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200176}
177
178/* This function declares a new variable name. It returns a pointer
179 * on the string identifying the name. This function assures that
180 * the same name exists only once.
181 *
182 * This function check if the variable name is acceptable.
183 *
184 * The function returns NULL if an error occurs, and <err> is filled.
185 * In this case, the HAProxy must be stopped because the structs are
186 * left inconsistent. Otherwise, it returns the pointer on the global
187 * name.
188 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100189static char *register_name(const char *name, int len, enum vars_scope *scope,
190 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200191{
192 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200193 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200194 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200195 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200196
197 /* Check length. */
198 if (len == 0) {
199 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100200 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200201 }
202
203 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100204 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
205 name += 5;
206 len -= 5;
207 *scope = SCOPE_PROC;
208 }
209 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200210 name += 5;
211 len -= 5;
212 *scope = SCOPE_SESS;
213 }
214 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
215 name += 4;
216 len -= 4;
217 *scope = SCOPE_TXN;
218 }
219 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
220 name += 4;
221 len -= 4;
222 *scope = SCOPE_REQ;
223 }
224 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
225 name += 4;
226 len -= 4;
227 *scope = SCOPE_RES;
228 }
229 else {
230 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Christopher Fauletff2613e2016-11-09 11:36:17 +0100231 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100232 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200233 }
234
Christopher Faulete95f2c32017-07-24 16:30:34 +0200235 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100236 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200237 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100238 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200239
240
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200241 /* Look for existing variable name. */
242 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200243 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
244 res = var_names[i];
245 goto end;
246 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200247
Christopher Faulete95f2c32017-07-24 16:30:34 +0200248 if (!alloc) {
249 res = NULL;
250 goto end;
251 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100252
Hubert Verstraete831962e2016-06-28 22:44:26 +0200253 /* Store variable name. If realloc fails, var_names remains valid */
254 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
255 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200256 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200257 res = NULL;
258 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200259 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200260 var_names_nb++;
261 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200262 var_names[var_names_nb - 1] = malloc(len + 1);
263 if (!var_names[var_names_nb - 1]) {
264 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200265 res = NULL;
266 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200267 }
268 memcpy(var_names[var_names_nb - 1], name, len);
269 var_names[var_names_nb - 1][len] = '\0';
270
271 /* Check variable name syntax. */
272 tmp = var_names[var_names_nb - 1];
273 while (*tmp) {
Christopher Fauletb71557a2016-10-31 10:49:03 +0100274 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200275 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200276 res = NULL;
277 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200278 }
279 tmp++;
280 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200281 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200282
Christopher Faulete95f2c32017-07-24 16:30:34 +0200283 end:
284 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100285 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200286 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100287 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200288
289 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200290}
291
292/* This function returns an existing variable or returns NULL. */
293static inline struct var *var_get(struct vars *vars, const char *name)
294{
295 struct var *var;
296
297 list_for_each_entry(var, &vars->head, l)
298 if (var->name == name)
299 return var;
300 return NULL;
301}
302
303/* Returns 0 if fails, else returns 1. */
304static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
305{
306 const struct var_desc *var_desc = &args[0].data.var;
307 struct var *var;
308 struct vars *vars;
309
310 /* Check the availibity of the variable. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200311 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
312 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200313 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200314
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100315 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200316 var = var_get(vars, var_desc->name);
317
318 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200319 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100320 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200321 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200322 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200323
Christopher Faulete95f2c32017-07-24 16:30:34 +0200324 /* Duplicate the sample data because it could modified by another
325 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200326 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200327 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200328 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200329
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100330 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200331 return 1;
332}
333
334/* This function search in the <head> a variable with the same
335 * pointer value that the <name>. If the variable doesn't exists,
336 * create it. The function stores a copy of smp> if the variable.
337 * It returns 0 if fails, else returns 1.
338 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100339static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200340{
341 struct var *var;
342
343 /* Look for existing variable name. */
344 var = var_get(vars, name);
345
346 if (var) {
347 /* free its used memory. */
348 if (var->data.type == SMP_T_STR ||
349 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200350 free(var->data.u.str.area);
351 var_accounting_diff(vars, smp->sess, smp->strm,
352 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200353 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200354 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200355 free(var->data.u.meth.str.area);
356 var_accounting_diff(vars, smp->sess, smp->strm,
357 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200358 }
359 } else {
360
Joseph Herlant07676892018-11-15 09:19:50 -0800361 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100362 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200363 return 0;
364
365 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100366 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200367 if (!var)
368 return 0;
369 LIST_ADDQ(&vars->head, &var->l);
370 var->name = name;
371 }
372
373 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200374 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200375
376 /* Copy data. If the data needs memory, the function can fail. */
377 switch (var->data.type) {
378 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200379 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200380 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200381 break;
382 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200383 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200384 break;
385 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200386 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200387 break;
388 case SMP_T_STR:
389 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200390 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200391 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
392 return 0;
393 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200394 var->data.u.str.area = malloc(smp->data.u.str.data);
395 if (!var->data.u.str.area) {
396 var_accounting_diff(vars, smp->sess, smp->strm,
397 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200398 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
399 return 0;
400 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200401 var->data.u.str.data = smp->data.u.str.data;
402 memcpy(var->data.u.str.area, smp->data.u.str.area,
403 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200404 break;
405 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200406 var->data.u.meth.meth = smp->data.u.meth.meth;
407 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
408 break;
409
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200410 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200411 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
412 return 0;
413 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200414 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
415 if (!var->data.u.meth.str.area) {
416 var_accounting_diff(vars, smp->sess, smp->strm,
417 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200418 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
419 return 0;
420 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200421 var->data.u.meth.str.data = smp->data.u.meth.str.data;
422 var->data.u.meth.str.size = smp->data.u.meth.str.data;
423 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
424 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200425 break;
426 }
427 return 1;
428}
429
Willy Tarreau620408f2016-10-21 16:37:51 +0200430/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100431static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200432{
433 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200434 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200435
Willy Tarreauf37b1402019-06-04 16:27:36 +0200436 vars = get_vars(smp->sess, smp->strm, scope);
437 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200438 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200439
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100440 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200441 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200443 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200444}
445
Christopher Faulet85d79c92016-11-09 16:54:56 +0100446/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
447static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
448{
449 struct vars *vars;
450 struct var *var;
451 unsigned int size = 0;
452
Willy Tarreauf37b1402019-06-04 16:27:36 +0200453 vars = get_vars(smp->sess, smp->strm, scope);
454 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100455 return 0;
456
457 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100458 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100459 var = var_get(vars, name);
460 if (var) {
461 size = var_clear(var);
462 var_accounting_diff(vars, smp->sess, smp->strm, -size);
463 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100464 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100465 return 1;
466}
467
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200468/* Returns 0 if fails, else returns 1. */
469static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
470{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100471 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200472}
473
Christopher Faulet85d79c92016-11-09 16:54:56 +0100474/* Returns 0 if fails, else returns 1. */
475static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
476{
477 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
478}
479
Joseph Herlant07676892018-11-15 09:19:50 -0800480/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200481 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800482 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200483 */
484int vars_check_arg(struct arg *arg, char **err)
485{
486 char *name;
487 enum vars_scope scope;
488
489 /* Check arg type. */
490 if (arg->type != ARGT_STR) {
491 memprintf(err, "unexpected argument type");
492 return 0;
493 }
494
495 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200496 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
497 1,
498 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200499 if (!name)
500 return 0;
501
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200502 /* properly destroy the chunk */
503 chunk_destroy(&arg->data.str);
504
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200505 /* Use the global variable name pointer. */
506 arg->type = ARGT_VAR;
507 arg->data.var.name = name;
508 arg->data.var.scope = scope;
509 return 1;
510}
511
Christopher Faulet09c9df22016-10-31 11:05:37 +0100512/* This function store a sample in a variable if it was already defined.
513 * In error case, it fails silently.
514 */
515void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
516{
517 enum vars_scope scope;
518
519 /* Resolve name and scope. */
520 name = register_name(name, len, &scope, 0, NULL);
521 if (!name)
522 return;
523
524 sample_store_stream(name, scope, smp);
525}
526
527
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200528/* This function store a sample in a variable.
529 * In error case, it fails silently.
530 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100531void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200532{
533 enum vars_scope scope;
534
535 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100536 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200537 if (!name)
538 return;
539
Willy Tarreau6204cd92016-03-10 16:33:04 +0100540 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200541}
542
Christopher Faulet85d79c92016-11-09 16:54:56 +0100543/* This function unset a variable if it was already defined.
544 * In error case, it fails silently.
545 */
546void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
547{
548 enum vars_scope scope;
549
550 /* Resolve name and scope. */
551 name = register_name(name, len, &scope, 0, NULL);
552 if (!name)
553 return;
554
555 sample_clear_stream(name, scope, smp);
556}
557
558
559/* This function unset a variable.
560 * In error case, it fails silently.
561 */
562void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
563{
564 enum vars_scope scope;
565
566 /* Resolve name and scope. */
567 name = register_name(name, len, &scope, 1, NULL);
568 if (!name)
569 return;
570
571 sample_clear_stream(name, scope, smp);
572}
573
Dragan Dosene980ca92021-02-22 17:20:01 +0100574/* This function fills a sample with the variable content.
575 *
576 * Keep in mind that a sample content is duplicated by using smp_dup()
577 * and it therefore uses a pre-allocated trash chunk as returned by
578 * get_trash_chunk().
579 *
580 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200581 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100582int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200583{
584 struct vars *vars;
585 struct var *var;
586 enum vars_scope scope;
587
588 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100589 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200590 if (!name)
591 return 0;
592
593 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200594 vars = get_vars(smp->sess, smp->strm, scope);
595 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200596 return 0;
597
598 /* Get the variable entry. */
Dragan Dosene980ca92021-02-22 17:20:01 +0100599 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200600 var = var_get(vars, name);
Dragan Dosene980ca92021-02-22 17:20:01 +0100601 if (!var) {
602 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200603 return 0;
Dragan Dosene980ca92021-02-22 17:20:01 +0100604 }
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200605
606 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200607 smp->data = var->data;
Dragan Dosene980ca92021-02-22 17:20:01 +0100608 smp_dup(smp);
609
610 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200611 return 1;
612}
613
Dragan Dosene980ca92021-02-22 17:20:01 +0100614/* This function fills a sample with the content of the variable described
615 * by <var_desc>.
616 *
617 * Keep in mind that a sample content is duplicated by using smp_dup()
618 * and it therefore uses a pre-allocated trash chunk as returned by
619 * get_trash_chunk().
620 *
621 * Returns 1 if the sample is filled, otherwise it returns 0.
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200622 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100623int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200624{
625 struct vars *vars;
626 struct var *var;
627
628 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200629 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200630
Joseph Herlant07676892018-11-15 09:19:50 -0800631 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200632 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200633 return 0;
634
635 /* Get the variable entry. */
Dragan Dosene980ca92021-02-22 17:20:01 +0100636 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200637 var = var_get(vars, var_desc->name);
Dragan Dosene980ca92021-02-22 17:20:01 +0100638 if (!var) {
639 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200640 return 0;
Dragan Dosene980ca92021-02-22 17:20:01 +0100641 }
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200642
643 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200644 smp->data = var->data;
Dragan Dosene980ca92021-02-22 17:20:01 +0100645 smp_dup(smp);
646
647 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200648 return 1;
649}
650
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200651/* Always returns ACT_RET_CONT even if an error occurs. */
652static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200653 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200654{
655 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200656 int dir;
657
658 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200659 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200660 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
661 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
662 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
663 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
664 default:
665 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
666 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100667 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200668 return ACT_RET_CONT;
669 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200670
671 /* Process the expression. */
672 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200673 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200674 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200675 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200676
677 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100678 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200679 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200680}
681
Christopher Faulet85d79c92016-11-09 16:54:56 +0100682/* Always returns ACT_RET_CONT even if an error occurs. */
683static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
684 struct session *sess, struct stream *s, int flags)
685{
686 struct sample smp;
687
688 memset(&smp, 0, sizeof(smp));
689 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
690
691 /* Clear the variable using the sample context, and ignore errors. */
692 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
693 return ACT_RET_CONT;
694}
695
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200696/* This two function checks the variable name and replace the
697 * configuration string name by the global string name. its
698 * the same string, but the global pointer can be easy to
699 * compare.
700 *
701 * The first function checks a sample-fetch and the second
702 * checks a converter.
703 */
704static int smp_check_var(struct arg *args, char **err)
705{
706 return vars_check_arg(&args[0], err);
707}
708
709static int conv_check_var(struct arg *args, struct sample_conv *conv,
710 const char *file, int line, char **err_msg)
711{
712 return vars_check_arg(&args[0], err_msg);
713}
714
715/* This function is a common parser for using variables. It understands
716 * the format:
717 *
718 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200719 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200720 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200721 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
722 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
723 * is filled with the pointer to the expression to execute.
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 != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100743 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
744 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] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100751 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
752 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;
765 return ACT_RET_PRS_OK;
766 }
767
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200768 kw_name = args[*arg-1];
769
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200770 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
771 px->conf.args.line, err, &px->conf.args);
772 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200773 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200774
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200775 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200776 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200777 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
778 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
779 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
780 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
781 default:
782 memprintf(err,
783 "internal error, unexpected rule->from=%d, please report this bug!",
784 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200785 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200786 }
787 if (!(rule->arg.vars.expr->fetch->val & flags)) {
788 memprintf(err,
789 "fetch method '%s' extracts information from '%s', none of which is available here",
790 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
791 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200792 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200793 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200794
Thierry FOURNIER42148732015-09-02 17:17:33 +0200795 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200796 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200797 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200798}
799
800static int vars_max_size(char **args, int section_type, struct proxy *curpx,
801 struct proxy *defpx, const char *file, int line,
802 char **err, unsigned int *limit)
803{
804 char *error;
805
806 *limit = strtol(args[1], &error, 10);
807 if (*error != 0) {
808 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
809 return -1;
810 }
811 return 0;
812}
813
814static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
815 struct proxy *defpx, const char *file, int line,
816 char **err)
817{
818 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
819}
820
Christopher Fauletff2613e2016-11-09 11:36:17 +0100821static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
822 struct proxy *defpx, const char *file, int line,
823 char **err)
824{
825 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
826}
827
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200828static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
829 struct proxy *defpx, const char *file, int line,
830 char **err)
831{
832 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
833}
834
835static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
836 struct proxy *defpx, const char *file, int line,
837 char **err)
838{
839 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
840}
841
842static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
843 struct proxy *defpx, const char *file, int line,
844 char **err)
845{
846 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
847}
848
849static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
850
Christopher Fauletff2613e2016-11-09 11:36:17 +0100851 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200852 { /* END */ },
853}};
854
Willy Tarreau0108d902018-11-25 19:14:37 +0100855INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
856
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200857static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100858 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
859 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200860 { /* END */ },
861}};
862
Willy Tarreau0108d902018-11-25 19:14:37 +0100863INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
864
Willy Tarreau620408f2016-10-21 16:37:51 +0200865static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100866 { "set-var", parse_store, 1 },
867 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200868 { /* END */ }
869}};
870
Willy Tarreau0108d902018-11-25 19:14:37 +0100871INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
872
Willy Tarreau620408f2016-10-21 16:37:51 +0200873static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100874 { "set-var", parse_store, 1 },
875 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200876 { /* END */ }
877}};
878
Willy Tarreau0108d902018-11-25 19:14:37 +0100879INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
880
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200881static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100882 { "set-var", parse_store, 1 },
883 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200884 { /* END */ }
885}};
886
Willy Tarreau0108d902018-11-25 19:14:37 +0100887INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
888
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200889static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100890 { "set-var", parse_store, 1 },
891 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200892 { /* END */ }
893}};
894
Willy Tarreau0108d902018-11-25 19:14:37 +0100895INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
896
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200897static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100898 { "set-var", parse_store, 1 },
899 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200900 { /* END */ }
901}};
902
Willy Tarreau0108d902018-11-25 19:14:37 +0100903INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
904
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200905static struct cfg_kw_list cfg_kws = {{ },{
906 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100907 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200908 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
909 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
910 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
911 { /* END */ }
912}};
913
Willy Tarreau0108d902018-11-25 19:14:37 +0100914INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);