blob: 4a2b11dce6aeb9ece7945b2a98f154571f3f76eb [file] [log] [blame]
Miroslav Zagorac70230c62020-12-09 16:54:31 +01001/***
2 * Copyright 2020 HAProxy Technologies
3 *
4 * This file is part of the HAProxy OpenTracing filter.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20#include "include.h"
21
22
23#ifdef DEBUG_OT
24
25/***
26 * NAME
27 * flt_ot_vars_scope_dump -
28 *
29 * ARGUMENTS
30 * vars -
31 * scope -
32 *
33 * DESCRIPTION
Miroslav Zagoracb51e94b2022-03-01 19:18:34 +010034 * Function prints the contents of all variables defined for a particular
35 * scope.
Miroslav Zagorac70230c62020-12-09 16:54:31 +010036 *
37 * RETURN VALUE
38 * This function does not return a value.
39 */
40static void flt_ot_vars_scope_dump(struct vars *vars, const char *scope)
41{
42 const struct var *var;
43
44 if (vars == NULL)
45 return;
46
Miroslav Zagorac6163e032022-02-23 18:15:56 +010047 vars_rdlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +010048 list_for_each_entry(var, &(vars->head), l)
49 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
Miroslav Zagorac6163e032022-02-23 18:15:56 +010050 vars_rdunlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +010051}
52
53
54/***
55 * NAME
56 * flt_ot_vars_dump -
57 *
58 * ARGUMENTS
59 * s -
60 *
61 * DESCRIPTION
Miroslav Zagoracb51e94b2022-03-01 19:18:34 +010062 * Function prints the contents of all variables grouped by individual
63 * scope.
Miroslav Zagorac70230c62020-12-09 16:54:31 +010064 *
65 * RETURN VALUE
66 * This function does not return a value.
67 */
68void flt_ot_vars_dump(struct stream *s)
69{
70 FLT_OT_FUNC("%p", s);
71
72 /*
73 * It would be nice if we could use the get_vars() function from HAProxy
74 * source here to get the value of the 'vars' pointer, but it is defined
75 * as 'static inline', so unfortunately none of this is possible.
76 */
Willy Tarreaucfc4f242021-05-08 11:41:28 +020077 flt_ot_vars_scope_dump(&(proc_vars), "PROC");
Miroslav Zagorac70230c62020-12-09 16:54:31 +010078 flt_ot_vars_scope_dump(&(s->sess->vars), "SESS");
79 flt_ot_vars_scope_dump(&(s->vars_txn), "TXN");
80 flt_ot_vars_scope_dump(&(s->vars_reqres), "REQ/RES");
81
82 FLT_OT_RETURN();
83}
84
85#endif /* DEBUG_OT */
86
87
88/***
89 * NAME
Miroslav Zagorac854efef2022-03-01 18:41:36 +010090 * flt_ot_smp_init -
91 *
92 * ARGUMENTS
93 * s -
94 * smp -
95 * opt -
96 * type -
97 * data -
98 *
99 * DESCRIPTION
100 * The function initializes the value of the 'smp' structure. If the 'data'
101 * argument is set, then the 'sample_data' member of the 'smp' structure is
102 * also initialized.
103 *
104 * RETURN VALUE
105 * This function does not return a value.
106 */
107static inline void flt_ot_smp_init(struct stream *s, struct sample *smp, uint opt, int type, const char *data)
108{
109 (void)memset(smp, 0, sizeof(*smp));
110 (void)smp_set_owner(smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
111
112 if (data != NULL) {
113 smp->data.type = type;
114
115 chunk_initstr(&(smp->data.u.str), data);
116 }
117}
118
119
120/***
121 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100122 * flt_ot_get_vars -
123 *
124 * ARGUMENTS
125 * s -
126 * scope -
127 *
128 * DESCRIPTION
129 * -
130 *
131 * RETURN VALUE
Miroslav Zagoracb51e94b2022-03-01 19:18:34 +0100132 * Returns the struct vars pointer for a stream and scope, or NULL if it does
133 * not exist.
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100134 */
135static inline struct vars *flt_ot_get_vars(struct stream *s, const char *scope)
136{
137 struct vars *retptr = NULL;
138
139 if (strcasecmp(scope, "proc") == 0)
Willy Tarreaucfc4f242021-05-08 11:41:28 +0200140 retptr = &(proc_vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100141 else if (strcasecmp(scope, "sess") == 0)
142 retptr = (&(s->sess->vars));
143 else if (strcasecmp(scope, "txn") == 0)
144 retptr = (&(s->vars_txn));
145 else if ((strcasecmp(scope, "req") == 0) || (strcasecmp(scope, "res") == 0))
146 retptr = (&(s->vars_reqres));
147
148 return retptr;
149}
150
151
152/***
153 * NAME
154 * flt_ot_normalize_name -
155 *
156 * ARGUMENTS
157 * var_name -
158 * size -
159 * len -
160 * name -
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100161 * flag_cpy -
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100162 * err -
163 *
164 * DESCRIPTION
165 * -
166 *
167 * RETURN VALUE
168 * -
169 */
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100170static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, bool flag_cpy, char **err)
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100171{
172 int retval = 0;
173
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100174 FLT_OT_FUNC("%p, %zu, %p, \"%s\", %hhu, %p:%p", var_name, size, len, name, flag_cpy, FLT_OT_DPTR_ARGS(err));
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100175
176 if (!FLT_OT_STR_ISVALID(name))
177 FLT_OT_RETURN(retval);
178
179 /*
180 * In case the name of the variable consists of several elements,
181 * the character '.' is added between them.
182 */
183 if ((*len == 0) || (var_name[*len - 1] == '.'))
184 /* Do nothing. */;
185 else if (*len < (size - 1))
186 var_name[(*len)++] = '.';
187 else
188 retval = -1;
189
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100190 if (flag_cpy) {
191 retval = strlen(name);
192 if ((*len + retval + 1) > size) {
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100193 FLT_OT_ERR("failed to normalize variable name, buffer too small");
194
195 retval = -1;
196 } else {
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100197 (void)memcpy(var_name + *len, name, retval + 1);
198 *len += retval;
199 }
200 } else {
201 /*
202 * HAProxy does not allow the use of variable names containing '-'
203 * or ' '. This of course applies to HTTP header names as well.
204 * Also, here the capital letters are converted to lowercase.
205 */
206 while (retval != -1)
207 if (*len >= (size - 1)) {
208 FLT_OT_ERR("failed to normalize variable name, buffer too small");
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100209
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100210 retval = -1;
211 } else {
212 uint8_t ch = name[retval];
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100213
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100214 if (ch == '\0')
215 break;
216 else if (ch == '-')
217 ch = FLT_OT_VAR_CHAR_DASH;
218 else if (ch == ' ')
219 ch = FLT_OT_VAR_CHAR_SPACE;
220 else if (isupper(ch))
221 ch = ist_lc[ch];
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100222
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100223 var_name[(*len)++] = ch;
224 retval++;
225 }
226
227 var_name[*len] = '\0';
228 }
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100229
230 FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
231
232 if (retval == -1)
233 *len = retval;
234
235 FLT_OT_RETURN(retval);
236}
237
238
239/***
240 * NAME
241 * flt_ot_var_name -
242 *
243 * ARGUMENTS
244 * scope -
245 * prefix -
246 * name -
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100247 * flag_cpy -
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100248 * var_name -
249 * size -
250 * err -
251 *
252 * DESCRIPTION
Miroslav Zagoracb51e94b2022-03-01 19:18:34 +0100253 * The function initializes the value of the 'smp' structure. If the 'data'
254 * argument is set, then the 'sample_data' member of the 'smp' structure is
255 * also initialized.
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100256 *
257 * RETURN VALUE
258 * -
259 */
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100260static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, bool flag_cpy, char *var_name, size_t size, char **err)
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100261{
262 int retval = 0;
263
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100264 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %hhu, %p, %zu, %p:%p", scope, prefix, name, flag_cpy, var_name, size, FLT_OT_DPTR_ARGS(err));
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100265
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100266 if (flt_ot_normalize_name(var_name, size, &retval, scope, 0, err) >= 0)
267 if (flt_ot_normalize_name(var_name, size, &retval, prefix, 0, err) >= 0)
268 (void)flt_ot_normalize_name(var_name, size, &retval, name, flag_cpy, err);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100269
270 if (retval == -1)
271 FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
272
273 FLT_OT_RETURN(retval);
274}
275
276
277/***
278 * NAME
279 * flt_ot_var_register -
280 *
281 * ARGUMENTS
282 * scope -
283 * prefix -
284 * name -
285 * err -
286 *
287 * DESCRIPTION
288 * -
289 *
290 * RETURN VALUE
291 * -
292 */
293int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
294{
295 struct arg arg;
296 char var_name[BUFSIZ];
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100297 int retval = -1, var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100298
299 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
300
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100301 var_name_len = flt_ot_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100302 if (var_name_len == -1)
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100303 FLT_OT_RETURN(retval);
304
305 /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
306 (void)memset(&arg, 0, sizeof(arg));
307 arg.type = ARGT_STR;
308 arg.data.str.area = var_name;
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100309 arg.data.str.data = var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100310
311 if (vars_check_arg(&arg, err) == 0) {
312 FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100313 } else {
314 FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name);
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100315
316 retval = var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100317 }
318
319 FLT_OT_RETURN(retval);
320}
321
322
323/***
324 * NAME
325 * flt_ot_var_set -
326 *
327 * ARGUMENTS
328 * s -
329 * scope -
330 * prefix -
331 * name -
332 * value -
333 * opt -
334 * err -
335 *
336 * DESCRIPTION
337 * -
338 *
339 * RETURN VALUE
340 * -
341 */
342int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
343{
344 struct sample smp;
345 char var_name[BUFSIZ];
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100346 int retval = -1, var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100347
348 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
349
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100350 var_name_len = flt_ot_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100351 if (var_name_len == -1)
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100352 FLT_OT_RETURN(retval);
353
Miroslav Zagorac854efef2022-03-01 18:41:36 +0100354 flt_ot_smp_init(s, &smp, opt, SMP_T_STR, value);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100355
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100356 if (vars_set_by_name_ifexist(var_name, var_name_len, &smp) == 0) {
Miroslav Zagorac728627f2022-03-01 18:42:54 +0100357 FLT_OT_ERR("failed to set variable '%s'", var_name);
Miroslav Zagorac728627f2022-03-01 18:42:54 +0100358 } else {
359 FLT_OT_DBG(2, "variable '%s' set", var_name);
Miroslav Zagoracaec19a72022-03-01 18:44:36 +0100360
361 retval = var_name_len;
Miroslav Zagorac728627f2022-03-01 18:42:54 +0100362 }
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100363
364 FLT_OT_RETURN(retval);
365}
366
367
368/***
369 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100370 * flt_ot_vars_unset -
371 *
372 * ARGUMENTS
373 * s -
374 * scope -
375 * prefix -
376 * opt -
377 * err -
378 *
379 * DESCRIPTION
380 * -
381 *
382 * RETURN VALUE
383 * -
384 */
385int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
386{
387 struct sample smp;
388 struct vars *vars;
389 struct var *var, *var_back;
390 char var_prefix[BUFSIZ], var_name[BUFSIZ];
391 uint size;
392 int var_prefix_len, var_name_len, retval = -1;
393
394 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
395
396 vars = flt_ot_get_vars(s, scope);
397 if (vars == NULL)
398 FLT_OT_RETURN(retval);
399
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100400 var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, 0, var_prefix, sizeof(var_prefix), err);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100401 if (var_prefix_len == -1)
402 FLT_OT_RETURN(retval);
403
404 retval = 0;
405
Miroslav Zagorac6163e032022-02-23 18:15:56 +0100406 vars_wrlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100407 list_for_each_entry_safe(var, var_back, &(vars->head), l) {
408 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len);
409
410 if (strncmp(var_prefix, var->name, var_prefix_len) == 0) {
411 var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name);
412 if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) {
413 FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name);
414
415 break;
416 }
417
418 FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area);
419
Miroslav Zagorac854efef2022-03-01 18:41:36 +0100420 size = var_clear(var, 1);
421 flt_ot_smp_init(s, &smp, opt, 0, NULL);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100422 var_accounting_diff(vars, smp.sess, smp.strm, -size);
423
424 retval++;
425 }
426 }
Miroslav Zagorac6163e032022-02-23 18:15:56 +0100427 vars_wrunlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100428
429 FLT_OT_RETURN(retval);
430}
431
432
433/***
434 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100435 * flt_ot_vars_get -
436 *
437 * ARGUMENTS
438 * s -
439 * scope -
440 * prefix -
441 * opt -
442 * err -
443 *
444 * DESCRIPTION
445 * -
446 *
447 * RETURN VALUE
448 * -
449 */
450struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
451{
452 struct vars *vars;
453 const struct var *var;
454 char var_name[BUFSIZ], ot_var_name[BUFSIZ];
455 int rc, i;
456 struct otc_text_map *retptr = NULL;
457
458 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
459
460 vars = flt_ot_get_vars(s, scope);
461 if (vars == NULL)
462 FLT_OT_RETURN(retptr);
463
Miroslav Zagoracb536cec2022-03-02 00:15:23 +0100464 rc = flt_ot_var_name(NULL, prefix, NULL, 0, var_name, sizeof(var_name), err);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100465 if (rc == -1)
466 FLT_OT_RETURN(retptr);
467
Miroslav Zagorac6163e032022-02-23 18:15:56 +0100468 vars_rdlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100469 list_for_each_entry(var, &(vars->head), l) {
470 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
471
472 if (strncmp(var_name, var->name, rc) == 0) {
473 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
474
475 if (retptr == NULL) {
476 retptr = otc_text_map_new(NULL, 8);
477 if (retptr == NULL) {
478 FLT_OT_ERR("failed to create data");
479
480 break;
481 }
482 }
483
484 /*
485 * Eh, because the use of some characters is not allowed
486 * in the variable name, the conversion of the replaced
487 * characters to the original is performed here.
488 */
489 for (i = 0; ; )
490 if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
491 FLT_OT_ERR("failed to reverse variable name, buffer too small");
492
493 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
494
495 break;
496 } else {
497 char ch = var->name[rc + i + 1];
498
499 if (ch == '\0')
500 break;
501 else if (ch == FLT_OT_VAR_CHAR_DASH)
502 ch = '-';
503 else if (ch == FLT_OT_VAR_CHAR_SPACE)
504 ch = ' ';
505
506 ot_var_name[i++] = ch;
507 }
508 ot_var_name[i] = '\0';
509
510 if (retptr == NULL) {
511 break;
512 }
513 else if (otc_text_map_add(retptr, ot_var_name, i, var->data.u.str.area, var->data.u.str.data, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) {
514 FLT_OT_ERR("failed to add map data");
515
516 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
517
518 break;
519 }
520 }
521 }
Miroslav Zagorac6163e032022-02-23 18:15:56 +0100522 vars_rdunlock(vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100523
524 ot_text_map_show(retptr);
525
526 if ((retptr != NULL) && (retptr->count == 0)) {
527 FLT_OT_DBG(2, "WARNING: no variables found");
528
529 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
530 }
531
532 FLT_OT_RETURN(retptr);
533}
534
535/*
536 * Local variables:
537 * c-indent-level: 8
538 * c-basic-offset: 8
539 * End:
540 *
541 * vi: noexpandtab shiftwidth=8 tabstop=8
542 */