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