blob: d79f317b98e25bc1c0557c0174c8da1eaf5433f9 [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 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010036static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020037{
38 switch (vars->scope) {
39 case SCOPE_REQ:
40 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010041 strm->vars_reqres.size += size;
42 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020043 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010044 strm->vars_txn.size += size;
45 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020046 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010047 sess->vars.size += size;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020048 var_global_size += size;
49 }
50}
51
52/* This function returns 1 if the <size> is available in the var
53 * pool <vars>, otherwise returns 0. If the space is avalaible,
Willy Tarreau72330982015-06-19 11:21:56 +020054 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010055 * the outer ones only. The accounting uses either <sess> or <strm>
56 * depending on the scope. <strm> may be NULL when no stream is known
57 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020058 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010059static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020060{
61 switch (vars->scope) {
62 case SCOPE_REQ:
63 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010064 if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020065 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010066 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020067 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010068 if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020069 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010070 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020071 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010072 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020073 return 0;
74 if (var_global_limit && var_global_size + size > var_global_limit)
75 return 0;
76 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010077 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020078 return 1;
79}
80
81/* This function free all the memory used by all the varaibles
82 * in the list.
83 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010084void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020085{
86 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +020087 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020088
89 list_for_each_entry_safe(var, tmp, &vars->head, l) {
90 if (var->data.type == SMP_T_STR ||
91 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020092 free(var->data.u.str.str);
93 size += var->data.u.str.len;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020094 }
95 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020096 free(var->data.u.meth.str.str);
97 size += var->data.u.meth.str.len;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020098 }
99 LIST_DEL(&var->l);
100 pool_free2(var_pool, var);
Willy Tarreau72330982015-06-19 11:21:56 +0200101 size += sizeof(struct var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200102 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100103 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200104}
105
Willy Tarreauebcd4842015-06-19 11:59:02 +0200106/* This function frees all the memory used by all the session variables in the
107 * list starting at <vars>.
108 */
109void vars_prune_per_sess(struct vars *vars)
110{
111 struct var *var, *tmp;
112 unsigned int size = 0;
113
114 list_for_each_entry_safe(var, tmp, &vars->head, l) {
115 if (var->data.type == SMP_T_STR ||
116 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200117 free(var->data.u.str.str);
118 size += var->data.u.str.len;
Willy Tarreauebcd4842015-06-19 11:59:02 +0200119 }
120 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200121 free(var->data.u.meth.str.str);
122 size += var->data.u.meth.str.len;
Willy Tarreauebcd4842015-06-19 11:59:02 +0200123 }
124 LIST_DEL(&var->l);
125 pool_free2(var_pool, var);
126 size += sizeof(struct var);
127 }
128 vars->size -= size;
129 var_global_size -= size;
130}
131
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200132/* This function init a list of variabes. */
133void vars_init(struct vars *vars, enum vars_scope scope)
134{
135 LIST_INIT(&vars->head);
136 vars->scope = scope;
137 vars->size = 0;
138}
139
140/* This function declares a new variable name. It returns a pointer
141 * on the string identifying the name. This function assures that
142 * the same name exists only once.
143 *
144 * This function check if the variable name is acceptable.
145 *
146 * The function returns NULL if an error occurs, and <err> is filled.
147 * In this case, the HAProxy must be stopped because the structs are
148 * left inconsistent. Otherwise, it returns the pointer on the global
149 * name.
150 */
151static char *register_name(const char *name, int len, enum vars_scope *scope, char **err)
152{
153 int i;
154 const char *tmp;
155
156 /* Check length. */
157 if (len == 0) {
158 memprintf(err, "Empty variable name cannot be accepted");
159 return NULL;
160 }
161
162 /* Check scope. */
163 if (len > 5 && strncmp(name, "sess.", 5) == 0) {
164 name += 5;
165 len -= 5;
166 *scope = SCOPE_SESS;
167 }
168 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
169 name += 4;
170 len -= 4;
171 *scope = SCOPE_TXN;
172 }
173 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
174 name += 4;
175 len -= 4;
176 *scope = SCOPE_REQ;
177 }
178 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
179 name += 4;
180 len -= 4;
181 *scope = SCOPE_RES;
182 }
183 else {
184 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
185 "The scope can be 'sess', 'txn', 'req' or 'res'", name);
186 return NULL;
187 }
188
189 /* Look for existing variable name. */
190 for (i = 0; i < var_names_nb; i++)
191 if (strncmp(var_names[i], name, len) == 0)
192 return var_names[i];
193
194 /* Store variable name. */
195 var_names_nb++;
196 var_names = realloc(var_names, var_names_nb * sizeof(*var_names));
197 if (!var_names) {
198 memprintf(err, "out of memory error");
199 return NULL;
200 }
201 var_names[var_names_nb - 1] = malloc(len + 1);
202 if (!var_names[var_names_nb - 1]) {
203 memprintf(err, "out of memory error");
204 return NULL;
205 }
206 memcpy(var_names[var_names_nb - 1], name, len);
207 var_names[var_names_nb - 1][len] = '\0';
208
209 /* Check variable name syntax. */
210 tmp = var_names[var_names_nb - 1];
211 while (*tmp) {
212 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_') {
213 memprintf(err, "invalid syntax at char '%s'", tmp);
214 return NULL;
215 }
216 tmp++;
217 }
218
219 /* Return the result. */
220 return var_names[var_names_nb - 1];
221}
222
223/* This function returns an existing variable or returns NULL. */
224static inline struct var *var_get(struct vars *vars, const char *name)
225{
226 struct var *var;
227
228 list_for_each_entry(var, &vars->head, l)
229 if (var->name == name)
230 return var;
231 return NULL;
232}
233
234/* Returns 0 if fails, else returns 1. */
235static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
236{
237 const struct var_desc *var_desc = &args[0].data.var;
238 struct var *var;
239 struct vars *vars;
240
241 /* Check the availibity of the variable. */
242 switch (var_desc->scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100243 case SCOPE_SESS: vars = &smp->sess->vars; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200244 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
245 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200246 case SCOPE_RES:
247 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200248 }
249 if (vars->scope != var_desc->scope)
250 return 0;
251 var = var_get(vars, var_desc->name);
252
253 /* check for the variable avalaibility */
254 if (!var)
255 return 0;
256
257 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200258 smp->data = var->data;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200259 smp->flags |= SMP_F_CONST;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200260 return 1;
261}
262
263/* This function search in the <head> a variable with the same
264 * pointer value that the <name>. If the variable doesn't exists,
265 * create it. The function stores a copy of smp> if the variable.
266 * It returns 0 if fails, else returns 1.
267 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100268static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200269{
270 struct var *var;
271
272 /* Look for existing variable name. */
273 var = var_get(vars, name);
274
275 if (var) {
276 /* free its used memory. */
277 if (var->data.type == SMP_T_STR ||
278 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200279 free(var->data.u.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100280 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200281 }
282 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200283 free(var->data.u.meth.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100284 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200285 }
286 } else {
287
288 /* Check memory avalaible. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100289 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200290 return 0;
291
292 /* Create new entry. */
293 var = pool_alloc2(var_pool);
294 if (!var)
295 return 0;
296 LIST_ADDQ(&vars->head, &var->l);
297 var->name = name;
298 }
299
300 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200301 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302
303 /* Copy data. If the data needs memory, the function can fail. */
304 switch (var->data.type) {
305 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200306 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200307 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200308 break;
309 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200310 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200311 break;
312 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200313 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200314 break;
315 case SMP_T_STR:
316 case SMP_T_BIN:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100317 if (!var_accounting_add(vars, smp->sess, smp->strm, 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.str = malloc(smp->data.u.str.len);
322 if (!var->data.u.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100323 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200324 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
325 return 0;
326 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200327 var->data.u.str.len = smp->data.u.str.len;
328 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200329 break;
330 case SMP_T_METH:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100331 if (!var_accounting_add(vars, smp->sess, smp->strm, 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.str.str = malloc(smp->data.u.meth.str.len);
336 if (!var->data.u.meth.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100337 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200338 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
339 return 0;
340 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200341 var->data.u.meth.meth = smp->data.u.meth.meth;
342 var->data.u.meth.str.len = smp->data.u.meth.str.len;
343 var->data.u.meth.str.size = smp->data.u.meth.str.len;
344 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 +0200345 break;
346 }
347 return 1;
348}
349
350/* Returns 0 if fails, else returns 1. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100351static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200352{
353 struct vars *vars;
354
355 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100356 case SCOPE_SESS: vars = &smp->sess->vars; break;
357 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200358 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200359 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100360 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200361 }
362 if (vars->scope != scope)
363 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100364 return sample_store(vars, name, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200365}
366
367/* Returns 0 if fails, else returns 1. */
368static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
369{
Willy Tarreau6204cd92016-03-10 16:33:04 +0100370 return sample_store_stream(args[0].data.var.name, args[1].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200371}
372
373/* This fucntions check an argument entry and fill it with a variable
374 * type. The argumen must be a string. If the variable lookup fails,
375 * the function retuns 0 and fill <err>, otherwise it returns 1.
376 */
377int vars_check_arg(struct arg *arg, char **err)
378{
379 char *name;
380 enum vars_scope scope;
381
382 /* Check arg type. */
383 if (arg->type != ARGT_STR) {
384 memprintf(err, "unexpected argument type");
385 return 0;
386 }
387
388 /* Register new variable name. */
389 name = register_name(arg->data.str.str, arg->data.str.len, &scope, err);
390 if (!name)
391 return 0;
392
393 /* Use the global variable name pointer. */
394 arg->type = ARGT_VAR;
395 arg->data.var.name = name;
396 arg->data.var.scope = scope;
397 return 1;
398}
399
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200400/* This function store a sample in a variable.
401 * In error case, it fails silently.
402 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100403void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200404{
405 enum vars_scope scope;
406
407 /* Resolve name and scope. */
408 name = register_name(name, len, &scope, NULL);
409 if (!name)
410 return;
411
Willy Tarreau6204cd92016-03-10 16:33:04 +0100412 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200413}
414
415/* this function fills a sample with the
416 * variable content. Returns 1 if the sample
417 * is filled, otherwise it returns 0.
418 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100419int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200420{
421 struct vars *vars;
422 struct var *var;
423 enum vars_scope scope;
424
425 /* Resolve name and scope. */
426 name = register_name(name, len, &scope, NULL);
427 if (!name)
428 return 0;
429
430 /* Select "vars" pool according with the scope. */
431 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100432 case SCOPE_SESS: vars = &smp->sess->vars; break;
433 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200434 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200435 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100436 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200437 }
438
439 /* Check if the scope is avalaible a this point of processing. */
440 if (vars->scope != scope)
441 return 0;
442
443 /* Get the variable entry. */
444 var = var_get(vars, name);
445 if (!var)
446 return 0;
447
448 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200449 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200450 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200451 return 1;
452}
453
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200454/* this function fills a sample with the
455 * content of the varaible described by <var_desc>. Returns 1
456 * if the sample is filled, otherwise it returns 0.
457 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100458int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200459{
460 struct vars *vars;
461 struct var *var;
462
463 /* Select "vars" pool according with the scope. */
464 switch (var_desc->scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100465 case SCOPE_SESS: vars = &smp->sess->vars; break;
466 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200467 case SCOPE_REQ:
468 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100469 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200470 }
471
472 /* Check if the scope is avalaible a this point of processing. */
473 if (vars->scope != var_desc->scope)
474 return 0;
475
476 /* Get the variable entry. */
477 var = var_get(vars, var_desc->name);
478 if (!var)
479 return 0;
480
481 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200482 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200483 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200484 return 1;
485}
486
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200487/* Always returns ACT_RET_CONT even if an error occurs. */
488static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200489 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200490{
491 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200492 int dir;
493
494 switch (rule->from) {
495 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
496 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
497 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
498 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
499 default:
500 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
501 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
502 Alert("Vars: internal error while execute action store.\n");
503 return ACT_RET_CONT;
504 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200505
506 /* Process the expression. */
507 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200508 if (!sample_process(px, s->sess, s, dir|SMP_OPT_FINAL,
509 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200510 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200511
512 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100513 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200514 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200515}
516
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200517/* This two function checks the variable name and replace the
518 * configuration string name by the global string name. its
519 * the same string, but the global pointer can be easy to
520 * compare.
521 *
522 * The first function checks a sample-fetch and the second
523 * checks a converter.
524 */
525static int smp_check_var(struct arg *args, char **err)
526{
527 return vars_check_arg(&args[0], err);
528}
529
530static int conv_check_var(struct arg *args, struct sample_conv *conv,
531 const char *file, int line, char **err_msg)
532{
533 return vars_check_arg(&args[0], err_msg);
534}
535
536/* This function is a common parser for using variables. It understands
537 * the format:
538 *
539 * set-var(<variable-name>) <expression>
540 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200541 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
542 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
543 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200544 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200545static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
546 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200547{
548 const char *var_name = args[*arg-1];
549 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200550 const char *kw_name;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200551 int flags;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200552
553 var_name += strlen("set-var");
554 if (*var_name != '(') {
555 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200556 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200557 }
558 var_name++; /* jump the '(' */
559 var_len = strlen(var_name);
560 var_len--; /* remove the ')' */
561 if (var_name[var_len] != ')') {
562 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200563 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200564 }
565
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200566 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, err);
567 if (!rule->arg.vars.name)
568 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200569
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200570 kw_name = args[*arg-1];
571
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200572 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
573 px->conf.args.line, err, &px->conf.args);
574 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200575 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200576
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200577 switch (rule->from) {
578 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
579 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
580 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
581 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
582 default:
583 memprintf(err,
584 "internal error, unexpected rule->from=%d, please report this bug!",
585 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200586 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200587 }
588 if (!(rule->arg.vars.expr->fetch->val & flags)) {
589 memprintf(err,
590 "fetch method '%s' extracts information from '%s', none of which is available here",
591 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
592 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200593 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200594 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200595
Thierry FOURNIER42148732015-09-02 17:17:33 +0200596 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200597 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200598 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200599}
600
601static int vars_max_size(char **args, int section_type, struct proxy *curpx,
602 struct proxy *defpx, const char *file, int line,
603 char **err, unsigned int *limit)
604{
605 char *error;
606
607 *limit = strtol(args[1], &error, 10);
608 if (*error != 0) {
609 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
610 return -1;
611 }
612 return 0;
613}
614
615static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
616 struct proxy *defpx, const char *file, int line,
617 char **err)
618{
619 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
620}
621
622static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
623 struct proxy *defpx, const char *file, int line,
624 char **err)
625{
626 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
627}
628
629static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
630 struct proxy *defpx, const char *file, int line,
631 char **err)
632{
633 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
634}
635
636static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
637 struct proxy *defpx, const char *file, int line,
638 char **err)
639{
640 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
641}
642
643static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
644
645 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_HTTP_ANY },
646 { /* END */ },
647}};
648
649static struct sample_conv_kw_list sample_conv_kws = {ILH, {
650 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
651 { /* END */ },
652}};
653
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200654static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200655 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200656 { /* END */ }
657}};
658
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200659static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200660 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200661 { /* END */ }
662}};
663
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200664static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200665 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200666 { /* END */ }
667}};
668
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200669static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200670 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200671 { /* END */ }
672}};
673
674static struct cfg_kw_list cfg_kws = {{ },{
675 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
676 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
677 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
678 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
679 { /* END */ }
680}};
681
682__attribute__((constructor))
683static void __http_protocol_init(void)
684{
685 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
686
687 sample_register_fetches(&sample_fetch_keywords);
688 sample_register_convs(&sample_conv_kws);
689 tcp_req_cont_keywords_register(&tcp_req_kws);
690 tcp_res_cont_keywords_register(&tcp_res_kws);
691 http_req_keywords_register(&http_req_kws);
692 http_res_keywords_register(&http_res_kws);
693 cfg_register_keywords(&cfg_kws);
694}