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 st->last_accessed_time = now_realtime_sec();
189 callback(st, w->response.data);
196 inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url) {
197 return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
200 inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w, char *url) {
203 buffer_flush(w->response.data);
204 w->response.data->contenttype = CT_APPLICATION_JSON;
205 rrd_stats_api_v1_charts(host, w->response.data);
209 inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) {
210 int format = ALLMETRICS_SHELL;
213 char *value = mystrsep(&url, "?&");
214 if (!value || !*value) continue;
216 char *name = mystrsep(&value, "=");
217 if(!name || !*name) continue;
218 if(!value || !*value) continue;
220 if(!strcmp(name, "format")) {
221 if(!strcmp(value, ALLMETRICS_FORMAT_SHELL))
222 format = ALLMETRICS_SHELL;
223 else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
224 format = ALLMETRICS_PROMETHEUS;
225 else if(!strcmp(value, ALLMETRICS_FORMAT_JSON))
226 format = ALLMETRICS_JSON;
232 buffer_flush(w->response.data);
233 buffer_no_cacheable(w->response.data);
236 case ALLMETRICS_JSON:
237 w->response.data->contenttype = CT_APPLICATION_JSON;
238 rrd_stats_api_v1_charts_allmetrics_json(host, w->response.data);
241 case ALLMETRICS_SHELL:
242 w->response.data->contenttype = CT_TEXT_PLAIN;
243 rrd_stats_api_v1_charts_allmetrics_shell(host, w->response.data);
246 case ALLMETRICS_PROMETHEUS:
247 w->response.data->contenttype = CT_PROMETHEUS;
248 rrd_stats_api_v1_charts_allmetrics_prometheus(host, w->response.data);
252 w->response.data->contenttype = CT_TEXT_PLAIN;
253 buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "' and '" ALLMETRICS_FORMAT_JSON "' are currently supported.");
258 inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, char *url) {
259 return web_client_api_request_single_chart(host, w, url, rrd_stats_api_v1_chart);
262 int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) {
264 buffer_flush(w->response.data);
266 BUFFER *dimensions = NULL;
268 const char *chart = NULL
272 , *multiply_str = NULL
276 , *label_color = NULL
277 , *value_color = NULL
278 , *refresh_str = NULL
279 , *precision_str = NULL
282 int group = GROUP_AVERAGE;
283 uint32_t options = 0x00000000;
286 char *value = mystrsep(&url, "/?&");
287 if(!value || !*value) continue;
289 char *name = mystrsep(&value, "=");
290 if(!name || !*name) continue;
291 if(!value || !*value) continue;
293 debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
295 // name and value are now the parameters
296 // they are not null and not empty
298 if(!strcmp(name, "chart")) chart = value;
299 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
301 dimensions = buffer_create(100);
303 buffer_strcat(dimensions, "|");
304 buffer_strcat(dimensions, value);
306 else if(!strcmp(name, "after")) after_str = value;
307 else if(!strcmp(name, "before")) before_str = value;
308 else if(!strcmp(name, "points")) points_str = value;
309 else if(!strcmp(name, "group")) {
310 group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
312 else if(!strcmp(name, "options")) {
313 options |= web_client_api_request_v1_data_options(value);
315 else if(!strcmp(name, "label")) label = value;
316 else if(!strcmp(name, "units")) units = value;
317 else if(!strcmp(name, "label_color")) label_color = value;
318 else if(!strcmp(name, "value_color")) value_color = value;
319 else if(!strcmp(name, "multiply")) multiply_str = value;
320 else if(!strcmp(name, "divide")) divide_str = value;
321 else if(!strcmp(name, "refresh")) refresh_str = value;
322 else if(!strcmp(name, "precision")) precision_str = value;
323 else if(!strcmp(name, "alarm")) alarm = value;
326 if(!chart || !*chart) {
327 buffer_no_cacheable(w->response.data);
328 buffer_sprintf(w->response.data, "No chart id is given at the request.");
332 RRDSET *st = rrdset_find(host, chart);
333 if(!st) st = rrdset_find_byname(host, chart);
335 buffer_no_cacheable(w->response.data);
336 buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
340 st->last_accessed_time = now_realtime_sec();
344 rc = rrdcalc_find(st, alarm);
346 buffer_no_cacheable(w->response.data);
347 buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
353 long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1;
354 long long divide = (divide_str && *divide_str )?str2l(divide_str):1;
355 long long before = (before_str && *before_str )?str2l(before_str):0;
356 long long after = (after_str && *after_str )?str2l(after_str):-st->update_every;
357 int points = (points_str && *points_str )?str2i(points_str):1;
358 int precision = (precision_str && *precision_str)?str2i(precision_str):-1;
360 if(!multiply) multiply = 1;
361 if(!divide) divide = 1;
364 if(refresh_str && *refresh_str) {
365 if(!strcmp(refresh_str, "auto")) {
366 if(rc) refresh = rc->update_every;
367 else if(options & RRDR_OPTION_NOT_ALIGNED)
368 refresh = st->update_every;
370 refresh = (int)(before - after);
371 if(refresh < 0) refresh = -refresh;
375 refresh = str2i(refresh_str);
376 if(refresh < 0) refresh = -refresh;
382 char *s = (char *)alarm;
384 if(*s == '_') *s = ' ';
389 else if(dimensions) {
390 const char *dim = buffer_tostring(dimensions);
391 if(*dim == '|') dim++;
404 else if(options & RRDR_OPTION_PERCENTAGE)
410 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'"
414 , (dimensions)?buffer_tostring(dimensions):""
424 buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
425 w->response.data->expires = now_realtime_sec() + refresh;
427 else buffer_no_cacheable(w->response.data);
431 case RRDCALC_STATUS_CRITICAL:
435 case RRDCALC_STATUS_WARNING:
436 value_color = "orange";
439 case RRDCALC_STATUS_CLEAR:
440 value_color = "brightgreen";
443 case RRDCALC_STATUS_UNDEFINED:
444 value_color = "lightgrey";
447 case RRDCALC_STATUS_UNINITIALIZED:
448 value_color = "#000";
452 value_color = "grey";
457 buffer_svg(w->response.data,
459 (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide,
467 time_t latest_timestamp = 0;
468 int value_is_null = 1;
469 calculated_number n = NAN;
472 // if the collected value is too old, don't calculate its value
473 if (rrdset_last_entry_t(st) >= (now_realtime_sec() - (st->update_every * st->gap_when_lost_iterations_above)))
474 ret = rrdset2value_api_v1(st, w->response.data, &n, (dimensions) ? buffer_tostring(dimensions) : NULL
475 , points, after, before, group, options, NULL, &latest_timestamp, &value_is_null);
477 // if the value cannot be calculated, show empty badge
479 buffer_no_cacheable(w->response.data);
484 else if (refresh > 0) {
485 buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
486 w->response.data->expires = now_realtime_sec() + refresh;
488 else buffer_no_cacheable(w->response.data);
491 buffer_svg(w->response.data,
493 (value_is_null)?NAN:(n * multiply / divide),
501 buffer_free(dimensions);
505 // returns the HTTP code
506 inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
507 debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
510 BUFFER *dimensions = NULL;
512 buffer_flush(w->response.data);
514 char *google_version = "0.6",
517 *google_out = "json",
518 *responseHandler = NULL,
521 time_t last_timestamp_in_data = 0, google_timestamp = 0;
526 , *points_str = NULL;
528 int group = GROUP_AVERAGE;
529 uint32_t format = DATASOURCE_JSON;
530 uint32_t options = 0x00000000;
533 char *value = mystrsep(&url, "?&");
534 if(!value || !*value) continue;
536 char *name = mystrsep(&value, "=");
537 if(!name || !*name) continue;
538 if(!value || !*value) continue;
540 debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
542 // name and value are now the parameters
543 // they are not null and not empty
545 if(!strcmp(name, "chart")) chart = value;
546 else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
547 if(!dimensions) dimensions = buffer_create(100);
548 buffer_strcat(dimensions, "|");
549 buffer_strcat(dimensions, value);
551 else if(!strcmp(name, "after")) after_str = value;
552 else if(!strcmp(name, "before")) before_str = value;
553 else if(!strcmp(name, "points")) points_str = value;
554 else if(!strcmp(name, "group")) {
555 group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
557 else if(!strcmp(name, "format")) {
558 format = web_client_api_request_v1_data_format(value);
560 else if(!strcmp(name, "options")) {
561 options |= web_client_api_request_v1_data_options(value);
563 else if(!strcmp(name, "callback")) {
564 responseHandler = value;
566 else if(!strcmp(name, "filename")) {
569 else if(!strcmp(name, "tqx")) {
570 // parse Google Visualization API options
571 // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
572 char *tqx_name, *tqx_value;
575 tqx_value = mystrsep(&value, ";");
576 if(!tqx_value || !*tqx_value) continue;
578 tqx_name = mystrsep(&tqx_value, ":");
579 if(!tqx_name || !*tqx_name) continue;
580 if(!tqx_value || !*tqx_value) continue;
582 if(!strcmp(tqx_name, "version"))
583 google_version = tqx_value;
584 else if(!strcmp(tqx_name, "reqId"))
585 google_reqId = tqx_value;
586 else if(!strcmp(tqx_name, "sig")) {
587 google_sig = tqx_value;
588 google_timestamp = strtoul(google_sig, NULL, 0);
590 else if(!strcmp(tqx_name, "out")) {
591 google_out = tqx_value;
592 format = web_client_api_request_v1_data_google_format(google_out);
594 else if(!strcmp(tqx_name, "responseHandler"))
595 responseHandler = tqx_value;
596 else if(!strcmp(tqx_name, "outFileName"))
597 outFileName = tqx_value;
602 if(!chart || !*chart) {
603 buffer_sprintf(w->response.data, "No chart id is given at the request.");
607 RRDSET *st = rrdset_find(host, chart);
608 if(!st) st = rrdset_find_byname(host, chart);
610 buffer_strcat(w->response.data, "Chart is not found: ");
611 buffer_strcat_htmlescape(w->response.data, chart);
615 st->last_accessed_time = now_realtime_sec();
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 = rrdset2anything_api_v1(st, w->response.data, dimensions, format, points, after, before, group, options
659 , &last_timestamp_in_data);
661 if(format == DATASOURCE_DATATABLE_JSONP) {
662 if(google_timestamp < last_timestamp_in_data)
663 buffer_strcat(w->response.data, "});");
666 // the client already has the latest data
667 buffer_flush(w->response.data);
668 buffer_sprintf(w->response.data,
669 "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
670 responseHandler, google_version, google_reqId);
673 else if(format == DATASOURCE_JSONP)
674 buffer_strcat(w->response.data, ");");
677 buffer_free(dimensions);
681 inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url) {
682 static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
683 hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
684 hash_to = 0 /*, hash_redirects = 0 */;
686 if(unlikely(!hash_action)) {
687 hash_action = simple_hash("action");
688 hash_access = simple_hash("access");
689 hash_hello = simple_hash("hello");
690 hash_delete = simple_hash("delete");
691 hash_search = simple_hash("search");
692 hash_switch = simple_hash("switch");
693 hash_machine = simple_hash("machine");
694 hash_url = simple_hash("url");
695 hash_name = simple_hash("name");
696 hash_delete_url = simple_hash("delete_url");
697 hash_for = simple_hash("for");
698 hash_to = simple_hash("to");
700 hash_redirects = simple_hash("redirects");
704 char person_guid[GUID_LEN + 1] = "";
706 debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
709 // The browser may send multiple cookies with our id
711 char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
713 strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
716 char *machine_guid = NULL,
719 *search_machine_guid = NULL,
721 *to_person_guid = NULL;
727 char *value = mystrsep(&url, "?&");
728 if (!value || !*value) continue;
730 char *name = mystrsep(&value, "=");
731 if (!name || !*name) continue;
732 if (!value || !*value) continue;
734 debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
736 uint32_t hash = simple_hash(name);
738 if(hash == hash_action && !strcmp(name, "action")) {
739 uint32_t vhash = simple_hash(value);
741 if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
742 else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
743 else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
744 else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
745 else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
746 #ifdef NETDATA_INTERNAL_CHECKS
747 else error("unknown registry action '%s'", value);
748 #endif /* NETDATA_INTERNAL_CHECKS */
751 else if(hash == hash_redirects && !strcmp(name, "redirects"))
752 redirects = atoi(value);
754 else if(hash == hash_machine && !strcmp(name, "machine"))
755 machine_guid = value;
757 else if(hash == hash_url && !strcmp(name, "url"))
760 else if(action == 'A') {
761 if(hash == hash_name && !strcmp(name, "name"))
764 else if(action == 'D') {
765 if(hash == hash_delete_url && !strcmp(name, "delete_url"))
768 else if(action == 'S') {
769 if(hash == hash_for && !strcmp(name, "for"))
770 search_machine_guid = value;
772 else if(action == 'W') {
773 if(hash == hash_to && !strcmp(name, "to"))
774 to_person_guid = value;
776 #ifdef NETDATA_INTERNAL_CHECKS
777 else error("unused registry URL parameter '%s' with value '%s'", name, value);
778 #endif /* NETDATA_INTERNAL_CHECKS */
781 if(respect_web_browser_do_not_track_policy && w->donottrack) {
782 buffer_flush(w->response.data);
783 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.");
787 if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
788 error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
789 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
790 buffer_flush(w->response.data);
791 buffer_strcat(w->response.data, "Invalid registry Access request.");
794 else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
795 error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
796 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
797 buffer_flush(w->response.data);
798 buffer_strcat(w->response.data, "Invalid registry Delete request.");
801 else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
802 error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
803 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
804 buffer_flush(w->response.data);
805 buffer_strcat(w->response.data, "Invalid registry Search request.");
808 else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
809 error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
810 machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
811 buffer_flush(w->response.data);
812 buffer_strcat(w->response.data, "Invalid registry Switch request.");
818 w->tracking_required = 1;
819 return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec());
822 w->tracking_required = 1;
823 return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec());
826 w->tracking_required = 1;
827 return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec());
830 w->tracking_required = 1;
831 return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec());
834 return registry_request_hello_json(host, w);
837 buffer_flush(w->response.data);
838 buffer_strcat(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
843 inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) {
844 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;
846 if(unlikely(hash_data == 0)) {
847 hash_data = simple_hash("data");
848 hash_chart = simple_hash("chart");
849 hash_charts = simple_hash("charts");
850 hash_registry = simple_hash("registry");
851 hash_badge = simple_hash("badge.svg");
852 hash_alarms = simple_hash("alarms");
853 hash_alarm_log = simple_hash("alarm_log");
854 hash_alarm_variables = simple_hash("alarm_variables");
855 hash_raw = simple_hash("allmetrics");
859 char *tok = mystrsep(&url, "/?&");
861 debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
862 uint32_t hash = simple_hash(tok);
864 if(hash == hash_data && !strcmp(tok, "data"))
865 return web_client_api_request_v1_data(host, w, url);
867 else if(hash == hash_chart && !strcmp(tok, "chart"))
868 return web_client_api_request_v1_chart(host, w, url);
870 else if(hash == hash_charts && !strcmp(tok, "charts"))
871 return web_client_api_request_v1_charts(host, w, url);
873 else if(hash == hash_registry && !strcmp(tok, "registry"))
874 return web_client_api_request_v1_registry(host, w, url);
876 else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
877 return web_client_api_request_v1_badge(host, w, url);
879 else if(hash == hash_alarms && !strcmp(tok, "alarms"))
880 return web_client_api_request_v1_alarms(host, w, url);
882 else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log"))
883 return web_client_api_request_v1_alarm_log(host, w, url);
885 else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables"))
886 return web_client_api_request_v1_alarm_variables(host, w, url);
888 else if(hash == hash_raw && !strcmp(tok, "allmetrics"))
889 return web_client_api_request_v1_allmetrics(host, w, url);
892 buffer_flush(w->response.data);
893 buffer_strcat(w->response.data, "Unsupported v1 API command: ");
894 buffer_strcat_htmlescape(w->response.data, tok);
899 buffer_flush(w->response.data);
900 buffer_sprintf(w->response.data, "Which API v1 command?");