@cryptotaxi247 / netdata-1 / commits / ff0b64dce

URL rewrite at the agent web server to support multiple dashboard versions (#15247)

* new routing for web requests * renamed and better error control * add missing return statements * do not serve files when no file extension is given * restore the api of the functions; use internal web_client flags to keep state; support redirects to fix directories * add window.location.hash to url redirect * do not redirect when sending to specific dashboard version and there are data after the version * uniform function to append slash to URL * remove obsolete proxy https flag

Costa Tsaousis committed Jun 26, 2023 at 11:37 UTC ff0b64dce2abb1f4e77cffaeb4a954fd5f985326
7 files changed +235 -127
aclk/aclk_query.c
+1 -1
@@ -128,7 +128,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
128 ACLK_STATS_UNLOCK;
129 }
130
131 - w->response.code = web_client_api_request_with_node_selection(localhost, w, path);
131 + w->response.code = (short)web_client_api_request_with_node_selection(localhost, w, path);
132 web_client_timeout_checkpoint_response_ready(w, &t);
133
134 if(buffer_strlen(w->response.data) > ACLK_MAX_WEB_RESPONSE_SIZE) {
libnetdata/buffer/buffer.h
+7 -10
@@ -242,19 +242,16 @@ static inline void buffer_strncat(BUFFER *wb, const char *txt, size_t len) {
242 if(unlikely(!txt || !*txt)) return;
243
244 const char *t = txt;
245 - while(*t) {
246 - buffer_need_bytes(wb, len);
247 - char *s = &wb->buffer[wb->len];
248 - char *d = s;
249 - const char *e = &wb->buffer[wb->len + len];
245 + buffer_need_bytes(wb, len + 1);
246 + char *s = &wb->buffer[wb->len];
247 + char *d = s;
248 + const char *e = &wb->buffer[wb->len + len];
249
251 - while(*t && d < e)
252 - *d++ = *t++;
250 + while(*t && d < e)
251 + *d++ = *t++;
252
254 - wb->len += d - s;
255 - }
253 + wb->len += d - s;
254
257 - buffer_need_bytes(wb, 1);
255 wb->buffer[wb->len] = '\0';
256
257 buffer_overflow_check(wb);
libnetdata/http/http_defs.h
+1
@@ -10,6 +10,7 @@
10 #define HTTP_RESP_MOVED_PERM 301
11 #define HTTP_RESP_REDIR_TEMP 307
12 #define HTTP_RESP_REDIR_PERM 308
13 +#define HTTP_RESP_HTTPS_UPGRADE 399
14
15 // HTTP_CODES 4XX Client Errors
16 #define HTTP_RESP_BAD_REQUEST 400
web/rtc/webrtc.c
+1 -1
@@ -304,7 +304,7 @@ static void webrtc_execute_api_request(WEBRTC_DC *chan, const char *request, siz
304 web_client_timeout_checkpoint_set(w, 0);
305 web_client_decode_path_and_query_string(w, path);
306 path = (char *)buffer_tostring(w->url_path_decoded);
307 - w->response.code = web_client_api_request_with_node_selection(localhost, w, path);
307 + w->response.code = (short)web_client_api_request_with_node_selection(localhost, w, path);
308 web_client_timeout_checkpoint_response_ready(w, NULL);
309
310 size_t sent_bytes = 0;
web/server/web_client.c
+203 -90
@@ -18,6 +18,14 @@ inline int web_client_permission_denied(struct web_client *w) {
18 return HTTP_RESP_FORBIDDEN;
19 }
20
21 +static inline int bad_request_multiple_dashboard_versions(struct web_client *w) {
22 + w->response.data->content_type = CT_TEXT_PLAIN;
23 + buffer_flush(w->response.data);
24 + buffer_strcat(w->response.data, "Multiple dashboard versions given at the URL.");
25 + w->response.code = HTTP_RESP_BAD_REQUEST;
26 + return HTTP_RESP_BAD_REQUEST;
27 +}
28 +
29 static inline int web_client_crock_socket(struct web_client *w __maybe_unused) {
30 #ifdef TCP_CORK
31 if(likely(web_client_is_corkable(w) && !w->tcp_cork && w->ofd != -1)) {
@@ -140,6 +148,8 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
148 w->response.zinitialized = false;
149 w->flags &= ~WEB_CLIENT_CHUNKED_TRANSFER;
150 }
151 +
152 + web_client_reset_path_flags(w);
153 }
154
155 void web_client_request_done(struct web_client *w) {
@@ -315,74 +325,152 @@ static inline uint8_t contenttype_for_filename(const char *filename) {
325 return CT_APPLICATION_OCTET_STREAM;
326 }
327
318 -static inline int access_to_file_is_not_permitted(struct web_client *w, const char *filename) {
328 +static int append_slash_to_url_and_redirect(struct web_client *w) {
329 + // this function returns a relative redirect
330 + // it finds the last path component on the URL and just appends / to it
331 + //
332 + // So, if the URL is:
333 + //
334 + // /path/to/file?query_string
335 + //
336 + // It adds a Location header like this:
337 + //
338 + // Location: file/?query_string\r\n
339 + //
340 + // The web browser already knows that it is inside /path/to/
341 + // so it converts the path to /path/to/file/ and executes the
342 + // request again.
343 +
344 + buffer_strcat(w->response.header, "Location: ");
345 + const char *b = buffer_tostring(w->url_as_received);
346 + const char *q = strchr(b, '?');
347 + if(q && q > b) {
348 + const char *e = q - 1;
349 + while(e > b && *e != '/') e--;
350 + if(*e == '/') e++;
351 +
352 + size_t len = q - e;
353 + buffer_strncat(w->response.header, e, len);
354 + buffer_strncat(w->response.header, "/", 1);
355 + buffer_strcat(w->response.header, q);
356 + }
357 + else {
358 + const char *e = &b[buffer_strlen(w->url_as_received) - 1];
359 + while(e > b && *e != '/') e--;
360 + if(*e == '/') e++;
361 +
362 + buffer_strcat(w->response.header, e);
363 + buffer_strncat(w->response.header, "/", 1);
364 + }
365 +
366 + buffer_strncat(w->response.header, "\r\n", 2);
367 +
368 w->response.data->content_type = CT_TEXT_HTML;
320 - buffer_strcat(w->response.data, "Access to file is not permitted: ");
321 - buffer_strcat_htmlescape(w->response.data, filename);
322 - return HTTP_RESP_FORBIDDEN;
369 + buffer_flush(w->response.data);
370 + buffer_strcat(w->response.data,
371 + "<!DOCTYPE html><html>"
372 + "<body onload=\"window.location.href = window.location.origin + window.location.pathname + '/' + window.location.search + window.location.hash\">"
373 + "Redirecting. In case your browser does not support redirection, please click "
374 + "<a onclick=\"window.location.href = window.location.origin + window.location.pathname + '/' + window.location.search + window.location.hash\">here</a>."
375 + "</body></html>");
376 + return HTTP_RESP_MOVED_PERM;
377 }
378
379 // Work around a bug in the CMocka library by removing this function during testing.
380 #ifndef REMOVE_MYSENDFILE
381
328 -static bool find_filename_to_serve(const char *filename, char *dst, size_t dst_len, struct stat *statbuf) {
329 - // copy the filename to our src buffer
330 - char path[FILENAME_MAX + 1];
331 - strncpyz(path, filename, FILENAME_MAX);
382 +static inline int dashboard_version(struct web_client *w) {
383 + if(!web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
384 + return -1;
385
333 - bool strip = false;
334 - while(1) {
335 - if(*path)
336 - snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, path);
337 - else
338 - snprintfz(dst, dst_len, "%s", netdata_configured_web_dir);
386 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V0))
387 + return 0;
388 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V1))
389 + return 1;
390 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V2))
391 + return 2;
392
340 - // internal_error(true, "WEBFILE: trying '%s', path '%s'", dst, path);
393 + return -1;
394 +}
395
342 - strip = false;
343 - if (lstat(dst, statbuf) != 0)
344 - strip = true;
396 +static bool find_filename_to_serve(const char *filename, char *dst, size_t dst_len, struct stat *statbuf, struct web_client *w, bool *is_dir) {
397 + int d_version = dashboard_version(w);
398 + bool has_extension = web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION);
399
346 - if (!strip && (statbuf->st_mode & S_IFMT) == S_IFDIR) {
347 - // it is a directory
348 - // let's see if it has index.html in it
349 - if(*path)
350 - snprintfz(dst, dst_len, "%s/%s/index.html", netdata_configured_web_dir, path);
351 - else
352 - snprintfz(dst, dst_len, "%s/index.html", netdata_configured_web_dir);
400 + int fallback = 0;
401
354 - if (lstat(dst, statbuf) != 0 || (statbuf->st_mode & S_IFMT) == S_IFDIR)
355 - strip = true;
402 + if(has_extension) {
403 + if(d_version == -1)
404 + snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
405 + else {
406 + // check if the filename or directory exists
407 + // fallback to the same path without the dashboard version otherwise
408 + snprintfz(dst, dst_len, "%s/v%d/%s", netdata_configured_web_dir, d_version, filename);
409 + fallback = 1;
410 + }
411 + }
412 + else if(d_version != -1) {
413 + if(filename && *filename) {
414 + // check if the filename exists
415 + // fallback to /vN/index.html otherwise
416 + snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
417 + fallback = 2;
418 + }
419 + else {
420 + if(filename && *filename)
421 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
422 + snprintfz(dst, dst_len, "%s/v%d", netdata_configured_web_dir, d_version);
423 }
424 + }
425 + else {
426 + // check if filename exists
427 + // this is needed to serve {filename}/index.html, in case a user puts a html file into a directory
428 + // fallback to /index.html otherwise
429 + snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
430 + fallback = 3;
431 + }
432 +
433 + if (lstat(dst, statbuf) != 0) {
434 + if(fallback == 1) {
435 + snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
436 + if (lstat(dst, statbuf) != 0)
437 + return false;
438 + }
439 + else if(fallback == 2) {
440 + if(filename && *filename)
441 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
442 + snprintfz(dst, dst_len, "%s/v%d", netdata_configured_web_dir, d_version);
443 + if (lstat(dst, statbuf) != 0)
444 + return false;
445 + }
446 + else if(fallback == 3) {
447 + if(filename && *filename)
448 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
449 + snprintfz(dst, dst_len, "%s", netdata_configured_web_dir);
450 + if (lstat(dst, statbuf) != 0)
451 + return false;
452 + }
453 + else
454 + return false;
455 + }
456
358 - if(!strip && (statbuf->st_mode & S_IFMT) != S_IFREG)
359 - strip = true;
457 + if((statbuf->st_mode & S_IFMT) == S_IFDIR) {
458 + size_t len = strlen(dst);
459 + if(len > dst_len - 11)
460 + return false;
461
361 - if(strip) {
362 - char *s = path, *e = path;
363 - while(*e) e++; // find the terminator
364 - if(e > s) e--; // find the last character
462 + strncpyz(&dst[len], "/index.html", dst_len - len);
463
366 - while(e >= s && *e != '/') *e-- = '\0'; // find the previous slash
367 - while(e >= s && *e == '/') *e-- = '\0'; // zero the slashes
464 + if (lstat(dst, statbuf) != 0)
465 + return false;
466
369 - if(!*s || e <= s) {
370 - snprintfz(dst, dst_len, "%s/index.html", netdata_configured_web_dir);
371 - if(lstat(dst, statbuf) != 0)
372 - return false;
373 - else
374 - break;
375 - }
376 - }
377 - else
378 - break;
467 + *is_dir = true;
468 }
469
381 - // internal_error(true, "WEBFILE: final '%s'", dst);
470 return true;
471 }
472
385 -int mysendfile(struct web_client *w, char *filename) {
473 +static int mysendfile(struct web_client *w, char *filename) {
474 debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, netdata_configured_web_dir, filename);
475
476 if(!web_client_can_access_dashboard(w))
@@ -413,15 +501,19 @@ int mysendfile(struct web_client *w, char *filename) {
501 }
502
503 // find the physical file on disk
504 + bool is_dir = false;
505 char web_filename[FILENAME_MAX + 1];
506 struct stat statbuf;
418 - if(!find_filename_to_serve(filename, web_filename, FILENAME_MAX, &statbuf)) {
507 + if(!find_filename_to_serve(filename, web_filename, FILENAME_MAX, &statbuf, w, &is_dir)) {
508 w->response.data->content_type = CT_TEXT_HTML;
509 buffer_strcat(w->response.data, "File does not exist, or is not accessible: ");
510 buffer_strcat_htmlescape(w->response.data, web_filename);
511 return HTTP_RESP_NOT_FOUND;
512 }
513
514 + if(is_dir && !web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH))
515 + return append_slash_to_url_and_redirect(w);
516 +
517 // open the file
518 w->ifd = open(web_filename, O_NONBLOCK, O_RDONLY);
519 if(w->ifd == -1) {
@@ -822,10 +914,6 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
914 // web_client_enable_deflate(w, 0);
915 }
916 }
825 - else if(hash == hash_forwarded_proto && !strcasecmp(s, "X-Forwarded-Proto")) {
826 - if(strcasestr(v, "https"))
827 - w->flags |= WEB_CLIENT_FLAG_PROXY_HTTPS;
828 - }
917 else if(hash == hash_forwarded_host && !strcasecmp(s, "X-Forwarded-Host")) {
918 char buffer[NI_MAXHOST];
919 strncpyz(buffer, v, ((size_t)(ve - v) < sizeof(buffer) - 1 ? (size_t)(ve - v) : sizeof(buffer) - 1));
@@ -1082,14 +1170,16 @@ void web_client_build_http_header(struct web_client *w) {
1170 strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", tm);
1171 }
1172
1085 - if (w->response.code == HTTP_RESP_MOVED_PERM) {
1173 + if (w->response.code == HTTP_RESP_HTTPS_UPGRADE) {
1174 buffer_sprintf(w->response.header_output,
1175 "HTTP/1.1 %d %s\r\n"
1176 "Location: https://%s%s\r\n",
1177 w->response.code, code_msg,
1178 w->server_host ? w->server_host : "",
1179 buffer_tostring(w->url_as_received));
1092 - }else {
1180 + w->response.code = HTTP_RESP_MOVED_PERM;
1181 + }
1182 + else {
1183 buffer_sprintf(w->response.header_output,
1184 "HTTP/1.1 %d %s\r\n"
1185 "Connection: %s\r\n"
@@ -1282,36 +1372,9 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1372 }
1373
1374 if (host) {
1285 - if(!url) { //no delim found
1286 - debug(D_WEB_CLIENT, "%llu: URL doesn't end with / generating redirect.", w->id);
1287 - char *protocol, *url_host;
1288 - protocol = (
1289 -#ifdef ENABLE_HTTPS
1290 - SSL_connection(&w->ssl) ||
1291 -#endif
1292 - (w->flags & WEB_CLIENT_FLAG_PROXY_HTTPS)) ? "https" : "http";
1293 -
1294 - url_host = w->forwarded_host;
1295 - if(!url_host) {
1296 - url_host = w->server_host;
1297 - if(!url_host) url_host = "";
1298 - }
1299 -
1300 - buffer_sprintf(w->response.header, "Location: %s://%s/%s/%s/%s",
1301 - protocol, url_host, nodeid?"node":"host", tok, buffer_tostring(w->url_path_decoded));
1302 -
1303 - if(buffer_strlen(w->url_query_string_decoded)) {
1304 - const char *query_string = buffer_tostring(w->url_query_string_decoded);
1305 - if(*query_string) {
1306 - if(*query_string != '?')
1307 - buffer_fast_strcat(w->response.header, "?", 1);
1308 - buffer_strcat(w->response.header, query_string);
1309 - }
1310 - }
1311 - buffer_fast_strcat(w->response.header, "\r\n", 2);
1312 - buffer_strcat(w->response.data, "Permanent redirect");
1313 - return HTTP_RESP_REDIR_PERM;
1314 - }
1375 + if(!url)
1376 + //no delim found
1377 + return append_slash_to_url_and_redirect(w);
1378
1379 size_t len = strlen(url) + 2;
1380 char buf[len];
@@ -1374,7 +1437,10 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1437 hash_api = 0,
1438 hash_netdata_conf = 0,
1439 hash_host = 0,
1377 - hash_node = 0;
1440 + hash_node = 0,
1441 + hash_v0 = 0,
1442 + hash_v1 = 0,
1443 + hash_v2 = 0;
1444
1445 #ifdef NETDATA_INTERNAL_CHECKS
1446 static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
@@ -1385,6 +1451,9 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1451 hash_netdata_conf = simple_hash("netdata.conf");
1452 hash_host = simple_hash("host");
1453 hash_node = simple_hash("node");
1454 + hash_v0 = simple_hash("v0");
1455 + hash_v1 = simple_hash("v1");
1456 + hash_v2 = simple_hash("v2");
1457 #ifdef NETDATA_INTERNAL_CHECKS
1458 hash_exit = simple_hash("exit");
1459 hash_debug = simple_hash("debug");
@@ -1394,14 +1463,14 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1463
1464 // keep a copy of the decoded path, in case we need to serve it as a filename
1465 char filename[FILENAME_MAX + 1];
1397 - strncpyz(filename, buffer_tostring(w->url_path_decoded), FILENAME_MAX);
1466 + strncpyz(filename, decoded_url_path ? decoded_url_path : "", FILENAME_MAX);
1467
1468 char *tok = strsep_skip_consecutive_separators(&decoded_url_path, "/?");
1469 if(likely(tok && *tok)) {
1470 uint32_t hash = simple_hash(tok);
1471 debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1472
1404 - if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
1473 + if(likely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
1474 debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
1475 return check_host_and_call(host, w, decoded_url_path, web_client_api_request);
1476 }
@@ -1409,6 +1478,24 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1478 debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
1479 return web_client_switch_host(host, w, decoded_url_path, hash == hash_node, web_client_process_url);
1480 }
1481 + else if(unlikely(hash == hash_v2 && strcmp(tok, "v2") == 0)) {
1482 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
1483 + return bad_request_multiple_dashboard_versions(w);
1484 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V2);
1485 + return web_client_process_url(host, w, decoded_url_path);
1486 + }
1487 + else if(unlikely(hash == hash_v1 && strcmp(tok, "v1") == 0)) {
1488 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
1489 + return bad_request_multiple_dashboard_versions(w);
1490 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V1);
1491 + return web_client_process_url(host, w, decoded_url_path);
1492 + }
1493 + else if(unlikely(hash == hash_v0 && strcmp(tok, "v0") == 0)) {
1494 + if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
1495 + return bad_request_multiple_dashboard_versions(w);
1496 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V0);
1497 + return web_client_process_url(host, w, decoded_url_path);
1498 + }
1499 else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
1500 if(unlikely(!web_client_can_access_netdataconf(w)))
1501 return web_client_permission_denied(w);
@@ -1546,7 +1633,33 @@ void web_client_process_request(struct web_client *w) {
1633 break;
1634 }
1635
1549 - w->response.code = web_client_process_url(localhost, w, (char *)buffer_tostring(w->url_path_decoded));
1636 + web_client_reset_path_flags(w);
1637 +
1638 + // find if the URL path has a filename extension
1639 + char path[FILENAME_MAX + 1];
1640 + strncpyz(path, buffer_tostring(w->url_path_decoded), FILENAME_MAX);
1641 + char *s = path, *e = path;
1642 +
1643 + // remove the query string and find the last char
1644 + for (; *e ; e++) {
1645 + if (*e == '?')
1646 + break;
1647 + }
1648 +
1649 + if(e == s || (*(e - 1) == '/'))
1650 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
1651 +
1652 + // check if there is a filename extension
1653 + while (--e > s) {
1654 + if (*e == '/')
1655 + break;
1656 + if(*e == '.') {
1657 + web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION);
1658 + break;
1659 + }
1660 + }
1661 +
1662 + w->response.code = (short)web_client_process_url(localhost, w, path);
1663 break;
1664 }
1665 break;
@@ -1585,7 +1698,7 @@ void web_client_process_request(struct web_client *w) {
1698 " click <a onclick=\"window.location.href ='https://'+ window.location.hostname + ':' "
1699 " + window.location.port + window.location.pathname + window.location.search\">here</a>."
1700 "</body></html>");
1588 - w->response.code = HTTP_RESP_MOVED_PERM;
1701 + w->response.code = HTTP_RESP_HTTPS_UPGRADE;
1702 break;
1703 }
1704 #endif
@@ -2064,7 +2177,7 @@ void web_client_decode_path_and_query_string(struct web_client *w, const char *p
2177 }
2178 }
2179
2067 -void web_client_zero(struct web_client *w) {
2180 +void web_client_reuse_from_cache(struct web_client *w) {
2181 // zero everything about it - but keep the buffers
2182
2183 web_client_reset_allocations(w, false);
web/server/web_client.h
+21 -24
@@ -33,29 +33,28 @@ typedef enum {
33 } HTTP_VALIDATION;
34
35 typedef enum web_client_flags {
36 - WEB_CLIENT_FLAG_DEAD = 1 << 1, // if set, this client is dead
37 -
38 - WEB_CLIENT_FLAG_KEEPALIVE = 1 << 2, // if set, the web client will be re-used
39 -
40 - WEB_CLIENT_FLAG_WAIT_RECEIVE = 1 << 3, // if set, we are waiting more input data
41 - WEB_CLIENT_FLAG_WAIT_SEND = 1 << 4, // if set, we have data to send to the client
42 -
43 - WEB_CLIENT_FLAG_DO_NOT_TRACK = 1 << 5, // if set, we should not set cookies on this client
44 - WEB_CLIENT_FLAG_TRACKING_REQUIRED = 1 << 6, // if set, we need to send cookies
45 -
46 - WEB_CLIENT_FLAG_TCP_CLIENT = 1 << 7, // if set, the client is using a TCP socket
47 - WEB_CLIENT_FLAG_UNIX_CLIENT = 1 << 8, // if set, the client is using a UNIX socket
48 -
49 - WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET = 1 << 9, // don't close the socket when cleaning up (static-threaded web server)
50 -
51 - WEB_CLIENT_CHUNKED_TRANSFER = 1 << 10, // chunked transfer (used with zlib compression)
52 -
53 - WEB_CLIENT_FLAG_SSL_WAIT_RECEIVE = 1 << 11, // if set, we are waiting more input data from an ssl conn
54 - WEB_CLIENT_FLAG_SSL_WAIT_SEND = 1 << 12, // if set, we have data to send to the client from an ssl conn
55 -
56 - WEB_CLIENT_FLAG_PROXY_HTTPS = 1 << 13, // if set, the client reaches us via an https proxy
36 + WEB_CLIENT_FLAG_DEAD = (1 << 1), // if set, this client is dead
37 + WEB_CLIENT_FLAG_KEEPALIVE = (1 << 2), // if set, the web client will be re-used
38 + WEB_CLIENT_FLAG_WAIT_RECEIVE = (1 << 3), // if set, we are waiting more input data
39 + WEB_CLIENT_FLAG_WAIT_SEND = (1 << 4), // if set, we have data to send to the client
40 + WEB_CLIENT_FLAG_DO_NOT_TRACK = (1 << 5), // if set, we should not set cookies on this client
41 + WEB_CLIENT_FLAG_TRACKING_REQUIRED = (1 << 6), // if set, we need to send cookies
42 + WEB_CLIENT_FLAG_TCP_CLIENT = (1 << 7), // if set, the client is using a TCP socket
43 + WEB_CLIENT_FLAG_UNIX_CLIENT = (1 << 8), // if set, the client is using a UNIX socket
44 + WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET = (1 << 9), // don't close the socket when cleaning up (static-threaded web server)
45 + WEB_CLIENT_CHUNKED_TRANSFER = (1 << 10), // chunked transfer (used with zlib compression)
46 + WEB_CLIENT_FLAG_SSL_WAIT_RECEIVE = (1 << 11), // if set, we are waiting more input data from an ssl conn
47 + WEB_CLIENT_FLAG_SSL_WAIT_SEND = (1 << 12), // if set, we have data to send to the client from an ssl conn
48 + WEB_CLIENT_FLAG_PATH_IS_V0 = (1 << 13), // v0 dashboard found on the path
49 + WEB_CLIENT_FLAG_PATH_IS_V1 = (1 << 14), // v1 dashboard found on the path
50 + WEB_CLIENT_FLAG_PATH_IS_V2 = (1 << 15), // v2 dashboard found on the path
51 + WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH = (1 << 16), // the path has a trailing hash
52 + WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION = (1 << 17), // the path ends with a filename extension
53 } WEB_CLIENT_FLAGS;
54
55 +#define WEB_CLIENT_FLAG_PATH_WITH_VERSION (WEB_CLIENT_FLAG_PATH_IS_V0|WEB_CLIENT_FLAG_PATH_IS_V1|WEB_CLIENT_FLAG_PATH_IS_V2)
56 +#define web_client_reset_path_flags(w) (w)->flags &= ~(WEB_CLIENT_FLAG_PATH_WITH_VERSION|WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH|WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION)
57 +
58 #define web_client_flag_check(w, flag) ((w)->flags & (flag))
59 #define web_client_flag_set(w, flag) (w)->flags |= flag
60 #define web_client_flag_clear(w, flag) (w)->flags &= ~flag
@@ -210,12 +209,10 @@ void web_client_request_done(struct web_client *w);
209
210 void buffer_data_options2string(BUFFER *wb, uint32_t options);
211
213 -int mysendfile(struct web_client *w, char *filename);
214 -
212 void web_client_build_http_header(struct web_client *w);
213 char *strip_control_characters(char *url);
214
218 -void web_client_zero(struct web_client *w);
215 +void web_client_reuse_from_cache(struct web_client *w);
216 struct web_client *web_client_create(size_t *statistics_memory_accounting);
217 void web_client_free(struct web_client *w);
218
web/server/web_client_cache.c
+1 -1
@@ -93,7 +93,7 @@ struct web_client *web_client_get_from_cache(void) {
93 web_clients_cache.avail.count--;
94 spinlock_unlock(&web_clients_cache.avail.spinlock);
95
96 - web_client_zero(w);
96 + web_client_reuse_from_cache(w);
97
98 spinlock_lock(&web_clients_cache.used.spinlock);
99 web_clients_cache.used.reused++;