blob: ae7e082d0f8887a9c52a84f28fee4c3038dc2109 [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#include <ctype.h>
2
3#include <common/cfgparse.h>
Willy Tarreau35b51c62018-09-10 15:38:55 +02004#include <common/http.h>
Willy Tarreau0108d902018-11-25 19:14:37 +01005#include <common/initcall.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02006#include <common/mini-clist.h>
7
8#include <types/vars.h>
9
10#include <proto/arg.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020011#include <proto/http_rules.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020012#include <proto/proto_http.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020013#include <proto/sample.h>
14#include <proto/stream.h>
Willy Tarreau39713102016-11-25 15:49:32 +010015#include <proto/tcp_rules.h>
Willy Tarreauebcd4842015-06-19 11:59:02 +020016#include <proto/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020017
18/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010019DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020020
21/* This array contain all the names of all the HAProxy vars.
22 * This permits to identify two variables name with
23 * only one pointer. It permits to not using strdup() for
24 * each variable name used during the runtime.
25 */
26static char **var_names = NULL;
27static int var_names_nb = 0;
28
29/* This array of int contains the system limits per context. */
30static unsigned int var_global_limit = 0;
31static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010032static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020033static unsigned int var_sess_limit = 0;
34static unsigned int var_txn_limit = 0;
35static unsigned int var_reqres_limit = 0;
36
Willy Tarreau86abe442018-11-25 20:12:18 +010037__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020038
Willy Tarreau72330982015-06-19 11:21:56 +020039/* This function adds or remove memory size from the accounting. The inner
40 * pointers may be null when setting the outer ones only.
41 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010042static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020043{
44 switch (vars->scope) {
45 case SCOPE_REQ:
46 case SCOPE_RES:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010047 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010048 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020049 case SCOPE_TXN:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010050 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010051 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020052 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010053 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010054 /* fall through */
55 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010056 _HA_ATOMIC_ADD(&global.vars.size, size);
57 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020058 }
59}
60
61/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080062 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020063 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010064 * the outer ones only. The accounting uses either <sess> or <strm>
65 * depending on the scope. <strm> may be NULL when no stream is known
66 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020067 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010068static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020069{
70 switch (vars->scope) {
71 case SCOPE_REQ:
72 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +010073 if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020074 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010075 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020076 case SCOPE_TXN:
Willy Tarreau6204cd92016-03-10 16:33:04 +010077 if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020078 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +010079 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020080 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +010081 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020082 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010083 /* fall through */
84 case SCOPE_PROC:
85 if (var_proc_limit && global.vars.size + size > var_proc_limit)
86 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020087 if (var_global_limit && var_global_size + size > var_global_limit)
88 return 0;
89 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010090 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020091 return 1;
92}
93
Christopher Faulet85d79c92016-11-09 16:54:56 +010094/* This fnuction remove a variable from the list and free memory it used */
95unsigned int var_clear(struct var *var)
96{
97 unsigned int size = 0;
98
99 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200100 free(var->data.u.str.area);
101 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100102 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200103 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200104 free(var->data.u.meth.str.area);
105 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100106 }
107 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100108 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100109 size += sizeof(struct var);
110 return size;
111}
112
Joseph Herlant07676892018-11-15 09:19:50 -0800113/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200114 * in the list.
115 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100116void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200117{
118 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200119 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200120
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100121 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200122 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100123 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200124 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100125 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100126 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200127}
128
Willy Tarreauebcd4842015-06-19 11:59:02 +0200129/* This function frees all the memory used by all the session variables in the
130 * list starting at <vars>.
131 */
132void vars_prune_per_sess(struct vars *vars)
133{
134 struct var *var, *tmp;
135 unsigned int size = 0;
136
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100137 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200138 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100139 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200140 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100141 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200142
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100143 _HA_ATOMIC_SUB(&vars->size, size);
144 _HA_ATOMIC_SUB(&global.vars.size, size);
145 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200146}
147
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200148/* This function init a list of variabes. */
149void vars_init(struct vars *vars, enum vars_scope scope)
150{
151 LIST_INIT(&vars->head);
152 vars->scope = scope;
153 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100154 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200155}
156
157/* This function declares a new variable name. It returns a pointer
158 * on the string identifying the name. This function assures that
159 * the same name exists only once.
160 *
161 * This function check if the variable name is acceptable.
162 *
163 * The function returns NULL if an error occurs, and <err> is filled.
164 * In this case, the HAProxy must be stopped because the structs are
165 * left inconsistent. Otherwise, it returns the pointer on the global
166 * name.
167 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100168static char *register_name(const char *name, int len, enum vars_scope *scope,
169 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200170{
171 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200172 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200173 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200174 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200175
176 /* Check length. */
177 if (len == 0) {
178 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100179 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200180 }
181
182 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100183 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
184 name += 5;
185 len -= 5;
186 *scope = SCOPE_PROC;
187 }
188 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200189 name += 5;
190 len -= 5;
191 *scope = SCOPE_SESS;
192 }
193 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
194 name += 4;
195 len -= 4;
196 *scope = SCOPE_TXN;
197 }
198 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
199 name += 4;
200 len -= 4;
201 *scope = SCOPE_REQ;
202 }
203 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
204 name += 4;
205 len -= 4;
206 *scope = SCOPE_RES;
207 }
208 else {
209 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Christopher Fauletff2613e2016-11-09 11:36:17 +0100210 "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100211 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200212 }
213
Christopher Faulete95f2c32017-07-24 16:30:34 +0200214 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100215 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200216 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100217 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200218
219
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200220 /* Look for existing variable name. */
221 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200222 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
223 res = var_names[i];
224 goto end;
225 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200226
Christopher Faulete95f2c32017-07-24 16:30:34 +0200227 if (!alloc) {
228 res = NULL;
229 goto end;
230 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100231
Hubert Verstraete831962e2016-06-28 22:44:26 +0200232 /* Store variable name. If realloc fails, var_names remains valid */
233 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
234 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200235 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200236 res = NULL;
237 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200238 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200239 var_names_nb++;
240 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200241 var_names[var_names_nb - 1] = malloc(len + 1);
242 if (!var_names[var_names_nb - 1]) {
243 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200244 res = NULL;
245 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200246 }
247 memcpy(var_names[var_names_nb - 1], name, len);
248 var_names[var_names_nb - 1][len] = '\0';
249
250 /* Check variable name syntax. */
251 tmp = var_names[var_names_nb - 1];
252 while (*tmp) {
Christopher Fauletb71557a2016-10-31 10:49:03 +0100253 if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200254 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200255 res = NULL;
256 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200257 }
258 tmp++;
259 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200260 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200261
Christopher Faulete95f2c32017-07-24 16:30:34 +0200262 end:
263 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100264 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200265 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100266 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200267
268 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200269}
270
271/* This function returns an existing variable or returns NULL. */
272static inline struct var *var_get(struct vars *vars, const char *name)
273{
274 struct var *var;
275
276 list_for_each_entry(var, &vars->head, l)
277 if (var->name == name)
278 return var;
279 return NULL;
280}
281
282/* Returns 0 if fails, else returns 1. */
283static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
284{
285 const struct var_desc *var_desc = &args[0].data.var;
286 struct var *var;
287 struct vars *vars;
288
289 /* Check the availibity of the variable. */
290 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100291 case SCOPE_PROC:
292 vars = &global.vars;
293 break;
Willy Tarreau7513d002016-10-21 17:14:35 +0200294 case SCOPE_SESS:
295 vars = &smp->sess->vars;
296 break;
297 case SCOPE_TXN:
298 if (!smp->strm)
299 return 0;
300 vars = &smp->strm->vars_txn;
301 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200303 case SCOPE_RES:
Willy Tarreau7513d002016-10-21 17:14:35 +0200304 default:
305 if (!smp->strm)
306 return 0;
307 vars = &smp->strm->vars_reqres;
308 break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200309 }
310 if (vars->scope != var_desc->scope)
311 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200312
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100313 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200314 var = var_get(vars, var_desc->name);
315
316 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200317 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100318 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200319 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200320 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200321
Christopher Faulete95f2c32017-07-24 16:30:34 +0200322 /* Duplicate the sample data because it could modified by another
323 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200324 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200325 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200326 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200327
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100328 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200329 return 1;
330}
331
332/* This function search in the <head> a variable with the same
333 * pointer value that the <name>. If the variable doesn't exists,
334 * create it. The function stores a copy of smp> if the variable.
335 * It returns 0 if fails, else returns 1.
336 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100337static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200338{
339 struct var *var;
340
341 /* Look for existing variable name. */
342 var = var_get(vars, name);
343
344 if (var) {
345 /* free its used memory. */
346 if (var->data.type == SMP_T_STR ||
347 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200348 free(var->data.u.str.area);
349 var_accounting_diff(vars, smp->sess, smp->strm,
350 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200351 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200352 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200353 free(var->data.u.meth.str.area);
354 var_accounting_diff(vars, smp->sess, smp->strm,
355 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200356 }
357 } else {
358
Joseph Herlant07676892018-11-15 09:19:50 -0800359 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100360 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200361 return 0;
362
363 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100364 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200365 if (!var)
366 return 0;
367 LIST_ADDQ(&vars->head, &var->l);
368 var->name = name;
369 }
370
371 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200372 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200373
374 /* Copy data. If the data needs memory, the function can fail. */
375 switch (var->data.type) {
376 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200377 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200378 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200379 break;
380 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200381 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200382 break;
383 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200384 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200385 break;
386 case SMP_T_STR:
387 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200388 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200389 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
390 return 0;
391 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200392 var->data.u.str.area = malloc(smp->data.u.str.data);
393 if (!var->data.u.str.area) {
394 var_accounting_diff(vars, smp->sess, smp->strm,
395 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200396 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
397 return 0;
398 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200399 var->data.u.str.data = smp->data.u.str.data;
400 memcpy(var->data.u.str.area, smp->data.u.str.area,
401 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200402 break;
403 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200404 var->data.u.meth.meth = smp->data.u.meth.meth;
405 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
406 break;
407
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200408 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200409 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
410 return 0;
411 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200412 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
413 if (!var->data.u.meth.str.area) {
414 var_accounting_diff(vars, smp->sess, smp->strm,
415 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200416 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
417 return 0;
418 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200419 var->data.u.meth.str.data = smp->data.u.meth.str.data;
420 var->data.u.meth.str.size = smp->data.u.meth.str.data;
421 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
422 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200423 break;
424 }
425 return 1;
426}
427
Willy Tarreau620408f2016-10-21 16:37:51 +0200428/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100429static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200430{
431 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200432 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200433
434 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100435 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100436 case SCOPE_SESS: vars = &smp->sess->vars; break;
437 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200438 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200439 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100440 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200441 }
442 if (vars->scope != scope)
443 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200444
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100445 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200446 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100447 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200448 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200449}
450
Christopher Faulet85d79c92016-11-09 16:54:56 +0100451/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
452static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
453{
454 struct vars *vars;
455 struct var *var;
456 unsigned int size = 0;
457
458 switch (scope) {
459 case SCOPE_PROC: vars = &global.vars; break;
460 case SCOPE_SESS: vars = &smp->sess->vars; break;
461 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
462 case SCOPE_REQ:
463 case SCOPE_RES:
464 default: vars = &smp->strm->vars_reqres; break;
465 }
466 if (vars->scope != scope)
467 return 0;
468
469 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100470 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100471 var = var_get(vars, name);
472 if (var) {
473 size = var_clear(var);
474 var_accounting_diff(vars, smp->sess, smp->strm, -size);
475 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100476 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100477 return 1;
478}
479
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200480/* Returns 0 if fails, else returns 1. */
481static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
482{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100483 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200484}
485
Christopher Faulet85d79c92016-11-09 16:54:56 +0100486/* Returns 0 if fails, else returns 1. */
487static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
488{
489 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
490}
491
Joseph Herlant07676892018-11-15 09:19:50 -0800492/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200493 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800494 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200495 */
496int vars_check_arg(struct arg *arg, char **err)
497{
498 char *name;
499 enum vars_scope scope;
500
501 /* Check arg type. */
502 if (arg->type != ARGT_STR) {
503 memprintf(err, "unexpected argument type");
504 return 0;
505 }
506
507 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200508 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
509 1,
510 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200511 if (!name)
512 return 0;
513
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200514 /* properly destroy the chunk */
515 chunk_destroy(&arg->data.str);
516
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200517 /* Use the global variable name pointer. */
518 arg->type = ARGT_VAR;
519 arg->data.var.name = name;
520 arg->data.var.scope = scope;
521 return 1;
522}
523
Christopher Faulet09c9df22016-10-31 11:05:37 +0100524/* This function store a sample in a variable if it was already defined.
525 * In error case, it fails silently.
526 */
527void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
528{
529 enum vars_scope scope;
530
531 /* Resolve name and scope. */
532 name = register_name(name, len, &scope, 0, NULL);
533 if (!name)
534 return;
535
536 sample_store_stream(name, scope, smp);
537}
538
539
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200540/* This function store a sample in a variable.
541 * In error case, it fails silently.
542 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100543void vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200544{
545 enum vars_scope scope;
546
547 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100548 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200549 if (!name)
550 return;
551
Willy Tarreau6204cd92016-03-10 16:33:04 +0100552 sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200553}
554
Christopher Faulet85d79c92016-11-09 16:54:56 +0100555/* This function unset a variable if it was already defined.
556 * In error case, it fails silently.
557 */
558void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
559{
560 enum vars_scope scope;
561
562 /* Resolve name and scope. */
563 name = register_name(name, len, &scope, 0, NULL);
564 if (!name)
565 return;
566
567 sample_clear_stream(name, scope, smp);
568}
569
570
571/* This function unset a variable.
572 * In error case, it fails silently.
573 */
574void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
575{
576 enum vars_scope scope;
577
578 /* Resolve name and scope. */
579 name = register_name(name, len, &scope, 1, NULL);
580 if (!name)
581 return;
582
583 sample_clear_stream(name, scope, smp);
584}
585
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200586/* this function fills a sample with the
587 * variable content. Returns 1 if the sample
588 * is filled, otherwise it returns 0.
589 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100590int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200591{
592 struct vars *vars;
593 struct var *var;
594 enum vars_scope scope;
595
596 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100597 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200598 if (!name)
599 return 0;
600
601 /* Select "vars" pool according with the scope. */
602 switch (scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100603 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100604 case SCOPE_SESS: vars = &smp->sess->vars; break;
605 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200606 case SCOPE_REQ:
Thierry FOURNIER0b243fd2015-06-16 23:52:47 +0200607 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100608 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200609 }
610
Joseph Herlant07676892018-11-15 09:19:50 -0800611 /* Check if the scope is available a this point of processing. */
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200612 if (vars->scope != scope)
613 return 0;
614
615 /* Get the variable entry. */
616 var = var_get(vars, name);
617 if (!var)
618 return 0;
619
620 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200621 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200622 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200623 return 1;
624}
625
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200626/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800627 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200628 * if the sample is filled, otherwise it returns 0.
629 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100630int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200631{
632 struct vars *vars;
633 struct var *var;
634
635 /* Select "vars" pool according with the scope. */
636 switch (var_desc->scope) {
Christopher Fauletff2613e2016-11-09 11:36:17 +0100637 case SCOPE_PROC: vars = &global.vars; break;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100638 case SCOPE_SESS: vars = &smp->sess->vars; break;
639 case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200640 case SCOPE_REQ:
641 case SCOPE_RES:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100642 default: vars = &smp->strm->vars_reqres; break;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200643 }
644
Joseph Herlant07676892018-11-15 09:19:50 -0800645 /* Check if the scope is available a this point of processing. */
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200646 if (vars->scope != var_desc->scope)
647 return 0;
648
649 /* Get the variable entry. */
650 var = var_get(vars, var_desc->name);
651 if (!var)
652 return 0;
653
654 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200655 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200656 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200657 return 1;
658}
659
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200660/* Always returns ACT_RET_CONT even if an error occurs. */
661static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200662 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200663{
664 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200665 int dir;
666
667 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200668 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200669 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
670 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
671 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
672 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
673 default:
674 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
675 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100676 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200677 return ACT_RET_CONT;
678 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200679
680 /* Process the expression. */
681 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200682 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200683 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200684 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200685
686 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100687 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200688 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200689}
690
Christopher Faulet85d79c92016-11-09 16:54:56 +0100691/* Always returns ACT_RET_CONT even if an error occurs. */
692static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
693 struct session *sess, struct stream *s, int flags)
694{
695 struct sample smp;
696
697 memset(&smp, 0, sizeof(smp));
698 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
699
700 /* Clear the variable using the sample context, and ignore errors. */
701 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
702 return ACT_RET_CONT;
703}
704
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200705/* This two function checks the variable name and replace the
706 * configuration string name by the global string name. its
707 * the same string, but the global pointer can be easy to
708 * compare.
709 *
710 * The first function checks a sample-fetch and the second
711 * checks a converter.
712 */
713static int smp_check_var(struct arg *args, char **err)
714{
715 return vars_check_arg(&args[0], err);
716}
717
718static int conv_check_var(struct arg *args, struct sample_conv *conv,
719 const char *file, int line, char **err_msg)
720{
721 return vars_check_arg(&args[0], err_msg);
722}
723
724/* This function is a common parser for using variables. It understands
725 * the format:
726 *
727 * set-var(<variable-name>) <expression>
728 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200729 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
730 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
731 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200732 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200733static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
734 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200735{
736 const char *var_name = args[*arg-1];
737 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200738 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100739 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200740
Christopher Faulet85d79c92016-11-09 16:54:56 +0100741 if (!strncmp(var_name, "set-var", 7)) {
742 var_name += 7;
743 set_var = 1;
744 }
745 if (!strncmp(var_name, "unset-var", 9)) {
746 var_name += 9;
747 set_var = 0;
748 }
749
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200750 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100751 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
752 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200753 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200754 }
755 var_name++; /* jump the '(' */
756 var_len = strlen(var_name);
757 var_len--; /* remove the ')' */
758 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100759 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
760 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200761 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200762 }
763
Christopher Faulet09c9df22016-10-31 11:05:37 +0100764 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200765 if (!rule->arg.vars.name)
766 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200767
Christopher Faulet85d79c92016-11-09 16:54:56 +0100768 /* There is no fetch method when variable is unset. Just set the right
769 * action and return. */
770 if (!set_var) {
771 if (*args[*arg]) {
772 memprintf(err, "fetch method not supported");
773 return ACT_RET_PRS_ERR;
774 }
775 rule->action = ACT_CUSTOM;
776 rule->action_ptr = action_clear;
777 return ACT_RET_PRS_OK;
778 }
779
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200780 kw_name = args[*arg-1];
781
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200782 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
783 px->conf.args.line, err, &px->conf.args);
784 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200785 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200786
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200787 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200788 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200789 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
790 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
791 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
792 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
793 default:
794 memprintf(err,
795 "internal error, unexpected rule->from=%d, please report this bug!",
796 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200797 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200798 }
799 if (!(rule->arg.vars.expr->fetch->val & flags)) {
800 memprintf(err,
801 "fetch method '%s' extracts information from '%s', none of which is available here",
802 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
803 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200804 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200805 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200806
Thierry FOURNIER42148732015-09-02 17:17:33 +0200807 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200808 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200809 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200810}
811
812static int vars_max_size(char **args, int section_type, struct proxy *curpx,
813 struct proxy *defpx, const char *file, int line,
814 char **err, unsigned int *limit)
815{
816 char *error;
817
818 *limit = strtol(args[1], &error, 10);
819 if (*error != 0) {
820 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
821 return -1;
822 }
823 return 0;
824}
825
826static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
827 struct proxy *defpx, const char *file, int line,
828 char **err)
829{
830 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
831}
832
Christopher Fauletff2613e2016-11-09 11:36:17 +0100833static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
834 struct proxy *defpx, const char *file, int line,
835 char **err)
836{
837 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
838}
839
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200840static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
841 struct proxy *defpx, const char *file, int line,
842 char **err)
843{
844 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
845}
846
847static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
848 struct proxy *defpx, const char *file, int line,
849 char **err)
850{
851 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
852}
853
854static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
855 struct proxy *defpx, const char *file, int line,
856 char **err)
857{
858 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
859}
860
861static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
862
Christopher Fauletff2613e2016-11-09 11:36:17 +0100863 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200864 { /* END */ },
865}};
866
Willy Tarreau0108d902018-11-25 19:14:37 +0100867INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
868
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200869static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100870 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
871 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200872 { /* END */ },
873}};
874
Willy Tarreau0108d902018-11-25 19:14:37 +0100875INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
876
Willy Tarreau620408f2016-10-21 16:37:51 +0200877static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100878 { "set-var", parse_store, 1 },
879 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200880 { /* END */ }
881}};
882
Willy Tarreau0108d902018-11-25 19:14:37 +0100883INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
884
Willy Tarreau620408f2016-10-21 16:37:51 +0200885static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100886 { "set-var", parse_store, 1 },
887 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200888 { /* END */ }
889}};
890
Willy Tarreau0108d902018-11-25 19:14:37 +0100891INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
892
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200893static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100894 { "set-var", parse_store, 1 },
895 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200896 { /* END */ }
897}};
898
Willy Tarreau0108d902018-11-25 19:14:37 +0100899INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
900
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200901static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100902 { "set-var", parse_store, 1 },
903 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200904 { /* END */ }
905}};
906
Willy Tarreau0108d902018-11-25 19:14:37 +0100907INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
908
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200909static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100910 { "set-var", parse_store, 1 },
911 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200912 { /* END */ }
913}};
914
Willy Tarreau0108d902018-11-25 19:14:37 +0100915INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
916
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200917static struct cfg_kw_list cfg_kws = {{ },{
918 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100919 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200920 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
921 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
922 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
923 { /* END */ }
924}};
925
Willy Tarreau0108d902018-11-25 19:14:37 +0100926INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);