blob: 6f9b16aa976f5d1824bb21386ef3d3a775d90225 [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 Tarreau7513d002016-10-21 17:14:35 +0200245 case SCOPE_SESS:
246 vars = &smp->sess->vars;
247 break;
248 case SCOPE_TXN:
249 if (!smp->strm)
250 return 0;
251 vars = &smp->strm->vars_txn;
252 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200253 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200254 case SCOPE_RES:
Willy Tarreau7513d002016-10-21 17:14:35 +0200255 default:
256 if (!smp->strm)
257 return 0;
258 vars = &smp->strm->vars_reqres;
259 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200260 }
261 if (vars->scope != var_desc->scope)
262 return 0;
263 var = var_get(vars, var_desc->name);
264
265 /* check for the variable avalaibility */
266 if (!var)
267 return 0;
268
269 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200270 smp->data = var->data;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200271 smp->flags |= SMP_F_CONST;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200272 return 1;
273}
274
275/* This function search in the <head> a variable with the same
276 * pointer value that the <name>. If the variable doesn't exists,
277 * create it. The function stores a copy of smp> if the variable.
278 * It returns 0 if fails, else returns 1.
279 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100280static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200281{
282 struct var *var;
283
284 /* Look for existing variable name. */
285 var = var_get(vars, name);
286
287 if (var) {
288 /* free its used memory. */
289 if (var->data.type == SMP_T_STR ||
290 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200291 free(var->data.u.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100292 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200293 }
294 else if (var->data.type == SMP_T_METH) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200295 free(var->data.u.meth.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100296 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200297 }
298 } else {
299
300 /* Check memory avalaible. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100301 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302 return 0;
303
304 /* Create new entry. */
305 var = pool_alloc2(var_pool);
306 if (!var)
307 return 0;
308 LIST_ADDQ(&vars->head, &var->l);
309 var->name = name;
310 }
311
312 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200313 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200314
315 /* Copy data. If the data needs memory, the function can fail. */
316 switch (var->data.type) {
317 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200318 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200319 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200320 break;
321 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200322 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200323 break;
324 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200325 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200326 break;
327 case SMP_T_STR:
328 case SMP_T_BIN:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100329 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200330 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
331 return 0;
332 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200333 var->data.u.str.str = malloc(smp->data.u.str.len);
334 if (!var->data.u.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100335 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200336 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
337 return 0;
338 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200339 var->data.u.str.len = smp->data.u.str.len;
340 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200341 break;
342 case SMP_T_METH:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100343 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200344 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
345 return 0;
346 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200347 var->data.u.meth.str.str = malloc(smp->data.u.meth.str.len);
348 if (!var->data.u.meth.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100349 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200350 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
351 return 0;
352 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200353 var->data.u.meth.meth = smp->data.u.meth.meth;
354 var->data.u.meth.str.len = smp->data.u.meth.str.len;
355 var->data.u.meth.str.size = smp->data.u.meth.str.len;
356 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 +0200357 break;
358 }
359 return 1;
360}
361
Willy Tarreau620408f2016-10-21 16:37:51 +0200362/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100363static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200364{
365 struct vars *vars;
366
367 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100368 case SCOPE_SESS: vars = &smp->sess->vars; break;
369 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200370 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200371 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100372 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200373 }
374 if (vars->scope != scope)
375 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100376 return sample_store(vars, name, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200377}
378
379/* Returns 0 if fails, else returns 1. */
380static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
381{
Willy Tarreau6204cd92016-03-10 16:33:04 +0100382 return sample_store_stream(args[0].data.var.name, args[1].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200383}
384
385/* This fucntions check an argument entry and fill it with a variable
386 * type. The argumen must be a string. If the variable lookup fails,
387 * the function retuns 0 and fill <err>, otherwise it returns 1.
388 */
389int vars_check_arg(struct arg *arg, char **err)
390{
391 char *name;
392 enum vars_scope scope;
393
394 /* Check arg type. */
395 if (arg->type != ARGT_STR) {
396 memprintf(err, "unexpected argument type");
397 return 0;
398 }
399
400 /* Register new variable name. */
401 name = register_name(arg->data.str.str, arg->data.str.len, &scope, err);
402 if (!name)
403 return 0;
404
405 /* Use the global variable name pointer. */
406 arg->type = ARGT_VAR;
407 arg->data.var.name = name;
408 arg->data.var.scope = scope;
409 return 1;
410}
411
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200412/* This function store a sample in a variable.
413 * In error case, it fails silently.
414 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100415void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200416{
417 enum vars_scope scope;
418
419 /* Resolve name and scope. */
420 name = register_name(name, len, &scope, NULL);
421 if (!name)
422 return;
423
Willy Tarreau6204cd92016-03-10 16:33:04 +0100424 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200425}
426
427/* this function fills a sample with the
428 * variable content. Returns 1 if the sample
429 * is filled, otherwise it returns 0.
430 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100431int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200432{
433 struct vars *vars;
434 struct var *var;
435 enum vars_scope scope;
436
437 /* Resolve name and scope. */
438 name = register_name(name, len, &scope, NULL);
439 if (!name)
440 return 0;
441
442 /* Select "vars" pool according with the scope. */
443 switch (scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100444 case SCOPE_SESS: vars = &smp->sess->vars; break;
445 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200446 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200447 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100448 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200449 }
450
451 /* Check if the scope is avalaible a this point of processing. */
452 if (vars->scope != scope)
453 return 0;
454
455 /* Get the variable entry. */
456 var = var_get(vars, name);
457 if (!var)
458 return 0;
459
460 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200461 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200462 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200463 return 1;
464}
465
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200466/* this function fills a sample with the
467 * content of the varaible described by <var_desc>. Returns 1
468 * if the sample is filled, otherwise it returns 0.
469 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100470int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200471{
472 struct vars *vars;
473 struct var *var;
474
475 /* Select "vars" pool according with the scope. */
476 switch (var_desc->scope) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100477 case SCOPE_SESS: vars = &smp->sess->vars; break;
478 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200479 case SCOPE_REQ:
480 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100481 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200482 }
483
484 /* Check if the scope is avalaible a this point of processing. */
485 if (vars->scope != var_desc->scope)
486 return 0;
487
488 /* Get the variable entry. */
489 var = var_get(vars, var_desc->name);
490 if (!var)
491 return 0;
492
493 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200494 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200495 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200496 return 1;
497}
498
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200499/* Always returns ACT_RET_CONT even if an error occurs. */
500static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200501 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200502{
503 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200504 int dir;
505
506 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200507 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200508 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
509 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
510 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
511 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
512 default:
513 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
514 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
515 Alert("Vars: internal error while execute action store.\n");
516 return ACT_RET_CONT;
517 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200518
519 /* Process the expression. */
520 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200521 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200522 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200523 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200524
525 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100526 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200527 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200528}
529
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200530/* This two function checks the variable name and replace the
531 * configuration string name by the global string name. its
532 * the same string, but the global pointer can be easy to
533 * compare.
534 *
535 * The first function checks a sample-fetch and the second
536 * checks a converter.
537 */
538static int smp_check_var(struct arg *args, char **err)
539{
540 return vars_check_arg(&args[0], err);
541}
542
543static int conv_check_var(struct arg *args, struct sample_conv *conv,
544 const char *file, int line, char **err_msg)
545{
546 return vars_check_arg(&args[0], err_msg);
547}
548
549/* This function is a common parser for using variables. It understands
550 * the format:
551 *
552 * set-var(<variable-name>) <expression>
553 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200554 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
555 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
556 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200557 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200558static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
559 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200560{
561 const char *var_name = args[*arg-1];
562 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200563 const char *kw_name;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200564 int flags;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200565
566 var_name += strlen("set-var");
567 if (*var_name != '(') {
568 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200569 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200570 }
571 var_name++; /* jump the '(' */
572 var_len = strlen(var_name);
573 var_len--; /* remove the ')' */
574 if (var_name[var_len] != ')') {
575 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200576 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200577 }
578
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200579 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, err);
580 if (!rule->arg.vars.name)
581 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200582
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200583 kw_name = args[*arg-1];
584
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200585 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
586 px->conf.args.line, err, &px->conf.args);
587 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200588 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200589
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200590 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200591 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200592 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
593 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
594 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
595 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
596 default:
597 memprintf(err,
598 "internal error, unexpected rule->from=%d, please report this bug!",
599 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200600 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200601 }
602 if (!(rule->arg.vars.expr->fetch->val & flags)) {
603 memprintf(err,
604 "fetch method '%s' extracts information from '%s', none of which is available here",
605 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
606 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200607 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200608 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200609
Thierry FOURNIER42148732015-09-02 17:17:33 +0200610 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200611 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200612 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200613}
614
615static int vars_max_size(char **args, int section_type, struct proxy *curpx,
616 struct proxy *defpx, const char *file, int line,
617 char **err, unsigned int *limit)
618{
619 char *error;
620
621 *limit = strtol(args[1], &error, 10);
622 if (*error != 0) {
623 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
624 return -1;
625 }
626 return 0;
627}
628
629static int vars_max_size_global(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_global_limit);
634}
635
636static int vars_max_size_sess(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_sess_limit);
641}
642
643static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
644 struct proxy *defpx, const char *file, int line,
645 char **err)
646{
647 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
648}
649
650static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
651 struct proxy *defpx, const char *file, int line,
652 char **err)
653{
654 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
655}
656
657static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
658
Willy Tarreau87846e42016-10-21 17:17:18 +0200659 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L5CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200660 { /* END */ },
661}};
662
663static struct sample_conv_kw_list sample_conv_kws = {ILH, {
664 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
665 { /* END */ },
666}};
667
Willy Tarreau620408f2016-10-21 16:37:51 +0200668static struct action_kw_list tcp_req_sess_kws = { { }, {
669 { "set-var", parse_store, 1 },
670 { /* END */ }
671}};
672
673static struct action_kw_list tcp_req_cont_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200674 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200675 { /* END */ }
676}};
677
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200678static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200679 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200680 { /* END */ }
681}};
682
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200683static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200684 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200685 { /* END */ }
686}};
687
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200688static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200689 { "set-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200690 { /* END */ }
691}};
692
693static struct cfg_kw_list cfg_kws = {{ },{
694 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
695 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
696 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
697 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
698 { /* END */ }
699}};
700
701__attribute__((constructor))
702static void __http_protocol_init(void)
703{
704 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
705
706 sample_register_fetches(&sample_fetch_keywords);
707 sample_register_convs(&sample_conv_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +0200708 tcp_req_sess_keywords_register(&tcp_req_sess_kws);
709 tcp_req_cont_keywords_register(&tcp_req_cont_kws);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200710 tcp_res_cont_keywords_register(&tcp_res_kws);
711 http_req_keywords_register(&http_req_kws);
712 http_res_keywords_register(&http_res_kws);
713 cfg_register_keywords(&cfg_kws);
714}