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