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
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"
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;
}
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);
}
}
}
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"
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"
);
}
- web_buffer_printf(wb,
+ web_buffer_snprintf(wb, 200,
"\t\t\t],\n"
"\t\t\t\"memory\" : %lu\n"
"\t\t}"
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"
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;
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;
}
// -------------------------------------------------------------------------
// 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
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);
// -------------------------------------------------------------------------
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;
}
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]++;
}
// 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++;
}
}
- 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;
}
}
- 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;
#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...
// 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';
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)
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;
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
};
#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);
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 */
// 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;
}
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;
}
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;
}
}
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;
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'",
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;
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));
}
}
w->data->contenttype = CT_APPLICATION_JSON;
- w->data->bytes = 0;
+ web_buffer_flush(w->data);
char *google_version = "0.6";
char *google_reqId = "0";
// 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;
}
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);
}
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);
}
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;
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, "/?&");
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");
}
}
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
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) {
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"
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);
}
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
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);
}
// 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
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;
/*
#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);
// 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;
// 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
// 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);
}
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);
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
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);
// 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;
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);
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)) {