buffer.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #ifndef NETDATA_WEB_BUFFER_H
  3. #define NETDATA_WEB_BUFFER_H 1
  4. #include "../string/utf8.h"
  5. #include "../libnetdata.h"
  6. #ifdef ENABLE_HTTPD
  7. #include "h2o/memory.h"
  8. #endif
  9. #define WEB_DATA_LENGTH_INCREASE_STEP 1024
  10. #define BUFFER_JSON_MAX_DEPTH 32 // max is 255
  11. extern const char hex_digits[16];
  12. extern const char base64_digits[64];
  13. extern unsigned char hex_value_from_ascii[256];
  14. extern unsigned char base64_value_from_ascii[256];
  15. typedef enum __attribute__ ((__packed__)) {
  16. BUFFER_JSON_EMPTY = 0,
  17. BUFFER_JSON_OBJECT,
  18. BUFFER_JSON_ARRAY,
  19. } BUFFER_JSON_NODE_TYPE;
  20. typedef struct web_buffer_json_node {
  21. BUFFER_JSON_NODE_TYPE type;
  22. uint32_t count:24;
  23. } BUFFER_JSON_NODE;
  24. #define BUFFER_QUOTE_MAX_SIZE 7
  25. typedef enum __attribute__ ((__packed__)) {
  26. WB_CONTENT_CACHEABLE = (1 << 0),
  27. WB_CONTENT_NO_CACHEABLE = (1 << 1),
  28. } BUFFER_OPTIONS;
  29. typedef enum __attribute__ ((__packed__)) {
  30. CT_NONE = 0,
  31. CT_APPLICATION_JSON,
  32. CT_TEXT_PLAIN,
  33. CT_TEXT_HTML,
  34. CT_APPLICATION_X_JAVASCRIPT,
  35. CT_TEXT_CSS,
  36. CT_TEXT_XML,
  37. CT_APPLICATION_XML,
  38. CT_TEXT_XSL,
  39. CT_APPLICATION_OCTET_STREAM,
  40. CT_APPLICATION_X_FONT_TRUETYPE,
  41. CT_APPLICATION_X_FONT_OPENTYPE,
  42. CT_APPLICATION_FONT_WOFF,
  43. CT_APPLICATION_FONT_WOFF2,
  44. CT_APPLICATION_VND_MS_FONTOBJ,
  45. CT_IMAGE_SVG_XML,
  46. CT_IMAGE_PNG,
  47. CT_IMAGE_JPG,
  48. CT_IMAGE_GIF,
  49. CT_IMAGE_XICON,
  50. CT_IMAGE_ICNS,
  51. CT_IMAGE_BMP,
  52. CT_PROMETHEUS,
  53. } HTTP_CONTENT_TYPE;
  54. typedef struct web_buffer {
  55. size_t size; // allocation size of buffer, in bytes
  56. size_t len; // current data length in buffer, in bytes
  57. char *buffer; // the buffer itself
  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. time_t date; // the timestamp this content has been generated
  61. time_t expires; // the timestamp this content expires
  62. size_t *statistics;
  63. struct {
  64. char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
  65. char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
  66. int8_t depth;
  67. bool minify;
  68. BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
  69. } json;
  70. } BUFFER;
  71. #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)
  72. #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)
  73. #define buffer_strlen(wb) ((wb)->len)
  74. const char *buffer_tostring(BUFFER *wb);
  75. #define BUFFER_OVERFLOW_EOF "EOF"
  76. #ifdef NETDATA_INTERNAL_CHECKS
  77. #define buffer_overflow_check(b) _buffer_overflow_check(b)
  78. #else
  79. #define buffer_overflow_check(b)
  80. #endif
  81. static inline void _buffer_overflow_check(BUFFER *b) {
  82. assert(b->len <= b->size &&
  83. "BUFFER: length is above buffer size.");
  84. assert(!(b->buffer && (b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0)) &&
  85. "BUFFER: detected overflow.");
  86. }
  87. static inline void buffer_flush(BUFFER *wb) {
  88. wb->len = 0;
  89. wb->json.depth = 0;
  90. wb->json.stack[0].type = BUFFER_JSON_EMPTY;
  91. wb->json.stack[0].count = 0;
  92. if(wb->buffer)
  93. wb->buffer[0] = '\0';
  94. }
  95. void buffer_reset(BUFFER *wb);
  96. void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
  97. void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
  98. BUFFER *buffer_create(size_t size, size_t *statistics);
  99. void buffer_free(BUFFER *b);
  100. void buffer_increase(BUFFER *b, size_t free_size_required);
  101. void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4);
  102. void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
  103. void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
  104. void buffer_strcat_htmlescape(BUFFER *wb, const char *txt);
  105. void buffer_char_replace(BUFFER *wb, char from, char to);
  106. void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit);
  107. #ifdef ENABLE_HTTPD
  108. h2o_iovec_t buffer_to_h2o_iovec(BUFFER *wb);
  109. #endif
  110. static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
  111. if(unlikely(buffer->len + needed_free_size >= buffer->size))
  112. buffer_increase(buffer, needed_free_size + 1);
  113. }
  114. void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth,
  115. bool add_anonymous_object, bool minify);
  116. void buffer_json_finalize(BUFFER *wb);
  117. static inline void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE type) {
  118. #ifdef NETDATA_INTERNAL_CHECKS
  119. assert(wb->json.depth <= BUFFER_JSON_MAX_DEPTH && "BUFFER JSON: max nesting reached");
  120. #endif
  121. wb->json.depth++;
  122. wb->json.stack[wb->json.depth].count = 0;
  123. wb->json.stack[wb->json.depth].type = type;
  124. }
  125. static inline void _buffer_json_depth_pop(BUFFER *wb) {
  126. wb->json.depth--;
  127. }
  128. static inline void buffer_fast_charcat(BUFFER *wb, const char c) {
  129. buffer_need_bytes(wb, 2);
  130. *(&wb->buffer[wb->len]) = c;
  131. wb->len += 1;
  132. wb->buffer[wb->len] = '\0';
  133. buffer_overflow_check(wb);
  134. }
  135. static inline void buffer_fast_rawcat(BUFFER *wb, const char *txt, size_t len) {
  136. if(unlikely(!txt || !*txt || !len)) return;
  137. buffer_need_bytes(wb, len + 1);
  138. const char *t = txt;
  139. const char *e = &txt[len];
  140. char *d = &wb->buffer[wb->len];
  141. while(t != e)
  142. *d++ = *t++;
  143. wb->len += len;
  144. wb->buffer[wb->len] = '\0';
  145. buffer_overflow_check(wb);
  146. }
  147. static inline void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) {
  148. if(unlikely(!txt || !*txt || !len)) return;
  149. buffer_need_bytes(wb, len + 1);
  150. const char *t = txt;
  151. const char *e = &txt[len];
  152. char *d = &wb->buffer[wb->len];
  153. while(t != e
  154. #ifdef NETDATA_INTERNAL_CHECKS
  155. && *t
  156. #endif
  157. )
  158. *d++ = *t++;
  159. #ifdef NETDATA_INTERNAL_CHECKS
  160. assert(!(t != e && !*t) && "BUFFER: source string is shorter than the length given.");
  161. #endif
  162. wb->len += len;
  163. wb->buffer[wb->len] = '\0';
  164. buffer_overflow_check(wb);
  165. }
  166. static inline void buffer_strcat(BUFFER *wb, const char *txt) {
  167. if(unlikely(!txt || !*txt)) return;
  168. const char *t = txt;
  169. while(*t) {
  170. buffer_need_bytes(wb, 100);
  171. char *s = &wb->buffer[wb->len];
  172. char *d = s;
  173. const char *e = &wb->buffer[wb->size];
  174. while(*t && d < e)
  175. *d++ = *t++;
  176. wb->len += d - s;
  177. }
  178. buffer_need_bytes(wb, 1);
  179. wb->buffer[wb->len] = '\0';
  180. buffer_overflow_check(wb);
  181. }
  182. static inline void buffer_strncat(BUFFER *wb, const char *txt, size_t len) {
  183. if(unlikely(!txt || !*txt)) return;
  184. const char *t = txt;
  185. while(*t) {
  186. buffer_need_bytes(wb, len);
  187. char *s = &wb->buffer[wb->len];
  188. char *d = s;
  189. const char *e = &wb->buffer[wb->len + len];
  190. while(*t && d < e)
  191. *d++ = *t++;
  192. wb->len += d - s;
  193. }
  194. buffer_need_bytes(wb, 1);
  195. wb->buffer[wb->len] = '\0';
  196. buffer_overflow_check(wb);
  197. }
  198. static inline void buffer_json_strcat(BUFFER *wb, const char *txt) {
  199. if(unlikely(!txt || !*txt)) return;
  200. const unsigned char *t = (const unsigned char *)txt;
  201. while(*t) {
  202. buffer_need_bytes(wb, 110);
  203. unsigned char *s = (unsigned char *)&wb->buffer[wb->len];
  204. unsigned char *d = s;
  205. const unsigned char *e = (unsigned char *)&wb->buffer[wb->size - 10]; // make room for the max escape sequence
  206. while(*t && d < e) {
  207. #ifdef BUFFER_JSON_ESCAPE_UTF
  208. if(unlikely(IS_UTF8_STARTBYTE(*t) && IS_UTF8_BYTE(t[1]))) {
  209. // UTF-8 multi-byte encoded character
  210. // find how big this character is (2-4 bytes)
  211. size_t utf_character_size = 2;
  212. while(utf_character_size < 4 && t[utf_character_size] && IS_UTF8_BYTE(t[utf_character_size]) && !IS_UTF8_STARTBYTE(t[utf_character_size]))
  213. utf_character_size++;
  214. uint32_t code_point = 0;
  215. for (size_t i = 0; i < utf_character_size; i++) {
  216. code_point <<= 6;
  217. code_point |= (t[i] & 0x3F);
  218. }
  219. t += utf_character_size;
  220. // encode as \u escape sequence
  221. *d++ = '\\';
  222. *d++ = 'u';
  223. *d++ = hex_digits[(code_point >> 12) & 0xf];
  224. *d++ = hex_digits[(code_point >> 8) & 0xf];
  225. *d++ = hex_digits[(code_point >> 4) & 0xf];
  226. *d++ = hex_digits[code_point & 0xf];
  227. }
  228. else
  229. #endif
  230. if(unlikely(*t < ' ')) {
  231. uint32_t v = *t++;
  232. *d++ = '\\';
  233. *d++ = 'u';
  234. *d++ = hex_digits[(v >> 12) & 0xf];
  235. *d++ = hex_digits[(v >> 8) & 0xf];
  236. *d++ = hex_digits[(v >> 4) & 0xf];
  237. *d++ = hex_digits[v & 0xf];
  238. }
  239. else {
  240. if (unlikely(*t == '\\' || *t == '\"'))
  241. *d++ = '\\';
  242. *d++ = *t++;
  243. }
  244. }
  245. wb->len += d - s;
  246. }
  247. buffer_need_bytes(wb, 1);
  248. wb->buffer[wb->len] = '\0';
  249. buffer_overflow_check(wb);
  250. }
  251. static inline void buffer_json_quoted_strcat(BUFFER *wb, const char *txt) {
  252. if(unlikely(!txt || !*txt)) return;
  253. if(*txt == '"')
  254. txt++;
  255. const char *t = txt;
  256. while(*t) {
  257. buffer_need_bytes(wb, 100);
  258. char *s = &wb->buffer[wb->len];
  259. char *d = s;
  260. const char *e = &wb->buffer[wb->size - 1]; // remove 1 to make room for the escape character
  261. while(*t && d < e) {
  262. if(unlikely(*t == '"' && !t[1])) {
  263. t++;
  264. continue;
  265. }
  266. if(unlikely(*t == '\\' || *t == '"'))
  267. *d++ = '\\';
  268. *d++ = *t++;
  269. }
  270. wb->len += d - s;
  271. }
  272. buffer_need_bytes(wb, 1);
  273. wb->buffer[wb->len] = '\0';
  274. buffer_overflow_check(wb);
  275. }
  276. // This trick seems to give an 80% speed increase in 32bit systems
  277. // print_number_llu_r() will just print the digits up to the
  278. // point the remaining value fits in 32 bits, and then calls
  279. // print_number_lu_r() to print the rest with 32 bit arithmetic.
  280. static inline char *print_uint32_reversed(char *dst, uint32_t value) {
  281. char *d = dst;
  282. do *d++ = (char)('0' + (value % 10)); while((value /= 10));
  283. return d;
  284. }
  285. static inline char *print_uint64_reversed(char *dst, uint64_t value) {
  286. #ifdef ENV32BIT
  287. if(value <= (uint64_t)0xffffffff)
  288. return print_uint32_reversed(dst, value);
  289. char *d = dst;
  290. do *d++ = (char)('0' + (value % 10)); while((value /= 10) && value > (uint64_t)0xffffffff);
  291. if(value) return print_uint32_reversed(d, value);
  292. return d;
  293. #else
  294. char *d = dst;
  295. do *d++ = (char)('0' + (value % 10)); while((value /= 10));
  296. return d;
  297. #endif
  298. }
  299. static inline char *print_uint32_hex_reversed(char *dst, uint32_t value) {
  300. static const char *digits = "0123456789ABCDEF";
  301. char *d = dst;
  302. do *d++ = digits[value & 0xf]; while((value >>= 4));
  303. return d;
  304. }
  305. static inline char *print_uint64_hex_reversed(char *dst, uint64_t value) {
  306. #ifdef ENV32BIT
  307. if(value <= (uint64_t)0xffffffff)
  308. return print_uint32_hex_reversed(dst, value);
  309. char *d = dst;
  310. do *d++ = hex_digits[value & 0xf]; while((value >>= 4) && value > (uint64_t)0xffffffff);
  311. if(value) return print_uint32_hex_reversed(d, value);
  312. return d;
  313. #else
  314. char *d = dst;
  315. do *d++ = hex_digits[value & 0xf]; while((value >>= 4));
  316. return d;
  317. #endif
  318. }
  319. static inline char *print_uint64_base64_reversed(char *dst, uint64_t value) {
  320. char *d = dst;
  321. do *d++ = base64_digits[value & 63]; while ((value >>= 6));
  322. return d;
  323. }
  324. static inline void char_array_reverse(char *from, char *to) {
  325. // from and to are inclusive
  326. char *begin = from, *end = to, aux;
  327. while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
  328. }
  329. static inline int print_netdata_double(char *dst, NETDATA_DOUBLE value) {
  330. char *s = dst;
  331. if(unlikely(value < 0)) {
  332. *s++ = '-';
  333. value = fabsndd(value);
  334. }
  335. uint64_t fractional_precision = 10000000ULL; // fractional part 7 digits
  336. int fractional_wanted_digits = 7;
  337. int exponent = 0;
  338. if(unlikely(value >= (NETDATA_DOUBLE)(UINT64_MAX / 10))) {
  339. // the number is too big to print using 64bit numbers
  340. // so, let's convert it to exponential notation
  341. exponent = (int)(floorndd(log10ndd(value)));
  342. value /= powndd(10, exponent);
  343. // the max precision we can support is 18 digits
  344. // (UINT64_MAX is 20, but the first is 1)
  345. fractional_precision = 1000000000000000000ULL; // fractional part 18 digits
  346. fractional_wanted_digits = 18;
  347. }
  348. char *d = s;
  349. NETDATA_DOUBLE integral_d, fractional_d;
  350. fractional_d = modfndd(value, &integral_d);
  351. // get the integral and the fractional parts as 64-bit integers
  352. uint64_t integral = (uint64_t)integral_d;
  353. uint64_t fractional = (uint64_t)llrintndd(fractional_d * (NETDATA_DOUBLE)fractional_precision);
  354. if(unlikely(fractional >= fractional_precision)) {
  355. integral++;
  356. fractional -= fractional_precision;
  357. }
  358. // convert the integral part to string (reversed)
  359. d = print_uint64_reversed(d, integral);
  360. char_array_reverse(s, d - 1); // copy reversed the integral string
  361. if(likely(fractional != 0)) {
  362. *d++ = '.'; // add the dot
  363. // convert the fractional part to string (reversed)
  364. d = print_uint64_reversed(s = d, fractional);
  365. while(d - s < fractional_wanted_digits) *d++ = '0'; // prepend zeros to reach precision
  366. char_array_reverse(s, d - 1); // copy reversed the fractional string
  367. // remove trailing zeros from the fractional part
  368. while(*(d - 1) == '0') d--;
  369. }
  370. if(unlikely(exponent != 0)) {
  371. *d++ = 'e';
  372. *d++ = '+';
  373. d = print_uint32_reversed(s = d, exponent);
  374. char_array_reverse(s, d - 1);
  375. }
  376. *d = '\0';
  377. return (int)(d - dst);
  378. }
  379. static inline void buffer_print_uint64(BUFFER *wb, uint64_t value) {
  380. buffer_need_bytes(wb, 50);
  381. char *s = &wb->buffer[wb->len];
  382. char *d = print_uint64_reversed(s, value);
  383. char_array_reverse(s, d - 1);
  384. *d = '\0';
  385. wb->len += d - s;
  386. buffer_overflow_check(wb);
  387. }
  388. static inline void buffer_print_int64(BUFFER *wb, int64_t value) {
  389. buffer_need_bytes(wb, 50);
  390. if(value < 0) {
  391. buffer_fast_strcat(wb, "-", 1);
  392. value = -value;
  393. }
  394. buffer_print_uint64(wb, (uint64_t)value);
  395. buffer_overflow_check(wb);
  396. }
  397. static inline void buffer_print_uint64_hex(BUFFER *wb, uint64_t value) {
  398. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
  399. buffer_fast_strcat(wb, HEX_PREFIX, sizeof(HEX_PREFIX) - 1);
  400. char *s = &wb->buffer[wb->len];
  401. char *d = print_uint64_hex_reversed(s, value);
  402. char_array_reverse(s, d - 1);
  403. *d = '\0';
  404. wb->len += d - s;
  405. buffer_overflow_check(wb);
  406. }
  407. static inline void buffer_print_uint64_base64(BUFFER *wb, uint64_t value) {
  408. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
  409. buffer_fast_strcat(wb, IEEE754_UINT64_B64_PREFIX, sizeof(IEEE754_UINT64_B64_PREFIX) - 1);
  410. char *s = &wb->buffer[wb->len];
  411. char *d = print_uint64_base64_reversed(s, value);
  412. char_array_reverse(s, d - 1);
  413. *d = '\0';
  414. wb->len += d - s;
  415. buffer_overflow_check(wb);
  416. }
  417. static inline void buffer_print_int64_hex(BUFFER *wb, int64_t value) {
  418. buffer_need_bytes(wb, 2);
  419. if(value < 0) {
  420. buffer_fast_strcat(wb, "-", 1);
  421. value = -value;
  422. }
  423. buffer_print_uint64_hex(wb, (uint64_t)value);
  424. buffer_overflow_check(wb);
  425. }
  426. static inline void buffer_print_int64_base64(BUFFER *wb, int64_t value) {
  427. buffer_need_bytes(wb, 2);
  428. if(value < 0) {
  429. buffer_fast_strcat(wb, "-", 1);
  430. value = -value;
  431. }
  432. buffer_print_uint64_base64(wb, (uint64_t)value);
  433. buffer_overflow_check(wb);
  434. }
  435. static inline void buffer_print_netdata_double(BUFFER *wb, NETDATA_DOUBLE value) {
  436. buffer_need_bytes(wb, 512 + 2);
  437. if(isnan(value) || isinf(value)) {
  438. buffer_fast_strcat(wb, "null", 4);
  439. return;
  440. }
  441. else
  442. wb->len += print_netdata_double(&wb->buffer[wb->len], value);
  443. // terminate it
  444. buffer_need_bytes(wb, 1);
  445. wb->buffer[wb->len] = '\0';
  446. buffer_overflow_check(wb);
  447. }
  448. static inline void buffer_print_netdata_double_hex(BUFFER *wb, NETDATA_DOUBLE value) {
  449. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
  450. uint64_t *ptr = (uint64_t *) (&value);
  451. buffer_fast_strcat(wb, IEEE754_DOUBLE_HEX_PREFIX, sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1);
  452. char *s = &wb->buffer[wb->len];
  453. char *d = print_uint64_hex_reversed(s, *ptr);
  454. char_array_reverse(s, d - 1);
  455. *d = '\0';
  456. wb->len += d - s;
  457. buffer_overflow_check(wb);
  458. }
  459. static inline void buffer_print_netdata_double_base64(BUFFER *wb, NETDATA_DOUBLE value) {
  460. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
  461. uint64_t *ptr = (uint64_t *) (&value);
  462. buffer_fast_strcat(wb, IEEE754_DOUBLE_B64_PREFIX, sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1);
  463. char *s = &wb->buffer[wb->len];
  464. char *d = print_uint64_base64_reversed(s, *ptr);
  465. char_array_reverse(s, d - 1);
  466. *d = '\0';
  467. wb->len += d - s;
  468. buffer_overflow_check(wb);
  469. }
  470. typedef enum {
  471. NUMBER_ENCODING_DECIMAL,
  472. NUMBER_ENCODING_HEX,
  473. NUMBER_ENCODING_BASE64,
  474. } NUMBER_ENCODING;
  475. static inline void buffer_print_int64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, int64_t value) {
  476. if(encoding == NUMBER_ENCODING_BASE64)
  477. return buffer_print_int64_base64(wb, value);
  478. if(encoding == NUMBER_ENCODING_HEX)
  479. return buffer_print_int64_hex(wb, value);
  480. return buffer_print_int64(wb, value);
  481. }
  482. static inline void buffer_print_uint64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, uint64_t value) {
  483. if(encoding == NUMBER_ENCODING_BASE64)
  484. return buffer_print_uint64_base64(wb, value);
  485. if(encoding == NUMBER_ENCODING_HEX)
  486. return buffer_print_uint64_hex(wb, value);
  487. return buffer_print_uint64(wb, value);
  488. }
  489. static inline void buffer_print_netdata_double_encoded(BUFFER *wb, NUMBER_ENCODING encoding, NETDATA_DOUBLE value) {
  490. if(encoding == NUMBER_ENCODING_BASE64)
  491. return buffer_print_netdata_double_base64(wb, value);
  492. if(encoding == NUMBER_ENCODING_HEX)
  493. return buffer_print_netdata_double_hex(wb, value);
  494. return buffer_print_netdata_double(wb, value);
  495. }
  496. static inline void buffer_print_spaces(BUFFER *wb, size_t spaces) {
  497. buffer_need_bytes(wb, spaces * 4 + 1);
  498. char *d = &wb->buffer[wb->len];
  499. for(size_t i = 0; i < spaces; i++) {
  500. *d++ = ' ';
  501. *d++ = ' ';
  502. *d++ = ' ';
  503. *d++ = ' ';
  504. }
  505. *d = '\0';
  506. wb->len += spaces * 4;
  507. buffer_overflow_check(wb);
  508. }
  509. static inline void buffer_print_json_comma_newline_spacing(BUFFER *wb) {
  510. if(wb->json.stack[wb->json.depth].count)
  511. buffer_fast_strcat(wb, ",", 1);
  512. if(wb->json.minify)
  513. return;
  514. buffer_fast_strcat(wb, "\n", 1);
  515. buffer_print_spaces(wb, wb->json.depth + 1);
  516. }
  517. static inline void buffer_print_json_key(BUFFER *wb, const char *key) {
  518. buffer_strcat(wb, wb->json.key_quote);
  519. buffer_json_strcat(wb, key);
  520. buffer_strcat(wb, wb->json.key_quote);
  521. }
  522. static inline void buffer_json_add_string_value(BUFFER *wb, const char *value) {
  523. if(value) {
  524. buffer_strcat(wb, wb->json.value_quote);
  525. buffer_json_strcat(wb, value);
  526. buffer_strcat(wb, wb->json.value_quote);
  527. }
  528. else
  529. buffer_fast_strcat(wb, "null", 4);
  530. }
  531. static inline void buffer_json_add_quoted_string_value(BUFFER *wb, const char *value) {
  532. if(value) {
  533. buffer_strcat(wb, wb->json.value_quote);
  534. buffer_json_quoted_strcat(wb, value);
  535. buffer_strcat(wb, wb->json.value_quote);
  536. }
  537. else
  538. buffer_fast_strcat(wb, "null", 4);
  539. }
  540. static inline void buffer_json_member_add_object(BUFFER *wb, const char *key) {
  541. buffer_print_json_comma_newline_spacing(wb);
  542. buffer_print_json_key(wb, key);
  543. buffer_fast_strcat(wb, ":{", 2);
  544. wb->json.stack[wb->json.depth].count++;
  545. _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
  546. }
  547. static inline void buffer_json_object_close(BUFFER *wb) {
  548. #ifdef NETDATA_INTERNAL_CHECKS
  549. assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
  550. assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_OBJECT && "BUFFER JSON: an object is not open to close it");
  551. #endif
  552. if(!wb->json.minify) {
  553. buffer_fast_strcat(wb, "\n", 1);
  554. buffer_print_spaces(wb, wb->json.depth);
  555. }
  556. buffer_fast_strcat(wb, "}", 1);
  557. _buffer_json_depth_pop(wb);
  558. }
  559. static inline void buffer_json_member_add_string(BUFFER *wb, const char *key, const char *value) {
  560. buffer_print_json_comma_newline_spacing(wb);
  561. buffer_print_json_key(wb, key);
  562. buffer_fast_strcat(wb, ":", 1);
  563. buffer_json_add_string_value(wb, value);
  564. wb->json.stack[wb->json.depth].count++;
  565. }
  566. static inline void buffer_json_member_add_string_or_omit(BUFFER *wb, const char *key, const char *value) {
  567. if(value && *value)
  568. buffer_json_member_add_string(wb, key, value);
  569. }
  570. static inline void buffer_json_member_add_string_or_empty(BUFFER *wb, const char *key, const char *value) {
  571. if(!value)
  572. value = "";
  573. buffer_json_member_add_string(wb, key, value);
  574. }
  575. static inline void buffer_json_member_add_quoted_string(BUFFER *wb, const char *key, const char *value) {
  576. buffer_print_json_comma_newline_spacing(wb);
  577. buffer_print_json_key(wb, key);
  578. buffer_fast_strcat(wb, ":", 1);
  579. if(!value || strcmp(value, "null") == 0)
  580. buffer_fast_strcat(wb, "null", 4);
  581. else
  582. buffer_json_add_quoted_string_value(wb, value);
  583. wb->json.stack[wb->json.depth].count++;
  584. }
  585. static inline void buffer_json_member_add_uuid(BUFFER *wb, const char *key, uuid_t *value) {
  586. buffer_print_json_comma_newline_spacing(wb);
  587. buffer_print_json_key(wb, key);
  588. buffer_fast_strcat(wb, ":", 1);
  589. if(value) {
  590. char uuid[GUID_LEN + 1];
  591. uuid_unparse_lower(*value, uuid);
  592. buffer_json_add_string_value(wb, uuid);
  593. }
  594. else
  595. buffer_json_add_string_value(wb, NULL);
  596. wb->json.stack[wb->json.depth].count++;
  597. }
  598. static inline void buffer_json_member_add_boolean(BUFFER *wb, const char *key, bool value) {
  599. buffer_print_json_comma_newline_spacing(wb);
  600. buffer_print_json_key(wb, key);
  601. buffer_fast_strcat(wb, ":", 1);
  602. buffer_strcat(wb, value?"true":"false");
  603. wb->json.stack[wb->json.depth].count++;
  604. }
  605. static inline void buffer_json_member_add_array(BUFFER *wb, const char *key) {
  606. buffer_print_json_comma_newline_spacing(wb);
  607. buffer_print_json_key(wb, key);
  608. buffer_fast_strcat(wb, ":[", 2);
  609. wb->json.stack[wb->json.depth].count++;
  610. _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
  611. }
  612. static inline void buffer_json_add_array_item_array(BUFFER *wb) {
  613. buffer_print_json_comma_newline_spacing(wb);
  614. buffer_fast_strcat(wb, "[", 1);
  615. wb->json.stack[wb->json.depth].count++;
  616. _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
  617. }
  618. static inline void buffer_json_add_array_item_string(BUFFER *wb, const char *value) {
  619. if(wb->json.stack[wb->json.depth].count)
  620. buffer_fast_strcat(wb, ",", 1);
  621. buffer_json_add_string_value(wb, value);
  622. wb->json.stack[wb->json.depth].count++;
  623. }
  624. static inline void buffer_json_add_array_item_double(BUFFER *wb, NETDATA_DOUBLE value) {
  625. if(wb->json.stack[wb->json.depth].count)
  626. buffer_fast_strcat(wb, ",", 1);
  627. buffer_print_netdata_double(wb, value);
  628. wb->json.stack[wb->json.depth].count++;
  629. }
  630. static inline void buffer_json_add_array_item_int64(BUFFER *wb, int64_t value) {
  631. if(wb->json.stack[wb->json.depth].count)
  632. buffer_fast_strcat(wb, ",", 1);
  633. buffer_print_int64(wb, value);
  634. wb->json.stack[wb->json.depth].count++;
  635. }
  636. static inline void buffer_json_add_array_item_uint64(BUFFER *wb, uint64_t value) {
  637. if(wb->json.stack[wb->json.depth].count)
  638. buffer_fast_strcat(wb, ",", 1);
  639. buffer_print_uint64(wb, value);
  640. wb->json.stack[wb->json.depth].count++;
  641. }
  642. static inline void buffer_json_add_array_item_time_t(BUFFER *wb, time_t value) {
  643. if(wb->json.stack[wb->json.depth].count)
  644. buffer_fast_strcat(wb, ",", 1);
  645. buffer_print_int64(wb, value);
  646. wb->json.stack[wb->json.depth].count++;
  647. }
  648. static inline void buffer_json_add_array_item_time_ms(BUFFER *wb, time_t value) {
  649. if(wb->json.stack[wb->json.depth].count)
  650. buffer_fast_strcat(wb, ",", 1);
  651. buffer_print_int64(wb, value);
  652. buffer_fast_strcat(wb, "000", 3);
  653. wb->json.stack[wb->json.depth].count++;
  654. }
  655. static inline void buffer_json_add_array_item_time_t2ms(BUFFER *wb, time_t value) {
  656. if(wb->json.stack[wb->json.depth].count)
  657. buffer_fast_strcat(wb, ",", 1);
  658. buffer_print_int64(wb, value);
  659. buffer_fast_strcat(wb, "000", 3);
  660. wb->json.stack[wb->json.depth].count++;
  661. }
  662. static inline void buffer_json_add_array_item_object(BUFFER *wb) {
  663. if(wb->json.stack[wb->json.depth].count)
  664. buffer_fast_strcat(wb, ",", 1);
  665. buffer_fast_strcat(wb, "{", 1);
  666. wb->json.stack[wb->json.depth].count++;
  667. _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
  668. }
  669. static inline void buffer_json_member_add_time_t(BUFFER *wb, const char *key, time_t value) {
  670. buffer_print_json_comma_newline_spacing(wb);
  671. buffer_print_json_key(wb, key);
  672. buffer_fast_strcat(wb, ":", 1);
  673. buffer_print_int64(wb, value);
  674. wb->json.stack[wb->json.depth].count++;
  675. }
  676. static inline void buffer_json_member_add_time_t2ms(BUFFER *wb, const char *key, time_t value) {
  677. buffer_print_json_comma_newline_spacing(wb);
  678. buffer_print_json_key(wb, key);
  679. buffer_fast_strcat(wb, ":", 1);
  680. buffer_print_int64(wb, value);
  681. buffer_fast_strcat(wb, "000", 3);
  682. wb->json.stack[wb->json.depth].count++;
  683. }
  684. static inline void buffer_json_member_add_uint64(BUFFER *wb, const char *key, uint64_t value) {
  685. buffer_print_json_comma_newline_spacing(wb);
  686. buffer_print_json_key(wb, key);
  687. buffer_fast_strcat(wb, ":", 1);
  688. buffer_print_uint64(wb, value);
  689. wb->json.stack[wb->json.depth].count++;
  690. }
  691. static inline void buffer_json_member_add_int64(BUFFER *wb, const char *key, int64_t value) {
  692. buffer_print_json_comma_newline_spacing(wb);
  693. buffer_print_json_key(wb, key);
  694. buffer_fast_strcat(wb, ":", 1);
  695. buffer_print_int64(wb, value);
  696. wb->json.stack[wb->json.depth].count++;
  697. }
  698. static inline void buffer_json_member_add_double(BUFFER *wb, const char *key, NETDATA_DOUBLE value) {
  699. buffer_print_json_comma_newline_spacing(wb);
  700. buffer_print_json_key(wb, key);
  701. buffer_fast_strcat(wb, ":", 1);
  702. buffer_print_netdata_double(wb, value);
  703. wb->json.stack[wb->json.depth].count++;
  704. }
  705. static inline void buffer_json_array_close(BUFFER *wb) {
  706. #ifdef NETDATA_INTERNAL_CHECKS
  707. assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
  708. assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && "BUFFER JSON: an array is not open to close it");
  709. #endif
  710. buffer_fast_strcat(wb, "]", 1);
  711. _buffer_json_depth_pop(wb);
  712. }
  713. #endif /* NETDATA_WEB_BUFFER_H */