blob: 53afe1a41f15630d5309f33c0925120a649a194d [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#include <ctype.h>
2
Willy Tarreaudfd3de82020-06-04 23:46:14 +02003#include <haproxy/arg.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +02004#include <haproxy/api.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02005#include <common/cfgparse.h>
Willy Tarreau4aa573d2020-06-04 18:21:56 +02006#include <haproxy/check.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +02007#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +02008#include <haproxy/http.h>
Willy Tarreauc761f842020-06-04 11:40:28 +02009#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020010#include <haproxy/list.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020011#include <haproxy/sample.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020012#include <haproxy/stream-t.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020013#include <haproxy/tcp_rules.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020014#include <haproxy/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020015
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020016
17/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010018DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020019
20/* This array contain all the names of all the HAProxy vars.
21 * This permits to identify two variables name with
22 * only one pointer. It permits to not using strdup() for
23 * each variable name used during the runtime.
24 */
25static char **var_names = NULL;
26static int var_names_nb = 0;
27
28/* This array of int contains the system limits per context. */
29static unsigned int var_global_limit = 0;
30static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010031static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020032static unsigned int var_sess_limit = 0;
33static unsigned int var_txn_limit = 0;
34static unsigned int var_reqres_limit = 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +010035static unsigned int var_check_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020036
Willy Tarreau86abe442018-11-25 20:12:18 +010037__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020038
Willy Tarreauf37b1402019-06-04 16:27:36 +020039/* returns the struct vars pointer for a session, stream and scope, or NULL if
40 * it does not exist.
41 */
42static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
43{
44 switch (scope) {
45 case SCOPE_PROC:
46 return &global.vars;
47 case SCOPE_SESS:
48 return &sess->vars;
Gaetan Rivet13a50432020-02-21 18:13:44 +010049 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020050 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010051
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020052 return check ? &check->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010053 }
Willy Tarreauf37b1402019-06-04 16:27:36 +020054 case SCOPE_TXN:
55 return strm ? &strm->vars_txn : NULL;
56 case SCOPE_REQ:
57 case SCOPE_RES:
58 default:
59 return strm ? &strm->vars_reqres : NULL;
60 }
61}
62
Willy Tarreau72330982015-06-19 11:21:56 +020063/* This function adds or remove memory size from the accounting. The inner
64 * pointers may be null when setting the outer ones only.
65 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010066static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020067{
68 switch (vars->scope) {
69 case SCOPE_REQ:
70 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020071 if (strm)
72 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010073 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020074 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020075 if (strm)
76 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010077 goto scope_sess;
78 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020079 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010080
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020081 if (check)
82 _HA_ATOMIC_ADD(&check->vars.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010083 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010084 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +010085scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020086 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010087 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010088 /* fall through */
89 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010090 _HA_ATOMIC_ADD(&global.vars.size, size);
91 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020092 }
93}
94
95/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080096 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020097 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010098 * the outer ones only. The accounting uses either <sess> or <strm>
99 * depending on the scope. <strm> may be NULL when no stream is known
100 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200101 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100102static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200103{
104 switch (vars->scope) {
105 case SCOPE_REQ:
106 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200107 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200108 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100109 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200110 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200111 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200112 return 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +0100113 goto scope_sess;
114 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200115 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +0100116
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200117 if (var_check_limit && check && check->vars.size + size > var_check_limit)
Gaetan Rivet13a50432020-02-21 18:13:44 +0100118 return 0;
119 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100120 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100121scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200122 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100123 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200124 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100125 /* fall through */
126 case SCOPE_PROC:
127 if (var_proc_limit && global.vars.size + size > var_proc_limit)
128 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200129 if (var_global_limit && var_global_size + size > var_global_limit)
130 return 0;
131 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100132 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200133 return 1;
134}
135
Christopher Faulet85d79c92016-11-09 16:54:56 +0100136/* This fnuction remove a variable from the list and free memory it used */
137unsigned int var_clear(struct var *var)
138{
139 unsigned int size = 0;
140
141 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200142 free(var->data.u.str.area);
143 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100144 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200145 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200146 free(var->data.u.meth.str.area);
147 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100148 }
149 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100150 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100151 size += sizeof(struct var);
152 return size;
153}
154
Joseph Herlant07676892018-11-15 09:19:50 -0800155/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200156 * in the list.
157 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100158void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200159{
160 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200161 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200162
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100163 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200164 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100165 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200166 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100167 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100168 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200169}
170
Willy Tarreauebcd4842015-06-19 11:59:02 +0200171/* This function frees all the memory used by all the session variables in the
172 * list starting at <vars>.
173 */
174void vars_prune_per_sess(struct vars *vars)
175{
176 struct var *var, *tmp;
177 unsigned int size = 0;
178
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100179 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200180 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100181 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200182 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100183 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200184
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100185 _HA_ATOMIC_SUB(&vars->size, size);
186 _HA_ATOMIC_SUB(&global.vars.size, size);
187 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200188}
189
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200190/* This function init a list of variabes. */
191void vars_init(struct vars *vars, enum vars_scope scope)
192{
193 LIST_INIT(&vars->head);
194 vars->scope = scope;
195 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100196 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200197}
198
199/* This function declares a new variable name. It returns a pointer
200 * on the string identifying the name. This function assures that
201 * the same name exists only once.
202 *
203 * This function check if the variable name is acceptable.
204 *
205 * The function returns NULL if an error occurs, and <err> is filled.
206 * In this case, the HAProxy must be stopped because the structs are
207 * left inconsistent. Otherwise, it returns the pointer on the global
208 * name.
209 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100210static char *register_name(const char *name, int len, enum vars_scope *scope,
211 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200212{
213 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200214 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200215 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200216 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200217
218 /* Check length. */
219 if (len == 0) {
220 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100221 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200222 }
223
224 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100225 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
226 name += 5;
227 len -= 5;
228 *scope = SCOPE_PROC;
229 }
230 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200231 name += 5;
232 len -= 5;
233 *scope = SCOPE_SESS;
234 }
235 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
236 name += 4;
237 len -= 4;
238 *scope = SCOPE_TXN;
239 }
240 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
241 name += 4;
242 len -= 4;
243 *scope = SCOPE_REQ;
244 }
245 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
246 name += 4;
247 len -= 4;
248 *scope = SCOPE_RES;
249 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100250 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
251 name += 6;
252 len -= 6;
253 *scope = SCOPE_CHECK;
254 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200255 else {
256 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Gaetan Rivet13a50432020-02-21 18:13:44 +0100257 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100258 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200259 }
260
Christopher Faulete95f2c32017-07-24 16:30:34 +0200261 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100262 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200263 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100264 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200265
266
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200267 /* Look for existing variable name. */
268 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200269 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
270 res = var_names[i];
271 goto end;
272 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200273
Christopher Faulete95f2c32017-07-24 16:30:34 +0200274 if (!alloc) {
275 res = NULL;
276 goto end;
277 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100278
Hubert Verstraete831962e2016-06-28 22:44:26 +0200279 /* Store variable name. If realloc fails, var_names remains valid */
280 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
281 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200282 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200283 res = NULL;
284 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200285 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200286 var_names_nb++;
287 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200288 var_names[var_names_nb - 1] = malloc(len + 1);
289 if (!var_names[var_names_nb - 1]) {
290 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200291 res = NULL;
292 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200293 }
294 memcpy(var_names[var_names_nb - 1], name, len);
295 var_names[var_names_nb - 1][len] = '\0';
296
297 /* Check variable name syntax. */
298 tmp = var_names[var_names_nb - 1];
299 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100300 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200301 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200302 res = NULL;
303 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200304 }
305 tmp++;
306 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200307 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200308
Christopher Faulete95f2c32017-07-24 16:30:34 +0200309 end:
310 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100311 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200312 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100313 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200314
315 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200316}
317
318/* This function returns an existing variable or returns NULL. */
319static inline struct var *var_get(struct vars *vars, const char *name)
320{
321 struct var *var;
322
323 list_for_each_entry(var, &vars->head, l)
324 if (var->name == name)
325 return var;
326 return NULL;
327}
328
329/* Returns 0 if fails, else returns 1. */
330static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
331{
332 const struct var_desc *var_desc = &args[0].data.var;
333 struct var *var;
334 struct vars *vars;
335
336 /* Check the availibity of the variable. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200337 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
338 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200339 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200340
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100341 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200342 var = var_get(vars, var_desc->name);
343
344 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200345 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100346 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200347 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200348 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200349
Christopher Faulete95f2c32017-07-24 16:30:34 +0200350 /* Duplicate the sample data because it could modified by another
351 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200352 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200353 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200354 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200355
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100356 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200357 return 1;
358}
359
360/* This function search in the <head> a variable with the same
361 * pointer value that the <name>. If the variable doesn't exists,
362 * create it. The function stores a copy of smp> if the variable.
363 * It returns 0 if fails, else returns 1.
364 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100365static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200366{
367 struct var *var;
368
369 /* Look for existing variable name. */
370 var = var_get(vars, name);
371
372 if (var) {
373 /* free its used memory. */
374 if (var->data.type == SMP_T_STR ||
375 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200376 free(var->data.u.str.area);
377 var_accounting_diff(vars, smp->sess, smp->strm,
378 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200379 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200380 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200381 free(var->data.u.meth.str.area);
382 var_accounting_diff(vars, smp->sess, smp->strm,
383 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200384 }
385 } else {
386
Joseph Herlant07676892018-11-15 09:19:50 -0800387 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100388 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200389 return 0;
390
391 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100392 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200393 if (!var)
394 return 0;
395 LIST_ADDQ(&vars->head, &var->l);
396 var->name = name;
397 }
398
399 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200400 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200401
402 /* Copy data. If the data needs memory, the function can fail. */
403 switch (var->data.type) {
404 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200405 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200406 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200407 break;
408 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200409 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200410 break;
411 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200412 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200413 break;
414 case SMP_T_STR:
415 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200416 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200417 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
418 return 0;
419 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200420 var->data.u.str.area = malloc(smp->data.u.str.data);
421 if (!var->data.u.str.area) {
422 var_accounting_diff(vars, smp->sess, smp->strm,
423 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200424 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
425 return 0;
426 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200427 var->data.u.str.data = smp->data.u.str.data;
428 memcpy(var->data.u.str.area, smp->data.u.str.area,
429 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200430 break;
431 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200432 var->data.u.meth.meth = smp->data.u.meth.meth;
433 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
434 break;
435
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200436 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200437 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
438 return 0;
439 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200440 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
441 if (!var->data.u.meth.str.area) {
442 var_accounting_diff(vars, smp->sess, smp->strm,
443 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200444 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
445 return 0;
446 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200447 var->data.u.meth.str.data = smp->data.u.meth.str.data;
448 var->data.u.meth.str.size = smp->data.u.meth.str.data;
449 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
450 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200451 break;
452 }
453 return 1;
454}
455
Willy Tarreau620408f2016-10-21 16:37:51 +0200456/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100457static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200458{
459 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200460 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200461
Willy Tarreauf37b1402019-06-04 16:27:36 +0200462 vars = get_vars(smp->sess, smp->strm, scope);
463 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200464 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200465
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100466 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200467 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100468 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200469 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200470}
471
Christopher Faulet85d79c92016-11-09 16:54:56 +0100472/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
473static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
474{
475 struct vars *vars;
476 struct var *var;
477 unsigned int size = 0;
478
Willy Tarreauf37b1402019-06-04 16:27:36 +0200479 vars = get_vars(smp->sess, smp->strm, scope);
480 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100481 return 0;
482
483 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100484 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100485 var = var_get(vars, name);
486 if (var) {
487 size = var_clear(var);
488 var_accounting_diff(vars, smp->sess, smp->strm, -size);
489 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100490 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100491 return 1;
492}
493
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200494/* Returns 0 if fails, else returns 1. */
495static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
496{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100497 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200498}
499
Christopher Faulet85d79c92016-11-09 16:54:56 +0100500/* Returns 0 if fails, else returns 1. */
501static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
502{
503 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
504}
505
Joseph Herlant07676892018-11-15 09:19:50 -0800506/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200507 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800508 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200509 */
510int vars_check_arg(struct arg *arg, char **err)
511{
512 char *name;
513 enum vars_scope scope;
514
515 /* Check arg type. */
516 if (arg->type != ARGT_STR) {
517 memprintf(err, "unexpected argument type");
518 return 0;
519 }
520
521 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200522 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
523 1,
524 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200525 if (!name)
526 return 0;
527
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200528 /* properly destroy the chunk */
529 chunk_destroy(&arg->data.str);
530
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200531 /* Use the global variable name pointer. */
532 arg->type = ARGT_VAR;
533 arg->data.var.name = name;
534 arg->data.var.scope = scope;
535 return 1;
536}
537
Christopher Faulet09c9df22016-10-31 11:05:37 +0100538/* This function store a sample in a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200539 * Returns zero on failure and non-zero otherwise. The variable not being
540 * defined is treated as a failure.
Christopher Faulet09c9df22016-10-31 11:05:37 +0100541 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200542int vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet09c9df22016-10-31 11:05:37 +0100543{
544 enum vars_scope scope;
545
546 /* Resolve name and scope. */
547 name = register_name(name, len, &scope, 0, NULL);
548 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200549 return 0;
Christopher Faulet09c9df22016-10-31 11:05:37 +0100550
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200551 return sample_store_stream(name, scope, smp);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100552}
553
554
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200555/* This function store a sample in a variable.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200556 * Returns zero on failure and non-zero otherwise.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200557 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200558int vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200559{
560 enum vars_scope scope;
561
562 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100563 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200564 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200565 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200566
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200567 return sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200568}
569
Christopher Faulet85d79c92016-11-09 16:54:56 +0100570/* This function unset a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200571 * Returns zero on failure and non-zero otherwise.
Christopher Faulet85d79c92016-11-09 16:54:56 +0100572 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200573int vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100574{
575 enum vars_scope scope;
576
577 /* Resolve name and scope. */
578 name = register_name(name, len, &scope, 0, NULL);
579 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200580 return 0;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100581
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200582 return sample_clear_stream(name, scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100583}
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. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200602 vars = get_vars(smp->sess, smp->strm, scope);
603 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200604 return 0;
605
606 /* Get the variable entry. */
607 var = var_get(vars, name);
608 if (!var)
609 return 0;
610
611 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200612 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200613 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200614 return 1;
615}
616
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200617/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800618 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200619 * if the sample is filled, otherwise it returns 0.
620 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100621int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200622{
623 struct vars *vars;
624 struct var *var;
625
626 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200627 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200628
Joseph Herlant07676892018-11-15 09:19:50 -0800629 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200630 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200631 return 0;
632
633 /* Get the variable entry. */
634 var = var_get(vars, var_desc->name);
635 if (!var)
636 return 0;
637
638 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200639 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200640 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200641 return 1;
642}
643
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200644/* Always returns ACT_RET_CONT even if an error occurs. */
645static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200646 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200647{
648 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200649 int dir;
650
651 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200652 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200653 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
654 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
655 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
656 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100657 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200658 default:
659 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
660 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100661 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200662 return ACT_RET_CONT;
663 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200664
665 /* Process the expression. */
666 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200667 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200668 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200669 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200670
671 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100672 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200673 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200674}
675
Christopher Faulet85d79c92016-11-09 16:54:56 +0100676/* Always returns ACT_RET_CONT even if an error occurs. */
677static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
678 struct session *sess, struct stream *s, int flags)
679{
680 struct sample smp;
681
682 memset(&smp, 0, sizeof(smp));
683 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
684
685 /* Clear the variable using the sample context, and ignore errors. */
686 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
687 return ACT_RET_CONT;
688}
689
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200690/* This two function checks the variable name and replace the
691 * configuration string name by the global string name. its
692 * the same string, but the global pointer can be easy to
693 * compare.
694 *
695 * The first function checks a sample-fetch and the second
696 * checks a converter.
697 */
698static int smp_check_var(struct arg *args, char **err)
699{
700 return vars_check_arg(&args[0], err);
701}
702
703static int conv_check_var(struct arg *args, struct sample_conv *conv,
704 const char *file, int line, char **err_msg)
705{
706 return vars_check_arg(&args[0], err_msg);
707}
708
709/* This function is a common parser for using variables. It understands
710 * the format:
711 *
712 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200713 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200714 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200715 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
716 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
717 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200718 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200719static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
720 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200721{
722 const char *var_name = args[*arg-1];
723 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200724 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100725 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200726
Christopher Faulet85d79c92016-11-09 16:54:56 +0100727 if (!strncmp(var_name, "set-var", 7)) {
728 var_name += 7;
729 set_var = 1;
730 }
731 if (!strncmp(var_name, "unset-var", 9)) {
732 var_name += 9;
733 set_var = 0;
734 }
735
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200736 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100737 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
738 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200739 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200740 }
741 var_name++; /* jump the '(' */
742 var_len = strlen(var_name);
743 var_len--; /* remove the ')' */
744 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100745 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
746 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200747 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200748 }
749
Christopher Faulet09c9df22016-10-31 11:05:37 +0100750 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200751 if (!rule->arg.vars.name)
752 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200753
Christopher Faulet85d79c92016-11-09 16:54:56 +0100754 /* There is no fetch method when variable is unset. Just set the right
755 * action and return. */
756 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100757 rule->action = ACT_CUSTOM;
758 rule->action_ptr = action_clear;
759 return ACT_RET_PRS_OK;
760 }
761
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200762 kw_name = args[*arg-1];
763
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200764 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +0100765 px->conf.args.line, err, &px->conf.args, NULL);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200766 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200767 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200768
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200769 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200770 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200771 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
772 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
773 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
774 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100775 case ACT_F_TCP_CHK: flags = SMP_VAL_BE_CHK_RUL; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200776 default:
777 memprintf(err,
778 "internal error, unexpected rule->from=%d, please report this bug!",
779 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200780 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200781 }
782 if (!(rule->arg.vars.expr->fetch->val & flags)) {
783 memprintf(err,
784 "fetch method '%s' extracts information from '%s', none of which is available here",
785 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
786 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200787 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200788 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200789
Thierry FOURNIER42148732015-09-02 17:17:33 +0200790 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200791 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200792 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200793}
794
795static int vars_max_size(char **args, int section_type, struct proxy *curpx,
796 struct proxy *defpx, const char *file, int line,
797 char **err, unsigned int *limit)
798{
799 char *error;
800
801 *limit = strtol(args[1], &error, 10);
802 if (*error != 0) {
803 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
804 return -1;
805 }
806 return 0;
807}
808
809static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
810 struct proxy *defpx, const char *file, int line,
811 char **err)
812{
813 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
814}
815
Christopher Fauletff2613e2016-11-09 11:36:17 +0100816static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
817 struct proxy *defpx, const char *file, int line,
818 char **err)
819{
820 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
821}
822
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200823static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
824 struct proxy *defpx, const char *file, int line,
825 char **err)
826{
827 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
828}
829
830static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
831 struct proxy *defpx, const char *file, int line,
832 char **err)
833{
834 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
835}
836
837static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
838 struct proxy *defpx, const char *file, int line,
839 char **err)
840{
841 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
842}
843
Gaetan Rivet13a50432020-02-21 18:13:44 +0100844static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
845 struct proxy *defpx, const char *file, int line,
846 char **err)
847{
848 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
849}
850
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200851static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
852
Christopher Fauletff2613e2016-11-09 11:36:17 +0100853 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200854 { /* END */ },
855}};
856
Willy Tarreau0108d902018-11-25 19:14:37 +0100857INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
858
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200859static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100860 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
861 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200862 { /* END */ },
863}};
864
Willy Tarreau0108d902018-11-25 19:14:37 +0100865INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
866
Willy Tarreau620408f2016-10-21 16:37:51 +0200867static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100868 { "set-var", parse_store, 1 },
869 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200870 { /* END */ }
871}};
872
Willy Tarreau0108d902018-11-25 19:14:37 +0100873INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
874
Willy Tarreau620408f2016-10-21 16:37:51 +0200875static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100876 { "set-var", parse_store, 1 },
877 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200878 { /* END */ }
879}};
880
Willy Tarreau0108d902018-11-25 19:14:37 +0100881INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
882
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200883static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100884 { "set-var", parse_store, 1 },
885 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200886 { /* END */ }
887}};
888
Willy Tarreau0108d902018-11-25 19:14:37 +0100889INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
890
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100891static struct action_kw_list tcp_check_kws = {ILH, {
892 { "set-var", parse_store, 1 },
893 { "unset-var", parse_store, 1 },
894 { /* END */ }
895}};
896
897INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
898
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200899static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100900 { "set-var", parse_store, 1 },
901 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200902 { /* END */ }
903}};
904
Willy Tarreau0108d902018-11-25 19:14:37 +0100905INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
906
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200907static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100908 { "set-var", parse_store, 1 },
909 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200910 { /* END */ }
911}};
912
Willy Tarreau0108d902018-11-25 19:14:37 +0100913INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
914
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100915static struct action_kw_list http_after_res_kws = { { }, {
916 { "set-var", parse_store, 1 },
917 { "unset-var", parse_store, 1 },
918 { /* END */ }
919}};
920
921INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
922
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200923static struct cfg_kw_list cfg_kws = {{ },{
924 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100925 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200926 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
927 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
928 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +0100929 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200930 { /* END */ }
931}};
932
Willy Tarreau0108d902018-11-25 19:14:37 +0100933INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);