@cryptotaxi247 / netdata-1 / commits / 0fca36fd5

Revert "New URL parser (#6070)"

This reverts commit 58b7d95a7ec9c576f8a06bbab07f755846b5349a. --- As agreed with @thiago and @cakrit we revert URL parser changes, to buy the time on a more detailed investigation ---

Pavlos Emm. Katsoulakis committed Jun 7, 2019 at 18:14 UTC 0fca36fd596e49395141561bc42c168a240f51b8
10 files changed +444 -1056
libnetdata/inlined.h
-28
@@ -31,19 +31,6 @@ static inline uint32_t simple_hash(const char *name) {
31 return hval;
32 }
33
34 -static inline uint32_t simple_nhash(const char *name,size_t len) {
35 - unsigned char *s = (unsigned char *) name;
36 - size_t i;
37 - uint32_t hval = 0x811c9dc5;
38 - i = 0;
39 - do {
40 - hval *= 16777619;
41 - hval ^= (uint32_t) *s++;
42 - } while (++i < len);
43 -
44 - return hval;
45 -}
46 -
34 static inline uint32_t simple_uhash(const char *name) {
35 unsigned char *s = (unsigned char *) name;
36 uint32_t hval = 0x811c9dc5, c;
@@ -55,21 +42,6 @@ static inline uint32_t simple_uhash(const char *name) {
42 return hval;
43 }
44
58 -static inline uint32_t simple_nuhash(const char *name,size_t len) {
59 - unsigned char *s = (unsigned char *) name;
60 - size_t i;
61 - uint32_t hval = 0x811c9dc5, c;
62 -
63 - i = 0;
64 - do {
65 - c = *s++;
66 - if (unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A';
67 - hval *= 16777619;
68 - hval ^= c;
69 - } while ( ++i < len);
70 - return hval;
71 -}
72 -
45 static inline int simple_hash_strcmp(const char *name, const char *b, uint32_t *hash) {
46 unsigned char *s = (unsigned char *) name;
47 uint32_t hval = 0x811c9dc5;
libnetdata/url/url.c
-85
@@ -79,88 +79,3 @@ char *url_decode_r(char *to, char *url, size_t size) {
79
80 return to;
81 }
82 -
83 -inline HTTP_VALIDATION url_is_request_complete(char *begin,char *end,size_t length) {
84 - if ( begin == end) {
85 - return HTTP_VALIDATION_INCOMPLETE;
86 - }
87 -
88 - if ( length > 3 ) {
89 - begin = end - 4;
90 - }
91 -
92 - uint32_t counter = 0;
93 - do {
94 - if (*begin == '\r') {
95 - begin++;
96 - if ( begin == end )
97 - {
98 - break;
99 - }
100 -
101 - if (*begin == '\n')
102 - {
103 - counter++;
104 - }
105 - } else if (*begin == '\n') {
106 - begin++;
107 - counter++;
108 - }
109 -
110 - if ( counter == 2) {
111 - break;
112 - }
113 - }
114 - while (begin != end);
115 -
116 - return (counter == 2)?HTTP_VALIDATION_OK:HTTP_VALIDATION_INCOMPLETE;
117 -}
118 -
119 -inline char *url_find_protocol(char *s) {
120 - while(*s) {
121 - // find the next space
122 - while (*s && *s != ' ') s++;
123 -
124 - // is it SPACE + "HTTP/" ?
125 - if(*s && !strncmp(s, " HTTP/", 6)) break;
126 - else s++;
127 - }
128 -
129 - return s;
130 -}
131 -
132 -int url_parse_query_string(struct web_fields *names,struct web_fields *values,char *moveme,char *divisor) {
133 - uint32_t i = 0;
134 - uint32_t max = WEB_FIELDS_MAX;
135 -
136 - do {
137 - if ( i == max) {
138 - error("We are exceeding the maximum number of elements possible(%u) in this query string(%s)",max,moveme);
139 - break;
140 - }
141 - if (divisor) {
142 - names[i].body = moveme;
143 - names[i].length = divisor - moveme;//= - begin
144 -
145 - moveme = ++divisor; //value
146 - values[i].body = moveme;
147 -
148 - (void)divisor;
149 - divisor = strchr(moveme,'&'); //end of value
150 - if (divisor) {
151 - values[i].length = (size_t )(divisor - moveme);
152 - } else{
153 - values[i].length = strlen(moveme);
154 - break;
155 - }
156 -
157 - moveme = divisor;
158 - divisor = strchr(++moveme,'='); //end of value
159 - i++;
160 - } else {
161 - break;
162 - }
163 - } while (moveme);
164 -
165 - return ++i;
166 -}
libnetdata/url/url.h
-22
@@ -25,26 +25,4 @@ extern char *url_decode(char *str);
25
26 extern char *url_decode_r(char *to, char *url, size_t size);
27
28 -#define WEB_FIELDS_MAX 200
29 -struct web_fields{
30 - char *body;
31 - size_t length;
32 -};
33 -// http_request_validate()
34 -// returns:
35 -// = 0 : all good, process the request
36 -// > 0 : request is not supported
37 -// < 0 : request is incomplete - wait for more data
38 -
39 -typedef enum {
40 - HTTP_VALIDATION_OK,
41 - HTTP_VALIDATION_NOT_SUPPORTED,
42 - HTTP_VALIDATION_INCOMPLETE,
43 - HTTP_VALIDATION_REDIRECT
44 -} HTTP_VALIDATION;
45 -
46 -extern HTTP_VALIDATION url_is_request_complete(char *begin,char *end,size_t length);
47 -extern char *url_find_protocol(char *s);
48 -extern int url_parse_query_string(struct web_fields *names,struct web_fields *values,char *moveme,char *divisor);
49 -
28 #endif /* NETDATA_URL_H */
tests/urls/requests.sh deleted
-207
@@ -1,207 +0,0 @@
1 -#!/bin/bash
2 -# SPDX-License-Identifier: GPL-3.0-or-later
3 -
4 -################################################################################################
5 -#### ####
6 -#### GLOBAL VARIABLES ####
7 -#### ####
8 -################################################################################################
9 -
10 -NETDATA_VARLIB_DIR="@varlibdir_POST@"
11 -
12 -#CT=`date +'%s%N' |cut -b1-13`
13 -# The current time
14 -CT=`date +'%s'`
15 -
16 -# The previous time
17 -PT=$(( $CT - 100))
18 -
19 -# The curl options used to do download
20 -CURLOPTS="-v --create-dirs -o"
21 -
22 -# The output directory where we will store the results and error
23 -OUTDIR="tests"
24 -
25 -################################################################################################
26 -#### ####
27 -#### FUNCTIONS ####
28 -#### ####
29 -################################################################################################
30 -
31 -# Print error message and close script
32 -netdata_print_error(){
33 - echo "Closing due error \"$1\" code \"$2\""
34 - exit 1
35 -}
36 -
37 -# Print the header message of the function
38 -netdata_print_header() {
39 - echo "$1"
40 -}
41 -
42 -# Create the main directory where the results will be stored
43 -netdata_create_directory() {
44 - netdata_print_header "Creating directory $1"
45 - if [ ! -d $1 ]; then
46 - mkdir $1
47 - if [ $? -ne 0 ]; then
48 - netdata_print_error "Cannot create directory" $?
49 - fi
50 - else
51 - echo "Working with directory $OUTDIR"
52 - fi
53 -}
54 -
55 -netdata_test_download(){
56 - grep "HTTP/1.1 200 OK" $1 2>/dev/null 1>/dev/null
57 - if [ $? -ne 0 ]; then
58 - netdata_print_error "Cannot do download of the page $2" $?
59 - fi
60 -}
61 -
62 -# Download information from Netdata
63 -netdata_download_various() {
64 - netdata_print_header "Getting $2"
65 - curl $CURLOPTS $OUTDIR/$3.out "$1/$2" 2> $OUTDIR/$3.err
66 - netdata_test_download $OUTDIR/$3.err "$1/$2"
67 -}
68 -
69 -# Download charts from Netdata
70 -netdata_download_charts() {
71 - curl $CURLOPTS $OUTDIR/charts.out "$1/$2/charts" 2> $OUTDIR/charts.err
72 - netdata_test_download $OUTDIR/charts.err "$1/$2/charts"
73 -
74 - #Rewrite the next
75 - cat tests/charts.out | grep -w "id"| cut -d: -f2 | grep "\"," | sed s/,//g | sort
76 -}
77 -
78 -#Test options for a specific chart
79 -netdata_download_chart() {
80 - NAME=`echo $3| sed s/\"//g`
81 - netdata_print_header "Getting data for $NAME using $4"
82 -
83 - LDIR=$OUTDIR"/"$4
84 -
85 - LURL=$1/$2=$NAME
86 -
87 - NAME=$NAME"_$4"
88 -
89 - curl $CURLOPTS $LDIR/$NAME.out "$LURL" 2> $LDIR/$NAME.err
90 - netdata_test_download $LDIR/$NAME.err $LURL
91 -
92 - UFILES=( "points" "before" "after" )
93 - COUNTER=0
94 - for OPT in "&points=100" "&before=$PT" "&after=$CT" ;
95 - do
96 - LURL="$LURL$OPT"
97 - LFILE=$NAME"_${UFILES[$COUNTER]}";
98 -
99 - curl $CURLOPTS "$LDIR/$LFILE.out" "$LURL" 2> "$LDIR/$LFILE.err"
100 - netdata_test_download $LDIR/$LFILE.err $LURL
101 -
102 - COUNTER=$(($COUNTER + 1))
103 - done
104 -
105 - LURL="$LURL&group="
106 - for OPT in "min" "max" "sum" "median" "stddev" "cv" "ses" "des" "incremental_sum" "average";
107 - do
108 - TURL=$LURL$OPT
109 - TFILE=$NAME"_$OPT";
110 - curl $CURLOPTS "$LDIR/$TFILE.out" "$TURL" 2> "$LDIR/$TFILE.err"
111 - netdata_test_download $LDIR/$TFILE.err $TURL
112 - for MORE in "jsonp" "json" "ssv" "csv" "datatable" "datasource" "tsv" "ssvcomma" "html" "array";
113 - do
114 - TURL=$TURL"&format="$MORE
115 - TFILE=$NAME"_$OPT""_$MORE";
116 - curl $CURLOPTS "$LDIR/$TFILE.out" "$TURL" 2> "$LDIR/$TFILE.err"
117 - netdata_test_download $LDIR/$TFILE.err $TURL
118 - done
119 -
120 - done
121 -
122 - LURL="$LURL$OPT&gtime=60"
123 - NFILE=$NAME"_gtime"
124 - curl $CURLOPTS "$LDIR/$NFILE.out" "$TURL" 2> "$LDIR/$NFILE.err"
125 - netdata_test_download $LDIR/$NFILE.err $LURL
126 -
127 - LURL="$LURL$OPT&options=percentage"
128 - NFILE=$NAME"_percentage"
129 - curl $CURLOPTS "$LDIR/$NFILE.out" "$TURL" 2> "$LDIR/$NFILE.err"
130 - netdata_test_download $LDIR/$NFILE.err $LURL
131 -
132 - LURL="$LURL$OPT&options=percentage"
133 - NFILE=$NAME"_percentage"
134 - curl $CURLOPTS "$LDIR/$NFILE.out" "$TURL" 2> "$LDIR/$NFILE.err"
135 - netdata_test_download $LDIR/$NFILE.err $LURL
136 -
137 - LURL="$LURL$OPT&dimensions=system%7Cnice"
138 - NFILE=$NAME"_dimension"
139 - curl $CURLOPTS "$LDIR/$NFILE.out" "$TURL" 2> "$LDIR/$NFILE.err"
140 - netdata_test_download $LDIR/$NFILE.err $LURL
141 -
142 -}
143 -
144 -# Download information from Netdata
145 -netdata_download_allmetrics() {
146 - netdata_print_header "Getting All metrics"
147 - curl $CURLOPTS $OUTDIR/allmetrics.out "$1/$2" 2> $OUTDIR/allmetrics.err
148 - netdata_test_download $OUTDIR/allmetrics.err "$1/$2"
149 -}
150 -
151 -# Download charts from Netdata
152 -
153 -################################################################################################
154 -#### ####
155 -#### MAIN ROUTINE ####
156 -#### ####
157 -################################################################################################
158 -MURL="http://127.0.0.1:19999"
159 -
160 -wget --execute="robots = off" --mirror --convert-links --no-parent http://127.0.0.1:19999
161 -
162 -netdata_create_directory $OUTDIR
163 -
164 -netdata_download_various $MURL "netdata.conf" "netdata.conf"
165 -
166 -netdata_download_various $MURL "api/v1/info" "info"
167 -
168 -netdata_download_various $MURL "api/v1/registry?action=hello" "action"
169 -
170 -netdata_print_header "Getting all the netdata charts"
171 -CHARTS=$( netdata_download_charts "http://127.0.0.1:19999" "api/v1" )
172 -
173 -netdata_download_various $MURL "api/v1/allmetrics?format=json" "allmetrics"
174 -
175 -netdata_download_various $MURL "api/v1/alarms?all" "alarms_all"
176 -
177 -netdata_download_various $MURL "api/v1/alarms?active" "alarms_active"
178 -
179 -netdata_download_various $MURL "api/v1/alarm_log?after&_=$PT" "alarm_log"
180 -
181 -for I in $CHARTS ; do
182 - NAME=`echo $I| sed s/\"//g`
183 - netdata_download_various $MURL "api/v1/alarm_variables?chart=$NAME" "alarm_variables_$NAME"
184 -done
185 -
186 -netdata_create_directory "$OUTDIR/data"
187 -for I in $CHARTS ; do
188 - netdata_download_chart $MURL "api/v1/data?chart" $I "data"
189 -done
190 -
191 -netdata_create_directory "$OUTDIR/badge.svg"
192 -for I in $CHARTS ; do
193 - netdata_download_chart $MURL "api/v1/badge.svg?chart" $I "badge.svg"
194 -done
195 -
196 -if [ -f "${NETDATA_VARLIB_DIR}/netdata.api.key" ] ;then
197 - read -r CORRECT_TOKEN < "${NETDATA_VARLIB_DIR}/netdata.api.key"
198 -else
199 - echo "${NETDATA_VARLIB_DIR}/netdata.api.key not found"
200 - echo "Token not found."
201 - exit 2
202 -fi
203 -curl -H "X-Auth-Token: $TOKEN" "http://127.0.0.1:19999/api/v1/manage/health?cmd=RESET"
204 -
205 -echo "ALL the URLS got 200 as answer!"
206 -
207 -exit 0
web/api/badges/web_buffer_svg.c
+40 -57
@@ -889,7 +889,6 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
889 }
890
891 int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) {
892 - (void)url;
892 int ret = 400;
893 buffer_flush(w->response.data);
894
@@ -913,54 +912,46 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
912 int group = RRDR_GROUPING_AVERAGE;
913 uint32_t options = 0x00000000;
914
916 - uint32_t i = 0;
917 - uint32_t end = w->total_params;
918 - char save[WEB_FIELDS_MAX];
919 - char *value;
920 - size_t lvalue;
921 - if(end) {
922 - do {
923 - value = w->param_values[i].body;
924 - lvalue = w->param_values[i].length;
925 - save[i] = value[lvalue];
926 - value[lvalue] = 0x00;
927 -
928 - char *name = w->param_name[i].body;
929 - size_t lname = w->param_name[i].length;
930 -
931 - debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
932 -
933 - // name and value are now the parameters
934 - // they are not null and not empty
935 - if(!strncmp(name, "chart",lname)) chart = value;
936 - else if(!strncmp(name, "dimension",lname) || !strncmp(name, "dim",lname) || !strncmp(name, "dimensions",lname) || !strncmp(name, "dims",lname)) {
937 - if(!dimensions)
938 - dimensions = buffer_create(100);
939 -
940 - buffer_strcat(dimensions, "|");
941 - buffer_strcat(dimensions, value);
942 - }
943 - else if(!strncmp(name, "after",lname)) after_str = value;
944 - else if(!strncmp(name, "before",lname)) before_str = value;
945 - else if(!strncmp(name, "points",lname)) points_str = value;
946 - else if(!strncmp(name, "group",lname)) {
947 - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
948 - }
949 - else if(!strncmp(name, "options",lname)) {
950 - options |= web_client_api_request_v1_data_options(value);
951 - }
952 - else if(!strncmp(name, "label",lname)) label = value;
953 - else if(!strncmp(name, "units",lname)) units = value;
954 - else if(!strncmp(name, "label_color",lname)) label_color = value;
955 - else if(!strncmp(name, "value_color",lname)) value_color = value;
956 - else if(!strncmp(name, "multiply",lname)) multiply_str = value;
957 - else if(!strncmp(name, "divide",lname)) divide_str = value;
958 - else if(!strncmp(name, "refresh",lname)) refresh_str = value;
959 - else if(!strncmp(name, "precision",lname)) precision_str = value;
960 - else if(!strncmp(name, "scale",lname)) scale_str = value;
961 - else if(!strncmp(name, "alarm",lname)) alarm = value;
962 -
963 - } while (++i < end );
915 + while(url) {
916 + char *value = mystrsep(&url, "&");
917 + if(!value || !*value) continue;
918 +
919 + char *name = mystrsep(&value, "=");
920 + if(!name || !*name) continue;
921 + if(!value || !*value) continue;
922 +
923 + debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
924 +
925 + // name and value are now the parameters
926 + // they are not null and not empty
927 +
928 + if(!strcmp(name, "chart")) chart = value;
929 + else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
930 + if(!dimensions)
931 + dimensions = buffer_create(100);
932 +
933 + buffer_strcat(dimensions, "|");
934 + buffer_strcat(dimensions, value);
935 + }
936 + else if(!strcmp(name, "after")) after_str = value;
937 + else if(!strcmp(name, "before")) before_str = value;
938 + else if(!strcmp(name, "points")) points_str = value;
939 + else if(!strcmp(name, "group")) {
940 + group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
941 + }
942 + else if(!strcmp(name, "options")) {
943 + options |= web_client_api_request_v1_data_options(value);
944 + }
945 + else if(!strcmp(name, "label")) label = value;
946 + else if(!strcmp(name, "units")) units = value;
947 + else if(!strcmp(name, "label_color")) label_color = value;
948 + else if(!strcmp(name, "value_color")) value_color = value;
949 + else if(!strcmp(name, "multiply")) multiply_str = value;
950 + else if(!strcmp(name, "divide")) divide_str = value;
951 + else if(!strcmp(name, "refresh")) refresh_str = value;
952 + else if(!strcmp(name, "precision")) precision_str = value;
953 + else if(!strcmp(name, "scale")) scale_str = value;
954 + else if(!strcmp(name, "alarm")) alarm = value;
955 }
956
957 if(!chart || !*chart) {
@@ -1146,14 +1137,6 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
1137 }
1138
1139 cleanup:
1149 - if(end) {
1150 - i = 0;
1151 - do {
1152 - value = w->param_values[i].body;
1153 - lvalue = w->param_values[i].length;
1154 - value[lvalue] = save[i];
1155 - } while(++i < end);
1156 - }
1140 buffer_free(dimensions);
1141 return ret;
1142 }
web/api/exporters/allmetrics.c
+38 -41
@@ -18,57 +18,54 @@ struct prometheus_output_options {
18 };
19
20 inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) {
21 - (void)url;
21 int format = ALLMETRICS_SHELL;
22 const char *prometheus_server = w->client_ip;
23 uint32_t prometheus_backend_options = global_backend_options;
24 PROMETHEUS_OUTPUT_OPTIONS prometheus_output_options = PROMETHEUS_OUTPUT_TIMESTAMPS | ((global_backend_options & BACKEND_OPTION_SEND_NAMES)?PROMETHEUS_OUTPUT_NAMES:0);
25 const char *prometheus_prefix = global_backend_prefix;
26
28 - uint32_t end = w->total_params;
29 - if (end) {
30 - uint32_t i = 0;
31 - do {
32 - char *name = w->param_name[i].body;
33 - size_t lname = w->param_name[i].length;
34 - char *value = w->param_values[i].body;
35 - size_t lvalue = w->param_values[i].length;
27 + while(url) {
28 + char *value = mystrsep(&url, "&");
29 + if (!value || !*value) continue;
30
37 - if(!strncmp(name, "format",lname)) {
38 - if(!strncmp(value, ALLMETRICS_FORMAT_SHELL,lvalue))
39 - format = ALLMETRICS_SHELL;
40 - else if(!strncmp(value, ALLMETRICS_FORMAT_PROMETHEUS,lvalue))
41 - format = ALLMETRICS_PROMETHEUS;
42 - else if(!strncmp(value, ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS,lvalue))
43 - format = ALLMETRICS_PROMETHEUS_ALL_HOSTS;
44 - else if(!strncmp(value, ALLMETRICS_FORMAT_JSON,lvalue))
45 - format = ALLMETRICS_JSON;
46 - else
47 - format = 0;
48 - }
49 - else if(!strncmp(name, "server",lname)) {
50 - prometheus_server = value;
51 - }
52 - else if(!strncmp(name, "prefix",lname)) {
53 - prometheus_prefix = value;
54 - }
55 - else if(!strncmp(name, "data",lname) || !strncmp(name, "source",lname) || !strncmp(name, "data source",lname) || !strncmp(name, "data-source",lname) || !strncmp(name, "data_source",lname) || !strncmp(name, "datasource",lname)) {
56 - prometheus_backend_options = backend_parse_data_source(value, prometheus_backend_options);
57 - }
58 - else {
59 - int i;
60 - for(i = 0; prometheus_output_flags_root[i].name ; i++) {
61 - if(!strncmp(name, prometheus_output_flags_root[i].name,lname)) {
62 - if(!strncmp(value, "yes",lvalue) || !strncmp(value, "1",lvalue) || !strncmp(value, "true",lvalue))
63 - prometheus_output_options |= prometheus_output_flags_root[i].flag;
64 - else
65 - prometheus_output_options &= ~prometheus_output_flags_root[i].flag;
31 + char *name = mystrsep(&value, "=");
32 + if(!name || !*name) continue;
33 + if(!value || !*value) continue;
34 +
35 + if(!strcmp(name, "format")) {
36 + if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
37 + format = ALLMETRICS_SHELL;
38 + else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
39 + format = ALLMETRICS_PROMETHEUS;
40 + else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS))
41 + format = ALLMETRICS_PROMETHEUS_ALL_HOSTS;
42 + else if(!strcmp(value, ALLMETRICS_FORMAT_JSON))
43 + format = ALLMETRICS_JSON;
44 + else
45 + format = 0;
46 + }
47 + else if(!strcmp(name, "server")) {
48 + prometheus_server = value;
49 + }
50 + else if(!strcmp(name, "prefix")) {
51 + prometheus_prefix = value;
52 + }
53 + else if(!strcmp(name, "data") || !strcmp(name, "source") || !strcmp(name, "data source") || !strcmp(name, "data-source") || !strcmp(name, "data_source") || !strcmp(name, "datasource")) {
54 + prometheus_backend_options = backend_parse_data_source(value, prometheus_backend_options);
55 + }
56 + else {
57 + int i;
58 + for(i = 0; prometheus_output_flags_root[i].name ; i++) {
59 + if(!strcmp(name, prometheus_output_flags_root[i].name)) {
60 + if(!strcmp(value, "yes") || !strcmp(value, "1") || !strcmp(value, "true"))
61 + prometheus_output_options |= prometheus_output_flags_root[i].flag;
62 + else
63 + prometheus_output_options &= ~prometheus_output_flags_root[i].flag;
64
67 - break;
68 - }
65 + break;
66 }
67 }
71 - } while( ++i < end);
68 + }
69 }
70
71 buffer_flush(w->response.data);
web/api/health/health_cmdapi.c
+68 -77
@@ -31,10 +31,13 @@ void free_silencers(SILENCER *t) {
31 return;
32 }
33
34 +
35 +
36 int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) {
37 int ret = 400;
38 (void) host;
37 - (void)url;
39 +
40 +
41
42 BUFFER *wb = w->response.data;
43 buffer_flush(wb);
@@ -70,86 +73,75 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
73 buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
74 ret = 403;
75 } else {
73 - uint32_t end = w->total_params;
74 - if (end) {
75 - uint32_t i = 0;
76 - do {
77 - char *key = w->param_name[i].body;
78 - size_t lkey = w->param_name[i].length;
79 - char ksave = key[lkey];
80 - key[lkey] = 0x00;
81 -
82 - char *value = w->param_values[i].body;
83 - size_t lvalue = w->param_values[i].length;
84 - char vsave = value[lvalue];
85 - value[lvalue] = 0x00;
86 -
87 - debug(D_WEB_CLIENT, "%llu: API v1 health query param '%s' with value '%s'", w->id, key, value);
88 -
89 - // name and value are now the parameters
90 - if (!strncmp(key, "cmd",lkey)) {
91 - if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
92 - silencers->all_alarms = 1;
93 - silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
94 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCEALL);
95 - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLEALL)) {
96 - silencers->all_alarms = 1;
97 - silencers->stype = STYPE_DISABLE_ALARMS;
98 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLEALL);
99 - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCE)) {
100 - silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
101 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCE);
102 - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLE)) {
103 - silencers->stype = STYPE_DISABLE_ALARMS;
104 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLE);
105 - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_RESET)) {
106 - silencers->all_alarms = 0;
107 - silencers->stype = STYPE_NONE;
108 - free_silencers(silencers->silencers);
109 - silencers->silencers = NULL;
110 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
111 - }
112 - } else {
113 - uint32_t hash = simple_uhash(key);
114 - if (unlikely(silencer == NULL)) {
115 - if (
116 - (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) ||
117 - (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) ||
118 - (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) ||
119 - (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) ||
120 - (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) ||
121 - (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY))
122 - ) {
123 - silencer = create_silencer();
124 - }
125 - }
126 -
127 - if (hash == hash_alarm && !strncasecmp(key, HEALTH_ALARM_KEY,lkey)) {
128 - silencer->alarms = strdupz(value);
129 - silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT);
130 - } else if (hash == hash_chart && !strncasecmp(key, HEALTH_CHART_KEY,lkey)) {
131 - silencer->charts = strdupz(value);
132 - silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT);
133 - } else if (hash == hash_context && !strncasecmp(key, HEALTH_CONTEXT_KEY,lkey)) {
134 - silencer->contexts = strdupz(value);
135 - silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT);
136 - } else if (hash == hash_host && !strncasecmp(key, HEALTH_HOST_KEY,lkey)) {
137 - silencer->hosts = strdupz(value);
138 - silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT);
139 - } else if (hash == hash_families && !strncasecmp(key, HEALTH_FAMILIES_KEY,lkey)) {
140 - silencer->families = strdupz(value);
141 - silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT);
142 - } else {
143 - buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY);
76 + while (url) {
77 + char *value = mystrsep(&url, "&");
78 + if (!value || !*value) continue;
79 +
80 + char *key = mystrsep(&value, "=");
81 + if (!key || !*key) continue;
82 + if (!value || !*value) continue;
83 +
84 + debug(D_WEB_CLIENT, "%llu: API v1 health query param '%s' with value '%s'", w->id, key, value);
85 +
86 + // name and value are now the parameters
87 + if (!strcmp(key, "cmd")) {
88 + if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
89 + silencers->all_alarms = 1;
90 + silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
91 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCEALL);
92 + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLEALL)) {
93 + silencers->all_alarms = 1;
94 + silencers->stype = STYPE_DISABLE_ALARMS;
95 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLEALL);
96 + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCE)) {
97 + silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
98 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCE);
99 + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLE)) {
100 + silencers->stype = STYPE_DISABLE_ALARMS;
101 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLE);
102 + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_RESET)) {
103 + silencers->all_alarms = 0;
104 + silencers->stype = STYPE_NONE;
105 + free_silencers(silencers->silencers);
106 + silencers->silencers = NULL;
107 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
108 + }
109 + } else {
110 + uint32_t hash = simple_uhash(key);
111 + if (unlikely(silencer == NULL)) {
112 + if (
113 + (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) ||
114 + (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) ||
115 + (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) ||
116 + (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) ||
117 + (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) ||
118 + (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY))
119 + ) {
120 + silencer = create_silencer();
121 }
122 }
146 - key[lkey] = ksave ;
147 - value[lvalue] = vsave ;
123
149 - } while( ++i < end );
124 + if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
125 + silencer->alarms = strdupz(value);
126 + silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT);
127 + } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) {
128 + silencer->charts = strdupz(value);
129 + silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT);
130 + } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) {
131 + silencer->contexts = strdupz(value);
132 + silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT);
133 + } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
134 + silencer->hosts = strdupz(value);
135 + silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT);
136 + } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
137 + silencer->families = strdupz(value);
138 + silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT);
139 + } else {
140 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY);
141 + }
142 + }
143
144 }
152 -
145 if (likely(silencer)) {
146 // Add the created instance to the linked list in silencers
147 silencer->next = silencers->silencers;
@@ -168,7 +160,6 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
160 ret = 200;
161 }
162 }
171 -
163 w->response.data = wb;
164 buffer_no_cacheable(w->response.data);
165 return ret;
web/api/web_api_v1.c
+138 -174
@@ -195,18 +195,14 @@ inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
195
196
197 inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url) {
198 - (void)url;
198 int all = 0;
199
201 - uint32_t end = w->total_params;
202 - if(end) {
203 - uint32_t i = 0;
204 - do {
205 - char *value = w->param_values[i].body;
200 + while(url) {
201 + char *value = mystrsep(&url, "&");
202 + if (!value || !*value) continue;
203
207 - if(!strncmp(value, "all",3)) all = 1;
208 - else if(!strncmp(value, "active",6)) all = 0;
209 - } while(++i < end);
204 + if(!strcmp(value, "all")) all = 1;
205 + else if(!strcmp(value, "active")) all = 0;
206 }
207
208 buffer_flush(w->response.data);
@@ -217,24 +213,17 @@ inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w,
213 }
214
215 inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) {
220 - (void)url;
216 uint32_t after = 0;
217
223 - uint32_t end = w->total_params;
224 - if(end) {
225 - uint32_t i = 0;
226 - do {
227 - char *value = w->param_values[i].body;
228 - size_t lvalue = w->param_values[i].length;
229 - char save = value[lvalue];
230 - value[lvalue] = 0x00;
231 -
232 - char *name = w->param_name[i].body;
233 - size_t lname = w->param_name[i].length;
234 -
235 - if(!strncmp(name, "after",lname)) after = (uint32_t)strtoul(value, NULL, 0);
236 - value[lvalue] = save;
237 - } while (++i < end);
218 + while(url) {
219 + char *value = mystrsep(&url, "&");
220 + if (!value || !*value) continue;
221 +
222 + char *name = mystrsep(&value, "=");
223 + if(!name || !*name) continue;
224 + if(!value || !*value) continue;
225 +
226 + if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0);
227 }
228
229 buffer_flush(w->response.data);
@@ -244,29 +233,27 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
233 }
234
235 inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf)) {
247 - (void)url;
236 int ret = 400;
237 char *chart = NULL;
238
239 buffer_flush(w->response.data);
240
253 - uint32_t i = 0;
254 - uint32_t end = w->total_params;
255 - if(end) {
256 - do {
257 - char *name = w->param_name[i].body;
258 - size_t nlength = w->param_name[i].length;
259 - char *value = w->param_values[i].body;
260 -
261 - // name and value are now the parameters
262 - // they are not null and not empty
263 -
264 - if(!strncmp(name, "chart",nlength)) chart = value;
265 - //else {
266 - /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
267 - // goto cleanup;
268 - //}
269 - } while (++i < end);
241 + while(url) {
242 + char *value = mystrsep(&url, "&");
243 + if(!value || !*value) continue;
244 +
245 + char *name = mystrsep(&value, "=");
246 + if(!name || !*name) continue;
247 + if(!value || !*value) continue;
248 +
249 + // name and value are now the parameters
250 + // they are not null and not empty
251 +
252 + if(!strcmp(name, "chart")) chart = value;
253 + //else {
254 + /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
255 + // goto cleanup;
256 + //}
257 }
258
259 if(!chart || !*chart) {
@@ -320,7 +307,6 @@ void fix_google_param(char *s) {
307
308 // returns the HTTP code
309 inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
323 - (void)url;
310 debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
311
312 int ret = 400;
@@ -347,82 +333,75 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
333 uint32_t format = DATASOURCE_JSON;
334 uint32_t options = 0x00000000;
335
350 - uint32_t end = w->total_params;
351 - char save[WEB_FIELDS_MAX];
352 - char *value ;
353 - size_t lvalue;
354 - if(end) {
355 - uint32_t i = 0;
356 - do {
357 - char *name = w->param_name[i].body;
358 - size_t lname = w->param_name[i].length;
359 - value = w->param_values[i].body;
360 - lvalue = w->param_values[i].length;
361 - save[i] = value[lvalue];
362 - value[lvalue] = 0x00;
363 -
364 - debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
365 -
366 - // name and value are now the parameters
367 - // they are not null and not empty
368 -
369 - if(!strncmp(name, "chart",lname)) chart = value;
370 - else if(!strncmp(name, "dimension",lname) || !strncmp(name, "dim",lname) || !strncmp(name, "dimensions",lname) || !strncmp(name, "dims",lname)) {
371 - if(!dimensions) dimensions = buffer_create(100);
372 - buffer_strcat(dimensions, "|");
373 - buffer_strcat(dimensions, value);
374 - }
375 - else if(!strncmp(name, "after",lname)) after_str = value;
376 - else if(!strncmp(name, "before",lname)) before_str = value;
377 - else if(!strncmp(name, "points",lname)) points_str = value;
378 - else if(!strncmp(name, "gtime",lname)) group_time_str = value;
379 - else if(!strncmp(name, "group",lname)) {
380 - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
381 - }
382 - else if(!strncmp(name, "format",lname)) {
383 - format = web_client_api_request_v1_data_format(value);
384 - }
385 - else if(!strncmp(name, "options",lname)) {
386 - options |= web_client_api_request_v1_data_options(value);
387 - }
388 - else if(!strncmp(name, "callback",lname)) {
389 - responseHandler = value;
390 - }
391 - else if(!strncmp(name, "filename",lname)) {
392 - outFileName = value;
393 - }
394 - else if(!strncmp(name, "tqx",lname)) {
395 - // parse Google Visualization API options
396 - // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
397 - char *tqx_name, *tqx_value;
398 -
399 - while(value) {
400 - tqx_value = mystrsep(&value, ";");
401 - if(!tqx_value || !*tqx_value) continue;
402 -
403 - tqx_name = mystrsep(&tqx_value, ":");
404 - if(!tqx_name || !*tqx_name) continue;
405 - if(!tqx_value || !*tqx_value) continue;
406 -
407 - if(!strcmp(tqx_name, "version"))
408 - google_version = tqx_value;
409 - else if(!strcmp(tqx_name, "reqId"))
410 - google_reqId = tqx_value;
411 - else if(!strcmp(tqx_name, "sig")) {
412 - google_sig = tqx_value;
413 - google_timestamp = strtoul(google_sig, NULL, 0);
414 - }
415 - else if(!strcmp(tqx_name, "out")) {
416 - google_out = tqx_value;
417 - format = web_client_api_request_v1_data_google_format(google_out);
418 - }
419 - else if(!strcmp(tqx_name, "responseHandler"))
420 - responseHandler = tqx_value;
421 - else if(!strcmp(tqx_name, "outFileName"))
422 - outFileName = tqx_value;
336 + while(url) {
337 + char *value = mystrsep(&url, "&");
338 + if(!value || !*value) continue;
339 +
340 + char *name = mystrsep(&value, "=");
341 + if(!name || !*name) continue;
342 + if(!value || !*value) continue;
343 +
344 + debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
345 +
346 + // name and value are now the parameters
347 + // they are not null and not empty
348 +
349 + if(!strcmp(name, "chart")) chart = value;
350 + else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
351 + if(!dimensions) dimensions = buffer_create(100);
352 + buffer_strcat(dimensions, "|");
353 + buffer_strcat(dimensions, value);
354 + }
355 + else if(!strcmp(name, "after")) after_str = value;
356 + else if(!strcmp(name, "before")) before_str = value;
357 + else if(!strcmp(name, "points")) points_str = value;
358 + else if(!strcmp(name, "gtime")) group_time_str = value;
359 + else if(!strcmp(name, "group")) {
360 + group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
361 + }
362 + else if(!strcmp(name, "format")) {
363 + format = web_client_api_request_v1_data_format(value);
364 + }
365 + else if(!strcmp(name, "options")) {
366 + options |= web_client_api_request_v1_data_options(value);
367 + }
368 + else if(!strcmp(name, "callback")) {
369 + responseHandler = value;
370 + }
371 + else if(!strcmp(name, "filename")) {
372 + outFileName = value;
373 + }
374 + else if(!strcmp(name, "tqx")) {
375 + // parse Google Visualization API options
376 + // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
377 + char *tqx_name, *tqx_value;
378 +
379 + while(value) {
380 + tqx_value = mystrsep(&value, ";");
381 + if(!tqx_value || !*tqx_value) continue;
382 +
383 + tqx_name = mystrsep(&tqx_value, ":");
384 + if(!tqx_name || !*tqx_name) continue;
385 + if(!tqx_value || !*tqx_value) continue;
386 +
387 + if(!strcmp(tqx_name, "version"))
388 + google_version = tqx_value;
389 + else if(!strcmp(tqx_name, "reqId"))
390 + google_reqId = tqx_value;
391 + else if(!strcmp(tqx_name, "sig")) {
392 + google_sig = tqx_value;
393 + google_timestamp = strtoul(google_sig, NULL, 0);
394 + }
395 + else if(!strcmp(tqx_name, "out")) {
396 + google_out = tqx_value;
397 + format = web_client_api_request_v1_data_google_format(google_out);
398 }
399 + else if(!strcmp(tqx_name, "responseHandler"))
400 + responseHandler = tqx_value;
401 + else if(!strcmp(tqx_name, "outFileName"))
402 + outFileName = tqx_value;
403 }
425 - } while (++i < end);
404 + }
405 }
406
407 // validate the google parameters given
@@ -509,14 +488,6 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
488 buffer_strcat(w->response.data, ");");
489
490 cleanup:
512 - if(end) {
513 - uint32_t i = 0;
514 - do {
515 - value = w->param_values[i].body;
516 - lvalue = w->param_values[i].length;
517 - value[lvalue] = save[i];
518 - } while ( ++i < end );
519 - }
491 buffer_free(dimensions);
492 return ret;
493 }
@@ -580,33 +551,26 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
551 int redirects = 0;
552 */
553
583 - uint32_t i = 0;
584 - uint32_t end = w->total_params;
585 - if (!end) {
586 - goto nothing;
587 - }
554 + while(url) {
555 + char *value = mystrsep(&url, "&");
556 + if (!value || !*value) continue;
557
589 - do {
590 - char *name = w->param_name[i].body;
591 - size_t nlength = w->param_name[i].length;
592 - char *value = w->param_values[i].body;
593 - size_t vlength = w->param_values[i].length;
558 + char *name = mystrsep(&value, "=");
559 + if (!name || !*name) continue;
560 + if (!value || !*value) continue;
561
562 debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
563
597 - //uint32_t hash = simple_hash(name);
598 - uint32_t hash = simple_nhash(name,nlength);
564 + uint32_t hash = simple_hash(name);
565
600 - //if(hash == hash_action && !strcmp(name, "action")) {
601 - if(hash == hash_action && !strncmp(name, "action",nlength)) {
602 - //uint32_t vhash = simple_hash(value);
603 - uint32_t vhash = simple_nhash(value,vlength);
566 + if(hash == hash_action && !strcmp(name, "action")) {
567 + uint32_t vhash = simple_hash(value);
568
605 - if(vhash == hash_access && !strncmp(value, "access",vlength)) action = 'A';
606 - else if(vhash == hash_hello && !strncmp(value, "hello",vlength)) action = 'H';
607 - else if(vhash == hash_delete && !strncmp(value, "delete",vlength)) action = 'D';
608 - else if(vhash == hash_search && !strncmp(value, "search",vlength)) action = 'S';
609 - else if(vhash == hash_switch && !strncmp(value, "switch",vlength)) action = 'W';
569 + if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
570 + else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
571 + else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
572 + else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
573 + else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
574 #ifdef NETDATA_INTERNAL_CHECKS
575 else error("unknown registry action '%s'", value);
576 #endif /* NETDATA_INTERNAL_CHECKS */
@@ -615,34 +579,33 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
579 else if(hash == hash_redirects && !strcmp(name, "redirects"))
580 redirects = atoi(value);
581 */
618 - else if(hash == hash_machine && !strncmp(name, "machine",nlength))
582 + else if(hash == hash_machine && !strcmp(name, "machine"))
583 machine_guid = value;
584
621 - else if(hash == hash_url && !strncmp(name, "url",nlength))
585 + else if(hash == hash_url && !strcmp(name, "url"))
586 machine_url = value;
587
588 else if(action == 'A') {
625 - if(hash == hash_name && !strncmp(name, "name",nlength))
589 + if(hash == hash_name && !strcmp(name, "name"))
590 url_name = value;
591 }
592 else if(action == 'D') {
629 - if(hash == hash_delete_url && !strncmp(name, "delete_url",nlength))
593 + if(hash == hash_delete_url && !strcmp(name, "delete_url"))
594 delete_url = value;
595 }
596 else if(action == 'S') {
633 - if(hash == hash_for && !strncmp(name, "for",nlength))
597 + if(hash == hash_for && !strcmp(name, "for"))
598 search_machine_guid = value;
599 }
600 else if(action == 'W') {
637 - if(hash == hash_to && !strncmp(name, "to",nlength))
601 + if(hash == hash_to && !strcmp(name, "to"))
602 to_person_guid = value;
603 }
604 #ifdef NETDATA_INTERNAL_CHECKS
605 else error("unused registry URL parameter '%s' with value '%s'", name, value);
606 #endif /* NETDATA_INTERNAL_CHECKS */
643 - } while (++i < end );
607 + }
608
645 -nothing:
609 if(unlikely(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w))) {
610 buffer_flush(w->response.data);
611 buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
@@ -834,27 +797,28 @@ inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *
797 }
798
799 // get the command
800 + char *tok = mystrsep(&url, "?");
801 + if(tok && *tok) {
802 + debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
803 + uint32_t hash = simple_hash(tok);
804
838 - char *cmd = w->command.body;
839 - size_t length = w->command.length;
840 - uint32_t hash = simple_nhash(cmd,length);
841 -
842 - for(i = 0; api_commands[i].command ;i++) {
843 - if(unlikely(hash == api_commands[i].hash && !strncmp(cmd, api_commands[i].command,length))) {
844 - if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl))
845 - return web_client_permission_denied(w);
805 + for(i = 0; api_commands[i].command ;i++) {
806 + if(unlikely(hash == api_commands[i].hash && !strcmp(tok, api_commands[i].command))) {
807 + if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl))
808 + return web_client_permission_denied(w);
809
847 - return api_commands[i].callback(host, w, url);
810 + return api_commands[i].callback(host, w, url);
811 + }
812 }
849 - }
850 -
851 - char copyme[256];
852 - length = w->path.length;
853 - memcpy(copyme,w->path.body,length);
854 - copyme[length] = 0x00;
813
856 - buffer_flush(w->response.data);
857 - buffer_strcat(w->response.data, "Unsupported v1 API command: ");
858 - buffer_strcat_htmlescape(w->response.data, copyme);
859 - return 404;
814 + buffer_flush(w->response.data);
815 + buffer_strcat(w->response.data, "Unsupported v1 API command: ");
816 + buffer_strcat_htmlescape(w->response.data, tok);
817 + return 404;
818 + }
819 + else {
820 + buffer_flush(w->response.data);
821 + buffer_sprintf(w->response.data, "Which API v1 command?");
822 + return 400;
823 + }
824 }
web/server/web_client.c
+160 -353
@@ -143,7 +143,7 @@ void web_client_request_done(struct web_client *w) {
143 debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
144
145 if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
146 - if (w->ifd != -1) {
146 + if (w->ifd != -1){
147 close(w->ifd);
148 }
149 }
@@ -352,7 +352,7 @@ int mysendfile(struct web_client *w, char *filename) {
352 // if the filename contains "strange" characters, refuse to serve it
353 char *s;
354 for(s = filename; *s ;s++) {
355 - if(!isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
355 + if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
356 debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
357 w->response.data->contenttype = CT_TEXT_HTML;
358 buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
@@ -594,26 +594,15 @@ int web_client_api_request(RRDHOST *host, struct web_client *w, char *url)
594 {
595 // get the api version
596 char *tok = mystrsep(&url, "/");
597 - (void)tok;
598 - char *body = w->version.body;
599 - size_t length = w->version.length;
600 - if(body) {
601 - //if(tok && *tok) {
602 - //debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
603 - debug(D_WEB_CLIENT, "%llu: Searching for API version'.", w->id);
604 - //if(strcmp(tok, "v1") == 0)
605 - if(strncmp(body, "v1",length) == 0) {
597 + if(tok && *tok) {
598 + debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
599 + if(strcmp(tok, "v1") == 0)
600 return web_client_api_request_v1(host, w, url);
607 - } else {
608 - char response[NETDATA_WEB_REQUEST_URL_SIZE];
609 - strncpy(response,w->version.body,length);
610 - response[length] = 0x00;
601 + else {
602 buffer_flush(w->response.data);
612 -
603 w->response.data->contenttype = CT_TEXT_HTML;
604 buffer_strcat(w->response.data, "Unsupported API version: ");
615 - buffer_strcat_htmlescape(w->response.data, response);
616 - //buffer_strcat_htmlescape(w->response.data, tok);
605 + buffer_strcat_htmlescape(w->response.data, tok);
606 return 404;
607 }
608 }
@@ -802,7 +791,7 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
791 } else if(hash == hash_authorization&& !strcasecmp(s, "X-Auth-Token")) {
792 w->auth_bearer_token = strdupz(v);
793 }
805 - else if(hash == hash_host && !strcasecmp(s, "Host")) {
794 + else if(hash == hash_host && !strcasecmp(s, "Host")){
795 strncpyz(w->host, v, (ve - v));
796 }
797 #ifdef NETDATA_WITH_ZLIB
@@ -823,67 +812,76 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
812 return ve;
813 }
814
826 -static inline HTTP_VALIDATION web_client_is_complete(char *begin,char *end,size_t length){
827 - if ( begin == end){
828 - return HTTP_VALIDATION_INCOMPLETE;
829 - }
815 +// http_request_validate()
816 +// returns:
817 +// = 0 : all good, process the request
818 +// > 0 : request is not supported
819 +// < 0 : request is incomplete - wait for more data
820
831 - if ( length > 3 ){
832 - begin = end - 4;
833 - }
821 +typedef enum {
822 + HTTP_VALIDATION_OK,
823 + HTTP_VALIDATION_NOT_SUPPORTED,
824 +#ifdef ENABLE_HTTPS
825 + HTTP_VALIDATION_INCOMPLETE,
826 + HTTP_VALIDATION_REDIRECT
827 +#else
828 + HTTP_VALIDATION_INCOMPLETE
829 +#endif
830 +} HTTP_VALIDATION;
831
835 - uint32_t counter = 0;
836 - do{
837 - if (*begin == '\r'){
838 - begin++;
839 - if ( begin == end )
840 - {
841 - break;
842 - }
832 +static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
833 + char *s = (char *)buffer_tostring(w->response.data), *encoded_url = NULL;
834 +
835 + size_t last_pos = w->header_parse_last_size;
836 + if(last_pos > 4) last_pos -= 4; // allow searching for \r\n\r\n
837 + else last_pos = 0;
838
844 - if (*begin == '\n')
845 - {
846 - counter++;
839 + w->header_parse_tries++;
840 + w->header_parse_last_size = buffer_strlen(w->response.data);
841 +
842 + if(w->header_parse_tries > 1) {
843 + if(w->header_parse_last_size < last_pos)
844 + last_pos = 0;
845 +
846 + if(strstr(&s[last_pos], "\r\n\r\n") == NULL) {
847 + if(w->header_parse_tries > 10) {
848 + info("Disabling slow client after %zu attempts to read the request (%zu bytes received)", w->header_parse_tries, buffer_strlen(w->response.data));
849 + w->header_parse_tries = 0;
850 + w->header_parse_last_size = 0;
851 + web_client_disable_wait_receive(w);
852 + return HTTP_VALIDATION_NOT_SUPPORTED;
853 }
848 - } else if (*begin == '\n') {
849 - begin++;
850 - counter++;
851 - }
854
853 - if ( counter == 2){
854 - break;
855 + return HTTP_VALIDATION_INCOMPLETE;
856 }
857 }
857 - while(begin != end);
858
859 - return (counter == 2)?HTTP_VALIDATION_OK:HTTP_VALIDATION_INCOMPLETE;
860 -}
861 -
862 -static inline char *web_client_parse_method(struct web_client *w,char *s) {
859 + // is is a valid request?
860 if(!strncmp(s, "GET ", 4)) {
864 - s = &s[4];
861 + encoded_url = s = &s[4];
862 w->mode = WEB_CLIENT_MODE_NORMAL;
863 }
864 else if(!strncmp(s, "OPTIONS ", 8)) {
868 - s = &s[8];
865 + encoded_url = s = &s[8];
866 w->mode = WEB_CLIENT_MODE_OPTIONS;
867 }
868 else if(!strncmp(s, "STREAM ", 7)) {
869 #ifdef ENABLE_HTTPS
873 - if ((w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)) {
870 + if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
871 w->header_parse_tries = 0;
872 w->header_parse_last_size = 0;
873 web_client_disable_wait_receive(w);
874 char hostname[256];
875 char *copyme = strstr(s,"hostname=");
879 - if (copyme) {
876 + if ( copyme ){
877 copyme += 9;
878 char *end = strchr(copyme,'&');
882 - if(end) {
879 + if(end){
880 size_t length = end - copyme;
881 memcpy(hostname,copyme,length);
882 hostname[length] = 0X00;
886 - } else {
883 + }
884 + else{
885 memcpy(hostname,"not available",13);
886 hostname[13] = 0x00;
887 }
@@ -893,205 +891,30 @@ static inline char *web_client_parse_method(struct web_client *w,char *s) {
891 hostname[13] = 0x00;
892 }
893 error("The server is configured to always use encrypt connection, please enable the SSL on slave with hostname '%s'.",hostname);
896 - return NULL;
894 + return HTTP_VALIDATION_NOT_SUPPORTED;
895 }
896 #endif
899 - s = &s[7];
897 +
898 + encoded_url = s = &s[7];
899 w->mode = WEB_CLIENT_MODE_STREAM;
900 }
901 else {
903 - s = NULL;
904 - }
905 -
906 - return s;
907 -}
908 -
909 -static inline char *web_client_find_protocol(struct web_client *w,char *s) {
910 - s = url_find_protocol(s);
911 -
912 - w->protocol.body = s+1;
913 - char *end = strchr(s+6,'\n');
914 - if (end) {
915 - w->protocol.length = end - w->protocol.body ;
916 - }
917 -
918 - return s;
919 -}
920 -
921 -static inline void web_client_parse_headers(struct web_client *w,char *s) {
922 - while(*s) {
923 - // find a line feed
924 - while(*s && *s++ != '\r');
925 -
926 - // did we reach the end?
927 - if(unlikely(!*s)) break;
928 -
929 - if (*s == '\n') {
930 - s++;
931 - }
932 -
933 - s = http_header_parse(w, s,
934 - (w->mode == WEB_CLIENT_MODE_STREAM) // parse user agent
935 - );
936 -
937 - }
938 -}
939 -
940 -int web_client_parse_request(struct web_client *w,char *divisor) {
941 - if(!divisor) {
942 - w->total_params = 0;
943 - return 0;
944 - }
945 -
946 - uint32_t i = url_parse_query_string(w->param_name,w->param_values,w->query_string.body+1,divisor);
947 - w->total_params = i;
948 -
949 - return i;
950 -}
951 -
952 -static inline void web_client_set_directory(struct web_client *w,char *begin,char *enddir,char *endcmd) {
953 - if (enddir) {
954 - w->directory.body = begin;
955 - w->directory.length = enddir - begin;
956 -
957 - if (!strncmp(w->directory.body,"api",w->directory.length)) {
958 - begin = enddir + 1;
959 - enddir = strchr(begin,'/');
960 - if(enddir) {
961 - w->version.body = begin;
962 - w->version.length = enddir - begin;
963 -
964 - enddir++;
965 - w->command.body = enddir;
966 - w->command.length = (size_t) (endcmd - enddir);
967 - }
968 - }
969 - }
970 - else{
971 - w->directory.body = begin;
972 - w->directory.length = w->path.length - 1;
973 - w->version.body = NULL;
974 - w->version.length = 0;
975 - w->command.body = NULL;
976 - w->command.length = 0;
977 - }
978 -}
979 -
980 -static inline void web_client_set_without_query_string(struct web_client *w) {
981 - w->query_string.body = NULL;
982 - w->query_string.length = 0;
983 -
984 - char *test = w->path.body+1;
985 - if (!strncmp(test,"api/v1/",7) ) {
986 - test += 7;
987 - if (!strncmp(test,"info",4)) {
988 - w->command.length = 4;
989 - }
990 - else if (!strncmp(test,"charts",6)) {
991 - w->command.length = 6;
992 - }
993 - else {
994 - test = NULL;
995 - w->command.length = 0;
996 - }
997 - }else{
998 - w->command.length = w->path.length;
999 - }
1000 - w->command.body = test;
1001 - w->total_params = 0;
1002 -}
1003 -
1004 -static inline void web_client_split_path_query(struct web_client *w) {
1005 - w->path.body = w->decoded_url;
1006 - w->decoded_length = strlen(w->decoded_url);
1007 - char *moveme = strchr(w->path.body,'?');
1008 - char *enddir;
1009 - if (moveme) {
1010 - w->path.length = moveme - w->path.body;
1011 - w->query_string.body = moveme;
1012 - w->query_string.length = w->decoded_length - w->path.length;
1013 -
1014 - enddir = strchr(w->path.body+1,'/');
1015 - char *begin = w->path.body+1;
1016 - web_client_set_directory(w,begin,enddir,moveme);
1017 - if (w->query_string.body) {
1018 - enddir = strchr(moveme,'=');
1019 - if (!web_client_parse_request(w,enddir) ) {
1020 - moveme++;
1021 - size_t length = strlen(moveme);
1022 - w->param_name[0].body = moveme;
1023 - w->param_name[0].length = length;
1024 - w->param_values[0].body = moveme;
1025 - w->param_values[0].length = length;
1026 -
1027 - w->total_params = 1;
1028 - }
1029 - }
1030 - } else {
1031 - w->path.length = w->decoded_length;
1032 -
1033 - enddir = strchr(w->path.body+1,'/');
1034 - w->directory.body = w->path.body + 1;
1035 - if(enddir) {
1036 - w->directory.length = (size_t)(enddir - w->directory.body);
1037 - enddir++;
1038 -
1039 - w->version.body = enddir;
1040 - enddir = strchr(++enddir,'/');
1041 - if(enddir) {
1042 - w->version.length = (size_t)(enddir - w->version.body);
1043 -
1044 - enddir++;
1045 - w->command.body = enddir;
1046 - w->command.length = (size_t)(moveme - enddir);
1047 - } else{
1048 - w->version.length = strlen(w->version.body);
1049 - }
1050 -
1051 - }else {
1052 - w->directory.length = w->decoded_length - 1;
1053 - }
1054 - web_client_set_without_query_string(w);
1055 - }
1056 -}
1057 -
1058 -static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
1059 - char *s = (char *)buffer_tostring(w->response.data), *encoded_url = NULL;
1060 - size_t status;
1061 -
1062 - w->header_parse_tries++;
1063 - w->header_parse_last_size = buffer_strlen(w->response.data);
1064 - status = w->header_parse_last_size;
1065 -
1066 - // make sure we have complete request
1067 - // complete requests contain: \r\n\r\n
1068 - status = url_is_request_complete(s,&s[status],status);
1069 - if (w->header_parse_tries > 10) {
1070 - if (status == HTTP_VALIDATION_INCOMPLETE) {
1071 - info("Disabling slow client after %zu attempts to read the request (%zu bytes received)", w->header_parse_tries, buffer_strlen(w->response.data));
1072 - w->header_parse_tries = 0;
1073 - w->header_parse_last_size = 0;
1074 - web_client_disable_wait_receive(w);
1075 - return HTTP_VALIDATION_NOT_SUPPORTED;
1076 - }
1077 - } else{
1078 - if (status == HTTP_VALIDATION_INCOMPLETE) {
1079 - web_client_enable_wait_receive(w);
1080 - return HTTP_VALIDATION_INCOMPLETE;
1081 - }
1082 - }
1083 - //Parse the method used to communicate
1084 - s = web_client_parse_method(w,s);
1085 - if (!s) {
902 w->header_parse_tries = 0;
903 w->header_parse_last_size = 0;
904 web_client_disable_wait_receive(w);
905 return HTTP_VALIDATION_NOT_SUPPORTED;
906 }
907
1092 - encoded_url = s;
908 + // find the SPACE + "HTTP/"
909 + while(*s) {
910 + // find the next space
911 + while (*s && *s != ' ') s++;
912 +
913 + // is it SPACE + "HTTP/" ?
914 + if(*s && !strncmp(s, " HTTP/", 6)) break;
915 + else s++;
916 + }
917
1094 - s = web_client_find_protocol(w,s);
918 // incomplete requests
919 if(unlikely(!*s)) {
920 web_client_enable_wait_receive(w);
@@ -1101,40 +924,64 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
924 // we have the end of encoded_url - remember it
925 char *ue = s;
926
1104 - *ue = '\0';
1105 - url_decode_r(w->decoded_url, encoded_url, NETDATA_WEB_REQUEST_URL_SIZE + 1);
927 + // make sure we have complete request
928 + // complete requests contain: \r\n\r\n
929 + while(*s) {
930 + // find a line feed
931 + while(*s && *s++ != '\r');
932 +
933 + // did we reach the end?
934 + if(unlikely(!*s)) break;
935
1107 - web_client_split_path_query(w);
1108 - *ue = ' ';
1109 - web_client_parse_headers(w,s);
936 + // is it \r\n ?
937 + if(likely(*s++ == '\n')) {
938
1111 - // copy the URL - we are going to overwrite parts of it
1112 - // TODO -- ideally we we should avoid copying buffers around
1113 - strncpyz(w->last_url, w->decoded_url, NETDATA_WEB_REQUEST_URL_SIZE);
939 + // is it again \r\n ? (header end)
940 + if(unlikely(*s == '\r' && s[1] == '\n')) {
941 + // a valid complete HTTP request found
942
943 + *ue = '\0';
944 + url_decode_r(w->decoded_url, encoded_url, NETDATA_WEB_REQUEST_URL_SIZE + 1);
945 + *ue = ' ';
946 +
947 + // copy the URL - we are going to overwrite parts of it
948 + // TODO -- ideally we we should avoid copying buffers around
949 + strncpyz(w->last_url, w->decoded_url, NETDATA_WEB_REQUEST_URL_SIZE);
950 #ifdef ENABLE_HTTPS
1116 - if ((!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1117 - if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (netdata_use_ssl_on_http & NETDATA_SSL_FORCE) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
1118 - w->header_parse_tries = 0;
1119 - w->header_parse_last_size = 0;
1120 - web_client_disable_wait_receive(w);
1121 - return HTTP_VALIDATION_REDIRECT;
951 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
952 + if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (netdata_use_ssl_on_http & NETDATA_SSL_FORCE) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
953 + w->header_parse_tries = 0;
954 + w->header_parse_last_size = 0;
955 + web_client_disable_wait_receive(w);
956 + return HTTP_VALIDATION_REDIRECT;
957 + }
958 + }
959 +#endif
960 +
961 + w->header_parse_tries = 0;
962 + w->header_parse_last_size = 0;
963 + web_client_disable_wait_receive(w);
964 + return HTTP_VALIDATION_OK;
965 + }
966 +
967 + // another header line
968 + s = http_header_parse(w, s,
969 + (w->mode == WEB_CLIENT_MODE_STREAM) // parse user agent
970 + );
971 }
972 }
1124 -#endif
973
1126 - w->header_parse_tries = 0;
1127 - w->header_parse_last_size = 0;
1128 - web_client_disable_wait_receive(w);
1129 - return HTTP_VALIDATION_OK;
974 + // incomplete request
975 + web_client_enable_wait_receive(w);
976 + return HTTP_VALIDATION_INCOMPLETE;
977 }
978
979 static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
980 {
981 ssize_t bytes;
982 #ifdef ENABLE_HTTPS
1136 - if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
1137 - if ((w->ssl.conn) && (!w->ssl.flags)) {
983 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
984 + if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
985 bytes = SSL_write(w->ssl.conn,buf, len) ;
986 } else {
987 bytes = send(w->ofd,buf, len , flags);
@@ -1255,7 +1102,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
1102 buffer_sprintf(w->response.header_output,
1103 "Cache-Control: %s\r\n"
1104 "Expires: %s\r\n",
1258 - (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
1105 + (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache, no-store, must-revalidate\r\nPragma: no-cache":"public",
1106 edate);
1107 }
1108
@@ -1296,8 +1143,8 @@ static inline void web_client_send_http_header(struct web_client *w) {
1143 size_t count = 0;
1144 ssize_t bytes;
1145 #ifdef ENABLE_HTTPS
1299 - if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
1300 - if ((w->ssl.conn) && (!w->ssl.flags)) {
1146 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1147 + if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
1148 while((bytes = SSL_write(w->ssl.conn, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output))) < 0) {
1149 count++;
1150 if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
@@ -1366,52 +1213,21 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1213 return 400;
1214 }
1215
1369 - char *tok = strchr(url,'/');
1370 - if (tok) {
1371 - w->switch_host = 1;
1372 - debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, url);
1216 + char *tok = mystrsep(&url, "/");
1217 + if(tok && *tok) {
1218 + debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, tok);
1219
1220 // copy the URL, we need it to serve files
1221 w->last_url[0] = '/';
1376 - if(*(tok+1) != ' ') {
1377 - strncpyz(&w->last_url[1], tok+1, NETDATA_WEB_REQUEST_URL_SIZE - 1);
1378 - char *enddir;
1379 - if (w->total_params) {
1380 - enddir = strchr(tok+1,'/');
1381 - if (enddir) {
1382 - char *moveme = strchr(enddir,'?');
1383 - if (moveme) {
1384 - web_client_set_directory(w,tok+1,enddir,moveme);
1385 - }
1386 - }
1387 - else {
1388 - w->directory.body = tok;
1389 - w->directory.length = strlen(tok);
1390 - }
1391 - } else {
1392 - enddir = strchr(tok+1,'/');
1393 - if(enddir) {
1394 - w->directory.body = tok + 1;
1395 - w->directory.length = enddir - tok - 1;
1396 - } else {
1397 - if (!strlen(tok + 1)) {
1398 - w->directory.body = tok;
1399 - w->directory.length = 1;
1400 - }
1401 - }
1402 - }
1403 - }
1404 - else {
1405 - w->last_url[1] = '\0';
1406 - }
1407 - *tok = 0x00;
1408 - uint32_t hash = simple_hash(url);
1222 + if(url && *url) strncpyz(&w->last_url[1], url, NETDATA_WEB_REQUEST_URL_SIZE - 1);
1223 + else w->last_url[1] = '\0';
1224 +
1225 + uint32_t hash = simple_hash(tok);
1226
1410 - host = rrdhost_find_by_hostname(url, hash);
1411 - if(!host) host = rrdhost_find_by_guid(url, hash);
1412 - *tok = '/';
1227 + host = rrdhost_find_by_hostname(tok, hash);
1228 + if(!host) host = rrdhost_find_by_guid(tok, hash);
1229
1414 - if(host) return web_client_process_url(host, w, tok);
1230 + if(host) return web_client_process_url(host, w, url);
1231 }
1232
1233 buffer_flush(w->response.data);
@@ -1442,21 +1258,20 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1258 #endif
1259 }
1260
1445 - if (w->path.length > 1) {
1446 - char *cmp = w->directory.body;
1447 - size_t len = w->directory.length;
1448 - uint32_t hash = simple_nhash(cmp,len);
1449 - debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, w->command.body);
1261 + char *tok = mystrsep(&url, "/?");
1262 + if(likely(tok && *tok)) {
1263 + uint32_t hash = simple_hash(tok);
1264 + debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1265
1451 - if(unlikely(hash == hash_api && strncmp(cmp, "api",len) == 0)) { // current API
1266 + if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
1267 debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
1268 return check_host_and_call(host, w, url, web_client_api_request);
1269 }
1455 - else if(unlikely(hash == hash_host && strncmp(cmp, "host",len) == 0)) { // host switching
1270 + else if(unlikely(hash == hash_host && strcmp(tok, "host") == 0)) { // host switching
1271 debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
1457 - return web_client_switch_host(host, w, cmp+5);
1272 + return web_client_switch_host(host, w, url);
1273 }
1459 - else if(unlikely(hash == hash_netdata_conf && strncmp(cmp, "netdata.conf",len) == 0)) { // current API
1274 + else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
1275 if(unlikely(!web_client_can_access_netdataconf(w)))
1276 return web_client_permission_denied(w);
1277
@@ -1467,7 +1282,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1282 return 200;
1283 }
1284 #ifdef NETDATA_INTERNAL_CHECKS
1470 - else if(unlikely(hash == hash_exit && strncmp(cmp, "exit",len) == 0)) {
1285 + else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) {
1286 if(unlikely(!web_client_can_access_netdataconf(w)))
1287 return web_client_permission_denied(w);
1288
@@ -1483,50 +1298,47 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1298 netdata_cleanup_and_exit(0);
1299 return 200;
1300 }
1486 - else if(unlikely(hash == hash_debug && strncmp(cmp, "debug",len) == 0)) {
1301 + else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) {
1302 if(unlikely(!web_client_can_access_netdataconf(w)))
1303 return web_client_permission_denied(w);
1304
1305 buffer_flush(w->response.data);
1306
1307 // get the name of the data to show
1493 - char *tok = mystrsep(&url, "/?");
1494 - if(likely(tok && *tok)) {
1495 - tok = mystrsep(&url, "&");
1496 - if(tok && *tok) {
1497 - debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1498 -
1499 - // do we have such a data set?
1500 - RRDSET *st = rrdset_find_byname(host, tok);
1501 - if(!st) st = rrdset_find(host, tok);
1502 - if(!st) {
1503 - w->response.data->contenttype = CT_TEXT_HTML;
1504 - buffer_strcat(w->response.data, "Chart is not found: ");
1505 - buffer_strcat_htmlescape(w->response.data, tok);
1506 - debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
1507 - return 404;
1508 - }
1509 -
1510 - debug_flags |= D_RRD_STATS;
1511 -
1512 - if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))
1513 - rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
1514 - else
1515 - rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
1516 -
1308 + tok = mystrsep(&url, "&");
1309 + if(tok && *tok) {
1310 + debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1311 +
1312 + // do we have such a data set?
1313 + RRDSET *st = rrdset_find_byname(host, tok);
1314 + if(!st) st = rrdset_find(host, tok);
1315 + if(!st) {
1316 w->response.data->contenttype = CT_TEXT_HTML;
1518 - buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
1317 + buffer_strcat(w->response.data, "Chart is not found: ");
1318 buffer_strcat_htmlescape(w->response.data, tok);
1520 - debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
1521 - return 200;
1319 + debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
1320 + return 404;
1321 }
1322 +
1323 + debug_flags |= D_RRD_STATS;
1324 +
1325 + if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))
1326 + rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
1327 + else
1328 + rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
1329 +
1330 + w->response.data->contenttype = CT_TEXT_HTML;
1331 + buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
1332 + buffer_strcat_htmlescape(w->response.data, tok);
1333 + debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
1334 + return 200;
1335 }
1336
1337 buffer_flush(w->response.data);
1338 buffer_strcat(w->response.data, "debug which chart?\r\n");
1339 return 400;
1340 }
1529 - else if(unlikely(hash == hash_mirror && strncmp(cmp, "mirror",len) == 0)) {
1341 + else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) {
1342 if(unlikely(!web_client_can_access_netdataconf(w)))
1343 return web_client_permission_denied(w);
1344
@@ -1543,17 +1355,12 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1355 #endif /* NETDATA_INTERNAL_CHECKS */
1356 }
1357
1546 - w->switch_host = 0;
1547 - char *tok = mystrsep(&url, "/?");
1548 - (void)tok;
1549 -
1358 char filename[FILENAME_MAX+1];
1359 url = filename;
1360 strncpyz(filename, w->last_url, FILENAME_MAX);
1361 tok = mystrsep(&url, "?");
1362 buffer_flush(w->response.data);
1555 -
1556 - return mysendfile(w, (w->path.length > 1)?tok:"/");
1363 + return mysendfile(w, (tok && *tok)?tok:"/");
1364 }
1365
1366 void web_client_process_request(struct web_client *w) {
@@ -2005,8 +1812,8 @@ ssize_t web_client_receive(struct web_client *w)
1812 buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_RECEIVE_SIZE);
1813
1814 #ifdef ENABLE_HTTPS
2008 - if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
2009 - if ((w->ssl.conn) && (!w->ssl.flags)) {
1815 + if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1816 + if ( ( w->ssl.conn ) && (!w->ssl.flags)) {
1817 bytes = SSL_read(w->ssl.conn, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
1818 }else {
1819 bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
web/server/web_client.h
-12
@@ -128,18 +128,6 @@ struct web_client {
128 char client_port[NI_MAXSERV+1];
129
130 char decoded_url[NETDATA_WEB_REQUEST_URL_SIZE + 1]; // we decode the URL in this buffer
131 - size_t decoded_length;
132 - struct web_fields path;
133 - struct web_fields directory;
134 - struct web_fields query_string;
135 - struct web_fields version;
136 - struct web_fields command;
137 - struct web_fields protocol;
138 - struct web_fields param_name[WEB_FIELDS_MAX];
139 - struct web_fields param_values[WEB_FIELDS_MAX];
140 - uint32_t total_params;
141 - int switch_host;
142 -
131 char last_url[NETDATA_WEB_REQUEST_URL_SIZE+1]; // we keep a copy of the decoded URL here
132 char host[256];
133