blob: 8cc08399c315a6044c8c26fdf7bdcdbd0a5ba58e [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>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020010#include <proto/sample.h>
11#include <proto/stream.h>
Willy Tarreau39713102016-11-25 15:49:32 +010012#include <proto/tcp_rules.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;
Christopher Fauletff2613e2016-11-09 11:36:17 +010029static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020030static unsigned int var_sess_limit = 0;
31static unsigned int var_txn_limit = 0;
32static unsigned int var_reqres_limit = 0;
33
Willy Tarreau72330982015-06-19 11:21:56 +020034/* This function adds or remove memory size from the accounting. The inner
35 * pointers may be null when setting the outer ones only.
36 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010037static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020038{
39 switch (vars->scope) {
40 case SCOPE_REQ:
41 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010042 strm->vars_reqres.size += size;
43 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020044 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010045 strm->vars_txn.size += size;
46 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020047 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010048 sess->vars.size += size;
Christopher Fauletff2613e2016-11-09 11:36:17 +010049 /* fall through */
50 case SCOPE_PROC:
51 global.vars.size += size;
52 var_global_size += size;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020053 }
54}
55
56/* This function returns 1 if the <size> is available in the var
57 * pool <vars>, otherwise returns 0. If the space is avalaible,
Willy Tarreau72330982015-06-19 11:21:56 +020058 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010059 * the outer ones only. The accounting uses either <sess> or <strm>
60 * depending on the scope. <strm> may be NULL when no stream is known
61 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020062 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010063static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020064{
65 switch (vars->scope) {
66 case SCOPE_REQ:
67 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010068 if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_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_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010072 if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020073 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010074 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020075 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010076 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020077 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010078 /* fall through */
79 case SCOPE_PROC:
80 if (var_proc_limit && global.vars.size + size > var_proc_limit)
81 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020082 if (var_global_limit && var_global_size + size > var_global_limit)
83 return 0;
84 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010085 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020086 return 1;
87}
88
Christopher Faulet85d79c92016-11-09 16:54:56 +010089/* This fnuction remove a variable from the list and free memory it used */
90unsigned int var_clear(struct var *var)
91{
92 unsigned int size = 0;
93
94 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
95 free(var->data.u.str.str);
96 size += var->data.u.str.len;
97 }
Christopher Fauletd02210c2017-07-24 16:24:39 +020098 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Christopher Faulet85d79c92016-11-09 16:54:56 +010099 free(var->data.u.meth.str.str);
100 size += var->data.u.meth.str.len;
101 }
102 LIST_DEL(&var->l);
103 pool_free2(var_pool, var);
104 size += sizeof(struct var);
105 return size;
106}
107
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200108/* This function free all the memory used by all the varaibles
109 * in the list.
110 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100111void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112{
113 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200114 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200115
116 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100117 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200118 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100119 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200120}
121
Willy Tarreauebcd4842015-06-19 11:59:02 +0200122/* This function frees all the memory used by all the session variables in the
123 * list starting at <vars>.
124 */
125void vars_prune_per_sess(struct vars *vars)
126{
127 struct var *var, *tmp;
128 unsigned int size = 0;
129
130 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100131 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200132 }
Christopher Fauletff2613e2016-11-09 11:36:17 +0100133 vars->size -= size;
134 global.vars.size -= size;
135 var_global_size -= size;
Willy Tarreauebcd4842015-06-19 11:59:02 +0200136}
137
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200138/* This function init a list of variabes. */
139void vars_init(struct vars *vars, enum vars_scope scope)
140{
141 LIST_INIT(&vars->head);
142 vars->scope = scope;
143 vars->size = 0;
144}
145
146/* This function declares a new variable name. It returns a pointer
147 * on the string identifying the name. This function assures that
148 * the same name exists only once.
149 *
150 * This function check if the variable name is acceptable.
151 *
152 * The function returns NULL if an error occurs, and <err> is filled.
153 * In this case, the HAProxy must be stopped because the structs are
154 * left inconsistent. Otherwise, it returns the pointer on the global
155 * name.
156 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100157static char *register_name(const char *name, int len, enum vars_scope *scope,
158 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200159{
160 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200161 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200162 const char *tmp;
163
164 /* Check length. */
165 if (len == 0) {
166 memprintf(err, "Empty variable name cannot be accepted");
167 return NULL;
168 }
169
170 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100171 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
172 name += 5;
173 len -= 5;
174 *scope = SCOPE_PROC;
175 }
176 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200177 name += 5;
178 len -= 5;
179 *scope = SCOPE_SESS;
180 }
181 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
182 name += 4;
183 len -= 4;
184 *scope = SCOPE_TXN;
185 }
186 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
187 name += 4;
188 len -= 4;
189 *scope = SCOPE_REQ;
190 }
191 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
192 name += 4;
193 len -= 4;
194 *scope = SCOPE_RES;
195 }
196 else {
197 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Christopher Fauletff2613e2016-11-09 11:36:17 +0100198 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200199 return NULL;
200 }
201
202 /* Look for existing variable name. */
203 for (i = 0; i < var_names_nb; i++)
Thierry FOURNIER / OZON.IOd2f6f472016-12-12 12:42:14 +0100204 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0')
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200205 return var_names[i];
206
Christopher Faulet09c9df22016-10-31 11:05:37 +0100207 if (!alloc)
208 return NULL;
209
Hubert Verstraete831962e2016-06-28 22:44:26 +0200210 /* Store variable name. If realloc fails, var_names remains valid */
211 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
212 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200213 memprintf(err, "out of memory error");
214 return NULL;
215 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200216 var_names_nb++;
217 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200218 var_names[var_names_nb - 1] = malloc(len + 1);
219 if (!var_names[var_names_nb - 1]) {
220 memprintf(err, "out of memory error");
221 return NULL;
222 }
223 memcpy(var_names[var_names_nb - 1], name, len);
224 var_names[var_names_nb - 1][len] = '\0';
225
226 /* Check variable name syntax. */
227 tmp = var_names[var_names_nb - 1];
228 while (*tmp) {
Christopher Fauletb71557a2016-10-31 10:49:03 +0100229 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200230 memprintf(err, "invalid syntax at char '%s'", tmp);
231 return NULL;
232 }
233 tmp++;
234 }
235
236 /* Return the result. */
237 return var_names[var_names_nb - 1];
238}
239
240/* This function returns an existing variable or returns NULL. */
241static inline struct var *var_get(struct vars *vars, const char *name)
242{
243 struct var *var;
244
245 list_for_each_entry(var, &vars->head, l)
246 if (var->name == name)
247 return var;
248 return NULL;
249}
250
251/* Returns 0 if fails, else returns 1. */
252static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
253{
254 const struct var_desc *var_desc = &args[0].data.var;
255 struct var *var;
256 struct vars *vars;
257
258 /* Check the availibity of the variable. */
259 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100260 case SCOPE_PROC:
261 vars = &global.vars;
262 break;
Willy Tarreau7513d002016-10-21 17:14:35 +0200263 case SCOPE_SESS:
264 vars = &smp->sess->vars;
265 break;
266 case SCOPE_TXN:
267 if (!smp->strm)
268 return 0;
269 vars = &smp->strm->vars_txn;
270 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200271 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200272 case SCOPE_RES:
Willy Tarreau7513d002016-10-21 17:14:35 +0200273 default:
274 if (!smp->strm)
275 return 0;
276 vars = &smp->strm->vars_reqres;
277 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200278 }
279 if (vars->scope != var_desc->scope)
280 return 0;
281 var = var_get(vars, var_desc->name);
282
283 /* check for the variable avalaibility */
284 if (!var)
285 return 0;
286
287 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200288 smp->data = var->data;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200289 smp->flags |= SMP_F_CONST;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200290 return 1;
291}
292
293/* This function search in the <head> a variable with the same
294 * pointer value that the <name>. If the variable doesn't exists,
295 * create it. The function stores a copy of smp> if the variable.
296 * It returns 0 if fails, else returns 1.
297 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100298static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200299{
300 struct var *var;
301
302 /* Look for existing variable name. */
303 var = var_get(vars, name);
304
305 if (var) {
306 /* free its used memory. */
307 if (var->data.type == SMP_T_STR ||
308 var->data.type == SMP_T_BIN) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200309 free(var->data.u.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100310 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200311 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200312 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200313 free(var->data.u.meth.str.str);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100314 var_accounting_diff(vars, smp->sess, smp->strm, -var->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200315 }
316 } else {
317
318 /* Check memory avalaible. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100319 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200320 return 0;
321
322 /* Create new entry. */
323 var = pool_alloc2(var_pool);
324 if (!var)
325 return 0;
326 LIST_ADDQ(&vars->head, &var->l);
327 var->name = name;
328 }
329
330 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200331 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200332
333 /* Copy data. If the data needs memory, the function can fail. */
334 switch (var->data.type) {
335 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200336 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200337 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200338 break;
339 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200340 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200341 break;
342 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200343 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200344 break;
345 case SMP_T_STR:
346 case SMP_T_BIN:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100347 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200348 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
349 return 0;
350 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200351 var->data.u.str.str = malloc(smp->data.u.str.len);
352 if (!var->data.u.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100353 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200354 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
355 return 0;
356 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200357 var->data.u.str.len = smp->data.u.str.len;
358 memcpy(var->data.u.str.str, smp->data.u.str.str, var->data.u.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200359 break;
360 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200361 var->data.u.meth.meth = smp->data.u.meth.meth;
362 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
363 break;
364
Willy Tarreau6204cd92016-03-10 16:33:04 +0100365 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.len)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200366 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
367 return 0;
368 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200369 var->data.u.meth.str.str = malloc(smp->data.u.meth.str.len);
370 if (!var->data.u.meth.str.str) {
Willy Tarreau6204cd92016-03-10 16:33:04 +0100371 var_accounting_diff(vars, smp->sess, smp->strm, -smp->data.u.meth.str.len);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200372 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
373 return 0;
374 }
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200375 var->data.u.meth.str.len = smp->data.u.meth.str.len;
376 var->data.u.meth.str.size = smp->data.u.meth.str.len;
377 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 +0200378 break;
379 }
380 return 1;
381}
382
Willy Tarreau620408f2016-10-21 16:37:51 +0200383/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100384static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200385{
386 struct vars *vars;
387
388 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100389 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100390 case SCOPE_SESS: vars = &smp->sess->vars; break;
391 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200392 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200393 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100394 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200395 }
396 if (vars->scope != scope)
397 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100398 return sample_store(vars, name, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200399}
400
Christopher Faulet85d79c92016-11-09 16:54:56 +0100401/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
402static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
403{
404 struct vars *vars;
405 struct var *var;
406 unsigned int size = 0;
407
408 switch (scope) {
409 case SCOPE_PROC: vars = &global.vars; break;
410 case SCOPE_SESS: vars = &smp->sess->vars; break;
411 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
412 case SCOPE_REQ:
413 case SCOPE_RES:
414 default: vars = &smp->strm->vars_reqres; break;
415 }
416 if (vars->scope != scope)
417 return 0;
418
419 /* Look for existing variable name. */
420 var = var_get(vars, name);
421 if (var) {
422 size = var_clear(var);
423 var_accounting_diff(vars, smp->sess, smp->strm, -size);
424 }
425 return 1;
426}
427
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200428/* Returns 0 if fails, else returns 1. */
429static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
430{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100431 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200432}
433
Christopher Faulet85d79c92016-11-09 16:54:56 +0100434/* Returns 0 if fails, else returns 1. */
435static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
436{
437 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
438}
439
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200440/* This fucntions check an argument entry and fill it with a variable
441 * type. The argumen must be a string. If the variable lookup fails,
442 * the function retuns 0 and fill <err>, otherwise it returns 1.
443 */
444int vars_check_arg(struct arg *arg, char **err)
445{
446 char *name;
447 enum vars_scope scope;
448
449 /* Check arg type. */
450 if (arg->type != ARGT_STR) {
451 memprintf(err, "unexpected argument type");
452 return 0;
453 }
454
455 /* Register new variable name. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100456 name = register_name(arg->data.str.str, arg->data.str.len, &scope, 1, err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200457 if (!name)
458 return 0;
459
460 /* Use the global variable name pointer. */
461 arg->type = ARGT_VAR;
462 arg->data.var.name = name;
463 arg->data.var.scope = scope;
464 return 1;
465}
466
Christopher Faulet09c9df22016-10-31 11:05:37 +0100467/* This function store a sample in a variable if it was already defined.
468 * In error case, it fails silently.
469 */
470void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
471{
472 enum vars_scope scope;
473
474 /* Resolve name and scope. */
475 name = register_name(name, len, &scope, 0, NULL);
476 if (!name)
477 return;
478
479 sample_store_stream(name, scope, smp);
480}
481
482
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200483/* This function store a sample in a variable.
484 * In error case, it fails silently.
485 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100486void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200487{
488 enum vars_scope scope;
489
490 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100491 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200492 if (!name)
493 return;
494
Willy Tarreau6204cd92016-03-10 16:33:04 +0100495 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200496}
497
Christopher Faulet85d79c92016-11-09 16:54:56 +0100498/* This function unset a variable if it was already defined.
499 * In error case, it fails silently.
500 */
501void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
502{
503 enum vars_scope scope;
504
505 /* Resolve name and scope. */
506 name = register_name(name, len, &scope, 0, NULL);
507 if (!name)
508 return;
509
510 sample_clear_stream(name, scope, smp);
511}
512
513
514/* This function unset a variable.
515 * In error case, it fails silently.
516 */
517void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
518{
519 enum vars_scope scope;
520
521 /* Resolve name and scope. */
522 name = register_name(name, len, &scope, 1, NULL);
523 if (!name)
524 return;
525
526 sample_clear_stream(name, scope, smp);
527}
528
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200529/* this function fills a sample with the
530 * variable content. Returns 1 if the sample
531 * is filled, otherwise it returns 0.
532 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100533int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200534{
535 struct vars *vars;
536 struct var *var;
537 enum vars_scope scope;
538
539 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100540 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200541 if (!name)
542 return 0;
543
544 /* Select "vars" pool according with the scope. */
545 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100546 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100547 case SCOPE_SESS: vars = &smp->sess->vars; break;
548 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200549 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200550 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100551 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200552 }
553
554 /* Check if the scope is avalaible a this point of processing. */
555 if (vars->scope != scope)
556 return 0;
557
558 /* Get the variable entry. */
559 var = var_get(vars, name);
560 if (!var)
561 return 0;
562
563 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200564 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200565 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200566 return 1;
567}
568
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200569/* this function fills a sample with the
570 * content of the varaible described by <var_desc>. Returns 1
571 * if the sample is filled, otherwise it returns 0.
572 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100573int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200574{
575 struct vars *vars;
576 struct var *var;
577
578 /* Select "vars" pool according with the scope. */
579 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100580 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100581 case SCOPE_SESS: vars = &smp->sess->vars; break;
582 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200583 case SCOPE_REQ:
584 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100585 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200586 }
587
588 /* Check if the scope is avalaible a this point of processing. */
589 if (vars->scope != var_desc->scope)
590 return 0;
591
592 /* Get the variable entry. */
593 var = var_get(vars, var_desc->name);
594 if (!var)
595 return 0;
596
597 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200598 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200599 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200600 return 1;
601}
602
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200603/* Always returns ACT_RET_CONT even if an error occurs. */
604static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200605 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200606{
607 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200608 int dir;
609
610 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200611 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200612 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
613 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
614 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
615 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
616 default:
617 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
618 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
619 Alert("Vars: internal error while execute action store.\n");
620 return ACT_RET_CONT;
621 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200622
623 /* Process the expression. */
624 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200625 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200626 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200627 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200628
629 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100630 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200631 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200632}
633
Christopher Faulet85d79c92016-11-09 16:54:56 +0100634/* Always returns ACT_RET_CONT even if an error occurs. */
635static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
636 struct session *sess, struct stream *s, int flags)
637{
638 struct sample smp;
639
640 memset(&smp, 0, sizeof(smp));
641 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
642
643 /* Clear the variable using the sample context, and ignore errors. */
644 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
645 return ACT_RET_CONT;
646}
647
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200648/* This two function checks the variable name and replace the
649 * configuration string name by the global string name. its
650 * the same string, but the global pointer can be easy to
651 * compare.
652 *
653 * The first function checks a sample-fetch and the second
654 * checks a converter.
655 */
656static int smp_check_var(struct arg *args, char **err)
657{
658 return vars_check_arg(&args[0], err);
659}
660
661static int conv_check_var(struct arg *args, struct sample_conv *conv,
662 const char *file, int line, char **err_msg)
663{
664 return vars_check_arg(&args[0], err_msg);
665}
666
667/* This function is a common parser for using variables. It understands
668 * the format:
669 *
670 * set-var(<variable-name>) <expression>
671 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200672 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
673 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
674 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200675 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200676static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
677 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200678{
679 const char *var_name = args[*arg-1];
680 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200681 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100682 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200683
Christopher Faulet85d79c92016-11-09 16:54:56 +0100684 if (!strncmp(var_name, "set-var", 7)) {
685 var_name += 7;
686 set_var = 1;
687 }
688 if (!strncmp(var_name, "unset-var", 9)) {
689 var_name += 9;
690 set_var = 0;
691 }
692
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200693 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100694 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
695 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200696 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200697 }
698 var_name++; /* jump the '(' */
699 var_len = strlen(var_name);
700 var_len--; /* remove the ')' */
701 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100702 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
703 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200704 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200705 }
706
Christopher Faulet09c9df22016-10-31 11:05:37 +0100707 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200708 if (!rule->arg.vars.name)
709 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200710
Christopher Faulet85d79c92016-11-09 16:54:56 +0100711 /* There is no fetch method when variable is unset. Just set the right
712 * action and return. */
713 if (!set_var) {
714 if (*args[*arg]) {
715 memprintf(err, "fetch method not supported");
716 return ACT_RET_PRS_ERR;
717 }
718 rule->action = ACT_CUSTOM;
719 rule->action_ptr = action_clear;
720 return ACT_RET_PRS_OK;
721 }
722
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200723 kw_name = args[*arg-1];
724
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200725 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
726 px->conf.args.line, err, &px->conf.args);
727 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200728 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200729
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200730 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200731 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200732 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
733 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
734 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
735 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
736 default:
737 memprintf(err,
738 "internal error, unexpected rule->from=%d, please report this bug!",
739 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200740 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200741 }
742 if (!(rule->arg.vars.expr->fetch->val & flags)) {
743 memprintf(err,
744 "fetch method '%s' extracts information from '%s', none of which is available here",
745 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
746 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200747 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200748 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200749
Thierry FOURNIER42148732015-09-02 17:17:33 +0200750 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200751 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200752 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200753}
754
755static int vars_max_size(char **args, int section_type, struct proxy *curpx,
756 struct proxy *defpx, const char *file, int line,
757 char **err, unsigned int *limit)
758{
759 char *error;
760
761 *limit = strtol(args[1], &error, 10);
762 if (*error != 0) {
763 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
764 return -1;
765 }
766 return 0;
767}
768
769static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
770 struct proxy *defpx, const char *file, int line,
771 char **err)
772{
773 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
774}
775
Christopher Fauletff2613e2016-11-09 11:36:17 +0100776static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
777 struct proxy *defpx, const char *file, int line,
778 char **err)
779{
780 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
781}
782
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200783static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
784 struct proxy *defpx, const char *file, int line,
785 char **err)
786{
787 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
788}
789
790static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
791 struct proxy *defpx, const char *file, int line,
792 char **err)
793{
794 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
795}
796
797static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
798 struct proxy *defpx, const char *file, int line,
799 char **err)
800{
801 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
802}
803
804static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
805
Christopher Fauletff2613e2016-11-09 11:36:17 +0100806 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200807 { /* END */ },
808}};
809
810static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100811 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
812 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200813 { /* END */ },
814}};
815
Willy Tarreau620408f2016-10-21 16:37:51 +0200816static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100817 { "set-var", parse_store, 1 },
818 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200819 { /* END */ }
820}};
821
822static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100823 { "set-var", parse_store, 1 },
824 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200825 { /* END */ }
826}};
827
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200828static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100829 { "set-var", parse_store, 1 },
830 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200831 { /* END */ }
832}};
833
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200834static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100835 { "set-var", parse_store, 1 },
836 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200837 { /* END */ }
838}};
839
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200840static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100841 { "set-var", parse_store, 1 },
842 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200843 { /* END */ }
844}};
845
846static struct cfg_kw_list cfg_kws = {{ },{
847 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100848 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200849 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
850 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
851 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
852 { /* END */ }
853}};
854
855__attribute__((constructor))
856static void __http_protocol_init(void)
857{
858 var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
859
860 sample_register_fetches(&sample_fetch_keywords);
861 sample_register_convs(&sample_conv_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +0200862 tcp_req_sess_keywords_register(&tcp_req_sess_kws);
863 tcp_req_cont_keywords_register(&tcp_req_cont_kws);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200864 tcp_res_cont_keywords_register(&tcp_res_kws);
865 http_req_keywords_register(&http_req_kws);
866 http_res_keywords_register(&http_res_kws);
867 cfg_register_keywords(&cfg_kws);
868}