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);