New URL parser (#6070)
* URL_parser 3 * URL_parser rebase 2! * URL_parameter parsing 3 * URL_parameter parsing 4 * URL_parameter parsing 5 * URL_parser alarms * URL_parser finish the basic structure * URL_parser codacity fixes! * URL_parser scripts! * URL_parser codacy! * URL_parser rebase 3! * URL_parser host fixes! * URL_parser host fixes 2! * URL_parser fix spaces! * URL_parser error message! * URL_parser Christopher requests! * URL_parser alarms fixed! * URL_parser health fixed! * URL_parser rebase 4! * URL_parser C fix write format! * URL_parser fix bugs due cache!
thiagoftsm committed
Jun 6, 2019 at 17:01 UTC
58b7d95a7ec9c576f8a06bbab07f755846b5349a
10 files changed
+1056
-444
libnetdata/inlined.h
+28
@@ -31,6 +31,19 @@ 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
+
47
static inline uint32_t simple_uhash(const char *name) {
48
unsigned char *s = (unsigned char *) name;
49
uint32_t hval = 0x811c9dc5, c;
@@ -42,6 +55,21 @@ static inline uint32_t simple_uhash(const char *name) {
55
return hval;
56
}
57
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
+
73
static inline int simple_hash_strcmp(const char *name, const char *b, uint32_t *hash) {
74
unsigned char *s = (unsigned char *) name;
75
uint32_t hval = 0x811c9dc5;
libnetdata/url/url.c
+85
@@ -79,3 +79,88 @@ 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,4 +25,26 @@ 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
+
50
#endif /* NETDATA_URL_H */
tests/urls/requests.sh
new
+207
@@ -0,0 +1,207 @@
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>ime=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
+57
-40
@@ -889,6 +889,7 @@ 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;
893
int ret = 400;
894
buffer_flush(w->response.data);
895
@@ -912,46 +913,54 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
913
int group = RRDR_GROUPING_AVERAGE;
914
uint32_t options = 0x00000000;
915
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;
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 );
964
}
965
966
if(!chart || !*chart) {
@@ -1137,6 +1146,14 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
1146
}
1147
1148
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
+ }
1157
buffer_free(dimensions);
1158
return ret;
1159
}
web/api/exporters/allmetrics.c
+41
-38
@@ -18,54 +18,57 @@ 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;
22
int format = ALLMETRICS_SHELL;
23
const char *prometheus_server = w->client_ip;
24
uint32_t prometheus_backend_options = global_backend_options;
25
PROMETHEUS_OUTPUT_OPTIONS prometheus_output_options = PROMETHEUS_OUTPUT_TIMESTAMPS | ((global_backend_options & BACKEND_OPTION_SEND_NAMES)?PROMETHEUS_OUTPUT_NAMES:0);
26
const char *prometheus_prefix = global_backend_prefix;
27
27
- while(url) {
28
- char *value = mystrsep(&url, "&");
29
- if (!value || !*value) continue;
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;
36
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;
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;
66
65
- break;
67
+ break;
68
+ }
69
}
70
}
68
- }
71
+ } while( ++i < end);
72
}
73
74
buffer_flush(w->response.data);
web/api/health/health_cmdapi.c
+77
-68
@@ -31,13 +31,10 @@ void free_silencers(SILENCER *t) {
31
return;
32
}
33
34
-
35
-
34
int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) {
35
int ret = 400;
36
(void) host;
39
-
40
-
37
+ (void)url;
38
39
BUFFER *wb = w->response.data;
40
buffer_flush(wb);
@@ -73,75 +70,86 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
70
buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
71
ret = 403;
72
} else {
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();
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
}
122
- }
123
-
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);
112
} else {
140
- buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY);
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);
144
+ }
145
}
142
- }
146
+ key[lkey] = ksave ;
147
+ value[lvalue] = vsave ;
148
+
149
+ } while( ++i < end );
150
151
}
152
+
153
if (likely(silencer)) {
154
// Add the created instance to the linked list in silencers
155
silencer->next = silencers->silencers;
@@ -160,6 +168,7 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
168
ret = 200;
169
}
170
}
171
+
172
w->response.data = wb;
173
buffer_no_cacheable(w->response.data);
174
return ret;
web/api/web_api_v1.c
+174
-138
@@ -195,14 +195,18 @@ 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;
199
int all = 0;
200
200
- while(url) {
201
- char *value = mystrsep(&url, "&");
202
- if (!value || !*value) continue;
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;
206
204
- if(!strcmp(value, "all")) all = 1;
205
- else if(!strcmp(value, "active")) all = 0;
207
+ if(!strncmp(value, "all",3)) all = 1;
208
+ else if(!strncmp(value, "active",6)) all = 0;
209
+ } while(++i < end);
210
}
211
212
buffer_flush(w->response.data);
@@ -213,17 +217,24 @@ inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w,
217
}
218
219
inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) {
220
+ (void)url;
221
uint32_t after = 0;
222
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);
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);
238
}
239
240
buffer_flush(w->response.data);
@@ -233,27 +244,29 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
244
}
245
246
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;
248
int ret = 400;
249
char *chart = NULL;
250
251
buffer_flush(w->response.data);
252
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
- //}
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);
270
}
271
272
if(!chart || !*chart) {
@@ -307,6 +320,7 @@ void fix_google_param(char *s) {
320
321
// returns the HTTP code
322
inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
323
+ (void)url;
324
debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
325
326
int ret = 400;
@@ -333,75 +347,82 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
347
uint32_t format = DATASOURCE_JSON;
348
uint32_t options = 0x00000000;
349
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);
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;
423
}
399
- else if(!strcmp(tqx_name, "responseHandler"))
400
- responseHandler = tqx_value;
401
- else if(!strcmp(tqx_name, "outFileName"))
402
- outFileName = tqx_value;
424
}
404
- }
425
+ } while (++i < end);
426
}
427
428
// validate the google parameters given
@@ -488,6 +509,14 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
509
buffer_strcat(w->response.data, ");");
510
511
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
+ }
520
buffer_free(dimensions);
521
return ret;
522
}
@@ -551,26 +580,33 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
580
int redirects = 0;
581
*/
582
554
- while(url) {
555
- char *value = mystrsep(&url, "&");
556
- if (!value || !*value) continue;
583
+ uint32_t i = 0;
584
+ uint32_t end = w->total_params;
585
+ if (!end) {
586
+ goto nothing;
587
+ }
588
558
- char *name = mystrsep(&value, "=");
559
- if (!name || !*name) continue;
560
- if (!value || !*value) continue;
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;
594
595
debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
596
564
- uint32_t hash = simple_hash(name);
597
+ //uint32_t hash = simple_hash(name);
598
+ uint32_t hash = simple_nhash(name,nlength);
599
566
- if(hash == hash_action && !strcmp(name, "action")) {
567
- uint32_t vhash = simple_hash(value);
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);
604
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';
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';
610
#ifdef NETDATA_INTERNAL_CHECKS
611
else error("unknown registry action '%s'", value);
612
#endif /* NETDATA_INTERNAL_CHECKS */
@@ -579,33 +615,34 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
615
else if(hash == hash_redirects && !strcmp(name, "redirects"))
616
redirects = atoi(value);
617
*/
582
- else if(hash == hash_machine && !strcmp(name, "machine"))
618
+ else if(hash == hash_machine && !strncmp(name, "machine",nlength))
619
machine_guid = value;
620
585
- else if(hash == hash_url && !strcmp(name, "url"))
621
+ else if(hash == hash_url && !strncmp(name, "url",nlength))
622
machine_url = value;
623
624
else if(action == 'A') {
589
- if(hash == hash_name && !strcmp(name, "name"))
625
+ if(hash == hash_name && !strncmp(name, "name",nlength))
626
url_name = value;
627
}
628
else if(action == 'D') {
593
- if(hash == hash_delete_url && !strcmp(name, "delete_url"))
629
+ if(hash == hash_delete_url && !strncmp(name, "delete_url",nlength))
630
delete_url = value;
631
}
632
else if(action == 'S') {
597
- if(hash == hash_for && !strcmp(name, "for"))
633
+ if(hash == hash_for && !strncmp(name, "for",nlength))
634
search_machine_guid = value;
635
}
636
else if(action == 'W') {
601
- if(hash == hash_to && !strcmp(name, "to"))
637
+ if(hash == hash_to && !strncmp(name, "to",nlength))
638
to_person_guid = value;
639
}
640
#ifdef NETDATA_INTERNAL_CHECKS
641
else error("unused registry URL parameter '%s' with value '%s'", name, value);
642
#endif /* NETDATA_INTERNAL_CHECKS */
607
- }
643
+ } while (++i < end );
644
645
+nothing:
646
if(unlikely(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w))) {
647
buffer_flush(w->response.data);
648
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.");
@@ -797,28 +834,27 @@ inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *
834
}
835
836
// 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);
837
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);
838
+ char *cmd = w->command.body;
839
+ size_t length = w->command.length;
840
+ uint32_t hash = simple_nhash(cmd,length);
841
810
- return api_commands[i].callback(host, w, url);
811
- }
812
- }
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);
846
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;
847
+ return api_commands[i].callback(host, w, url);
848
+ }
849
}
850
+
851
+ char copyme[256];
852
+ length = w->path.length;
853
+ memcpy(copyme,w->path.body,length);
854
+ copyme[length] = 0x00;
855
+
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;
860
}
web/server/web_client.c
+353
-160
@@ -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,15 +594,26 @@ 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
- if(tok && *tok) {
598
- debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
599
- if(strcmp(tok, "v1") == 0)
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) {
606
return web_client_api_request_v1(host, w, url);
601
- else {
607
+ } else {
608
+ char response[NETDATA_WEB_REQUEST_URL_SIZE];
609
+ strncpy(response,w->version.body,length);
610
+ response[length] = 0x00;
611
buffer_flush(w->response.data);
612
+
613
w->response.data->contenttype = CT_TEXT_HTML;
614
buffer_strcat(w->response.data, "Unsupported API version: ");
605
- buffer_strcat_htmlescape(w->response.data, tok);
615
+ buffer_strcat_htmlescape(w->response.data, response);
616
+ //buffer_strcat_htmlescape(w->response.data, tok);
617
return 404;
618
}
619
}
@@ -791,7 +802,7 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
802
} else if(hash == hash_authorization&& !strcasecmp(s, "X-Auth-Token")) {
803
w->auth_bearer_token = strdupz(v);
804
}
794
- else if(hash == hash_host && !strcasecmp(s, "Host")){
805
+ else if(hash == hash_host && !strcasecmp(s, "Host")) {
806
strncpyz(w->host, v, (ve - v));
807
}
808
#ifdef NETDATA_WITH_ZLIB
@@ -812,76 +823,67 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
823
return ve;
824
}
825
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
-
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
-
832
-static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
833
- char *s = (char *)buffer_tostring(w->response.data), *encoded_url = NULL;
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
+ }
830
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;
831
+ if ( length > 3 ){
832
+ begin = end - 4;
833
+ }
834
839
- w->header_parse_tries++;
840
- w->header_parse_last_size = buffer_strlen(w->response.data);
835
+ uint32_t counter = 0;
836
+ do{
837
+ if (*begin == '\r'){
838
+ begin++;
839
+ if ( begin == end )
840
+ {
841
+ break;
842
+ }
843
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;
844
+ if (*begin == '\n')
845
+ {
846
+ counter++;
847
}
848
+ } else if (*begin == '\n') {
849
+ begin++;
850
+ counter++;
851
+ }
852
855
- return HTTP_VALIDATION_INCOMPLETE;
853
+ if ( counter == 2){
854
+ break;
855
}
856
}
857
+ while(begin != end);
858
859
- // is is a valid request?
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) {
863
if(!strncmp(s, "GET ", 4)) {
861
- encoded_url = s = &s[4];
864
+ s = &s[4];
865
w->mode = WEB_CLIENT_MODE_NORMAL;
866
}
867
else if(!strncmp(s, "OPTIONS ", 8)) {
865
- encoded_url = s = &s[8];
868
+ s = &s[8];
869
w->mode = WEB_CLIENT_MODE_OPTIONS;
870
}
871
else if(!strncmp(s, "STREAM ", 7)) {
872
#ifdef ENABLE_HTTPS
870
- if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
873
+ if ((w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)) {
874
w->header_parse_tries = 0;
875
w->header_parse_last_size = 0;
876
web_client_disable_wait_receive(w);
877
char hostname[256];
878
char *copyme = strstr(s,"hostname=");
876
- if ( copyme ){
879
+ if (copyme) {
880
copyme += 9;
881
char *end = strchr(copyme,'&');
879
- if(end){
882
+ if(end) {
883
size_t length = end - copyme;
884
memcpy(hostname,copyme,length);
885
hostname[length] = 0X00;
883
- }
884
- else{
886
+ } else {
887
memcpy(hostname,"not available",13);
888
hostname[13] = 0x00;
889
}
@@ -891,30 +893,205 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
893
hostname[13] = 0x00;
894
}
895
error("The server is configured to always use encrypt connection, please enable the SSL on slave with hostname '%s'.",hostname);
894
- return HTTP_VALIDATION_NOT_SUPPORTED;
896
+ return NULL;
897
}
898
#endif
897
-
898
- encoded_url = s = &s[7];
899
+ s = &s[7];
900
w->mode = WEB_CLIENT_MODE_STREAM;
901
}
902
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) {
1086
w->header_parse_tries = 0;
1087
w->header_parse_last_size = 0;
1088
web_client_disable_wait_receive(w);
1089
return HTTP_VALIDATION_NOT_SUPPORTED;
1090
}
1091
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
- }
1092
+ encoded_url = s;
1093
1094
+ s = web_client_find_protocol(w,s);
1095
// incomplete requests
1096
if(unlikely(!*s)) {
1097
web_client_enable_wait_receive(w);
@@ -924,64 +1101,40 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
1101
// we have the end of encoded_url - remember it
1102
char *ue = s;
1103
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;
1104
+ *ue = '\0';
1105
+ url_decode_r(w->decoded_url, encoded_url, NETDATA_WEB_REQUEST_URL_SIZE + 1);
1106
936
- // is it \r\n ?
937
- if(likely(*s++ == '\n')) {
1107
+ web_client_split_path_query(w);
1108
+ *ue = ' ';
1109
+ web_client_parse_headers(w,s);
1110
939
- // is it again \r\n ? (header end)
940
- if(unlikely(*s == '\r' && s[1] == '\n')) {
941
- // a valid complete HTTP request found
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);
1114
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);
1115
#ifdef ENABLE_HTTPS
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
- );
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;
1122
}
1123
}
1124
+#endif
1125
974
- // incomplete request
975
- web_client_enable_wait_receive(w);
976
- return HTTP_VALIDATION_INCOMPLETE;
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;
1130
}
1131
1132
static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
1133
{
1134
ssize_t bytes;
1135
#ifdef ENABLE_HTTPS
983
- if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
984
- if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
1136
+ if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
1137
+ if ((w->ssl.conn) && (!w->ssl.flags)) {
1138
bytes = SSL_write(w->ssl.conn,buf, len) ;
1139
} else {
1140
bytes = send(w->ofd,buf, len , flags);
@@ -1102,7 +1255,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
1255
buffer_sprintf(w->response.header_output,
1256
"Cache-Control: %s\r\n"
1257
"Expires: %s\r\n",
1105
- (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache, no-store, must-revalidate\r\nPragma: no-cache":"public",
1258
+ (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache":"public",
1259
edate);
1260
}
1261
@@ -1143,8 +1296,8 @@ static inline void web_client_send_http_header(struct web_client *w) {
1296
size_t count = 0;
1297
ssize_t bytes;
1298
#ifdef ENABLE_HTTPS
1146
- if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1147
- if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
1299
+ if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
1300
+ if ((w->ssl.conn) && (!w->ssl.flags)) {
1301
while((bytes = SSL_write(w->ssl.conn, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output))) < 0) {
1302
count++;
1303
if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
@@ -1213,21 +1366,52 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1366
return 400;
1367
}
1368
1216
- char *tok = mystrsep(&url, "/");
1217
- if(tok && *tok) {
1218
- debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, tok);
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);
1373
1374
// copy the URL, we need it to serve files
1375
w->last_url[0] = '/';
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);
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);
1409
1227
- host = rrdhost_find_by_hostname(tok, hash);
1228
- if(!host) host = rrdhost_find_by_guid(tok, hash);
1410
+ host = rrdhost_find_by_hostname(url, hash);
1411
+ if(!host) host = rrdhost_find_by_guid(url, hash);
1412
+ *tok = '/';
1413
1230
- if(host) return web_client_process_url(host, w, url);
1414
+ if(host) return web_client_process_url(host, w, tok);
1415
}
1416
1417
buffer_flush(w->response.data);
@@ -1258,20 +1442,21 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1442
#endif
1443
}
1444
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);
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);
1450
1266
- if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
1451
+ if(unlikely(hash == hash_api && strncmp(cmp, "api",len) == 0)) { // current API
1452
debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
1453
return check_host_and_call(host, w, url, web_client_api_request);
1454
}
1270
- else if(unlikely(hash == hash_host && strcmp(tok, "host") == 0)) { // host switching
1455
+ else if(unlikely(hash == hash_host && strncmp(cmp, "host",len) == 0)) { // host switching
1456
debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
1272
- return web_client_switch_host(host, w, url);
1457
+ return web_client_switch_host(host, w, cmp+5);
1458
}
1274
- else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
1459
+ else if(unlikely(hash == hash_netdata_conf && strncmp(cmp, "netdata.conf",len) == 0)) { // current API
1460
if(unlikely(!web_client_can_access_netdataconf(w)))
1461
return web_client_permission_denied(w);
1462
@@ -1282,7 +1467,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1467
return 200;
1468
}
1469
#ifdef NETDATA_INTERNAL_CHECKS
1285
- else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) {
1470
+ else if(unlikely(hash == hash_exit && strncmp(cmp, "exit",len) == 0)) {
1471
if(unlikely(!web_client_can_access_netdataconf(w)))
1472
return web_client_permission_denied(w);
1473
@@ -1298,47 +1483,50 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1483
netdata_cleanup_and_exit(0);
1484
return 200;
1485
}
1301
- else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) {
1486
+ else if(unlikely(hash == hash_debug && strncmp(cmp, "debug",len) == 0)) {
1487
if(unlikely(!web_client_can_access_netdataconf(w)))
1488
return web_client_permission_denied(w);
1489
1490
buffer_flush(w->response.data);
1491
1492
// get the name of the data to show
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;
1317
- buffer_strcat(w->response.data, "Chart is not found: ");
1318
- buffer_strcat_htmlescape(w->response.data, tok);
1319
- debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
1320
- return 404;
1321
- }
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
1323
- debug_flags |= D_RRD_STATS;
1510
+ debug_flags |= D_RRD_STATS;
1511
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);
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
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;
1517
+ 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");
1519
+ 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;
1522
+ }
1523
}
1524
1525
buffer_flush(w->response.data);
1526
buffer_strcat(w->response.data, "debug which chart?\r\n");
1527
return 400;
1528
}
1341
- else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) {
1529
+ else if(unlikely(hash == hash_mirror && strncmp(cmp, "mirror",len) == 0)) {
1530
if(unlikely(!web_client_can_access_netdataconf(w)))
1531
return web_client_permission_denied(w);
1532
@@ -1355,12 +1543,17 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1543
#endif /* NETDATA_INTERNAL_CHECKS */
1544
}
1545
1546
+ w->switch_host = 0;
1547
+ char *tok = mystrsep(&url, "/?");
1548
+ (void)tok;
1549
+
1550
char filename[FILENAME_MAX+1];
1551
url = filename;
1552
strncpyz(filename, w->last_url, FILENAME_MAX);
1553
tok = mystrsep(&url, "?");
1554
buffer_flush(w->response.data);
1363
- return mysendfile(w, (tok && *tok)?tok:"/");
1555
+
1556
+ return mysendfile(w, (w->path.length > 1)?tok:"/");
1557
}
1558
1559
void web_client_process_request(struct web_client *w) {
@@ -1812,8 +2005,8 @@ ssize_t web_client_receive(struct web_client *w)
2005
buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_RECEIVE_SIZE);
2006
2007
#ifdef ENABLE_HTTPS
1815
- if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1816
- if ( ( w->ssl.conn ) && (!w->ssl.flags)) {
2008
+ if ((!web_client_check_unix(w)) && (netdata_srv_ctx)) {
2009
+ if ((w->ssl.conn) && (!w->ssl.flags)) {
2010
bytes = SSL_read(w->ssl.conn, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
2011
}else {
2012
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,6 +128,18 @@ 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
+
143
char last_url[NETDATA_WEB_REQUEST_URL_SIZE+1]; // we keep a copy of the decoded URL here
144
char host[256];
145