// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_WEB_BUFFER_H
#define NETDATA_WEB_BUFFER_H 1
#include "../string/utf8.h"
#include "../libnetdata.h"
#ifdef ENABLE_HTTPD
#include "h2o/memory.h"
#endif
#define WEB_DATA_LENGTH_INCREASE_STEP 1024
#define BUFFER_JSON_MAX_DEPTH 32 // max is 255
extern const char hex_digits[16];
extern const char base64_digits[64];
extern unsigned char hex_value_from_ascii[256];
extern unsigned char base64_value_from_ascii[256];
typedef enum __attribute__ ((__packed__)) {
BUFFER_JSON_EMPTY = 0,
BUFFER_JSON_OBJECT,
BUFFER_JSON_ARRAY,
} BUFFER_JSON_NODE_TYPE;
typedef struct web_buffer_json_node {
BUFFER_JSON_NODE_TYPE type;
uint32_t count:24;
} BUFFER_JSON_NODE;
#define BUFFER_QUOTE_MAX_SIZE 7
typedef enum __attribute__ ((__packed__)) {
WB_CONTENT_CACHEABLE = (1 << 0),
WB_CONTENT_NO_CACHEABLE = (1 << 1),
} BUFFER_OPTIONS;
typedef enum __attribute__ ((__packed__)) {
CT_NONE = 0,
CT_APPLICATION_JSON,
CT_TEXT_PLAIN,
CT_TEXT_HTML,
CT_APPLICATION_X_JAVASCRIPT,
CT_TEXT_CSS,
CT_TEXT_XML,
CT_APPLICATION_XML,
CT_TEXT_XSL,
CT_APPLICATION_OCTET_STREAM,
CT_APPLICATION_X_FONT_TRUETYPE,
CT_APPLICATION_X_FONT_OPENTYPE,
CT_APPLICATION_FONT_WOFF,
CT_APPLICATION_FONT_WOFF2,
CT_APPLICATION_VND_MS_FONTOBJ,
CT_IMAGE_SVG_XML,
CT_IMAGE_PNG,
CT_IMAGE_JPG,
CT_IMAGE_GIF,
CT_IMAGE_XICON,
CT_IMAGE_ICNS,
CT_IMAGE_BMP,
CT_PROMETHEUS,
} HTTP_CONTENT_TYPE;
typedef struct web_buffer {
size_t size; // allocation size of buffer, in bytes
size_t len; // current data length in buffer, in bytes
char *buffer; // the buffer itself
HTTP_CONTENT_TYPE content_type; // the content type of the data in the buffer
BUFFER_OPTIONS options; // options related to the content
time_t date; // the timestamp this content has been generated
time_t expires; // the timestamp this content expires
size_t *statistics;
struct {
char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
int8_t depth;
bool minify;
BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
} json;
} BUFFER;
#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)
#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)
#define buffer_strlen(wb) ((wb)->len)
const char *buffer_tostring(BUFFER *wb);
#define BUFFER_OVERFLOW_EOF "EOF"
#ifdef NETDATA_INTERNAL_CHECKS
#define buffer_overflow_check(b) _buffer_overflow_check(b)
#else
#define buffer_overflow_check(b)
#endif
static inline void _buffer_overflow_check(BUFFER *b) {
assert(b->len <= b->size &&
"BUFFER: length is above buffer size.");
assert(!(b->buffer && (b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0)) &&
"BUFFER: detected overflow.");
}
static inline void buffer_flush(BUFFER *wb) {
wb->len = 0;
wb->json.depth = 0;
wb->json.stack[0].type = BUFFER_JSON_EMPTY;
wb->json.stack[0].count = 0;
if(wb->buffer)
wb->buffer[0] = '\0';
}
void buffer_reset(BUFFER *wb);
void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
BUFFER *buffer_create(size_t size, size_t *statistics);
void buffer_free(BUFFER *b);
void buffer_increase(BUFFER *b, size_t free_size_required);
void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4);
void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
void buffer_strcat_htmlescape(BUFFER *wb, const char *txt);
void buffer_char_repla