]> arthur.barton.de Git - netdata.git/commitdiff
code cleanup
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sun, 22 Nov 2015 12:16:54 +0000 (14:16 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sun, 22 Nov 2015 12:16:54 +0000 (14:16 +0200)
README.md
src/appconfig.c
src/rrd2json.c
src/web_buffer.c
src/web_buffer.h
src/web_client.c

index a7f23786e17ba79d2487cdb79bccbfbd2417f72d..64d89fa5cf7d870375b2f7b06b6e349392c13c8f 100755 (executable)
--- a/README.md
+++ b/README.md
@@ -17,7 +17,9 @@ Check it live at:
 
 Here is a screenshot:
 
-![image](https://cloud.githubusercontent.com/assets/2662304/10440038/b40bcb6c-7146-11e5-93ac-db2e177e39f8.png)
+![image](https://cloud.githubusercontent.com/assets/2662304/11323720/0ea2a5f4-9123-11e5-9c30-d57072b8e12c.png)
+
+![image](https://cloud.githubusercontent.com/assets/2662304/11323728/3cb6e810-9123-11e5-97b3-662fd6f35725.png)
 
 
 # Features
index 0a60bc51a8f7183702d8c36912933a9b49aab8b5..94002fe4c0bed74c7f4c2457fcba58405111b928 100755 (executable)
@@ -359,10 +359,9 @@ void generate_config(struct web_buffer *wb, int only_changed)
        struct config_value *cv;
 
        for(i = 0; i < 3 ;i++) {
-               web_buffer_increase(wb, 500);
                switch(i) {
                        case 0:
-                               web_buffer_printf(wb, 
+                               web_buffer_strcat(wb,
                                        "# NetData Configuration\n"
                                        "# You can uncomment and change any of the options below.\n"
                                        "# The value shown in the commented settings, is the default value.\n"
@@ -370,11 +369,11 @@ void generate_config(struct web_buffer *wb, int only_changed)
                                break;
 
                        case 1:
-                               web_buffer_printf(wb, "\n\n# per plugin configuration\n");
+                               web_buffer_strcat(wb, "\n\n# per plugin configuration\n");
                                break;
 
                        case 2:
-                               web_buffer_printf(wb, "\n\n# per chart configuration\n");
+                               web_buffer_strcat(wb, "\n\n# per chart configuration\n");
                                break;
                }
 
@@ -397,21 +396,17 @@ void generate_config(struct web_buffer *wb, int only_changed)
                                if(only_changed && !changed) continue;
 
                                if(!used) {
-                                       web_buffer_increase(wb, 500);
-                                       web_buffer_printf(wb, "\n# node '%s' is not used.", co->name);
+                                       web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX+1, "\n# node '%s' is not used.", co->name);
                                }
 
-                               web_buffer_increase(wb, CONFIG_FILE_LINE_MAX+1);
-                               web_buffer_printf(wb, "\n[%s]\n", co->name);
+                               web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX+1, "\n[%s]\n", co->name);
 
                                for(cv = co->values; cv ; cv = cv->next) {
 
                                        if(used && !(cv->flags & CONFIG_VALUE_USED)) {
-                                               web_buffer_increase(wb, CONFIG_FILE_LINE_MAX + 1);
-                                               web_buffer_printf(wb, "\n\t# option '%s' is not used.\n", cv->name);
+                                               web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX + 1, "\n\t# option '%s' is not used.\n", cv->name);
                                        }
-                                       web_buffer_increase(wb, CONFIG_FILE_LINE_MAX + 1);
-                                       web_buffer_printf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
+                                       web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX + 1, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
                                }
                        }
                }
index 888c8f492981824faf82db1a8d42e2157d04b90e..64cfa98f491d1e913d7392d3ef4b9c7f988a9ee5 100755 (executable)
@@ -15,11 +15,10 @@ char *hostname = "unknown";
 unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *wb)
 {
        time_t now = time(NULL);
-       web_buffer_increase(wb, 65536);
 
        pthread_rwlock_rdlock(&st->rwlock);
 
-       web_buffer_printf(wb,
+       web_buffer_snprintf(wb, 65536,
                "\t\t{\n"
                "\t\t\t\"id\": \"%s\",\n"
                "\t\t\t\"name\": \"%s\",\n"
@@ -70,11 +69,10 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
 
        RRDDIM *rd;
        for(rd = st->dimensions; rd ; rd = rd->next) {
-               web_buffer_increase(wb, 4096);
 
                memory += rd->memsize;
 
-               web_buffer_printf(wb,
+               web_buffer_snprintf(wb, 4096,
                        "\t\t\t\t{\n"
                        "\t\t\t\t\t\"id\": \"%s\",\n"
                        "\t\t\t\t\t\"name\": \"%s\",\n"
@@ -107,7 +105,7 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
                        );
        }
 
-       web_buffer_printf(wb,
+       web_buffer_snprintf(wb, 200,
                "\t\t\t],\n"
                "\t\t\t\"memory\" : %lu\n"
                "\t\t}"
@@ -123,34 +121,30 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
 
 void rrd_stats_graph_json(RRDSET *st, char *options, struct web_buffer *wb)
 {
-       web_buffer_increase(wb, 2048);
-
-       web_buffer_printf(wb, RRD_GRAPH_JSON_HEADER);
+       web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_HEADER), RRD_GRAPH_JSON_HEADER);
        rrd_stats_one_json(st, options, wb);
-       web_buffer_printf(wb, RRD_GRAPH_JSON_FOOTER);
+       web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_FOOTER), RRD_GRAPH_JSON_FOOTER);
 }
 
 void rrd_stats_all_json(struct web_buffer *wb)
 {
-       web_buffer_increase(wb, 2048);
-
        unsigned long memory = 0;
        long c;
        RRDSET *st;
 
-       web_buffer_printf(wb, RRD_GRAPH_JSON_HEADER);
+       web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_HEADER), RRD_GRAPH_JSON_HEADER);
 
        pthread_rwlock_rdlock(&rrdset_root_rwlock);
        for(st = rrdset_root, c = 0; st ; st = st->next) {
                if(st->enabled) {
-                       if(c) web_buffer_printf(wb, "%s", ",\n");
+                       if(c) web_buffer_strcat(wb, ",\n");
                        memory += rrd_stats_one_json(st, NULL, wb);
                        c++;
                }
        }
        pthread_rwlock_unlock(&rrdset_root_rwlock);
        
-       web_buffer_printf(wb, "\n\t],\n"
+       web_buffer_snprintf(wb, 4096, "\n\t],\n"
                "\t\"hostname\": \"%s\",\n"
                "\t\"update_every\": %d,\n"
                "\t\"history\": %d,\n"
@@ -379,7 +373,8 @@ RRDR *rrd2rrdr(RRDSET *st, long points, time_t after, time_t before, int group_m
        if(duration <= 0) return NULL;
 
        // check the required points
-       if(points <= 0) points = duration;
+       if(points > duration / st->update_every) points = 0;
+       if(points <= 0) points = duration / st->update_every;
 
        // calculate proper grouping of source data
        long group = duration / points;
@@ -622,7 +617,7 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
        for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
        if(!dimensions) {
                pthread_rwlock_unlock(&st->rwlock);
-               web_buffer_printf(wb, "No dimensions yet.");
+               web_buffer_strcat(wb, "No dimensions yet.");
                return 0;
        }
 
@@ -694,10 +689,10 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                // -------------------------------------------------------------------------
                // print the JSON header
 
-               web_buffer_printf(wb, "{\n      %scols%s:\n     [\n", kq, kq);
-               web_buffer_printf(wb, "         {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
-               web_buffer_printf(wb, "         {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-               web_buffer_printf(wb, "         {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+               web_buffer_snprintf(wb, 1024, "{\n      %scols%s:\n     [\n", kq, kq);
+               web_buffer_snprintf(wb, 1024, "         {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+               web_buffer_snprintf(wb, 1024, "         {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+               web_buffer_snprintf(wb, 1024, "         {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
 
                // print the header for each dimension
                // and update the print_hidden array for the dimensions that should be hidden
@@ -705,15 +700,15 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
                        if(!print_hidden[c]) {
                                pc++;
-                               web_buffer_printf(wb, ",\n              {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+                               web_buffer_snprintf(wb, 1024, ",\n              {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
                        }
                }
                if(!pc) {
-                       web_buffer_printf(wb, ",\n              {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
+                       web_buffer_snprintf(wb, 1024, ",\n              {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
                }
 
                // print the begin of row data
-               web_buffer_printf(wb, "\n       ],\n    %srows%s:\n     [\n", kq, kq);
+               web_buffer_snprintf(wb, 1024, "\n       ],\n    %srows%s:\n     [\n", kq, kq);
 
 
                // -------------------------------------------------------------------------
@@ -785,18 +780,15 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                                        break;
                                }
 
-                               // check if we may exceed the buffer provided
-                               web_buffer_increase(wb, line_size);
-
                                // generate the local date time
                                struct tm *tm = localtime(&now);
                                if(!tm) { error("localtime() failed."); continue; }
                                if(now > last_timestamp) last_timestamp = now;
 
-                               if(printed) web_buffer_strcpy(wb, "]},\n");
-                               web_buffer_strcpy(wb, pre_date);
+                               if(printed) web_buffer_strcat(wb, "]},\n");
+                               web_buffer_strcat(wb, pre_date);
                                web_buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-                               web_buffer_strcpy(wb, post_date);
+                               web_buffer_strcat(wb, post_date);
 
                                print_this = 1;
                        }
@@ -832,26 +824,26 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                        if(print_this) {
                                if(annotate_reset) {
                                        annotation_count++;
-                                       web_buffer_strcpy(wb, overflow_annotation);
+                                       web_buffer_strcat(wb, overflow_annotation);
                                        annotate_reset = 0;
                                }
                                else
-                                       web_buffer_strcpy(wb, normal_annotation);
+                                       web_buffer_strcat(wb, normal_annotation);
 
                                pc = 0;
                                for(c = 0 ; c < dimensions ; c++) {
                                        if(found_non_existing[c] == group_count) {
                                                // all entries are non-existing
                                                pc++;
-                                               web_buffer_strcpy(wb, pre_value);
-                                               web_buffer_strcpy(wb, "null");
-                                               web_buffer_strcpy(wb, post_value);
+                                               web_buffer_strcat(wb, pre_value);
+                                               web_buffer_strcat(wb, "null");
+                                               web_buffer_strcat(wb, post_value);
                                        }
                                        else if(!print_hidden[c]) {
                                                pc++;
-                                               web_buffer_strcpy(wb, pre_value);
+                                               web_buffer_strcat(wb, pre_value);
                                                web_buffer_rrd_value(wb, group_values[c]);
-                                               web_buffer_strcpy(wb, post_value);
+                                               web_buffer_strcat(wb, post_value);
 
                                                if(group_values[c]) found_non_zero[c]++;
                                        }
@@ -863,9 +855,9 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
 
                                // if all dimensions are hidden, print a null
                                if(!pc) {
-                                       web_buffer_strcpy(wb, pre_value);
-                                       web_buffer_strcpy(wb, "null");
-                                       web_buffer_strcpy(wb, post_value);
+                                       web_buffer_strcat(wb, pre_value);
+                                       web_buffer_strcat(wb, "null");
+                                       web_buffer_strcat(wb, post_value);
                                }
 
                                printed++;
@@ -873,8 +865,8 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                        }
                }
 
-               if(printed) web_buffer_printf(wb, "]}");
-               web_buffer_printf(wb, "\n       ]\n}\n");
+               if(printed) web_buffer_strcat(wb, "]}");
+               web_buffer_strcat(wb, "\n       ]\n}\n");
 
                if(only_non_zero && max_loop > 1) {
                        int changed = 0;
@@ -888,14 +880,14 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
                                }
                        }
 
-                       if(changed) web_buffer_reset(wb);
+                       if(changed) web_buffer_flush(wb);
                        else break;
                }
                else break;
 
        } // max_loop
 
-       debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %ld bytes", st->name, wb->bytes);
+       debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %ld bytes", st->name, wb->len);
 
        pthread_rwlock_unlock(&st->rwlock);
        return last_timestamp;
index f679f1b7e6d2f36e4d7d4c051ca76dd1d259f205..cea5be61f03e2ceec479dc6be9fbfa4b90dac96e 100755 (executable)
@@ -2,6 +2,7 @@
 #include <config.h>
 #endif
 #include <stdlib.h>
+#include <string.h>
 
 #ifdef STORAGE_WITH_MATH
 #include <math.h>
 #include "web_buffer.h"
 #include "log.h"
 
-void web_buffer_strcpy(struct web_buffer *wb, const char *txt)
+void web_buffer_reset(struct web_buffer *wb)
+{
+       web_buffer_flush(wb);
+
+       wb->sent = 0;
+       wb->rlen = 0;
+       wb->contenttype = CT_TEXT_PLAIN;
+       wb->date = 0;
+}
+
+void web_buffer_char_replace(struct web_buffer *wb, char from, char to)
+{
+       char *s = wb->buffer, *end = &wb->buffer[wb->len];
+
+       while(s != end) {
+               if(*s == from) *s = to;
+               s++;
+       }
+}
+
+
+void web_buffer_strcat(struct web_buffer *wb, const char *txt)
 {
        char *buffer = wb->buffer;
-       long bytes = wb->bytes, size = wb->size, i = 0;
+       const char *s = txt;
+       long bytes = wb->len, size = wb->size;
+
+       while(*s && bytes < size)
+               buffer[bytes++] = *s++;
 
-       while(txt[i] && bytes < size)
-               buffer[bytes++] = txt[i++];
+       wb->len = bytes;
 
-       wb->bytes = bytes;
+       if(*s) {
+               web_buffer_need_bytes(wb, strlen(s));
+               web_buffer_strcat(wb, s);
+       }
+       else {
+               // terminate the string
+               // without increasing the length
+               web_buffer_need_bytes(wb, 1);
+               wb->buffer[wb->len] = '\0';
+       }
 }
 
+
+void web_buffer_snprintf(struct web_buffer *wb, size_t len, const char *fmt, ...)
+{
+       web_buffer_need_bytes(wb, len+1);
+
+       va_list args;
+       va_start(args, fmt);
+       wb->len += vsnprintf(&wb->buffer[wb->len], len+1, fmt, args);
+       va_end(args);
+
+       // the buffer is \0 terminated by vsnprintf
+}
+
+
 void web_buffer_rrd_value(struct web_buffer *wb, calculated_number value)
 {
-       if(wb->size - wb->bytes < 50) return;
-       wb->bytes += print_calculated_number(&wb->buffer[wb->bytes], value);
+       web_buffer_need_bytes(wb, 50);
+       wb->len += print_calculated_number(&wb->buffer[wb->len], value);
+
+       // terminate it
+       web_buffer_need_bytes(wb, 1);
+       wb->buffer[wb->len] = '\0';
 }
 
 // generate a javascript date, the fastest possible way...
@@ -35,9 +87,9 @@ void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int
        // 01234567890123456789012345678901234
        // Date(2014, 04, 01, 03, 28, 20, 065)
 
-       if(wb->size - wb->bytes < 36) return;
+       web_buffer_need_bytes(wb, 36);
 
-       char *b = &wb->buffer[wb->bytes];
+       char *b = &wb->buffer[wb->len];
 
        int i = 0;
        b[i++]='D';
@@ -72,7 +124,11 @@ void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int
        b[i++]=')';
        b[i]='\0';
 
-       wb->bytes += i;
+       wb->len += i;
+
+       // terminate it
+       web_buffer_need_bytes(wb, 1);
+       wb->buffer[wb->len] = '\0';
 }
 
 struct web_buffer *web_buffer_create(long size)
@@ -109,9 +165,10 @@ void web_buffer_free(struct web_buffer *b)
 
 void web_buffer_increase(struct web_buffer *b, long free_size_required)
 {
-       long left = b->size - b->bytes;
+       long left = b->size - b->len;
 
        if(left >= free_size_required) return;
+
        long increase = free_size_required - left;
        if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
 
index ae237afe3f54edc880b06b0dc6f176fb4ecc4b6b..93e4c065b8a92837272e27c30ecf5a0f677b30ef 100755 (executable)
@@ -9,11 +9,11 @@
 
 struct web_buffer {
        long size;              // allocation size of buffer
-       long bytes;             // current data length in buffer
+       long len;               // current data length in buffer
        long sent;              // current data length sent to output
        char *buffer;   // the buffer
        int contenttype;
-       long rbytes;    // if non-zero, the excepted size of ifd
+       long rlen;      // if non-zero, the excepted size of ifd
        time_t date;    // the date this content has been generated
 };
 
@@ -33,10 +33,12 @@ struct web_buffer {
 #define CT_APPLICATION_VND_MS_FONTOBJ  13
 #define CT_IMAGE_SVG_XML                               14
 
-#define web_buffer_printf(wb, args...) wb->bytes += snprintf(&wb->buffer[wb->bytes], (wb->size - wb->bytes), ##args)
-#define web_buffer_reset(wb) wb->buffer[wb->bytes = 0] = '\0'
+#define web_buffer_need_bytes(buffer, needed_free_size) do { if(unlikely((buffer)->size - (buffer)->len < (needed_free_size))) web_buffer_increase((buffer), (needed_free_size)); } while(0)
 
-void web_buffer_strcpy(struct web_buffer *wb, const char *txt);
+#define web_buffer_flush(wb) wb->buffer[wb->len = 0] = '\0'
+void web_buffer_reset(struct web_buffer *wb);
+
+void web_buffer_strcat(struct web_buffer *wb, const char *txt);
 void web_buffer_rrd_value(struct web_buffer *wb, calculated_number value);
 
 void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int hours, int minutes, int seconds);
@@ -45,4 +47,8 @@ struct web_buffer *web_buffer_create(long size);
 void web_buffer_free(struct web_buffer *b);
 void web_buffer_increase(struct web_buffer *b, long free_size_required);
 
+void web_buffer_snprintf(struct web_buffer *wb, size_t len, const char *fmt, ...);
+
+void web_buffer_char_replace(struct web_buffer *wb, char from, char to);
+
 #endif /* NETDATA_WEB_BUFFER_H */
index 48fd47be4bd51cec3ab9edbc6637ec9eb64b64b7..3e263f1dc7d83bd1067119d367b7cfa7195cb27e 100755 (executable)
@@ -152,7 +152,7 @@ int mysendfile(struct web_client *w, char *filename)
        // if the filename contains a / or a .., refuse to serve it
        if(strchr(filename, '/') != 0 || strstr(filename, "..") != 0) {
                debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
-               web_buffer_printf(w->data, "File '%s' cannot be served. Filenames cannot contain / or ..", filename);
+               web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "File '%s' cannot be served. Filenames cannot contain / or ..", filename);
                return 400;
        }
 
@@ -164,14 +164,14 @@ int mysendfile(struct web_client *w, char *filename)
        struct stat stat;
        if(lstat(webfilename, &stat) != 0) {
                error("%llu: File '%s' is not found.", w->id, webfilename);
-               web_buffer_printf(w->data, "File '%s' does not exist, or is not accessible.", filename);
+               web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "File '%s' does not exist, or is not accessible.", filename);
                return 404;
        }
 
        // check if the file is owned by us
        if(stat.st_uid != getuid() && stat.st_uid != geteuid()) {
                error("%llu: File '%s' is owned by user %d (I run as user %d). Access Denied.", w->id, webfilename, stat.st_uid, getuid());
-               web_buffer_printf(w->data, "Access to file '%s' is not permitted.", filename);
+               web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "Access to file '%s' is not permitted.", filename);
                return 403;
        }
 
@@ -183,12 +183,12 @@ int mysendfile(struct web_client *w, char *filename)
                if(errno == EBUSY || errno == EAGAIN) {
                        error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
                        snprintf(w->response_header, MAX_HTTP_HEADER_SIZE, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
-                       web_buffer_printf(w->data, "The file '%s' is currently busy. Please try again later.", filename);
+                       web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "The file '%s' is currently busy. Please try again later.", filename);
                        return 307;
                }
                else {
                        error("%llu: Cannot open file '%s'.", w->id, webfilename);
-                       web_buffer_printf(w->data, "Cannot open file '%s'.", filename);
+                       web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "Cannot open file '%s'.", filename);
                        return 404;
                }
        }
@@ -212,9 +212,8 @@ int mysendfile(struct web_client *w, char *filename)
        w->mode = WEB_CLIENT_MODE_FILECOPY;
        w->wait_receive = 1;
        w->wait_send = 0;
-       w->data->bytes = 0;
-       w->data->buffer[0] = '\0';
-       w->data->rbytes = stat.st_size;
+       web_buffer_flush(w->data);
+       w->data->rlen = stat.st_size;
        w->data->date = stat.st_mtim.tv_sec;
 
        return 200;
@@ -225,13 +224,13 @@ void web_client_reset(struct web_client *w)
        struct timeval tv;
        gettimeofday(&tv, NULL);
 
-       long sent = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
+       long sent = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rlen:w->data->len;
 
 #ifdef NETDATA_WITH_ZLIB
        if(likely(w->zoutput)) sent = (long)w->zstream.total_out;
 #endif
 
-       long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
+       long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rlen:w->data->len;
 
        if(likely(w->last_url[0]))
                log_access("%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
@@ -254,15 +253,11 @@ void web_client_reset(struct web_client *w)
 
        w->last_url[0] = '\0';
 
-       w->data->contenttype = CT_TEXT_PLAIN;
        w->mode = WEB_CLIENT_MODE_NORMAL;
 
-       w->data->rbytes = 0;
-       w->data->bytes = 0;
-       w->data->sent = 0;
-
        w->response_header[0] = '\0';
-       w->data->buffer[0] = '\0';
+
+       web_buffer_reset(w->data);
 
        w->wait_receive = 1;
        w->wait_send = 0;
@@ -350,7 +345,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
        if(!st) {
                // we don't have it
                // try to send a file with that name
-               w->data->bytes = 0;
+               web_buffer_flush(w->data);
                return(mysendfile(w, tok));
        }
 
@@ -404,7 +399,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
        }
 
        w->data->contenttype = CT_APPLICATION_JSON;
-       w->data->bytes = 0;
+       web_buffer_flush(w->data);
 
        char *google_version = "0.6";
        char *google_reqId = "0";
@@ -456,7 +451,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
 
                        // check the client wants json
                        if(strcmp(google_out, "json") != 0) {
-                               w->data->bytes = snprintf(w->data->buffer, w->data->size,
+                               web_buffer_snprintf(w->data, 65536,
                                        "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
                                        google_responseHandler, google_version, google_reqId, google_out);
                                        return 200;
@@ -465,7 +460,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
        }
 
        if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
-               w->data->bytes = snprintf(w->data->buffer, w->data->size,
+               web_buffer_snprintf(w->data, 65536,
                        "%s({version:'%s',reqId:'%s',status:'ok',sig:'%lu',table:",
                        google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
        }
@@ -475,11 +470,11 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
 
        if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
                if(timestamp_in_data > last_timestamp_in_data)
-                       w->data->bytes += snprintf(&w->data->buffer[w->data->bytes], w->data->size - w->data->bytes, "});");
+                       web_buffer_strcat(w->data, "});");
 
                else {
                        // the client already has the latest data
-                       w->data->bytes = snprintf(w->data->buffer, w->data->size,
+                       web_buffer_snprintf(w->data, 65536,
                                "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
                                google_responseHandler, google_version, google_reqId);
                }
@@ -549,7 +544,7 @@ void web_client_process(struct web_client *w) {
                global_statistics_unlock();
 
                gettimeofday(&w->tv_in, NULL);
-               debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
+               debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->len, w->data->buffer);
 
                // check if the client requested keep-alive HTTP
                if(strcasestr(w->data->buffer, "Connection: keep-alive")) w->keepalive = 1;
@@ -614,19 +609,19 @@ void web_client_process(struct web_client *w) {
                                if(!st) {
                                        // we don't have it
                                        // try to send a file with that name
-                                       w->data->bytes = 0;
+                                       web_buffer_flush(w->data);
                                        code = mysendfile(w, tok);
                                }
                                else {
                                        code = 200;
                                        debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
                                        w->data->contenttype = CT_APPLICATION_JSON;
-                                       w->data->bytes = 0;
+                                       web_buffer_flush(w->data);
                                        rrd_stats_graph_json(st, url, w->data);
                                }
                        }
                        else if(strcmp(tok, "debug") == 0) {
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
 
                                // get the name of the data to show
                                tok = mystrsep(&url, "/?&");
@@ -637,14 +632,14 @@ void web_client_process(struct web_client *w) {
                                if(!st) st = rrdset_find(tok);
                                if(!st) {
                                        code = 404;
-                                       web_buffer_printf(w->data, "Chart %s is not found.\r\n", tok);
+                                       web_buffer_snprintf(w->data, 1024, "Chart %s is not found.\r\n", tok);
                                        debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
                                }
                                else {
                                        code = 200;
                                        debug_flags |= D_RRD_STATS;
                                        st->debug = st->debug?0:1;
-                                       web_buffer_printf(w->data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
+                                       web_buffer_snprintf(w->data, 1024, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
                                        debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
                                }
                        }
@@ -654,9 +649,7 @@ void web_client_process(struct web_client *w) {
                                debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
 
                                // replace the zero bytes with spaces
-                               int i;
-                               for(i = 0; i < w->data->size; i++)
-                                       if(w->data->buffer[i] == '\0') w->data->buffer[i] = ' ';
+                               web_buffer_char_replace(w->data, '\0', ' ');
 
                                // just leave the buffer as is
                                // it will be copied back to the client
@@ -666,18 +659,18 @@ void web_client_process(struct web_client *w) {
 
                                debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
 
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
                                RRDSET *st = rrdset_root;
 
                                for ( ; st ; st = st->next )
-                                       web_buffer_printf(w->data, "%s\n", st->name);
+                                       web_buffer_snprintf(w->data, 1024, "%s\n", st->name);
                        }
                        else if(strcmp(tok, "all.json") == 0) {
                                code = 200;
                                debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
 
                                w->data->contenttype = CT_APPLICATION_JSON;
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
                                rrd_stats_all_json(w->data);
                        }
                        else if(strcmp(tok, "netdata.conf") == 0) {
@@ -685,7 +678,7 @@ void web_client_process(struct web_client *w) {
                                debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
 
                                w->data->contenttype = CT_TEXT_PLAIN;
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
                                generate_config(w->data, 0);
                        }
                        else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
@@ -693,17 +686,16 @@ void web_client_process(struct web_client *w) {
                                if(tok && *tok) code = mysendfile(w, tok);
                                else {
                                        code = 400;
-                                       w->data->bytes = 0;
-                                       strcpy(w->data->buffer, "You have to give a filename to get.\r\n");
-                                       w->data->bytes = strlen(w->data->buffer);
+                                       web_buffer_flush(w->data);
+                                       web_buffer_strcat(w->data, "You have to give a filename to get.\r\n");
                                }
                        }
                        else if(!tok[0]) {
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
                                code = mysendfile(w, "index.html");
                        }
                        else {
-                               w->data->bytes = 0;
+                               web_buffer_flush(w->data);
                                code = mysendfile(w, tok);
                        }
 
@@ -714,23 +706,21 @@ void web_client_process(struct web_client *w) {
                        if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
 
                        code = 500;
-                       w->data->bytes = 0;
-                       strcpy(w->data->buffer, "I don't understand you...\r\n");
-                       w->data->bytes = strlen(w->data->buffer);
+                       web_buffer_flush(w->data);
+                       web_buffer_strcat(w->data, "I don't understand you...\r\n");
                }
 
                // free url_decode() buffer
                if(pointer_to_free) free(pointer_to_free);
        }
-       else if(w->data->bytes > 8192) {
+       else if(w->data->len > 8192) {
                strcpy(w->last_url, "too big request");
 
                debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
 
                code = 400;
-               w->data->bytes = 0;
-               strcpy(w->data->buffer, "Received request is too big.\r\n");
-               w->data->bytes = strlen(w->data->buffer);
+               web_buffer_flush(w->data);
+               web_buffer_strcat(w->data, "Received request is too big.\r\n");
        }
        else {
                // wait for more data
@@ -738,8 +728,8 @@ void web_client_process(struct web_client *w) {
                return;
        }
 
-       if(w->data->bytes > w->data->size) {
-               error("%llu: memory overflow encountered (size is %ld, written %ld).", w->data->size, w->data->bytes);
+       if(w->data->len > w->data->size) {
+               error("%llu: memory overflow encountered (size is %ld, written %ld).", w->data->size, w->data->len);
        }
 
        gettimeofday(&w->tv_ready, NULL);
@@ -875,10 +865,10 @@ void web_client_process(struct web_client *w) {
        }
 
        // if we know the content length, put it
-       if(!w->zoutput && (w->data->bytes || w->data->rbytes))
+       if(!w->zoutput && (w->data->len || w->data->rlen))
                headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
                        "Content-Length: %ld\r\n"
-                       , w->data->bytes?w->data->bytes:w->data->rbytes
+                       , w->data->len?w->data->len:w->data->rlen
                        );
        else if(!w->zoutput)
                w->keepalive = 0;       // content-length is required for keep-alive
@@ -913,18 +903,18 @@ void web_client_process(struct web_client *w) {
        if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0) error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
 
        // enable sending immediately if we have data
-       if(w->data->bytes) w->wait_send = 1;
+       if(w->data->len) w->wait_send = 1;
        else w->wait_send = 0;
 
        // pretty logging
        switch(w->mode) {
                case WEB_CLIENT_MODE_NORMAL:
-                       debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%d bytes) to client.", w->id, w->data->bytes);
+                       debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%d bytes) to client.", w->id, w->data->len);
                        break;
 
                case WEB_CLIENT_MODE_FILECOPY:
-                       if(w->data->rbytes) {
-                               debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %d bytes to client.", w->id, w->data->rbytes);
+                       if(w->data->rlen) {
+                               debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %d bytes to client.", w->id, w->data->rlen);
                                w->wait_receive = 1;
 
                                /*
@@ -991,14 +981,14 @@ long web_client_send_chunk_finalize(struct web_client *w)
 #ifdef NETDATA_WITH_ZLIB
 long web_client_send_deflate(struct web_client *w)
 {
-       long bytes = 0, t = 0;
+       long len = 0, t = 0;
 
        // when using compression,
        // w->data->sent is the amount of bytes passed through compression
 
        // debug(D_DEFLATE, "%llu: TEST w->data->bytes = %d, w->data->sent = %d, w->zhave = %d, w->zsent = %d, w->zstream.avail_in = %d, w->zstream.avail_out = %d, w->zstream.total_in = %d, w->zstream.total_out = %d.", w->id, w->data->bytes, w->data->sent, w->zhave, w->zsent, w->zstream.avail_in, w->zstream.avail_out, w->zstream.total_in, w->zstream.total_out);
 
-       if(w->data->bytes - w->data->sent == 0 && w->zstream.avail_in == 0 && w->zhave == w->zsent && w->zstream.avail_out != 0) {
+       if(w->data->len - w->data->sent == 0 && w->zstream.avail_in == 0 && w->zhave == w->zsent && w->zstream.avail_out != 0) {
                // there is nothing to send
 
                debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
@@ -1011,7 +1001,7 @@ long web_client_send_deflate(struct web_client *w)
                // A. we have done everything
                // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
 
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rbytes && w->data->rbytes > w->data->bytes) {
+               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rlen && w->data->rlen > w->data->len) {
                        // we have to wait, more data will come
                        debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
                        w->wait_send = 0;
@@ -1036,12 +1026,12 @@ long web_client_send_deflate(struct web_client *w)
                // close the previous open chunk
                if(w->data->sent != 0) t += web_client_send_chunk_close(w);
 
-               debug(D_DEFLATE, "%llu: Compressing %d bytes starting from %d.", w->id, (w->data->bytes - w->data->sent), w->data->sent);
+               debug(D_DEFLATE, "%llu: Compressing %d bytes starting from %d.", w->id, (w->data->len - w->data->sent), w->data->sent);
 
                // give the compressor all the data not passed through the compressor yet
-               if(w->data->bytes > w->data->sent) {
+               if(w->data->len > w->data->sent) {
                        w->zstream.next_in = (Bytef *)&w->data->buffer[w->data->sent];
-                       w->zstream.avail_in = (w->data->bytes - w->data->sent);
+                       w->zstream.avail_in = (w->data->len - w->data->sent);
                }
 
                // reset the compressor output buffer
@@ -1051,7 +1041,7 @@ long web_client_send_deflate(struct web_client *w)
                // ask for FINISH if we have all the input
                int flush = Z_SYNC_FLUSH;
                if(w->mode == WEB_CLIENT_MODE_NORMAL
-                       || (w->mode == WEB_CLIENT_MODE_FILECOPY && w->data->bytes == w->data->rbytes)) {
+                       || (w->mode == WEB_CLIENT_MODE_FILECOPY && w->data->len == w->data->rlen)) {
                        flush = Z_FINISH;
                        debug(D_DEFLATE, "%llu: Requesting Z_FINISH.", w->id);
                }
@@ -1070,7 +1060,7 @@ long web_client_send_deflate(struct web_client *w)
                w->zsent = 0;
 
                // keep track of the bytes passed through the compressor
-               w->data->sent = w->data->bytes;
+               w->data->sent = w->data->len;
 
                debug(D_DEFLATE, "%llu: Compression produced %d bytes.", w->id, w->zhave);
 
@@ -1078,16 +1068,16 @@ long web_client_send_deflate(struct web_client *w)
                t += web_client_send_chunk_header(w, w->zhave);
        }
 
-       bytes = send(w->ofd, &w->zbuffer[w->zsent], w->zhave - w->zsent, MSG_DONTWAIT);
-       if(bytes > 0) {
-               w->zsent += bytes;
-               if(t > 0) bytes += t;
-               debug(D_WEB_CLIENT, "%llu: Sent %d bytes.", w->id, bytes);
+       len = send(w->ofd, &w->zbuffer[w->zsent], w->zhave - w->zsent, MSG_DONTWAIT);
+       if(len > 0) {
+               w->zsent += len;
+               if(t > 0) len += t;
+               debug(D_WEB_CLIENT, "%llu: Sent %d bytes.", w->id, len);
        }
-       else if(bytes == 0) debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
+       else if(len == 0) debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
        else debug(D_WEB_CLIENT, "%llu: Failed to send data to client. Reason: %s", w->id, strerror(errno));
 
-       return(bytes);
+       return(len);
 }
 #endif // NETDATA_WITH_ZLIB
 
@@ -1099,7 +1089,7 @@ long web_client_send(struct web_client *w)
 
        long bytes;
 
-       if(unlikely(w->data->bytes - w->data->sent == 0)) {
+       if(unlikely(w->data->len - w->data->sent == 0)) {
                // there is nothing to send
 
                debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
@@ -1108,7 +1098,7 @@ long web_client_send(struct web_client *w)
                // A. we have done everything
                // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
 
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rbytes && w->data->rbytes > w->data->bytes) {
+               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rlen && w->data->rlen > w->data->len) {
                        // we have to wait, more data will come
                        debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
                        w->wait_send = 0;
@@ -1126,7 +1116,7 @@ long web_client_send(struct web_client *w)
                return(0);
        }
 
-       bytes = send(w->ofd, &w->data->buffer[w->data->sent], w->data->bytes - w->data->sent, MSG_DONTWAIT);
+       bytes = send(w->ofd, &w->data->buffer[w->data->sent], w->data->len - w->data->sent, MSG_DONTWAIT);
        if(likely(bytes > 0)) {
                w->data->sent += bytes;
                debug(D_WEB_CLIENT, "%llu: Sent %d bytes.", w->id, bytes);
@@ -1140,27 +1130,27 @@ long web_client_send(struct web_client *w)
 long web_client_receive(struct web_client *w)
 {
        // do we have any space for more data?
-       web_buffer_increase(w->data, WEB_DATA_LENGTH_INCREASE_STEP);
+       web_buffer_need_bytes(w->data, WEB_DATA_LENGTH_INCREASE_STEP);
 
-       long left = w->data->size - w->data->bytes;
+       long left = w->data->size - w->data->len;
        long bytes;
 
        if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
-               bytes = read(w->ifd, &w->data->buffer[w->data->bytes], (left-1));
+               bytes = read(w->ifd, &w->data->buffer[w->data->len], (left-1));
        else
-               bytes = recv(w->ifd, &w->data->buffer[w->data->bytes], left-1, MSG_DONTWAIT);
+               bytes = recv(w->ifd, &w->data->buffer[w->data->len], left-1, MSG_DONTWAIT);
 
        if(likely(bytes > 0)) {
-               int old = w->data->bytes;
-               w->data->bytes += bytes;
-               w->data->buffer[w->data->bytes] = '\0';
+               int old = w->data->len;
+               w->data->len += bytes;
+               w->data->buffer[w->data->len] = '\0';
 
                debug(D_WEB_CLIENT, "%llu: Received %d bytes.", w->id, bytes);
                debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->data->buffer[old]);
 
                if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
                        w->wait_send = 1;
-                       if(w->data->rbytes && w->data->bytes >= w->data->rbytes) w->wait_receive = 0;
+                       if(w->data->rlen && w->data->len >= w->data->rlen) w->wait_receive = 0;
                }
        }
        else if(likely(bytes == 0)) {