master
h 1,197 lines 34.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_WEB_BUFFER_H
4 #define NETDATA_WEB_BUFFER_H 1
5
6 #include "../uuid/uuid.h"
7 #include "../http/content_type.h"
8 #include "../clocks/clocks.h"
9 #include "../string/utf8.h"
10 #include "../libnetdata.h"
11
12 #define API_RELATIVE_TIME_MAX (time_t)(3 * 365 * 86400)
13
14 #define BUFFER_JSON_MAX_DEPTH 32 // max is 255
15
16 // gcc with libstdc++ may require this,
17 // but with libc++ it does not work correctly.
18 #if defined(__cplusplus) && !defined(_LIBCPP_VERSION)
19 #include <cmath>
20 using std::isinf;
21 using std::isnan;
22 #endif
23
24 extern const char hex_digits[16];
25 extern const char hex_digits_lower[16];
26 extern const char base64_digits[64];
27 extern unsigned char hex_value_from_ascii[256];
28 extern unsigned char base64_value_from_ascii[256];
29
30 typedef enum __attribute__ ((__packed__)) {
31 BUFFER_JSON_EMPTY = 0,
32 BUFFER_JSON_OBJECT,
33 BUFFER_JSON_ARRAY,
34 } BUFFER_JSON_NODE_TYPE;
35
36 typedef struct web_buffer_json_node {
37 BUFFER_JSON_NODE_TYPE type;
38 uint32_t count:24;
39 } BUFFER_JSON_NODE;
40
41 #define BUFFER_QUOTE_MAX_SIZE 7
42
43 typedef enum __attribute__ ((__packed__)) {
44 WB_CONTENT_CACHEABLE = (1 << 0),
45 WB_CONTENT_NO_CACHEABLE = (1 << 1),
46 } BUFFER_OPTIONS;
47
48 typedef enum __attribute__ ((__packed__)) {
49 BUFFER_JSON_OPTIONS_DEFAULT = 0,
50 BUFFER_JSON_OPTIONS_MINIFY = (1 << 0),
51 BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS = (1 << 1),
52 BUFFER_JSON_OPTIONS_NON_ANONYMOUS = (1 << 2),
53 } BUFFER_JSON_OPTIONS;
54
55 typedef struct web_buffer {
56 uint32_t size; // allocation size of buffer, in bytes
57 uint32_t len; // current data length in buffer, in bytes
58 HTTP_CONTENT_TYPE content_type; // the content type of the data in the buffer
59 BUFFER_OPTIONS options; // options related to the content
60 uint16_t response_code;
61 time_t date; // the timestamp this content has been generated
62 time_t expires; // the timestamp this content expires
63 size_t *statistics;
64 char *buffer; // the buffer itself
65
66 struct {
67 char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
68 char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
69 int8_t depth;
70 BUFFER_JSON_OPTIONS options;
71 BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
72 } json;
73 } BUFFER;
74
75 #define CLEAN_BUFFER _cleanup_(buffer_freep) BUFFER
76
77 #define buffer_cacheable(wb) do { (wb)->options |= WB_CONTENT_CACHEABLE; if((wb)->options & WB_CONTENT_NO_CACHEABLE) (wb)->options &= ~WB_CONTENT_NO_CACHEABLE; } while(0)
78 #define buffer_no_cacheable(wb) do { (wb)->options |= WB_CONTENT_NO_CACHEABLE; if((wb)->options & WB_CONTENT_CACHEABLE) (wb)->options &= ~WB_CONTENT_CACHEABLE; (wb)->expires = 0; } while(0)
79
80 #define buffer_strlen(wb) (size_t)((wb)->len)
81
82 #define BUFFER_OVERFLOW_EOF "EOF"
83
84 #ifdef NETDATA_INTERNAL_CHECKS
85 #define buffer_overflow_check(b) _buffer_overflow_check(b)
86 #else
87 #define buffer_overflow_check(b)
88 #endif
89
90 static inline void _buffer_overflow_check(BUFFER *b __maybe_unused) {
91 assert(b->len <= b->size &&
92 "BUFFER: length is above buffer size.");
93
94 assert(!(b->buffer && (b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0)) &&
95 "BUFFER: detected overflow.");
96 }
97
98 ALWAYS_INLINE
99 static void buffer_flush(BUFFER *wb) {
100 wb->len = 0;
101
102 wb->json.depth = 0;
103 wb->json.stack[0].type = BUFFER_JSON_EMPTY;
104 wb->json.stack[0].count = 0;
105
106 if(wb->buffer)
107 wb->buffer[0] = '\0';
108 }
109
110 void buffer_reset(BUFFER *wb);
111
112 void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
113 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
114
115 BUFFER *buffer_create(size_t size, size_t *statistics);
116 void buffer_free(BUFFER *b);
117 void buffer_increase(BUFFER *b, size_t free_size_required);
118
119 static inline void buffer_freep(BUFFER **bp) {
120 if(bp) buffer_free(*bp);
121 }
122
123 void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4);
124 void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
125 void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
126 void buffer_json_member_add_sprintf(BUFFER *wb, const char *key, const char *fmt, ...) PRINTFLIKE(3,4);
127 void buffer_json_add_array_item_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
128 void buffer_strcat_htmlescape(BUFFER *wb, const char *txt);
129
130 void buffer_char_replace(BUFFER *wb, char from, char to);
131
132 void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit);
133
134 ALWAYS_INLINE
135 static void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
136 if(unlikely(buffer->len + needed_free_size >= buffer->size))
137 buffer_increase(buffer, needed_free_size + 1);
138 }
139
140 void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth,
141 bool add_anonymous_object, BUFFER_JSON_OPTIONS options);
142
143 void buffer_json_finalize(BUFFER *wb);
144
145 ALWAYS_INLINE
146 static const char *buffer_tostring(BUFFER *wb)
147 {
148 if(unlikely(!wb))
149 return NULL;
150
151 buffer_need_bytes(wb, 1);
152 wb->buffer[wb->len] = '\0';
153
154 buffer_overflow_check(wb);
155
156 return(wb->buffer);
157 }
158
159 ALWAYS_INLINE
160 static void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE type) {
161 #ifdef NETDATA_INTERNAL_CHECKS
162 assert(wb->json.depth <= BUFFER_JSON_MAX_DEPTH && "BUFFER JSON: max nesting reached");
163 #endif
164 wb->json.depth++;
165 #ifdef NETDATA_INTERNAL_CHECKS
166 assert(wb->json.depth >= 0 && "Depth wrapped around and is negative");
167 #endif
168 wb->json.stack[wb->json.depth].count = 0;
169 wb->json.stack[wb->json.depth].type = type;
170 }
171
172 ALWAYS_INLINE
173 static void _buffer_json_depth_pop(BUFFER *wb) {
174 wb->json.depth--;
175 }
176
177 ALWAYS_INLINE
178 static void buffer_putc(BUFFER *wb, char c) {
179 buffer_need_bytes(wb, 2);
180 wb->buffer[wb->len++] = c;
181 wb->buffer[wb->len] = '\0';
182 buffer_overflow_check(wb);
183 }
184
185 ALWAYS_INLINE
186 static void buffer_fast_rawcat(BUFFER *wb, const char *txt, size_t len) {
187 if(unlikely(!txt || !*txt || !len)) return;
188
189 buffer_need_bytes(wb, len + 1);
190
191 const char *t = txt;
192 const char *e = &txt[len];
193
194 char *d = &wb->buffer[wb->len];
195
196 while(t != e)
197 *d++ = *t++;
198
199 wb->len += len;
200 wb->buffer[wb->len] = '\0';
201
202 buffer_overflow_check(wb);
203 }
204
205 ALWAYS_INLINE
206 static void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) {
207 if(unlikely(!txt || !*txt || !len)) return;
208
209 buffer_need_bytes(wb, len + 1);
210
211 const char *t = txt;
212 const char *e = &txt[len];
213
214 char *d = &wb->buffer[wb->len];
215
216 while(t != e
217 #ifdef NETDATA_INTERNAL_CHECKS
218 && *t
219 #endif
220 )
221 *d++ = *t++;
222
223 #ifdef NETDATA_INTERNAL_CHECKS
224 assert(!(t != e && !*t) && "BUFFER: source string is shorter than the length given.");
225 #endif
226
227 wb->len += len;
228 wb->buffer[wb->len] = '\0';
229
230 buffer_overflow_check(wb);
231 }
232
233 ALWAYS_INLINE
234 static void buffer_strcat(BUFFER *wb, const char *txt) {
235 if(unlikely(!txt || !*txt)) return;
236
237 const char *t = txt;
238 while(*t) {
239 buffer_need_bytes(wb, 100);
240 char *s = &wb->buffer[wb->len];
241 char *d = s;
242 const char *e = &wb->buffer[wb->size];
243
244 while(*t && d < e)
245 *d++ = *t++;
246
247 wb->len += d - s;
248 }
249
250 buffer_need_bytes(wb, 1);
251 wb->buffer[wb->len] = '\0';
252
253 buffer_overflow_check(wb);
254 }
255
256 ALWAYS_INLINE
257 static void buffer_contents_replace(BUFFER *wb, const char *txt, size_t len) {
258 wb->len = 0;
259 buffer_need_bytes(wb, len + 1);
260
261 memcpy(wb->buffer, txt, len);
262 wb->len = len;
263 wb->buffer[wb->len] = '\0';
264
265 buffer_overflow_check(wb);
266 }
267
268 ALWAYS_INLINE
269 static void buffer_strncat(BUFFER *wb, const char *txt, size_t len) {
270 if(unlikely(!txt || !*txt)) return;
271
272 buffer_need_bytes(wb, len + 1);
273
274 memcpy(&wb->buffer[wb->len], txt, len);
275
276 wb->len += len;
277 wb->buffer[wb->len] = '\0';
278
279 buffer_overflow_check(wb);
280 }
281
282 ALWAYS_INLINE
283 static void buffer_memcat(BUFFER *wb, const void *mem, size_t bytes) {
284 if(unlikely(!mem)) return;
285
286 buffer_need_bytes(wb, bytes + 1);
287
288 memcpy(&wb->buffer[wb->len], mem, bytes);
289
290 wb->len += bytes;
291 wb->buffer[wb->len] = '\0';
292
293 buffer_overflow_check(wb);
294 }
295
296 ALWAYS_INLINE
297 static void buffer_json_strcat(BUFFER *wb, const char *txt)
298 {
299 if(unlikely(!txt || !*txt)) return;
300
301 const unsigned char *t = (const unsigned char *)txt;
302 while(*t) {
303 buffer_need_bytes(wb, 110);
304 unsigned char *s = (unsigned char *)&wb->buffer[wb->len];
305 unsigned char *d = s;
306 const unsigned char *e = (unsigned char *)&wb->buffer[wb->size - 10]; // make room for the max escape sequence
307
308 while(*t && d < e) {
309 #ifdef BUFFER_JSON_ESCAPE_UTF
310 if(unlikely(IS_UTF8_STARTBYTE(*t) && IS_UTF8_BYTE(t[1]))) {
311 // UTF-8 multi-byte encoded character
312
313 // find how big this character is (2-4 bytes)
314 size_t utf_character_size = 2;
315 while(utf_character_size < 4 && t[utf_character_size] && IS_UTF8_BYTE(t[utf_character_size]) && !IS_UTF8_STARTBYTE(t[utf_character_size]))
316 utf_character_size++;
317
318 uint32_t code_point = 0;
319 for (size_t i = 0; i < utf_character_size; i++) {
320 code_point <<= 6;
321 code_point |= (t[i] & 0x3F);
322 }
323
324 t += utf_character_size;
325
326 // encode as \u escape sequence
327 *d++ = '\\';
328 *d++ = 'u';
329 *d++ = hex_digits[(code_point >> 12) & 0xf];
330 *d++ = hex_digits[(code_point >> 8) & 0xf];
331 *d++ = hex_digits[(code_point >> 4) & 0xf];
332 *d++ = hex_digits[code_point & 0xf];
333 }
334 else
335 #endif
336 if(unlikely(*t < ' ')) {
337 uint32_t v = *t++;
338 *d++ = '\\';
339 switch (v) {
340 case '\n': *d++ = 'n'; break;
341 case '\r': *d++ = 'r'; break;
342 case '\t': *d++ = 't'; break;
343 case '\b': *d++ = 'b'; break;
344 case '\f': *d++ = 'f'; break;
345 default:
346 *d++ = 'u';
347 *d++ = hex_digits[(v >> 12) & 0xf];
348 *d++ = hex_digits[(v >> 8) & 0xf];
349 *d++ = hex_digits[(v >> 4) & 0xf];
350 *d++ = hex_digits[v & 0xf];
351 break;
352 }
353 }
354 else {
355 if (unlikely(*t == '\\' || *t == '\"'))
356 *d++ = '\\';
357
358 *d++ = *t++;
359 }
360 }
361
362 wb->len += d - s;
363 }
364
365 buffer_need_bytes(wb, 1);
366 wb->buffer[wb->len] = '\0';
367
368 buffer_overflow_check(wb);
369 }
370
371 ALWAYS_INLINE
372 static void buffer_json_quoted_strcat(BUFFER *wb, const char *txt) {
373 if(unlikely(!txt || !*txt)) return;
374
375 if(*txt == '"')
376 txt++;
377
378 const char *t = txt;
379 while(*t) {
380 buffer_need_bytes(wb, 100);
381 char *s = &wb->buffer[wb->len];
382 char *d = s;
383 const char *e = &wb->buffer[wb->size - 1]; // remove 1 to make room for the escape character
384
385 while(*t && d < e) {
386 if(unlikely(*t == '"' && !t[1])) {
387 t++;
388 continue;
389 }
390
391 if(unlikely(*t == '\\' || *t == '"'))
392 *d++ = '\\';
393
394 *d++ = *t++;
395 }
396
397 wb->len += d - s;
398 }
399
400 buffer_need_bytes(wb, 1);
401 wb->buffer[wb->len] = '\0';
402
403 buffer_overflow_check(wb);
404 }
405
406 // This trick seems to give an 80% speed increase in 32bit systems
407 // print_number_llu_r() will just print the digits up to the
408 // point the remaining value fits in 32 bits, and then calls
409 // print_number_lu_r() to print the rest with 32 bit arithmetic.
410
411 ALWAYS_INLINE
412 static char *print_uint32_reversed(char *dst, uint32_t value) {
413 char *d = dst;
414 do *d++ = (char)('0' + (value % 10)); while((value /= 10));
415 return d;
416 }
417
418 ALWAYS_INLINE
419 static char *print_uint64_reversed(char *dst, uint64_t value) {
420 #ifdef ENV32BIT
421 if(value <= (uint64_t)0xffffffff)
422 return print_uint32_reversed(dst, value);
423
424 char *d = dst;
425 do *d++ = (char)('0' + (value % 10)); while((value /= 10) && value > (uint64_t)0xffffffff);
426 if(value) return print_uint32_reversed(d, value);
427 return d;
428 #else
429 char *d = dst;
430 do *d++ = (char)('0' + (value % 10)); while((value /= 10));
431 return d;
432 #endif
433 }
434
435 ALWAYS_INLINE
436 static char *print_uint32_hex_reversed(char *dst, uint32_t value) {
437 static const char *digits = "0123456789ABCDEF";
438 char *d = dst;
439 do *d++ = digits[value & 0xf]; while((value >>= 4));
440 return d;
441 }
442
443 ALWAYS_INLINE
444 static char *print_uint64_hex_reversed(char *dst, uint64_t value) {
445 #ifdef ENV32BIT
446 if(value <= (uint64_t)0xffffffff)
447 return print_uint32_hex_reversed(dst, value);
448
449 char *d = dst;
450 do *d++ = hex_digits[value & 0xf]; while((value >>= 4) && value > (uint64_t)0xffffffff);
451 if(value) return print_uint32_hex_reversed(d, value);
452 return d;
453 #else
454 char *d = dst;
455 do *d++ = hex_digits[value & 0xf]; while((value >>= 4));
456 return d;
457 #endif
458 }
459
460 ALWAYS_INLINE
461 static char *print_uint64_hex_reversed_full(char *dst, uint64_t value) {
462 char *d = dst;
463 for(size_t c = 0; c < sizeof(uint64_t) * 2; c++) {
464 *d++ = hex_digits[value & 0xf];
465 value >>= 4;
466 }
467
468 return d;
469 }
470
471 ALWAYS_INLINE
472 static char *print_uint64_base64_reversed(char *dst, uint64_t value) {
473 char *d = dst;
474 do *d++ = base64_digits[value & 63]; while ((value >>= 6));
475 return d;
476 }
477
478 ALWAYS_INLINE
479 static void char_array_reverse(char *from, char *to) {
480 // from and to are inclusive
481 char *begin = from, *end = to, aux;
482 while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
483 }
484
485 ALWAYS_INLINE
486 static int print_netdata_double(char *dst, NETDATA_DOUBLE value) {
487 char *s = dst;
488
489 if(unlikely(value < 0)) {
490 *s++ = '-';
491 value = fabsndd(value);
492 }
493
494 uint64_t fractional_precision = 10000000ULL; // fractional part 7 digits
495 int fractional_wanted_digits = 7;
496 int exponent = 0;
497 if(unlikely(value >= (NETDATA_DOUBLE)(UINT64_MAX / 10))) {
498 // the number is too big to print using 64bit numbers
499 // so, let's convert it to exponential notation
500 exponent = (int)(floorndd(log10ndd(value)));
501 value /= powndd(10, exponent);
502
503 // the max precision we can support is 18 digits
504 // (UINT64_MAX is 20, but the first is 1)
505 fractional_precision = 1000000000000000000ULL; // fractional part 18 digits
506 fractional_wanted_digits = 18;
507 }
508
509 char *d = s;
510 NETDATA_DOUBLE integral_d, fractional_d;
511 fractional_d = modfndd(value, &integral_d);
512
513 // get the integral and the fractional parts as 64-bit integers
514 uint64_t integral = (uint64_t)integral_d;
515 uint64_t fractional = (uint64_t)llrintndd(fractional_d * (NETDATA_DOUBLE)fractional_precision);
516 if(unlikely(fractional >= fractional_precision)) {
517 integral++;
518 fractional -= fractional_precision;
519 }
520
521 // convert the integral part to string (reversed)
522 d = print_uint64_reversed(d, integral);
523 char_array_reverse(s, d - 1); // copy reversed the integral string
524
525 if(likely(fractional != 0)) {
526 *d++ = '.'; // add the dot
527
528 // convert the fractional part to string (reversed)
529 d = print_uint64_reversed(s = d, fractional);
530
531 while(d - s < fractional_wanted_digits) *d++ = '0'; // prepend zeros to reach precision
532 char_array_reverse(s, d - 1); // copy reversed the fractional string
533
534 // remove trailing zeros from the fractional part
535 while(*(d - 1) == '0') d--;
536 }
537
538 if(unlikely(exponent != 0)) {
539 *d++ = 'e';
540 *d++ = '+';
541 d = print_uint32_reversed(s = d, exponent);
542 char_array_reverse(s, d - 1);
543 }
544
545 *d = '\0';
546 return (int)(d - dst);
547 }
548
549 ALWAYS_INLINE
550 static size_t print_uint64(char *dst, uint64_t value) {
551 char *s = dst;
552 char *d = print_uint64_reversed(s, value);
553 char_array_reverse(s, d - 1);
554 *d = '\0';
555 return d - s;
556 }
557
558 ALWAYS_INLINE
559 static size_t print_int64(char *dst, int64_t value) {
560 size_t len = 0;
561
562 if(value < 0) {
563 *dst++ = '-';
564 value = -value;
565 len++;
566 }
567
568 return print_uint64(dst, value) + len;
569 }
570
571 #define UINT64_MAX_LENGTH (24) // 21 should be enough
572 ALWAYS_INLINE
573 static void buffer_print_uint64(BUFFER *wb, uint64_t value) {
574 buffer_need_bytes(wb, UINT64_MAX_LENGTH);
575 wb->len += print_uint64(&wb->buffer[wb->len], value);
576 buffer_overflow_check(wb);
577 }
578
579 ALWAYS_INLINE
580 static void buffer_print_int64(BUFFER *wb, int64_t value) {
581 buffer_need_bytes(wb, UINT64_MAX_LENGTH);
582 wb->len += print_int64(&wb->buffer[wb->len], value);
583 buffer_overflow_check(wb);
584 }
585
586 #define UINT64_HEX_MAX_LENGTH ((sizeof(HEX_PREFIX) - 1) + (sizeof(uint64_t) * 2) + 1)
587 ALWAYS_INLINE
588 static size_t print_uint64_hex(char *dst, uint64_t value) {
589 char *d = dst;
590
591 const char *s = HEX_PREFIX;
592 while(*s) *d++ = *s++;
593
594 char *e = print_uint64_hex_reversed(d, value);
595 char_array_reverse(d, e - 1);
596 *e = '\0';
597 return e - dst;
598 }
599
600 ALWAYS_INLINE
601 static size_t print_uint64_hex_full(char *dst, uint64_t value) {
602 char *d = dst;
603
604 const char *s = HEX_PREFIX;
605 while(*s) *d++ = *s++;
606
607 char *e = print_uint64_hex_reversed_full(d, value);
608 char_array_reverse(d, e - 1);
609 *e = '\0';
610 return e - dst;
611 }
612
613 ALWAYS_INLINE
614 static void buffer_print_uint64_hex(BUFFER *wb, uint64_t value) {
615 buffer_need_bytes(wb, UINT64_HEX_MAX_LENGTH);
616 wb->len += print_uint64_hex(&wb->buffer[wb->len], value);
617 buffer_overflow_check(wb);
618 }
619
620 ALWAYS_INLINE
621 static void buffer_print_uint64_hex_full(BUFFER *wb, uint64_t value) {
622 buffer_need_bytes(wb, UINT64_HEX_MAX_LENGTH);
623 wb->len += print_uint64_hex_full(&wb->buffer[wb->len], value);
624 buffer_overflow_check(wb);
625 }
626
627 #define UINT64_B64_MAX_LENGTH ((sizeof(IEEE754_UINT64_B64_PREFIX) - 1) + (sizeof(uint64_t) * 2) + 1)
628 ALWAYS_INLINE
629 static void buffer_print_uint64_base64(BUFFER *wb, uint64_t value) {
630 buffer_need_bytes(wb, UINT64_B64_MAX_LENGTH);
631
632 buffer_fast_strcat(wb, IEEE754_UINT64_B64_PREFIX, sizeof(IEEE754_UINT64_B64_PREFIX) - 1);
633
634 char *s = &wb->buffer[wb->len];
635 char *d = print_uint64_base64_reversed(s, value);
636 char_array_reverse(s, d - 1);
637 *d = '\0';
638 wb->len += d - s;
639
640 buffer_overflow_check(wb);
641 }
642
643 ALWAYS_INLINE
644 static void buffer_print_int64_hex(BUFFER *wb, int64_t value) {
645 buffer_need_bytes(wb, 2);
646
647 if(value < 0) {
648 buffer_putc(wb, '-');
649 value = -value;
650 }
651
652 buffer_print_uint64_hex(wb, (uint64_t)value);
653
654 buffer_overflow_check(wb);
655 }
656
657 ALWAYS_INLINE
658 static void buffer_print_int64_base64(BUFFER *wb, int64_t value) {
659 buffer_need_bytes(wb, 2);
660
661 if(value < 0) {
662 buffer_putc(wb, '-');
663 value = -value;
664 }
665
666 buffer_print_uint64_base64(wb, (uint64_t)value);
667
668 buffer_overflow_check(wb);
669 }
670
671 #define DOUBLE_MAX_LENGTH (512) // 318 should be enough, including null
672
673 ALWAYS_INLINE
674 static void buffer_print_netdata_double(BUFFER *wb, NETDATA_DOUBLE value) {
675 buffer_need_bytes(wb, DOUBLE_MAX_LENGTH);
676
677 if(isnan(value) || isinf(value)) {
678 buffer_fast_strcat(wb, "null", 4);
679 return;
680 }
681 else
682 wb->len += print_netdata_double(&wb->buffer[wb->len], value);
683
684 // terminate it
685 buffer_need_bytes(wb, 1);
686 wb->buffer[wb->len] = '\0';
687
688 buffer_overflow_check(wb);
689 }
690
691 #define DOUBLE_HEX_MAX_LENGTH ((sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1) + (sizeof(uint64_t) * 2) + 1)
692 ALWAYS_INLINE
693 static void buffer_print_netdata_double_hex(BUFFER *wb, NETDATA_DOUBLE value) {
694 buffer_need_bytes(wb, DOUBLE_HEX_MAX_LENGTH);
695
696 uint64_t *ptr = (uint64_t *) (&value);
697 buffer_fast_strcat(wb, IEEE754_DOUBLE_HEX_PREFIX, sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1);
698
699 char *s = &wb->buffer[wb->len];
700 char *d = print_uint64_hex_reversed(s, *ptr);
701 char_array_reverse(s, d - 1);
702 *d = '\0';
703 wb->len += d - s;
704
705 buffer_overflow_check(wb);
706 }
707
708 #define DOUBLE_B64_MAX_LENGTH ((sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1) + (sizeof(uint64_t) * 2) + 1)
709 ALWAYS_INLINE
710 static void buffer_print_netdata_double_base64(BUFFER *wb, NETDATA_DOUBLE value) {
711 buffer_need_bytes(wb, DOUBLE_B64_MAX_LENGTH);
712
713 uint64_t *ptr = (uint64_t *) (&value);
714 buffer_fast_strcat(wb, IEEE754_DOUBLE_B64_PREFIX, sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1);
715
716 char *s = &wb->buffer[wb->len];
717 char *d = print_uint64_base64_reversed(s, *ptr);
718 char_array_reverse(s, d - 1);
719 *d = '\0';
720 wb->len += d - s;
721
722 buffer_overflow_check(wb);
723 }
724
725 typedef enum {
726 NUMBER_ENCODING_DECIMAL,
727 NUMBER_ENCODING_HEX,
728 NUMBER_ENCODING_BASE64,
729 } NUMBER_ENCODING;
730
731 ALWAYS_INLINE
732 static void buffer_print_int64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, int64_t value) {
733 if(encoding == NUMBER_ENCODING_BASE64)
734 return buffer_print_int64_base64(wb, value);
735
736 if(encoding == NUMBER_ENCODING_HEX)
737 return buffer_print_int64_hex(wb, value);
738
739 return buffer_print_int64(wb, value);
740 }
741
742 ALWAYS_INLINE
743 static void buffer_print_uint64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, uint64_t value) {
744 if(encoding == NUMBER_ENCODING_BASE64)
745 return buffer_print_uint64_base64(wb, value);
746
747 if(encoding == NUMBER_ENCODING_HEX)
748 return buffer_print_uint64_hex(wb, value);
749
750 return buffer_print_uint64(wb, value);
751 }
752
753 ALWAYS_INLINE
754 static void buffer_print_netdata_double_encoded(BUFFER *wb, NUMBER_ENCODING encoding, NETDATA_DOUBLE value) {
755 if(encoding == NUMBER_ENCODING_BASE64)
756 return buffer_print_netdata_double_base64(wb, value);
757
758 if(encoding == NUMBER_ENCODING_HEX)
759 return buffer_print_netdata_double_hex(wb, value);
760
761 return buffer_print_netdata_double(wb, value);
762 }
763
764 ALWAYS_INLINE
765 static void buffer_print_spaces(BUFFER *wb, size_t spaces) {
766 buffer_need_bytes(wb, spaces * 4 + 1);
767
768 char *d = &wb->buffer[wb->len];
769 for(size_t i = 0; i < spaces; i++) {
770 *d++ = ' ';
771 *d++ = ' ';
772 *d++ = ' ';
773 *d++ = ' ';
774 }
775
776 *d = '\0';
777 wb->len += spaces * 4;
778
779 buffer_overflow_check(wb);
780 }
781
782 ALWAYS_INLINE
783 static void buffer_print_json_comma(BUFFER *wb) {
784 if(wb->json.stack[wb->json.depth].count)
785 buffer_putc(wb, ',');
786 }
787
788 ALWAYS_INLINE
789 static void buffer_print_json_comma_newline_spacing(BUFFER *wb) {
790 buffer_print_json_comma(wb);
791
792 if((wb->json.options & BUFFER_JSON_OPTIONS_MINIFY) ||
793 (wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && !(wb->json.options & BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS)))
794 return;
795
796 buffer_putc(wb, '\n');
797 buffer_print_spaces(wb, wb->json.depth + 1);
798 }
799
800 ALWAYS_INLINE
801 static void buffer_print_json_key(BUFFER *wb, const char *key) {
802 buffer_strcat(wb, wb->json.key_quote);
803 buffer_json_strcat(wb, key);
804 buffer_strcat(wb, wb->json.key_quote);
805 }
806
807 ALWAYS_INLINE
808 static void buffer_json_add_string_value(BUFFER *wb, const char *value) {
809 if(value) {
810 buffer_strcat(wb, wb->json.value_quote);
811 buffer_json_strcat(wb, value);
812 buffer_strcat(wb, wb->json.value_quote);
813 }
814 else
815 buffer_fast_strcat(wb, "null", 4);
816 }
817
818 ALWAYS_INLINE
819 static void buffer_json_add_quoted_string_value(BUFFER *wb, const char *value) {
820 if(value) {
821 buffer_strcat(wb, wb->json.value_quote);
822 buffer_json_quoted_strcat(wb, value);
823 buffer_strcat(wb, wb->json.value_quote);
824 }
825 else
826 buffer_fast_strcat(wb, "null", 4);
827 }
828
829 ALWAYS_INLINE
830 static void buffer_json_member_add_object(BUFFER *wb, const char *key) {
831 buffer_print_json_comma_newline_spacing(wb);
832 buffer_print_json_key(wb, key);
833 buffer_fast_strcat(wb, ":{", 2);
834 wb->json.stack[wb->json.depth].count++;
835
836 _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
837 }
838
839 ALWAYS_INLINE
840 static void buffer_json_object_close(BUFFER *wb) {
841 #ifdef NETDATA_INTERNAL_CHECKS
842 assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
843 assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_OBJECT && "BUFFER JSON: an object is not open to close it");
844 #endif
845 if(!(wb->json.options & BUFFER_JSON_OPTIONS_MINIFY)) {
846 buffer_putc(wb, '\n');
847 buffer_print_spaces(wb, wb->json.depth);
848 }
849 buffer_putc(wb, '}');
850 _buffer_json_depth_pop(wb);
851 }
852
853 ALWAYS_INLINE
854 static void buffer_json_member_add_string(BUFFER *wb, const char *key, const char *value) {
855 buffer_print_json_comma_newline_spacing(wb);
856 buffer_print_json_key(wb, key);
857 buffer_putc(wb, ':');
858 buffer_json_add_string_value(wb, value);
859
860 wb->json.stack[wb->json.depth].count++;
861 }
862
863 ALWAYS_INLINE
864 static void buffer_json_member_add_string_or_omit(BUFFER *wb, const char *key, const char *value) {
865 if(value && *value)
866 buffer_json_member_add_string(wb, key, value);
867 }
868
869 ALWAYS_INLINE
870 static void buffer_json_member_add_string_or_empty(BUFFER *wb, const char *key, const char *value) {
871 if(!value)
872 value = "";
873
874 buffer_json_member_add_string(wb, key, value);
875 }
876
877 void buffer_json_member_add_datetime_rfc3339(BUFFER *wb, const char *key, uint64_t datetime_ut, bool utc);
878 void buffer_json_member_add_duration_ut(BUFFER *wb, const char *key, int64_t duration_ut);
879
880 ALWAYS_INLINE
881 static void buffer_json_member_add_quoted_string(BUFFER *wb, const char *key, const char *value) {
882 buffer_print_json_comma_newline_spacing(wb);
883 buffer_print_json_key(wb, key);
884 buffer_putc(wb, ':');
885
886 if(!value || strcmp(value, "null") == 0)
887 buffer_fast_strcat(wb, "null", 4);
888 else
889 buffer_json_add_quoted_string_value(wb, value);
890
891 wb->json.stack[wb->json.depth].count++;
892 }
893
894 ALWAYS_INLINE
895 static void buffer_json_member_add_uuid_ptr(BUFFER *wb, const char *key, nd_uuid_t *value) {
896 buffer_print_json_comma_newline_spacing(wb);
897 buffer_print_json_key(wb, key);
898 buffer_putc(wb, ':');
899
900 if(value && !uuid_is_null(*value)) {
901 char uuid[GUID_LEN + 1];
902 uuid_unparse_lower(*value, uuid);
903 buffer_json_add_string_value(wb, uuid);
904 }
905 else
906 buffer_json_add_string_value(wb, NULL);
907
908 wb->json.stack[wb->json.depth].count++;
909 }
910
911 ALWAYS_INLINE
912 static void buffer_json_member_add_uuid(BUFFER *wb, const char *key, nd_uuid_t value) {
913 buffer_print_json_comma_newline_spacing(wb);
914 buffer_print_json_key(wb, key);
915 buffer_putc(wb, ':');
916
917 if(!uuid_is_null(value)) {
918 char uuid[UUID_STR_LEN];
919 uuid_unparse_lower(value, uuid);
920 buffer_json_add_string_value(wb, uuid);
921 }
922 else
923 buffer_json_add_string_value(wb, NULL);
924
925 wb->json.stack[wb->json.depth].count++;
926 }
927
928 ALWAYS_INLINE
929 static void buffer_json_member_add_uuid_compact(BUFFER *wb, const char *key, nd_uuid_t value) {
930 buffer_print_json_comma_newline_spacing(wb);
931 buffer_print_json_key(wb, key);
932 buffer_putc(wb, ':');
933
934 if(!uuid_is_null(value)) {
935 char uuid[UUID_COMPACT_STR_LEN];
936 uuid_unparse_lower_compact(value, uuid);
937 buffer_json_add_string_value(wb, uuid);
938 }
939 else
940 buffer_json_add_string_value(wb, NULL);
941
942 wb->json.stack[wb->json.depth].count++;
943 }
944
945 ALWAYS_INLINE
946 static void buffer_json_member_add_boolean(BUFFER *wb, const char *key, bool value) {
947 buffer_print_json_comma_newline_spacing(wb);
948 buffer_print_json_key(wb, key);
949 buffer_putc(wb, ':');
950 buffer_strcat(wb, value?"true":"false");
951
952 wb->json.stack[wb->json.depth].count++;
953 }
954
955 ALWAYS_INLINE
956 static void buffer_json_member_add_array(BUFFER *wb, const char *key) {
957 buffer_print_json_comma_newline_spacing(wb);
958 if (key) {
959 buffer_print_json_key(wb, key);
960 buffer_fast_strcat(wb, ":[", 2);
961 }
962 else
963 buffer_putc(wb, '[');
964
965 wb->json.stack[wb->json.depth].count++;
966
967 _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
968 }
969
970 ALWAYS_INLINE
971 static void buffer_json_add_array_item_array(BUFFER *wb) {
972 if(!(wb->json.options & BUFFER_JSON_OPTIONS_MINIFY) && wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY) {
973 // an array inside another array
974 buffer_print_json_comma(wb);
975 buffer_putc(wb, '\n');
976 buffer_print_spaces(wb, wb->json.depth + 1);
977 }
978 else
979 buffer_print_json_comma_newline_spacing(wb);
980
981 buffer_putc(wb, '[');
982 wb->json.stack[wb->json.depth].count++;
983
984 _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
985 }
986
987 ALWAYS_INLINE
988 static void buffer_json_add_array_item_string(BUFFER *wb, const char *value) {
989 buffer_print_json_comma_newline_spacing(wb);
990
991 buffer_json_add_string_value(wb, value);
992 wb->json.stack[wb->json.depth].count++;
993 }
994
995 ALWAYS_INLINE
996 static void buffer_json_add_array_item_uuid(BUFFER *wb, nd_uuid_t *value) {
997 if(value && !uuid_is_null(*value)) {
998 char uuid[GUID_LEN + 1];
999 uuid_unparse_lower(*value, uuid);
1000 buffer_json_add_array_item_string(wb, uuid);
1001 }
1002 else
1003 buffer_json_add_array_item_string(wb, NULL);
1004 }
1005
1006 ALWAYS_INLINE
1007 static void buffer_json_add_array_item_uuid_compact(BUFFER *wb, nd_uuid_t *value) {
1008 if(value && !uuid_is_null(*value)) {
1009 char uuid[GUID_LEN + 1];
1010 uuid_unparse_lower_compact(*value, uuid);
1011 buffer_json_add_array_item_string(wb, uuid);
1012 }
1013 else
1014 buffer_json_add_array_item_string(wb, NULL);
1015 }
1016
1017 ALWAYS_INLINE
1018 static void buffer_json_add_array_item_double(BUFFER *wb, NETDATA_DOUBLE value) {
1019 buffer_print_json_comma_newline_spacing(wb);
1020
1021 buffer_print_netdata_double(wb, value);
1022 wb->json.stack[wb->json.depth].count++;
1023 }
1024
1025 ALWAYS_INLINE
1026 static void buffer_json_add_array_item_int64(BUFFER *wb, int64_t value) {
1027 buffer_print_json_comma_newline_spacing(wb);
1028
1029 buffer_print_int64(wb, value);
1030 wb->json.stack[wb->json.depth].count++;
1031 }
1032
1033 ALWAYS_INLINE
1034 static void buffer_json_add_array_item_uint64(BUFFER *wb, uint64_t value) {
1035 buffer_print_json_comma_newline_spacing(wb);
1036
1037 buffer_print_uint64(wb, value);
1038 wb->json.stack[wb->json.depth].count++;
1039 }
1040
1041 ALWAYS_INLINE
1042 static void buffer_json_add_array_item_boolean(BUFFER *wb, bool value) {
1043 buffer_print_json_comma_newline_spacing(wb);
1044
1045 buffer_strcat(wb, value ? "true" : "false");
1046 wb->json.stack[wb->json.depth].count++;
1047 }
1048
1049 ALWAYS_INLINE
1050 static void buffer_json_add_array_item_time_t(BUFFER *wb, time_t value) {
1051 buffer_print_json_comma_newline_spacing(wb);
1052
1053 buffer_print_int64(wb, value);
1054 wb->json.stack[wb->json.depth].count++;
1055 }
1056
1057 ALWAYS_INLINE
1058 static void buffer_json_add_array_item_time_ms(BUFFER *wb, time_t value) {
1059 buffer_print_json_comma_newline_spacing(wb);
1060
1061 buffer_print_int64(wb, value);
1062 buffer_fast_strcat(wb, "000", 3);
1063 wb->json.stack[wb->json.depth].count++;
1064 }
1065
1066 void buffer_json_add_array_item_datetime_rfc3339(BUFFER *wb, uint64_t datetime_ut, bool utc);
1067
1068 ALWAYS_INLINE
1069 static void buffer_json_add_array_item_time_t_formatted(BUFFER *wb, time_t value, bool rfc3339) {
1070 if(unlikely(rfc3339 && (!value || value > API_RELATIVE_TIME_MAX))) {
1071 if (!value)
1072 buffer_json_add_array_item_string(wb, NULL);
1073 else
1074 buffer_json_add_array_item_datetime_rfc3339(wb, (uint64_t)value * USEC_PER_SEC, true);
1075 }
1076 else
1077 buffer_json_add_array_item_time_t(wb, value);
1078 }
1079
1080 ALWAYS_INLINE
1081 static void buffer_json_add_array_item_object(BUFFER *wb) {
1082 buffer_print_json_comma_newline_spacing(wb);
1083
1084 buffer_putc(wb, '{');
1085 wb->json.stack[wb->json.depth].count++;
1086
1087 _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
1088 }
1089
1090 ALWAYS_INLINE
1091 static void buffer_json_member_add_time_t(BUFFER *wb, const char *key, time_t value) {
1092 buffer_print_json_comma_newline_spacing(wb);
1093 buffer_print_json_key(wb, key);
1094 buffer_putc(wb, ':');
1095 buffer_print_int64(wb, value);
1096
1097 wb->json.stack[wb->json.depth].count++;
1098 }
1099
1100 ALWAYS_INLINE
1101 static void buffer_json_member_add_time_t_formatted(BUFFER *wb, const char *key, time_t value, bool rfc3339) {
1102 if(unlikely(rfc3339 && (!value || value > API_RELATIVE_TIME_MAX))) {
1103 if(!value)
1104 buffer_json_member_add_string(wb, key, NULL);
1105 else
1106 buffer_json_member_add_datetime_rfc3339(wb, key, (uint64_t)value * USEC_PER_SEC, true);
1107 }
1108 else
1109 buffer_json_member_add_time_t(wb, key, value);
1110 }
1111
1112 ALWAYS_INLINE
1113 static void buffer_json_member_add_uint64(BUFFER *wb, const char *key, uint64_t value) {
1114 buffer_print_json_comma_newline_spacing(wb);
1115 buffer_print_json_key(wb, key);
1116 buffer_putc(wb, ':');
1117 buffer_print_uint64(wb, value);
1118
1119 wb->json.stack[wb->json.depth].count++;
1120 }
1121
1122 ALWAYS_INLINE
1123 static void buffer_json_member_add_int64(BUFFER *wb, const char *key, int64_t value) {
1124 buffer_print_json_comma_newline_spacing(wb);
1125 buffer_print_json_key(wb, key);
1126 buffer_putc(wb, ':');
1127 buffer_print_int64(wb, value);
1128
1129 wb->json.stack[wb->json.depth].count++;
1130 }
1131
1132 ALWAYS_INLINE
1133 static void buffer_json_member_add_double(BUFFER *wb, const char *key, NETDATA_DOUBLE value) {
1134 buffer_print_json_comma_newline_spacing(wb);
1135 buffer_print_json_key(wb, key);
1136 buffer_putc(wb, ':');
1137 buffer_print_netdata_double(wb, value);
1138
1139 wb->json.stack[wb->json.depth].count++;
1140 }
1141
1142 ALWAYS_INLINE
1143 static void buffer_json_array_close(BUFFER *wb) {
1144 #ifdef NETDATA_INTERNAL_CHECKS
1145 assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
1146 assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && "BUFFER JSON: an array is not open to close it");
1147 #endif
1148 if(wb->json.options & BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS) {
1149 buffer_putc(wb, '\n');
1150 buffer_print_spaces(wb, wb->json.depth);
1151 }
1152
1153 buffer_putc(wb, ']');
1154 _buffer_json_depth_pop(wb);
1155 }
1156
1157 ALWAYS_INLINE
1158 static void buffer_copy(BUFFER *dst, BUFFER *src) {
1159 if(!src || !dst)
1160 return;
1161
1162 buffer_contents_replace(dst, buffer_tostring(src), buffer_strlen(src));
1163
1164 dst->content_type = src->content_type;
1165 dst->options = src->options;
1166 dst->date = src->date;
1167 dst->expires = src->expires;
1168 dst->json = src->json;
1169 }
1170
1171 ALWAYS_INLINE
1172 static BUFFER *buffer_dup(BUFFER *src) {
1173 if(!src)
1174 return NULL;
1175
1176 BUFFER *dst = buffer_create(buffer_strlen(src) + 1, src->statistics);
1177 buffer_copy(dst, src);
1178 return dst;
1179 }
1180
1181 char *url_encode(const char *str);
1182 ALWAYS_INLINE
1183 static void buffer_key_value_urlencode(BUFFER *wb, const char *key, const char *value) {
1184 char *encoded = NULL;
1185
1186 if(value && *value)
1187 encoded = url_encode(value);
1188
1189 buffer_sprintf(wb, "%s=%s", key, encoded ? encoded : "");
1190
1191 freez(encoded);
1192 }
1193
1194 // Include functions_fields.h for field-related functionalities
1195 #include "functions_fields.h"
1196
1197 #endif /* NETDATA_WEB_BUFFER_H */