blob: d307b52ec6adf5c9acc58ee355bcef4451e4daf4 [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 Zagorac222b3f32022-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
47 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
48 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);
50 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
51}
52
53
54/***
55 * NAME
56 * flt_ot_vars_dump -
57 *
58 * ARGUMENTS
59 * s -
60 *
61 * DESCRIPTION
Miroslav Zagorac222b3f32022-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 Zagoracf508f7e2022-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 Zagorac222b3f32022-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 -
161 * err -
162 *
163 * DESCRIPTION
164 * -
165 *
166 * RETURN VALUE
167 * -
168 */
169static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, char **err)
170{
171 int retval = 0;
172
173 FLT_OT_FUNC("%p, %zu, %p, \"%s\", %p:%p", var_name, size, len, name, FLT_OT_DPTR_ARGS(err));
174
175 if (!FLT_OT_STR_ISVALID(name))
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100176 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100177
178 /*
179 * In case the name of the variable consists of several elements,
180 * the character '.' is added between them.
181 */
182 if ((*len == 0) || (var_name[*len - 1] == '.'))
183 /* Do nothing. */;
184 else if (*len < (size - 1))
185 var_name[(*len)++] = '.';
186 else
187 retval = -1;
188
189 /*
190 * HAProxy does not allow the use of variable names containing '-'
191 * or ' '. This of course applies to HTTP header names as well.
192 * Also, here the capital letters are converted to lowercase.
193 */
194 while (retval != -1)
195 if (*len >= (size - 1)) {
196 FLT_OT_ERR("failed to normalize variable name, buffer too small");
197
198 retval = -1;
199 } else {
200 uint8_t ch = name[retval];
201
202 if (ch == '\0')
203 break;
204 else if (ch == '-')
205 ch = FLT_OT_VAR_CHAR_DASH;
206 else if (ch == ' ')
207 ch = FLT_OT_VAR_CHAR_SPACE;
208 else if (isupper(ch))
209 ch = ist_lc[ch];
210
211 var_name[(*len)++] = ch;
212 retval++;
213 }
214
215 var_name[*len] = '\0';
216
217 FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
218
219 if (retval == -1)
220 *len = retval;
221
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100222 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100223}
224
225
226/***
227 * NAME
228 * flt_ot_var_name -
229 *
230 * ARGUMENTS
231 * scope -
232 * prefix -
233 * name -
234 * var_name -
235 * size -
236 * err -
237 *
238 * DESCRIPTION
Miroslav Zagorac222b3f32022-03-01 19:18:34 +0100239 * The function initializes the value of the 'smp' structure. If the 'data'
240 * argument is set, then the 'sample_data' member of the 'smp' structure is
241 * also initialized.
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100242 *
243 * RETURN VALUE
244 * -
245 */
246static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, char *var_name, size_t size, char **err)
247{
248 int retval = 0;
249
250 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p, %zu, %p:%p", scope, prefix, name, var_name, size, FLT_OT_DPTR_ARGS(err));
251
252 if (flt_ot_normalize_name(var_name, size, &retval, scope, err) >= 0)
253 if (flt_ot_normalize_name(var_name, size, &retval, prefix, err) >= 0)
254 (void)flt_ot_normalize_name(var_name, size, &retval, name, err);
255
256 if (retval == -1)
257 FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
258
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100259 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100260}
261
262
263/***
264 * NAME
265 * flt_ot_var_register -
266 *
267 * ARGUMENTS
268 * scope -
269 * prefix -
270 * name -
271 * err -
272 *
273 * DESCRIPTION
274 * -
275 *
276 * RETURN VALUE
277 * -
278 */
279int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
280{
281 struct arg arg;
282 char var_name[BUFSIZ];
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100283 int retval = -1, var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100284
285 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
286
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100287 var_name_len = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
288 if (var_name_len == -1)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100289 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100290
291 /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
292 (void)memset(&arg, 0, sizeof(arg));
293 arg.type = ARGT_STR;
294 arg.data.str.area = var_name;
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100295 arg.data.str.data = var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100296
297 if (vars_check_arg(&arg, err) == 0) {
298 FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100299 } else {
300 FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name);
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100301
302 retval = var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100303 }
304
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100305 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100306}
307
308
309/***
310 * NAME
311 * flt_ot_var_set -
312 *
313 * ARGUMENTS
314 * s -
315 * scope -
316 * prefix -
317 * name -
318 * value -
319 * opt -
320 * err -
321 *
322 * DESCRIPTION
323 * -
324 *
325 * RETURN VALUE
326 * -
327 */
328int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
329{
330 struct sample smp;
331 char var_name[BUFSIZ];
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100332 int retval = -1, var_name_len;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100333
334 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
335
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100336 var_name_len = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
337 if (var_name_len == -1)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100338 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100339
Miroslav Zagoracf508f7e2022-03-01 18:41:36 +0100340 flt_ot_smp_init(s, &smp, opt, SMP_T_STR, value);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100341
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100342 if (vars_set_by_name_ifexist(var_name, var_name_len, &smp) == 0) {
Miroslav Zagorac5ac14832022-03-01 18:42:54 +0100343 FLT_OT_ERR("failed to set variable '%s'", var_name);
Miroslav Zagorac5ac14832022-03-01 18:42:54 +0100344 } else {
345 FLT_OT_DBG(2, "variable '%s' set", var_name);
Miroslav Zagorac44eaa942022-03-01 18:44:36 +0100346
347 retval = var_name_len;
Miroslav Zagorac5ac14832022-03-01 18:42:54 +0100348 }
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100349
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100350 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100351}
352
353
354/***
355 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100356 * flt_ot_vars_unset -
357 *
358 * ARGUMENTS
359 * s -
360 * scope -
361 * prefix -
362 * opt -
363 * err -
364 *
365 * DESCRIPTION
366 * -
367 *
368 * RETURN VALUE
369 * -
370 */
371int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
372{
373 struct sample smp;
374 struct vars *vars;
375 struct var *var, *var_back;
376 char var_prefix[BUFSIZ], var_name[BUFSIZ];
377 uint size;
378 int var_prefix_len, var_name_len, retval = -1;
379
380 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
381
382 vars = flt_ot_get_vars(s, scope);
383 if (vars == NULL)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100384 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100385
386 var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, var_prefix, sizeof(var_prefix), err);
387 if (var_prefix_len == -1)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100388 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100389
390 retval = 0;
391
392 HA_RWLOCK_WRLOCK(VARS_LOCK, &(vars->rwlock));
393 list_for_each_entry_safe(var, var_back, &(vars->head), l) {
394 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len);
395
396 if (strncmp(var_prefix, var->name, var_prefix_len) == 0) {
397 var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name);
398 if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) {
399 FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name);
400
401 break;
402 }
403
404 FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area);
405
Miroslav Zagoracf508f7e2022-03-01 18:41:36 +0100406 size = var_clear(var, 1);
407 flt_ot_smp_init(s, &smp, opt, 0, NULL);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100408 var_accounting_diff(vars, smp.sess, smp.strm, -size);
409
410 retval++;
411 }
412 }
413 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &(vars->rwlock));
414
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100415 FLT_OT_RETURN_INT(retval);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100416}
417
418
419/***
420 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100421 * flt_ot_vars_get -
422 *
423 * ARGUMENTS
424 * s -
425 * scope -
426 * prefix -
427 * opt -
428 * err -
429 *
430 * DESCRIPTION
431 * -
432 *
433 * RETURN VALUE
434 * -
435 */
436struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
437{
438 struct vars *vars;
439 const struct var *var;
440 char var_name[BUFSIZ], ot_var_name[BUFSIZ];
441 int rc, i;
442 struct otc_text_map *retptr = NULL;
443
444 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
445
446 vars = flt_ot_get_vars(s, scope);
447 if (vars == NULL)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100448 FLT_OT_RETURN_PTR(retptr);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100449
450 rc = flt_ot_var_name(NULL, prefix, NULL, var_name, sizeof(var_name), err);
451 if (rc == -1)
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100452 FLT_OT_RETURN_PTR(retptr);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100453
454 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
455 list_for_each_entry(var, &(vars->head), l) {
456 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
457
458 if (strncmp(var_name, var->name, rc) == 0) {
459 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
460
461 if (retptr == NULL) {
462 retptr = otc_text_map_new(NULL, 8);
463 if (retptr == NULL) {
464 FLT_OT_ERR("failed to create data");
465
466 break;
467 }
468 }
469
470 /*
471 * Eh, because the use of some characters is not allowed
472 * in the variable name, the conversion of the replaced
473 * characters to the original is performed here.
474 */
475 for (i = 0; ; )
476 if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
477 FLT_OT_ERR("failed to reverse variable name, buffer too small");
478
479 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
480
481 break;
482 } else {
483 char ch = var->name[rc + i + 1];
484
485 if (ch == '\0')
486 break;
487 else if (ch == FLT_OT_VAR_CHAR_DASH)
488 ch = '-';
489 else if (ch == FLT_OT_VAR_CHAR_SPACE)
490 ch = ' ';
491
492 ot_var_name[i++] = ch;
493 }
494 ot_var_name[i] = '\0';
495
496 if (retptr == NULL) {
497 break;
498 }
499 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) {
500 FLT_OT_ERR("failed to add map data");
501
502 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
503
504 break;
505 }
506 }
507 }
508 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
509
510 ot_text_map_show(retptr);
511
512 if ((retptr != NULL) && (retptr->count == 0)) {
513 FLT_OT_DBG(2, "WARNING: no variables found");
514
515 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
516 }
517
Miroslav Zagorac5b5b0622022-03-04 09:56:00 +0100518 FLT_OT_RETURN_PTR(retptr);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100519}
520
521/*
522 * Local variables:
523 * c-indent-level: 8
524 * c-basic-offset: 8
525 * End:
526 *
527 * vi: noexpandtab shiftwidth=8 tabstop=8
528 */