blob: 2e3258300ecae0a2819f1cb479cecddae9b2cd38 [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>
Willy Tarreau6be78492020-06-05 00:00:29 +02005#include <haproxy/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 Tarreau51cd5952020-06-05 12:25:38 +020013#include <haproxy/tcpcheck.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020014#include <haproxy/tcp_rules.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020015#include <haproxy/vars.h>
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020016
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020017
18/* This contains a pool of struct vars */
Willy Tarreau8ceae722018-11-26 11:58:30 +010019DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020020
21/* This array contain all the names of all the HAProxy vars.
22 * This permits to identify two variables name with
23 * only one pointer. It permits to not using strdup() for
24 * each variable name used during the runtime.
25 */
26static char **var_names = NULL;
27static int var_names_nb = 0;
28
29/* This array of int contains the system limits per context. */
30static unsigned int var_global_limit = 0;
31static unsigned int var_global_size = 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +010032static unsigned int var_proc_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020033static unsigned int var_sess_limit = 0;
34static unsigned int var_txn_limit = 0;
35static unsigned int var_reqres_limit = 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +010036static unsigned int var_check_limit = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020037
Willy Tarreau86abe442018-11-25 20:12:18 +010038__decl_rwlock(var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +020039
Willy Tarreauf37b1402019-06-04 16:27:36 +020040/* returns the struct vars pointer for a session, stream and scope, or NULL if
41 * it does not exist.
42 */
43static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
44{
45 switch (scope) {
46 case SCOPE_PROC:
47 return &global.vars;
48 case SCOPE_SESS:
49 return &sess->vars;
Gaetan Rivet13a50432020-02-21 18:13:44 +010050 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020051 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010052
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020053 return check ? &check->vars : NULL;
Gaetan Rivet13a50432020-02-21 18:13:44 +010054 }
Willy Tarreauf37b1402019-06-04 16:27:36 +020055 case SCOPE_TXN:
56 return strm ? &strm->vars_txn : NULL;
57 case SCOPE_REQ:
58 case SCOPE_RES:
59 default:
60 return strm ? &strm->vars_reqres : NULL;
61 }
62}
63
Willy Tarreau72330982015-06-19 11:21:56 +020064/* This function adds or remove memory size from the accounting. The inner
65 * pointers may be null when setting the outer ones only.
66 */
Willy Tarreau6204cd92016-03-10 16:33:04 +010067static void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020068{
69 switch (vars->scope) {
70 case SCOPE_REQ:
71 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +020072 if (strm)
73 _HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
Willy Tarreau6204cd92016-03-10 16:33:04 +010074 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020075 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +020076 if (strm)
77 _HA_ATOMIC_ADD(&strm->vars_txn.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010078 goto scope_sess;
79 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020080 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +010081
Christopher Faulet0fca7ed2020-04-21 11:53:32 +020082 if (check)
83 _HA_ATOMIC_ADD(&check->vars.size, size);
Gaetan Rivet13a50432020-02-21 18:13:44 +010084 }
Willy Tarreau6204cd92016-03-10 16:33:04 +010085 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +010086scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020087 case SCOPE_SESS:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010088 _HA_ATOMIC_ADD(&sess->vars.size, size);
Christopher Fauletff2613e2016-11-09 11:36:17 +010089 /* fall through */
90 case SCOPE_PROC:
Olivier Houchard25ad13f2019-03-08 18:55:38 +010091 _HA_ATOMIC_ADD(&global.vars.size, size);
92 _HA_ATOMIC_ADD(&var_global_size, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +020093 }
94}
95
96/* This function returns 1 if the <size> is available in the var
Joseph Herlant07676892018-11-15 09:19:50 -080097 * pool <vars>, otherwise returns 0. If the space is available,
Willy Tarreau72330982015-06-19 11:21:56 +020098 * the size is reserved. The inner pointers may be null when setting
Willy Tarreau6204cd92016-03-10 16:33:04 +010099 * the outer ones only. The accounting uses either <sess> or <strm>
100 * depending on the scope. <strm> may be NULL when no stream is known
101 * and only the session exists (eg: tcp-request connection).
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200102 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100103static int var_accounting_add(struct vars *vars, struct session *sess, struct stream *strm, int size)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200104{
105 switch (vars->scope) {
106 case SCOPE_REQ:
107 case SCOPE_RES:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200108 if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200109 return 0;
Willy Tarreau6204cd92016-03-10 16:33:04 +0100110 /* fall through */
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200111 case SCOPE_TXN:
Willy Tarreauf37b1402019-06-04 16:27:36 +0200112 if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200113 return 0;
Gaetan Rivet13a50432020-02-21 18:13:44 +0100114 goto scope_sess;
115 case SCOPE_CHECK: {
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200116 struct check *check = objt_check(sess->origin);
Gaetan Rivet13a50432020-02-21 18:13:44 +0100117
Christopher Faulet0fca7ed2020-04-21 11:53:32 +0200118 if (var_check_limit && check && check->vars.size + size > var_check_limit)
Gaetan Rivet13a50432020-02-21 18:13:44 +0100119 return 0;
120 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100121 /* fall through */
Gaetan Rivet13a50432020-02-21 18:13:44 +0100122scope_sess:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200123 case SCOPE_SESS:
Willy Tarreau6204cd92016-03-10 16:33:04 +0100124 if (var_sess_limit && sess->vars.size + size > var_sess_limit)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200125 return 0;
Christopher Fauletff2613e2016-11-09 11:36:17 +0100126 /* fall through */
127 case SCOPE_PROC:
128 if (var_proc_limit && global.vars.size + size > var_proc_limit)
129 return 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200130 if (var_global_limit && var_global_size + size > var_global_limit)
131 return 0;
132 }
Willy Tarreau6204cd92016-03-10 16:33:04 +0100133 var_accounting_diff(vars, sess, strm, size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200134 return 1;
135}
136
Christopher Faulet85d79c92016-11-09 16:54:56 +0100137/* This fnuction remove a variable from the list and free memory it used */
138unsigned int var_clear(struct var *var)
139{
140 unsigned int size = 0;
141
142 if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200143 free(var->data.u.str.area);
144 size += var->data.u.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100145 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200146 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200147 free(var->data.u.meth.str.area);
148 size += var->data.u.meth.str.data;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100149 }
150 LIST_DEL(&var->l);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100151 pool_free(var_pool, var);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100152 size += sizeof(struct var);
153 return size;
154}
155
Joseph Herlant07676892018-11-15 09:19:50 -0800156/* This function free all the memory used by all the variables
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200157 * in the list.
158 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100159void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200160{
161 struct var *var, *tmp;
Willy Tarreau72330982015-06-19 11:21:56 +0200162 unsigned int size = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200163
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100164 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200165 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100166 size += var_clear(var);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200167 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100168 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreau6204cd92016-03-10 16:33:04 +0100169 var_accounting_diff(vars, sess, strm, -size);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200170}
171
Willy Tarreauebcd4842015-06-19 11:59:02 +0200172/* This function frees all the memory used by all the session variables in the
173 * list starting at <vars>.
174 */
175void vars_prune_per_sess(struct vars *vars)
176{
177 struct var *var, *tmp;
178 unsigned int size = 0;
179
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100180 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200181 list_for_each_entry_safe(var, tmp, &vars->head, l) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100182 size += var_clear(var);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200183 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100184 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200185
Olivier Houchard25ad13f2019-03-08 18:55:38 +0100186 _HA_ATOMIC_SUB(&vars->size, size);
187 _HA_ATOMIC_SUB(&global.vars.size, size);
188 _HA_ATOMIC_SUB(&var_global_size, size);
Willy Tarreauebcd4842015-06-19 11:59:02 +0200189}
190
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200191/* This function init a list of variabes. */
192void vars_init(struct vars *vars, enum vars_scope scope)
193{
194 LIST_INIT(&vars->head);
195 vars->scope = scope;
196 vars->size = 0;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100197 HA_RWLOCK_INIT(&vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200198}
199
200/* This function declares a new variable name. It returns a pointer
201 * on the string identifying the name. This function assures that
202 * the same name exists only once.
203 *
204 * This function check if the variable name is acceptable.
205 *
206 * The function returns NULL if an error occurs, and <err> is filled.
207 * In this case, the HAProxy must be stopped because the structs are
208 * left inconsistent. Otherwise, it returns the pointer on the global
209 * name.
210 */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100211static char *register_name(const char *name, int len, enum vars_scope *scope,
212 int alloc, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200213{
214 int i;
Hubert Verstraete831962e2016-06-28 22:44:26 +0200215 char **var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200216 const char *tmp;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200217 char *res = NULL;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200218
219 /* Check length. */
220 if (len == 0) {
221 memprintf(err, "Empty variable name cannot be accepted");
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100222 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200223 }
224
225 /* Check scope. */
Christopher Fauletff2613e2016-11-09 11:36:17 +0100226 if (len > 5 && strncmp(name, "proc.", 5) == 0) {
227 name += 5;
228 len -= 5;
229 *scope = SCOPE_PROC;
230 }
231 else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200232 name += 5;
233 len -= 5;
234 *scope = SCOPE_SESS;
235 }
236 else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
237 name += 4;
238 len -= 4;
239 *scope = SCOPE_TXN;
240 }
241 else if (len > 4 && strncmp(name, "req.", 4) == 0) {
242 name += 4;
243 len -= 4;
244 *scope = SCOPE_REQ;
245 }
246 else if (len > 4 && strncmp(name, "res.", 4) == 0) {
247 name += 4;
248 len -= 4;
249 *scope = SCOPE_RES;
250 }
Gaetan Rivet13a50432020-02-21 18:13:44 +0100251 else if (len > 6 && strncmp(name, "check.", 6) == 0) {
252 name += 6;
253 len -= 6;
254 *scope = SCOPE_CHECK;
255 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200256 else {
257 memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
Gaetan Rivet13a50432020-02-21 18:13:44 +0100258 "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
Christopher Fauleteb3e2762017-12-08 09:17:39 +0100259 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200260 }
261
Christopher Faulete95f2c32017-07-24 16:30:34 +0200262 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100263 HA_RWLOCK_WRLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200264 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100265 HA_RWLOCK_RDLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200266
267
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200268 /* Look for existing variable name. */
269 for (i = 0; i < var_names_nb; i++)
Christopher Faulete95f2c32017-07-24 16:30:34 +0200270 if (strncmp(var_names[i], name, len) == 0 && var_names[i][len] == '\0') {
271 res = var_names[i];
272 goto end;
273 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200274
Christopher Faulete95f2c32017-07-24 16:30:34 +0200275 if (!alloc) {
276 res = NULL;
277 goto end;
278 }
Christopher Faulet09c9df22016-10-31 11:05:37 +0100279
Hubert Verstraete831962e2016-06-28 22:44:26 +0200280 /* Store variable name. If realloc fails, var_names remains valid */
281 var_names2 = realloc(var_names, (var_names_nb + 1) * sizeof(*var_names));
282 if (!var_names2) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200283 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200284 res = NULL;
285 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200286 }
Hubert Verstraete831962e2016-06-28 22:44:26 +0200287 var_names_nb++;
288 var_names = var_names2;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200289 var_names[var_names_nb - 1] = malloc(len + 1);
290 if (!var_names[var_names_nb - 1]) {
291 memprintf(err, "out of memory error");
Christopher Faulete95f2c32017-07-24 16:30:34 +0200292 res = NULL;
293 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200294 }
295 memcpy(var_names[var_names_nb - 1], name, len);
296 var_names[var_names_nb - 1][len] = '\0';
297
298 /* Check variable name syntax. */
299 tmp = var_names[var_names_nb - 1];
300 while (*tmp) {
Willy Tarreau90807112020-02-25 08:16:33 +0100301 if (!isalnum((unsigned char)*tmp) && *tmp != '_' && *tmp != '.') {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200302 memprintf(err, "invalid syntax at char '%s'", tmp);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200303 res = NULL;
304 goto end;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200305 }
306 tmp++;
307 }
Christopher Faulete95f2c32017-07-24 16:30:34 +0200308 res = var_names[var_names_nb - 1];
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200309
Christopher Faulete95f2c32017-07-24 16:30:34 +0200310 end:
311 if (alloc)
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100312 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200313 else
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100314 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &var_names_rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200315
316 return res;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200317}
318
319/* This function returns an existing variable or returns NULL. */
320static inline struct var *var_get(struct vars *vars, const char *name)
321{
322 struct var *var;
323
324 list_for_each_entry(var, &vars->head, l)
325 if (var->name == name)
326 return var;
327 return NULL;
328}
329
330/* Returns 0 if fails, else returns 1. */
331static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
332{
333 const struct var_desc *var_desc = &args[0].data.var;
334 struct var *var;
335 struct vars *vars;
336
337 /* Check the availibity of the variable. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200338 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
339 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200340 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200341
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100342 HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200343 var = var_get(vars, var_desc->name);
344
345 /* check for the variable avalaibility */
Christopher Faulete95f2c32017-07-24 16:30:34 +0200346 if (!var) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100347 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200348 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200349 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200350
Christopher Faulete95f2c32017-07-24 16:30:34 +0200351 /* Duplicate the sample data because it could modified by another
352 * thread */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200353 smp->data = var->data;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200354 smp_dup(smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200355 smp->flags |= SMP_F_CONST;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200356
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100357 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200358 return 1;
359}
360
361/* This function search in the <head> a variable with the same
362 * pointer value that the <name>. If the variable doesn't exists,
363 * create it. The function stores a copy of smp> if the variable.
364 * It returns 0 if fails, else returns 1.
365 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100366static int sample_store(struct vars *vars, const char *name, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200367{
368 struct var *var;
369
370 /* Look for existing variable name. */
371 var = var_get(vars, name);
372
373 if (var) {
374 /* free its used memory. */
375 if (var->data.type == SMP_T_STR ||
376 var->data.type == SMP_T_BIN) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200377 free(var->data.u.str.area);
378 var_accounting_diff(vars, smp->sess, smp->strm,
379 -var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200380 }
Christopher Fauletd02210c2017-07-24 16:24:39 +0200381 else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200382 free(var->data.u.meth.str.area);
383 var_accounting_diff(vars, smp->sess, smp->strm,
384 -var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200385 }
386 } else {
387
Joseph Herlant07676892018-11-15 09:19:50 -0800388 /* Check memory available. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100389 if (!var_accounting_add(vars, smp->sess, smp->strm, sizeof(struct var)))
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200390 return 0;
391
392 /* Create new entry. */
Willy Tarreaubafbe012017-11-24 17:34:44 +0100393 var = pool_alloc(var_pool);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200394 if (!var)
395 return 0;
396 LIST_ADDQ(&vars->head, &var->l);
397 var->name = name;
398 }
399
400 /* Set type. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200401 var->data.type = smp->data.type;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200402
403 /* Copy data. If the data needs memory, the function can fail. */
404 switch (var->data.type) {
405 case SMP_T_BOOL:
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200406 case SMP_T_SINT:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200407 var->data.u.sint = smp->data.u.sint;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200408 break;
409 case SMP_T_IPV4:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200410 var->data.u.ipv4 = smp->data.u.ipv4;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200411 break;
412 case SMP_T_IPV6:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200413 var->data.u.ipv6 = smp->data.u.ipv6;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200414 break;
415 case SMP_T_STR:
416 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200417 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200418 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
419 return 0;
420 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200421 var->data.u.str.area = malloc(smp->data.u.str.data);
422 if (!var->data.u.str.area) {
423 var_accounting_diff(vars, smp->sess, smp->strm,
424 -smp->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200425 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
426 return 0;
427 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200428 var->data.u.str.data = smp->data.u.str.data;
429 memcpy(var->data.u.str.area, smp->data.u.str.area,
430 var->data.u.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200431 break;
432 case SMP_T_METH:
Christopher Fauletd02210c2017-07-24 16:24:39 +0200433 var->data.u.meth.meth = smp->data.u.meth.meth;
434 if (smp->data.u.meth.meth != HTTP_METH_OTHER)
435 break;
436
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200437 if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.meth.str.data)) {
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200438 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
439 return 0;
440 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200441 var->data.u.meth.str.area = malloc(smp->data.u.meth.str.data);
442 if (!var->data.u.meth.str.area) {
443 var_accounting_diff(vars, smp->sess, smp->strm,
444 -smp->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200445 var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
446 return 0;
447 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200448 var->data.u.meth.str.data = smp->data.u.meth.str.data;
449 var->data.u.meth.str.size = smp->data.u.meth.str.data;
450 memcpy(var->data.u.meth.str.area, smp->data.u.meth.str.area,
451 var->data.u.meth.str.data);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200452 break;
453 }
454 return 1;
455}
456
Willy Tarreau620408f2016-10-21 16:37:51 +0200457/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100458static inline int sample_store_stream(const char *name, enum vars_scope scope, struct sample *smp)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200459{
460 struct vars *vars;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200461 int ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200462
Willy Tarreauf37b1402019-06-04 16:27:36 +0200463 vars = get_vars(smp->sess, smp->strm, scope);
464 if (!vars || vars->scope != scope)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200465 return 0;
Christopher Faulete95f2c32017-07-24 16:30:34 +0200466
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100467 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200468 ret = sample_store(vars, name, smp);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulete95f2c32017-07-24 16:30:34 +0200470 return ret;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200471}
472
Christopher Faulet85d79c92016-11-09 16:54:56 +0100473/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
474static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
475{
476 struct vars *vars;
477 struct var *var;
478 unsigned int size = 0;
479
Willy Tarreauf37b1402019-06-04 16:27:36 +0200480 vars = get_vars(smp->sess, smp->strm, scope);
481 if (!vars || vars->scope != scope)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100482 return 0;
483
484 /* Look for existing variable name. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100485 HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100486 var = var_get(vars, name);
487 if (var) {
488 size = var_clear(var);
489 var_accounting_diff(vars, smp->sess, smp->strm, -size);
490 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100491 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &vars->rwlock);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100492 return 1;
493}
494
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200495/* Returns 0 if fails, else returns 1. */
496static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
497{
Christopher Faulet0099a8c2016-11-09 16:15:32 +0100498 return sample_store_stream(args[0].data.var.name, args[0].data.var.scope, smp);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200499}
500
Christopher Faulet85d79c92016-11-09 16:54:56 +0100501/* Returns 0 if fails, else returns 1. */
502static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
503{
504 return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, smp);
505}
506
Joseph Herlant07676892018-11-15 09:19:50 -0800507/* This functions check an argument entry and fill it with a variable
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200508 * type. The argumen must be a string. If the variable lookup fails,
Joseph Herlant07676892018-11-15 09:19:50 -0800509 * the function returns 0 and fill <err>, otherwise it returns 1.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200510 */
511int vars_check_arg(struct arg *arg, char **err)
512{
513 char *name;
514 enum vars_scope scope;
515
516 /* Check arg type. */
517 if (arg->type != ARGT_STR) {
518 memprintf(err, "unexpected argument type");
519 return 0;
520 }
521
522 /* Register new variable name. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200523 name = register_name(arg->data.str.area, arg->data.str.data, &scope,
524 1,
525 err);
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200526 if (!name)
527 return 0;
528
Tim Duesterhusa6cc7e82019-05-13 10:53:29 +0200529 /* properly destroy the chunk */
530 chunk_destroy(&arg->data.str);
531
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200532 /* Use the global variable name pointer. */
533 arg->type = ARGT_VAR;
534 arg->data.var.name = name;
535 arg->data.var.scope = scope;
536 return 1;
537}
538
Christopher Faulet09c9df22016-10-31 11:05:37 +0100539/* This function store a sample in a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200540 * Returns zero on failure and non-zero otherwise. The variable not being
541 * defined is treated as a failure.
Christopher Faulet09c9df22016-10-31 11:05:37 +0100542 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200543int vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet09c9df22016-10-31 11:05:37 +0100544{
545 enum vars_scope scope;
546
547 /* Resolve name and scope. */
548 name = register_name(name, len, &scope, 0, NULL);
549 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200550 return 0;
Christopher Faulet09c9df22016-10-31 11:05:37 +0100551
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200552 return sample_store_stream(name, scope, smp);
Christopher Faulet09c9df22016-10-31 11:05:37 +0100553}
554
555
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200556/* This function store a sample in a variable.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200557 * Returns zero on failure and non-zero otherwise.
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200558 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200559int vars_set_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200560{
561 enum vars_scope scope;
562
563 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100564 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200565 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200566 return 0;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200567
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200568 return sample_store_stream(name, scope, smp);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200569}
570
Christopher Faulet85d79c92016-11-09 16:54:56 +0100571/* This function unset a variable if it was already defined.
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200572 * Returns zero on failure and non-zero otherwise.
Christopher Faulet85d79c92016-11-09 16:54:56 +0100573 */
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200574int vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
Christopher Faulet85d79c92016-11-09 16:54:56 +0100575{
576 enum vars_scope scope;
577
578 /* Resolve name and scope. */
579 name = register_name(name, len, &scope, 0, NULL);
580 if (!name)
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200581 return 0;
Christopher Faulet85d79c92016-11-09 16:54:56 +0100582
Tim Duesterhusb4fac1e2020-05-19 13:49:40 +0200583 return sample_clear_stream(name, scope, smp);
Christopher Faulet85d79c92016-11-09 16:54:56 +0100584}
585
586
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200587/* this function fills a sample with the
588 * variable content. Returns 1 if the sample
589 * is filled, otherwise it returns 0.
590 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100591int vars_get_by_name(const char *name, size_t len, struct sample *smp)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200592{
593 struct vars *vars;
594 struct var *var;
595 enum vars_scope scope;
596
597 /* Resolve name and scope. */
Christopher Faulet09c9df22016-10-31 11:05:37 +0100598 name = register_name(name, len, &scope, 1, NULL);
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200599 if (!name)
600 return 0;
601
602 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200603 vars = get_vars(smp->sess, smp->strm, scope);
604 if (!vars || vars->scope != scope)
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200605 return 0;
606
607 /* Get the variable entry. */
608 var = var_get(vars, name);
609 if (!var)
610 return 0;
611
612 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200613 smp->data = var->data;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200614 smp->flags = SMP_F_CONST;
Thierry FOURNIERc365d992015-06-09 12:27:17 +0200615 return 1;
616}
617
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200618/* this function fills a sample with the
Joseph Herlant07676892018-11-15 09:19:50 -0800619 * content of the variable described by <var_desc>. Returns 1
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200620 * if the sample is filled, otherwise it returns 0.
621 */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100622int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200623{
624 struct vars *vars;
625 struct var *var;
626
627 /* Select "vars" pool according with the scope. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200628 vars = get_vars(smp->sess, smp->strm, var_desc->scope);
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200629
Joseph Herlant07676892018-11-15 09:19:50 -0800630 /* Check if the scope is available a this point of processing. */
Willy Tarreauf37b1402019-06-04 16:27:36 +0200631 if (!vars || vars->scope != var_desc->scope)
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200632 return 0;
633
634 /* Get the variable entry. */
635 var = var_get(vars, var_desc->name);
636 if (!var)
637 return 0;
638
639 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200640 smp->data = var->data;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200641 smp->flags = SMP_F_CONST;
Thierry FOURNIERfd77e052015-07-07 21:20:42 +0200642 return 1;
643}
644
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200645/* Always returns ACT_RET_CONT even if an error occurs. */
646static enum act_return action_store(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +0200647 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200648{
649 struct sample smp;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200650 int dir;
651
652 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200653 case ACT_F_TCP_REQ_SES: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200654 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
655 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
656 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
657 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Gaetan Rivet0c39ecc2020-02-24 17:34:11 +0100658 case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200659 default:
660 send_log(px, LOG_ERR, "Vars: internal error while execute action store.");
661 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
Christopher Faulet767a84b2017-11-24 16:50:31 +0100662 ha_alert("Vars: internal error while execute action store.\n");
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200663 return ACT_RET_CONT;
664 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200665
666 /* Process the expression. */
667 memset(&smp, 0, sizeof(smp));
Willy Tarreau108a8fd2016-10-21 17:13:24 +0200668 if (!sample_process(px, sess, s, dir|SMP_OPT_FINAL,
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200669 rule->arg.vars.expr, &smp))
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200670 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200671
672 /* Store the sample, and ignore errors. */
Willy Tarreau6204cd92016-03-10 16:33:04 +0100673 sample_store_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
Thierry FOURNIER24ff6c62015-08-06 08:52:53 +0200674 return ACT_RET_CONT;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200675}
676
Christopher Faulet85d79c92016-11-09 16:54:56 +0100677/* Always returns ACT_RET_CONT even if an error occurs. */
678static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
679 struct session *sess, struct stream *s, int flags)
680{
681 struct sample smp;
682
683 memset(&smp, 0, sizeof(smp));
684 smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
685
686 /* Clear the variable using the sample context, and ignore errors. */
687 sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
688 return ACT_RET_CONT;
689}
690
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200691/* This two function checks the variable name and replace the
692 * configuration string name by the global string name. its
693 * the same string, but the global pointer can be easy to
694 * compare.
695 *
696 * The first function checks a sample-fetch and the second
697 * checks a converter.
698 */
699static int smp_check_var(struct arg *args, char **err)
700{
701 return vars_check_arg(&args[0], err);
702}
703
704static int conv_check_var(struct arg *args, struct sample_conv *conv,
705 const char *file, int line, char **err_msg)
706{
707 return vars_check_arg(&args[0], err_msg);
708}
709
710/* This function is a common parser for using variables. It understands
711 * the format:
712 *
713 * set-var(<variable-name>) <expression>
Willy Tarreau4b7531f2019-06-04 16:43:29 +0200714 * unset-var(<variable-name>)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200715 *
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200716 * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
717 * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
718 * is filled with the pointer to the expression to execute.
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200719 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200720static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px,
721 struct act_rule *rule, char **err)
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200722{
723 const char *var_name = args[*arg-1];
724 int var_len;
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200725 const char *kw_name;
Willy Tarreaue3658152016-11-24 21:23:28 +0100726 int flags, set_var = 0;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200727
Christopher Faulet85d79c92016-11-09 16:54:56 +0100728 if (!strncmp(var_name, "set-var", 7)) {
729 var_name += 7;
730 set_var = 1;
731 }
732 if (!strncmp(var_name, "unset-var", 9)) {
733 var_name += 9;
734 set_var = 0;
735 }
736
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200737 if (*var_name != '(') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100738 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
739 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200740 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200741 }
742 var_name++; /* jump the '(' */
743 var_len = strlen(var_name);
744 var_len--; /* remove the ')' */
745 if (var_name[var_len] != ')') {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100746 memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
747 args[*arg-1]);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200748 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200749 }
750
Christopher Faulet09c9df22016-10-31 11:05:37 +0100751 rule->arg.vars.name = register_name(var_name, var_len, &rule->arg.vars.scope, 1, err);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200752 if (!rule->arg.vars.name)
753 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200754
Christopher Faulet85d79c92016-11-09 16:54:56 +0100755 /* There is no fetch method when variable is unset. Just set the right
756 * action and return. */
757 if (!set_var) {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100758 rule->action = ACT_CUSTOM;
759 rule->action_ptr = action_clear;
760 return ACT_RET_PRS_OK;
761 }
762
Thierry FOURNIER48a9cd12015-07-28 19:00:28 +0200763 kw_name = args[*arg-1];
764
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200765 rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +0100766 px->conf.args.line, err, &px->conf.args, NULL);
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200767 if (!rule->arg.vars.expr)
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200768 return ACT_RET_PRS_ERR;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200769
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200770 switch (rule->from) {
Willy Tarreau620408f2016-10-21 16:37:51 +0200771 case ACT_F_TCP_REQ_SES: flags = SMP_VAL_FE_SES_ACC; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200772 case ACT_F_TCP_REQ_CNT: flags = SMP_VAL_FE_REQ_CNT; break;
773 case ACT_F_TCP_RES_CNT: flags = SMP_VAL_BE_RES_CNT; break;
774 case ACT_F_HTTP_REQ: flags = SMP_VAL_FE_HRQ_HDR; break;
775 case ACT_F_HTTP_RES: flags = SMP_VAL_BE_HRS_HDR; break;
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100776 case ACT_F_TCP_CHK: flags = SMP_VAL_BE_CHK_RUL; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200777 default:
778 memprintf(err,
779 "internal error, unexpected rule->from=%d, please report this bug!",
780 rule->from);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200781 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200782 }
783 if (!(rule->arg.vars.expr->fetch->val & flags)) {
784 memprintf(err,
785 "fetch method '%s' extracts information from '%s', none of which is available here",
786 kw_name, sample_src_names(rule->arg.vars.expr->fetch->use));
787 free(rule->arg.vars.expr);
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200788 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200789 }
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200790
Thierry FOURNIER42148732015-09-02 17:17:33 +0200791 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +0200792 rule->action_ptr = action_store;
Thierry FOURNIERafa80492015-08-19 09:04:15 +0200793 return ACT_RET_PRS_OK;
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200794}
795
796static int vars_max_size(char **args, int section_type, struct proxy *curpx,
797 struct proxy *defpx, const char *file, int line,
798 char **err, unsigned int *limit)
799{
800 char *error;
801
802 *limit = strtol(args[1], &error, 10);
803 if (*error != 0) {
804 memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
805 return -1;
806 }
807 return 0;
808}
809
810static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
811 struct proxy *defpx, const char *file, int line,
812 char **err)
813{
814 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
815}
816
Christopher Fauletff2613e2016-11-09 11:36:17 +0100817static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
818 struct proxy *defpx, const char *file, int line,
819 char **err)
820{
821 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
822}
823
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200824static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
825 struct proxy *defpx, const char *file, int line,
826 char **err)
827{
828 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
829}
830
831static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
832 struct proxy *defpx, const char *file, int line,
833 char **err)
834{
835 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
836}
837
838static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
839 struct proxy *defpx, const char *file, int line,
840 char **err)
841{
842 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
843}
844
Gaetan Rivet13a50432020-02-21 18:13:44 +0100845static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
846 struct proxy *defpx, const char *file, int line,
847 char **err)
848{
849 return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
850}
851
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200852static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
853
Christopher Fauletff2613e2016-11-09 11:36:17 +0100854 { "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200855 { /* END */ },
856}};
857
Willy Tarreau0108d902018-11-25 19:14:37 +0100858INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
859
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200860static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100861 { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
862 { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200863 { /* END */ },
864}};
865
Willy Tarreau0108d902018-11-25 19:14:37 +0100866INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
867
Willy Tarreau620408f2016-10-21 16:37:51 +0200868static struct action_kw_list tcp_req_sess_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100869 { "set-var", parse_store, 1 },
870 { "unset-var", parse_store, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +0200871 { /* END */ }
872}};
873
Willy Tarreau0108d902018-11-25 19:14:37 +0100874INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
875
Willy Tarreau620408f2016-10-21 16:37:51 +0200876static struct action_kw_list tcp_req_cont_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100877 { "set-var", parse_store, 1 },
878 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200879 { /* END */ }
880}};
881
Willy Tarreau0108d902018-11-25 19:14:37 +0100882INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
883
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200884static struct action_kw_list tcp_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100885 { "set-var", parse_store, 1 },
886 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200887 { /* END */ }
888}};
889
Willy Tarreau0108d902018-11-25 19:14:37 +0100890INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
891
Gaetan Rivet707b52f2020-02-21 18:14:59 +0100892static struct action_kw_list tcp_check_kws = {ILH, {
893 { "set-var", parse_store, 1 },
894 { "unset-var", parse_store, 1 },
895 { /* END */ }
896}};
897
898INITCALL1(STG_REGISTER, tcp_check_keywords_register, &tcp_check_kws);
899
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200900static struct action_kw_list http_req_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100901 { "set-var", parse_store, 1 },
902 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200903 { /* END */ }
904}};
905
Willy Tarreau0108d902018-11-25 19:14:37 +0100906INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
907
Thierry FOURNIER36481b82015-08-19 09:01:53 +0200908static struct action_kw_list http_res_kws = { { }, {
Christopher Faulet85d79c92016-11-09 16:54:56 +0100909 { "set-var", parse_store, 1 },
910 { "unset-var", parse_store, 1 },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200911 { /* END */ }
912}};
913
Willy Tarreau0108d902018-11-25 19:14:37 +0100914INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
915
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100916static struct action_kw_list http_after_res_kws = { { }, {
917 { "set-var", parse_store, 1 },
918 { "unset-var", parse_store, 1 },
919 { /* END */ }
920}};
921
922INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws);
923
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200924static struct cfg_kw_list cfg_kws = {{ },{
925 { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
Christopher Fauletff2613e2016-11-09 11:36:17 +0100926 { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200927 { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
928 { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
929 { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
Gaetan Rivet13a50432020-02-21 18:13:44 +0100930 { CFG_GLOBAL, "tune.vars.check-max-size", vars_max_size_check },
Thierry FOURNIER4834bc72015-06-06 19:29:07 +0200931 { /* END */ }
932}};
933
Willy Tarreau0108d902018-11-25 19:14:37 +0100934INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);