@cryptotaxi247 / netdata-1 / commits / 900e280a3

string comparison with hash in web requests

Costa Tsaousis committed May 28, 2016 at 13:25 UTC 900e280a367724c258674d794f917c88f27f7f6f
3 files changed +200 -192
src/common.c
+13
@@ -596,6 +596,19 @@ uint32_t simple_hash(const char *name) {
596 return hval;
597 }
598
599 +uint32_t simple_uhash(const char *name) {
600 + unsigned char *s = (unsigned char *)name;
601 + uint32_t hval = 0x811c9dc5, c;
602 +
603 + // FNV-1a algorithm
604 + while((c = *s++)) {
605 + if(unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A';
606 + hval *= 16777619;
607 + hval ^= c;
608 + }
609 + return hval;
610 +}
611 +
612 /*
613 // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
614 // one at a time hash
src/common.h
+2
@@ -21,6 +21,8 @@ extern void netdata_fix_chart_id(char *s);
21 extern void netdata_fix_chart_name(char *s);
22
23 extern uint32_t simple_hash(const char *name);
24 +extern uint32_t simple_uhash(const char *name);
25 +
26 extern void strreverse(char* begin, char* end);
27 extern char *mystrsep(char **ptr, char *s);
28 extern char *trim(char *s);
src/web_client.c
+185 -192
@@ -805,6 +805,25 @@ cleanup:
805
806 int web_client_api_request_v1_registry(struct web_client *w, char *url)
807 {
808 + static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
809 + hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
810 + hash_to = 0;
811 +
812 + if(unlikely(!hash_action)) {
813 + hash_action = simple_hash("action");
814 + hash_access = simple_hash("access");
815 + hash_hello = simple_hash("hello");
816 + hash_delete = simple_hash("delete");
817 + hash_search = simple_hash("search");
818 + hash_switch = simple_hash("switch");
819 + hash_machine = simple_hash("machine");
820 + hash_url = simple_hash("url");
821 + hash_name = simple_hash("name");
822 + hash_delete_url = simple_hash("delete_url");
823 + hash_for = simple_hash("for");
824 + hash_to = simple_hash("to");
825 + }
826 +
827 char person_guid[36 + 1] = "";
828
829 debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
@@ -834,33 +853,37 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
853
854 debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
855
837 - if(!strcmp(name, "action")) {
838 - if(!strcmp(value, "access")) action = 'A';
839 - else if(!strcmp(value, "hello")) action = 'H';
840 - else if(!strcmp(value, "delete")) action = 'D';
841 - else if(!strcmp(value, "search")) action = 'S';
842 - else if(!strcmp(value, "switch")) action = 'W';
856 + uint32_t hash = simple_hash(name);
857 +
858 + if(hash == hash_action && !strcmp(name, "action")) {
859 + uint32_t vhash = simple_hash(value);
860 +
861 + if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
862 + else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
863 + else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
864 + else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
865 + else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
866 }
844 - else if(!strcmp(name, "machine"))
867 + else if(hash == hash_machine && !strcmp(name, "machine"))
868 machine_guid = value;
869
847 - else if(!strcmp(name, "url"))
870 + else if(hash == hash_url && !strcmp(name, "url"))
871 machine_url = value;
872
873 else if(action == 'A') {
851 - if(!strcmp(name, "name"))
874 + if(hash == hash_name && !strcmp(name, "name"))
875 url_name = value;
876 }
877 else if(action == 'D') {
855 - if(!strcmp(name, "delete_url"))
878 + if(hash == hash_delete_url && !strcmp(name, "delete_url"))
879 delete_url = value;
880 }
881 else if(action == 'S') {
859 - if(!strcmp(name, "for"))
882 + if(hash == hash_for && !strcmp(name, "for"))
883 search_machine_guid = value;
884 }
885 else if(action == 'W') {
863 - if(!strcmp(name, "to"))
886 + if(hash == hash_to && !strcmp(name, "to"))
887 to_person_guid = value;
888 }
889 }
@@ -919,13 +942,13 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url)
942
943 int web_client_api_request_v1(struct web_client *w, char *url)
944 {
922 - static uint32_t data_hash = 0, chart_hash = 0, charts_hash = 0, registry_hash = 0;
945 + static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0;
946
924 - if(unlikely(data_hash == 0)) {
925 - data_hash = simple_hash("data");
926 - chart_hash = simple_hash("chart");
927 - charts_hash = simple_hash("charts");
928 - registry_hash = simple_hash("registry");
947 + if(unlikely(hash_data == 0)) {
948 + hash_data = simple_hash("data");
949 + hash_chart = simple_hash("chart");
950 + hash_charts = simple_hash("charts");
951 + hash_registry = simple_hash("registry");
952 }
953
954 // get the command
@@ -934,16 +957,16 @@ int web_client_api_request_v1(struct web_client *w, char *url)
957 debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
958 uint32_t hash = simple_hash(tok);
959
937 - if(hash == data_hash && !strcmp(tok, "data"))
960 + if(hash == hash_data && !strcmp(tok, "data"))
961 return web_client_api_request_v1_data(w, url);
962
940 - else if(hash == chart_hash && !strcmp(tok, "chart"))
963 + else if(hash == hash_chart && !strcmp(tok, "chart"))
964 return web_client_api_request_v1_chart(w, url);
965
943 - else if(hash == charts_hash && !strcmp(tok, "charts"))
966 + else if(hash == hash_charts && !strcmp(tok, "charts"))
967 return web_client_api_request_v1_charts(w, url);
968
946 - else if(hash == registry_hash && !strcmp(tok, "registry"))
969 + else if(hash == hash_registry && !strcmp(tok, "registry"))
970 return web_client_api_request_v1_registry(w, url);
971
972 else {
@@ -980,7 +1003,7 @@ int web_client_api_request(struct web_client *w, char *url)
1003 }
1004 }
1005
983 -int web_client_data_request(struct web_client *w, char *url, int datasource_type)
1006 +int web_client_api_old_data_request(struct web_client *w, char *url, int datasource_type)
1007 {
1008 RRDSET *st = NULL;
1009
@@ -1144,56 +1167,124 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1167 return 200;
1168 }
1169
1147 -/*
1148 -int web_client_parse_request(struct web_client *w) {
1149 - // protocol
1150 - // hostname
1151 - // path
1152 - // query string name-value
1153 - // http version
1154 - // method
1155 - // http request headers name-value
1170 +const char *web_content_type_to_string(uint8_t contenttype) {
1171 + switch(contenttype) {
1172 + case CT_TEXT_HTML:
1173 + return "text/html; charset=utf-8";
1174
1157 - web_client_clean_request(w);
1175 + case CT_APPLICATION_XML:
1176 + return "application/xml; charset=utf-8";
1177
1159 - debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->response.data->bytes, w->response.data->buffer);
1178 + case CT_APPLICATION_JSON:
1179 + return "application/json; charset=utf-8";
1180
1161 - char *buf = w->response.data->buffer;
1162 - char *line, *tok;
1181 + case CT_APPLICATION_X_JAVASCRIPT:
1182 + return "application/x-javascript; charset=utf-8";
1183
1164 - // ------------------------------------------------------------------------
1165 - // the first line
1184 + case CT_TEXT_CSS:
1185 + return "text/css; charset=utf-8";
1186
1167 - if(buf && (line = strsep(&buf, "\r\n"))) {
1168 - // method
1169 - if(line && (tok = strsep(&line, " "))) {
1170 - w->request.protocol = strdup(tok);
1171 - }
1172 - else goto cleanup;
1187 + case CT_TEXT_XML:
1188 + return "text/xml; charset=utf-8";
1189
1174 - // url
1175 - }
1176 - else goto cleanup;
1190 + case CT_TEXT_XSL:
1191 + return "text/xsl; charset=utf-8";
1192
1178 - // ------------------------------------------------------------------------
1179 - // the rest of the lines
1193 + case CT_APPLICATION_OCTET_STREAM:
1194 + return "application/octet-stream";
1195
1181 - while(buf && (line = strsep(&buf, "\r\n"))) {
1182 - while(line && (tok = strsep(&line, ": "))) {
1183 - }
1184 - }
1196 + case CT_IMAGE_SVG_XML:
1197 + return "image/svg+xml";
1198
1186 - char *url = NULL;
1199 + case CT_APPLICATION_X_FONT_TRUETYPE:
1200 + return "application/x-font-truetype";
1201
1202 + case CT_APPLICATION_X_FONT_OPENTYPE:
1203 + return "application/x-font-opentype";
1204
1189 -cleanup:
1190 - web_client_clean_request(w);
1191 - return 0;
1205 + case CT_APPLICATION_FONT_WOFF:
1206 + return "application/font-woff";
1207 +
1208 + case CT_APPLICATION_FONT_WOFF2:
1209 + return "application/font-woff2";
1210 +
1211 + case CT_APPLICATION_VND_MS_FONTOBJ:
1212 + return "application/vnd.ms-fontobject";
1213 +
1214 + case CT_IMAGE_PNG:
1215 + return "image/png";
1216 +
1217 + case CT_IMAGE_JPG:
1218 + return "image/jpeg";
1219 +
1220 + case CT_IMAGE_GIF:
1221 + return "image/gif";
1222 +
1223 + case CT_IMAGE_XICON:
1224 + return "image/x-icon";
1225 +
1226 + case CT_IMAGE_BMP:
1227 + return "image/bmp";
1228 +
1229 + case CT_IMAGE_ICNS:
1230 + return "image/icns";
1231 +
1232 + default:
1233 + case CT_TEXT_PLAIN:
1234 + return "text/plain; charset=utf-8";
1235 + }
1236 }
1193 -*/
1237
1238
1239 +const char *web_response_code_to_string(int code) {
1240 + switch(code) {
1241 + case 200:
1242 + return "OK";
1243 +
1244 + case 307:
1245 + return "Temporary Redirect";
1246 +
1247 + case 400:
1248 + return "Bad Request";
1249 +
1250 + case 403:
1251 + return "Forbidden";
1252 +
1253 + case 404:
1254 + return "Not Found";
1255 +
1256 + case 412:
1257 + return "Preconditions Failed";
1258 +
1259 + default:
1260 + if(code >= 100 && code < 200)
1261 + return "Informational";
1262 +
1263 + if(code >= 200 && code < 300)
1264 + return "Successful";
1265 +
1266 + if(code >= 300 && code < 400)
1267 + return "Redirection";
1268 +
1269 + if(code >= 400 && code < 500)
1270 + return "Bad Request";
1271 +
1272 + if(code >= 500 && code < 600)
1273 + return "Server Error";
1274 +
1275 + return "Undefined Error";
1276 + }
1277 +}
1278 +
1279 static inline char *http_header_parse(struct web_client *w, char *s) {
1280 + static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0;
1281 +
1282 + if(unlikely(!hash_origin)) {
1283 + hash_origin = simple_uhash("Origin");
1284 + hash_connection = simple_uhash("Connection");
1285 + hash_accept_encoding = simple_uhash("Accept-Encoding");
1286 + }
1287 +
1288 char *e = s;
1289
1290 // find the :
@@ -1218,16 +1309,17 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
1309 *ve = '\0';
1310
1311 // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
1312 + uint32_t hash = simple_uhash(s);
1313
1222 - if(!strcasecmp(s, "Origin"))
1314 + if(hash == hash_origin && !strcasecmp(s, "Origin"))
1315 strncpyz(w->origin, v, ORIGIN_MAX);
1316
1225 - else if(!strcasecmp(s, "Connection")) {
1317 + else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
1318 if(strcasestr(v, "keep-alive"))
1319 w->keepalive = 1;
1320 }
1321 #ifdef NETDATA_WITH_ZLIB
1230 - else if(!strcasecmp(s, "Accept-Encoding")) {
1322 + else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
1323 if(web_enable_gzip) {
1324 if(strcasestr(v, "gzip"))
1325 web_client_enable_deflate(w, 1);
@@ -1325,6 +1417,22 @@ static inline int http_request_validate(struct web_client *w) {
1417 }
1418
1419 void web_client_process(struct web_client *w) {
1420 + static uint32_t hash_api = 0, hash_netdata_conf = 0, hash_data = 0, hash_datasource = 0, hash_graph = 0,
1421 + hash_list = 0, hash_all_json = 0, hash_exit = 0, hash_debug = 0, hash_mirror = 0;
1422 +
1423 + if(unlikely(!hash_api)) {
1424 + hash_api = simple_hash("api");
1425 + hash_netdata_conf = simple_hash("netdata.conf");
1426 + hash_data = simple_hash(WEB_PATH_DATA);
1427 + hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
1428 + hash_graph = simple_hash(WEB_PATH_GRAPH);
1429 + hash_list = simple_hash("list");
1430 + hash_all_json = simple_hash("all.json");
1431 + hash_exit = simple_hash("exit");
1432 + hash_debug = simple_hash("debug");
1433 + hash_mirror = simple_hash("mirror");
1434 + }
1435 +
1436 int code = 500;
1437 ssize_t bytes;
1438
@@ -1347,7 +1455,7 @@ void web_client_process(struct web_client *w) {
1455 }
1456 }
1457 else if(what_to_do > 0) {
1350 - strcpy(w->last_url, "not a valid response");
1458 + strcpy(w->last_url, "not a valid request");
1459
1460 debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
1461
@@ -1368,13 +1476,14 @@ void web_client_process(struct web_client *w) {
1476 char *url = w->decoded_url;
1477 char *tok = mystrsep(&url, "/?");
1478 if(tok && *tok) {
1479 + uint32_t hash = simple_hash(tok);
1480 debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1481
1373 - if(strcmp(tok, "api") == 0) {
1482 + if(hash == hash_api && strcmp(tok, "api") == 0) {
1483 // the client is requesting api access
1484 code = web_client_api_request(w, url);
1485 }
1377 - else if(strcmp(tok, "netdata.conf") == 0) {
1486 + else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
1487 code = 200;
1488 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
1489
@@ -1382,15 +1491,15 @@ void web_client_process(struct web_client *w) {
1491 buffer_flush(w->response.data);
1492 generate_config(w->response.data, 0);
1493 }
1385 - else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1494 + else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1495 // the client is requesting rrd data -- OLD API
1387 - code = web_client_data_request(w, url, DATASOURCE_JSON);
1496 + code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
1497 }
1389 - else if(strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
1498 + else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
1499 // the client is requesting google datasource -- OLD API
1391 - code = web_client_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
1500 + code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
1501 }
1393 - else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1502 + else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1503 // the client is requesting an rrd graph -- OLD API
1504
1505 // get the name of the data to show
@@ -1421,7 +1530,7 @@ void web_client_process(struct web_client *w) {
1530 buffer_strcat(w->response.data, "Graph name?\r\n");
1531 }
1532 }
1424 - else if(strcmp(tok, "list") == 0) {
1533 + else if(hash == hash_list && strcmp(tok, "list") == 0) {
1534 // OLD API
1535 code = 200;
1536
@@ -1433,7 +1542,7 @@ void web_client_process(struct web_client *w) {
1542 for ( ; st ; st = st->next )
1543 buffer_sprintf(w->response.data, "%s\n", st->name);
1544 }
1436 - else if(strcmp(tok, "all.json") == 0) {
1545 + else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
1546 // OLD API
1547 code = 200;
1548 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
@@ -1443,7 +1552,7 @@ void web_client_process(struct web_client *w) {
1552 rrd_stats_all_json(w->response.data);
1553 }
1554 #ifdef NETDATA_INTERNAL_CHECKS
1446 - else if(strcmp(tok, "exit") == 0) {
1555 + else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
1556 code = 200;
1557 w->response.data->contenttype = CT_TEXT_PLAIN;
1558 buffer_flush(w->response.data);
@@ -1455,7 +1564,7 @@ void web_client_process(struct web_client *w) {
1564
1565 netdata_exit = 1;
1566 }
1458 - else if(strcmp(tok, "debug") == 0) {
1567 + else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
1568 buffer_flush(w->response.data);
1569
1570 // get the name of the data to show
@@ -1485,7 +1594,7 @@ void web_client_process(struct web_client *w) {
1594 buffer_strcat(w->response.data, "debug which chart?\r\n");
1595 }
1596 }
1488 - else if(strcmp(tok, "mirror") == 0) {
1597 + else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
1598 code = 200;
1599
1600 debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
@@ -1525,124 +1634,8 @@ void web_client_process(struct web_client *w) {
1634 // prepare the HTTP response header
1635 debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
1636
1528 - char *content_type_string;
1529 - switch(w->response.data->contenttype) {
1530 - case CT_TEXT_HTML:
1531 - content_type_string = "text/html; charset=utf-8";
1532 - break;
1533 -
1534 - case CT_APPLICATION_XML:
1535 - content_type_string = "application/xml; charset=utf-8";
1536 - break;
1537 -
1538 - case CT_APPLICATION_JSON:
1539 - content_type_string = "application/json; charset=utf-8";
1540 - break;
1541 -
1542 - case CT_APPLICATION_X_JAVASCRIPT:
1543 - content_type_string = "application/x-javascript; charset=utf-8";
1544 - break;
1545 -
1546 - case CT_TEXT_CSS:
1547 - content_type_string = "text/css; charset=utf-8";
1548 - break;
1549 -
1550 - case CT_TEXT_XML:
1551 - content_type_string = "text/xml; charset=utf-8";
1552 - break;
1553 -
1554 - case CT_TEXT_XSL:
1555 - content_type_string = "text/xsl; charset=utf-8";
1556 - break;
1557 -
1558 - case CT_APPLICATION_OCTET_STREAM:
1559 - content_type_string = "application/octet-stream";
1560 - break;
1561 -
1562 - case CT_IMAGE_SVG_XML:
1563 - content_type_string = "image/svg+xml";
1564 - break;
1565 -
1566 - case CT_APPLICATION_X_FONT_TRUETYPE:
1567 - content_type_string = "application/x-font-truetype";
1568 - break;
1569 -
1570 - case CT_APPLICATION_X_FONT_OPENTYPE:
1571 - content_type_string = "application/x-font-opentype";
1572 - break;
1573 -
1574 - case CT_APPLICATION_FONT_WOFF:
1575 - content_type_string = "application/font-woff";
1576 - break;
1577 -
1578 - case CT_APPLICATION_FONT_WOFF2:
1579 - content_type_string = "application/font-woff2";
1580 - break;
1581 -
1582 - case CT_APPLICATION_VND_MS_FONTOBJ:
1583 - content_type_string = "application/vnd.ms-fontobject";
1584 - break;
1585 -
1586 - case CT_IMAGE_PNG:
1587 - content_type_string = "image/png";
1588 - break;
1589 -
1590 - case CT_IMAGE_JPG:
1591 - content_type_string = "image/jpeg";
1592 - break;
1593 -
1594 - case CT_IMAGE_GIF:
1595 - content_type_string = "image/gif";
1596 - break;
1597 -
1598 - case CT_IMAGE_XICON:
1599 - content_type_string = "image/x-icon";
1600 - break;
1601 -
1602 - case CT_IMAGE_BMP:
1603 - content_type_string = "image/bmp";
1604 - break;
1605 -
1606 - case CT_IMAGE_ICNS:
1607 - content_type_string = "image/icns";
1608 - break;
1609 -
1610 - default:
1611 - case CT_TEXT_PLAIN:
1612 - content_type_string = "text/plain; charset=utf-8";
1613 - break;
1614 - }
1615 -
1616 - char *code_msg;
1617 - switch(code) {
1618 - case 200:
1619 - code_msg = "OK";
1620 - break;
1621 -
1622 - case 307:
1623 - code_msg = "Temporary Redirect";
1624 - break;
1625 -
1626 - case 400:
1627 - code_msg = "Bad Request";
1628 - break;
1629 -
1630 - case 403:
1631 - code_msg = "Forbidden";
1632 - break;
1633 -
1634 - case 404:
1635 - code_msg = "Not Found";
1636 - break;
1637 -
1638 - case 412:
1639 - code_msg = "Preconditions Failed";
1640 - break;
1641 -
1642 - default:
1643 - code_msg = "Internal Server Error";
1644 - break;
1645 - }
1637 + const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
1638 + const char *code_msg = web_response_code_to_string(code);
1639
1640 char date[100];
1641 struct tm tmbuf, *tm = gmtime_r(&w->response.data->date, &tmbuf);