blob: 56fade5d9ffab1fb043f31fb17842345f02a81e0 [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;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200154 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200155 const char *tmp;
156
157 /* Check length. */
158 if (len == 0) {
159 memprintf(err, "Empty variable name cannot be accepted");
160 return NULL;
161 }
162
163 /* Check scope. */
164 if (len > 5 && strncmp(name, "sess.", 5) == 0) {
165 name += 5;
166 len -= 5;
167 *scope = SCOPE_SESS;
168 }
169 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
170 name += 4;
171 len -= 4;
172 *scope = SCOPE_TXN;
173 }
174 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
175 name += 4;
176 len -= 4;
177 *scope = SCOPE_REQ;
178 }
179 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
180 name += 4;
181 len -= 4;
182 *scope = SCOPE_RES;
183 }
184 else {
185 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
186 "The scope can be 'sess', 'txn', 'req' or 'res'", name);
187 return NULL;
188 }
189
190 /* Look for existing variable name. */
191 for (i = 0; i < var_names_nb; i++)
192 if (strncmp(var_names[i], name, len) == 0)
193 return var_names[i];
194
Hubert Verstraete831962e2016-06-28 22:44:26 +0200195 /* Store variable name. If realloc fails, var_names remains valid */
196 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
197 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200198 memprintf(err, "out of memory error");
199 return NULL;
200 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200201 var_names_nb++;
202 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200203 var_names[var_names_nb - 1] = malloc(len + 1);
204 if (!var_names[var_names_nb - 1]) {
205 memprintf(err, "out of memory error");
206 return NULL;
207 }
208 memcpy(var_names[var_names_nb - 1], name, len);
209 var_names[var_names_nb - 1][len] = '\0';
210
211 /* Check variable name syntax. */
212 tmp = var_names[var_names_nb - 1];
213 while (*tmp) {
214 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_') {
215 memprintf(err, "invalid syntax at char '%s'", tmp);
216 return NULL;
217 }
218 tmp++;
219 }
220
221 /* Return the result. */
222 return var_names[var_names_nb - 1];
223}
224
225/* This function returns an existing variable or returns NULL. */
226static inline struct var *var_get(struct vars *vars, const char *name)
227{
228 struct var *var;
229
230 list_for_each_entry(var, &vars->head, l)
231 if (var->name == name)
232 return var;
233 return NULL;
234}
235
236/* Returns 0 if fails, else returns 1. */
237static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
238{
239 const struct var_desc *var_desc = &args[0].data.var;
240 struct var *var;
241 struct vars *vars;
242
243 /* Check the availibity of the variable. */
244 switch (var_desc->scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100245 case SCOPE_SESS: vars = &smp->sess->vars; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200246 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
247 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200248 case SCOPE_RES:
249 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200250 }
251 if (vars->scope != var_desc->scope)
252 return 0;
253 var = var_get(vars, var_desc->name);
254
255 /* check for the variable avalaibility */
256 if (!var)
257 return 0;
258
259 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200260 smp->data = var->data;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200261 smp->flags |= SMP_F_CONST;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200262 return 1;
263}
264
265/* This function search in the <head> a variable with the same
266 * pointer value that the <name>. If the variable doesn't exists,
267 * create it. The function stores a copy of smp> if the variable.
268 * It returns 0 if fails, else returns 1.
269 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100270static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200271{
272 struct var *var;
273
274 /* Look for existing variable name. */
275 var = var_get(vars, name);
276
277 if (var) {
278 /* free its used memory. */
279 if (var->data.type == SMP_T_STR ||
280 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200281 free(var->data.u.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100282 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200283 }
284 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200285 free(var->data.u.meth.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100286 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200287 }
288 } else {
289
290 /* Check memory avalaible. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100291 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200292 return 0;
293
294 /* Create new entry. */
295 var = pool_alloc2(var_pool);
296 if (!var)
297 return 0;
298 LIST_ADDQ(&vars->head, &var->l);
299 var->name = name;
300 }
301
302 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200303 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200304
305 /* Copy data. If the data needs memory, the function can fail. */
306 switch (var->data.type) {
307 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200308 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200309 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200310 break;
311 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200312 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200313 break;
314 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200315 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200316 break;
317 case SMP_T_STR:
318 case SMP_T_BIN:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100319 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200320 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
321 return 0;
322 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200323 var->data.u.str.str = malloc(smp->data.u.str.len);
324 if (!var->data.u.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100325 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.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.str.len = smp->data.u.str.len;
330 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200331 break;
332 case SMP_T_METH:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100333 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200334 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
335 return 0;
336 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200337 var->data.u.meth.str.str = malloc(smp->data.u.meth.str.len);
338 if (!var->data.u.meth.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100339 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200340 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
341 return 0;
342 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200343 var->data.u.meth.meth = smp->data.u.meth.meth;
344 var->data.u.meth.str.len = smp->data.u.meth.str.len;
345 var->data.u.meth.str.size = smp->data.u.meth.str.len;
346 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 +0200347 break;
348 }
349 return 1;
350}
351
352/* Returns 0 if fails, else returns 1. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100353static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200354{
355 struct vars *vars;
356
357 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100358 case SCOPE_SESS: vars = &smp->sess->vars; break;
359 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200360 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200361 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100362 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200363 }
364 if (vars->scope != scope)
365 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100366 return sample_store(vars, name, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200367}
368
369/* Returns 0 if fails, else returns 1. */
370static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
371{
Willy Tarreau6204cd92016-03-10 16:33:04 +0100372 return sample_store_stream(args[0].data.var.name, args[1].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200373}
374
375/* This fucntions check an argument entry and fill it with a variable
376 * type. The argumen must be a string. If the variable lookup fails,
377 * the function retuns 0 and fill <err>, otherwise it returns 1.
378 */
379int vars_check_arg(struct arg *arg, char **err)
380{
381 char *name;
382 enum vars_scope scope;
383
384 /* Check arg type. */
385 if (arg->type != ARGT_STR) {
386 memprintf(err, "unexpected argument type");
387 return 0;
388 }
389
390 /* Register new variable name. */
391 name = register_name(arg->data.str.str, arg->data.str.len, &scope, err);
392 if (!name)
393 return 0;
394
395 /* Use the global variable name pointer. */
396 arg->type = ARGT_VAR;
397 arg->data.var.name = name;
398 arg->data.var.scope = scope;
399 return 1;
400}
401
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200402/* This function store a sample in a variable.
403 * In error case, it fails silently.
404 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100405void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200406{
407 enum vars_scope scope;
408
409 /* Resolve name and scope. */
410 name = register_name(name, len, &scope, NULL);
411 if (!name)
412 return;
413
Willy Tarreau6204cd92016-03-10 16:33:04 +0100414 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200415}
416
417/* this function fills a sample with the
418 * variable content. Returns 1 if the sample
419 * is filled, otherwise it returns 0.
420 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100421int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200422{
423 struct vars *vars;
424 struct var *var;
425 enum vars_scope scope;
426
427 /* Resolve name and scope. */
428 name = register_name(name, len, &scope, NULL);
429 if (!name)
430 return 0;
431
432 /* Select "vars" pool according with the scope. */
433 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100434 case SCOPE_SESS: vars = &smp->sess->vars; break;
435 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200436 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200437 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100438 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200439 }
440
441 /* Check if the scope is avalaible a this point of processing. */
442 if (vars->scope != scope)
443 return 0;
444
445 /* Get the variable entry. */
446 var = var_get(vars, name);
447 if (!var)
448 return 0;
449
450 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200451 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200452 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200453 return 1;
454}
455
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200456/* this function fills a sample with the
457 * content of the varaible described by <var_desc>. Returns 1
458 * if the sample is filled, otherwise it returns 0.
459 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100460int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200461{
462 struct vars *vars;
463 struct var *var;
464
465 /* Select "vars" pool according with the scope. */
466 switch (var_desc->scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100467 case SCOPE_SESS: vars = &smp->sess->vars; break;
468 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200469 case SCOPE_REQ:
470 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100471 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200472 }
473
474 /* Check if the scope is avalaible a this point of processing. */
475 if (vars->scope != var_desc->scope)
476 return 0;
477
478 /* Get the variable entry. */
479 var = var_get(vars, var_desc->name);
480 if (!var)
481 return 0;
482
483 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200484 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200485 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200486 return 1;
487}
488
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200489/* Always returns ACT_RET_CONT even if an error occurs. */
490static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200491 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200492{
493 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200494 int dir;
495
496 switch (rule->from) {
497 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
498 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
499 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
500 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
501 default:
502 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
503 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
504 Alert("Vars: internal error while execute action store.\n");
505 return ACT_RET_CONT;
506 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200507
508 /* Process the expression. */
509 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200510 if (!sample_process(px, s->sess, s, dir|SMP_OPT_FINAL,
511 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200512 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200513
514 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100515 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200516 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200517}
518
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200519/* This two function checks the variable name and replace the
520 * configuration string name by the global string name. its
521 * the same string, but the global pointer can be easy to
522 * compare.
523 *
524 * The first function checks a sample-fetch and the second
525 * checks a converter.
526 */
527static int smp_check_var(struct arg *args, char **err)
528{
529 return vars_check_arg(&args[0], err);
530}
531
532static int conv_check_var(struct arg *args, struct sample_conv *conv,
533 const char *file, int line, char **err_msg)
534{
535 return vars_check_arg(&args[0], err_msg);
536}
537
538/* This function is a common parser for using variables. It understands
539 * the format:
540 *
541 * set-var(<variable-name>) <expression>
542 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200543 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
544 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
545 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200546 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200547static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
548 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200549{
550 const char *var_name = args[*arg-1];
551 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200552 const char *kw_name;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200553 int flags;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200554
555 var_name += strlen("set-var");
556 if (*var_name != '(') {
557 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200558 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200559 }
560 var_name++; /* jump the '(' */
561 var_len = strlen(var_name);
562 var_len--; /* remove the ')' */
563 if (var_name[var_len] != ')') {
564 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200565 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200566 }
567
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200568 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, err);
569 if (!rule->arg.vars.name)
570 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200571
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200572 kw_name = args[*arg-1];
573
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200574 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
575 px->conf.args.line, err, &px->conf.args);
576 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200577 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200578
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200579 switch (rule->from) {
580 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
581 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
582 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
583 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
584 default:
585 memprintf(err,
586 "internal error, unexpected rule->from=%d, please report this bug!",
587 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200588 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200589 }
590 if (!(rule->arg.vars.expr->fetch->val & flags)) {
591 memprintf(err,
592 "fetch method '%s' extracts information from '%s', none of which is available here",
593 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
594 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200595 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200596 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200597
Thierry FOURNIER42148732015-09-02 17:17:33 +0200598 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200599 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200600 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200601}
602
603static int vars_max_size(char **args, int section_type, struct proxy *curpx,
604 struct proxy *defpx, const char *file, int line,
605 char **err, unsigned int *limit)
606{
607 char *error;
608
609 *limit = strtol(args[1], &error, 10);
610 if (*error != 0) {
611 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
612 return -1;
613 }
614 return 0;
615}
616
617static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
618 struct proxy *defpx, const char *file, int line,
619 char **err)
620{
621 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
622}
623
624static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
625 struct proxy *defpx, const char *file, int line,
626 char **err)
627{
628 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
629}
630
631static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
632 struct proxy *defpx, const char *file, int line,
633 char **err)
634{
635 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
636}
637
638static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
639 struct proxy *defpx, const char *file, int line,
640 char **err)
641{
642 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
643}
644
645static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
646
647 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_HTTP_ANY },
648 { /* END */ },
649}};
650
651static struct sample_conv_kw_list sample_conv_kws = {ILH, {
652 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
653 { /* END */ },
654}};
655
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200656static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200657 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200658 { /* END */ }
659}};
660
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200661static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200662 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200663 { /* END */ }
664}};
665
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200666static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200667 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200668 { /* END */ }
669}};
670
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200671static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200672 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200673 { /* END */ }
674}};
675
676static struct cfg_kw_list cfg_kws = {{ },{
677 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
678 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
679 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
680 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
681 { /* END */ }
682}};
683
684__attribute__((constructor))
685static void __http_protocol_init(void)
686{
687 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
688
689 sample_register_fetches(&sample_fetch_keywords);
690 sample_register_convs(&sample_conv_kws);
691 tcp_req_cont_keywords_register(&tcp_req_kws);
692 tcp_res_cont_keywords_register(&tcp_res_kws);
693 http_req_keywords_register(&http_req_kws);
694 http_res_keywords_register(&http_res_kws);
695 cfg_register_keywords(&cfg_kws);
696}