@cryptotaxi247 / netdata-1 / commits / 17b945890

code cleanup and re-arrangements for better scalability

Costa Tsaousis (ktsaou) committed Nov 28, 2015 at 06:08 UTC 17b945890c89b33a08d0d36d2c60e9193d55831d
9 files changed +533 -401
src/appconfig.c
+8 -8
@@ -353,7 +353,7 @@ int config_set_boolean(const char *section, const char *name, int value)
353 return value;
354 }
355
356 -void generate_config(struct web_buffer *wb, int only_changed)
356 +void generate_config(BUFFER *wb, int only_changed)
357 {
358 int i, pri;
359 struct config *co;
@@ -362,7 +362,7 @@ void generate_config(struct web_buffer *wb, int only_changed)
362 for(i = 0; i < 3 ;i++) {
363 switch(i) {
364 case 0:
365 - web_buffer_strcat(wb,
365 + buffer_strcat(wb,
366 "# NetData Configuration\n"
367 "# You can uncomment and change any of the options below.\n"
368 "# The value shown in the commented settings, is the default value.\n"
@@ -370,11 +370,11 @@ void generate_config(struct web_buffer *wb, int only_changed)
370 break;
371
372 case 1:
373 - web_buffer_strcat(wb, "\n\n# per plugin configuration\n");
373 + buffer_strcat(wb, "\n\n# per plugin configuration\n");
374 break;
375
376 case 2:
377 - web_buffer_strcat(wb, "\n\n# per chart configuration\n");
377 + buffer_strcat(wb, "\n\n# per chart configuration\n");
378 break;
379 }
380
@@ -397,17 +397,17 @@ void generate_config(struct web_buffer *wb, int only_changed)
397 if(only_changed && !changed) continue;
398
399 if(!used) {
400 - web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX+1, "\n# node '%s' is not used.", co->name);
400 + buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
401 }
402
403 - web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX+1, "\n[%s]\n", co->name);
403 + buffer_sprintf(wb, "\n[%s]\n", co->name);
404
405 for(cv = co->values; cv ; cv = cv->next) {
406
407 if(used && !(cv->flags & CONFIG_VALUE_USED)) {
408 - web_buffer_snprintf(wb, CONFIG_FILE_LINE_MAX + 1, "\n\t# option '%s' is not used.\n", cv->name);
408 + buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
409 }
410 - 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);
410 + buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
411 }
412 }
413 }
src/appconfig.h
+1 -1
@@ -20,6 +20,6 @@ extern const char *config_set(const char *section, const char *name, const char
20 extern long long config_set_number(const char *section, const char *name, long long value);
21 extern int config_set_boolean(const char *section, const char *name, int value);
22
23 -extern void generate_config(struct web_buffer *wb, int only_changed);
23 +extern void generate_config(BUFFER *wb, int only_changed);
24
25 #endif /* NETDATA_CONFIG_H */
src/daemon.c
+17 -7
@@ -112,29 +112,39 @@ int become_user(const char *username)
112 {
113 struct passwd *pw = getpwnam(username);
114 if(!pw) {
115 - fprintf(stderr, "User %s is not present. Error: %s\n", username, strerror(errno));
115 + error("User %s is not present. Error: %s\n", username, strerror(errno));
116 return -1;
117 }
118
119 if(chown(rundir, pw->pw_uid, pw->pw_gid) != 0) {
120 - fprintf(stderr, "Cannot chown directory '%s' to user %s. Error: %s\n", rundir, username, strerror(errno));
120 + error("Cannot chown directory '%s' to user %s. Error: %s\n", rundir, username, strerror(errno));
121 + return -1;
122 + }
123 +
124 + if(setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
125 + error("Cannot switch to user's %s group (gid: %d). Error: %s\n", username, pw->pw_gid, strerror(errno));
126 + return -1;
127 + }
128 +
129 + if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
130 + error("Cannot switch to user %s (uid: %d). Error: %s\n", username, pw->pw_uid, strerror(errno));
131 return -1;
132 }
133
134 if(setgid(pw->pw_gid) != 0) {
125 - fprintf(stderr, "Cannot switch to user's %s group (gid: %d). Error: %s\n", username, pw->pw_gid, strerror(errno));
135 + error("Cannot switch to user's %s group (gid: %d). Error: %s\n", username, pw->pw_gid, strerror(errno));
136 return -1;
137 }
138 if(setegid(pw->pw_gid) != 0) {
129 - fprintf(stderr, "Cannot effectively switch to user's %s group (gid: %d). Error: %s\n", username, pw->pw_gid, strerror(errno));
139 + error("Cannot effectively switch to user's %s group (gid: %d). Error: %s\n", username, pw->pw_gid, strerror(errno));
140 return -1;
141 }
142 if(setuid(pw->pw_uid) != 0) {
133 - fprintf(stderr, "Cannot switch to user %s (uid: %d). Error: %s\n", username, pw->pw_uid, strerror(errno));
143 + error("Cannot switch to user %s (uid: %d). Error: %s\n", username, pw->pw_uid, strerror(errno));
144 return -1;
145 }
146 if(seteuid(pw->pw_uid) != 0) {
137 - fprintf(stderr, "Cannot effectively switch to user %s (uid: %d). Error: %s\n", username, pw->pw_uid, strerror(errno));
147 + error("Cannot effectively switch to user %s (uid: %d). Error: %s\n", username, pw->pw_uid, strerror(errno));
148 return -1;
149 }
150
@@ -319,7 +329,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
329 if(become_user(user) != 0) {
330 error("Cannot become user '%s'. Continuing as we are.", user);
331 }
322 - else debug(D_OPTIONS, "Successfully became user '%s'.", user);
332 + else info("Successfully became user '%s'.", user);
333 }
334
335 return(0);
src/rrd2json.c
+49 -49
@@ -12,13 +12,13 @@
12 #define HOSTNAME_MAX 1024
13 char *hostname = "unknown";
14
15 -void rrd_stats_api_v1_chart(RRDSET *st, struct web_buffer *wb)
15 +void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
16 {
17 time_t now = time(NULL);
18
19 pthread_rwlock_rdlock(&st->rwlock);
20
21 - web_buffer_snprintf(wb, 65536,
21 + buffer_sprintf(wb,
22 "\t\t{\n"
23 "\t\t\t\"id\": \"%s\",\n"
24 "\t\t\t\"name\": \"%s\",\n"
@@ -60,7 +60,7 @@ void rrd_stats_api_v1_chart(RRDSET *st, struct web_buffer *wb)
60
61 memory += rd->memsize;
62
63 - web_buffer_snprintf(wb, 4096,
63 + buffer_sprintf(wb,
64 "%s"
65 "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
66 , c?",\n":""
@@ -71,7 +71,7 @@ void rrd_stats_api_v1_chart(RRDSET *st, struct web_buffer *wb)
71 c++;
72 }
73
74 - web_buffer_snprintf(wb, 200,
74 + buffer_sprintf(wb,
75 "\n\t\t\t}\n"
76 "\t\t}"
77 );
@@ -79,12 +79,12 @@ void rrd_stats_api_v1_chart(RRDSET *st, struct web_buffer *wb)
79 pthread_rwlock_unlock(&st->rwlock);
80 }
81
82 -void rrd_stats_api_v1_charts(struct web_buffer *wb)
82 +void rrd_stats_api_v1_charts(BUFFER *wb)
83 {
84 long c;
85 RRDSET *st;
86
87 - web_buffer_snprintf(wb, 4096, "{\n"
87 + buffer_sprintf(wb, "{\n"
88 "\t\"hostname\": \"%s\""
89 ",\n\t\"update_every\": %d"
90 ",\n\t\"history\": %d"
@@ -97,27 +97,27 @@ void rrd_stats_api_v1_charts(struct web_buffer *wb)
97 pthread_rwlock_rdlock(&rrdset_root_rwlock);
98 for(st = rrdset_root, c = 0; st ; st = st->next) {
99 if(st->enabled) {
100 - if(c) web_buffer_strcat(wb, ",");
101 - web_buffer_strcat(wb, "\n\t\t\"");
102 - web_buffer_strcat(wb, st->id);
103 - web_buffer_strcat(wb, "\": ");
100 + if(c) buffer_strcat(wb, ",");
101 + buffer_strcat(wb, "\n\t\t\"");
102 + buffer_strcat(wb, st->id);
103 + buffer_strcat(wb, "\": ");
104 rrd_stats_api_v1_chart(st, wb);
105 c++;
106 }
107 }
108 pthread_rwlock_unlock(&rrdset_root_rwlock);
109
110 - web_buffer_strcat(wb, "\n\t}\n}\n");
110 + buffer_strcat(wb, "\n\t}\n}\n");
111 }
112
113
114 -unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *wb)
114 +unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
115 {
116 time_t now = time(NULL);
117
118 pthread_rwlock_rdlock(&st->rwlock);
119
120 - web_buffer_snprintf(wb, 65536,
120 + buffer_sprintf(wb,
121 "\t\t{\n"
122 "\t\t\t\"id\": \"%s\",\n"
123 "\t\t\t\"name\": \"%s\",\n"
@@ -171,7 +171,7 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
171
172 memory += rd->memsize;
173
174 - web_buffer_snprintf(wb, 4096,
174 + buffer_sprintf(wb,
175 "\t\t\t\t{\n"
176 "\t\t\t\t\t\"id\": \"%s\",\n"
177 "\t\t\t\t\t\"name\": \"%s\",\n"
@@ -204,7 +204,7 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
204 );
205 }
206
207 - web_buffer_snprintf(wb, 200,
207 + buffer_sprintf(wb,
208 "\t\t\t],\n"
209 "\t\t\t\"memory\" : %lu\n"
210 "\t\t}"
@@ -218,32 +218,32 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *w
218 #define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
219 #define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
220
221 -void rrd_stats_graph_json(RRDSET *st, char *options, struct web_buffer *wb)
221 +void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb)
222 {
223 - web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_HEADER), RRD_GRAPH_JSON_HEADER);
223 + buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
224 rrd_stats_one_json(st, options, wb);
225 - web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_FOOTER), RRD_GRAPH_JSON_FOOTER);
225 + buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
226 }
227
228 -void rrd_stats_all_json(struct web_buffer *wb)
228 +void rrd_stats_all_json(BUFFER *wb)
229 {
230 unsigned long memory = 0;
231 long c;
232 RRDSET *st;
233
234 - web_buffer_snprintf(wb, sizeof(RRD_GRAPH_JSON_HEADER), RRD_GRAPH_JSON_HEADER);
234 + buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
235
236 pthread_rwlock_rdlock(&rrdset_root_rwlock);
237 for(st = rrdset_root, c = 0; st ; st = st->next) {
238 if(st->enabled) {
239 - if(c) web_buffer_strcat(wb, ",\n");
239 + if(c) buffer_strcat(wb, ",\n");
240 memory += rrd_stats_one_json(st, NULL, wb);
241 c++;
242 }
243 }
244 pthread_rwlock_unlock(&rrdset_root_rwlock);
245
246 - web_buffer_snprintf(wb, 4096, "\n\t],\n"
246 + buffer_sprintf(wb, "\n\t],\n"
247 "\t\"hostname\": \"%s\",\n"
248 "\t\"update_every\": %d,\n"
249 "\t\"history\": %d,\n"
@@ -668,7 +668,7 @@ RRDR *rrd2rrdr(RRDSET *st, long points, time_t after, time_t before, int group_m
668 return NULL;
669 }
670
671 -unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int points, int group, int group_method, time_t after, time_t before, int only_non_zero)
671 +unsigned long rrd_stats_json(int type, RRDSET *st, BUFFER *wb, int points, int group, int group_method, time_t after, time_t before, int only_non_zero)
672 {
673 int c;
674 pthread_rwlock_rdlock(&st->rwlock);
@@ -716,7 +716,7 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
716 for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
717 if(!dimensions) {
718 pthread_rwlock_unlock(&st->rwlock);
719 - web_buffer_strcat(wb, "No dimensions yet.");
719 + buffer_strcat(wb, "No dimensions yet.");
720 return 0;
721 }
722
@@ -788,10 +788,10 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
788 // -------------------------------------------------------------------------
789 // print the JSON header
790
791 - web_buffer_snprintf(wb, 1024, "{\n %scols%s:\n [\n", kq, kq);
792 - 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);
793 - 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);
794 - 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);
791 + buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
792 + buffer_sprintf(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);
793 + buffer_sprintf(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);
794 + buffer_sprintf(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);
795
796 // print the header for each dimension
797 // and update the print_hidden array for the dimensions that should be hidden
@@ -799,15 +799,15 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
799 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
800 if(!print_hidden[c]) {
801 pc++;
802 - 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);
802 + buffer_sprintf(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);
803 }
804 }
805 if(!pc) {
806 - 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);
806 + buffer_sprintf(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);
807 }
808
809 // print the begin of row data
810 - web_buffer_snprintf(wb, 1024, "\n ],\n %srows%s:\n [\n", kq, kq);
810 + buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
811
812
813 // -------------------------------------------------------------------------
@@ -884,10 +884,10 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
884 if(!tm) { error("localtime() failed."); continue; }
885 if(now > last_timestamp) last_timestamp = now;
886
887 - if(printed) web_buffer_strcat(wb, "]},\n");
888 - web_buffer_strcat(wb, pre_date);
889 - web_buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
890 - web_buffer_strcat(wb, post_date);
887 + if(printed) buffer_strcat(wb, "]},\n");
888 + buffer_strcat(wb, pre_date);
889 + buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
890 + buffer_strcat(wb, post_date);
891
892 print_this = 1;
893 }
@@ -923,26 +923,26 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
923 if(print_this) {
924 if(annotate_reset) {
925 annotation_count++;
926 - web_buffer_strcat(wb, overflow_annotation);
926 + buffer_strcat(wb, overflow_annotation);
927 annotate_reset = 0;
928 }
929 else
930 - web_buffer_strcat(wb, normal_annotation);
930 + buffer_strcat(wb, normal_annotation);
931
932 pc = 0;
933 for(c = 0 ; c < dimensions ; c++) {
934 if(found_non_existing[c] == group_count) {
935 // all entries are non-existing
936 pc++;
937 - web_buffer_strcat(wb, pre_value);
938 - web_buffer_strcat(wb, "null");
939 - web_buffer_strcat(wb, post_value);
937 + buffer_strcat(wb, pre_value);
938 + buffer_strcat(wb, "null");
939 + buffer_strcat(wb, post_value);
940 }
941 else if(!print_hidden[c]) {
942 pc++;
943 - web_buffer_strcat(wb, pre_value);
944 - web_buffer_rrd_value(wb, group_values[c]);
945 - web_buffer_strcat(wb, post_value);
943 + buffer_strcat(wb, pre_value);
944 + buffer_rrd_value(wb, group_values[c]);
945 + buffer_strcat(wb, post_value);
946
947 if(group_values[c]) found_non_zero[c]++;
948 }
@@ -954,9 +954,9 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
954
955 // if all dimensions are hidden, print a null
956 if(!pc) {
957 - web_buffer_strcat(wb, pre_value);
958 - web_buffer_strcat(wb, "null");
959 - web_buffer_strcat(wb, post_value);
957 + buffer_strcat(wb, pre_value);
958 + buffer_strcat(wb, "null");
959 + buffer_strcat(wb, post_value);
960 }
961
962 printed++;
@@ -964,8 +964,8 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
964 }
965 }
966
967 - if(printed) web_buffer_strcat(wb, "]}");
968 - web_buffer_strcat(wb, "\n ]\n}\n");
967 + if(printed) buffer_strcat(wb, "]}");
968 + buffer_strcat(wb, "\n ]\n}\n");
969
970 if(only_non_zero && max_loop > 1) {
971 int changed = 0;
@@ -979,7 +979,7 @@ unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int po
979 }
980 }
981
982 - if(changed) web_buffer_flush(wb);
982 + if(changed) buffer_flush(wb);
983 else break;
984 }
985 else break;
src/rrd2json.h
+6 -6
@@ -21,15 +21,15 @@ extern char *hostname;
21 #define GROUP_MAX 1
22 #define GROUP_SUM 2
23
24 -extern void rrd_stats_api_v1_chart(RRDSET *st, struct web_buffer *wb);
25 -extern void rrd_stats_api_v1_charts(struct web_buffer *wb);
24 +extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
25 +extern void rrd_stats_api_v1_charts(BUFFER *wb);
26
27 -extern unsigned long rrd_stats_one_json(RRDSET *st, char *options, struct web_buffer *wb);
27 +extern unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb);
28
29 -extern void rrd_stats_graph_json(RRDSET *st, char *options, struct web_buffer *wb);
29 +extern void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb);
30
31 -extern void rrd_stats_all_json(struct web_buffer *wb);
31 +extern void rrd_stats_all_json(BUFFER *wb);
32
33 -extern unsigned long rrd_stats_json(int type, RRDSET *st, struct web_buffer *wb, int entries_to_show, int group, int group_method, time_t after, time_t before, int only_non_zero);
33 +extern unsigned long rrd_stats_json(int type, RRDSET *st, BUFFER *wb, int entries_to_show, int group, int group_method, time_t after, time_t before, int only_non_zero);
34
35 #endif /* NETDATA_RRD2JSON_H */
src/web_buffer.c
+143 -33
@@ -12,17 +12,51 @@
12 #include "web_buffer.h"
13 #include "log.h"
14
15 -void web_buffer_reset(struct web_buffer *wb)
15 +#define BUFFER_OVERFLOW_EOF "EOF"
16 +
17 +static inline void buffer_overflow_init(BUFFER *b)
18 +{
19 + b->buffer[b->size] = '\0';
20 + strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
21 +}
22 +
23 +#define buffer_overflow_check(b) _buffer_overflow_check(b, __FILE__, __FUNCTION__, __LINE__)
24 +
25 +static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line)
26 +{
27 + if(b->len > b->size) {
28 + error("BUFFER: length %ld is above size %ld, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
29 + b->len = b->size;
30 + }
31 +
32 + if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF)) {
33 + error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
34 + buffer_overflow_init(b);
35 + }
36 +}
37 +
38 +
39 +void buffer_reset(BUFFER *wb)
40 {
17 - web_buffer_flush(wb);
41 + buffer_flush(wb);
42
19 - wb->sent = 0;
20 - wb->rlen = 0;
43 wb->contenttype = CT_TEXT_PLAIN;
44 wb->date = 0;
45 +
46 + buffer_overflow_check(wb);
47 }
48
25 -void web_buffer_char_replace(struct web_buffer *wb, char from, char to)
49 +const char *buffer_tostring(BUFFER *wb)
50 +{
51 + buffer_need_bytes(wb, 1);
52 + wb->buffer[wb->len] = '\0';
53 +
54 + buffer_overflow_check(wb);
55 +
56 + return(wb->buffer);
57 +}
58 +
59 +void buffer_char_replace(BUFFER *wb, char from, char to)
60 {
61 char *s = wb->buffer, *end = &wb->buffer[wb->len];
62
@@ -30,64 +64,128 @@ void web_buffer_char_replace(struct web_buffer *wb, char from, char to)
64 if(*s == from) *s = to;
65 s++;
66 }
67 +
68 + buffer_overflow_check(wb);
69 }
70
71
36 -void web_buffer_strcat(struct web_buffer *wb, const char *txt)
72 +void buffer_strcat(BUFFER *wb, const char *txt)
73 {
38 - char *buffer = wb->buffer;
39 - const char *s = txt;
40 - long bytes = wb->len, size = wb->size;
74 + if(wb->size - wb->len < 512)
75 + buffer_need_bytes(wb, 512);
76
42 - while(*s && bytes < size)
43 - buffer[bytes++] = *s++;
77 + char *s = &wb->buffer[wb->len], *end = &wb->buffer[wb->size];
78 + long len = wb->len;
79
45 - wb->len = bytes;
80 + while(*txt && s != end) {
81 + *s++ = *txt++;
82 + len++;
83 + }
84
47 - if(*s) {
48 - web_buffer_need_bytes(wb, strlen(s));
49 - web_buffer_strcat(wb, s);
85 + wb->len = len;
86 + buffer_overflow_check(wb);
87 +
88 + if(*txt) {
89 + debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %ld, size = %ld\n", wb->len, wb->size);
90 + len = strlen(txt);
91 + buffer_increase(wb, len);
92 + buffer_strcat(wb, txt);
93 }
94 else {
95 // terminate the string
96 // without increasing the length
54 - web_buffer_need_bytes(wb, 1);
97 + buffer_need_bytes(wb, 1);
98 wb->buffer[wb->len] = '\0';
99 }
100 }
101
102
60 -void web_buffer_snprintf(struct web_buffer *wb, size_t len, const char *fmt, ...)
103 +void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...)
104 {
62 - web_buffer_need_bytes(wb, len+1);
105 + buffer_need_bytes(wb, len+1);
106
107 va_list args;
108 va_start(args, fmt);
109 wb->len += vsnprintf(&wb->buffer[wb->len], len+1, fmt, args);
110 va_end(args);
111
112 + buffer_overflow_check(wb);
113 +
114 // the buffer is \0 terminated by vsnprintf
115 }
116
117 +void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args)
118 +{
119 + size_t len = wb->size - wb->len;
120 + if(unlikely(!len)) return;
121 +
122 + wb->len += vsnprintf(&wb->buffer[wb->len], len, fmt, args);
123 +
124 + buffer_overflow_check(wb);
125
73 -void web_buffer_rrd_value(struct web_buffer *wb, calculated_number value)
126 + // the buffer is \0 terminated by vsnprintf
127 +}
128 +
129 +void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
130 +{
131 + if(unlikely(wb->len > wb->size)) {
132 + error("web_buffer_sprintf(): already overflown length %ld, size = %ld", wb->len, wb->size);
133 + }
134 +
135 +// if(wb->size - wb->len < 512)
136 +// web_buffer_need_bytes(wb, 512);
137 +
138 + size_t len = wb->size - wb->len, old_len = wb->len, wrote;
139 +
140 + buffer_need_bytes(wb, len);
141 +
142 + va_list args;
143 + va_start(args, fmt);
144 + wrote = vsnprintf(&wb->buffer[wb->len], len, fmt, args);
145 + va_end(args);
146 +
147 + if(unlikely(wrote >= len)) {
148 + // there is bug in vsnprintf() and it returns
149 + // a number higher to len, but it does not
150 + // overflow the buffer.
151 + // our buffer overflow detector will log it
152 + // if it does.
153 + buffer_overflow_check(wb);
154 +
155 + debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %ld, size = %ld\n", wb->len, wb->size);
156 + buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
157 +
158 + va_start(args, fmt);
159 + buffer_vsprintf(wb, fmt, args);
160 + va_end(args);
161 + }
162 + else
163 + wb->len += wrote;
164 +
165 + // the buffer is \0 terminated by vsnprintf
166 +}
167 +
168 +
169 +void buffer_rrd_value(BUFFER *wb, calculated_number value)
170 {
75 - web_buffer_need_bytes(wb, 50);
171 + buffer_need_bytes(wb, 50);
172 wb->len += print_calculated_number(&wb->buffer[wb->len], value);
173
174 // terminate it
79 - web_buffer_need_bytes(wb, 1);
175 + buffer_need_bytes(wb, 1);
176 wb->buffer[wb->len] = '\0';
177 +
178 + buffer_overflow_check(wb);
179 }
180
181 // generate a javascript date, the fastest possible way...
84 -void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int hours, int minutes, int seconds)
182 +void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
183 {
184 // 10 20 30 = 35
185 // 01234567890123456789012345678901234
186 // Date(2014, 04, 01, 03, 28, 20, 065)
187
90 - web_buffer_need_bytes(wb, 36);
188 + buffer_need_bytes(wb, 36);
189
190 char *b = &wb->buffer[wb->len];
191
@@ -127,44 +225,53 @@ void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int
225 wb->len += i;
226
227 // terminate it
130 - web_buffer_need_bytes(wb, 1);
228 + buffer_need_bytes(wb, 1);
229 wb->buffer[wb->len] = '\0';
230 +
231 + buffer_overflow_check(wb);
232 }
233
134 -struct web_buffer *web_buffer_create(long size)
234 +BUFFER *buffer_create(long size)
235 {
136 - struct web_buffer *b;
236 + BUFFER *b;
237
238 debug(D_WEB_BUFFER, "Creating new web buffer of size %d.", size);
239
140 - b = calloc(1, sizeof(struct web_buffer));
240 + b = calloc(1, sizeof(BUFFER));
241 if(!b) {
242 error("Cannot allocate a web_buffer.");
243 return NULL;
244 }
245
146 - b->buffer = malloc(size);
246 + b->buffer = malloc(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
247 if(!b->buffer) {
148 - error("Cannot allocate a buffer of size %u.", size);
248 + error("Cannot allocate a buffer of size %u.", size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
249 free(b);
250 return NULL;
251 }
252 b->buffer[0] = '\0';
253 b->size = size;
254 b->contenttype = CT_TEXT_PLAIN;
255 + buffer_overflow_init(b);
256 + buffer_overflow_check(b);
257 +
258 return(b);
259 }
260
158 -void web_buffer_free(struct web_buffer *b)
261 +void buffer_free(BUFFER *b)
262 {
263 + buffer_overflow_check(b);
264 +
265 debug(D_WEB_BUFFER, "Freeing web buffer of size %d.", b->size);
266
267 if(b->buffer) free(b->buffer);
268 free(b);
269 }
270
166 -void web_buffer_increase(struct web_buffer *b, long free_size_required)
271 +void buffer_increase(BUFFER *b, long free_size_required)
272 {
273 + buffer_overflow_check(b);
274 +
275 long left = b->size - b->len;
276
277 if(left >= free_size_required) return;
@@ -174,8 +281,11 @@ void web_buffer_increase(struct web_buffer *b, long free_size_required)
281
282 debug(D_WEB_BUFFER, "Increasing data buffer from size %d to %d.", b->size, b->size + increase);
283
177 - b->buffer = realloc(b->buffer, b->size + increase);
178 - if(!b->buffer) fatal("Failed to increase data buffer from size %d to %d.", b->size, b->size + increase);
284 + b->buffer = realloc(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
285 + if(!b->buffer) fatal("Failed to increase data buffer from size %d to %d.", b->size + sizeof(BUFFER_OVERFLOW_EOF) + 2, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
286
287 b->size += increase;
288 +
289 + buffer_overflow_init(b);
290 + buffer_overflow_check(b);
291 }
src/web_buffer.h
+19 -16
@@ -5,17 +5,15 @@
5 #ifndef NETDATA_WEB_BUFFER_H
6 #define NETDATA_WEB_BUFFER_H 1
7
8 -#define WEB_DATA_LENGTH_INCREASE_STEP 65536
8 +#define WEB_DATA_LENGTH_INCREASE_STEP 16384
9
10 -struct web_buffer {
10 +typedef struct web_buffer {
11 long size; // allocation size of buffer
12 long len; // current data length in buffer
13 - long sent; // current data length sent to output
13 char *buffer; // the buffer
14 int contenttype;
16 - long rlen; // if non-zero, the excepted size of ifd
15 time_t date; // the date this content has been generated
18 -};
16 +} BUFFER;
17
18 // content-types
19 #define CT_APPLICATION_JSON 1
@@ -33,22 +31,27 @@ struct web_buffer {
31 #define CT_APPLICATION_VND_MS_FONTOBJ 13
32 #define CT_IMAGE_SVG_XML 14
33
36 -#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)
34 +#define buffer_strlen(wb) ((wb)->len)
35 +extern const char *buffer_tostring(BUFFER *wb);
36
38 -#define web_buffer_flush(wb) wb->buffer[wb->len = 0] = '\0'
39 -void web_buffer_reset(struct web_buffer *wb);
37 +#define buffer_need_bytes(buffer, needed_free_size) do { if(unlikely((buffer)->size - (buffer)->len < (needed_free_size))) buffer_increase((buffer), (needed_free_size)); } while(0)
38
41 -void web_buffer_strcat(struct web_buffer *wb, const char *txt);
42 -void web_buffer_rrd_value(struct web_buffer *wb, calculated_number value);
39 +#define buffer_flush(wb) wb->buffer[wb->len = 0] = '\0'
40 +extern void buffer_reset(BUFFER *wb);
41
44 -void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int hours, int minutes, int seconds);
42 +extern void buffer_strcat(BUFFER *wb, const char *txt);
43 +extern void buffer_rrd_value(BUFFER *wb, calculated_number value);
44
46 -struct web_buffer *web_buffer_create(long size);
47 -void web_buffer_free(struct web_buffer *b);
48 -void web_buffer_increase(struct web_buffer *b, long free_size_required);
45 +extern void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
46
50 -void web_buffer_snprintf(struct web_buffer *wb, size_t len, const char *fmt, ...);
47 +extern BUFFER *buffer_create(long size);
48 +extern void buffer_free(BUFFER *b);
49 +extern void buffer_increase(BUFFER *b, long free_size_required);
50
52 -void web_buffer_char_replace(struct web_buffer *wb, char from, char to);
51 +extern void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...);
52 +extern void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
53 +extern void buffer_sprintf(BUFFER *wb, const char *fmt, ...);
54 +
55 +extern void buffer_char_replace(BUFFER *wb, char from, char to);
56
57 #endif /* NETDATA_WEB_BUFFER_H */
src/web_client.c
+271 -248
@@ -26,7 +26,8 @@
26
27 #include "web_client.h"
28
29 -#define INITIAL_WEB_DATA_LENGTH 65536
29 +#define INITIAL_WEB_DATA_LENGTH 16384
30 +#define WEB_REQUEST_LENGTH 16384
31
32 int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
33 int web_enable_gzip = 1;
@@ -93,14 +94,33 @@ struct web_client *web_client_create(int listener)
94 if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0) error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
95 }
96
96 - w->data = web_buffer_create(INITIAL_WEB_DATA_LENGTH);
97 - if(unlikely(!w->data)) {
97 + w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
98 + if(unlikely(!w->response.data)) {
99 // no need for error log - web_buffer_create already logged the error
100 close(w->ifd);
101 free(w);
102 return NULL;
103 }
104
105 + w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
106 + if(unlikely(!w->response.header)) {
107 + // no need for error log - web_buffer_create already logged the error
108 + buffer_free(w->response.data);
109 + close(w->ifd);
110 + free(w);
111 + return NULL;
112 + }
113 +
114 + w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
115 + if(unlikely(!w->response.header_output)) {
116 + // no need for error log - web_buffer_create already logged the error
117 + buffer_free(w->response.header);
118 + buffer_free(w->response.data);
119 + close(w->ifd);
120 + free(w);
121 + return NULL;
122 + }
123 +
124 w->wait_receive = 1;
125
126 if(web_clients) web_clients->prev = w;
@@ -112,6 +132,69 @@ struct web_client *web_client_create(int listener)
132 return(w);
133 }
134
135 +void web_client_reset(struct web_client *w)
136 +{
137 + struct timeval tv;
138 + gettimeofday(&tv, NULL);
139 +
140 + long sent = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
141 +
142 +#ifdef NETDATA_WITH_ZLIB
143 + if(likely(w->response.zoutput)) sent = (long)w->response.zstream.total_out;
144 +#endif
145 +
146 + long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
147 +
148 + if(likely(w->last_url[0]))
149 + log_access("%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
150 + w->id,
151 + sent, size, -((size>0)?((float)(size-sent)/(float)size * 100.0):0.0),
152 + (float)usecdiff(&w->tv_ready, &w->tv_in) / 1000.0,
153 + (float)usecdiff(&tv, &w->tv_ready) / 1000.0,
154 + (float)usecdiff(&tv, &w->tv_in) / 1000.0,
155 + (w->mode == WEB_CLIENT_MODE_FILECOPY)?"filecopy":"data",
156 + w->last_url
157 + );
158 +
159 + debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
160 +
161 + if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
162 + debug(D_WEB_CLIENT, "%llu: Closing filecopy input file.", w->id);
163 + close(w->ifd);
164 + w->ifd = w->ofd;
165 + }
166 +
167 + w->last_url[0] = '\0';
168 +
169 + w->mode = WEB_CLIENT_MODE_NORMAL;
170 +
171 + buffer_reset(w->response.header_output);
172 + buffer_reset(w->response.header);
173 + buffer_reset(w->response.data);
174 + w->response.rlen = 0;
175 + w->response.sent = 0;
176 +
177 + w->wait_receive = 1;
178 + w->wait_send = 0;
179 +
180 + w->response.zoutput = 0;
181 +
182 + // if we had enabled compression, release it
183 +#ifdef NETDATA_WITH_ZLIB
184 + if(w->response.zinitialized) {
185 + debug(D_DEFLATE, "%llu: Reseting compression.", w->id);
186 + deflateEnd(&w->response.zstream);
187 + w->response.zsent = 0;
188 + w->response.zhave = 0;
189 + w->response.zstream.avail_in = 0;
190 + w->response.zstream.avail_out = 0;
191 + w->response.zstream.total_in = 0;
192 + w->response.zstream.total_out = 0;
193 + w->response.zinitialized = 0;
194 + }
195 +#endif // NETDATA_WITH_ZLIB
196 +}
197 +
198 struct web_client *web_client_free(struct web_client *w)
199 {
200 struct web_client *n = w->next;
@@ -123,7 +206,8 @@ struct web_client *web_client_free(struct web_client *w)
206
207 if(w == web_clients) web_clients = w->next;
208
126 - if(w->data) web_buffer_free(w->data);
209 + if(w->response.header) buffer_free(w->response.header);
210 + if(w->response.data) buffer_free(w->response.data);
211 close(w->ifd);
212 if(w->ofd != w->ifd) close(w->ofd);
213 free(w);
@@ -152,7 +236,7 @@ int mysendfile(struct web_client *w, char *filename)
236 // if the filename contains a / or a .., refuse to serve it
237 if(strchr(filename, '/') != 0 || strstr(filename, "..") != 0) {
238 debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
155 - web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "File '%s' cannot be served. Filenames cannot contain / or ..", filename);
239 + buffer_sprintf(w->response.data, "File '%s' cannot be served. Filenames cannot contain / or ..", filename);
240 return 400;
241 }
242
@@ -164,14 +248,14 @@ int mysendfile(struct web_client *w, char *filename)
248 struct stat stat;
249 if(lstat(webfilename, &stat) != 0) {
250 error("%llu: File '%s' is not found.", w->id, webfilename);
167 - web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "File '%s' does not exist, or is not accessible.", filename);
251 + buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", filename);
252 return 404;
253 }
254
255 // check if the file is owned by us
256 if(stat.st_uid != getuid() && stat.st_uid != geteuid()) {
257 error("%llu: File '%s' is owned by user %d (I run as user %d). Access Denied.", w->id, webfilename, stat.st_uid, getuid());
174 - web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "Access to file '%s' is not permitted.", filename);
258 + buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", filename);
259 return 403;
260 }
261
@@ -182,152 +266,92 @@ int mysendfile(struct web_client *w, char *filename)
266
267 if(errno == EBUSY || errno == EAGAIN) {
268 error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
185 - snprintf(w->response_header, MAX_HTTP_HEADER_SIZE, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
186 - web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "The file '%s' is currently busy. Please try again later.", filename);
269 + buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
270 + buffer_sprintf(w->response.data, "The file '%s' is currently busy. Please try again later.", filename);
271 return 307;
272 }
273 else {
274 error("%llu: Cannot open file '%s'.", w->id, webfilename);
191 - web_buffer_snprintf(w->data, FILENAME_MAX + 1024, "Cannot open file '%s'.", filename);
275 + buffer_sprintf(w->response.data, "Cannot open file '%s'.", filename);
276 return 404;
277 }
278 }
279
280 // pick a Content-Type for the file
197 - if(strstr(filename, ".html") != NULL) w->data->contenttype = CT_TEXT_HTML;
198 - else if(strstr(filename, ".js") != NULL) w->data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
199 - else if(strstr(filename, ".css") != NULL) w->data->contenttype = CT_TEXT_CSS;
200 - else if(strstr(filename, ".xml") != NULL) w->data->contenttype = CT_TEXT_XML;
201 - else if(strstr(filename, ".xsl") != NULL) w->data->contenttype = CT_TEXT_XSL;
202 - else if(strstr(filename, ".txt") != NULL) w->data->contenttype = CT_TEXT_PLAIN;
203 - else if(strstr(filename, ".svg") != NULL) w->data->contenttype = CT_IMAGE_SVG_XML;
204 - else if(strstr(filename, ".ttf") != NULL) w->data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
205 - else if(strstr(filename, ".otf") != NULL) w->data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
206 - else if(strstr(filename, ".woff") != NULL) w->data->contenttype = CT_APPLICATION_FONT_WOFF;
207 - else if(strstr(filename, ".eot") != NULL) w->data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
208 - else w->data->contenttype = CT_APPLICATION_OCTET_STREAM;
281 + if(strstr(filename, ".html") != NULL) w->response.data->contenttype = CT_TEXT_HTML;
282 + else if(strstr(filename, ".js") != NULL) w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
283 + else if(strstr(filename, ".css") != NULL) w->response.data->contenttype = CT_TEXT_CSS;
284 + else if(strstr(filename, ".xml") != NULL) w->response.data->contenttype = CT_TEXT_XML;
285 + else if(strstr(filename, ".xsl") != NULL) w->response.data->contenttype = CT_TEXT_XSL;
286 + else if(strstr(filename, ".txt") != NULL) w->response.data->contenttype = CT_TEXT_PLAIN;
287 + else if(strstr(filename, ".svg") != NULL) w->response.data->contenttype = CT_IMAGE_SVG_XML;
288 + else if(strstr(filename, ".ttf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
289 + else if(strstr(filename, ".otf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
290 + else if(strstr(filename, ".woff") != NULL) w->response.data->contenttype = CT_APPLICATION_FONT_WOFF;
291 + else if(strstr(filename, ".eot") != NULL) w->response.data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
292 + else w->response.data->contenttype = CT_APPLICATION_OCTET_STREAM;
293
294 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
295
296 w->mode = WEB_CLIENT_MODE_FILECOPY;
297 w->wait_receive = 1;
298 w->wait_send = 0;
215 - web_buffer_flush(w->data);
216 - w->data->rlen = stat.st_size;
217 - w->data->date = stat.st_mtim.tv_sec;
299 + buffer_flush(w->response.data);
300 + w->response.rlen = stat.st_size;
301 + w->response.data->date = stat.st_mtim.tv_sec;
302
303 return 200;
304 }
305
222 -void web_client_reset(struct web_client *w)
223 -{
224 - struct timeval tv;
225 - gettimeofday(&tv, NULL);
226 -
227 - long sent = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rlen:w->data->len;
228 -
229 -#ifdef NETDATA_WITH_ZLIB
230 - if(likely(w->zoutput)) sent = (long)w->zstream.total_out;
231 -#endif
232 -
233 - long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rlen:w->data->len;
234 -
235 - if(likely(w->last_url[0]))
236 - log_access("%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
237 - w->id,
238 - sent, size, -((size>0)?((float)(size-sent)/(float)size * 100.0):0.0),
239 - (float)usecdiff(&w->tv_ready, &w->tv_in) / 1000.0,
240 - (float)usecdiff(&tv, &w->tv_ready) / 1000.0,
241 - (float)usecdiff(&tv, &w->tv_in) / 1000.0,
242 - (w->mode == WEB_CLIENT_MODE_FILECOPY)?"filecopy":"data",
243 - w->last_url
244 - );
245 -
246 - debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
247 -
248 - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
249 - debug(D_WEB_CLIENT, "%llu: Closing filecopy input file.", w->id);
250 - close(w->ifd);
251 - w->ifd = w->ofd;
252 - }
253 -
254 - w->last_url[0] = '\0';
255 -
256 - w->mode = WEB_CLIENT_MODE_NORMAL;
257 -
258 - w->response_header[0] = '\0';
259 -
260 - web_buffer_reset(w->data);
261 -
262 - w->wait_receive = 1;
263 - w->wait_send = 0;
264 -
265 - w->zoutput = 0;
266 -
267 - // if we had enabled compression, release it
268 -#ifdef NETDATA_WITH_ZLIB
269 - if(w->zinitialized) {
270 - debug(D_DEFLATE, "%llu: Reseting compression.", w->id);
271 - deflateEnd(&w->zstream);
272 - w->zsent = 0;
273 - w->zhave = 0;
274 - w->zstream.avail_in = 0;
275 - w->zstream.avail_out = 0;
276 - w->zstream.total_in = 0;
277 - w->zstream.total_out = 0;
278 - w->zinitialized = 0;
279 - }
280 -#endif // NETDATA_WITH_ZLIB
281 -}
306
307 #ifdef NETDATA_WITH_ZLIB
308 void web_client_enable_deflate(struct web_client *w) {
285 - if(w->zinitialized == 1) {
309 + if(w->response.zinitialized == 1) {
310 error("%llu: Compression has already be initialized for this client.", w->id);
311 return;
312 }
313
290 - if(w->data->sent) {
314 + if(w->response.sent) {
315 error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
316 return;
317 }
318
295 - w->zstream.zalloc = Z_NULL;
296 - w->zstream.zfree = Z_NULL;
297 - w->zstream.opaque = Z_NULL;
319 + w->response.zstream.zalloc = Z_NULL;
320 + w->response.zstream.zfree = Z_NULL;
321 + w->response.zstream.opaque = Z_NULL;
322
299 - w->zstream.next_in = (Bytef *)w->data->buffer;
300 - w->zstream.avail_in = 0;
301 - w->zstream.total_in = 0;
323 + w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
324 + w->response.zstream.avail_in = 0;
325 + w->response.zstream.total_in = 0;
326
303 - w->zstream.next_out = w->zbuffer;
304 - w->zstream.avail_out = 0;
305 - w->zstream.total_out = 0;
327 + w->response.zstream.next_out = w->response.zbuffer;
328 + w->response.zstream.avail_out = 0;
329 + w->response.zstream.total_out = 0;
330
307 - w->zstream.zalloc = Z_NULL;
308 - w->zstream.zfree = Z_NULL;
309 - w->zstream.opaque = Z_NULL;
331 + w->response.zstream.zalloc = Z_NULL;
332 + w->response.zstream.zfree = Z_NULL;
333 + w->response.zstream.opaque = Z_NULL;
334
311 -// if(deflateInit(&w->zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
335 +// if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
336 // error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
337 // return;
338 // }
339
340 // Select GZIP compression: windowbits = 15 + 16 = 31
317 - if(deflateInit2(&w->zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
341 + if(deflateInit2(&w->response.zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
342 error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
343 return;
344 }
345
322 - w->zsent = 0;
323 - w->zoutput = 1;
324 - w->zinitialized = 1;
346 + w->response.zsent = 0;
347 + w->response.zoutput = 1;
348 + w->response.zinitialized = 1;
349
350 debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
351 }
352 #endif // NETDATA_WITH_ZLIB
353
330 -int rrdset_validate_dimensions(RRDSET *st, struct web_buffer *dimensions)
354 +int rrdset_validate_dimensions(RRDSET *st, BUFFER *dimensions)
355 {
356 ;
357 }
@@ -354,8 +378,8 @@ int web_client_api_request_v1_data_format(char *name)
378
379 int web_client_api_request_v1_charts(struct web_client *w, char *url)
380 {
357 - web_buffer_flush(w->data);
358 - rrd_stats_api_v1_charts(w->data);
381 + buffer_flush(w->response.data);
382 + rrd_stats_api_v1_charts(w->response.data);
383 return 200;
384 }
385
@@ -364,7 +388,7 @@ int web_client_api_request_v1_chart(struct web_client *w, char *url)
388 int ret = 400;
389 char *chart = NULL;
390
367 - web_buffer_flush(w->data);
391 + buffer_flush(w->response.data);
392
393 while(url) {
394 char *value = mystrsep(&url, "?&[]");
@@ -379,26 +403,26 @@ int web_client_api_request_v1_chart(struct web_client *w, char *url)
403
404 if(!strcmp(name, "chart")) chart = value;
405 else {
382 - web_buffer_snprintf(w->data, 1024, "Unknown parameter '%s' in request.", name);
406 + buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
407 goto cleanup;
408 }
409 }
410
411 if(!chart || !*chart) {
388 - web_buffer_snprintf(w->data, 1024, "No chart id is given at the request.");
412 + buffer_sprintf(w->response.data, "No chart id is given at the request.");
413 goto cleanup;
414 }
415
416 RRDSET *st = rrdset_find(chart);
417 if(!st) st = rrdset_find_byname(chart);
418 if(!st) {
395 - web_buffer_snprintf(w->data, 1024, "Chart '%s' is not found.", chart);
419 + buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
420 ret = 404;
421 goto cleanup;
422 }
423
400 - w->data->contenttype = CT_APPLICATION_JSON;
401 - rrd_stats_api_v1_chart(st, w->data);
424 + w->response.data->contenttype = CT_APPLICATION_JSON;
425 + rrd_stats_api_v1_chart(st, w->response.data);
426 return 200;
427
428 cleanup:
@@ -408,9 +432,9 @@ cleanup:
432 int web_client_api_request_v1_data(struct web_client *w, char *url)
433 {
434 int ret = 400;
411 - struct web_buffer *dimensions = NULL;
435 + BUFFER *dimensions = NULL;
436
413 - web_buffer_flush(w->data);
437 + buffer_flush(w->response.data);
438
439 char *chart = NULL
440 , *dim = NULL
@@ -435,10 +459,10 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
459
460 if(!strcmp(name, "chart")) chart = value;
461 else if(!strcmp(name, "dimension") || !strcmp(name, "dim")) {
438 - if(!dimensions) dimensions = web_buffer_create(strlen(value));
462 + if(!dimensions) dimensions = buffer_create(strlen(value));
463 if(dimensions) {
440 - web_buffer_strcat(dimensions, "|");
441 - web_buffer_strcat(dimensions, value);
464 + buffer_strcat(dimensions, "|");
465 + buffer_strcat(dimensions, value);
466 }
467 }
468 else if(!strcmp(name, "after")) after_str = value;
@@ -452,20 +476,20 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
476 options = value;
477 }
478 else {
455 - web_buffer_snprintf(w->data, 1024, "Unknown parameter '%s' in request.", name);
479 + buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
480 goto cleanup;
481 }
482 }
483
484 if(!chart || !*chart) {
461 - web_buffer_snprintf(w->data, 1024, "No chart id is given at the request.");
485 + buffer_sprintf(w->response.data, "No chart id is given at the request.");
486 goto cleanup;
487 }
488
489 RRDSET *st = rrdset_find(chart);
490 if(!st) st = rrdset_find_byname(chart);
491 if(!st) {
468 - web_buffer_snprintf(w->data, 1024, "Chart '%s' is not found.", chart);
492 + buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
493 ret = 404;
494 goto cleanup;
495 }
@@ -475,10 +499,10 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
499 int points = (points_str && *points_str)?atoi(points_str):0;
500 int group = (group_str && *group_str) ?atoi(group_str):0;
501
478 - web_buffer_snprintf(w->data, 1024, "API command 'data' for chart '%s', dimensions '%s', after '%s', before '%s', points '%s', group '%s', format '%s', options '%s'", chart, dim, after_str, before_str, points_str, group_str, format, options);
502 + buffer_sprintf(w->response.data, "API command 'data' for chart '%s', dimensions '%s', after '%s', before '%s', points '%s', group '%s', format '%s', options '%s'", chart, dim, after_str, before_str, points_str, group_str, format, options);
503
504 cleanup:
481 - if(dimensions) web_buffer_free(dimensions);
505 + if(dimensions) buffer_free(dimensions);
506 return ret;
507 }
508
@@ -495,8 +519,8 @@ int web_client_api_request_v1(struct web_client *w, char *url)
519 else if(strcmp(tok, "charts") == 0)
520 return web_client_api_request_v1_charts(w, url);
521
498 - web_buffer_flush(w->data);
499 - web_buffer_snprintf(w->data, 1024, "Unsupported v1 API command: %s", tok);
522 + buffer_flush(w->response.data);
523 + buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
524 return 404;
525 }
526
@@ -509,8 +533,8 @@ int web_client_api_request(struct web_client *w, char *url)
533 if(strcmp(tok, "v1") == 0)
534 return web_client_api_request_v1(w, url);
535
512 - web_buffer_flush(w->data);
513 - web_buffer_snprintf(w->data, 1024, "Unsupported API version: %s", tok);
536 + buffer_flush(w->response.data);
537 + buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
538 return 404;
539 }
540
@@ -532,7 +556,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
556 if(!st) {
557 // we don't have it
558 // try to send a file with that name
535 - web_buffer_flush(w->data);
559 + buffer_flush(w->response.data);
560 return(mysendfile(w, tok));
561 }
562
@@ -585,8 +609,8 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
609 if(tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
610 }
611
588 - w->data->contenttype = CT_APPLICATION_JSON;
589 - web_buffer_flush(w->data);
612 + w->response.data->contenttype = CT_APPLICATION_JSON;
613 + buffer_flush(w->response.data);
614
615 char *google_version = "0.6";
616 char *google_reqId = "0";
@@ -597,7 +621,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
621 unsigned long last_timestamp_in_data = 0;
622 if(datasource_type == DATASOURCE_GOOGLE_JSON || datasource_type == DATASOURCE_GOOGLE_JSONP) {
623
600 - w->data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
624 + w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
625
626 while(args) {
627 tok = mystrsep(&args, "&");
@@ -638,7 +662,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
662
663 // check the client wants json
664 if(strcmp(google_out, "json") != 0) {
641 - web_buffer_snprintf(w->data, 65536,
665 + buffer_sprintf(w->response.data,
666 "%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.'}]});",
667 google_responseHandler, google_version, google_reqId, google_out);
668 return 200;
@@ -647,21 +671,21 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
671 }
672
673 if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
650 - web_buffer_snprintf(w->data, 65536,
674 + buffer_sprintf(w->response.data,
675 "%s({version:'%s',reqId:'%s',status:'ok',sig:'%lu',table:",
676 google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
677 }
678
679 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %lu after, %lu before).", w->id, st->name, st->id, lines, group_count, group_method, after, before);
656 - unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method, after, before, nonzero);
680 + unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, after, before, nonzero);
681
682 if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
683 if(timestamp_in_data > last_timestamp_in_data)
660 - web_buffer_strcat(w->data, "});");
684 + buffer_strcat(w->response.data, "});");
685
686 else {
687 // the client already has the latest data
664 - web_buffer_snprintf(w->data, 65536,
688 + buffer_sprintf(w->response.data,
689 "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
690 google_responseHandler, google_version, google_reqId);
691 }
@@ -682,9 +706,9 @@ int web_client_parse_request(struct web_client *w) {
706
707 web_client_clean_request(w);
708
685 - debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
709 + debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->response.data->bytes, w->response.data->buffer);
710
687 - char *buf = w->data->buffer;
711 + char *buf = w->response.data->buffer;
712 char *line, *tok;
713
714 // ------------------------------------------------------------------------
@@ -725,29 +749,29 @@ void web_client_process(struct web_client *w) {
749 w->wait_receive = 0;
750
751 // check if we have an empty line (end of HTTP header)
728 - if(strstr(w->data->buffer, "\r\n\r\n")) {
752 + if(strstr(w->response.data->buffer, "\r\n\r\n")) {
753 global_statistics_lock();
754 global_statistics.web_requests++;
755 global_statistics_unlock();
756
757 gettimeofday(&w->tv_in, NULL);
734 - debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->len, w->data->buffer);
758 + debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->response.data->len, w->response.data->buffer);
759
760 // check if the client requested keep-alive HTTP
737 - if(strcasestr(w->data->buffer, "Connection: keep-alive")) w->keepalive = 1;
761 + if(strcasestr(w->response.data->buffer, "Connection: keep-alive")) w->keepalive = 1;
762 else w->keepalive = 0;
763
764 #ifdef NETDATA_WITH_ZLIB
765 // check if the client accepts deflate
742 - if(web_enable_gzip && strstr(w->data->buffer, "gzip"))
766 + if(web_enable_gzip && strstr(w->response.data->buffer, "gzip"))
767 web_client_enable_deflate(w);
768 #endif // NETDATA_WITH_ZLIB
769
770 int datasource_type = DATASOURCE_GOOGLE_JSONP;
747 - //if(strstr(w->data->buffer, "X-DataSource-Auth"))
771 + //if(strstr(w->response.data->buffer, "X-DataSource-Auth"))
772 // datasource_type = DATASOURCE_GOOGLE_JSON;
773
750 - char *buf = w->data->buffer;
774 + char *buf = w->response.data->buffer;
775 char *tok = strsep(&buf, " \r\n");
776 char *url = NULL;
777 char *pointer_to_free = NULL; // keep url_decode() allocated buffer
@@ -801,19 +825,19 @@ void web_client_process(struct web_client *w) {
825 if(!st) {
826 // we don't have it
827 // try to send a file with that name
804 - web_buffer_flush(w->data);
828 + buffer_flush(w->response.data);
829 code = mysendfile(w, tok);
830 }
831 else {
832 code = 200;
833 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
810 - w->data->contenttype = CT_APPLICATION_JSON;
811 - web_buffer_flush(w->data);
812 - rrd_stats_graph_json(st, url, w->data);
834 + w->response.data->contenttype = CT_APPLICATION_JSON;
835 + buffer_flush(w->response.data);
836 + rrd_stats_graph_json(st, url, w->response.data);
837 }
838 }
839 else if(strcmp(tok, "debug") == 0) {
816 - web_buffer_flush(w->data);
840 + buffer_flush(w->response.data);
841
842 // get the name of the data to show
843 tok = mystrsep(&url, "/?&");
@@ -824,14 +848,14 @@ void web_client_process(struct web_client *w) {
848 if(!st) st = rrdset_find(tok);
849 if(!st) {
850 code = 404;
827 - web_buffer_snprintf(w->data, 1024, "Chart %s is not found.\r\n", tok);
851 + buffer_sprintf(w->response.data, "Chart %s is not found.\r\n", tok);
852 debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
853 }
854 else {
855 code = 200;
856 debug_flags |= D_RRD_STATS;
857 st->debug = st->debug?0:1;
834 - web_buffer_snprintf(w->data, 1024, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
858 + buffer_sprintf(w->response.data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
859 debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
860 }
861 }
@@ -841,7 +865,7 @@ void web_client_process(struct web_client *w) {
865 debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
866
867 // replace the zero bytes with spaces
844 - web_buffer_char_replace(w->data, '\0', ' ');
868 + buffer_char_replace(w->response.data, '\0', ' ');
869
870 // just leave the buffer as is
871 // it will be copied back to the client
@@ -851,43 +875,43 @@ void web_client_process(struct web_client *w) {
875
876 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
877
854 - web_buffer_flush(w->data);
878 + buffer_flush(w->response.data);
879 RRDSET *st = rrdset_root;
880
881 for ( ; st ; st = st->next )
858 - web_buffer_snprintf(w->data, 1024, "%s\n", st->name);
882 + buffer_sprintf(w->response.data, "%s\n", st->name);
883 }
884 else if(strcmp(tok, "all.json") == 0) {
885 code = 200;
886 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
887
864 - w->data->contenttype = CT_APPLICATION_JSON;
865 - web_buffer_flush(w->data);
866 - rrd_stats_all_json(w->data);
888 + w->response.data->contenttype = CT_APPLICATION_JSON;
889 + buffer_flush(w->response.data);
890 + rrd_stats_all_json(w->response.data);
891 }
892 else if(strcmp(tok, "netdata.conf") == 0) {
893 code = 200;
894 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
895
872 - w->data->contenttype = CT_TEXT_PLAIN;
873 - web_buffer_flush(w->data);
874 - generate_config(w->data, 0);
896 + w->response.data->contenttype = CT_TEXT_PLAIN;
897 + buffer_flush(w->response.data);
898 + generate_config(w->response.data, 0);
899 }
900 else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
901 tok = mystrsep(&url, "/?&");
902 if(tok && *tok) code = mysendfile(w, tok);
903 else {
904 code = 400;
881 - web_buffer_flush(w->data);
882 - web_buffer_strcat(w->data, "You have to give a filename to get.\r\n");
905 + buffer_flush(w->response.data);
906 + buffer_strcat(w->response.data, "You have to give a filename to get.\r\n");
907 }
908 }
909 else if(!tok[0]) {
886 - web_buffer_flush(w->data);
910 + buffer_flush(w->response.data);
911 code = mysendfile(w, "index.html");
912 }
913 else {
890 - web_buffer_flush(w->data);
914 + buffer_flush(w->response.data);
915 code = mysendfile(w, tok);
916 }
917
@@ -898,21 +922,21 @@ void web_client_process(struct web_client *w) {
922 if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
923
924 code = 500;
901 - web_buffer_flush(w->data);
902 - web_buffer_strcat(w->data, "I don't understand you...\r\n");
925 + buffer_flush(w->response.data);
926 + buffer_strcat(w->response.data, "I don't understand you...\r\n");
927 }
928
929 // free url_decode() buffer
930 if(pointer_to_free) free(pointer_to_free);
931 }
908 - else if(w->data->len > 8192) {
932 + else if(w->response.data->len > 8192) {
933 strcpy(w->last_url, "too big request");
934
935 debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
936
937 code = 400;
914 - web_buffer_flush(w->data);
915 - web_buffer_strcat(w->data, "Received request is too big.\r\n");
938 + buffer_flush(w->response.data);
939 + buffer_strcat(w->response.data, "Received request is too big.\r\n");
940 }
941 else {
942 // wait for more data
@@ -920,19 +944,19 @@ void web_client_process(struct web_client *w) {
944 return;
945 }
946
923 - if(w->data->len > w->data->size) {
924 - error("%llu: memory overflow encountered (size is %ld, written %ld).", w->data->size, w->data->len);
947 + if(w->response.data->len > w->response.data->size) {
948 + error("%llu: memory overflow encountered (size is %ld, written %ld).", w->response.data->size, w->response.data->len);
949 }
950
951 gettimeofday(&w->tv_ready, NULL);
928 - w->data->date = time(NULL);
929 - w->data->sent = 0;
952 + w->response.data->date = time(NULL);
953 + w->response.sent = 0;
954
955 // prepare the HTTP response header
956 debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
957
958 char *content_type_string = "";
935 - switch(w->data->contenttype) {
959 + switch(w->response.data->contenttype) {
960 case CT_TEXT_HTML:
961 content_type_string = "text/html; charset=utf-8";
962 break;
@@ -1019,15 +1043,10 @@ void web_client_process(struct web_client *w) {
1043 }
1044
1045 char date[100];
1022 - struct tm tm = *gmtime(&w->data->date);
1046 + struct tm tm = *gmtime(&w->response.data->date);
1047 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", &tm);
1048
1025 - char custom_header[MAX_HTTP_HEADER_SIZE + 1] = "";
1026 - if(w->response_header[0])
1027 - strcpy(custom_header, w->response_header);
1028 -
1029 - int headerlen = 0;
1030 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
1049 + buffer_sprintf(w->response.header_output,
1050 "HTTP/1.1 %d %s\r\n"
1051 "Connection: %s\r\n"
1052 "Server: NetData Embedded HTTP Server\r\n"
@@ -1040,50 +1059,54 @@ void web_client_process(struct web_client *w) {
1059 , date
1060 );
1061
1043 - if(custom_header[0])
1044 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen, "%s", custom_header);
1062 + if(buffer_strlen(w->response.header))
1063 + buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
1064
1065 if(w->mode == WEB_CLIENT_MODE_NORMAL) {
1047 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
1066 + buffer_sprintf(w->response.header_output,
1067 "Expires: %s\r\n"
1068 "Cache-Control: no-cache\r\n"
1050 - , date
1051 - );
1052 - }
1053 - else {
1054 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
1055 - "Cache-Control: public\r\n"
1056 - );
1069 + , date);
1070 }
1071 + else
1072 + buffer_strcat(w->response.header_output, "Cache-Control: public\r\n");
1073
1074 // if we know the content length, put it
1060 - if(!w->zoutput && (w->data->len || w->data->rlen))
1061 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
1075 + if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
1076 + buffer_sprintf(w->response.header_output,
1077 "Content-Length: %ld\r\n"
1063 - , w->data->len?w->data->len:w->data->rlen
1078 + , w->response.data->len?w->response.data->len:w->response.rlen
1079 );
1065 - else if(!w->zoutput)
1080 + else if(!w->response.zoutput)
1081 w->keepalive = 0; // content-length is required for keep-alive
1082
1068 - if(w->zoutput) {
1069 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
1083 + if(w->response.zoutput) {
1084 + buffer_strcat(w->response.header_output,
1085 "Content-Encoding: gzip\r\n"
1086 "Transfer-Encoding: chunked\r\n"
1087 );
1088 }
1089
1075 - headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen, "\r\n");
1090 + buffer_strcat(w->response.header_output, "\r\n");
1091
1092 // disable TCP_NODELAY, to buffer the header
1093 int flag = 0;
1079 - if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0) error("%llu: failed to disable TCP_NODELAY on socket.", w->id);
1094 + if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
1095 + error("%llu: failed to disable TCP_NODELAY on socket.", w->id);
1096
1097 // sent the HTTP header
1082 - debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %d: '%s'", w->id, headerlen, w->response_header);
1098 + debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %d: '%s'"
1099 + , w->id
1100 + , buffer_strlen(w->response.header_output)
1101 + , buffer_tostring(w->response.header_output)
1102 + );
1103
1084 - bytes = send(w->ofd, w->response_header, headerlen, 0);
1085 - if(bytes != headerlen)
1086 - error("%llu: HTTP Header failed to be sent (I sent %d bytes but the system sent %d bytes).", w->id, headerlen, bytes);
1104 + bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
1105 + if(bytes != buffer_strlen(w->response.header_output))
1106 + error("%llu: HTTP Header failed to be sent (I sent %d bytes but the system sent %d bytes)."
1107 + , w->id
1108 + , buffer_strlen(w->response.header_output)
1109 + , bytes);
1110 else {
1111 global_statistics_lock();
1112 global_statistics.bytes_sent += bytes;
@@ -1095,18 +1118,18 @@ void web_client_process(struct web_client *w) {
1118 if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0) error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
1119
1120 // enable sending immediately if we have data
1098 - if(w->data->len) w->wait_send = 1;
1121 + if(w->response.data->len) w->wait_send = 1;
1122 else w->wait_send = 0;
1123
1124 // pretty logging
1125 switch(w->mode) {
1126 case WEB_CLIENT_MODE_NORMAL:
1104 - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%d bytes) to client.", w->id, w->data->len);
1127 + debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%d bytes) to client.", w->id, w->response.data->len);
1128 break;
1129
1130 case WEB_CLIENT_MODE_FILECOPY:
1108 - if(w->data->rlen) {
1109 - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %d bytes to client.", w->id, w->data->rlen);
1131 + if(w->response.rlen) {
1132 + debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %d bytes to client.", w->id, w->response.rlen);
1133 w->wait_receive = 1;
1134
1135 /*
@@ -1114,8 +1137,8 @@ void web_client_process(struct web_client *w) {
1137 // this block of code can be commented, without anything missing.
1138 // when it is commented, the program will copy the data using async I/O.
1139 {
1117 - long len = sendfile(w->ofd, w->ifd, NULL, w->data->rbytes);
1118 - if(len != w->data->rbytes) error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->data->rbytes, len);
1140 + long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
1141 + if(len != w->response.data->rbytes) error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
1142 else web_client_reset(w);
1143 }
1144 */
@@ -1176,24 +1199,24 @@ long web_client_send_deflate(struct web_client *w)
1199 long len = 0, t = 0;
1200
1201 // when using compression,
1179 - // w->data->sent is the amount of bytes passed through compression
1202 + // w->response.sent is the amount of bytes passed through compression
1203
1181 - // 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);
1204 + debug(D_DEFLATE, "%llu: TEST w->response.data->len = %d, w->response.sent = %d, w->response.zhave = %d, w->response.zsent = %d, w->response.zstream.avail_in = %d, w->response.zstream.avail_out = %d, w->response.zstream.total_in = %d, w->response.zstream.total_out = %d.", w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
1205
1183 - if(w->data->len - w->data->sent == 0 && w->zstream.avail_in == 0 && w->zhave == w->zsent && w->zstream.avail_out != 0) {
1206 + if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
1207 // there is nothing to send
1208
1209 debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
1210
1211 // finalize the chunk
1189 - if(w->data->sent != 0)
1212 + if(w->response.sent != 0)
1213 t += web_client_send_chunk_finalize(w);
1214
1215 // there can be two cases for this
1216 // A. we have done everything
1217 // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
1218
1196 - if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rlen && w->data->rlen > w->data->len) {
1219 + if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->response.rlen && w->response.rlen > w->response.data->len) {
1220 // we have to wait, more data will come
1221 debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
1222 w->wait_send = 0;
@@ -1201,7 +1224,7 @@ long web_client_send_deflate(struct web_client *w)
1224 }
1225
1226 if(w->keepalive == 0) {
1204 - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %ld bytes sent.", w->id, w->data->sent);
1227 + debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %ld bytes sent.", w->id, w->response.sent);
1228 errno = 0;
1229 return(-1);
1230 }
@@ -1212,28 +1235,28 @@ long web_client_send_deflate(struct web_client *w)
1235 return(0);
1236 }
1237
1215 - if(w->zstream.avail_out == 0 && w->zhave == w->zsent) {
1238 + if(w->response.zhave == w->response.zsent) {
1239 // compress more input data
1240
1241 // close the previous open chunk
1219 - if(w->data->sent != 0) t += web_client_send_chunk_close(w);
1242 + if(w->response.sent != 0) t += web_client_send_chunk_close(w);
1243
1221 - debug(D_DEFLATE, "%llu: Compressing %d bytes starting from %d.", w->id, (w->data->len - w->data->sent), w->data->sent);
1244 + debug(D_DEFLATE, "%llu: Compressing %d bytes starting from %d.", w->id, (w->response.data->len - w->response.sent), w->response.sent);
1245
1246 // give the compressor all the data not passed through the compressor yet
1224 - if(w->data->len > w->data->sent) {
1225 - w->zstream.next_in = (Bytef *)&w->data->buffer[w->data->sent];
1226 - w->zstream.avail_in = (w->data->len - w->data->sent);
1247 + if(w->response.data->len > w->response.sent) {
1248 + w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent];
1249 + w->response.zstream.avail_in = (w->response.data->len - w->response.sent);
1250 }
1251
1252 // reset the compressor output buffer
1230 - w->zstream.next_out = w->zbuffer;
1231 - w->zstream.avail_out = ZLIB_CHUNK;
1253 + w->response.zstream.next_out = w->response.zbuffer;
1254 + w->response.zstream.avail_out = ZLIB_CHUNK;
1255
1256 // ask for FINISH if we have all the input
1257 int flush = Z_SYNC_FLUSH;
1258 if(w->mode == WEB_CLIENT_MODE_NORMAL
1236 - || (w->mode == WEB_CLIENT_MODE_FILECOPY && w->data->len == w->data->rlen)) {
1259 + || (w->mode == WEB_CLIENT_MODE_FILECOPY && w->response.data->len == w->response.rlen)) {
1260 flush = Z_FINISH;
1261 debug(D_DEFLATE, "%llu: Requesting Z_FINISH.", w->id);
1262 }
@@ -1242,31 +1265,31 @@ long web_client_send_deflate(struct web_client *w)
1265 }
1266
1267 // compress
1245 - if(deflate(&w->zstream, flush) == Z_STREAM_ERROR) {
1268 + if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
1269 error("%llu: Compression failed. Closing down client.", w->id);
1270 web_client_reset(w);
1271 return(-1);
1272 }
1273
1251 - w->zhave = ZLIB_CHUNK - w->zstream.avail_out;
1252 - w->zsent = 0;
1274 + w->response.zhave = ZLIB_CHUNK - w->response.zstream.avail_out;
1275 + w->response.zsent = 0;
1276
1277 // keep track of the bytes passed through the compressor
1255 - w->data->sent = w->data->len;
1278 + w->response.sent = w->response.data->len;
1279
1257 - debug(D_DEFLATE, "%llu: Compression produced %d bytes.", w->id, w->zhave);
1280 + debug(D_DEFLATE, "%llu: Compression produced %d bytes.", w->id, w->response.zhave);
1281
1282 // open a new chunk
1260 - t += web_client_send_chunk_header(w, w->zhave);
1283 + t += web_client_send_chunk_header(w, w->response.zhave);
1284 }
1285
1263 - len = send(w->ofd, &w->zbuffer[w->zsent], w->zhave - w->zsent, MSG_DONTWAIT);
1286 + len = send(w->ofd, &w->response.zbuffer[w->response.zsent], w->response.zhave - w->response.zsent, MSG_DONTWAIT);
1287 if(len > 0) {
1265 - w->zsent += len;
1288 + w->response.zsent += len;
1289 if(t > 0) len += t;
1290 debug(D_WEB_CLIENT, "%llu: Sent %d bytes.", w->id, len);
1291 }
1269 - else if(len == 0) debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
1292 + else if(len == 0) debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %ld, zsent = %ld, need to send = %ld).", w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
1293 else debug(D_WEB_CLIENT, "%llu: Failed to send data to client. Reason: %s", w->id, strerror(errno));
1294
1295 return(len);
@@ -1276,12 +1299,12 @@ long web_client_send_deflate(struct web_client *w)
1299 long web_client_send(struct web_client *w)
1300 {
1301 #ifdef NETDATA_WITH_ZLIB
1279 - if(likely(w->zoutput)) return web_client_send_deflate(w);
1302 + if(likely(w->response.zoutput)) return web_client_send_deflate(w);
1303 #endif // NETDATA_WITH_ZLIB
1304
1305 long bytes;
1306
1284 - if(unlikely(w->data->len - w->data->sent == 0)) {
1307 + if(unlikely(w->response.data->len - w->response.sent == 0)) {
1308 // there is nothing to send
1309
1310 debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
@@ -1290,7 +1313,7 @@ long web_client_send(struct web_client *w)
1313 // A. we have done everything
1314 // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
1315
1293 - if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->data->rlen && w->data->rlen > w->data->len) {
1316 + if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->ifd != w->ofd && w->response.rlen && w->response.rlen > w->response.data->len) {
1317 // we have to wait, more data will come
1318 debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
1319 w->wait_send = 0;
@@ -1298,7 +1321,7 @@ long web_client_send(struct web_client *w)
1321 }
1322
1323 if(unlikely(w->keepalive == 0)) {
1301 - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %ld bytes sent.", w->id, w->data->sent);
1324 + debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %ld bytes sent.", w->id, w->response.sent);
1325 errno = 0;
1326 return(-1);
1327 }
@@ -1308,9 +1331,9 @@ long web_client_send(struct web_client *w)
1331 return(0);
1332 }
1333
1311 - bytes = send(w->ofd, &w->data->buffer[w->data->sent], w->data->len - w->data->sent, MSG_DONTWAIT);
1334 + bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
1335 if(likely(bytes > 0)) {
1313 - w->data->sent += bytes;
1336 + w->response.sent += bytes;
1337 debug(D_WEB_CLIENT, "%llu: Sent %d bytes.", w->id, bytes);
1338 }
1339 else if(likely(bytes == 0)) debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
@@ -1322,27 +1345,27 @@ long web_client_send(struct web_client *w)
1345 long web_client_receive(struct web_client *w)
1346 {
1347 // do we have any space for more data?
1325 - web_buffer_need_bytes(w->data, WEB_DATA_LENGTH_INCREASE_STEP);
1348 + buffer_need_bytes(w->response.data, WEB_REQUEST_LENGTH);
1349
1327 - long left = w->data->size - w->data->len;
1350 + long left = w->response.data->size - w->response.data->len;
1351 long bytes;
1352
1353 if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
1331 - bytes = read(w->ifd, &w->data->buffer[w->data->len], (left-1));
1354 + bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (left-1));
1355 else
1333 - bytes = recv(w->ifd, &w->data->buffer[w->data->len], left-1, MSG_DONTWAIT);
1356 + bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], left-1, MSG_DONTWAIT);
1357
1358 if(likely(bytes > 0)) {
1336 - int old = w->data->len;
1337 - w->data->len += bytes;
1338 - w->data->buffer[w->data->len] = '\0';
1359 + int old = w->response.data->len;
1360 + w->response.data->len += bytes;
1361 + w->response.data->buffer[w->response.data->len] = '\0';
1362
1363 debug(D_WEB_CLIENT, "%llu: Received %d bytes.", w->id, bytes);
1341 - debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->data->buffer[old]);
1364 + debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
1365
1366 if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
1367 w->wait_send = 1;
1345 - if(w->data->rlen && w->data->len >= w->data->rlen) w->wait_receive = 0;
1368 + if(w->response.rlen && w->response.data->len >= w->response.rlen) w->wait_receive = 0;
1369 }
1370 }
1371 else if(likely(bytes == 0)) {
src/web_client.h
+19 -33
@@ -1,5 +1,5 @@
1
2 -#ifndef NETDATA_WITHOUT_ZLIB
2 +#ifdef NETDATA_WITH_ZLIB
3 #include <zlib.h>
4 #endif
5
@@ -24,27 +24,26 @@ extern int web_enable_gzip;
24
25 #define URL_MAX 8192
26 #define ZLIB_CHUNK 16384
27 -#define MAX_HTTP_HEADER_SIZE 16384
28 -
29 -/*
30 -struct name_value {
31 - char *name;
32 - char *value;
33 - unsigned long hash;
34 - struct name_value *next;
35 -};
27 +#define HTTP_RESPONSE_HEADER_SIZE 4096
28 +
29 +struct response {
30 + BUFFER *header; // our response header
31 + BUFFER *header_output; // internal use
32 + BUFFER *data; // our response data buffer
33
37 -struct web_request {
38 - char *protocol;
39 - char *hostname;
40 - char *path;
41 - char *query_string;
34 + long rlen; // if non-zero, the excepted size of ifd (input)
35 + long sent; // current data length sent to output
36 +
37 + int zoutput; // if set to 1, web_client_send() will send compressed data
38 +#ifdef NETDATA_WITH_ZLIB
39 + z_stream zstream; // zlib stream for sending compressed output to client
40 + Bytef zbuffer[ZLIB_CHUNK]; // temporary buffer for storing compressed output
41 + long zsent; // the compressed bytes we have sent to the client
42 + long zhave; // the compressed bytes that we have to send
43 + int zinitialized;
44 +#endif
45
43 - struct name_value *headers;
44 - struct name_value *query_parameters;
45 - struct name_value *post_parameters;
46 };
47 -*/
47
48 struct web_client {
49 unsigned long long id;
@@ -54,8 +53,6 @@ struct web_client {
53
54 char last_url[URL_MAX+1];
55
57 - struct web_request *request;
58 -
56 struct timeval tv_in, tv_ready;
57
58 int mode;
@@ -69,22 +66,11 @@ struct web_client {
66 int ifd;
67 int ofd;
68
72 - struct web_buffer *data;
73 -
74 - int zoutput; // if set to 1, web_client_send() will send compressed data
75 -#ifndef NETDATA_WITHOUT_ZLIB
76 - z_stream zstream; // zlib stream for sending compressed output to client
77 - Bytef zbuffer[ZLIB_CHUNK]; // temporary buffer for storing compressed output
78 - long zsent; // the compressed bytes we have sent to the client
79 - long zhave; // the compressed bytes that we have to send
80 - int zinitialized;
81 -#endif
69 + struct response response;
70
71 int wait_receive;
72 int wait_send;
73
86 - char response_header[MAX_HTTP_HEADER_SIZE+1];
87 -
74 struct web_client *prev;
75 struct web_client *next;
76 };