blob: fff54acac568b4646ff42d90df1c9a840f9e63f1 [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
34 * -
35 *
36 * RETURN VALUE
37 * This function does not return a value.
38 */
39static void flt_ot_vars_scope_dump(struct vars *vars, const char *scope)
40{
41 const struct var *var;
42
43 if (vars == NULL)
44 return;
45
46 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
47 list_for_each_entry(var, &(vars->head), l)
48 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
49 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
50}
51
52
53/***
54 * NAME
55 * flt_ot_vars_dump -
56 *
57 * ARGUMENTS
58 * s -
59 *
60 * DESCRIPTION
61 * -
62 *
63 * RETURN VALUE
64 * This function does not return a value.
65 */
66void flt_ot_vars_dump(struct stream *s)
67{
68 FLT_OT_FUNC("%p", s);
69
70 /*
71 * It would be nice if we could use the get_vars() function from HAProxy
72 * source here to get the value of the 'vars' pointer, but it is defined
73 * as 'static inline', so unfortunately none of this is possible.
74 */
Willy Tarreaucfc4f242021-05-08 11:41:28 +020075 flt_ot_vars_scope_dump(&(proc_vars), "PROC");
Miroslav Zagorac70230c62020-12-09 16:54:31 +010076 flt_ot_vars_scope_dump(&(s->sess->vars), "SESS");
77 flt_ot_vars_scope_dump(&(s->vars_txn), "TXN");
78 flt_ot_vars_scope_dump(&(s->vars_reqres), "REQ/RES");
79
80 FLT_OT_RETURN();
81}
82
83#endif /* DEBUG_OT */
84
85
86/***
87 * NAME
88 * flt_ot_get_vars -
89 *
90 * ARGUMENTS
91 * s -
92 * scope -
93 *
94 * DESCRIPTION
95 * -
96 *
97 * RETURN VALUE
98 * -
99 */
100static inline struct vars *flt_ot_get_vars(struct stream *s, const char *scope)
101{
102 struct vars *retptr = NULL;
103
104 if (strcasecmp(scope, "proc") == 0)
Willy Tarreaucfc4f242021-05-08 11:41:28 +0200105 retptr = &(proc_vars);
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100106 else if (strcasecmp(scope, "sess") == 0)
107 retptr = (&(s->sess->vars));
108 else if (strcasecmp(scope, "txn") == 0)
109 retptr = (&(s->vars_txn));
110 else if ((strcasecmp(scope, "req") == 0) || (strcasecmp(scope, "res") == 0))
111 retptr = (&(s->vars_reqres));
112
113 return retptr;
114}
115
116
117/***
118 * NAME
119 * flt_ot_normalize_name -
120 *
121 * ARGUMENTS
122 * var_name -
123 * size -
124 * len -
125 * name -
126 * err -
127 *
128 * DESCRIPTION
129 * -
130 *
131 * RETURN VALUE
132 * -
133 */
134static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, char **err)
135{
136 int retval = 0;
137
138 FLT_OT_FUNC("%p, %zu, %p, \"%s\", %p:%p", var_name, size, len, name, FLT_OT_DPTR_ARGS(err));
139
140 if (!FLT_OT_STR_ISVALID(name))
141 FLT_OT_RETURN(retval);
142
143 /*
144 * In case the name of the variable consists of several elements,
145 * the character '.' is added between them.
146 */
147 if ((*len == 0) || (var_name[*len - 1] == '.'))
148 /* Do nothing. */;
149 else if (*len < (size - 1))
150 var_name[(*len)++] = '.';
151 else
152 retval = -1;
153
154 /*
155 * HAProxy does not allow the use of variable names containing '-'
156 * or ' '. This of course applies to HTTP header names as well.
157 * Also, here the capital letters are converted to lowercase.
158 */
159 while (retval != -1)
160 if (*len >= (size - 1)) {
161 FLT_OT_ERR("failed to normalize variable name, buffer too small");
162
163 retval = -1;
164 } else {
165 uint8_t ch = name[retval];
166
167 if (ch == '\0')
168 break;
169 else if (ch == '-')
170 ch = FLT_OT_VAR_CHAR_DASH;
171 else if (ch == ' ')
172 ch = FLT_OT_VAR_CHAR_SPACE;
173 else if (isupper(ch))
174 ch = ist_lc[ch];
175
176 var_name[(*len)++] = ch;
177 retval++;
178 }
179
180 var_name[*len] = '\0';
181
182 FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
183
184 if (retval == -1)
185 *len = retval;
186
187 FLT_OT_RETURN(retval);
188}
189
190
191/***
192 * NAME
193 * flt_ot_var_name -
194 *
195 * ARGUMENTS
196 * scope -
197 * prefix -
198 * name -
199 * var_name -
200 * size -
201 * err -
202 *
203 * DESCRIPTION
204 * -
205 *
206 * RETURN VALUE
207 * -
208 */
209static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, char *var_name, size_t size, char **err)
210{
211 int retval = 0;
212
213 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p, %zu, %p:%p", scope, prefix, name, var_name, size, FLT_OT_DPTR_ARGS(err));
214
215 if (flt_ot_normalize_name(var_name, size, &retval, scope, err) >= 0)
216 if (flt_ot_normalize_name(var_name, size, &retval, prefix, err) >= 0)
217 (void)flt_ot_normalize_name(var_name, size, &retval, name, err);
218
219 if (retval == -1)
220 FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
221
222 FLT_OT_RETURN(retval);
223}
224
225
226/***
227 * NAME
228 * flt_ot_var_register -
229 *
230 * ARGUMENTS
231 * scope -
232 * prefix -
233 * name -
234 * err -
235 *
236 * DESCRIPTION
237 * -
238 *
239 * RETURN VALUE
240 * -
241 */
242int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
243{
244 struct arg arg;
245 char var_name[BUFSIZ];
246 int retval;
247
248 FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
249
250 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
251 if (retval == -1)
252 FLT_OT_RETURN(retval);
253
254 /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
255 (void)memset(&arg, 0, sizeof(arg));
256 arg.type = ARGT_STR;
257 arg.data.str.area = var_name;
258 arg.data.str.data = retval;
259
260 if (vars_check_arg(&arg, err) == 0) {
261 FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
262
263 retval = -1;
264 } else {
265 FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name);
266 }
267
268 FLT_OT_RETURN(retval);
269}
270
271
272/***
273 * NAME
274 * flt_ot_var_set -
275 *
276 * ARGUMENTS
277 * s -
278 * scope -
279 * prefix -
280 * name -
281 * value -
282 * opt -
283 * err -
284 *
285 * DESCRIPTION
286 * -
287 *
288 * RETURN VALUE
289 * -
290 */
291int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
292{
293 struct sample smp;
294 char var_name[BUFSIZ];
295 int retval;
296
297 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
298
299 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
300 if (retval == -1)
301 FLT_OT_RETURN(retval);
302
303 (void)memset(&smp, 0, sizeof(smp));
304 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
305 smp.data.type = SMP_T_STR;
306 smp.data.u.str.area = (char *)value;
307 smp.data.u.str.data = strlen(value);
308
309 vars_set_by_name_ifexist(var_name, retval, &smp);
310
311 FLT_OT_RETURN(retval);
312}
313
314
315/***
316 * NAME
317 * flt_ot_var_unset -
318 *
319 * ARGUMENTS
320 * s -
321 * scope -
322 * prefix -
323 * name -
324 * opt -
325 * err -
326 *
327 * DESCRIPTION
328 * -
329 *
330 * RETURN VALUE
331 * -
332 */
333int flt_ot_var_unset(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err)
334{
335 struct sample smp;
336 char var_name[BUFSIZ];
337 int retval;
338
339 FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, opt, FLT_OT_DPTR_ARGS(err));
340
341 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
342 if (retval == -1)
343 FLT_OT_RETURN(retval);
344
345 (void)memset(&smp, 0, sizeof(smp));
346 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
347
348 vars_unset_by_name_ifexist(var_name, retval, &smp);
349
350 FLT_OT_RETURN(retval);
351}
352
353
354/***
355 * NAME
356 * 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)
384 FLT_OT_RETURN(retval);
385
386 var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, var_prefix, sizeof(var_prefix), err);
387 if (var_prefix_len == -1)
388 FLT_OT_RETURN(retval);
389
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
406 (void)memset(&smp, 0, sizeof(smp));
407 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
408
409 size = var_clear(var);
410 var_accounting_diff(vars, smp.sess, smp.strm, -size);
411
412 retval++;
413 }
414 }
415 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &(vars->rwlock));
416
417 FLT_OT_RETURN(retval);
418}
419
420
421/***
422 * NAME
423 * flt_ot_var_get -
424 *
425 * ARGUMENTS
426 * s -
427 * scope -
428 * prefix -
429 * name -
430 * value -
431 * opt -
432 * err -
433 *
434 * DESCRIPTION
435 * -
436 *
437 * RETURN VALUE
438 * -
439 */
440int flt_ot_var_get(struct stream *s, const char *scope, const char *prefix, const char *name, char **value, uint opt, char **err)
441{
442 struct sample smp;
443 char var_name[BUFSIZ], var_value[BUFSIZ];
444 int retval;
445
446 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));
447
448 retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
449 if (retval == -1)
450 FLT_OT_RETURN(retval);
451
452 (void)memset(&smp, 0, sizeof(smp));
453 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
454
455 if (vars_get_by_name(var_name, retval, &smp)) {
456 retval = flt_ot_sample_to_str(&(smp.data), var_value, sizeof(var_value), err);
457 if (retval != -1)
458 FLT_OT_DBG(3, "data type %d: '%s' = '%s'", smp.data.type, var_name, var_value);
459 } else {
460 FLT_OT_ERR("failed to get variable '%s'", var_name);
461
462 retval = -1;
463 }
464
465 FLT_OT_RETURN(retval);
466}
467
468
469/***
470 * NAME
471 * flt_ot_vars_get -
472 *
473 * ARGUMENTS
474 * s -
475 * scope -
476 * prefix -
477 * opt -
478 * err -
479 *
480 * DESCRIPTION
481 * -
482 *
483 * RETURN VALUE
484 * -
485 */
486struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
487{
488 struct vars *vars;
489 const struct var *var;
490 char var_name[BUFSIZ], ot_var_name[BUFSIZ];
491 int rc, i;
492 struct otc_text_map *retptr = NULL;
493
494 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
495
496 vars = flt_ot_get_vars(s, scope);
497 if (vars == NULL)
498 FLT_OT_RETURN(retptr);
499
500 rc = flt_ot_var_name(NULL, prefix, NULL, var_name, sizeof(var_name), err);
501 if (rc == -1)
502 FLT_OT_RETURN(retptr);
503
504 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
505 list_for_each_entry(var, &(vars->head), l) {
506 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
507
508 if (strncmp(var_name, var->name, rc) == 0) {
509 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
510
511 if (retptr == NULL) {
512 retptr = otc_text_map_new(NULL, 8);
513 if (retptr == NULL) {
514 FLT_OT_ERR("failed to create data");
515
516 break;
517 }
518 }
519
520 /*
521 * Eh, because the use of some characters is not allowed
522 * in the variable name, the conversion of the replaced
523 * characters to the original is performed here.
524 */
525 for (i = 0; ; )
526 if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
527 FLT_OT_ERR("failed to reverse variable name, buffer too small");
528
529 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
530
531 break;
532 } else {
533 char ch = var->name[rc + i + 1];
534
535 if (ch == '\0')
536 break;
537 else if (ch == FLT_OT_VAR_CHAR_DASH)
538 ch = '-';
539 else if (ch == FLT_OT_VAR_CHAR_SPACE)
540 ch = ' ';
541
542 ot_var_name[i++] = ch;
543 }
544 ot_var_name[i] = '\0';
545
546 if (retptr == NULL) {
547 break;
548 }
549 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) {
550 FLT_OT_ERR("failed to add map data");
551
552 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
553
554 break;
555 }
556 }
557 }
558 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
559
560 ot_text_map_show(retptr);
561
562 if ((retptr != NULL) && (retptr->count == 0)) {
563 FLT_OT_DBG(2, "WARNING: no variables found");
564
565 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
566 }
567
568 FLT_OT_RETURN(retptr);
569}
570
571/*
572 * Local variables:
573 * c-indent-level: 8
574 * c-basic-offset: 8
575 * End:
576 *
577 * vi: noexpandtab shiftwidth=8 tabstop=8
578 */