blob: 905e20c4f2eeb6efd85db2f909aec491b2a5d31a [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>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02005#include <common/mini-clist.h>
6
7#include <types/vars.h>
8
9#include <proto/arg.h>
10#include <proto/proto_http.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020011#include <proto/sample.h>
12#include <proto/stream.h>
Willy Tarreau39713102016-11-25 15:49:32 +010013#include <proto/tcp_rules.h>
Willy Tarreauebcd4842015-06-19 11:59:02 +020014#include <proto/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020015
16/* This contains a pool of struct vars */
17static struct pool_head *var_pool = NULL;
18
19/* This array contain all the names of all the HAProxy vars.
20 * This permits to identify two variables name with
21 * only one pointer. It permits to not using strdup() for
22 * each variable name used during the runtime.
23 */
24static char **var_names = NULL;
25static int var_names_nb = 0;
26
27/* This array of int contains the system limits per context. */
28static unsigned int var_global_limit = 0;
29static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010030static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020031static unsigned int var_sess_limit = 0;
32static unsigned int var_txn_limit = 0;
33static unsigned int var_reqres_limit = 0;
34
Christopher Faulete95f2c32017-07-24 16:30:34 +020035
Christopher Faulet9dcf9b62017-11-13 10:34:01 +010036__decl_hathreads(HA_RWLOCK_T var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020037
Willy Tarreau72330982015-06-19 11:21:56 +020038/* This function adds or remove memory size from the accounting. The inner
39 * pointers may be null when setting the outer ones only.
40 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010041static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020042{
43 switch (vars->scope) {
44 case SCOPE_REQ:
45 case SCOPE_RES:
Christopher Faulete95f2c32017-07-24 16:30:34 +020046 HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010047 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020048 case SCOPE_TXN:
Christopher Faulete95f2c32017-07-24 16:30:34 +020049 HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010050 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020051 case SCOPE_SESS:
Christopher Faulete95f2c32017-07-24 16:30:34 +020052 HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010053 /* fall through */
54 case SCOPE_PROC:
Christopher Faulete95f2c32017-07-24 16:30:34 +020055 HA_ATOMIC_ADD(&global.vars.size, size);
56 HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020057 }
58}
59
60/* This function returns 1 if the <size> is available in the var
61 * pool <vars>, otherwise returns 0. If the space is avalaible,
Willy Tarreau72330982015-06-19 11:21:56 +020062 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010063 * the outer ones only. The accounting uses either <sess> or <strm>
64 * depending on the scope. <strm> may be NULL when no stream is known
65 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020066 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010067static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020068{
69 switch (vars->scope) {
70 case SCOPE_REQ:
71 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010072 if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020073 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010074 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020075 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010076 if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020077 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010078 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020079 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010080 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020081 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010082 /* fall through */
83 case SCOPE_PROC:
84 if (var_proc_limit && global.vars.size + size > var_proc_limit)
85 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020086 if (var_global_limit && var_global_size + size > var_global_limit)
87 return 0;
88 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010089 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020090 return 1;
91}
92
Christopher Faulet85d79c92016-11-09 16:54:56 +010093/* This fnuction remove a variable from the list and free memory it used */
94unsigned int var_clear(struct var *var)
95{
96 unsigned int size = 0;
97
98 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020099 free(var->data.u.str.area);
100 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100101 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200102 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200103 free(var->data.u.meth.str.area);
104 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100105 }
106 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100107 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100108 size += sizeof(struct var);
109 return size;
110}
111
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112/* This function free all the memory used by all the varaibles
113 * in the list.
114 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100115void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200116{
117 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200118 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200119
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100120 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200121 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100122 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200123 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100124 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100125 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200126}
127
Willy Tarreauebcd4842015-06-19 11:59:02 +0200128/* This function frees all the memory used by all the session variables in the
129 * list starting at <vars>.
130 */
131void vars_prune_per_sess(struct vars *vars)
132{
133 struct var *var, *tmp;
134 unsigned int size = 0;
135
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100136 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200137 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100138 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200139 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100140 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200141
142 HA_ATOMIC_SUB(&vars->size, size);
143 HA_ATOMIC_SUB(&global.vars.size, size);
144 HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200145}
146
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200147/* This function init a list of variabes. */
148void vars_init(struct vars *vars, enum vars_scope scope)
149{
150 LIST_INIT(&vars->head);
151 vars->scope = scope;
152 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100153 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200154}
155
156/* This function declares a new variable name. It returns a pointer
157 * on the string identifying the name. This function assures that
158 * the same name exists only once.
159 *
160 * This function check if the variable name is acceptable.
161 *
162 * The function returns NULL if an error occurs, and <err> is filled.
163 * In this case, the HAProxy must be stopped because the structs are
164 * left inconsistent. Otherwise, it returns the pointer on the global
165 * name.
166 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100167static char *register_name(const char *name, int len, enum vars_scope *scope,
168 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200169{
170 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200171 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200172 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200173 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200174
175 /* Check length. */
176 if (len == 0) {
177 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100178 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200179 }
180
181 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100182 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
183 name += 5;
184 len -= 5;
185 *scope = SCOPE_PROC;
186 }
187 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200188 name += 5;
189 len -= 5;
190 *scope = SCOPE_SESS;
191 }
192 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
193 name += 4;
194 len -= 4;
195 *scope = SCOPE_TXN;
196 }
197 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
198 name += 4;
199 len -= 4;
200 *scope = SCOPE_REQ;
201 }
202 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
203 name += 4;
204 len -= 4;
205 *scope = SCOPE_RES;
206 }
207 else {
208 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Christopher Fauletff2613e2016-11-09 11:36:17 +0100209 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100210 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200211 }
212
Christopher Faulete95f2c32017-07-24 16:30:34 +0200213 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100214 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200215 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100216 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200217
218
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200219 /* Look for existing variable name. */
220 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200221 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
222 res = var_names[i];
223 goto end;
224 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200225
Christopher Faulete95f2c32017-07-24 16:30:34 +0200226 if (!alloc) {
227 res = NULL;
228 goto end;
229 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100230
Hubert Verstraete831962e2016-06-28 22:44:26 +0200231 /* Store variable name. If realloc fails, var_names remains valid */
232 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
233 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200234 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200235 res = NULL;
236 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200237 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200238 var_names_nb++;
239 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200240 var_names[var_names_nb - 1] = malloc(len + 1);
241 if (!var_names[var_names_nb - 1]) {
242 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200243 res = NULL;
244 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200245 }
246 memcpy(var_names[var_names_nb - 1], name, len);
247 var_names[var_names_nb - 1][len] = '\0';
248
249 /* Check variable name syntax. */
250 tmp = var_names[var_names_nb - 1];
251 while (*tmp) {
Christopher Fauletb71557a2016-10-31 10:49:03 +0100252 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200253 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200254 res = NULL;
255 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200256 }
257 tmp++;
258 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200259 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200260
Christopher Faulete95f2c32017-07-24 16:30:34 +0200261 end:
262 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100263 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200264 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100265 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200266
267 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200268}
269
270/* This function returns an existing variable or returns NULL. */
271static inline struct var *var_get(struct vars *vars, const char *name)
272{
273 struct var *var;
274
275 list_for_each_entry(var, &vars->head, l)
276 if (var->name == name)
277 return var;
278 return NULL;
279}
280
281/* Returns 0 if fails, else returns 1. */
282static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
283{
284 const struct var_desc *var_desc = &args[0].data.var;
285 struct var *var;
286 struct vars *vars;
287
288 /* Check the availibity of the variable. */
289 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100290 case SCOPE_PROC:
291 vars = &global.vars;
292 break;
Willy Tarreau7513d002016-10-21 17:14:35 +0200293 case SCOPE_SESS:
294 vars = &smp->sess->vars;
295 break;
296 case SCOPE_TXN:
297 if (!smp->strm)
298 return 0;
299 vars = &smp->strm->vars_txn;
300 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200301 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200302 case SCOPE_RES:
Willy Tarreau7513d002016-10-21 17:14:35 +0200303 default:
304 if (!smp->strm)
305 return 0;
306 vars = &smp->strm->vars_reqres;
307 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200308 }
309 if (vars->scope != var_desc->scope)
310 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200311
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100312 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200313 var = var_get(vars, var_desc->name);
314
315 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200316 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100317 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200318 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200319 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200320
Christopher Faulete95f2c32017-07-24 16:30:34 +0200321 /* Duplicate the sample data because it could modified by another
322 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200323 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200324 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200325 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200326
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100327 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200328 return 1;
329}
330
331/* This function search in the <head> a variable with the same
332 * pointer value that the <name>. If the variable doesn't exists,
333 * create it. The function stores a copy of smp> if the variable.
334 * It returns 0 if fails, else returns 1.
335 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100336static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200337{
338 struct var *var;
339
340 /* Look for existing variable name. */
341 var = var_get(vars, name);
342
343 if (var) {
344 /* free its used memory. */
345 if (var->data.type == SMP_T_STR ||
346 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200347 free(var->data.u.str.area);
348 var_accounting_diff(vars, smp->sess, smp->strm,
349 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200350 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200351 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200352 free(var->data.u.meth.str.area);
353 var_accounting_diff(vars, smp->sess, smp->strm,
354 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200355 }
356 } else {
357
358 /* Check memory avalaible. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100359 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200360 return 0;
361
362 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100363 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200364 if (!var)
365 return 0;
366 LIST_ADDQ(&vars->head, &var->l);
367 var->name = name;
368 }
369
370 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200371 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200372
373 /* Copy data. If the data needs memory, the function can fail. */
374 switch (var->data.type) {
375 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200376 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200377 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200378 break;
379 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200380 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200381 break;
382 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200383 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200384 break;
385 case SMP_T_STR:
386 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200387 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200388 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
389 return 0;
390 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200391 var->data.u.str.area = malloc(smp->data.u.str.data);
392 if (!var->data.u.str.area) {
393 var_accounting_diff(vars, smp->sess, smp->strm,
394 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200395 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
396 return 0;
397 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200398 var->data.u.str.data = smp->data.u.str.data;
399 memcpy(var->data.u.str.area, smp->data.u.str.area,
400 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200401 break;
402 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200403 var->data.u.meth.meth = smp->data.u.meth.meth;
404 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
405 break;
406
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200407 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200408 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
409 return 0;
410 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200411 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
412 if (!var->data.u.meth.str.area) {
413 var_accounting_diff(vars, smp->sess, smp->strm,
414 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200415 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
416 return 0;
417 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200418 var->data.u.meth.str.data = smp->data.u.meth.str.data;
419 var->data.u.meth.str.size = smp->data.u.meth.str.data;
420 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
421 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200422 break;
423 }
424 return 1;
425}
426
Willy Tarreau620408f2016-10-21 16:37:51 +0200427/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100428static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200429{
430 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200431 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200432
433 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100434 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100435 case SCOPE_SESS: vars = &smp->sess->vars; break;
436 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200437 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200438 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100439 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200440 }
441 if (vars->scope != scope)
442 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200443
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100444 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200445 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100446 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200447 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200448}
449
Christopher Faulet85d79c92016-11-09 16:54:56 +0100450/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
451static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
452{
453 struct vars *vars;
454 struct var *var;
455 unsigned int size = 0;
456
457 switch (scope) {
458 case SCOPE_PROC: vars = &global.vars; break;
459 case SCOPE_SESS: vars = &smp->sess->vars; break;
460 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
461 case SCOPE_REQ:
462 case SCOPE_RES:
463 default: vars = &smp->strm->vars_reqres; break;
464 }
465 if (vars->scope != scope)
466 return 0;
467
468 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100470 var = var_get(vars, name);
471 if (var) {
472 size = var_clear(var);
473 var_accounting_diff(vars, smp->sess, smp->strm, -size);
474 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100475 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100476 return 1;
477}
478
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200479/* Returns 0 if fails, else returns 1. */
480static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
481{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100482 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200483}
484
Christopher Faulet85d79c92016-11-09 16:54:56 +0100485/* Returns 0 if fails, else returns 1. */
486static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
487{
488 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
489}
490
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200491/* This fucntions check an argument entry and fill it with a variable
492 * type. The argumen must be a string. If the variable lookup fails,
493 * the function retuns 0 and fill <err>, otherwise it returns 1.
494 */
495int vars_check_arg(struct arg *arg, char **err)
496{
497 char *name;
498 enum vars_scope scope;
499
500 /* Check arg type. */
501 if (arg->type != ARGT_STR) {
502 memprintf(err, "unexpected argument type");
503 return 0;
504 }
505
506 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200507 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
508 1,
509 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200510 if (!name)
511 return 0;
512
513 /* Use the global variable name pointer. */
514 arg->type = ARGT_VAR;
515 arg->data.var.name = name;
516 arg->data.var.scope = scope;
517 return 1;
518}
519
Christopher Faulet09c9df22016-10-31 11:05:37 +0100520/* This function store a sample in a variable if it was already defined.
521 * In error case, it fails silently.
522 */
523void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
524{
525 enum vars_scope scope;
526
527 /* Resolve name and scope. */
528 name = register_name(name, len, &scope, 0, NULL);
529 if (!name)
530 return;
531
532 sample_store_stream(name, scope, smp);
533}
534
535
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200536/* This function store a sample in a variable.
537 * In error case, it fails silently.
538 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100539void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200540{
541 enum vars_scope scope;
542
543 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100544 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200545 if (!name)
546 return;
547
Willy Tarreau6204cd92016-03-10 16:33:04 +0100548 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200549}
550
Christopher Faulet85d79c92016-11-09 16:54:56 +0100551/* This function unset a variable if it was already defined.
552 * In error case, it fails silently.
553 */
554void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
555{
556 enum vars_scope scope;
557
558 /* Resolve name and scope. */
559 name = register_name(name, len, &scope, 0, NULL);
560 if (!name)
561 return;
562
563 sample_clear_stream(name, scope, smp);
564}
565
566
567/* This function unset a variable.
568 * In error case, it fails silently.
569 */
570void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
571{
572 enum vars_scope scope;
573
574 /* Resolve name and scope. */
575 name = register_name(name, len, &scope, 1, NULL);
576 if (!name)
577 return;
578
579 sample_clear_stream(name, scope, smp);
580}
581
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200582/* this function fills a sample with the
583 * variable content. Returns 1 if the sample
584 * is filled, otherwise it returns 0.
585 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100586int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200587{
588 struct vars *vars;
589 struct var *var;
590 enum vars_scope scope;
591
592 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100593 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200594 if (!name)
595 return 0;
596
597 /* Select "vars" pool according with the scope. */
598 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100599 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100600 case SCOPE_SESS: vars = &smp->sess->vars; break;
601 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200602 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200603 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100604 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200605 }
606
607 /* Check if the scope is avalaible a this point of processing. */
608 if (vars->scope != scope)
609 return 0;
610
611 /* Get the variable entry. */
612 var = var_get(vars, name);
613 if (!var)
614 return 0;
615
616 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200617 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200618 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200619 return 1;
620}
621
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200622/* this function fills a sample with the
623 * content of the varaible described by <var_desc>. Returns 1
624 * if the sample is filled, otherwise it returns 0.
625 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100626int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200627{
628 struct vars *vars;
629 struct var *var;
630
631 /* Select "vars" pool according with the scope. */
632 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100633 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100634 case SCOPE_SESS: vars = &smp->sess->vars; break;
635 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200636 case SCOPE_REQ:
637 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100638 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200639 }
640
641 /* Check if the scope is avalaible a this point of processing. */
642 if (vars->scope != var_desc->scope)
643 return 0;
644
645 /* Get the variable entry. */
646 var = var_get(vars, var_desc->name);
647 if (!var)
648 return 0;
649
650 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200651 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200652 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200653 return 1;
654}
655
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200656/* Always returns ACT_RET_CONT even if an error occurs. */
657static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200658 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200659{
660 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200661 int dir;
662
663 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200664 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200665 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
666 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
667 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
668 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
669 default:
670 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
671 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100672 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200673 return ACT_RET_CONT;
674 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200675
676 /* Process the expression. */
677 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200678 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200679 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200680 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200681
682 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100683 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200684 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200685}
686
Christopher Faulet85d79c92016-11-09 16:54:56 +0100687/* Always returns ACT_RET_CONT even if an error occurs. */
688static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
689 struct session *sess, struct stream *s, int flags)
690{
691 struct sample smp;
692
693 memset(&smp, 0, sizeof(smp));
694 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
695
696 /* Clear the variable using the sample context, and ignore errors. */
697 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
698 return ACT_RET_CONT;
699}
700
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200701/* This two function checks the variable name and replace the
702 * configuration string name by the global string name. its
703 * the same string, but the global pointer can be easy to
704 * compare.
705 *
706 * The first function checks a sample-fetch and the second
707 * checks a converter.
708 */
709static int smp_check_var(struct arg *args, char **err)
710{
711 return vars_check_arg(&args[0], err);
712}
713
714static int conv_check_var(struct arg *args, struct sample_conv *conv,
715 const char *file, int line, char **err_msg)
716{
717 return vars_check_arg(&args[0], err_msg);
718}
719
720/* This function is a common parser for using variables. It understands
721 * the format:
722 *
723 * set-var(<variable-name>) <expression>
724 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200725 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
726 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
727 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200728 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200729static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
730 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200731{
732 const char *var_name = args[*arg-1];
733 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200734 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100735 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200736
Christopher Faulet85d79c92016-11-09 16:54:56 +0100737 if (!strncmp(var_name, "set-var", 7)) {
738 var_name += 7;
739 set_var = 1;
740 }
741 if (!strncmp(var_name, "unset-var", 9)) {
742 var_name += 9;
743 set_var = 0;
744 }
745
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200746 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100747 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
748 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200749 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200750 }
751 var_name++; /* jump the '(' */
752 var_len = strlen(var_name);
753 var_len--; /* remove the ')' */
754 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100755 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
756 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200757 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200758 }
759
Christopher Faulet09c9df22016-10-31 11:05:37 +0100760 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200761 if (!rule->arg.vars.name)
762 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200763
Christopher Faulet85d79c92016-11-09 16:54:56 +0100764 /* There is no fetch method when variable is unset. Just set the right
765 * action and return. */
766 if (!set_var) {
767 if (*args[*arg]) {
768 memprintf(err, "fetch method not supported");
769 return ACT_RET_PRS_ERR;
770 }
771 rule->action = ACT_CUSTOM;
772 rule->action_ptr = action_clear;
773 return ACT_RET_PRS_OK;
774 }
775
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200776 kw_name = args[*arg-1];
777
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200778 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
779 px->conf.args.line, err, &px->conf.args);
780 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200781 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200782
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200783 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200784 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200785 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
786 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
787 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
788 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
789 default:
790 memprintf(err,
791 "internal error, unexpected rule->from=%d, please report this bug!",
792 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200793 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200794 }
795 if (!(rule->arg.vars.expr->fetch->val & flags)) {
796 memprintf(err,
797 "fetch method '%s' extracts information from '%s', none of which is available here",
798 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
799 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200800 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200801 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200802
Thierry FOURNIER42148732015-09-02 17:17:33 +0200803 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200804 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200805 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200806}
807
808static int vars_max_size(char **args, int section_type, struct proxy *curpx,
809 struct proxy *defpx, const char *file, int line,
810 char **err, unsigned int *limit)
811{
812 char *error;
813
814 *limit = strtol(args[1], &error, 10);
815 if (*error != 0) {
816 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
817 return -1;
818 }
819 return 0;
820}
821
822static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
823 struct proxy *defpx, const char *file, int line,
824 char **err)
825{
826 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
827}
828
Christopher Fauletff2613e2016-11-09 11:36:17 +0100829static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
830 struct proxy *defpx, const char *file, int line,
831 char **err)
832{
833 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
834}
835
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200836static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
837 struct proxy *defpx, const char *file, int line,
838 char **err)
839{
840 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
841}
842
843static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
844 struct proxy *defpx, const char *file, int line,
845 char **err)
846{
847 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
848}
849
850static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
851 struct proxy *defpx, const char *file, int line,
852 char **err)
853{
854 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
855}
856
857static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
858
Christopher Fauletff2613e2016-11-09 11:36:17 +0100859 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200860 { /* END */ },
861}};
862
863static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100864 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
865 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200866 { /* END */ },
867}};
868
Willy Tarreau620408f2016-10-21 16:37:51 +0200869static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100870 { "set-var", parse_store, 1 },
871 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200872 { /* END */ }
873}};
874
875static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100876 { "set-var", parse_store, 1 },
877 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200878 { /* END */ }
879}};
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
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200887static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100888 { "set-var", parse_store, 1 },
889 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200890 { /* END */ }
891}};
892
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200893static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100894 { "set-var", parse_store, 1 },
895 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200896 { /* END */ }
897}};
898
899static struct cfg_kw_list cfg_kws = {{ },{
900 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100901 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200902 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
903 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
904 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
905 { /* END */ }
906}};
907
908__attribute__((constructor))
Christopher Faulete95f2c32017-07-24 16:30:34 +0200909static void __vars_init(void)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200910{
911 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
912
913 sample_register_fetches(&sample_fetch_keywords);
914 sample_register_convs(&sample_conv_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +0200915 tcp_req_sess_keywords_register(&tcp_req_sess_kws);
916 tcp_req_cont_keywords_register(&tcp_req_cont_kws);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200917 tcp_res_cont_keywords_register(&tcp_res_kws);
918 http_req_keywords_register(&http_req_kws);
919 http_res_keywords_register(&http_res_kws);
920 cfg_register_keywords(&cfg_kws);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200921
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100922 HA_RWLOCK_INIT(&var_names_rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200923}