blob: 81cb9dfa5de275b588e6f9a4e0ed46a4cec417b0 [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
90 * flt_ot_get_vars -
91 *
92 * ARGUMENTS
93 * s -
94 * scope -
95 *
96 * DESCRIPTION
97 * -
98 *
99 * RETURN VALUE
Miroslav Zagorac222b3f32022-03-01 19:18:34 +0100100 * Returns the struct vars pointer for a stream and scope, or NULL if it does
101 * not exist.
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100102 */
103static inline struct vars *flt_ot_get_vars(struct stream *s, const char *scope)
104{
105 struct vars *retptr = NULL;
106
107 if (strcasecmp(scope, "proc") == 0)
Willy Tarreaucfc4f242021-05-08 11:41:28 +0200108 retptr = &(proc_vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100109 else if (strcasecmp(scope, "sess") == 0)
110 retptr = (&(s->sess->vars));
111 else if (strcasecmp(scope, "txn") == 0)
112 retptr = (&(s->vars_txn));
113 else if ((strcasecmp(scope, "req") == 0) || (strcasecmp(scope, "res") == 0))
114 retptr = (&(s->vars_reqres));
115
116 return retptr;
117}
118
119
120/***
121 * NAME
122 * flt_ot_normalize_name -
123 *
124 * ARGUMENTS
125 * var_name -
126 * size -
127 * len -
128 * name -
129 * err -
130 *
131 * DESCRIPTION
132 * -
133 *
134 * RETURN VALUE
135 * -
136 */
137static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, char **err)
138{
139 int retval = 0;
140
141 FLT_OT_FUNC("%p, %zu, %p, \"%s\", %p:%p", var_name, size, len, name, FLT_OT_DPTR_ARGS(err));
142
143 if (!FLT_OT_STR_ISVALID(name))
144 FLT_OT_RETURN(retval);
145
146 /*
147 * In case the name of the variable consists of several elements,
148 * the character '.' is added between them.
149 */
150 if ((*len == 0) || (var_name[*len - 1] == '.'))
151 /* Do nothing. */;
152 else if (*len < (size - 1))
153 var_name[(*len)++] = '.';
154 else
155 retval = -1;
156
157 /*
158 * HAProxy does not allow the use of variable names containing '-'
159 * or ' '. This of course applies to HTTP header names as well.
160 * Also, here the capital letters are converted to lowercase.
161 */
162 while (retval != -1)
163 if (*len >= (size - 1)) {
164 FLT_OT_ERR("failed to normalize variable name, buffer too small");
165
166 retval = -1;
167 } else {
168 uint8_t ch = name[retval];
169
170 if (ch == '\0')
171 break;
172 else if (ch == '-')
173 ch = FLT_OT_VAR_CHAR_DASH;
174 else if (ch == ' ')
175 ch = FLT_OT_VAR_CHAR_SPACE;
176 else if (isupper(ch))
177 ch = ist_lc[ch];
178
179 var_name[(*len)++] = ch;
180 retval++;
181 }
182
183 var_name[*len] = '\0';
184
185 FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
186
187 if (retval == -1)
188 *len = retval;
189
190 FLT_OT_RETURN(retval);
191}
192
193
194/***
195 * NAME
196 * flt_ot_var_name -
197 *
198 * ARGUMENTS
199 * scope -
200 * prefix -
201 * name -
202 * var_name -
203 * size -
204 * err -
205 *
206 * DESCRIPTION
Miroslav Zagorac222b3f32022-03-01 19:18:34 +0100207 * The function initializes the value of the 'smp' structure. If the 'data'
208 * argument is set, then the 'sample_data' member of the 'smp' structure is
209 * also initialized.
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100210 *
211 * RETURN VALUE
212 * -
213 */
214static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, char *var_name, size_t size, char **err)
215{
216 int retval = 0;
217
218 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p, %zu, %p:%p", scope, prefix, name, var_name, size, FLT_OT_DPTR_ARGS(err));
219
220 if (flt_ot_normalize_name(var_name, size, &retval, scope, err) >= 0)
221 if (flt_ot_normalize_name(var_name, size, &retval, prefix, err) >= 0)
222 (void)flt_ot_normalize_name(var_name, size, &retval, name, err);
223
224 if (retval == -1)
225 FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
226
227 FLT_OT_RETURN(retval);
228}
229
230
231/***
232 * NAME
233 * flt_ot_var_register -
234 *
235 * ARGUMENTS
236 * scope -
237 * prefix -
238 * name -
239 * err -
240 *
241 * DESCRIPTION
242 * -
243 *
244 * RETURN VALUE
245 * -
246 */
247int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
248{
249 struct arg arg;
250 char var_name[BUFSIZ];
251 int retval;
252
253 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
254
255 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
256 if (retval == -1)
257 FLT_OT_RETURN(retval);
258
259 /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
260 (void)memset(&arg, 0, sizeof(arg));
261 arg.type = ARGT_STR;
262 arg.data.str.area = var_name;
263 arg.data.str.data = retval;
264
265 if (vars_check_arg(&arg, err) == 0) {
266 FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
267
268 retval = -1;
269 } else {
270 FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name);
271 }
272
273 FLT_OT_RETURN(retval);
274}
275
276
277/***
278 * NAME
279 * flt_ot_var_set -
280 *
281 * ARGUMENTS
282 * s -
283 * scope -
284 * prefix -
285 * name -
286 * value -
287 * opt -
288 * err -
289 *
290 * DESCRIPTION
291 * -
292 *
293 * RETURN VALUE
294 * -
295 */
296int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
297{
298 struct sample smp;
299 char var_name[BUFSIZ];
300 int retval;
301
302 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
303
304 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
305 if (retval == -1)
306 FLT_OT_RETURN(retval);
307
308 (void)memset(&smp, 0, sizeof(smp));
309 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
310 smp.data.type = SMP_T_STR;
311 smp.data.u.str.area = (char *)value;
312 smp.data.u.str.data = strlen(value);
313
Miroslav Zagorac5ac14832022-03-01 18:42:54 +0100314 if (vars_set_by_name_ifexist(var_name, retval, &smp) == 0) {
315 FLT_OT_ERR("failed to set variable '%s'", var_name);
316
317 retval = -1;
318 } else {
319 FLT_OT_DBG(2, "variable '%s' set", var_name);
320 }
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100321
322 FLT_OT_RETURN(retval);
323}
324
325
326/***
327 * NAME
328 * flt_ot_var_unset -
329 *
330 * ARGUMENTS
331 * s -
332 * scope -
333 * prefix -
334 * name -
335 * opt -
336 * err -
337 *
338 * DESCRIPTION
339 * -
340 *
341 * RETURN VALUE
342 * -
343 */
344int flt_ot_var_unset(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err)
345{
346 struct sample smp;
347 char var_name[BUFSIZ];
348 int retval;
349
350 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, opt, FLT_OT_DPTR_ARGS(err));
351
352 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
353 if (retval == -1)
354 FLT_OT_RETURN(retval);
355
356 (void)memset(&smp, 0, sizeof(smp));
357 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
358
359 vars_unset_by_name_ifexist(var_name, retval, &smp);
360
361 FLT_OT_RETURN(retval);
362}
363
364
365/***
366 * NAME
367 * flt_ot_vars_unset -
368 *
369 * ARGUMENTS
370 * s -
371 * scope -
372 * prefix -
373 * opt -
374 * err -
375 *
376 * DESCRIPTION
377 * -
378 *
379 * RETURN VALUE
380 * -
381 */
382int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
383{
384 struct sample smp;
385 struct vars *vars;
386 struct var *var, *var_back;
387 char var_prefix[BUFSIZ], var_name[BUFSIZ];
388 uint size;
389 int var_prefix_len, var_name_len, retval = -1;
390
391 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
392
393 vars = flt_ot_get_vars(s, scope);
394 if (vars == NULL)
395 FLT_OT_RETURN(retval);
396
397 var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, var_prefix, sizeof(var_prefix), err);
398 if (var_prefix_len == -1)
399 FLT_OT_RETURN(retval);
400
401 retval = 0;
402
403 HA_RWLOCK_WRLOCK(VARS_LOCK, &(vars->rwlock));
404 list_for_each_entry_safe(var, var_back, &(vars->head), l) {
405 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len);
406
407 if (strncmp(var_prefix, var->name, var_prefix_len) == 0) {
408 var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name);
409 if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) {
410 FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name);
411
412 break;
413 }
414
415 FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area);
416
417 (void)memset(&smp, 0, sizeof(smp));
418 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
419
420 size = var_clear(var);
421 var_accounting_diff(vars, smp.sess, smp.strm, -size);
422
423 retval++;
424 }
425 }
426 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &(vars->rwlock));
427
428 FLT_OT_RETURN(retval);
429}
430
431
432/***
433 * NAME
434 * flt_ot_var_get -
435 *
436 * ARGUMENTS
437 * s -
438 * scope -
439 * prefix -
440 * name -
441 * value -
442 * opt -
443 * err -
444 *
445 * DESCRIPTION
446 * -
447 *
448 * RETURN VALUE
449 * -
450 */
451int flt_ot_var_get(struct stream *s, const char *scope, const char *prefix, const char *name, char **value, uint opt, char **err)
452{
453 struct sample smp;
454 char var_name[BUFSIZ], var_value[BUFSIZ];
455 int retval;
456
457 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p, %u, %p:%p", s, scope, prefix, name, FLT_OT_DPTR_ARGS(value), opt, FLT_OT_DPTR_ARGS(err));
458
459 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
460 if (retval == -1)
461 FLT_OT_RETURN(retval);
462
463 (void)memset(&smp, 0, sizeof(smp));
464 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
465
466 if (vars_get_by_name(var_name, retval, &smp)) {
467 retval = flt_ot_sample_to_str(&(smp.data), var_value, sizeof(var_value), err);
468 if (retval != -1)
469 FLT_OT_DBG(3, "data type %d: '%s' = '%s'", smp.data.type, var_name, var_value);
470 } else {
471 FLT_OT_ERR("failed to get variable '%s'", var_name);
472
473 retval = -1;
474 }
475
476 FLT_OT_RETURN(retval);
477}
478
479
480/***
481 * NAME
482 * flt_ot_vars_get -
483 *
484 * ARGUMENTS
485 * s -
486 * scope -
487 * prefix -
488 * opt -
489 * err -
490 *
491 * DESCRIPTION
492 * -
493 *
494 * RETURN VALUE
495 * -
496 */
497struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
498{
499 struct vars *vars;
500 const struct var *var;
501 char var_name[BUFSIZ], ot_var_name[BUFSIZ];
502 int rc, i;
503 struct otc_text_map *retptr = NULL;
504
505 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
506
507 vars = flt_ot_get_vars(s, scope);
508 if (vars == NULL)
509 FLT_OT_RETURN(retptr);
510
511 rc = flt_ot_var_name(NULL, prefix, NULL, var_name, sizeof(var_name), err);
512 if (rc == -1)
513 FLT_OT_RETURN(retptr);
514
515 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
516 list_for_each_entry(var, &(vars->head), l) {
517 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
518
519 if (strncmp(var_name, var->name, rc) == 0) {
520 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
521
522 if (retptr == NULL) {
523 retptr = otc_text_map_new(NULL, 8);
524 if (retptr == NULL) {
525 FLT_OT_ERR("failed to create data");
526
527 break;
528 }
529 }
530
531 /*
532 * Eh, because the use of some characters is not allowed
533 * in the variable name, the conversion of the replaced
534 * characters to the original is performed here.
535 */
536 for (i = 0; ; )
537 if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
538 FLT_OT_ERR("failed to reverse variable name, buffer too small");
539
540 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
541
542 break;
543 } else {
544 char ch = var->name[rc + i + 1];
545
546 if (ch == '\0')
547 break;
548 else if (ch == FLT_OT_VAR_CHAR_DASH)
549 ch = '-';
550 else if (ch == FLT_OT_VAR_CHAR_SPACE)
551 ch = ' ';
552
553 ot_var_name[i++] = ch;
554 }
555 ot_var_name[i] = '\0';
556
557 if (retptr == NULL) {
558 break;
559 }
560 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) {
561 FLT_OT_ERR("failed to add map data");
562
563 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
564
565 break;
566 }
567 }
568 }
569 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
570
571 ot_text_map_show(retptr);
572
573 if ((retptr != NULL) && (retptr->count == 0)) {
574 FLT_OT_DBG(2, "WARNING: no variables found");
575
576 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
577 }
578
579 FLT_OT_RETURN(retptr);
580}
581
582/*
583 * Local variables:
584 * c-indent-level: 8
585 * c-basic-offset: 8
586 * End:
587 *
588 * vi: noexpandtab shiftwidth=8 tabstop=8
589 */