3 inline int web_client_api_request_v1_data_group(char *name, int def) {
4 if(!strcmp(name, "average"))
7 else if(!strcmp(name, "min"))
10 else if(!strcmp(name, "max"))
13 else if(!strcmp(name, "sum"))
16 else if(!strcmp(name, "incremental-sum"))
17 return GROUP_INCREMENTAL_SUM;
22 inline uint32_t web_client_api_request_v1_data_options(char *o) {
23 uint32_t ret = 0x00000000;
26 while(o && *o && (tok = mystrsep(&o, ", |"))) {
29 if(!strcmp(tok, "nonzero"))
30 ret |= RRDR_OPTION_NONZERO;
31 else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
32 ret |= RRDR_OPTION_REVERSED;
33 else if(!strcmp(tok, "jsonwrap"))
34 ret |= RRDR_OPTION_JSON_WRAP;
35 else if(!strcmp(tok, "min2max"))
36 ret |= RRDR_OPTION_MIN2MAX;
37 else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
38 ret |= RRDR_OPTION_MILLISECONDS;
39 else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
40 ret |= RRDR_OPTION_ABSOLUTE;
41 else if(!strcmp(tok, "seconds"))
42 ret |= RRDR_OPTION_SECONDS;
43 else if(!strcmp(tok, "null2zero"))
44 ret |= RRDR_OPTION_NULL2ZERO;
45 else if(!strcmp(tok, "objectrows"))
46 ret |= RRDR_OPTION_OBJECTSROWS;
47 else if(!strcmp(tok, "google_json"))
48 ret |= RRDR_OPTION_GOOGLE_JSON;
49 else if(!strcmp(tok, "percentage"))
50 ret |= RRDR_OPTION_PERCENTAGE;
51 else if(!strcmp(tok, "unaligned"))
52 ret |= RRDR_OPTION_NOT_ALIGNED;
58 inline uint32_t web_client_api_request_v1_data_format(char *name) {
59 if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
60 return DATASOURCE_DATATABLE_JSON;
62 else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
63 return DATASOURCE_DATATABLE_JSONP;
65 else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
66 return DATASOURCE_JSON;
68 else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
69 return DATASOURCE_JSONP;
71 else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
72 return DATASOURCE_SSV;
74 else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
75 return DATASOURCE_CSV;
77 else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
78 return DATASOURCE_TSV;
80 else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
81 return DATASOURCE_HTML;
83 else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
84 return DATASOURCE_JS_ARRAY;
86 else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
87 return DATASOURCE_SSV_COMMA;
89 else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
90 return DATASOURCE_CSV_JSON_ARRAY;
92 return DATASOURCE_JSON;
95 inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
96 if(!strcmp(name, "json"))
97 return DATASOURCE_DATATABLE_JSONP;
99 else if(!strcmp(name, "html"))
100 return DATASOURCE_HTML;
102 else if(!strcmp(name, "csv"))
103 return DATASOURCE_CSV;
105 else if(!strcmp(name, "tsv-excel"))
106 return DATASOURCE_TSV;
108 return DATASOURCE_JSON;
112 inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url) {
116 char *value = mystrsep(&url, "?&");
117 if (!value || !*value) continue;
119 if(!strcmp(value, "all")) all = 1;
120 else if(!strcmp(value, "active")) all = 0;
123 buffer_flush(w->response.data);
124 w->response.data->contenttype = CT_APPLICATION_JSON;
125 health_alarms2json(host, w->response.data, all);
129 inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) {
133 char *value = mystrsep(&url, "?&");
134 if (!value || !*value) continue;
136 char *name = mystrsep(&value, "=");
137 if(!name || !*name) continue;
138 if(!value || !*value) continue;
140 if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0);
143 buffer_flush(w->response.data);
144 w->response.data->contenttype = CT_APPLICATION_JSON;
145 health_alarm_log2json(host, w->response.data, after);
149 inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf)) {
153 buffer_flush(w->response.data);
156 char *value = mystrsep(&url, "?&");
157 if(!value || !*value) continue;
159 char *name = mystrsep(&value, "=");
160 if(!name || !*name) continue;
161 if(!value || !*value) continue;
163 // name and value are now the parameters
164 // they are not null and not empty
166 if(!strcmp(name, "chart")) chart = value;
168 /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
173 if(!chart || !*chart) {
174 buffer_sprintf(w->response.data, "No chart id is given at the request.");
178 RRDSET *st = rrdset_find(host, chart);
179 if(!st) st = rrdset_find_byname(host, chart);
181 buffer_strcat(w->response.data, "Chart is not found: ");
182 buffer_strcat_htmlescape(w->response.data, chart);
187 w->response.data->contenttype = CT_APPLICATION_JSON;
188 callback(st, w->response.data);
195 inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url) {
196 return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
199 inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url) {
202 buffer_flush(w->response.data);
203 w->response.data->contenttype = CT_APPLICATION_JSON;
204 rrd_stats_api_v1_charts(host, w->response.data);
208 inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) {
209 int format = ALLMETRICS_SHELL;
212 char *value = mystrsep(&url, "?&");
213 if (!value || !*value) continue;
215 char *name = mystrsep(&value, "=");
216 if(!name || !*name) continue;
217 if(!value || !*value) continue;
219 if(!strcmp(name, "format")) {
220 if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
221 format = ALLMETRICS_SHELL;
222 else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
223 format = ALLMETRICS_PROMETHEUS;
229 buffer_flush(w->response.data);
230 buffer_no_cacheable(w->response.data);
233 case ALLMETRICS_SHELL:
234 w->response.data->contenttype = CT_TEXT_PLAIN;
235 rrd_stats_api_v1_charts_allmetrics_shell(host, w->response.data);
238 case ALLMETRICS_PROMETHEUS:
239 w->response.data->contenttype = CT_PROMETHEUS;
240 rrd_stats_api_v1_charts_allmetrics_prometheus(host, w->response.data);
244 w->response.data->contenttype = CT_TEXT_PLAIN;
245 buffer_strcat(w->response.data, "Which format? Only '" ALLMETRICS_FORMAT_SHELL "' and '" ALLMETRICS_FORMAT_PROMETHEUS "' is currently supported.");
250 inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url) {
251 return web_client_api_request_single_chart(host, w, url, rrd_stats_api_v1_chart);
254 int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) {
256 buffer_flush(w->response.data);
258 BUFFER *dimensions = NULL;
260 const char *chart = NULL
264 , *multiply_str = NULL
268 , *label_color = NULL
269 , *value_color = NULL
270 , *refresh_str = NULL
271 , *precision_str = NULL
274 int group = GROUP_AVERAGE;
275 uint32_t options = 0x00000000;
278 char *value = mystrsep(&url, "/?&");
279 if(!value || !*value) continue;
281 char *name = mystrsep(&value, "=");
282 if(!name || !*name) continue;
283 if(!value || !*value) continue;
285 debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
287 // name and value are now the parameters
288 // they are not null and not empty
290 if(!strcmp(name, "chart")) chart = value;
291 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
293 dimensions = buffer_create(100);
295 buffer_strcat(dimensions, "|");
296 buffer_strcat(dimensions, value);
298 else if(!strcmp(name, "after")) after_str = value;
299 else if(!strcmp(name, "before")) before_str = value;
300 else if(!strcmp(name, "points")) points_str = value;
301 else if(!strcmp(name, "group")) {
302 group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
304 else if(!strcmp(name, "options")) {
305 options |= web_client_api_request_v1_data_options(value);
307 else if(!strcmp(name, "label")) label = value;
308 else if(!strcmp(name, "units")) units = value;
309 else if(!strcmp(name, "label_color")) label_color = value;
310 else if(!strcmp(name, "value_color")) value_color = value;
311 else if(!strcmp(name, "multiply")) multiply_str = value;
312 else if(!strcmp(name, "divide")) divide_str = value;
313 else if(!strcmp(name, "refresh")) refresh_str = value;
314 else if(!strcmp(name, "precision")) precision_str = value;
315 else if(!strcmp(name, "alarm")) alarm = value;
318 if(!chart || !*chart) {
319 buffer_no_cacheable(w->response.data);
320 buffer_sprintf(w->response.data, "No chart id is given at the request.");
324 RRDSET *st = rrdset_find(host, chart);
325 if(!st) st = rrdset_find_byname(host, chart);
327 buffer_no_cacheable(w->response.data);
328 buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
335 rc = rrdcalc_find(st, alarm);
337 buffer_no_cacheable(w->response.data);
338 buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
344 long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
345 long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
346 long long before = (before_str && *before_str )?str2l(before_str):0;
347 long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
348 int points = (points_str && *points_str )?str2i(points_str):1;
349 int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
351 if(!multiply) multiply = 1;
352 if(!divide) divide = 1;
355 if(refresh_str && *refresh_str) {
356 if(!strcmp(refresh_str, "auto")) {
357 if(rc) refresh = rc->update_every;
358 else if(options & RRDR_OPTION_NOT_ALIGNED)
359 refresh = st->update_every;
361 refresh = (int)(before - after);
362 if(refresh < 0) refresh = -refresh;
366 refresh = str2i(refresh_str);
367 if(refresh < 0) refresh = -refresh;
373 char *s = (char *)alarm;
375 if(*s == '_') *s = ' ';
380 else if(dimensions) {
381 const char *dim = buffer_tostring(dimensions);
382 if(*dim == '|') dim++;
395 else if(options & RRDR_OPTION_PERCENTAGE)
401 debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
405 , (dimensions)?buffer_tostring(dimensions):""
415 buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
416 w->response.data->expires = now_realtime_sec() + refresh;
418 else buffer_no_cacheable(w->response.data);
422 case RRDCALC_STATUS_CRITICAL:
426 case RRDCALC_STATUS_WARNING:
427 value_color = "orange";
430 case RRDCALC_STATUS_CLEAR:
431 value_color = "brightgreen";
434 case RRDCALC_STATUS_UNDEFINED:
435 value_color = "lightgrey";
438 case RRDCALC_STATUS_UNINITIALIZED:
439 value_color = "#000";
443 value_color = "grey";
448 buffer_svg(w->response.data,
450 (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide,
458 time_t latest_timestamp = 0;
459 int value_is_null = 1;
460 calculated_number n = NAN;
463 // if the collected value is too old, don't calculate its value
464 if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
468 (dimensions) ? buffer_tostring(dimensions) : NULL,
478 // if the value cannot be calculated, show empty badge
480 buffer_no_cacheable(w->response.data);
485 else if (refresh > 0) {
486 buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
487 w->response.data->expires = now_realtime_sec() + refresh;
489 else buffer_no_cacheable(w->response.data);
492 buffer_svg(w->response.data,
494 (value_is_null)?NAN:(n * multiply / divide),
502 buffer_free(dimensions);
506 // returns the HTTP code
507 inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
508 debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
511 BUFFER *dimensions = NULL;
513 buffer_flush(w->response.data);
515 char *google_version = "0.6",
518 *google_out = "json",
519 *responseHandler = NULL,
522 time_t last_timestamp_in_data = 0, google_timestamp = 0;
527 , *points_str = NULL;
529 int group = GROUP_AVERAGE;
530 uint32_t format = DATASOURCE_JSON;
531 uint32_t options = 0x00000000;
534 char *value = mystrsep(&url, "?&");
535 if(!value || !*value) continue;
537 char *name = mystrsep(&value, "=");
538 if(!name || !*name) continue;
539 if(!value || !*value) continue;
541 debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
543 // name and value are now the parameters
544 // they are not null and not empty
546 if(!strcmp(name, "chart")) chart = value;
547 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
548 if(!dimensions) dimensions = buffer_create(100);
549 buffer_strcat(dimensions, "|");
550 buffer_strcat(dimensions, value);
552 else if(!strcmp(name, "after")) after_str = value;
553 else if(!strcmp(name, "before")) before_str = value;
554 else if(!strcmp(name, "points")) points_str = value;
555 else if(!strcmp(name, "group")) {
556 group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
558 else if(!strcmp(name, "format")) {
559 format = web_client_api_request_v1_data_format(value);
561 else if(!strcmp(name, "options")) {
562 options |= web_client_api_request_v1_data_options(value);
564 else if(!strcmp(name, "callback")) {
565 responseHandler = value;
567 else if(!strcmp(name, "filename")) {
570 else if(!strcmp(name, "tqx")) {
571 // parse Google Visualization API options
572 // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
573 char *tqx_name, *tqx_value;
576 tqx_value = mystrsep(&value, ";");
577 if(!tqx_value || !*tqx_value) continue;
579 tqx_name = mystrsep(&tqx_value, ":");
580 if(!tqx_name || !*tqx_name) continue;
581 if(!tqx_value || !*tqx_value) continue;
583 if(!strcmp(tqx_name, "version"))
584 google_version = tqx_value;
585 else if(!strcmp(tqx_name, "reqId"))
586 google_reqId = tqx_value;
587 else if(!strcmp(tqx_name, "sig")) {
588 google_sig = tqx_value;
589 google_timestamp = strtoul(google_sig, NULL, 0);
591 else if(!strcmp(tqx_name, "out")) {
592 google_out = tqx_value;
593 format = web_client_api_request_v1_data_google_format(google_out);
595 else if(!strcmp(tqx_name, "responseHandler"))
596 responseHandler = tqx_value;
597 else if(!strcmp(tqx_name, "outFileName"))
598 outFileName = tqx_value;
603 if(!chart || !*chart) {
604 buffer_sprintf(w->response.data, "No chart id is given at the request.");
608 RRDSET *st = rrdset_find(host, chart);
609 if(!st) st = rrdset_find_byname(host, chart);
611 buffer_strcat(w->response.data, "Chart is not found: ");
612 buffer_strcat_htmlescape(w->response.data, chart);
617 long long before = (before_str && *before_str)?str2l(before_str):0;
618 long long after = (after_str && *after_str) ?str2l(after_str):0;
619 int points = (points_str && *points_str)?str2i(points_str):0;
621 debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
624 , (dimensions)?buffer_tostring(dimensions):""
633 if(outFileName && *outFileName) {
634 buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
635 debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
638 if(format == DATASOURCE_DATATABLE_JSONP) {
639 if(responseHandler == NULL)
640 responseHandler = "google.visualization.Query.setResponse";
642 debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
643 w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
646 buffer_sprintf(w->response.data,
647 "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
648 responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
650 else if(format == DATASOURCE_JSONP) {
651 if(responseHandler == NULL)
652 responseHandler = "callback";
654 buffer_strcat(w->response.data, responseHandler);
655 buffer_strcat(w->response.data, "(");
658 ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
660 if(format == DATASOURCE_DATATABLE_JSONP) {
661 if(google_timestamp < last_timestamp_in_data)
662 buffer_strcat(w->response.data, "});");
665 // the client already has the latest data
666 buffer_flush(w->response.data);
667 buffer_sprintf(w->response.data,
668 "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
669 responseHandler, google_version, google_reqId);
672 else if(format == DATASOURCE_JSONP)
673 buffer_strcat(w->response.data, ");");
676 buffer_free(dimensions);
680 inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url) {
681 static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
682 hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
683 hash_to = 0 /*, hash_redirects = 0 */;
685 if(unlikely(!hash_action)) {
686 hash_action = simple_hash("action");
687 hash_access = simple_hash("access");
688 hash_hello = simple_hash("hello");
689 hash_delete = simple_hash("delete");
690 hash_search = simple_hash("search");
691 hash_switch = simple_hash("switch");
692 hash_machine = simple_hash("machine");
693 hash_url = simple_hash("url");
694 hash_name = simple_hash("name");
695 hash_delete_url = simple_hash("delete_url");
696 hash_for = simple_hash("for");
697 hash_to = simple_hash("to");
699 hash_redirects = simple_hash("redirects");
703 char person_guid[GUID_LEN + 1] = "";
705 debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
708 // The browser may send multiple cookies with our id
710 char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
712 strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
715 char *machine_guid = NULL,
718 *search_machine_guid = NULL,
720 *to_person_guid = NULL;
726 char *value = mystrsep(&url, "?&");
727 if (!value || !*value) continue;
729 char *name = mystrsep(&value, "=");
730 if (!name || !*name) continue;
731 if (!value || !*value) continue;
733 debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
735 uint32_t hash = simple_hash(name);
737 if(hash == hash_action && !strcmp(name, "action")) {
738 uint32_t vhash = simple_hash(value);
740 if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
741 else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
742 else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
743 else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
744 else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
745 #ifdef NETDATA_INTERNAL_CHECKS
746 else error("unknown registry action '%s'", value);
747 #endif /* NETDATA_INTERNAL_CHECKS */
750 else if(hash == hash_redirects && !strcmp(name, "redirects"))
751 redirects = atoi(value);
753 else if(hash == hash_machine && !strcmp(name, "machine"))
754 machine_guid = value;
756 else if(hash == hash_url && !strcmp(name, "url"))
759 else if(action == 'A') {
760 if(hash == hash_name && !strcmp(name, "name"))
763 else if(action == 'D') {
764 if(hash == hash_delete_url && !strcmp(name, "delete_url"))
767 else if(action == 'S') {
768 if(hash == hash_for && !strcmp(name, "for"))
769 search_machine_guid = value;
771 else if(action == 'W') {
772 if(hash == hash_to && !strcmp(name, "to"))
773 to_person_guid = value;
775 #ifdef NETDATA_INTERNAL_CHECKS
776 else error("unused registry URL parameter '%s' with value '%s'", name, value);
777 #endif /* NETDATA_INTERNAL_CHECKS */
780 if(respect_web_browser_do_not_track_policy && w->donottrack) {
781 buffer_flush(w->response.data);
782 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.");
786 if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
787 error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
788 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
789 buffer_flush(w->response.data);
790 buffer_strcat(w->response.data, "Invalid registry Access request.");
793 else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
794 error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
795 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
796 buffer_flush(w->response.data);
797 buffer_strcat(w->response.data, "Invalid registry Delete request.");
800 else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
801 error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
802 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
803 buffer_flush(w->response.data);
804 buffer_strcat(w->response.data, "Invalid registry Search request.");
807 else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
808 error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
809 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
810 buffer_flush(w->response.data);
811 buffer_strcat(w->response.data, "Invalid registry Switch request.");
817 w->tracking_required = 1;
818 return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
821 w->tracking_required = 1;
822 return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
825 w->tracking_required = 1;
826 return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
829 w->tracking_required = 1;
830 return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
833 return registry_request_hello_json(host, w);
836 buffer_flush(w->response.data);
837 buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
842 inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) {
843 static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0;
845 if(unlikely(hash_data == 0)) {
846 hash_data = simple_hash("data");
847 hash_chart = simple_hash("chart");
848 hash_charts = simple_hash("charts");
849 hash_registry = simple_hash("registry");
850 hash_badge = simple_hash("badge.svg");
851 hash_alarms = simple_hash("alarms");
852 hash_alarm_log = simple_hash("alarm_log");
853 hash_alarm_variables = simple_hash("alarm_variables");
854 hash_raw = simple_hash("allmetrics");
858 char *tok = mystrsep(&url, "/?&");
860 debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
861 uint32_t hash = simple_hash(tok);
863 if(hash == hash_data && !strcmp(tok, "data"))
864 return web_client_api_request_v1_data(host, w, url);
866 else if(hash == hash_chart && !strcmp(tok, "chart"))
867 return web_client_api_request_v1_chart(host, w, url);
869 else if(hash == hash_charts && !strcmp(tok, "charts"))
870 return web_client_api_request_v1_charts(host, w, url);
872 else if(hash == hash_registry && !strcmp(tok, "registry"))
873 return web_client_api_request_v1_registry(host, w, url);
875 else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
876 return web_client_api_request_v1_badge(host, w, url);
878 else if(hash == hash_alarms && !strcmp(tok, "alarms"))
879 return web_client_api_request_v1_alarms(host, w, url);
881 else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
882 return web_client_api_request_v1_alarm_log(host, w, url);
884 else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
885 return web_client_api_request_v1_alarm_variables(host, w, url);
887 else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
888 return web_client_api_request_v1_allmetrics(host, w, url);
891 buffer_flush(w->response.data);
892 buffer_strcat(w->response.data, "Unsupported v1 API command: ");
893 buffer_strcat_htmlescape(w->response.data, tok);
898 buffer_flush(w->response.data);
899 buffer_sprintf(w->response.data, "Which API v1 command?");