From 58b7d95a7ec9c576f8a06bbab07f755846b5349a Mon Sep 17 00:00:00 2001 From: thiagoftsm <49162938+thiagoftsm@users.noreply.github.com> Date: Thu, 6 Jun 2019 17:01:39 +0000 Subject: 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! --- web/api/badges/web_buffer_svg.c | 97 +++++++------ web/api/exporters/allmetrics.c | 79 +++++----- web/api/health/health_cmdapi.c | 145 ++++++++++--------- web/api/web_api_v1.c | 312 ++++++++++++++++++++++------------------ 4 files changed, 349 insertions(+), 284 deletions(-) (limited to 'web/api') diff --git a/web/api/badges/web_buffer_svg.c b/web/api/badges/web_buffer_svg.c index b24fddedf5..d24e2820ef 100644 --- a/web/api/badges/web_buffer_svg.c +++ b/web/api/badges/web_buffer_svg.c @@ -889,6 +889,7 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch } int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) { + (void)url; int ret = 400; buffer_flush(w->response.data); @@ -912,46 +913,54 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u int group = RRDR_GROUPING_AVERAGE; uint32_t options = 0x00000000; - while(url) { - char *value = mystrsep(&url, "&"); - if(!value || !*value) continue; - - char *name = mystrsep(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value); - - // name and value are now the parameters - // they are not null and not empty - - if(!strcmp(name, "chart")) chart = value; - else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) { - if(!dimensions) - dimensions = buffer_create(100); - - buffer_strcat(dimensions, "|"); - buffer_strcat(dimensions, value); - } - else if(!strcmp(name, "after")) after_str = value; - else if(!strcmp(name, "before")) before_str = value; - else if(!strcmp(name, "points")) points_str = value; - else if(!strcmp(name, "group")) { - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE); - } - else if(!strcmp(name, "options")) { - options |= web_client_api_request_v1_data_options(value); - } - else if(!strcmp(name, "label")) label = value; - else if(!strcmp(name, "units")) units = value; - else if(!strcmp(name, "label_color")) label_color = value; - else if(!strcmp(name, "value_color")) value_color = value; - else if(!strcmp(name, "multiply")) multiply_str = value; - else if(!strcmp(name, "divide")) divide_str = value; - else if(!strcmp(name, "refresh")) refresh_str = value; - else if(!strcmp(name, "precision")) precision_str = value; - else if(!strcmp(name, "scale")) scale_str = value; - else if(!strcmp(name, "alarm")) alarm = value; + uint32_t i = 0; + uint32_t end = w->total_params; + char save[WEB_FIELDS_MAX]; + char *value; + size_t lvalue; + if(end) { + do { + value = w->param_values[i].body; + lvalue = w->param_values[i].length; + save[i] = value[lvalue]; + value[lvalue] = 0x00; + + char *name = w->param_name[i].body; + size_t lname = w->param_name[i].length; + + debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value); + + // name and value are now the parameters + // they are not null and not empty + if(!strncmp(name, "chart",lname)) chart = value; + else if(!strncmp(name, "dimension",lname) || !strncmp(name, "dim",lname) || !strncmp(name, "dimensions",lname) || !strncmp(name, "dims",lname)) { + if(!dimensions) + dimensions = buffer_create(100); + + buffer_strcat(dimensions, "|"); + buffer_strcat(dimensions, value); + } + else if(!strncmp(name, "after",lname)) after_str = value; + else if(!strncmp(name, "before",lname)) before_str = value; + else if(!strncmp(name, "points",lname)) points_str = value; + else if(!strncmp(name, "group",lname)) { + group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE); + } + else if(!strncmp(name, "options",lname)) { + options |= web_client_api_request_v1_data_options(value); + } + else if(!strncmp(name, "label",lname)) label = value; + else if(!strncmp(name, "units",lname)) units = value; + else if(!strncmp(name, "label_color",lname)) label_color = value; + else if(!strncmp(name, "value_color",lname)) value_color = value; + else if(!strncmp(name, "multiply",lname)) multiply_str = value; + else if(!strncmp(name, "divide",lname)) divide_str = value; + else if(!strncmp(name, "refresh",lname)) refresh_str = value; + else if(!strncmp(name, "precision",lname)) precision_str = value; + else if(!strncmp(name, "scale",lname)) scale_str = value; + else if(!strncmp(name, "alarm",lname)) alarm = value; + + } while (++i < end ); } if(!chart || !*chart) { @@ -1137,6 +1146,14 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u } cleanup: + if(end) { + i = 0; + do { + value = w->param_values[i].body; + lvalue = w->param_values[i].length; + value[lvalue] = save[i]; + } while(++i < end); + } buffer_free(dimensions); return ret; } diff --git a/web/api/exporters/allmetrics.c b/web/api/exporters/allmetrics.c index 88ff78e7e4..17e5e077eb 100644 --- a/web/api/exporters/allmetrics.c +++ b/web/api/exporters/allmetrics.c @@ -18,54 +18,57 @@ struct prometheus_output_options { }; inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client *w, char *url) { + (void)url; int format = ALLMETRICS_SHELL; const char *prometheus_server = w->client_ip; uint32_t prometheus_backend_options = global_backend_options; PROMETHEUS_OUTPUT_OPTIONS prometheus_output_options = PROMETHEUS_OUTPUT_TIMESTAMPS | ((global_backend_options & BACKEND_OPTION_SEND_NAMES)?PROMETHEUS_OUTPUT_NAMES:0); const char *prometheus_prefix = global_backend_prefix; - while(url) { - char *value = mystrsep(&url, "&"); - if (!value || !*value) continue; + uint32_t end = w->total_params; + if (end) { + uint32_t i = 0; + do { + char *name = w->param_name[i].body; + size_t lname = w->param_name[i].length; + char *value = w->param_values[i].body; + size_t lvalue = w->param_values[i].length; - char *name = mystrsep(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - if(!strcmp(name, "format")) { - if(!strcmp(value, ALLMETRICS_FORMAT_SHELL)) - format = ALLMETRICS_SHELL; - else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS)) - format = ALLMETRICS_PROMETHEUS; - else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS)) - format = ALLMETRICS_PROMETHEUS_ALL_HOSTS; - else if(!strcmp(value, ALLMETRICS_FORMAT_JSON)) - format = ALLMETRICS_JSON; - else - format = 0; - } - else if(!strcmp(name, "server")) { - prometheus_server = value; - } - else if(!strcmp(name, "prefix")) { - prometheus_prefix = value; - } - else if(!strcmp(name, "data") || !strcmp(name, "source") || !strcmp(name, "data source") || !strcmp(name, "data-source") || !strcmp(name, "data_source") || !strcmp(name, "datasource")) { - prometheus_backend_options = backend_parse_data_source(value, prometheus_backend_options); - } - else { - int i; - for(i = 0; prometheus_output_flags_root[i].name ; i++) { - if(!strcmp(name, prometheus_output_flags_root[i].name)) { - if(!strcmp(value, "yes") || !strcmp(value, "1") || !strcmp(value, "true")) - prometheus_output_options |= prometheus_output_flags_root[i].flag; - else - prometheus_output_options &= ~prometheus_output_flags_root[i].flag; + if(!strncmp(name, "format",lname)) { + if(!strncmp(value, ALLMETRICS_FORMAT_SHELL,lvalue)) + format = ALLMETRICS_SHELL; + else if(!strncmp(value, ALLMETRICS_FORMAT_PROMETHEUS,lvalue)) + format = ALLMETRICS_PROMETHEUS; + else if(!strncmp(value, ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS,lvalue)) + format = ALLMETRICS_PROMETHEUS_ALL_HOSTS; + else if(!strncmp(value, ALLMETRICS_FORMAT_JSON,lvalue)) + format = ALLMETRICS_JSON; + else + format = 0; + } + else if(!strncmp(name, "server",lname)) { + prometheus_server = value; + } + else if(!strncmp(name, "prefix",lname)) { + prometheus_prefix = value; + } + 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)) { + prometheus_backend_options = backend_parse_data_source(value, prometheus_backend_options); + } + else { + int i; + for(i = 0; prometheus_output_flags_root[i].name ; i++) { + if(!strncmp(name, prometheus_output_flags_root[i].name,lname)) { + if(!strncmp(value, "yes",lvalue) || !strncmp(value, "1",lvalue) || !strncmp(value, "true",lvalue)) + prometheus_output_options |= prometheus_output_flags_root[i].flag; + else + prometheus_output_options &= ~prometheus_output_flags_root[i].flag; - break; + break; + } } } - } + } while( ++i < end); } buffer_flush(w->response.data); diff --git a/web/api/health/health_cmdapi.c b/web/api/health/health_cmdapi.c index ec177751b9..eac3daf06b 100644 --- a/web/api/health/health_cmdapi.c +++ b/web/api/health/health_cmdapi.c @@ -31,13 +31,10 @@ void free_silencers(SILENCER *t) { return; } - - int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) { int ret = 400; (void) host; - - + (void)url; BUFFER *wb = w->response.data; buffer_flush(wb); @@ -73,75 +70,86 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR); ret = 403; } else { - while (url) { - char *value = mystrsep(&url, "&"); - if (!value || !*value) continue; - - char *key = mystrsep(&value, "="); - if (!key || !*key) continue; - if (!value || !*value) continue; - - debug(D_WEB_CLIENT, "%llu: API v1 health query param '%s' with value '%s'", w->id, key, value); - - // name and value are now the parameters - if (!strcmp(key, "cmd")) { - if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) { - silencers->all_alarms = 1; - silencers->stype = STYPE_SILENCE_NOTIFICATIONS; - buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCEALL); - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLEALL)) { - silencers->all_alarms = 1; - silencers->stype = STYPE_DISABLE_ALARMS; - buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLEALL); - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCE)) { - silencers->stype = STYPE_SILENCE_NOTIFICATIONS; - buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCE); - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLE)) { - silencers->stype = STYPE_DISABLE_ALARMS; - buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLE); - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_RESET)) { - silencers->all_alarms = 0; - silencers->stype = STYPE_NONE; - free_silencers(silencers->silencers); - silencers->silencers = NULL; - buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET); - } - } else { - uint32_t hash = simple_uhash(key); - if (unlikely(silencer == NULL)) { - if ( - (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) || - (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) || - (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) || - (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) || - (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) || - (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) - ) { - silencer = create_silencer(); + uint32_t end = w->total_params; + if (end) { + uint32_t i = 0; + do { + char *key = w->param_name[i].body; + size_t lkey = w->param_name[i].length; + char ksave = key[lkey]; + key[lkey] = 0x00; + + char *value = w->param_values[i].body; + size_t lvalue = w->param_values[i].length; + char vsave = value[lvalue]; + value[lvalue] = 0x00; + + debug(D_WEB_CLIENT, "%llu: API v1 health query param '%s' with value '%s'", w->id, key, value); + + // name and value are now the parameters + if (!strncmp(key, "cmd",lkey)) { + if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) { + silencers->all_alarms = 1; + silencers->stype = STYPE_SILENCE_NOTIFICATIONS; + buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCEALL); + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLEALL)) { + silencers->all_alarms = 1; + silencers->stype = STYPE_DISABLE_ALARMS; + buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLEALL); + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCE)) { + silencers->stype = STYPE_SILENCE_NOTIFICATIONS; + buffer_strcat(wb, HEALTH_CMDAPI_MSG_SILENCE); + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_DISABLE)) { + silencers->stype = STYPE_DISABLE_ALARMS; + buffer_strcat(wb, HEALTH_CMDAPI_MSG_DISABLE); + } else if (!strcmp(value, HEALTH_CMDAPI_CMD_RESET)) { + silencers->all_alarms = 0; + silencers->stype = STYPE_NONE; + free_silencers(silencers->silencers); + silencers->silencers = NULL; + buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET); } - } - - if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) { - silencer->alarms = strdupz(value); - silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) { - silencer->charts = strdupz(value); - silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) { - silencer->contexts = strdupz(value); - silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) { - silencer->hosts = strdupz(value); - silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) { - silencer->families = strdupz(value); - silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT); } else { - buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY); + uint32_t hash = simple_uhash(key); + if (unlikely(silencer == NULL)) { + if ( + (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) || + (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) || + (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) || + (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) || + (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) || + (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) + ) { + silencer = create_silencer(); + } + } + + if (hash == hash_alarm && !strncasecmp(key, HEALTH_ALARM_KEY,lkey)) { + silencer->alarms = strdupz(value); + silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_chart && !strncasecmp(key, HEALTH_CHART_KEY,lkey)) { + silencer->charts = strdupz(value); + silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_context && !strncasecmp(key, HEALTH_CONTEXT_KEY,lkey)) { + silencer->contexts = strdupz(value); + silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_host && !strncasecmp(key, HEALTH_HOST_KEY,lkey)) { + silencer->hosts = strdupz(value); + silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_families && !strncasecmp(key, HEALTH_FAMILIES_KEY,lkey)) { + silencer->families = strdupz(value); + silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT); + } else { + buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY); + } } - } + key[lkey] = ksave ; + value[lvalue] = vsave ; + + } while( ++i < end ); } + if (likely(silencer)) { // Add the created instance to the linked list in silencers silencer->next = silencers->silencers; @@ -160,6 +168,7 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c ret = 200; } } + w->response.data = wb; buffer_no_cacheable(w->response.data); return ret; diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 7c0d728bf8..590c025632 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -195,14 +195,18 @@ inline uint32_t web_client_api_request_v1_data_google_format(char *name) { inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, char *url) { + (void)url; int all = 0; - while(url) { - char *value = mystrsep(&url, "&"); - if (!value || !*value) continue; + uint32_t end = w->total_params; + if(end) { + uint32_t i = 0; + do { + char *value = w->param_values[i].body; - if(!strcmp(value, "all")) all = 1; - else if(!strcmp(value, "active")) all = 0; + if(!strncmp(value, "all",3)) all = 1; + else if(!strncmp(value, "active",6)) all = 0; + } while(++i < end); } buffer_flush(w->response.data); @@ -213,17 +217,24 @@ inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w, } inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client *w, char *url) { + (void)url; uint32_t after = 0; - while(url) { - char *value = mystrsep(&url, "&"); - if (!value || !*value) continue; - - char *name = mystrsep(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - if(!strcmp(name, "after")) after = (uint32_t)strtoul(value, NULL, 0); + uint32_t end = w->total_params; + if(end) { + uint32_t i = 0; + do { + char *value = w->param_values[i].body; + size_t lvalue = w->param_values[i].length; + char save = value[lvalue]; + value[lvalue] = 0x00; + + char *name = w->param_name[i].body; + size_t lname = w->param_name[i].length; + + if(!strncmp(name, "after",lname)) after = (uint32_t)strtoul(value, NULL, 0); + value[lvalue] = save; + } while (++i < end); } buffer_flush(w->response.data); @@ -233,27 +244,29 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client } inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client *w, char *url, void callback(RRDSET *st, BUFFER *buf)) { + (void)url; int ret = 400; char *chart = NULL; buffer_flush(w->response.data); - while(url) { - char *value = mystrsep(&url, "&"); - if(!value || !*value) continue; - - char *name = mystrsep(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - // name and value are now the parameters - // they are not null and not empty - - if(!strcmp(name, "chart")) chart = value; - //else { - /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name); - // goto cleanup; - //} + uint32_t i = 0; + uint32_t end = w->total_params; + if(end) { + do { + char *name = w->param_name[i].body; + size_t nlength = w->param_name[i].length; + char *value = w->param_values[i].body; + + // name and value are now the parameters + // they are not null and not empty + + if(!strncmp(name, "chart",nlength)) chart = value; + //else { + /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name); + // goto cleanup; + //} + } while (++i < end); } if(!chart || !*chart) { @@ -307,6 +320,7 @@ void fix_google_param(char *s) { // returns the HTTP code inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) { + (void)url; debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url); int ret = 400; @@ -333,75 +347,82 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c uint32_t format = DATASOURCE_JSON; uint32_t options = 0x00000000; - while(url) { - char *value = mystrsep(&url, "&"); - if(!value || !*value) continue; - - char *name = mystrsep(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value); - - // name and value are now the parameters - // they are not null and not empty - - if(!strcmp(name, "chart")) chart = value; - else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) { - if(!dimensions) dimensions = buffer_create(100); - buffer_strcat(dimensions, "|"); - buffer_strcat(dimensions, value); - } - else if(!strcmp(name, "after")) after_str = value; - else if(!strcmp(name, "before")) before_str = value; - else if(!strcmp(name, "points")) points_str = value; - else if(!strcmp(name, "gtime")) group_time_str = value; - else if(!strcmp(name, "group")) { - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE); - } - else if(!strcmp(name, "format")) { - format = web_client_api_request_v1_data_format(value); - } - else if(!strcmp(name, "options")) { - options |= web_client_api_request_v1_data_options(value); - } - else if(!strcmp(name, "callback")) { - responseHandler = value; - } - else if(!strcmp(name, "filename")) { - outFileName = value; - } - else if(!strcmp(name, "tqx")) { - // parse Google Visualization API options - // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source - char *tqx_name, *tqx_value; - - while(value) { - tqx_value = mystrsep(&value, ";"); - if(!tqx_value || !*tqx_value) continue; - - tqx_name = mystrsep(&tqx_value, ":"); - if(!tqx_name || !*tqx_name) continue; - if(!tqx_value || !*tqx_value) continue; - - if(!strcmp(tqx_name, "version")) - google_version = tqx_value; - else if(!strcmp(tqx_name, "reqId")) - google_reqId = tqx_value; - else if(!strcmp(tqx_name, "sig")) { - google_sig = tqx_value; - google_timestamp = strtoul(google_sig, NULL, 0); - } - else if(!strcmp(tqx_name, "out")) { - google_out = tqx_value; - format = web_client_api_request_v1_data_google_format(google_out); + uint32_t end = w->total_params; + char save[WEB_FIELDS_MAX]; + char *value ; + size_t lvalue; + if(end) { + uint32_t i = 0; + do { + char *name = w->param_name[i].body; + size_t lname = w->param_name[i].length; + value = w->param_values[i].body; + lvalue = w->param_values[i].length; + save[i] = value[lvalue]; + value[lvalue] = 0x00; + + debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value); + + // name and value are now the parameters + // they are not null and not empty + + if(!strncmp(name, "chart",lname)) chart = value; + else if(!strncmp(name, "dimension",lname) || !strncmp(name, "dim",lname) || !strncmp(name, "dimensions",lname) || !strncmp(name, "dims",lname)) { + if(!dimensions) dimensions = buffer_create(100); + buffer_strcat(dimensions, "|"); + buffer_strcat(dimensions, value); + } + else if(!strncmp(name, "after",lname)) after_str = value; + else if(!strncmp(name, "before",lname)) before_str = value; + else if(!strncmp(name, "points",lname)) points_str = value; + else if(!strncmp(name, "gtime",lname)) group_time_str = value; + else if(!strncmp(name, "group",lname)) { + group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE); + } + else if(!strncmp(name, "format",lname)) { + format = web_client_api_request_v1_data_format(value); + } + else if(!strncmp(name, "options",lname)) { + options |= web_client_api_request_v1_data_options(value); + } + else if(!strncmp(name, "callback",lname)) { + responseHandler = value; + } + else if(!strncmp(name, "filename",lname)) { + outFileName = value; + } + else if(!strncmp(name, "tqx",lname)) { + // parse Google Visualization API options + // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source + char *tqx_name, *tqx_value; + + while(value) { + tqx_value = mystrsep(&value, ";"); + if(!tqx_value || !*tqx_value) continue; + + tqx_name = mystrsep(&tqx_value, ":"); + if(!tqx_name || !*tqx_name) continue; + if(!tqx_value || !*tqx_value) continue; + + if(!strcmp(tqx_name, "version")) + google_version = tqx_value; + else if(!strcmp(tqx_name, "reqId")) + google_reqId = tqx_value; + else if(!strcmp(tqx_name, "sig")) { + google_sig = tqx_value; + google_timestamp = strtoul(google_sig, NULL, 0); + } + else if(!strcmp(tqx_name, "out")) { + google_out = tqx_value; + format = web_client_api_request_v1_data_google_format(google_out); + } + else if(!strcmp(tqx_name, "responseHandler")) + responseHandler = tqx_value; + else if(!strcmp(tqx_name, "outFileName")) + outFileName = tqx_value; } - else if(!strcmp(tqx_name, "responseHandler")) - responseHandler = tqx_value; - else if(!strcmp(tqx_name, "outFileName")) - outFileName = tqx_value; } - } + } while (++i < end); } // validate the google parameters given @@ -488,6 +509,14 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c buffer_strcat(w->response.data, ");"); cleanup: + if(end) { + uint32_t i = 0; + do { + value = w->param_values[i].body; + lvalue = w->param_values[i].length; + value[lvalue] = save[i]; + } while ( ++i < end ); + } buffer_free(dimensions); return ret; } @@ -551,26 +580,33 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * int redirects = 0; */ - while(url) { - char *value = mystrsep(&url, "&"); - if (!value || !*value) continue; + uint32_t i = 0; + uint32_t end = w->total_params; + if (!end) { + goto nothing; + } - char *name = mystrsep(&value, "="); - if (!name || !*name) continue; - if (!value || !*value) continue; + do { + char *name = w->param_name[i].body; + size_t nlength = w->param_name[i].length; + char *value = w->param_values[i].body; + size_t vlength = w->param_values[i].length; debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value); - uint32_t hash = simple_hash(name); + //uint32_t hash = simple_hash(name); + uint32_t hash = simple_nhash(name,nlength); - if(hash == hash_action && !strcmp(name, "action")) { - uint32_t vhash = simple_hash(value); + //if(hash == hash_action && !strcmp(name, "action")) { + if(hash == hash_action && !strncmp(name, "action",nlength)) { + //uint32_t vhash = simple_hash(value); + uint32_t vhash = simple_nhash(value,vlength); - if(vhash == hash_access && !strcmp(value, "access")) action = 'A'; - else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H'; - else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D'; - else if(vhash == hash_search && !strcmp(value, "search")) action = 'S'; - else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W'; + if(vhash == hash_access && !strncmp(value, "access",vlength)) action = 'A'; + else if(vhash == hash_hello && !strncmp(value, "hello",vlength)) action = 'H'; + else if(vhash == hash_delete && !strncmp(value, "delete",vlength)) action = 'D'; + else if(vhash == hash_search && !strncmp(value, "search",vlength)) action = 'S'; + else if(vhash == hash_switch && !strncmp(value, "switch",vlength)) action = 'W'; #ifdef NETDATA_INTERNAL_CHECKS else error("unknown registry action '%s'", value); #endif /* NETDATA_INTERNAL_CHECKS */ @@ -579,33 +615,34 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * else if(hash == hash_redirects && !strcmp(name, "redirects")) redirects = atoi(value); */ - else if(hash == hash_machine && !strcmp(name, "machine")) + else if(hash == hash_machine && !strncmp(name, "machine",nlength)) machine_guid = value; - else if(hash == hash_url && !strcmp(name, "url")) + else if(hash == hash_url && !strncmp(name, "url",nlength)) machine_url = value; else if(action == 'A') { - if(hash == hash_name && !strcmp(name, "name")) + if(hash == hash_name && !strncmp(name, "name",nlength)) url_name = value; } else if(action == 'D') { - if(hash == hash_delete_url && !strcmp(name, "delete_url")) + if(hash == hash_delete_url && !strncmp(name, "delete_url",nlength)) delete_url = value; } else if(action == 'S') { - if(hash == hash_for && !strcmp(name, "for")) + if(hash == hash_for && !strncmp(name, "for",nlength)) search_machine_guid = value; } else if(action == 'W') { - if(hash == hash_to && !strcmp(name, "to")) + if(hash == hash_to && !strncmp(name, "to",nlength)) to_person_guid = value; } #ifdef NETDATA_INTERNAL_CHECKS else error("unused registry URL parameter '%s' with value '%s'", name, value); #endif /* NETDATA_INTERNAL_CHECKS */ - } + } while (++i < end ); +nothing: if(unlikely(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w))) { buffer_flush(w->response.data); 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 * } // get the command - char *tok = mystrsep(&url, "?"); - if(tok && *tok) { - debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok); - uint32_t hash = simple_hash(tok); - for(i = 0; api_commands[i].command ;i++) { - if(unlikely(hash == api_commands[i].hash && !strcmp(tok, api_commands[i].command))) { - if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl)) - return web_client_permission_denied(w); + char *cmd = w->command.body; + size_t length = w->command.length; + uint32_t hash = simple_nhash(cmd,length); - return api_commands[i].callback(host, w, url); - } - } + for(i = 0; api_commands[i].command ;i++) { + if(unlikely(hash == api_commands[i].hash && !strncmp(cmd, api_commands[i].command,length))) { + if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl)) + return web_client_permission_denied(w); - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Unsupported v1 API command: "); - buffer_strcat_htmlescape(w->response.data, tok); - return 404; - } - else { - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Which API v1 command?"); - return 400; + return api_commands[i].callback(host, w, url); + } } + + char copyme[256]; + length = w->path.length; + memcpy(copyme,w->path.body,length); + copyme[length] = 0x00; + + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Unsupported v1 API command: "); + buffer_strcat_htmlescape(w->response.data, copyme); + return 404; } -- cgit v1.2.3