1 #include <ctype.h>
2
3 #include <common/cfgparse.h>
4 #include <common/mini-clist.h>
5
6 #include <types/vars.h>
7
8 #include <proto/arg.h>
9 #include <proto/proto_http.h>
10 #include <proto/sample.h>
11 #include <proto/stream.h>
12 #include <proto/tcp_rules.h>
13 #include <proto/vars.h>
14
15 /* This contains a pool of struct vars */
16 static struct pool_head *var_pool = NULL;
17
18 /* This array contain all the names of all the HAProxy vars.
19 * This permits to identify two variables name with
20 * only one pointer. It permits to not using strdup() for
21 * each variable name used during the runtime.
22 */
23 static char **var_names = NULL;
24 static int var_names_nb = 0;
25
26 /* This array of int contains the system limits per context. */
27 static unsigned int var_global_limit = 0;
28 static unsigned int var_global_size = 0;
29 static unsigned int var_proc_limit = 0;
30 static unsigned int var_sess_limit = 0;
31 static unsigned int var_txn_limit = 0;
32 static unsigned int var_reqres_limit = 0;
33
34
35 __decl_hathreads(HA_RWLOCK_T var_names_rwlock);
36
37 /* returns the struct vars pointer for a session, stream and scope, or NULL if
38 * it does not exist.
39 */
get_vars(struct session * sess,struct stream * strm,enum vars_scope scope)40 static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
41 {
42 switch (scope) {
43 case SCOPE_PROC:
44 return &global.vars;
45 case SCOPE_SESS:
46 return &sess->vars;
47 case SCOPE_TXN:
48 return strm ? &strm->vars_txn : NULL;
49 case SCOPE_REQ:
50 case SCOPE_RES:
51 default:
52 return strm ? &strm->vars_reqres : NULL;
53 }
54 }
55
56 /* This function adds or remove memory size from the accounting. The inner
57 * pointers may be null when setting the outer ones only.
58 */
var_accounting_diff(struct vars * vars,struct session * sess,struct stream * strm,int size)59 static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
60 {
61 switch (vars->scope) {
62 case SCOPE_REQ:
63 case SCOPE_RES:
64 if (strm)
65 HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
66 /* fall through */
67 case SCOPE_TXN:
68 if (strm)
69 HA_ATOMIC_ADD(&strm->vars_txn.size, size);
70 /* fall through */
71 case SCOPE_SESS:
72 HA_ATOMIC_ADD(&sess->vars.size, size);
73 /* fall through */
74 case SCOPE_PROC:
75 HA_ATOMIC_ADD(&global.vars.size, size);
76 HA_ATOMIC_ADD(&var_global_size, size);
77 }
78 }
79
80 /* This function returns 1 if the <size> is available in the var
81 * pool <vars>, otherwise returns 0. If the space is avalaible,
82 * the size is reserved. The inner pointers may be null when setting
83 * the outer ones only. The accounting uses either <sess> or <strm>
84 * depending on the scope. <strm> may be NULL when no stream is known
85 * and only the session exists (eg: tcp-request connection).
86 */
var_accounting_add(struct vars * vars,struct session * sess,struct stream * strm,int size)87 static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
88 {
89 switch (vars->scope) {
90 case SCOPE_REQ:
91 case SCOPE_RES:
92 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
93 return 0;
94 /* fall through */
95 case SCOPE_TXN:
96 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
97 return 0;
98 /* fall through */
99 case SCOPE_SESS:
100 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
101 return 0;
102 /* fall through */
103 case SCOPE_PROC:
104 if (var_proc_limit && global.vars.size + size > var_proc_limit)
105 return 0;
106 if (var_global_limit && var_global_size + size > var_global_limit)
107 return 0;
108 }
109 var_accounting_diff(vars, sess, strm, size);
110 return 1;
111 }
112
113 /* This fnuction remove a variable from the list and free memory it used */
var_clear(struct var * var)114 unsigned int var_clear(struct var *var)
115 {
116 unsigned int size = 0;
117
118 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
119 free(var->data.u.str.str);
120 size += var->data.u.str.len;
121 }
122 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
123 free(var->data.u.meth.str.str);
124 size += var->data.u.meth.str.len;
125 }
126 LIST_DEL(&var->l);
127 pool_free(var_pool, var);
128 size += sizeof(struct var);
129 return size;
130 }
131
132 /* This function free all the memory used by all the varaibles
133 * in the list.
134 */
vars_prune(struct vars * vars,struct session * sess,struct stream * strm)135 void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
136 {
137 struct var *var, *tmp;
138 unsigned int size = 0;
139
140 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
141 list_for_each_entry_safe(var, tmp, &vars->head, l) {
142 size += var_clear(var);
143 }
144 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
145 var_accounting_diff(vars, sess, strm, -size);
146 }
147
148 /* This function frees all the memory used by all the session variables in the
149 * list starting at <vars>.
150 */
vars_prune_per_sess(struct vars * vars)151 void vars_prune_per_sess(struct vars *vars)
152 {
153 struct var *var, *tmp;
154 unsigned int size = 0;
155
156 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
157 list_for_each_entry_safe(var, tmp, &vars->head, l) {
158 size += var_clear(var);
159 }
160 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
161
162 HA_ATOMIC_SUB(&vars->size, size);
163 HA_ATOMIC_SUB(&global.vars.size, size);
164 HA_ATOMIC_SUB(&var_global_size, size);
165 }
166
167 /* This function init a list of variabes. */
vars_init(struct vars * vars,enum vars_scope scope)168 void vars_init(struct vars *vars, enum vars_scope scope)
169 {
170 LIST_INIT(&vars->head);
171 vars->scope = scope;
172 vars->size = 0;
173 HA_RWLOCK_INIT(&vars->rwlock);
174 }
175
176 /* This function declares a new variable name. It returns a pointer
177 * on the string identifying the name. This function assures that
178 * the same name exists only once.
179 *
180 * This function check if the variable name is acceptable.
181 *
182 * The function returns NULL if an error occurs, and <err> is filled.
183 * In this case, the HAProxy must be stopped because the structs are
184 * left inconsistent. Otherwise, it returns the pointer on the global
185 * name.
186 */
register_name(const char * name,int len,enum vars_scope * scope,int alloc,char ** err)187 static char *register_name(const char *name, int len, enum vars_scope *scope,
188 int alloc, char **err)
189 {
190 int i;
191 char **var_names2;
192 const char *tmp;
193 char *res = NULL;
194
195 /* Check length. */
196 if (len == 0) {
197 memprintf(err, "Empty variable name cannot be accepted");
198 return res;
199 }
200
201 /* Check scope. */
202 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
203 name += 5;
204 len -= 5;
205 *scope = SCOPE_PROC;
206 }
207 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
208 name += 5;
209 len -= 5;
210 *scope = SCOPE_SESS;
211 }
212 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
213 name += 4;
214 len -= 4;
215 *scope = SCOPE_TXN;
216 }
217 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
218 name += 4;
219 len -= 4;
220 *scope = SCOPE_REQ;
221 }
222 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
223 name += 4;
224 len -= 4;
225 *scope = SCOPE_RES;
226 }
227 else {
228 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
229 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
230 return res;
231 }
232
233 if (alloc)
234 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
235 else
236 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
237
238
239 /* Look for existing variable name. */
240 for (i = 0; i < var_names_nb; i++)
241 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
242 res = var_names[i];
243 goto end;
244 }
245
246 if (!alloc) {
247 res = NULL;
248 goto end;
249 }
250
251 /* Store variable name. If realloc fails, var_names remains valid */
252 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
253 if (!var_names2) {
254 memprintf(err, "out of memory error");
255 res = NULL;
256 goto end;
257 }
258 var_names_nb++;
259 var_names = var_names2;
260 var_names[var_names_nb - 1] = malloc(len + 1);
261 if (!var_names[var_names_nb - 1]) {
262 memprintf(err, "out of memory error");
263 res = NULL;
264 goto end;
265 }
266 memcpy(var_names[var_names_nb - 1], name, len);
267 var_names[var_names_nb - 1][len] = '\0';
268
269 /* Check variable name syntax. */
270 tmp = var_names[var_names_nb - 1];
271 while (*tmp) {
272 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
273 memprintf(err, "invalid syntax at char '%s'", tmp);
274 res = NULL;
275 goto end;
276 }
277 tmp++;
278 }
279 res = var_names[var_names_nb - 1];
280
281 end:
282 if (alloc)
283 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
284 else
285 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
286
287 return res;
288 }
289
290 /* This function returns an existing variable or returns NULL. */
var_get(struct vars * vars,const char * name)291 static inline struct var *var_get(struct vars *vars, const char *name)
292 {
293 struct var *var;
294
295 list_for_each_entry(var, &vars->head, l)
296 if (var->name == name)
297 return var;
298 return NULL;
299 }
300
301 /* Returns 0 if fails, else returns 1. */
smp_fetch_var(const struct arg * args,struct sample * smp,const char * kw,void * private)302 static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
303 {
304 const struct var_desc *var_desc = &args[0].data.var;
305 struct var *var;
306 struct vars *vars;
307
308 /* Check the availibity of the variable. */
309 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
310 if (!vars || vars->scope != var_desc->scope)
311 return 0;
312
313 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
314 var = var_get(vars, var_desc->name);
315
316 /* check for the variable avalaibility */
317 if (!var) {
318 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
319 return 0;
320 }
321
322 /* Duplicate the sample data because it could modified by another
323 * thread */
324 smp->data = var->data;
325 smp_dup(smp);
326 smp->flags |= SMP_F_CONST;
327
328 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
329 return 1;
330 }
331
332 /* This function search in the <head> a variable with the same
333 * pointer value that the <name>. If the variable doesn't exists,
334 * create it. The function stores a copy of smp> if the variable.
335 * It returns 0 if fails, else returns 1.
336 */
sample_store(struct vars * vars,const char * name,struct sample * smp)337 static int sample_store(struct vars *vars, const char *name, struct sample *smp)
338 {
339 struct var *var;
340
341 /* Look for existing variable name. */
342 var = var_get(vars, name);
343
344 if (var) {
345 /* free its used memory. */
346 if (var->data.type == SMP_T_STR ||
347 var->data.type == SMP_T_BIN) {
348 free(var->data.u.str.str);
349 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.str.len);
350 }
351 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
352 free(var->data.u.meth.str.str);
353 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.meth.str.len);
354 }
355 } else {
356
357 /* Check memory avalaible. */
358 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
359 return 0;
360
361 /* Create new entry. */
362 var = pool_alloc(var_pool);
363 if (!var)
364 return 0;
365 LIST_ADDQ(&vars->head, &var->l);
366 var->name = name;
367 }
368
369 /* Set type. */
370 var->data.type = smp->data.type;
371
372 /* Copy data. If the data needs memory, the function can fail. */
373 switch (var->data.type) {
374 case SMP_T_BOOL:
375 case SMP_T_SINT:
376 var->data.u.sint = smp->data.u.sint;
377 break;
378 case SMP_T_IPV4:
379 var->data.u.ipv4 = smp->data.u.ipv4;
380 break;
381 case SMP_T_IPV6:
382 var->data.u.ipv6 = smp->data.u.ipv6;
383 break;
384 case SMP_T_STR:
385 case SMP_T_BIN:
386 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.len)) {
387 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
388 return 0;
389 }
390 var->data.u.str.str = malloc(smp->data.u.str.len);
391 if (!var->data.u.str.str) {
392 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.str.len);
393 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
394 return 0;
395 }
396 var->data.u.str.len = smp->data.u.str.len;
397 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
398 break;
399 case SMP_T_METH:
400 var->data.u.meth.meth = smp->data.u.meth.meth;
401 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
402 break;
403
404 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.len)) {
405 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
406 return 0;
407 }
408 var->data.u.meth.str.str = malloc(smp->data.u.meth.str.len);
409 if (!var->data.u.meth.str.str) {
410 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.meth.str.len);
411 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
412 return 0;
413 }
414 var->data.u.meth.str.len = smp->data.u.meth.str.len;
415 var->data.u.meth.str.size = smp->data.u.meth.str.len;
416 memcpy(var->data.u.meth.str.str, smp->data.u.meth.str.str, var->data.u.meth.str.len);
417 break;
418 }
419 return 1;
420 }
421
422 /* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
sample_store_stream(const char * name,enum vars_scope scope,struct sample * smp)423 static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
424 {
425 struct vars *vars;
426 int ret;
427
428 vars = get_vars(smp->sess, smp->strm, scope);
429 if (!vars || vars->scope != scope)
430 return 0;
431
432 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
433 ret = sample_store(vars, name, smp);
434 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
435 return ret;
436 }
437
438 /* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
sample_clear_stream(const char * name,enum vars_scope scope,struct sample * smp)439 static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
440 {
441 struct vars *vars;
442 struct var *var;
443 unsigned int size = 0;
444
445 vars = get_vars(smp->sess, smp->strm, scope);
446 if (!vars || vars->scope != scope)
447 return 0;
448
449 /* Look for existing variable name. */
450 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
451 var = var_get(vars, name);
452 if (var) {
453 size = var_clear(var);
454 var_accounting_diff(vars, smp->sess, smp->strm, -size);
455 }
456 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
457 return 1;
458 }
459
460 /* Returns 0 if fails, else returns 1. */
smp_conv_store(const struct arg * args,struct sample * smp,void * private)461 static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
462 {
463 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
464 }
465
466 /* Returns 0 if fails, else returns 1. */
smp_conv_clear(const struct arg * args,struct sample * smp,void * private)467 static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
468 {
469 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
470 }
471
472 /* This fucntions check an argument entry and fill it with a variable
473 * type. The argumen must be a string. If the variable lookup fails,
474 * the function retuns 0 and fill <err>, otherwise it returns 1.
475 */
vars_check_arg(struct arg * arg,char ** err)476 int vars_check_arg(struct arg *arg, char **err)
477 {
478 char *name;
479 enum vars_scope scope;
480
481 /* Check arg type. */
482 if (arg->type != ARGT_STR) {
483 memprintf(err, "unexpected argument type");
484 return 0;
485 }
486
487 /* Register new variable name. */
488 name = register_name(arg->data.str.str, arg->data.str.len, &scope, 1, err);
489 if (!name)
490 return 0;
491
492 /* Use the global variable name pointer. */
493 arg->type = ARGT_VAR;
494 arg->data.var.name = name;
495 arg->data.var.scope = scope;
496 return 1;
497 }
498
499 /* This function store a sample in a variable if it was already defined.
500 * In error case, it fails silently.
501 */
vars_set_by_name_ifexist(const char * name,size_t len,struct sample * smp)502 void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
503 {
504 enum vars_scope scope;
505
506 /* Resolve name and scope. */
507 name = register_name(name, len, &scope, 0, NULL);
508 if (!name)
509 return;
510
511 sample_store_stream(name, scope, smp);
512 }
513
514
515 /* This function store a sample in a variable.
516 * In error case, it fails silently.
517 */
vars_set_by_name(const char * name,size_t len,struct sample * smp)518 void vars_set_by_name(const char *name, size_t len, struct sample *smp)
519 {
520 enum vars_scope scope;
521
522 /* Resolve name and scope. */
523 name = register_name(name, len, &scope, 1, NULL);
524 if (!name)
525 return;
526
527 sample_store_stream(name, scope, smp);
528 }
529
530 /* This function unset a variable if it was already defined.
531 * In error case, it fails silently.
532 */
vars_unset_by_name_ifexist(const char * name,size_t len,struct sample * smp)533 void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
534 {
535 enum vars_scope scope;
536
537 /* Resolve name and scope. */
538 name = register_name(name, len, &scope, 0, NULL);
539 if (!name)
540 return;
541
542 sample_clear_stream(name, scope, smp);
543 }
544
545
546 /* This function unset a variable.
547 * In error case, it fails silently.
548 */
vars_unset_by_name(const char * name,size_t len,struct sample * smp)549 void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
550 {
551 enum vars_scope scope;
552
553 /* Resolve name and scope. */
554 name = register_name(name, len, &scope, 1, NULL);
555 if (!name)
556 return;
557
558 sample_clear_stream(name, scope, smp);
559 }
560
561 /* this function fills a sample with the
562 * variable content. Returns 1 if the sample
563 * is filled, otherwise it returns 0.
564 */
vars_get_by_name(const char * name,size_t len,struct sample * smp)565 int vars_get_by_name(const char *name, size_t len, struct sample *smp)
566 {
567 struct vars *vars;
568 struct var *var;
569 enum vars_scope scope;
570
571 /* Resolve name and scope. */
572 name = register_name(name, len, &scope, 1, NULL);
573 if (!name)
574 return 0;
575
576 /* Select "vars" pool according with the scope. */
577 vars = get_vars(smp->sess, smp->strm, scope);
578 if (!vars || vars->scope != scope)
579 return 0;
580
581 /* Get the variable entry. */
582 var = var_get(vars, name);
583 if (!var)
584 return 0;
585
586 /* Copy sample. */
587 smp->data = var->data;
588 smp->flags = SMP_F_CONST;
589 return 1;
590 }
591
592 /* this function fills a sample with the
593 * content of the varaible described by <var_desc>. Returns 1
594 * if the sample is filled, otherwise it returns 0.
595 */
vars_get_by_desc(const struct var_desc * var_desc,struct sample * smp)596 int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
597 {
598 struct vars *vars;
599 struct var *var;
600
601 /* Select "vars" pool according with the scope. */
602 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
603
604 /* Check if the scope is available a this point of processing. */
605 if (!vars || vars->scope != var_desc->scope)
606 return 0;
607
608 /* Get the variable entry. */
609 var = var_get(vars, var_desc->name);
610 if (!var)
611 return 0;
612
613 /* Copy sample. */
614 smp->data = var->data;
615 smp->flags = SMP_F_CONST;
616 return 1;
617 }
618
619 /* Always returns ACT_RET_CONT even if an error occurs. */
action_store(struct act_rule * rule,struct proxy * px,struct session * sess,struct stream * s,int flags)620 static enum act_return action_store(struct act_rule *rule, struct proxy *px,
621 struct session *sess, struct stream *s, int flags)
622 {
623 struct sample smp;
624 int dir;
625
626 switch (rule->from) {
627 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
628 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
629 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
630 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
631 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
632 default:
633 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
634 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
635 ha_alert("Vars: internal error while execute action store.\n");
636 return ACT_RET_CONT;
637 }
638
639 /* Process the expression. */
640 memset(&smp, 0, sizeof(smp));
641 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
642 rule->arg.vars.expr, &smp))
643 return ACT_RET_CONT;
644
645 /* Store the sample, and ignore errors. */
646 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
647 return ACT_RET_CONT;
648 }
649
650 /* Always returns ACT_RET_CONT even if an error occurs. */
action_clear(struct act_rule * rule,struct proxy * px,struct session * sess,struct stream * s,int flags)651 static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
652 struct session *sess, struct stream *s, int flags)
653 {
654 struct sample smp;
655
656 memset(&smp, 0, sizeof(smp));
657 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
658
659 /* Clear the variable using the sample context, and ignore errors. */
660 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
661 return ACT_RET_CONT;
662 }
663
664 /* This two function checks the variable name and replace the
665 * configuration string name by the global string name. its
666 * the same string, but the global pointer can be easy to
667 * compare.
668 *
669 * The first function checks a sample-fetch and the second
670 * checks a converter.
671 */
smp_check_var(struct arg * args,char ** err)672 static int smp_check_var(struct arg *args, char **err)
673 {
674 return vars_check_arg(&args[0], err);
675 }
676
conv_check_var(struct arg * args,struct sample_conv * conv,const char * file,int line,char ** err_msg)677 static int conv_check_var(struct arg *args, struct sample_conv *conv,
678 const char *file, int line, char **err_msg)
679 {
680 return vars_check_arg(&args[0], err_msg);
681 }
682
683 /* This function is a common parser for using variables. It understands
684 * the format:
685 *
686 * set-var(<variable-name>) <expression>
687 * unset-var(<variable-name>)
688 *
689 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
690 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
691 * is filled with the pointer to the expression to execute.
692 */
parse_store(const char ** args,int * arg,struct proxy * px,struct act_rule * rule,char ** err)693 static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
694 struct act_rule *rule, char **err)
695 {
696 const char *var_name = args[*arg-1];
697 int var_len;
698 const char *kw_name;
699 int flags, set_var = 0;
700
701 if (!strncmp(var_name, "set-var", 7)) {
702 var_name += 7;
703 set_var = 1;
704 }
705 if (!strncmp(var_name, "unset-var", 9)) {
706 var_name += 9;
707 set_var = 0;
708 }
709
710 if (*var_name != '(') {
711 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
712 args[*arg-1]);
713 return ACT_RET_PRS_ERR;
714 }
715 var_name++; /* jump the '(' */
716 var_len = strlen(var_name);
717 var_len--; /* remove the ')' */
718 if (var_name[var_len] != ')') {
719 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
720 args[*arg-1]);
721 return ACT_RET_PRS_ERR;
722 }
723
724 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
725 if (!rule->arg.vars.name)
726 return ACT_RET_PRS_ERR;
727
728 /* There is no fetch method when variable is unset. Just set the right
729 * action and return. */
730 if (!set_var) {
731 rule->action = ACT_CUSTOM;
732 rule->action_ptr = action_clear;
733 return ACT_RET_PRS_OK;
734 }
735
736 kw_name = args[*arg-1];
737
738 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
739 px->conf.args.line, err, &px->conf.args);
740 if (!rule->arg.vars.expr)
741 return ACT_RET_PRS_ERR;
742
743 switch (rule->from) {
744 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
745 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
746 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
747 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
748 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
749 default:
750 memprintf(err,
751 "internal error, unexpected rule->from=%d, please report this bug!",
752 rule->from);
753 return ACT_RET_PRS_ERR;
754 }
755 if (!(rule->arg.vars.expr->fetch->val & flags)) {
756 memprintf(err,
757 "fetch method '%s' extracts information from '%s', none of which is available here",
758 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
759 free(rule->arg.vars.expr);
760 return ACT_RET_PRS_ERR;
761 }
762
763 rule->action = ACT_CUSTOM;
764 rule->action_ptr = action_store;
765 return ACT_RET_PRS_OK;
766 }
767
vars_max_size(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err,unsigned int * limit)768 static int vars_max_size(char **args, int section_type, struct proxy *curpx,
769 struct proxy *defpx, const char *file, int line,
770 char **err, unsigned int *limit)
771 {
772 char *error;
773
774 *limit = strtol(args[1], &error, 10);
775 if (*error != 0) {
776 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
777 return -1;
778 }
779 return 0;
780 }
781
vars_max_size_global(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)782 static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
783 struct proxy *defpx, const char *file, int line,
784 char **err)
785 {
786 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
787 }
788
vars_max_size_proc(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)789 static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
790 struct proxy *defpx, const char *file, int line,
791 char **err)
792 {
793 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
794 }
795
vars_max_size_sess(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)796 static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
797 struct proxy *defpx, const char *file, int line,
798 char **err)
799 {
800 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
801 }
802
vars_max_size_txn(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)803 static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
804 struct proxy *defpx, const char *file, int line,
805 char **err)
806 {
807 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
808 }
809
vars_max_size_reqres(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)810 static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
811 struct proxy *defpx, const char *file, int line,
812 char **err)
813 {
814 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
815 }
816
817 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
818
819 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
820 { /* END */ },
821 }};
822
823 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
824 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
825 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
826 { /* END */ },
827 }};
828
829 static struct action_kw_list tcp_req_sess_kws = { { }, {
830 { "set-var", parse_store, 1 },
831 { "unset-var", parse_store, 1 },
832 { /* END */ }
833 }};
834
835 static struct action_kw_list tcp_req_cont_kws = { { }, {
836 { "set-var", parse_store, 1 },
837 { "unset-var", parse_store, 1 },
838 { /* END */ }
839 }};
840
841 static struct action_kw_list tcp_res_kws = { { }, {
842 { "set-var", parse_store, 1 },
843 { "unset-var", parse_store, 1 },
844 { /* END */ }
845 }};
846
847 static struct action_kw_list http_req_kws = { { }, {
848 { "set-var", parse_store, 1 },
849 { "unset-var", parse_store, 1 },
850 { /* END */ }
851 }};
852
853 static struct action_kw_list http_res_kws = { { }, {
854 { "set-var", parse_store, 1 },
855 { "unset-var", parse_store, 1 },
856 { /* END */ }
857 }};
858
859 static struct cfg_kw_list cfg_kws = {{ },{
860 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
861 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
862 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
863 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
864 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
865 { /* END */ }
866 }};
867
868 __attribute__((constructor))
__vars_init(void)869 static void __vars_init(void)
870 {
871 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
872
873 sample_register_fetches(&sample_fetch_keywords);
874 sample_register_convs(&sample_conv_kws);
875 tcp_req_sess_keywords_register(&tcp_req_sess_kws);
876 tcp_req_cont_keywords_register(&tcp_req_cont_kws);
877 tcp_res_cont_keywords_register(&tcp_res_kws);
878 http_req_keywords_register(&http_req_kws);
879 http_res_keywords_register(&http_res_kws);
880 cfg_register_keywords(&cfg_kws);
881
882 HA_RWLOCK_INIT(&var_names_rwlock);
883 }
884