blob: e44a78600a51527bbbd5df04e6ae9ed60febdc7c [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 */
19static struct pool_head *var_pool = NULL;
20
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
Christopher Faulete95f2c32017-07-24 16:30:34 +020037
Christopher Faulet9dcf9b62017-11-13 10:34:01 +010038__decl_hathreads(HA_RWLOCK_T var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020039
Willy Tarreau72330982015-06-19 11:21:56 +020040/* This function adds or remove memory size from the accounting. The inner
41 * pointers may be null when setting the outer ones only.
42 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010043static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020044{
45 switch (vars->scope) {
46 case SCOPE_REQ:
47 case SCOPE_RES:
Christopher Faulete95f2c32017-07-24 16:30:34 +020048 HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010049 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020050 case SCOPE_TXN:
Christopher Faulete95f2c32017-07-24 16:30:34 +020051 HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010052 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020053 case SCOPE_SESS:
Christopher Faulete95f2c32017-07-24 16:30:34 +020054 HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010055 /* fall through */
56 case SCOPE_PROC:
Christopher Faulete95f2c32017-07-24 16:30:34 +020057 HA_ATOMIC_ADD(&global.vars.size, size);
58 HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020059 }
60}
61
62/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080063 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020064 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010065 * the outer ones only. The accounting uses either <sess> or <strm>
66 * depending on the scope. <strm> may be NULL when no stream is known
67 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020068 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010069static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020070{
71 switch (vars->scope) {
72 case SCOPE_REQ:
73 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010074 if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020075 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010076 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020077 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010078 if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020079 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010080 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020081 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010082 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020083 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010084 /* fall through */
85 case SCOPE_PROC:
86 if (var_proc_limit && global.vars.size + size > var_proc_limit)
87 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020088 if (var_global_limit && var_global_size + size > var_global_limit)
89 return 0;
90 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010091 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020092 return 1;
93}
94
Christopher Faulet85d79c92016-11-09 16:54:56 +010095/* This fnuction remove a variable from the list and free memory it used */
96unsigned int var_clear(struct var *var)
97{
98 unsigned int size = 0;
99
100 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200101 free(var->data.u.str.area);
102 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100103 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200104 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200105 free(var->data.u.meth.str.area);
106 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100107 }
108 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100109 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100110 size += sizeof(struct var);
111 return size;
112}
113
Joseph Herlant07676892018-11-15 09:19:50 -0800114/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200115 * in the list.
116 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100117void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200118{
119 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200120 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200121
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100122 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200123 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100124 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200125 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100126 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100127 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200128}
129
Willy Tarreauebcd4842015-06-19 11:59:02 +0200130/* This function frees all the memory used by all the session variables in the
131 * list starting at <vars>.
132 */
133void vars_prune_per_sess(struct vars *vars)
134{
135 struct var *var, *tmp;
136 unsigned int size = 0;
137
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100138 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200139 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100140 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200141 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100142 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200143
144 HA_ATOMIC_SUB(&vars->size, size);
145 HA_ATOMIC_SUB(&global.vars.size, size);
146 HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200147}
148
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200149/* This function init a list of variabes. */
150void vars_init(struct vars *vars, enum vars_scope scope)
151{
152 LIST_INIT(&vars->head);
153 vars->scope = scope;
154 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100155 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200156}
157
158/* This function declares a new variable name. It returns a pointer
159 * on the string identifying the name. This function assures that
160 * the same name exists only once.
161 *
162 * This function check if the variable name is acceptable.
163 *
164 * The function returns NULL if an error occurs, and <err> is filled.
165 * In this case, the HAProxy must be stopped because the structs are
166 * left inconsistent. Otherwise, it returns the pointer on the global
167 * name.
168 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100169static char *register_name(const char *name, int len, enum vars_scope *scope,
170 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200171{
172 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200173 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200174 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200175 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200176
177 /* Check length. */
178 if (len == 0) {
179 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100180 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200181 }
182
183 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100184 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
185 name += 5;
186 len -= 5;
187 *scope = SCOPE_PROC;
188 }
189 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200190 name += 5;
191 len -= 5;
192 *scope = SCOPE_SESS;
193 }
194 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
195 name += 4;
196 len -= 4;
197 *scope = SCOPE_TXN;
198 }
199 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
200 name += 4;
201 len -= 4;
202 *scope = SCOPE_REQ;
203 }
204 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
205 name += 4;
206 len -= 4;
207 *scope = SCOPE_RES;
208 }
209 else {
210 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Christopher Fauletff2613e2016-11-09 11:36:17 +0100211 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100212 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200213 }
214
Christopher Faulete95f2c32017-07-24 16:30:34 +0200215 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100216 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200217 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100218 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200219
220
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200221 /* Look for existing variable name. */
222 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200223 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
224 res = var_names[i];
225 goto end;
226 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200227
Christopher Faulete95f2c32017-07-24 16:30:34 +0200228 if (!alloc) {
229 res = NULL;
230 goto end;
231 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100232
Hubert Verstraete831962e2016-06-28 22:44:26 +0200233 /* Store variable name. If realloc fails, var_names remains valid */
234 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
235 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200236 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200237 res = NULL;
238 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200239 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200240 var_names_nb++;
241 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200242 var_names[var_names_nb - 1] = malloc(len + 1);
243 if (!var_names[var_names_nb - 1]) {
244 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200245 res = NULL;
246 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200247 }
248 memcpy(var_names[var_names_nb - 1], name, len);
249 var_names[var_names_nb - 1][len] = '\0';
250
251 /* Check variable name syntax. */
252 tmp = var_names[var_names_nb - 1];
253 while (*tmp) {
Christopher Fauletb71557a2016-10-31 10:49:03 +0100254 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200255 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200256 res = NULL;
257 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200258 }
259 tmp++;
260 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200261 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200262
Christopher Faulete95f2c32017-07-24 16:30:34 +0200263 end:
264 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100265 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200266 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100267 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200268
269 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200270}
271
272/* This function returns an existing variable or returns NULL. */
273static inline struct var *var_get(struct vars *vars, const char *name)
274{
275 struct var *var;
276
277 list_for_each_entry(var, &vars->head, l)
278 if (var->name == name)
279 return var;
280 return NULL;
281}
282
283/* Returns 0 if fails, else returns 1. */
284static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
285{
286 const struct var_desc *var_desc = &args[0].data.var;
287 struct var *var;
288 struct vars *vars;
289
290 /* Check the availibity of the variable. */
291 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100292 case SCOPE_PROC:
293 vars = &global.vars;
294 break;
Willy Tarreau7513d002016-10-21 17:14:35 +0200295 case SCOPE_SESS:
296 vars = &smp->sess->vars;
297 break;
298 case SCOPE_TXN:
299 if (!smp->strm)
300 return 0;
301 vars = &smp->strm->vars_txn;
302 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200303 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200304 case SCOPE_RES:
Willy Tarreau7513d002016-10-21 17:14:35 +0200305 default:
306 if (!smp->strm)
307 return 0;
308 vars = &smp->strm->vars_reqres;
309 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200310 }
311 if (vars->scope != var_desc->scope)
312 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200313
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100314 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200315 var = var_get(vars, var_desc->name);
316
317 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200318 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100319 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200320 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200321 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200322
Christopher Faulete95f2c32017-07-24 16:30:34 +0200323 /* Duplicate the sample data because it could modified by another
324 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200325 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200326 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200327 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200328
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100329 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200330 return 1;
331}
332
333/* This function search in the <head> a variable with the same
334 * pointer value that the <name>. If the variable doesn't exists,
335 * create it. The function stores a copy of smp> if the variable.
336 * It returns 0 if fails, else returns 1.
337 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100338static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200339{
340 struct var *var;
341
342 /* Look for existing variable name. */
343 var = var_get(vars, name);
344
345 if (var) {
346 /* free its used memory. */
347 if (var->data.type == SMP_T_STR ||
348 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200349 free(var->data.u.str.area);
350 var_accounting_diff(vars, smp->sess, smp->strm,
351 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200352 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200353 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200354 free(var->data.u.meth.str.area);
355 var_accounting_diff(vars, smp->sess, smp->strm,
356 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200357 }
358 } else {
359
Joseph Herlant07676892018-11-15 09:19:50 -0800360 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100361 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200362 return 0;
363
364 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100365 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200366 if (!var)
367 return 0;
368 LIST_ADDQ(&vars->head, &var->l);
369 var->name = name;
370 }
371
372 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200373 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200374
375 /* Copy data. If the data needs memory, the function can fail. */
376 switch (var->data.type) {
377 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200378 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200379 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200380 break;
381 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200382 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200383 break;
384 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200385 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200386 break;
387 case SMP_T_STR:
388 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200389 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200390 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
391 return 0;
392 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200393 var->data.u.str.area = malloc(smp->data.u.str.data);
394 if (!var->data.u.str.area) {
395 var_accounting_diff(vars, smp->sess, smp->strm,
396 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200397 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
398 return 0;
399 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200400 var->data.u.str.data = smp->data.u.str.data;
401 memcpy(var->data.u.str.area, smp->data.u.str.area,
402 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200403 break;
404 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200405 var->data.u.meth.meth = smp->data.u.meth.meth;
406 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
407 break;
408
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200409 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200410 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
411 return 0;
412 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200413 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
414 if (!var->data.u.meth.str.area) {
415 var_accounting_diff(vars, smp->sess, smp->strm,
416 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200417 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
418 return 0;
419 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200420 var->data.u.meth.str.data = smp->data.u.meth.str.data;
421 var->data.u.meth.str.size = smp->data.u.meth.str.data;
422 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
423 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200424 break;
425 }
426 return 1;
427}
428
Willy Tarreau620408f2016-10-21 16:37:51 +0200429/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100430static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200431{
432 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200433 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200434
435 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100436 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100437 case SCOPE_SESS: vars = &smp->sess->vars; break;
438 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200439 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200440 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100441 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200442 }
443 if (vars->scope != scope)
444 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200445
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100446 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200447 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100448 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200449 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200450}
451
Christopher Faulet85d79c92016-11-09 16:54:56 +0100452/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
453static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
454{
455 struct vars *vars;
456 struct var *var;
457 unsigned int size = 0;
458
459 switch (scope) {
460 case SCOPE_PROC: vars = &global.vars; break;
461 case SCOPE_SESS: vars = &smp->sess->vars; break;
462 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
463 case SCOPE_REQ:
464 case SCOPE_RES:
465 default: vars = &smp->strm->vars_reqres; break;
466 }
467 if (vars->scope != scope)
468 return 0;
469
470 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100471 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100472 var = var_get(vars, name);
473 if (var) {
474 size = var_clear(var);
475 var_accounting_diff(vars, smp->sess, smp->strm, -size);
476 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100477 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100478 return 1;
479}
480
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200481/* Returns 0 if fails, else returns 1. */
482static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
483{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100484 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200485}
486
Christopher Faulet85d79c92016-11-09 16:54:56 +0100487/* Returns 0 if fails, else returns 1. */
488static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
489{
490 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
491}
492
Joseph Herlant07676892018-11-15 09:19:50 -0800493/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200494 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800495 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200496 */
497int vars_check_arg(struct arg *arg, char **err)
498{
499 char *name;
500 enum vars_scope scope;
501
502 /* Check arg type. */
503 if (arg->type != ARGT_STR) {
504 memprintf(err, "unexpected argument type");
505 return 0;
506 }
507
508 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200509 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
510 1,
511 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200512 if (!name)
513 return 0;
514
515 /* Use the global variable name pointer. */
516 arg->type = ARGT_VAR;
517 arg->data.var.name = name;
518 arg->data.var.scope = scope;
519 return 1;
520}
521
Christopher Faulet09c9df22016-10-31 11:05:37 +0100522/* This function store a sample in a variable if it was already defined.
523 * In error case, it fails silently.
524 */
525void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
526{
527 enum vars_scope scope;
528
529 /* Resolve name and scope. */
530 name = register_name(name, len, &scope, 0, NULL);
531 if (!name)
532 return;
533
534 sample_store_stream(name, scope, smp);
535}
536
537
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200538/* This function store a sample in a variable.
539 * In error case, it fails silently.
540 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100541void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200542{
543 enum vars_scope scope;
544
545 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100546 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200547 if (!name)
548 return;
549
Willy Tarreau6204cd92016-03-10 16:33:04 +0100550 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200551}
552
Christopher Faulet85d79c92016-11-09 16:54:56 +0100553/* This function unset a variable if it was already defined.
554 * In error case, it fails silently.
555 */
556void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
557{
558 enum vars_scope scope;
559
560 /* Resolve name and scope. */
561 name = register_name(name, len, &scope, 0, NULL);
562 if (!name)
563 return;
564
565 sample_clear_stream(name, scope, smp);
566}
567
568
569/* This function unset a variable.
570 * In error case, it fails silently.
571 */
572void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
573{
574 enum vars_scope scope;
575
576 /* Resolve name and scope. */
577 name = register_name(name, len, &scope, 1, NULL);
578 if (!name)
579 return;
580
581 sample_clear_stream(name, scope, smp);
582}
583
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200584/* this function fills a sample with the
585 * variable content. Returns 1 if the sample
586 * is filled, otherwise it returns 0.
587 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100588int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200589{
590 struct vars *vars;
591 struct var *var;
592 enum vars_scope scope;
593
594 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100595 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200596 if (!name)
597 return 0;
598
599 /* Select "vars" pool according with the scope. */
600 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100601 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100602 case SCOPE_SESS: vars = &smp->sess->vars; break;
603 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200604 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200605 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100606 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200607 }
608
Joseph Herlant07676892018-11-15 09:19:50 -0800609 /* Check if the scope is available a this point of processing. */
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200610 if (vars->scope != scope)
611 return 0;
612
613 /* Get the variable entry. */
614 var = var_get(vars, name);
615 if (!var)
616 return 0;
617
618 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200619 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200620 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200621 return 1;
622}
623
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200624/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800625 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200626 * if the sample is filled, otherwise it returns 0.
627 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100628int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200629{
630 struct vars *vars;
631 struct var *var;
632
633 /* Select "vars" pool according with the scope. */
634 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100635 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100636 case SCOPE_SESS: vars = &smp->sess->vars; break;
637 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200638 case SCOPE_REQ:
639 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100640 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200641 }
642
Joseph Herlant07676892018-11-15 09:19:50 -0800643 /* Check if the scope is available a this point of processing. */
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200644 if (vars->scope != var_desc->scope)
645 return 0;
646
647 /* Get the variable entry. */
648 var = var_get(vars, var_desc->name);
649 if (!var)
650 return 0;
651
652 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200653 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200654 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200655 return 1;
656}
657
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200658/* Always returns ACT_RET_CONT even if an error occurs. */
659static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200660 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200661{
662 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200663 int dir;
664
665 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200666 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200667 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
668 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
669 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
670 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
671 default:
672 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
673 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100674 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200675 return ACT_RET_CONT;
676 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200677
678 /* Process the expression. */
679 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200680 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200681 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200682 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200683
684 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100685 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200686 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200687}
688
Christopher Faulet85d79c92016-11-09 16:54:56 +0100689/* Always returns ACT_RET_CONT even if an error occurs. */
690static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
691 struct session *sess, struct stream *s, int flags)
692{
693 struct sample smp;
694
695 memset(&smp, 0, sizeof(smp));
696 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
697
698 /* Clear the variable using the sample context, and ignore errors. */
699 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
700 return ACT_RET_CONT;
701}
702
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200703/* This two function checks the variable name and replace the
704 * configuration string name by the global string name. its
705 * the same string, but the global pointer can be easy to
706 * compare.
707 *
708 * The first function checks a sample-fetch and the second
709 * checks a converter.
710 */
711static int smp_check_var(struct arg *args, char **err)
712{
713 return vars_check_arg(&args[0], err);
714}
715
716static int conv_check_var(struct arg *args, struct sample_conv *conv,
717 const char *file, int line, char **err_msg)
718{
719 return vars_check_arg(&args[0], err_msg);
720}
721
722/* This function is a common parser for using variables. It understands
723 * the format:
724 *
725 * set-var(<variable-name>) <expression>
726 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200727 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
728 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
729 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200730 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200731static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
732 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200733{
734 const char *var_name = args[*arg-1];
735 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200736 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100737 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200738
Christopher Faulet85d79c92016-11-09 16:54:56 +0100739 if (!strncmp(var_name, "set-var", 7)) {
740 var_name += 7;
741 set_var = 1;
742 }
743 if (!strncmp(var_name, "unset-var", 9)) {
744 var_name += 9;
745 set_var = 0;
746 }
747
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200748 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100749 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
750 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200751 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200752 }
753 var_name++; /* jump the '(' */
754 var_len = strlen(var_name);
755 var_len--; /* remove the ')' */
756 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100757 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
758 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200759 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200760 }
761
Christopher Faulet09c9df22016-10-31 11:05:37 +0100762 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200763 if (!rule->arg.vars.name)
764 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200765
Christopher Faulet85d79c92016-11-09 16:54:56 +0100766 /* There is no fetch method when variable is unset. Just set the right
767 * action and return. */
768 if (!set_var) {
769 if (*args[*arg]) {
770 memprintf(err, "fetch method not supported");
771 return ACT_RET_PRS_ERR;
772 }
773 rule->action = ACT_CUSTOM;
774 rule->action_ptr = action_clear;
775 return ACT_RET_PRS_OK;
776 }
777
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200778 kw_name = args[*arg-1];
779
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200780 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
781 px->conf.args.line, err, &px->conf.args);
782 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200783 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200784
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200785 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200786 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200787 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
788 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
789 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
790 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
791 default:
792 memprintf(err,
793 "internal error, unexpected rule->from=%d, please report this bug!",
794 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200795 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200796 }
797 if (!(rule->arg.vars.expr->fetch->val & flags)) {
798 memprintf(err,
799 "fetch method '%s' extracts information from '%s', none of which is available here",
800 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
801 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200802 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200803 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200804
Thierry FOURNIER42148732015-09-02 17:17:33 +0200805 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200806 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200807 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200808}
809
810static int vars_max_size(char **args, int section_type, struct proxy *curpx,
811 struct proxy *defpx, const char *file, int line,
812 char **err, unsigned int *limit)
813{
814 char *error;
815
816 *limit = strtol(args[1], &error, 10);
817 if (*error != 0) {
818 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
819 return -1;
820 }
821 return 0;
822}
823
824static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
825 struct proxy *defpx, const char *file, int line,
826 char **err)
827{
828 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
829}
830
Christopher Fauletff2613e2016-11-09 11:36:17 +0100831static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
832 struct proxy *defpx, const char *file, int line,
833 char **err)
834{
835 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
836}
837
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200838static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
839 struct proxy *defpx, const char *file, int line,
840 char **err)
841{
842 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
843}
844
845static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
846 struct proxy *defpx, const char *file, int line,
847 char **err)
848{
849 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
850}
851
852static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
853 struct proxy *defpx, const char *file, int line,
854 char **err)
855{
856 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
857}
858
859static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
860
Christopher Fauletff2613e2016-11-09 11:36:17 +0100861 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200862 { /* END */ },
863}};
864
Willy Tarreau0108d902018-11-25 19:14:37 +0100865INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
866
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200867static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100868 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
869 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200870 { /* END */ },
871}};
872
Willy Tarreau0108d902018-11-25 19:14:37 +0100873INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
874
Willy Tarreau620408f2016-10-21 16:37:51 +0200875static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100876 { "set-var", parse_store, 1 },
877 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200878 { /* END */ }
879}};
880
Willy Tarreau0108d902018-11-25 19:14:37 +0100881INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
882
Willy Tarreau620408f2016-10-21 16:37:51 +0200883static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100884 { "set-var", parse_store, 1 },
885 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200886 { /* END */ }
887}};
888
Willy Tarreau0108d902018-11-25 19:14:37 +0100889INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
890
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200891static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100892 { "set-var", parse_store, 1 },
893 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200894 { /* END */ }
895}};
896
Willy Tarreau0108d902018-11-25 19:14:37 +0100897INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
898
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200899static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100900 { "set-var", parse_store, 1 },
901 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200902 { /* END */ }
903}};
904
Willy Tarreau0108d902018-11-25 19:14:37 +0100905INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
906
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200907static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100908 { "set-var", parse_store, 1 },
909 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200910 { /* END */ }
911}};
912
Willy Tarreau0108d902018-11-25 19:14:37 +0100913INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
914
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200915static struct cfg_kw_list cfg_kws = {{ },{
916 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100917 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200918 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
919 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
920 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
921 { /* END */ }
922}};
923
Willy Tarreau0108d902018-11-25 19:14:37 +0100924INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
925
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200926__attribute__((constructor))
Christopher Faulete95f2c32017-07-24 16:30:34 +0200927static void __vars_init(void)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200928{
929 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
930
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100931 HA_RWLOCK_INIT(&var_names_rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200932}