blob: 8769d54e75e16d679c1acd7f632ca7bc390e41b9 [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
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100328 * flt_ot_vars_unset -
329 *
330 * ARGUMENTS
331 * s -
332 * scope -
333 * prefix -
334 * opt -
335 * err -
336 *
337 * DESCRIPTION
338 * -
339 *
340 * RETURN VALUE
341 * -
342 */
343int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
344{
345 struct sample smp;
346 struct vars *vars;
347 struct var *var, *var_back;
348 char var_prefix[BUFSIZ], var_name[BUFSIZ];
349 uint size;
350 int var_prefix_len, var_name_len, retval = -1;
351
352 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
353
354 vars = flt_ot_get_vars(s, scope);
355 if (vars == NULL)
356 FLT_OT_RETURN(retval);
357
358 var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, var_prefix, sizeof(var_prefix), err);
359 if (var_prefix_len == -1)
360 FLT_OT_RETURN(retval);
361
362 retval = 0;
363
364 HA_RWLOCK_WRLOCK(VARS_LOCK, &(vars->rwlock));
365 list_for_each_entry_safe(var, var_back, &(vars->head), l) {
366 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len);
367
368 if (strncmp(var_prefix, var->name, var_prefix_len) == 0) {
369 var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name);
370 if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) {
371 FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name);
372
373 break;
374 }
375
376 FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area);
377
378 (void)memset(&smp, 0, sizeof(smp));
379 (void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
380
381 size = var_clear(var);
382 var_accounting_diff(vars, smp.sess, smp.strm, -size);
383
384 retval++;
385 }
386 }
387 HA_RWLOCK_WRUNLOCK(VARS_LOCK, &(vars->rwlock));
388
389 FLT_OT_RETURN(retval);
390}
391
392
393/***
394 * NAME
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100395 * flt_ot_vars_get -
396 *
397 * ARGUMENTS
398 * s -
399 * scope -
400 * prefix -
401 * opt -
402 * err -
403 *
404 * DESCRIPTION
405 * -
406 *
407 * RETURN VALUE
408 * -
409 */
410struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
411{
412 struct vars *vars;
413 const struct var *var;
414 char var_name[BUFSIZ], ot_var_name[BUFSIZ];
415 int rc, i;
416 struct otc_text_map *retptr = NULL;
417
418 FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
419
420 vars = flt_ot_get_vars(s, scope);
421 if (vars == NULL)
422 FLT_OT_RETURN(retptr);
423
424 rc = flt_ot_var_name(NULL, prefix, NULL, var_name, sizeof(var_name), err);
425 if (rc == -1)
426 FLT_OT_RETURN(retptr);
427
428 HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
429 list_for_each_entry(var, &(vars->head), l) {
430 FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
431
432 if (strncmp(var_name, var->name, rc) == 0) {
433 FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
434
435 if (retptr == NULL) {
436 retptr = otc_text_map_new(NULL, 8);
437 if (retptr == NULL) {
438 FLT_OT_ERR("failed to create data");
439
440 break;
441 }
442 }
443
444 /*
445 * Eh, because the use of some characters is not allowed
446 * in the variable name, the conversion of the replaced
447 * characters to the original is performed here.
448 */
449 for (i = 0; ; )
450 if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
451 FLT_OT_ERR("failed to reverse variable name, buffer too small");
452
453 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
454
455 break;
456 } else {
457 char ch = var->name[rc + i + 1];
458
459 if (ch == '\0')
460 break;
461 else if (ch == FLT_OT_VAR_CHAR_DASH)
462 ch = '-';
463 else if (ch == FLT_OT_VAR_CHAR_SPACE)
464 ch = ' ';
465
466 ot_var_name[i++] = ch;
467 }
468 ot_var_name[i] = '\0';
469
470 if (retptr == NULL) {
471 break;
472 }
473 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) {
474 FLT_OT_ERR("failed to add map data");
475
476 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
477
478 break;
479 }
480 }
481 }
482 HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
483
484 ot_text_map_show(retptr);
485
486 if ((retptr != NULL) && (retptr->count == 0)) {
487 FLT_OT_DBG(2, "WARNING: no variables found");
488
489 otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
490 }
491
492 FLT_OT_RETURN(retptr);
493}
494
495/*
496 * Local variables:
497 * c-indent-level: 8
498 * c-basic-offset: 8
499 * End:
500 *
501 * vi: noexpandtab shiftwidth=8 tabstop=8
502 */