blob: b26d60f2b41c71af435d51a78fd471c3afccb950 [file] [log] [blame]
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02001#include <ctype.h>
2
Willy Tarreau4c7e4b72020-05-27 12:58:42 +02003#include <haproxy/api.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +02004#include <common/cfgparse.h>
Willy Tarreau4aa573d2020-06-04 18:21:56 +02005#include <haproxy/check.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +02006#include <haproxy/http.h>
Willy Tarreauc761f842020-06-04 11:40:28 +02007#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +02008#include <haproxy/list.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +02009#include <haproxy/sample.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020010#include <haproxy/tcp_rules.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020011#include <haproxy/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020012
Willy Tarreauaa74c4e2020-06-04 10:19:23 +020013#include <haproxy/arg.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020014#include <proto/stream.h>
15
16/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010017DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020018
19/* This array contain all the names of all the HAProxy vars.
20 * This permits to identify two variables name with
21 * only one pointer. It permits to not using strdup() for
22 * each variable name used during the runtime.
23 */
24static char **var_names = NULL;
25static int var_names_nb = 0;
26
27/* This array of int contains the system limits per context. */
28static unsigned int var_global_limit = 0;
29static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010030static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020031static unsigned int var_sess_limit = 0;
32static unsigned int var_txn_limit = 0;
33static unsigned int var_reqres_limit = 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +010034static unsigned int var_check_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020035
Willy Tarreau86abe442018-11-25 20:12:18 +010036__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020037
Willy Tarreauf37b1402019-06-04 16:27:36 +020038/* returns the struct vars pointer for a session, stream and scope, or NULL if
39 * it does not exist.
40 */
41static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
42{
43 switch (scope) {
44 case SCOPE_PROC:
45 return &global.vars;
46 case SCOPE_SESS:
47 return &sess->vars;
Gaetan Rivet13a50432020-02-21 18:13:44 +010048 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020049 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010050
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020051 return check ? &check->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010052 }
Willy Tarreauf37b1402019-06-04 16:27:36 +020053 case SCOPE_TXN:
54 return strm ? &strm->vars_txn : NULL;
55 case SCOPE_REQ:
56 case SCOPE_RES:
57 default:
58 return strm ? &strm->vars_reqres : NULL;
59 }
60}
61
Willy Tarreau72330982015-06-19 11:21:56 +020062/* This function adds or remove memory size from the accounting. The inner
63 * pointers may be null when setting the outer ones only.
64 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010065static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020066{
67 switch (vars->scope) {
68 case SCOPE_REQ:
69 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020070 if (strm)
71 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010072 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020073 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020074 if (strm)
75 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010076 goto scope_sess;
77 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020078 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010079
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020080 if (check)
81 _HA_ATOMIC_ADD(&check->vars.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010082 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010083 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +010084scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020085 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010086 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010087 /* fall through */
88 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010089 _HA_ATOMIC_ADD(&global.vars.size, size);
90 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020091 }
92}
93
94/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080095 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020096 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010097 * the outer ones only. The accounting uses either <sess> or <strm>
98 * depending on the scope. <strm> may be NULL when no stream is known
99 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200100 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100101static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200102{
103 switch (vars->scope) {
104 case SCOPE_REQ:
105 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200106 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200107 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100108 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200109 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200110 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200111 return 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +0100112 goto scope_sess;
113 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200114 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +0100115
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200116 if (var_check_limit && check && check->vars.size + size > var_check_limit)
Gaetan Rivet13a50432020-02-21 18:13:44 +0100117 return 0;
118 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100119 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100120scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200121 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100122 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200123 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100124 /* fall through */
125 case SCOPE_PROC:
126 if (var_proc_limit && global.vars.size + size > var_proc_limit)
127 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200128 if (var_global_limit && var_global_size + size > var_global_limit)
129 return 0;
130 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100131 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200132 return 1;
133}
134
Christopher Faulet85d79c92016-11-09 16:54:56 +0100135/* This fnuction remove a variable from the list and free memory it used */
136unsigned int var_clear(struct var *var)
137{
138 unsigned int size = 0;
139
140 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200141 free(var->data.u.str.area);
142 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100143 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200144 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200145 free(var->data.u.meth.str.area);
146 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100147 }
148 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100149 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100150 size += sizeof(struct var);
151 return size;
152}
153
Joseph Herlant07676892018-11-15 09:19:50 -0800154/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200155 * in the list.
156 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100157void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200158{
159 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200160 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200161
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100162 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200163 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100164 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200165 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100166 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100167 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200168}
169
Willy Tarreauebcd4842015-06-19 11:59:02 +0200170/* This function frees all the memory used by all the session variables in the
171 * list starting at <vars>.
172 */
173void vars_prune_per_sess(struct vars *vars)
174{
175 struct var *var, *tmp;
176 unsigned int size = 0;
177
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100178 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200179 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100180 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200181 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100182 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200183
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100184 _HA_ATOMIC_SUB(&vars->size, size);
185 _HA_ATOMIC_SUB(&global.vars.size, size);
186 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200187}
188
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200189/* This function init a list of variabes. */
190void vars_init(struct vars *vars, enum vars_scope scope)
191{
192 LIST_INIT(&vars->head);
193 vars->scope = scope;
194 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100195 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200196}
197
198/* This function declares a new variable name. It returns a pointer
199 * on the string identifying the name. This function assures that
200 * the same name exists only once.
201 *
202 * This function check if the variable name is acceptable.
203 *
204 * The function returns NULL if an error occurs, and <err> is filled.
205 * In this case, the HAProxy must be stopped because the structs are
206 * left inconsistent. Otherwise, it returns the pointer on the global
207 * name.
208 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100209static char *register_name(const char *name, int len, enum vars_scope *scope,
210 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200211{
212 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200213 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200214 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200215 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200216
217 /* Check length. */
218 if (len == 0) {
219 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100220 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200221 }
222
223 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100224 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
225 name += 5;
226 len -= 5;
227 *scope = SCOPE_PROC;
228 }
229 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200230 name += 5;
231 len -= 5;
232 *scope = SCOPE_SESS;
233 }
234 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
235 name += 4;
236 len -= 4;
237 *scope = SCOPE_TXN;
238 }
239 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
240 name += 4;
241 len -= 4;
242 *scope = SCOPE_REQ;
243 }
244 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
245 name += 4;
246 len -= 4;
247 *scope = SCOPE_RES;
248 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100249 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
250 name += 6;
251 len -= 6;
252 *scope = SCOPE_CHECK;
253 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200254 else {
255 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Gaetan Rivet13a50432020-02-21 18:13:44 +0100256 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100257 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200258 }
259
Christopher Faulete95f2c32017-07-24 16:30:34 +0200260 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100261 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200262 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100263 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200264
265
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200266 /* Look for existing variable name. */
267 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200268 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
269 res = var_names[i];
270 goto end;
271 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200272
Christopher Faulete95f2c32017-07-24 16:30:34 +0200273 if (!alloc) {
274 res = NULL;
275 goto end;
276 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100277
Hubert Verstraete831962e2016-06-28 22:44:26 +0200278 /* Store variable name. If realloc fails, var_names remains valid */
279 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
280 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200281 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200282 res = NULL;
283 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200284 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200285 var_names_nb++;
286 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200287 var_names[var_names_nb - 1] = malloc(len + 1);
288 if (!var_names[var_names_nb - 1]) {
289 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200290 res = NULL;
291 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200292 }
293 memcpy(var_names[var_names_nb - 1], name, len);
294 var_names[var_names_nb - 1][len] = '\0';
295
296 /* Check variable name syntax. */
297 tmp = var_names[var_names_nb - 1];
298 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100299 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200300 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200301 res = NULL;
302 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200303 }
304 tmp++;
305 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200306 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200307
Christopher Faulete95f2c32017-07-24 16:30:34 +0200308 end:
309 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100310 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200311 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100312 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200313
314 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200315}
316
317/* This function returns an existing variable or returns NULL. */
318static inline struct var *var_get(struct vars *vars, const char *name)
319{
320 struct var *var;
321
322 list_for_each_entry(var, &vars->head, l)
323 if (var->name == name)
324 return var;
325 return NULL;
326}
327
328/* Returns 0 if fails, else returns 1. */
329static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
330{
331 const struct var_desc *var_desc = &args[0].data.var;
332 struct var *var;
333 struct vars *vars;
334
335 /* Check the availibity of the variable. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200336 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
337 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200338 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200339
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100340 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200341 var = var_get(vars, var_desc->name);
342
343 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200344 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100345 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200346 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200347 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200348
Christopher Faulete95f2c32017-07-24 16:30:34 +0200349 /* Duplicate the sample data because it could modified by another
350 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200351 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200352 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200353 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200354
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100355 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200356 return 1;
357}
358
359/* This function search in the <head> a variable with the same
360 * pointer value that the <name>. If the variable doesn't exists,
361 * create it. The function stores a copy of smp> if the variable.
362 * It returns 0 if fails, else returns 1.
363 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100364static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200365{
366 struct var *var;
367
368 /* Look for existing variable name. */
369 var = var_get(vars, name);
370
371 if (var) {
372 /* free its used memory. */
373 if (var->data.type == SMP_T_STR ||
374 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200375 free(var->data.u.str.area);
376 var_accounting_diff(vars, smp->sess, smp->strm,
377 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200378 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200379 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200380 free(var->data.u.meth.str.area);
381 var_accounting_diff(vars, smp->sess, smp->strm,
382 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200383 }
384 } else {
385
Joseph Herlant07676892018-11-15 09:19:50 -0800386 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100387 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200388 return 0;
389
390 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100391 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200392 if (!var)
393 return 0;
394 LIST_ADDQ(&vars->head, &var->l);
395 var->name = name;
396 }
397
398 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200399 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200400
401 /* Copy data. If the data needs memory, the function can fail. */
402 switch (var->data.type) {
403 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200404 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200405 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200406 break;
407 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200408 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200409 break;
410 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200411 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200412 break;
413 case SMP_T_STR:
414 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200415 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.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.str.area = malloc(smp->data.u.str.data);
420 if (!var->data.u.str.area) {
421 var_accounting_diff(vars, smp->sess, smp->strm,
422 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200423 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
424 return 0;
425 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200426 var->data.u.str.data = smp->data.u.str.data;
427 memcpy(var->data.u.str.area, smp->data.u.str.area,
428 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200429 break;
430 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200431 var->data.u.meth.meth = smp->data.u.meth.meth;
432 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
433 break;
434
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200435 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200436 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
437 return 0;
438 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200439 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
440 if (!var->data.u.meth.str.area) {
441 var_accounting_diff(vars, smp->sess, smp->strm,
442 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200443 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
444 return 0;
445 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200446 var->data.u.meth.str.data = smp->data.u.meth.str.data;
447 var->data.u.meth.str.size = smp->data.u.meth.str.data;
448 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
449 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200450 break;
451 }
452 return 1;
453}
454
Willy Tarreau620408f2016-10-21 16:37:51 +0200455/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100456static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200457{
458 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200459 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200460
Willy Tarreauf37b1402019-06-04 16:27:36 +0200461 vars = get_vars(smp->sess, smp->strm, scope);
462 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200463 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200464
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100465 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200466 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100467 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200468 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200469}
470
Christopher Faulet85d79c92016-11-09 16:54:56 +0100471/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
472static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
473{
474 struct vars *vars;
475 struct var *var;
476 unsigned int size = 0;
477
Willy Tarreauf37b1402019-06-04 16:27:36 +0200478 vars = get_vars(smp->sess, smp->strm, scope);
479 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100480 return 0;
481
482 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100483 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100484 var = var_get(vars, name);
485 if (var) {
486 size = var_clear(var);
487 var_accounting_diff(vars, smp->sess, smp->strm, -size);
488 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100489 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100490 return 1;
491}
492
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200493/* Returns 0 if fails, else returns 1. */
494static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
495{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100496 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200497}
498
Christopher Faulet85d79c92016-11-09 16:54:56 +0100499/* Returns 0 if fails, else returns 1. */
500static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
501{
502 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
503}
504
Joseph Herlant07676892018-11-15 09:19:50 -0800505/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200506 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800507 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200508 */
509int vars_check_arg(struct arg *arg, char **err)
510{
511 char *name;
512 enum vars_scope scope;
513
514 /* Check arg type. */
515 if (arg->type != ARGT_STR) {
516 memprintf(err, "unexpected argument type");
517 return 0;
518 }
519
520 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200521 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
522 1,
523 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200524 if (!name)
525 return 0;
526
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200527 /* properly destroy the chunk */
528 chunk_destroy(&arg->data.str);
529
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200530 /* Use the global variable name pointer. */
531 arg->type = ARGT_VAR;
532 arg->data.var.name = name;
533 arg->data.var.scope = scope;
534 return 1;
535}
536
Christopher Faulet09c9df22016-10-31 11:05:37 +0100537/* This function store a sample in a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200538 * Returns zero on failure and non-zero otherwise. The variable not being
539 * defined is treated as a failure.
Christopher Faulet09c9df22016-10-31 11:05:37 +0100540 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200541int vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet09c9df22016-10-31 11:05:37 +0100542{
543 enum vars_scope scope;
544
545 /* Resolve name and scope. */
546 name = register_name(name, len, &scope, 0, NULL);
547 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200548 return 0;
Christopher Faulet09c9df22016-10-31 11:05:37 +0100549
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200550 return sample_store_stream(name, scope, smp);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100551}
552
553
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200554/* This function store a sample in a variable.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200555 * Returns zero on failure and non-zero otherwise.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200556 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200557int vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200558{
559 enum vars_scope scope;
560
561 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100562 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200563 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200564 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200565
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200566 return sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200567}
568
Christopher Faulet85d79c92016-11-09 16:54:56 +0100569/* This function unset a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200570 * Returns zero on failure and non-zero otherwise.
Christopher Faulet85d79c92016-11-09 16:54:56 +0100571 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200572int vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100573{
574 enum vars_scope scope;
575
576 /* Resolve name and scope. */
577 name = register_name(name, len, &scope, 0, NULL);
578 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200579 return 0;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100580
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200581 return sample_clear_stream(name, scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100582}
583
584
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200585/* this function fills a sample with the
586 * variable content. Returns 1 if the sample
587 * is filled, otherwise it returns 0.
588 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100589int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200590{
591 struct vars *vars;
592 struct var *var;
593 enum vars_scope scope;
594
595 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100596 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200597 if (!name)
598 return 0;
599
600 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200601 vars = get_vars(smp->sess, smp->strm, scope);
602 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200603 return 0;
604
605 /* Get the variable entry. */
606 var = var_get(vars, name);
607 if (!var)
608 return 0;
609
610 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200611 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200612 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200613 return 1;
614}
615
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200616/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800617 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200618 * if the sample is filled, otherwise it returns 0.
619 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100620int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200621{
622 struct vars *vars;
623 struct var *var;
624
625 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200626 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200627
Joseph Herlant07676892018-11-15 09:19:50 -0800628 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200629 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200630 return 0;
631
632 /* Get the variable entry. */
633 var = var_get(vars, var_desc->name);
634 if (!var)
635 return 0;
636
637 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200638 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200639 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200640 return 1;
641}
642
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200643/* Always returns ACT_RET_CONT even if an error occurs. */
644static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200645 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200646{
647 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200648 int dir;
649
650 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200651 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200652 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
653 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
654 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
655 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100656 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200657 default:
658 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
659 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100660 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200661 return ACT_RET_CONT;
662 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200663
664 /* Process the expression. */
665 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200666 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200667 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200668 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200669
670 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100671 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200672 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200673}
674
Christopher Faulet85d79c92016-11-09 16:54:56 +0100675/* Always returns ACT_RET_CONT even if an error occurs. */
676static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
677 struct session *sess, struct stream *s, int flags)
678{
679 struct sample smp;
680
681 memset(&smp, 0, sizeof(smp));
682 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
683
684 /* Clear the variable using the sample context, and ignore errors. */
685 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
686 return ACT_RET_CONT;
687}
688
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200689/* This two function checks the variable name and replace the
690 * configuration string name by the global string name. its
691 * the same string, but the global pointer can be easy to
692 * compare.
693 *
694 * The first function checks a sample-fetch and the second
695 * checks a converter.
696 */
697static int smp_check_var(struct arg *args, char **err)
698{
699 return vars_check_arg(&args[0], err);
700}
701
702static int conv_check_var(struct arg *args, struct sample_conv *conv,
703 const char *file, int line, char **err_msg)
704{
705 return vars_check_arg(&args[0], err_msg);
706}
707
708/* This function is a common parser for using variables. It understands
709 * the format:
710 *
711 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200712 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200713 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200714 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
715 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
716 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200717 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200718static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
719 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200720{
721 const char *var_name = args[*arg-1];
722 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200723 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100724 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200725
Christopher Faulet85d79c92016-11-09 16:54:56 +0100726 if (!strncmp(var_name, "set-var", 7)) {
727 var_name += 7;
728 set_var = 1;
729 }
730 if (!strncmp(var_name, "unset-var", 9)) {
731 var_name += 9;
732 set_var = 0;
733 }
734
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200735 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100736 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
737 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200738 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200739 }
740 var_name++; /* jump the '(' */
741 var_len = strlen(var_name);
742 var_len--; /* remove the ')' */
743 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100744 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
745 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200746 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200747 }
748
Christopher Faulet09c9df22016-10-31 11:05:37 +0100749 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200750 if (!rule->arg.vars.name)
751 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200752
Christopher Faulet85d79c92016-11-09 16:54:56 +0100753 /* There is no fetch method when variable is unset. Just set the right
754 * action and return. */
755 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100756 rule->action = ACT_CUSTOM;
757 rule->action_ptr = action_clear;
758 return ACT_RET_PRS_OK;
759 }
760
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200761 kw_name = args[*arg-1];
762
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200763 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +0100764 px->conf.args.line, err, &px->conf.args, NULL);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200765 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200766 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200767
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200768 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200769 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200770 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
771 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
772 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
773 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100774 case ACT_F_TCP_CHK: flags = SMP_VAL_BE_CHK_RUL; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200775 default:
776 memprintf(err,
777 "internal error, unexpected rule->from=%d, please report this bug!",
778 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200779 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200780 }
781 if (!(rule->arg.vars.expr->fetch->val & flags)) {
782 memprintf(err,
783 "fetch method '%s' extracts information from '%s', none of which is available here",
784 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
785 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200786 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200787 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200788
Thierry FOURNIER42148732015-09-02 17:17:33 +0200789 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200790 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200791 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200792}
793
794static int vars_max_size(char **args, int section_type, struct proxy *curpx,
795 struct proxy *defpx, const char *file, int line,
796 char **err, unsigned int *limit)
797{
798 char *error;
799
800 *limit = strtol(args[1], &error, 10);
801 if (*error != 0) {
802 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
803 return -1;
804 }
805 return 0;
806}
807
808static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
809 struct proxy *defpx, const char *file, int line,
810 char **err)
811{
812 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
813}
814
Christopher Fauletff2613e2016-11-09 11:36:17 +0100815static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
816 struct proxy *defpx, const char *file, int line,
817 char **err)
818{
819 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
820}
821
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200822static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
823 struct proxy *defpx, const char *file, int line,
824 char **err)
825{
826 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
827}
828
829static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
830 struct proxy *defpx, const char *file, int line,
831 char **err)
832{
833 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
834}
835
836static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
837 struct proxy *defpx, const char *file, int line,
838 char **err)
839{
840 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
841}
842
Gaetan Rivet13a50432020-02-21 18:13:44 +0100843static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
844 struct proxy *defpx, const char *file, int line,
845 char **err)
846{
847 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
848}
849
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200850static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
851
Christopher Fauletff2613e2016-11-09 11:36:17 +0100852 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200853 { /* END */ },
854}};
855
Willy Tarreau0108d902018-11-25 19:14:37 +0100856INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
857
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200858static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100859 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
860 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200861 { /* END */ },
862}};
863
Willy Tarreau0108d902018-11-25 19:14:37 +0100864INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
865
Willy Tarreau620408f2016-10-21 16:37:51 +0200866static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100867 { "set-var", parse_store, 1 },
868 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200869 { /* END */ }
870}};
871
Willy Tarreau0108d902018-11-25 19:14:37 +0100872INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
873
Willy Tarreau620408f2016-10-21 16:37:51 +0200874static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100875 { "set-var", parse_store, 1 },
876 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200877 { /* END */ }
878}};
879
Willy Tarreau0108d902018-11-25 19:14:37 +0100880INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
881
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200882static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100883 { "set-var", parse_store, 1 },
884 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200885 { /* END */ }
886}};
887
Willy Tarreau0108d902018-11-25 19:14:37 +0100888INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
889
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100890static struct action_kw_list tcp_check_kws = {ILH, {
891 { "set-var", parse_store, 1 },
892 { "unset-var", parse_store, 1 },
893 { /* END */ }
894}};
895
896INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
897
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200898static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100899 { "set-var", parse_store, 1 },
900 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200901 { /* END */ }
902}};
903
Willy Tarreau0108d902018-11-25 19:14:37 +0100904INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
905
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200906static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100907 { "set-var", parse_store, 1 },
908 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200909 { /* END */ }
910}};
911
Willy Tarreau0108d902018-11-25 19:14:37 +0100912INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
913
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100914static struct action_kw_list http_after_res_kws = { { }, {
915 { "set-var", parse_store, 1 },
916 { "unset-var", parse_store, 1 },
917 { /* END */ }
918}};
919
920INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
921
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200922static struct cfg_kw_list cfg_kws = {{ },{
923 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100924 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200925 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
926 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
927 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +0100928 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200929 { /* END */ }
930}};
931
Willy Tarreau0108d902018-11-25 19:14:37 +0100932INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);