blob: 50fb36a05dfe28c22ff72dca70542abf9d1593c3 [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#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/proto_tcp.h>
11#include <proto/sample.h>
12#include <proto/stream.h>
Willy Tarreauebcd4842015-06-19 11:59:02 +020013#include <proto/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020014
15/* This contains a pool of struct vars */
16static 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 */
23static char **var_names = NULL;
24static int var_names_nb = 0;
25
26/* This array of int contains the system limits per context. */
27static unsigned int var_global_limit = 0;
28static unsigned int var_global_size = 0;
29static unsigned int var_sess_limit = 0;
30static unsigned int var_txn_limit = 0;
31static unsigned int var_reqres_limit = 0;
32
Willy Tarreau72330982015-06-19 11:21:56 +020033/* This function adds or remove memory size from the accounting. The inner
34 * pointers may be null when setting the outer ones only.
35 */
36static void var_accounting_diff(struct vars *vars, struct vars *per_sess, struct vars *per_strm, struct vars *per_chn, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020037{
38 switch (vars->scope) {
39 case SCOPE_REQ:
40 case SCOPE_RES:
Willy Tarreau72330982015-06-19 11:21:56 +020041 per_chn->size += size;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020042 case SCOPE_TXN:
Willy Tarreau72330982015-06-19 11:21:56 +020043 per_strm->size += size;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020044 case SCOPE_SESS:
Willy Tarreau72330982015-06-19 11:21:56 +020045 per_sess->size += size;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020046 var_global_size += size;
47 }
48}
49
50/* This function returns 1 if the <size> is available in the var
51 * pool <vars>, otherwise returns 0. If the space is avalaible,
Willy Tarreau72330982015-06-19 11:21:56 +020052 * the size is reserved. The inner pointers may be null when setting
53 * the outer ones only.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020054 */
Willy Tarreau72330982015-06-19 11:21:56 +020055static int var_accounting_add(struct vars *vars, struct vars *per_sess, struct vars *per_strm, struct vars *per_chn, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020056{
57 switch (vars->scope) {
58 case SCOPE_REQ:
59 case SCOPE_RES:
Willy Tarreau72330982015-06-19 11:21:56 +020060 if (var_reqres_limit && per_chn->size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020061 return 0;
62 case SCOPE_TXN:
Willy Tarreau72330982015-06-19 11:21:56 +020063 if (var_txn_limit && per_strm->size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020064 return 0;
65 case SCOPE_SESS:
Willy Tarreau72330982015-06-19 11:21:56 +020066 if (var_sess_limit && per_sess->size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020067 return 0;
68 if (var_global_limit && var_global_size + size > var_global_limit)
69 return 0;
70 }
Willy Tarreau72330982015-06-19 11:21:56 +020071 var_accounting_diff(vars, per_sess, per_strm, per_chn, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020072 return 1;
73}
74
75/* This function free all the memory used by all the varaibles
76 * in the list.
77 */
78void vars_prune(struct vars *vars, struct stream *strm)
79{
80 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +020081 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020082
83 list_for_each_entry_safe(var, tmp, &vars->head, l) {
84 if (var->data.type == SMP_T_STR ||
85 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020086 free(var->data.u.str.str);
87 size += var->data.u.str.len;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020088 }
89 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020090 free(var->data.u.meth.str.str);
91 size += var->data.u.meth.str.len;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020092 }
93 LIST_DEL(&var->l);
94 pool_free2(var_pool, var);
Willy Tarreau72330982015-06-19 11:21:56 +020095 size += sizeof(struct var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020096 }
Willy Tarreauebcd4842015-06-19 11:59:02 +020097 var_accounting_diff(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020098}
99
Willy Tarreauebcd4842015-06-19 11:59:02 +0200100/* This function frees all the memory used by all the session variables in the
101 * list starting at <vars>.
102 */
103void vars_prune_per_sess(struct vars *vars)
104{
105 struct var *var, *tmp;
106 unsigned int size = 0;
107
108 list_for_each_entry_safe(var, tmp, &vars->head, l) {
109 if (var->data.type == SMP_T_STR ||
110 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200111 free(var->data.u.str.str);
112 size += var->data.u.str.len;
Willy Tarreauebcd4842015-06-19 11:59:02 +0200113 }
114 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200115 free(var->data.u.meth.str.str);
116 size += var->data.u.meth.str.len;
Willy Tarreauebcd4842015-06-19 11:59:02 +0200117 }
118 LIST_DEL(&var->l);
119 pool_free2(var_pool, var);
120 size += sizeof(struct var);
121 }
122 vars->size -= size;
123 var_global_size -= size;
124}
125
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200126/* This function init a list of variabes. */
127void vars_init(struct vars *vars, enum vars_scope scope)
128{
129 LIST_INIT(&vars->head);
130 vars->scope = scope;
131 vars->size = 0;
132}
133
134/* This function declares a new variable name. It returns a pointer
135 * on the string identifying the name. This function assures that
136 * the same name exists only once.
137 *
138 * This function check if the variable name is acceptable.
139 *
140 * The function returns NULL if an error occurs, and <err> is filled.
141 * In this case, the HAProxy must be stopped because the structs are
142 * left inconsistent. Otherwise, it returns the pointer on the global
143 * name.
144 */
145static char *register_name(const char *name, int len, enum vars_scope *scope, char **err)
146{
147 int i;
148 const char *tmp;
149
150 /* Check length. */
151 if (len == 0) {
152 memprintf(err, "Empty variable name cannot be accepted");
153 return NULL;
154 }
155
156 /* Check scope. */
157 if (len > 5 && strncmp(name, "sess.", 5) == 0) {
158 name += 5;
159 len -= 5;
160 *scope = SCOPE_SESS;
161 }
162 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
163 name += 4;
164 len -= 4;
165 *scope = SCOPE_TXN;
166 }
167 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
168 name += 4;
169 len -= 4;
170 *scope = SCOPE_REQ;
171 }
172 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
173 name += 4;
174 len -= 4;
175 *scope = SCOPE_RES;
176 }
177 else {
178 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
179 "The scope can be 'sess', 'txn', 'req' or 'res'", name);
180 return NULL;
181 }
182
183 /* Look for existing variable name. */
184 for (i = 0; i < var_names_nb; i++)
185 if (strncmp(var_names[i], name, len) == 0)
186 return var_names[i];
187
188 /* Store variable name. */
189 var_names_nb++;
190 var_names = realloc(var_names, var_names_nb * sizeof(*var_names));
191 if (!var_names) {
192 memprintf(err, "out of memory error");
193 return NULL;
194 }
195 var_names[var_names_nb - 1] = malloc(len + 1);
196 if (!var_names[var_names_nb - 1]) {
197 memprintf(err, "out of memory error");
198 return NULL;
199 }
200 memcpy(var_names[var_names_nb - 1], name, len);
201 var_names[var_names_nb - 1][len] = '\0';
202
203 /* Check variable name syntax. */
204 tmp = var_names[var_names_nb - 1];
205 while (*tmp) {
206 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_') {
207 memprintf(err, "invalid syntax at char '%s'", tmp);
208 return NULL;
209 }
210 tmp++;
211 }
212
213 /* Return the result. */
214 return var_names[var_names_nb - 1];
215}
216
217/* This function returns an existing variable or returns NULL. */
218static inline struct var *var_get(struct vars *vars, const char *name)
219{
220 struct var *var;
221
222 list_for_each_entry(var, &vars->head, l)
223 if (var->name == name)
224 return var;
225 return NULL;
226}
227
228/* Returns 0 if fails, else returns 1. */
229static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
230{
231 const struct var_desc *var_desc = &args[0].data.var;
232 struct var *var;
233 struct vars *vars;
234
235 /* Check the availibity of the variable. */
236 switch (var_desc->scope) {
Willy Tarreauebcd4842015-06-19 11:59:02 +0200237 case SCOPE_SESS: vars = &smp->strm->sess->vars; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200238 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
239 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200240 case SCOPE_RES:
241 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200242 }
243 if (vars->scope != var_desc->scope)
244 return 0;
245 var = var_get(vars, var_desc->name);
246
247 /* check for the variable avalaibility */
248 if (!var)
249 return 0;
250
251 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200252 smp->data = var->data;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200253 smp->flags |= SMP_F_CONST;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200254 return 1;
255}
256
257/* This function search in the <head> a variable with the same
258 * pointer value that the <name>. If the variable doesn't exists,
259 * create it. The function stores a copy of smp> if the variable.
260 * It returns 0 if fails, else returns 1.
261 */
262static int sample_store(struct vars *vars, const char *name, struct stream *strm, struct sample *smp)
263{
264 struct var *var;
265
266 /* Look for existing variable name. */
267 var = var_get(vars, name);
268
269 if (var) {
270 /* free its used memory. */
271 if (var->data.type == SMP_T_STR ||
272 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200273 free(var->data.u.str.str);
274 var_accounting_diff(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, -var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200275 }
276 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200277 free(var->data.u.meth.str.str);
278 var_accounting_diff(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, -var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200279 }
280 } else {
281
282 /* Check memory avalaible. */
Willy Tarreauebcd4842015-06-19 11:59:02 +0200283 if (!var_accounting_add(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200284 return 0;
285
286 /* Create new entry. */
287 var = pool_alloc2(var_pool);
288 if (!var)
289 return 0;
290 LIST_ADDQ(&vars->head, &var->l);
291 var->name = name;
292 }
293
294 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200295 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200296
297 /* Copy data. If the data needs memory, the function can fail. */
298 switch (var->data.type) {
299 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200300 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200301 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302 break;
303 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200304 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200305 break;
306 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200307 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200308 break;
309 case SMP_T_STR:
310 case SMP_T_BIN:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200311 if (!var_accounting_add(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, smp->data.u.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200312 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
313 return 0;
314 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200315 var->data.u.str.str = malloc(smp->data.u.str.len);
316 if (!var->data.u.str.str) {
317 var_accounting_diff(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, -smp->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200318 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
319 return 0;
320 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200321 var->data.u.str.len = smp->data.u.str.len;
322 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200323 break;
324 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200325 if (!var_accounting_add(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, smp->data.u.meth.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200326 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
327 return 0;
328 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200329 var->data.u.meth.str.str = malloc(smp->data.u.meth.str.len);
330 if (!var->data.u.meth.str.str) {
331 var_accounting_diff(vars, &strm->sess->vars, &strm->vars_txn, &strm->vars_reqres, -smp->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200332 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
333 return 0;
334 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200335 var->data.u.meth.meth = smp->data.u.meth.meth;
336 var->data.u.meth.str.len = smp->data.u.meth.str.len;
337 var->data.u.meth.str.size = smp->data.u.meth.str.len;
338 memcpy(var->data.u.meth.str.str, smp->data.u.meth.str.str, var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200339 break;
340 }
341 return 1;
342}
343
344/* Returns 0 if fails, else returns 1. */
345static inline int sample_store_stream(const char *name, enum vars_scope scope,
346 struct stream *strm, struct sample *smp)
347{
348 struct vars *vars;
349
350 switch (scope) {
Willy Tarreauebcd4842015-06-19 11:59:02 +0200351 case SCOPE_SESS: vars = &strm->sess->vars; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200352 case SCOPE_TXN: vars = &strm->vars_txn; break;
353 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200354 case SCOPE_RES:
355 default: vars = &strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200356 }
357 if (vars->scope != scope)
358 return 0;
359 return sample_store(vars, name, strm, smp);
360}
361
362/* Returns 0 if fails, else returns 1. */
363static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
364{
365 return sample_store_stream(args[0].data.var.name, args[1].data.var.scope, smp->strm, smp);
366}
367
368/* This fucntions check an argument entry and fill it with a variable
369 * type. The argumen must be a string. If the variable lookup fails,
370 * the function retuns 0 and fill <err>, otherwise it returns 1.
371 */
372int vars_check_arg(struct arg *arg, char **err)
373{
374 char *name;
375 enum vars_scope scope;
376
377 /* Check arg type. */
378 if (arg->type != ARGT_STR) {
379 memprintf(err, "unexpected argument type");
380 return 0;
381 }
382
383 /* Register new variable name. */
384 name = register_name(arg->data.str.str, arg->data.str.len, &scope, err);
385 if (!name)
386 return 0;
387
388 /* Use the global variable name pointer. */
389 arg->type = ARGT_VAR;
390 arg->data.var.name = name;
391 arg->data.var.scope = scope;
392 return 1;
393}
394
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200395/* This function store a sample in a variable.
396 * In error case, it fails silently.
397 */
398void vars_set_by_name(const char *name, size_t len, struct stream *strm, struct sample *smp)
399{
400 enum vars_scope scope;
401
402 /* Resolve name and scope. */
403 name = register_name(name, len, &scope, NULL);
404 if (!name)
405 return;
406
407 sample_store_stream(name, scope, strm, smp);
408}
409
410/* this function fills a sample with the
411 * variable content. Returns 1 if the sample
412 * is filled, otherwise it returns 0.
413 */
414int vars_get_by_name(const char *name, size_t len, struct stream *strm, struct sample *smp)
415{
416 struct vars *vars;
417 struct var *var;
418 enum vars_scope scope;
419
420 /* Resolve name and scope. */
421 name = register_name(name, len, &scope, NULL);
422 if (!name)
423 return 0;
424
425 /* Select "vars" pool according with the scope. */
426 switch (scope) {
Willy Tarreauebcd4842015-06-19 11:59:02 +0200427 case SCOPE_SESS: vars = &strm->sess->vars; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200428 case SCOPE_TXN: vars = &strm->vars_txn; break;
429 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200430 case SCOPE_RES:
431 default: vars = &strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200432 }
433
434 /* Check if the scope is avalaible a this point of processing. */
435 if (vars->scope != scope)
436 return 0;
437
438 /* Get the variable entry. */
439 var = var_get(vars, name);
440 if (!var)
441 return 0;
442
443 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200444 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200445 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200446 return 1;
447}
448
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200449/* this function fills a sample with the
450 * content of the varaible described by <var_desc>. Returns 1
451 * if the sample is filled, otherwise it returns 0.
452 */
453int vars_get_by_desc(const struct var_desc *var_desc, struct stream *strm, struct sample *smp)
454{
455 struct vars *vars;
456 struct var *var;
457
458 /* Select "vars" pool according with the scope. */
459 switch (var_desc->scope) {
460 case SCOPE_SESS: vars = &strm->sess->vars; break;
461 case SCOPE_TXN: vars = &strm->vars_txn; break;
462 case SCOPE_REQ:
463 case SCOPE_RES:
464 default: vars = &strm->vars_reqres; break;
465 }
466
467 /* Check if the scope is avalaible a this point of processing. */
468 if (vars->scope != var_desc->scope)
469 return 0;
470
471 /* Get the variable entry. */
472 var = var_get(vars, var_desc->name);
473 if (!var)
474 return 0;
475
476 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200477 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200478 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200479 return 1;
480}
481
Willy Tarreaue44136f2015-06-23 15:17:33 +0200482/* Returns 0 if we need to come back later to complete the sample's retrieval,
483 * otherwise 1. For now all processing is considered final so we only return 1.
484 */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200485static inline int action_store(struct sample_expr *expr, const char *name,
486 enum vars_scope scope, struct proxy *px,
487 struct stream *s, int sens)
488{
489 struct sample smp;
490
491 /* Process the expression. */
492 memset(&smp, 0, sizeof(smp));
493 if (!sample_process(px, s->sess, s, sens|SMP_OPT_FINAL, expr, &smp))
Willy Tarreaue44136f2015-06-23 15:17:33 +0200494 return 1;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200495
496 /* Store the sample, and ignore errors. */
497 sample_store_stream(name, scope, s, &smp);
498 return 1;
499}
500
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200501/* Wrapper for action_store */
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200502static int action_tcp_req_store(struct act_rule *rule, struct proxy *px,
Thierry FOURNIER422a3af2015-08-10 18:30:18 +0200503 struct session *sess, struct stream *s)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200504{
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200505 return action_store(rule->arg.vars.expr, rule->arg.vars.name,
506 rule->arg.vars.scope, px, s, SMP_OPT_DIR_REQ);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200507}
508
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200509/* Wrapper for action_store */
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200510static int action_tcp_res_store(struct act_rule *rule, struct proxy *px,
Thierry FOURNIER422a3af2015-08-10 18:30:18 +0200511 struct session *sess, struct stream *s)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200512{
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200513 return action_store(rule->arg.vars.expr, rule->arg.vars.name,
514 rule->arg.vars.scope, px, s, SMP_OPT_DIR_RES);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200515}
516
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200517/* Wrapper for action_store */
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200518static int action_http_req_store(struct act_rule *rule, struct proxy *px,
519 struct session *sess, struct stream *s)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200520{
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200521 return action_store(rule->arg.vars.expr, rule->arg.vars.name,
522 rule->arg.vars.scope, px, s, SMP_OPT_DIR_REQ);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200523}
524
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200525/* Wrapper for action_store */
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200526static int action_http_res_store(struct act_rule *rule, struct proxy *px,
527 struct session *sess, struct stream *s)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200528{
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200529 return action_store(rule->arg.vars.expr, rule->arg.vars.name,
530 rule->arg.vars.scope, px, s, SMP_OPT_DIR_RES);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200531}
532
533/* This two function checks the variable name and replace the
534 * configuration string name by the global string name. its
535 * the same string, but the global pointer can be easy to
536 * compare.
537 *
538 * The first function checks a sample-fetch and the second
539 * checks a converter.
540 */
541static int smp_check_var(struct arg *args, char **err)
542{
543 return vars_check_arg(&args[0], err);
544}
545
546static int conv_check_var(struct arg *args, struct sample_conv *conv,
547 const char *file, int line, char **err_msg)
548{
549 return vars_check_arg(&args[0], err_msg);
550}
551
552/* This function is a common parser for using variables. It understands
553 * the format:
554 *
555 * set-var(<variable-name>) <expression>
556 *
557 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
558 * it returns 1 and the variable <expr> is filled with the pointer to the
559 * expression to execute.
560 */
561static int parse_vars(const char **args, int *arg, struct proxy *px,
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200562 int flags, char **err, struct sample_expr **expr,
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200563 const char **name, enum vars_scope *scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200564{
565 const char *var_name = args[*arg-1];
566 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200567 const char *kw_name;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200568
569 var_name += strlen("set-var");
570 if (*var_name != '(') {
571 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
572 return 0;
573 }
574 var_name++; /* jump the '(' */
575 var_len = strlen(var_name);
576 var_len--; /* remove the ')' */
577 if (var_name[var_len] != ')') {
578 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
579 return 0;
580 }
581
582 *name = register_name(var_name, var_len, scope, err);
583 if (!*name)
584 return 0;
585
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200586 kw_name = args[*arg-1];
587
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200588 *expr = sample_parse_expr((char **)args, arg, px->conf.args.file, px->conf.args.line,
589 err, &px->conf.args);
590 if (!*expr)
591 return 0;
592
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200593 if (!((*expr)->fetch->val & flags)) {
594 memprintf(err,
595 "fetch method '%s' extracts information from '%s', none of which is available here",
596 kw_name, sample_src_names((*expr)->fetch->use));
597 free(*expr);
598 return 0;
599 }
600
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200601 return 1;
602}
603
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200604/* Wrapper for parse_vars */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200605static int parse_tcp_req_store(const char **args, int *arg, struct proxy *px,
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200606 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200607{
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200608 if (!parse_vars(args, arg, px, SMP_VAL_FE_REQ_CNT, err,
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200609 &rule->arg.vars.expr,
610 &rule->arg.vars.name,
611 &rule->arg.vars.scope))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200612 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200613 rule->action = TCP_ACT_CUSTOM_CONT;
614 rule->action_ptr = action_tcp_req_store;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200615 return 1;
616}
617
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200618/* Wrapper for parse_vars */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200619static int parse_tcp_res_store(const char **args, int *arg, struct proxy *px,
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200620 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200621{
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200622 if (!parse_vars(args, arg, px, SMP_VAL_BE_RES_CNT, err,
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200623 &rule->arg.vars.expr,
624 &rule->arg.vars.name,
625 &rule->arg.vars.scope))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200626 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200627 rule->action = TCP_ACT_CUSTOM_CONT;
628 rule->action_ptr = action_tcp_res_store;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200629 return 1;
630}
631
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200632/* Wrapper for parse_vars */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200633static int parse_http_req_store(const char **args, int *arg, struct proxy *px,
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200634 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200635{
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200636 if (!parse_vars(args, arg, px, SMP_VAL_FE_HRQ_HDR, err,
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200637 &rule->arg.vars.expr,
638 &rule->arg.vars.name,
639 &rule->arg.vars.scope))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200640 return -1;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200641 rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
642 rule->action_ptr = action_http_req_store;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200643 return 0;
644}
645
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200646/* Wrapper for parse_vars */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200647static int parse_http_res_store(const char **args, int *arg, struct proxy *px,
Thierry FOURNIERa28a9422015-08-04 19:35:46 +0200648 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200649{
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200650 if (!parse_vars(args, arg, px, SMP_VAL_BE_HRS_HDR, err,
Thierry FOURNIERf8c1dce2015-07-30 19:12:50 +0200651 &rule->arg.vars.expr,
652 &rule->arg.vars.name,
653 &rule->arg.vars.scope))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200654 return -1;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200655 rule->action = HTTP_RES_ACT_CUSTOM_CONT;
656 rule->action_ptr = action_http_res_store;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200657 return 0;
658}
659
660static int vars_max_size(char **args, int section_type, struct proxy *curpx,
661 struct proxy *defpx, const char *file, int line,
662 char **err, unsigned int *limit)
663{
664 char *error;
665
666 *limit = strtol(args[1], &error, 10);
667 if (*error != 0) {
668 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
669 return -1;
670 }
671 return 0;
672}
673
674static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
675 struct proxy *defpx, const char *file, int line,
676 char **err)
677{
678 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
679}
680
681static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
682 struct proxy *defpx, const char *file, int line,
683 char **err)
684{
685 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
686}
687
688static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
689 struct proxy *defpx, const char *file, int line,
690 char **err)
691{
692 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
693}
694
695static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
696 struct proxy *defpx, const char *file, int line,
697 char **err)
698{
699 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
700}
701
702static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
703
704 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_HTTP_ANY },
705 { /* END */ },
706}};
707
708static struct sample_conv_kw_list sample_conv_kws = {ILH, {
709 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
710 { /* END */ },
711}};
712
Thierry FOURNIERa6b63432015-08-11 10:59:49 +0200713static struct tcp_action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200714 { "set-var", parse_tcp_req_store, 1 },
715 { /* END */ }
716}};
717
Thierry FOURNIERa6b63432015-08-11 10:59:49 +0200718static struct tcp_action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200719 { "set-var", parse_tcp_res_store, 1 },
720 { /* END */ }
721}};
722
Thierry FOURNIERa6b63432015-08-11 10:59:49 +0200723static struct http_req_action_kw_list http_req_kws = { { }, {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200724 { "set-var", parse_http_req_store, 1 },
725 { /* END */ }
726}};
727
Thierry FOURNIERa6b63432015-08-11 10:59:49 +0200728static struct http_res_action_kw_list http_res_kws = { { }, {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200729 { "set-var", parse_http_res_store, 1 },
730 { /* END */ }
731}};
732
733static struct cfg_kw_list cfg_kws = {{ },{
734 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
735 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
736 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
737 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
738 { /* END */ }
739}};
740
741__attribute__((constructor))
742static void __http_protocol_init(void)
743{
744 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
745
746 sample_register_fetches(&sample_fetch_keywords);
747 sample_register_convs(&sample_conv_kws);
748 tcp_req_cont_keywords_register(&tcp_req_kws);
749 tcp_res_cont_keywords_register(&tcp_res_kws);
750 http_req_keywords_register(&http_req_kws);
751 http_res_keywords_register(&http_res_kws);
752 cfg_register_keywords(&cfg_kws);
753}