buffer.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. #define BUFFER_OVERFLOW_EOF "EOF"
  4. static inline void buffer_overflow_init(BUFFER *b)
  5. {
  6. b->buffer[b->size] = '\0';
  7. strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
  8. }
  9. #ifdef NETDATA_INTERNAL_CHECKS
  10. #define buffer_overflow_check(b) _buffer_overflow_check(b, __FILE__, __FUNCTION__, __LINE__)
  11. #else
  12. #define buffer_overflow_check(b)
  13. #endif
  14. static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line)
  15. {
  16. if(b->len > b->size) {
  17. error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
  18. b->len = b->size;
  19. }
  20. if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0) {
  21. error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
  22. buffer_overflow_init(b);
  23. }
  24. }
  25. void buffer_reset(BUFFER *wb)
  26. {
  27. buffer_flush(wb);
  28. wb->contenttype = CT_TEXT_PLAIN;
  29. wb->options = 0;
  30. wb->date = 0;
  31. wb->expires = 0;
  32. buffer_overflow_check(wb);
  33. }
  34. const char *buffer_tostring(BUFFER *wb)
  35. {
  36. buffer_need_bytes(wb, 1);
  37. wb->buffer[wb->len] = '\0';
  38. buffer_overflow_check(wb);
  39. return(wb->buffer);
  40. }
  41. void buffer_char_replace(BUFFER *wb, char from, char to)
  42. {
  43. char *s = wb->buffer, *end = &wb->buffer[wb->len];
  44. while(s != end) {
  45. if(*s == from) *s = to;
  46. s++;
  47. }
  48. buffer_overflow_check(wb);
  49. }
  50. // This trick seems to give an 80% speed increase in 32bit systems
  51. // print_calculated_number_llu_r() will just print the digits up to the
  52. // point the remaining value fits in 32 bits, and then calls
  53. // print_calculated_number_lu_r() to print the rest with 32 bit arithmetic.
  54. inline char *print_number_lu_r(char *str, unsigned long uvalue) {
  55. char *wstr = str;
  56. // print each digit
  57. do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
  58. return wstr;
  59. }
  60. inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
  61. char *wstr = str;
  62. // print each digit
  63. do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
  64. if(uvalue) return print_number_lu_r(wstr, uvalue);
  65. return wstr;
  66. }
  67. inline char *print_number_llu_r_smart(char *str, unsigned long long uvalue) {
  68. #ifdef ENVIRONMENT32
  69. if(uvalue > (unsigned long long)0xffffffff)
  70. str = print_number_llu_r(str, uvalue);
  71. else
  72. str = print_number_lu_r(str, uvalue);
  73. #else
  74. do *str++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
  75. #endif
  76. return str;
  77. }
  78. void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
  79. {
  80. buffer_need_bytes(wb, 50);
  81. char *str = &wb->buffer[wb->len];
  82. char *wstr = str;
  83. #ifdef ENVIRONMENT32
  84. if(uvalue > (unsigned long long)0xffffffff)
  85. wstr = print_number_llu_r(wstr, uvalue);
  86. else
  87. wstr = print_number_lu_r(wstr, uvalue);
  88. #else
  89. do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
  90. #endif
  91. // terminate it
  92. *wstr = '\0';
  93. // reverse it
  94. char *begin = str, *end = wstr - 1, aux;
  95. while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
  96. // return the buffer length
  97. wb->len += wstr - str;
  98. }
  99. void buffer_strcat(BUFFER *wb, const char *txt)
  100. {
  101. // buffer_sprintf(wb, "%s", txt);
  102. if(unlikely(!txt || !*txt)) return;
  103. buffer_need_bytes(wb, 1);
  104. char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
  105. size_t len = wb->len;
  106. start = s;
  107. while(*txt && s != end)
  108. *s++ = *txt++;
  109. len += s - start;
  110. wb->len = len;
  111. buffer_overflow_check(wb);
  112. if(*txt) {
  113. debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
  114. len = strlen(txt);
  115. buffer_increase(wb, len);
  116. buffer_strcat(wb, txt);
  117. }
  118. else {
  119. // terminate the string
  120. // without increasing the length
  121. buffer_need_bytes(wb, (size_t)1);
  122. wb->buffer[wb->len] = '\0';
  123. }
  124. }
  125. void buffer_strcat_jsonescape(BUFFER *wb, const char *txt)
  126. {
  127. while(*txt) {
  128. switch(*txt) {
  129. case '\\':
  130. buffer_need_bytes(wb, 2);
  131. wb->buffer[wb->len++] = '\\';
  132. wb->buffer[wb->len++] = '\\';
  133. break;
  134. case '"':
  135. buffer_need_bytes(wb, 2);
  136. wb->buffer[wb->len++] = '\\';
  137. wb->buffer[wb->len++] = '"';
  138. break;
  139. default: {
  140. buffer_need_bytes(wb, 1);
  141. wb->buffer[wb->len++] = *txt;
  142. }
  143. }
  144. txt++;
  145. }
  146. buffer_overflow_check(wb);
  147. }
  148. void buffer_strcat_htmlescape(BUFFER *wb, const char *txt)
  149. {
  150. while(*txt) {
  151. switch(*txt) {
  152. case '&': buffer_strcat(wb, "&"); break;
  153. case '<': buffer_strcat(wb, "&lt;"); break;
  154. case '>': buffer_strcat(wb, "&gt;"); break;
  155. case '"': buffer_strcat(wb, "&quot;"); break;
  156. case '/': buffer_strcat(wb, "&#x2F;"); break;
  157. case '\'': buffer_strcat(wb, "&#x27;"); break;
  158. default: {
  159. buffer_need_bytes(wb, 1);
  160. wb->buffer[wb->len++] = *txt;
  161. }
  162. }
  163. txt++;
  164. }
  165. buffer_overflow_check(wb);
  166. }
  167. void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...)
  168. {
  169. if(unlikely(!fmt || !*fmt)) return;
  170. buffer_need_bytes(wb, len + 1);
  171. va_list args;
  172. va_start(args, fmt);
  173. wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
  174. va_end(args);
  175. buffer_overflow_check(wb);
  176. // the buffer is \0 terminated by vsnprintfz
  177. }
  178. void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args)
  179. {
  180. if(unlikely(!fmt || !*fmt)) return;
  181. buffer_need_bytes(wb, 2);
  182. size_t len = wb->size - wb->len - 1;
  183. wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
  184. buffer_overflow_check(wb);
  185. // the buffer is \0 terminated by vsnprintfz
  186. }
  187. void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
  188. {
  189. if(unlikely(!fmt || !*fmt)) return;
  190. va_list args;
  191. size_t wrote = 0, need = 2, multiplier = 0, len;
  192. do {
  193. need += wrote + multiplier * WEB_DATA_LENGTH_INCREASE_STEP;
  194. multiplier++;
  195. debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu, by %zu bytes (wrote = %zu)\n", wb->len, wb->size, need, wrote);
  196. buffer_need_bytes(wb, need);
  197. len = wb->size - wb->len - 1;
  198. va_start(args, fmt);
  199. wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
  200. va_end(args);
  201. } while(wrote >= len);
  202. wb->len += wrote;
  203. // the buffer is \0 terminated by vsnprintf
  204. }
  205. void buffer_rrd_value(BUFFER *wb, calculated_number value)
  206. {
  207. buffer_need_bytes(wb, 50);
  208. if(isnan(value) || isinf(value)) {
  209. buffer_strcat(wb, "null");
  210. return;
  211. }
  212. else
  213. wb->len += print_calculated_number(&wb->buffer[wb->len], value);
  214. // terminate it
  215. buffer_need_bytes(wb, 1);
  216. wb->buffer[wb->len] = '\0';
  217. buffer_overflow_check(wb);
  218. }
  219. // generate a javascript date, the fastest possible way...
  220. void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
  221. {
  222. // 10 20 30 = 35
  223. // 01234567890123456789012345678901234
  224. // Date(2014,04,01,03,28,20)
  225. buffer_need_bytes(wb, 30);
  226. char *b = &wb->buffer[wb->len], *p;
  227. unsigned int *q = (unsigned int *)b;
  228. #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
  229. *q++ = 0x65746144; // "Date" backwards.
  230. #else
  231. *q++ = 0x44617465; // "Date"
  232. #endif
  233. p = (char *)q;
  234. *p++ = '(';
  235. *p++ = '0' + year / 1000; year %= 1000;
  236. *p++ = '0' + year / 100; year %= 100;
  237. *p++ = '0' + year / 10;
  238. *p++ = '0' + year % 10;
  239. *p++ = ',';
  240. *p = '0' + month / 10; if (*p != '0') p++;
  241. *p++ = '0' + month % 10;
  242. *p++ = ',';
  243. *p = '0' + day / 10; if (*p != '0') p++;
  244. *p++ = '0' + day % 10;
  245. *p++ = ',';
  246. *p = '0' + hours / 10; if (*p != '0') p++;
  247. *p++ = '0' + hours % 10;
  248. *p++ = ',';
  249. *p = '0' + minutes / 10; if (*p != '0') p++;
  250. *p++ = '0' + minutes % 10;
  251. *p++ = ',';
  252. *p = '0' + seconds / 10; if (*p != '0') p++;
  253. *p++ = '0' + seconds % 10;
  254. unsigned short *r = (unsigned short *)p;
  255. #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
  256. *r++ = 0x0029; // ")\0" backwards.
  257. #else
  258. *r++ = 0x2900; // ")\0"
  259. #endif
  260. wb->len += (size_t)((char *)r - b - 1);
  261. // terminate it
  262. wb->buffer[wb->len] = '\0';
  263. buffer_overflow_check(wb);
  264. }
  265. // generate a date, the fastest possible way...
  266. void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
  267. {
  268. // 10 20 30 = 35
  269. // 01234567890123456789012345678901234
  270. // 2014-04-01 03:28:20
  271. buffer_need_bytes(wb, 36);
  272. char *b = &wb->buffer[wb->len];
  273. char *p = b;
  274. *p++ = '0' + year / 1000; year %= 1000;
  275. *p++ = '0' + year / 100; year %= 100;
  276. *p++ = '0' + year / 10;
  277. *p++ = '0' + year % 10;
  278. *p++ = '-';
  279. *p++ = '0' + month / 10;
  280. *p++ = '0' + month % 10;
  281. *p++ = '-';
  282. *p++ = '0' + day / 10;
  283. *p++ = '0' + day % 10;
  284. *p++ = ' ';
  285. *p++ = '0' + hours / 10;
  286. *p++ = '0' + hours % 10;
  287. *p++ = ':';
  288. *p++ = '0' + minutes / 10;
  289. *p++ = '0' + minutes % 10;
  290. *p++ = ':';
  291. *p++ = '0' + seconds / 10;
  292. *p++ = '0' + seconds % 10;
  293. *p = '\0';
  294. wb->len += (size_t)(p - b);
  295. // terminate it
  296. wb->buffer[wb->len] = '\0';
  297. buffer_overflow_check(wb);
  298. }
  299. BUFFER *buffer_create(size_t size)
  300. {
  301. BUFFER *b;
  302. debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
  303. b = callocz(1, sizeof(BUFFER));
  304. b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
  305. b->buffer[0] = '\0';
  306. b->size = size;
  307. b->contenttype = CT_TEXT_PLAIN;
  308. buffer_overflow_init(b);
  309. buffer_overflow_check(b);
  310. return(b);
  311. }
  312. void buffer_free(BUFFER *b) {
  313. if(unlikely(!b)) return;
  314. buffer_overflow_check(b);
  315. debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
  316. freez(b->buffer);
  317. freez(b);
  318. }
  319. void buffer_increase(BUFFER *b, size_t free_size_required) {
  320. buffer_overflow_check(b);
  321. size_t left = b->size - b->len;
  322. if(left >= free_size_required) return;
  323. size_t increase = free_size_required - left;
  324. if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
  325. debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
  326. b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
  327. b->size += increase;
  328. buffer_overflow_init(b);
  329. buffer_overflow_check(b);
  330. }