web_client.c 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "web_client.h"
  3. // this is an async I/O implementation of the web server request parser
  4. // it is used by all netdata web servers
  5. int respect_web_browser_do_not_track_policy = 0;
  6. char *web_x_frame_options = NULL;
  7. int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY;
  8. inline int web_client_permission_denied(struct web_client *w) {
  9. w->response.data->content_type = CT_TEXT_PLAIN;
  10. buffer_flush(w->response.data);
  11. buffer_strcat(w->response.data, "You are not allowed to access this resource.");
  12. w->response.code = HTTP_RESP_FORBIDDEN;
  13. return HTTP_RESP_FORBIDDEN;
  14. }
  15. inline int web_client_bearer_required(struct web_client *w) {
  16. w->response.data->content_type = CT_TEXT_PLAIN;
  17. buffer_flush(w->response.data);
  18. buffer_strcat(w->response.data, "An authorization bearer is required to access the resource.");
  19. w->response.code = HTTP_RESP_UNAUTHORIZED;
  20. return HTTP_RESP_UNAUTHORIZED;
  21. }
  22. static inline int bad_request_multiple_dashboard_versions(struct web_client *w) {
  23. w->response.data->content_type = CT_TEXT_PLAIN;
  24. buffer_flush(w->response.data);
  25. buffer_strcat(w->response.data, "Multiple dashboard versions given at the URL.");
  26. w->response.code = HTTP_RESP_BAD_REQUEST;
  27. return HTTP_RESP_BAD_REQUEST;
  28. }
  29. static inline int web_client_cork_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)) {
  32. w->tcp_cork = true;
  33. if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
  34. netdata_log_error("%llu: failed to enable TCP_CORK on socket.", w->id);
  35. w->tcp_cork = false;
  36. return -1;
  37. }
  38. }
  39. #endif /* TCP_CORK */
  40. return 0;
  41. }
  42. static inline void web_client_enable_wait_from_ssl(struct web_client *w) {
  43. if (w->ssl.ssl_errno == SSL_ERROR_WANT_READ)
  44. web_client_enable_ssl_wait_receive(w);
  45. else if (w->ssl.ssl_errno == SSL_ERROR_WANT_WRITE)
  46. web_client_enable_ssl_wait_send(w);
  47. else {
  48. web_client_disable_ssl_wait_receive(w);
  49. web_client_disable_ssl_wait_send(w);
  50. }
  51. }
  52. static inline int web_client_uncork_socket(struct web_client *w __maybe_unused) {
  53. #ifdef TCP_CORK
  54. if(likely(w->tcp_cork && w->ofd != -1)) {
  55. w->tcp_cork = false;
  56. if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
  57. netdata_log_error("%llu: failed to disable TCP_CORK on socket.", w->id);
  58. w->tcp_cork = true;
  59. return -1;
  60. }
  61. }
  62. #endif /* TCP_CORK */
  63. w->tcp_cork = false;
  64. return 0;
  65. }
  66. char *strip_control_characters(char *url) {
  67. char *s = url;
  68. if(!s) return "";
  69. if(iscntrl(*s)) *s = ' ';
  70. while(*++s) {
  71. if(iscntrl(*s)) *s = ' ';
  72. }
  73. return url;
  74. }
  75. static void web_client_reset_allocations(struct web_client *w, bool free_all) {
  76. if(free_all) {
  77. // the web client is to be destroyed
  78. buffer_free(w->url_as_received);
  79. w->url_as_received = NULL;
  80. buffer_free(w->url_path_decoded);
  81. w->url_path_decoded = NULL;
  82. buffer_free(w->url_query_string_decoded);
  83. w->url_query_string_decoded = NULL;
  84. buffer_free(w->response.header_output);
  85. w->response.header_output = NULL;
  86. buffer_free(w->response.header);
  87. w->response.header = NULL;
  88. buffer_free(w->response.data);
  89. w->response.data = NULL;
  90. freez(w->post_payload);
  91. w->post_payload = NULL;
  92. w->post_payload_size = 0;
  93. }
  94. else {
  95. // the web client is to be re-used
  96. buffer_reset(w->url_as_received);
  97. buffer_reset(w->url_path_decoded);
  98. buffer_reset(w->url_query_string_decoded);
  99. buffer_reset(w->response.header_output);
  100. buffer_reset(w->response.header);
  101. buffer_reset(w->response.data);
  102. // leave w->post_payload
  103. }
  104. freez(w->server_host);
  105. w->server_host = NULL;
  106. freez(w->forwarded_host);
  107. w->forwarded_host = NULL;
  108. freez(w->origin);
  109. w->origin = NULL;
  110. freez(w->user_agent);
  111. w->user_agent = NULL;
  112. freez(w->auth_bearer_token);
  113. w->auth_bearer_token = NULL;
  114. // if we had enabled compression, release it
  115. if(w->response.zinitialized) {
  116. deflateEnd(&w->response.zstream);
  117. w->response.zsent = 0;
  118. w->response.zhave = 0;
  119. w->response.zstream.avail_in = 0;
  120. w->response.zstream.avail_out = 0;
  121. w->response.zstream.total_in = 0;
  122. w->response.zstream.total_out = 0;
  123. w->response.zinitialized = false;
  124. w->flags &= ~WEB_CLIENT_CHUNKED_TRANSFER;
  125. }
  126. web_client_reset_path_flags(w);
  127. }
  128. void web_client_request_done(struct web_client *w) {
  129. web_client_uncork_socket(w);
  130. netdata_log_debug(D_WEB_CLIENT, "%llu: Resetting client.", w->id);
  131. if(likely(buffer_strlen(w->url_as_received))) {
  132. struct timeval tv;
  133. now_monotonic_high_precision_timeval(&tv);
  134. size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
  135. size_t sent = size;
  136. if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
  137. // --------------------------------------------------------------------
  138. // global statistics
  139. global_statistics_web_request_completed(dt_usec(&tv, &w->timings.tv_in),
  140. w->statistics.received_bytes,
  141. w->statistics.sent_bytes,
  142. size,
  143. sent);
  144. w->statistics.received_bytes = 0;
  145. w->statistics.sent_bytes = 0;
  146. // --------------------------------------------------------------------
  147. const char *mode;
  148. switch(w->mode) {
  149. case WEB_CLIENT_MODE_FILECOPY:
  150. mode = "FILECOPY";
  151. break;
  152. case WEB_CLIENT_MODE_OPTIONS:
  153. mode = "OPTIONS";
  154. break;
  155. case WEB_CLIENT_MODE_STREAM:
  156. mode = "STREAM";
  157. break;
  158. case WEB_CLIENT_MODE_POST:
  159. case WEB_CLIENT_MODE_GET:
  160. mode = "DATA";
  161. break;
  162. default:
  163. mode = "UNKNOWN";
  164. break;
  165. }
  166. // access log
  167. netdata_log_access("%llu: %d '[%s]:%s' '%s' (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %d '%s'",
  168. w->id
  169. , gettid()
  170. , w->client_ip
  171. , w->client_port
  172. , mode
  173. , sent
  174. , size
  175. , -((size > 0) ? ((double)(size - sent) / (double) size * 100.0) : 0.0)
  176. , (double)dt_usec(&w->timings.tv_ready, &w->timings.tv_in) / 1000.0
  177. , (double)dt_usec(&tv, &w->timings.tv_ready) / 1000.0
  178. , (double)dt_usec(&tv, &w->timings.tv_in) / 1000.0
  179. , w->response.code
  180. , strip_control_characters((char *)buffer_tostring(w->url_as_received))
  181. );
  182. }
  183. if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
  184. if(w->ifd != w->ofd) {
  185. netdata_log_debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
  186. if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
  187. if (w->ifd != -1){
  188. close(w->ifd);
  189. }
  190. }
  191. w->ifd = w->ofd;
  192. }
  193. }
  194. web_client_reset_allocations(w, false);
  195. w->mode = WEB_CLIENT_MODE_GET;
  196. web_client_disable_donottrack(w);
  197. web_client_disable_tracking_required(w);
  198. web_client_disable_keepalive(w);
  199. w->header_parse_tries = 0;
  200. w->header_parse_last_size = 0;
  201. web_client_enable_wait_receive(w);
  202. web_client_disable_wait_send(w);
  203. w->response.has_cookies = false;
  204. w->response.rlen = 0;
  205. w->response.sent = 0;
  206. w->response.code = 0;
  207. w->response.zoutput = false;
  208. }
  209. static struct {
  210. const char *extension;
  211. uint32_t hash;
  212. uint8_t contenttype;
  213. } mime_types[] = {
  214. { "html" , 0 , CT_TEXT_HTML}
  215. , {"js" , 0 , CT_APPLICATION_X_JAVASCRIPT}
  216. , {"css" , 0 , CT_TEXT_CSS}
  217. , {"xml" , 0 , CT_TEXT_XML}
  218. , {"xsl" , 0 , CT_TEXT_XSL}
  219. , {"txt" , 0 , CT_TEXT_PLAIN}
  220. , {"svg" , 0 , CT_IMAGE_SVG_XML}
  221. , {"ttf" , 0 , CT_APPLICATION_X_FONT_TRUETYPE}
  222. , {"otf" , 0 , CT_APPLICATION_X_FONT_OPENTYPE}
  223. , {"woff2", 0 , CT_APPLICATION_FONT_WOFF2}
  224. , {"woff" , 0 , CT_APPLICATION_FONT_WOFF}
  225. , {"eot" , 0 , CT_APPLICATION_VND_MS_FONTOBJ}
  226. , {"png" , 0 , CT_IMAGE_PNG}
  227. , {"jpg" , 0 , CT_IMAGE_JPG}
  228. , {"jpeg" , 0 , CT_IMAGE_JPG}
  229. , {"gif" , 0 , CT_IMAGE_GIF}
  230. , {"bmp" , 0 , CT_IMAGE_BMP}
  231. , {"ico" , 0 , CT_IMAGE_XICON}
  232. , {"icns" , 0 , CT_IMAGE_ICNS}
  233. , { NULL, 0, 0}
  234. };
  235. static inline uint8_t contenttype_for_filename(const char *filename) {
  236. // netdata_log_info("checking filename '%s'", filename);
  237. static int initialized = 0;
  238. int i;
  239. if(unlikely(!initialized)) {
  240. for (i = 0; mime_types[i].extension; i++)
  241. mime_types[i].hash = simple_hash(mime_types[i].extension);
  242. initialized = 1;
  243. }
  244. const char *s = filename, *last_dot = NULL;
  245. // find the last dot
  246. while(*s) {
  247. if(unlikely(*s == '.')) last_dot = s;
  248. s++;
  249. }
  250. if(unlikely(!last_dot || !*last_dot || !last_dot[1])) {
  251. // netdata_log_info("no extension for filename '%s'", filename);
  252. return CT_APPLICATION_OCTET_STREAM;
  253. }
  254. last_dot++;
  255. // netdata_log_info("extension for filename '%s' is '%s'", filename, last_dot);
  256. uint32_t hash = simple_hash(last_dot);
  257. for(i = 0; mime_types[i].extension ; i++) {
  258. if(unlikely(hash == mime_types[i].hash && !strcmp(last_dot, mime_types[i].extension))) {
  259. // netdata_log_info("matched extension for filename '%s': '%s'", filename, last_dot);
  260. return mime_types[i].contenttype;
  261. }
  262. }
  263. // netdata_log_info("not matched extension for filename '%s': '%s'", filename, last_dot);
  264. return CT_APPLICATION_OCTET_STREAM;
  265. }
  266. static int append_slash_to_url_and_redirect(struct web_client *w) {
  267. // this function returns a relative redirect
  268. // it finds the last path component on the URL and just appends / to it
  269. //
  270. // So, if the URL is:
  271. //
  272. // /path/to/file?query_string
  273. //
  274. // It adds a Location header like this:
  275. //
  276. // Location: file/?query_string\r\n
  277. //
  278. // The web browser already knows that it is inside /path/to/
  279. // so it converts the path to /path/to/file/ and executes the
  280. // request again.
  281. buffer_strcat(w->response.header, "Location: ");
  282. const char *b = buffer_tostring(w->url_as_received);
  283. const char *q = strchr(b, '?');
  284. if(q && q > b) {
  285. const char *e = q - 1;
  286. while(e > b && *e != '/') e--;
  287. if(*e == '/') e++;
  288. size_t len = q - e;
  289. buffer_strncat(w->response.header, e, len);
  290. buffer_strncat(w->response.header, "/", 1);
  291. buffer_strcat(w->response.header, q);
  292. }
  293. else {
  294. const char *e = &b[buffer_strlen(w->url_as_received) - 1];
  295. while(e > b && *e != '/') e--;
  296. if(*e == '/') e++;
  297. buffer_strcat(w->response.header, e);
  298. buffer_strncat(w->response.header, "/", 1);
  299. }
  300. buffer_strncat(w->response.header, "\r\n", 2);
  301. w->response.data->content_type = CT_TEXT_HTML;
  302. buffer_flush(w->response.data);
  303. buffer_strcat(w->response.data,
  304. "<!DOCTYPE html><html>"
  305. "<body onload=\"window.location.href = window.location.origin + window.location.pathname + '/' + window.location.search + window.location.hash\">"
  306. "Redirecting. In case your browser does not support redirection, please click "
  307. "<a onclick=\"window.location.href = window.location.origin + window.location.pathname + '/' + window.location.search + window.location.hash\">here</a>."
  308. "</body></html>");
  309. return HTTP_RESP_MOVED_PERM;
  310. }
  311. // Work around a bug in the CMocka library by removing this function during testing.
  312. #ifndef REMOVE_MYSENDFILE
  313. static inline int dashboard_version(struct web_client *w) {
  314. if(!web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
  315. return -1;
  316. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V0))
  317. return 0;
  318. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V1))
  319. return 1;
  320. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V2))
  321. return 2;
  322. return -1;
  323. }
  324. 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) {
  325. int d_version = dashboard_version(w);
  326. bool has_extension = web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION);
  327. int fallback = 0;
  328. if(has_extension) {
  329. if(d_version == -1)
  330. snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
  331. else {
  332. // check if the filename or directory exists
  333. // fallback to the same path without the dashboard version otherwise
  334. snprintfz(dst, dst_len, "%s/v%d/%s", netdata_configured_web_dir, d_version, filename);
  335. fallback = 1;
  336. }
  337. }
  338. else if(d_version != -1) {
  339. if(filename && *filename) {
  340. // check if the filename exists
  341. // fallback to /vN/index.html otherwise
  342. snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
  343. fallback = 2;
  344. }
  345. else {
  346. if(filename && *filename)
  347. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
  348. snprintfz(dst, dst_len, "%s/v%d", netdata_configured_web_dir, d_version);
  349. }
  350. }
  351. else {
  352. // check if filename exists
  353. // this is needed to serve {filename}/index.html, in case a user puts a html file into a directory
  354. // fallback to /index.html otherwise
  355. snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
  356. fallback = 3;
  357. }
  358. if (stat(dst, statbuf) != 0) {
  359. if(fallback == 1) {
  360. snprintfz(dst, dst_len, "%s/%s", netdata_configured_web_dir, filename);
  361. if (stat(dst, statbuf) != 0)
  362. return false;
  363. }
  364. else if(fallback == 2) {
  365. if(filename && *filename)
  366. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
  367. snprintfz(dst, dst_len, "%s/v%d", netdata_configured_web_dir, d_version);
  368. if (stat(dst, statbuf) != 0)
  369. return false;
  370. }
  371. else if(fallback == 3) {
  372. if(filename && *filename)
  373. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
  374. snprintfz(dst, dst_len, "%s", netdata_configured_web_dir);
  375. if (stat(dst, statbuf) != 0)
  376. return false;
  377. }
  378. else
  379. return false;
  380. }
  381. if((statbuf->st_mode & S_IFMT) == S_IFDIR) {
  382. size_t len = strlen(dst);
  383. if(len > dst_len - 11)
  384. return false;
  385. strncpyz(&dst[len], "/index.html", dst_len - len);
  386. if (stat(dst, statbuf) != 0)
  387. return false;
  388. *is_dir = true;
  389. }
  390. return true;
  391. }
  392. static int mysendfile(struct web_client *w, char *filename) {
  393. netdata_log_debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, netdata_configured_web_dir, filename);
  394. if(!web_client_can_access_dashboard(w))
  395. return web_client_permission_denied(w);
  396. // skip leading slashes
  397. while (*filename == '/') filename++;
  398. // if the filename contains "strange" characters, refuse to serve it
  399. char *s;
  400. for(s = filename; *s ;s++) {
  401. if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
  402. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
  403. w->response.data->content_type = CT_TEXT_HTML;
  404. buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
  405. buffer_strcat_htmlescape(w->response.data, filename);
  406. return HTTP_RESP_BAD_REQUEST;
  407. }
  408. }
  409. // if the filename contains a double dot refuse to serve it
  410. if(strstr(filename, "..") != 0) {
  411. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
  412. w->response.data->content_type = CT_TEXT_HTML;
  413. buffer_strcat(w->response.data, "Relative filenames are not supported: ");
  414. buffer_strcat_htmlescape(w->response.data, filename);
  415. return HTTP_RESP_BAD_REQUEST;
  416. }
  417. // find the physical file on disk
  418. bool is_dir = false;
  419. char web_filename[FILENAME_MAX + 1];
  420. struct stat statbuf;
  421. if(!find_filename_to_serve(filename, web_filename, FILENAME_MAX, &statbuf, w, &is_dir)) {
  422. w->response.data->content_type = CT_TEXT_HTML;
  423. buffer_strcat(w->response.data, "File does not exist, or is not accessible: ");
  424. buffer_strcat_htmlescape(w->response.data, web_filename);
  425. return HTTP_RESP_NOT_FOUND;
  426. }
  427. if(is_dir && !web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH))
  428. return append_slash_to_url_and_redirect(w);
  429. // open the file
  430. w->ifd = open(web_filename, O_NONBLOCK, O_RDONLY);
  431. if(w->ifd == -1) {
  432. w->ifd = w->ofd;
  433. if(errno == EBUSY || errno == EAGAIN) {
  434. netdata_log_error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, web_filename);
  435. w->response.data->content_type = CT_TEXT_HTML;
  436. buffer_sprintf(w->response.header, "Location: /%s\r\n", filename);
  437. buffer_strcat(w->response.data, "File is currently busy, please try again later: ");
  438. buffer_strcat_htmlescape(w->response.data, web_filename);
  439. return HTTP_RESP_REDIR_TEMP;
  440. }
  441. else {
  442. netdata_log_error("%llu: Cannot open file '%s'.", w->id, web_filename);
  443. w->response.data->content_type = CT_TEXT_HTML;
  444. buffer_strcat(w->response.data, "Cannot open file: ");
  445. buffer_strcat_htmlescape(w->response.data, web_filename);
  446. return HTTP_RESP_NOT_FOUND;
  447. }
  448. }
  449. sock_setnonblock(w->ifd);
  450. w->response.data->content_type = contenttype_for_filename(web_filename);
  451. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%"PRId64" bytes, ifd %d, ofd %d).", w->id, web_filename, (int64_t)statbuf.st_size, w->ifd, w->ofd);
  452. w->mode = WEB_CLIENT_MODE_FILECOPY;
  453. web_client_enable_wait_receive(w);
  454. web_client_disable_wait_send(w);
  455. buffer_flush(w->response.data);
  456. buffer_need_bytes(w->response.data, (size_t)statbuf.st_size);
  457. w->response.rlen = (size_t)statbuf.st_size;
  458. #ifdef __APPLE__
  459. w->response.data->date = statbuf.st_mtimespec.tv_sec;
  460. #else
  461. w->response.data->date = statbuf.st_mtim.tv_sec;
  462. #endif
  463. buffer_cacheable(w->response.data);
  464. return HTTP_RESP_OK;
  465. }
  466. #endif
  467. void web_client_enable_deflate(struct web_client *w, int gzip) {
  468. if(unlikely(w->response.zinitialized)) {
  469. netdata_log_debug(D_DEFLATE, "%llu: Compression has already be initialized for this client.", w->id);
  470. return;
  471. }
  472. if(unlikely(w->response.sent)) {
  473. netdata_log_error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
  474. return;
  475. }
  476. w->response.zstream.zalloc = Z_NULL;
  477. w->response.zstream.zfree = Z_NULL;
  478. w->response.zstream.opaque = Z_NULL;
  479. w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
  480. w->response.zstream.avail_in = 0;
  481. w->response.zstream.total_in = 0;
  482. w->response.zstream.next_out = w->response.zbuffer;
  483. w->response.zstream.avail_out = 0;
  484. w->response.zstream.total_out = 0;
  485. w->response.zstream.zalloc = Z_NULL;
  486. w->response.zstream.zfree = Z_NULL;
  487. w->response.zstream.opaque = Z_NULL;
  488. // if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
  489. // netdata_log_error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
  490. // return;
  491. // }
  492. // Select GZIP compression: windowbits = 15 + 16 = 31
  493. if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) {
  494. netdata_log_error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
  495. return;
  496. }
  497. w->response.zsent = 0;
  498. w->response.zoutput = true;
  499. w->response.zinitialized = true;
  500. w->flags |= WEB_CLIENT_CHUNKED_TRANSFER;
  501. netdata_log_debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
  502. }
  503. void buffer_data_options2string(BUFFER *wb, uint32_t options) {
  504. int count = 0;
  505. if(options & RRDR_OPTION_NONZERO) {
  506. if(count++) buffer_strcat(wb, " ");
  507. buffer_strcat(wb, "nonzero");
  508. }
  509. if(options & RRDR_OPTION_REVERSED) {
  510. if(count++) buffer_strcat(wb, " ");
  511. buffer_strcat(wb, "flip");
  512. }
  513. if(options & RRDR_OPTION_JSON_WRAP) {
  514. if(count++) buffer_strcat(wb, " ");
  515. buffer_strcat(wb, "jsonwrap");
  516. }
  517. if(options & RRDR_OPTION_MIN2MAX) {
  518. if(count++) buffer_strcat(wb, " ");
  519. buffer_strcat(wb, "min2max");
  520. }
  521. if(options & RRDR_OPTION_MILLISECONDS) {
  522. if(count++) buffer_strcat(wb, " ");
  523. buffer_strcat(wb, "ms");
  524. }
  525. if(options & RRDR_OPTION_ABSOLUTE) {
  526. if(count++) buffer_strcat(wb, " ");
  527. buffer_strcat(wb, "absolute");
  528. }
  529. if(options & RRDR_OPTION_SECONDS) {
  530. if(count++) buffer_strcat(wb, " ");
  531. buffer_strcat(wb, "seconds");
  532. }
  533. if(options & RRDR_OPTION_NULL2ZERO) {
  534. if(count++) buffer_strcat(wb, " ");
  535. buffer_strcat(wb, "null2zero");
  536. }
  537. if(options & RRDR_OPTION_OBJECTSROWS) {
  538. if(count++) buffer_strcat(wb, " ");
  539. buffer_strcat(wb, "objectrows");
  540. }
  541. if(options & RRDR_OPTION_GOOGLE_JSON) {
  542. if(count++) buffer_strcat(wb, " ");
  543. buffer_strcat(wb, "google_json");
  544. }
  545. if(options & RRDR_OPTION_PERCENTAGE) {
  546. if(count++) buffer_strcat(wb, " ");
  547. buffer_strcat(wb, "percentage");
  548. }
  549. if(options & RRDR_OPTION_NOT_ALIGNED) {
  550. if(count++) buffer_strcat(wb, " ");
  551. buffer_strcat(wb, "unaligned");
  552. }
  553. if(options & RRDR_OPTION_ANOMALY_BIT) {
  554. if(count++) buffer_strcat(wb, " ");
  555. buffer_strcat(wb, "anomaly-bit");
  556. }
  557. }
  558. static inline int check_host_and_call(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) {
  559. //if(unlikely(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
  560. // buffer_flush(w->response.data);
  561. // buffer_strcat(w->response.data, "This host does not maintain a database");
  562. // return HTTP_RESP_BAD_REQUEST;
  563. //}
  564. return func(host, w, url);
  565. }
  566. static inline int UNUSED_FUNCTION(check_host_and_dashboard_acl_and_call)(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) {
  567. if(!web_client_can_access_dashboard(w))
  568. return web_client_permission_denied(w);
  569. return check_host_and_call(host, w, url, func);
  570. }
  571. static inline int UNUSED_FUNCTION(check_host_and_mgmt_acl_and_call)(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) {
  572. if(!web_client_can_access_mgmt(w))
  573. return web_client_permission_denied(w);
  574. return check_host_and_call(host, w, url, func);
  575. }
  576. int web_client_api_request(RRDHOST *host, struct web_client *w, char *url_path_fragment)
  577. {
  578. // get the api version
  579. char *tok = strsep_skip_consecutive_separators(&url_path_fragment, "/");
  580. if(tok && *tok) {
  581. netdata_log_debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
  582. if(strcmp(tok, "v2") == 0)
  583. return web_client_api_request_v2(host, w, url_path_fragment);
  584. else if(strcmp(tok, "v1") == 0)
  585. return web_client_api_request_v1(host, w, url_path_fragment);
  586. else {
  587. buffer_flush(w->response.data);
  588. w->response.data->content_type = CT_TEXT_HTML;
  589. buffer_strcat(w->response.data, "Unsupported API version: ");
  590. buffer_strcat_htmlescape(w->response.data, tok);
  591. return HTTP_RESP_NOT_FOUND;
  592. }
  593. }
  594. else {
  595. buffer_flush(w->response.data);
  596. buffer_sprintf(w->response.data, "Which API version?");
  597. return HTTP_RESP_BAD_REQUEST;
  598. }
  599. }
  600. const char *web_content_type_to_string(HTTP_CONTENT_TYPE content_type) {
  601. switch(content_type) {
  602. case CT_TEXT_HTML:
  603. return "text/html; charset=utf-8";
  604. case CT_APPLICATION_XML:
  605. return "application/xml; charset=utf-8";
  606. case CT_APPLICATION_JSON:
  607. return "application/json; charset=utf-8";
  608. case CT_APPLICATION_X_JAVASCRIPT:
  609. return "application/javascript; charset=utf-8";
  610. case CT_TEXT_CSS:
  611. return "text/css; charset=utf-8";
  612. case CT_TEXT_XML:
  613. return "text/xml; charset=utf-8";
  614. case CT_TEXT_XSL:
  615. return "text/xsl; charset=utf-8";
  616. case CT_APPLICATION_OCTET_STREAM:
  617. return "application/octet-stream";
  618. case CT_IMAGE_SVG_XML:
  619. return "image/svg+xml";
  620. case CT_APPLICATION_X_FONT_TRUETYPE:
  621. return "application/x-font-truetype";
  622. case CT_APPLICATION_X_FONT_OPENTYPE:
  623. return "application/x-font-opentype";
  624. case CT_APPLICATION_FONT_WOFF:
  625. return "application/font-woff";
  626. case CT_APPLICATION_FONT_WOFF2:
  627. return "application/font-woff2";
  628. case CT_APPLICATION_VND_MS_FONTOBJ:
  629. return "application/vnd.ms-fontobject";
  630. case CT_IMAGE_PNG:
  631. return "image/png";
  632. case CT_IMAGE_JPG:
  633. return "image/jpeg";
  634. case CT_IMAGE_GIF:
  635. return "image/gif";
  636. case CT_IMAGE_XICON:
  637. return "image/x-icon";
  638. case CT_IMAGE_BMP:
  639. return "image/bmp";
  640. case CT_IMAGE_ICNS:
  641. return "image/icns";
  642. case CT_PROMETHEUS:
  643. return "text/plain; version=0.0.4";
  644. case CT_AUDIO_MPEG:
  645. return "audio/mpeg";
  646. case CT_AUDIO_OGG:
  647. return "audio/ogg";
  648. case CT_VIDEO_MP4:
  649. return "video/mp4";
  650. case CT_APPLICATION_PDF:
  651. return "application/pdf";
  652. case CT_APPLICATION_ZIP:
  653. return "application/zip";
  654. default:
  655. case CT_TEXT_PLAIN:
  656. return "text/plain; charset=utf-8";
  657. }
  658. }
  659. const char *web_response_code_to_string(int code) {
  660. switch(code) {
  661. case 100:
  662. return "Continue";
  663. case 101:
  664. return "Switching Protocols";
  665. case 102:
  666. return "Processing";
  667. case 103:
  668. return "Early Hints";
  669. case 200:
  670. return "OK";
  671. case 201:
  672. return "Created";
  673. case 202:
  674. return "Accepted";
  675. case 203:
  676. return "Non-Authoritative Information";
  677. case 204:
  678. return "No Content";
  679. case 205:
  680. return "Reset Content";
  681. case 206:
  682. return "Partial Content";
  683. case 207:
  684. return "Multi-Status";
  685. case 208:
  686. return "Already Reported";
  687. case 226:
  688. return "IM Used";
  689. case 300:
  690. return "Multiple Choices";
  691. case 301:
  692. return "Moved Permanently";
  693. case 302:
  694. return "Found";
  695. case 303:
  696. return "See Other";
  697. case 304:
  698. return "Not Modified";
  699. case 305:
  700. return "Use Proxy";
  701. case 306:
  702. return "Switch Proxy";
  703. case 307:
  704. return "Temporary Redirect";
  705. case 308:
  706. return "Permanent Redirect";
  707. case 400:
  708. return "Bad Request";
  709. case 401:
  710. return "Unauthorized";
  711. case 402:
  712. return "Payment Required";
  713. case 403:
  714. return "Forbidden";
  715. case 404:
  716. return "Not Found";
  717. case 405:
  718. return "Method Not Allowed";
  719. case 406:
  720. return "Not Acceptable";
  721. case 407:
  722. return "Proxy Authentication Required";
  723. case 408:
  724. return "Request Timeout";
  725. case 409:
  726. return "Conflict";
  727. case 410:
  728. return "Gone";
  729. case 411:
  730. return "Length Required";
  731. case 412:
  732. return "Precondition Failed";
  733. case 413:
  734. return "Payload Too Large";
  735. case 414:
  736. return "URI Too Long";
  737. case 415:
  738. return "Unsupported Media Type";
  739. case 416:
  740. return "Range Not Satisfiable";
  741. case 417:
  742. return "Expectation Failed";
  743. case 418:
  744. return "I'm a teapot";
  745. case 421:
  746. return "Misdirected Request";
  747. case 422:
  748. return "Unprocessable Entity";
  749. case 423:
  750. return "Locked";
  751. case 424:
  752. return "Failed Dependency";
  753. case 425:
  754. return "Too Early";
  755. case 426:
  756. return "Upgrade Required";
  757. case 428:
  758. return "Precondition Required";
  759. case 429:
  760. return "Too Many Requests";
  761. case 431:
  762. return "Request Header Fields Too Large";
  763. case 451:
  764. return "Unavailable For Legal Reasons";
  765. case 500:
  766. return "Internal Server Error";
  767. case 501:
  768. return "Not Implemented";
  769. case 502:
  770. return "Bad Gateway";
  771. case 503:
  772. return "Service Unavailable";
  773. case 504:
  774. return "Gateway Timeout";
  775. case 505:
  776. return "HTTP Version Not Supported";
  777. case 506:
  778. return "Variant Also Negotiates";
  779. case 507:
  780. return "Insufficient Storage";
  781. case 508:
  782. return "Loop Detected";
  783. case 510:
  784. return "Not Extended";
  785. case 511:
  786. return "Network Authentication Required";
  787. default:
  788. if(code >= 100 && code < 200)
  789. return "Informational";
  790. if(code >= 200 && code < 300)
  791. return "Successful";
  792. if(code >= 300 && code < 400)
  793. return "Redirection";
  794. if(code >= 400 && code < 500)
  795. return "Client Error";
  796. if(code >= 500 && code < 600)
  797. return "Server Error";
  798. return "Undefined Error";
  799. }
  800. }
  801. static inline char *http_header_parse(struct web_client *w, char *s, int parse_useragent) {
  802. static uint32_t hash_origin = 0, hash_connection = 0, hash_donottrack = 0, hash_useragent = 0,
  803. hash_authorization = 0, hash_host = 0, hash_forwarded_host = 0;
  804. static uint32_t hash_accept_encoding = 0;
  805. if(unlikely(!hash_origin)) {
  806. hash_origin = simple_uhash("Origin");
  807. hash_connection = simple_uhash("Connection");
  808. hash_accept_encoding = simple_uhash("Accept-Encoding");
  809. hash_donottrack = simple_uhash("DNT");
  810. hash_useragent = simple_uhash("User-Agent");
  811. hash_authorization = simple_uhash("X-Auth-Token");
  812. hash_host = simple_uhash("Host");
  813. hash_forwarded_host = simple_uhash("X-Forwarded-Host");
  814. }
  815. char *e = s;
  816. // find the :
  817. while(*e && *e != ':') e++;
  818. if(!*e) return e;
  819. // get the name
  820. *e = '\0';
  821. // find the value
  822. char *v = e + 1, *ve;
  823. // skip leading spaces from value
  824. while(*v == ' ') v++;
  825. ve = v;
  826. // find the \r
  827. while(*ve && *ve != '\r') ve++;
  828. if(!*ve || ve[1] != '\n') {
  829. *e = ':';
  830. return ve;
  831. }
  832. // terminate the value
  833. *ve = '\0';
  834. uint32_t hash = simple_uhash(s);
  835. if(hash == hash_origin && !strcasecmp(s, "Origin"))
  836. w->origin = strdupz(v);
  837. else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
  838. if(strcasestr(v, "keep-alive"))
  839. web_client_enable_keepalive(w);
  840. }
  841. else if(respect_web_browser_do_not_track_policy && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
  842. if(*v == '0') web_client_disable_donottrack(w);
  843. else if(*v == '1') web_client_enable_donottrack(w);
  844. }
  845. else if(parse_useragent && hash == hash_useragent && !strcasecmp(s, "User-Agent")) {
  846. w->user_agent = strdupz(v);
  847. }
  848. else if(hash == hash_authorization&& !strcasecmp(s, "X-Auth-Token")) {
  849. w->auth_bearer_token = strdupz(v);
  850. }
  851. else if(hash == hash_host && !strcasecmp(s, "Host")) {
  852. char buffer[NI_MAXHOST];
  853. strncpyz(buffer, v, ((size_t)(ve - v) < sizeof(buffer) - 1 ? (size_t)(ve - v) : sizeof(buffer) - 1));
  854. w->server_host = strdupz(buffer);
  855. }
  856. else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
  857. if(web_enable_gzip) {
  858. if(strcasestr(v, "gzip"))
  859. web_client_enable_deflate(w, 1);
  860. //
  861. // does not seem to work
  862. // else if(strcasestr(v, "deflate"))
  863. // web_client_enable_deflate(w, 0);
  864. }
  865. }
  866. else if(hash == hash_forwarded_host && !strcasecmp(s, "X-Forwarded-Host")) {
  867. char buffer[NI_MAXHOST];
  868. strncpyz(buffer, v, ((size_t)(ve - v) < sizeof(buffer) - 1 ? (size_t)(ve - v) : sizeof(buffer) - 1));
  869. w->forwarded_host = strdupz(buffer);
  870. }
  871. *e = ':';
  872. *ve = '\r';
  873. return ve;
  874. }
  875. /**
  876. * Valid Method
  877. *
  878. * Netdata accepts only three methods, including one of these three(STREAM) is an internal method.
  879. *
  880. * @param w is the structure with the client request
  881. * @param s is the start string to parse
  882. *
  883. * @return it returns the next address to parse case the method is valid and NULL otherwise.
  884. */
  885. static inline char *web_client_valid_method(struct web_client *w, char *s) {
  886. // is is a valid request?
  887. if(!strncmp(s, "GET ", 4)) {
  888. s = &s[4];
  889. w->mode = WEB_CLIENT_MODE_GET;
  890. }
  891. else if(!strncmp(s, "OPTIONS ", 8)) {
  892. s = &s[8];
  893. w->mode = WEB_CLIENT_MODE_OPTIONS;
  894. }
  895. else if(!strncmp(s, "POST ", 5)) {
  896. s = &s[5];
  897. w->mode = WEB_CLIENT_MODE_POST;
  898. }
  899. else if(!strncmp(s, "STREAM ", 7)) {
  900. s = &s[7];
  901. #ifdef ENABLE_HTTPS
  902. if (!SSL_connection(&w->ssl) && web_client_is_using_ssl_force(w)) {
  903. w->header_parse_tries = 0;
  904. w->header_parse_last_size = 0;
  905. web_client_disable_wait_receive(w);
  906. char hostname[256];
  907. char *copyme = strstr(s,"hostname=");
  908. if ( copyme ){
  909. copyme += 9;
  910. char *end = strchr(copyme,'&');
  911. if(end){
  912. size_t length = MIN(255, end - copyme);
  913. memcpy(hostname,copyme,length);
  914. hostname[length] = 0X00;
  915. }
  916. else{
  917. memcpy(hostname,"not available",13);
  918. hostname[13] = 0x00;
  919. }
  920. }
  921. else{
  922. memcpy(hostname,"not available",13);
  923. hostname[13] = 0x00;
  924. }
  925. netdata_log_error("The server is configured to always use encrypted connections, please enable the SSL on child with hostname '%s'.",hostname);
  926. s = NULL;
  927. }
  928. #endif
  929. w->mode = WEB_CLIENT_MODE_STREAM;
  930. }
  931. else {
  932. s = NULL;
  933. }
  934. return s;
  935. }
  936. /**
  937. * Request validate
  938. *
  939. * @param w is the structure with the client request
  940. *
  941. * @return It returns HTTP_VALIDATION_OK on success and another code present
  942. * in the enum HTTP_VALIDATION otherwise.
  943. */
  944. static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
  945. char *s = (char *)buffer_tostring(w->response.data), *encoded_url = NULL;
  946. size_t last_pos = w->header_parse_last_size;
  947. w->header_parse_tries++;
  948. w->header_parse_last_size = buffer_strlen(w->response.data);
  949. int is_it_valid;
  950. if(w->header_parse_tries > 1) {
  951. if(last_pos > 4) last_pos -= 4; // allow searching for \r\n\r\n
  952. else last_pos = 0;
  953. if(w->header_parse_last_size < last_pos)
  954. last_pos = 0;
  955. is_it_valid = url_is_request_complete(s, &s[last_pos], w->header_parse_last_size, &w->post_payload, &w->post_payload_size);
  956. if(!is_it_valid) {
  957. if(w->header_parse_tries > HTTP_REQ_MAX_HEADER_FETCH_TRIES) {
  958. netdata_log_info("Disabling slow client after %zu attempts to read the request (%zu bytes received)", w->header_parse_tries, buffer_strlen(w->response.data));
  959. w->header_parse_tries = 0;
  960. w->header_parse_last_size = 0;
  961. web_client_disable_wait_receive(w);
  962. return HTTP_VALIDATION_TOO_MANY_READ_RETRIES;
  963. }
  964. return HTTP_VALIDATION_INCOMPLETE;
  965. }
  966. is_it_valid = 1;
  967. } else {
  968. last_pos = w->header_parse_last_size;
  969. is_it_valid = url_is_request_complete(s, &s[last_pos], w->header_parse_last_size, &w->post_payload, &w->post_payload_size);
  970. }
  971. s = web_client_valid_method(w, s);
  972. if (!s) {
  973. w->header_parse_tries = 0;
  974. w->header_parse_last_size = 0;
  975. web_client_disable_wait_receive(w);
  976. return HTTP_VALIDATION_NOT_SUPPORTED;
  977. } else if (!is_it_valid) {
  978. //Invalid request, we have more data after the end of message
  979. char *check = strstr((char *)buffer_tostring(w->response.data), "\r\n\r\n");
  980. if(check) {
  981. check += 4;
  982. if (*check) {
  983. w->header_parse_tries = 0;
  984. w->header_parse_last_size = 0;
  985. web_client_disable_wait_receive(w);
  986. return HTTP_VALIDATION_EXCESS_REQUEST_DATA;
  987. }
  988. }
  989. web_client_enable_wait_receive(w);
  990. return HTTP_VALIDATION_INCOMPLETE;
  991. }
  992. //After the method we have the path and query string together
  993. encoded_url = s;
  994. //we search for the position where we have " HTTP/", because it finishes the user request
  995. s = url_find_protocol(s);
  996. // incomplete requests
  997. if(unlikely(!*s)) {
  998. web_client_enable_wait_receive(w);
  999. return HTTP_VALIDATION_INCOMPLETE;
  1000. }
  1001. // we have the end of encoded_url - remember it
  1002. char *ue = s;
  1003. // make sure we have complete request
  1004. // complete requests contain: \r\n\r\n
  1005. while(*s) {
  1006. // find a line feed
  1007. while(*s && *s++ != '\r');
  1008. // did we reach the end?
  1009. if(unlikely(!*s)) break;
  1010. // is it \r\n ?
  1011. if(likely(*s++ == '\n')) {
  1012. // is it again \r\n ? (header end)
  1013. if(unlikely(*s == '\r' && s[1] == '\n')) {
  1014. // a valid complete HTTP request found
  1015. char c = *ue;
  1016. *ue = '\0';
  1017. web_client_decode_path_and_query_string(w, encoded_url);
  1018. *ue = c;
  1019. #ifdef ENABLE_HTTPS
  1020. if ( (!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx) ) {
  1021. if (!w->ssl.conn && (web_client_is_using_ssl_force(w) || web_client_is_using_ssl_default(w)) && (w->mode != WEB_CLIENT_MODE_STREAM)) {
  1022. w->header_parse_tries = 0;
  1023. w->header_parse_last_size = 0;
  1024. web_client_disable_wait_receive(w);
  1025. return HTTP_VALIDATION_REDIRECT;
  1026. }
  1027. }
  1028. #endif
  1029. w->header_parse_tries = 0;
  1030. w->header_parse_last_size = 0;
  1031. web_client_disable_wait_receive(w);
  1032. return HTTP_VALIDATION_OK;
  1033. }
  1034. // another header line
  1035. s = http_header_parse(w, s, (w->mode == WEB_CLIENT_MODE_STREAM)); // parse user agent
  1036. }
  1037. }
  1038. // incomplete request
  1039. web_client_enable_wait_receive(w);
  1040. return HTTP_VALIDATION_INCOMPLETE;
  1041. }
  1042. static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
  1043. {
  1044. ssize_t bytes;
  1045. #ifdef ENABLE_HTTPS
  1046. if ((!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx)) {
  1047. if (SSL_connection(&w->ssl)) {
  1048. bytes = netdata_ssl_write(&w->ssl, buf, len) ;
  1049. web_client_enable_wait_from_ssl(w);
  1050. }
  1051. else
  1052. bytes = send(w->ofd,buf, len , flags);
  1053. } else
  1054. bytes = send(w->ofd,buf, len , flags);
  1055. #else
  1056. bytes = send(w->ofd, buf, len, flags);
  1057. #endif
  1058. return bytes;
  1059. }
  1060. void web_client_build_http_header(struct web_client *w) {
  1061. if(unlikely(w->response.code != HTTP_RESP_OK))
  1062. buffer_no_cacheable(w->response.data);
  1063. if(unlikely(!w->response.data->date))
  1064. w->response.data->date = now_realtime_sec();
  1065. // set a proper expiration date, if not already set
  1066. if(unlikely(!w->response.data->expires)) {
  1067. if(w->response.data->options & WB_CONTENT_NO_CACHEABLE)
  1068. w->response.data->expires = w->response.data->date + localhost->rrd_update_every;
  1069. else
  1070. w->response.data->expires = w->response.data->date + 86400;
  1071. }
  1072. // prepare the HTTP response header
  1073. netdata_log_debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, w->response.code);
  1074. const char *content_type_string = web_content_type_to_string(w->response.data->content_type);
  1075. const char *code_msg = web_response_code_to_string(w->response.code);
  1076. // prepare the last modified and expiration dates
  1077. char date[32], edate[32];
  1078. {
  1079. struct tm tmbuf, *tm;
  1080. tm = gmtime_r(&w->response.data->date, &tmbuf);
  1081. strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm);
  1082. tm = gmtime_r(&w->response.data->expires, &tmbuf);
  1083. strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", tm);
  1084. }
  1085. if (w->response.code == HTTP_RESP_HTTPS_UPGRADE) {
  1086. buffer_sprintf(w->response.header_output,
  1087. "HTTP/1.1 %d %s\r\n"
  1088. "Location: https://%s%s\r\n",
  1089. w->response.code, code_msg,
  1090. w->server_host ? w->server_host : "",
  1091. buffer_tostring(w->url_as_received));
  1092. w->response.code = HTTP_RESP_MOVED_PERM;
  1093. }
  1094. else {
  1095. buffer_sprintf(w->response.header_output,
  1096. "HTTP/1.1 %d %s\r\n"
  1097. "Connection: %s\r\n"
  1098. "Server: Netdata Embedded HTTP Server %s\r\n"
  1099. "Access-Control-Allow-Origin: %s\r\n"
  1100. "Access-Control-Allow-Credentials: true\r\n"
  1101. "Content-Type: %s\r\n"
  1102. "Date: %s\r\n",
  1103. w->response.code,
  1104. code_msg,
  1105. web_client_has_keepalive(w)?"keep-alive":"close",
  1106. VERSION,
  1107. w->origin ? w->origin : "*",
  1108. content_type_string,
  1109. date);
  1110. }
  1111. if(unlikely(web_x_frame_options))
  1112. buffer_sprintf(w->response.header_output, "X-Frame-Options: %s\r\n", web_x_frame_options);
  1113. if(w->response.has_cookies) {
  1114. if(respect_web_browser_do_not_track_policy)
  1115. buffer_sprintf(w->response.header_output,
  1116. "Tk: T;cookies\r\n");
  1117. }
  1118. else {
  1119. if(respect_web_browser_do_not_track_policy) {
  1120. if(web_client_has_tracking_required(w))
  1121. buffer_sprintf(w->response.header_output,
  1122. "Tk: T;cookies\r\n");
  1123. else
  1124. buffer_sprintf(w->response.header_output,
  1125. "Tk: N\r\n");
  1126. }
  1127. }
  1128. if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
  1129. buffer_strcat(w->response.header_output,
  1130. "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
  1131. "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control, x-auth-token\r\n"
  1132. "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
  1133. );
  1134. }
  1135. else {
  1136. buffer_sprintf(w->response.header_output,
  1137. "Cache-Control: %s\r\n"
  1138. "Expires: %s\r\n",
  1139. (w->response.data->options & WB_CONTENT_NO_CACHEABLE)?"no-cache, no-store, must-revalidate\r\nPragma: no-cache":"public",
  1140. edate);
  1141. }
  1142. // copy a possibly available custom header
  1143. if(unlikely(buffer_strlen(w->response.header)))
  1144. buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
  1145. // headers related to the transfer method
  1146. if(likely(w->response.zoutput))
  1147. buffer_strcat(w->response.header_output, "Content-Encoding: gzip\r\n");
  1148. if(likely(w->flags & WEB_CLIENT_CHUNKED_TRANSFER))
  1149. buffer_strcat(w->response.header_output, "Transfer-Encoding: chunked\r\n");
  1150. else {
  1151. if(likely((w->response.data->len || w->response.rlen))) {
  1152. // we know the content length, put it
  1153. buffer_sprintf(w->response.header_output, "Content-Length: %zu\r\n", w->response.data->len? w->response.data->len: w->response.rlen);
  1154. }
  1155. else {
  1156. // we don't know the content length, disable keep-alive
  1157. web_client_disable_keepalive(w);
  1158. }
  1159. }
  1160. // end of HTTP header
  1161. buffer_strcat(w->response.header_output, "\r\n");
  1162. }
  1163. static inline void web_client_send_http_header(struct web_client *w) {
  1164. web_client_build_http_header(w);
  1165. // sent the HTTP header
  1166. netdata_log_debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
  1167. , w->id
  1168. , buffer_strlen(w->response.header_output)
  1169. , buffer_tostring(w->response.header_output)
  1170. );
  1171. web_client_cork_socket(w);
  1172. size_t count = 0;
  1173. ssize_t bytes;
  1174. #ifdef ENABLE_HTTPS
  1175. if ( (!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx) ) {
  1176. if (SSL_connection(&w->ssl)) {
  1177. bytes = netdata_ssl_write(&w->ssl, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output));
  1178. web_client_enable_wait_from_ssl(w);
  1179. }
  1180. else {
  1181. while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
  1182. count++;
  1183. if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
  1184. netdata_log_error("Cannot send HTTP headers to web client.");
  1185. break;
  1186. }
  1187. }
  1188. }
  1189. }
  1190. else {
  1191. while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
  1192. count++;
  1193. if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
  1194. netdata_log_error("Cannot send HTTP headers to web client.");
  1195. break;
  1196. }
  1197. }
  1198. }
  1199. #else
  1200. while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
  1201. count++;
  1202. if(count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
  1203. netdata_log_error("Cannot send HTTP headers to web client.");
  1204. break;
  1205. }
  1206. }
  1207. #endif
  1208. if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
  1209. if(bytes > 0)
  1210. w->statistics.sent_bytes += bytes;
  1211. if (bytes < 0) {
  1212. netdata_log_error("HTTP headers failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
  1213. , buffer_strlen(w->response.header_output)
  1214. , bytes);
  1215. WEB_CLIENT_IS_DEAD(w);
  1216. return;
  1217. }
  1218. }
  1219. else
  1220. w->statistics.sent_bytes += bytes;
  1221. }
  1222. static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, char *url, bool nodeid, int (*func)(RRDHOST *, struct web_client *, char *)) {
  1223. static uint32_t hash_localhost = 0;
  1224. if(unlikely(!hash_localhost)) {
  1225. hash_localhost = simple_hash("localhost");
  1226. }
  1227. if(host != localhost) {
  1228. buffer_flush(w->response.data);
  1229. buffer_strcat(w->response.data, "Nesting of hosts is not allowed.");
  1230. return HTTP_RESP_BAD_REQUEST;
  1231. }
  1232. char *tok = strsep_skip_consecutive_separators(&url, "/");
  1233. if(tok && *tok) {
  1234. netdata_log_debug(D_WEB_CLIENT, "%llu: Searching for host with name '%s'.", w->id, tok);
  1235. if(nodeid) {
  1236. host = find_host_by_node_id(tok);
  1237. if(!host) {
  1238. host = rrdhost_find_by_hostname(tok);
  1239. if (!host)
  1240. host = rrdhost_find_by_guid(tok);
  1241. }
  1242. }
  1243. else {
  1244. host = rrdhost_find_by_hostname(tok);
  1245. if(!host) {
  1246. host = rrdhost_find_by_guid(tok);
  1247. if (!host)
  1248. host = find_host_by_node_id(tok);
  1249. }
  1250. }
  1251. if(!host) {
  1252. // we didn't find it, but it may be a uuid case mismatch for MACHINE_GUID
  1253. // so, recreate the machine guid in lower-case.
  1254. uuid_t uuid;
  1255. char txt[UUID_STR_LEN];
  1256. if (uuid_parse(tok, uuid) == 0) {
  1257. uuid_unparse_lower(uuid, txt);
  1258. host = rrdhost_find_by_guid(txt);
  1259. }
  1260. }
  1261. if (host) {
  1262. if(!url)
  1263. //no delim found
  1264. return append_slash_to_url_and_redirect(w);
  1265. size_t len = strlen(url) + 2;
  1266. char buf[len];
  1267. buf[0] = '/';
  1268. strcpy(&buf[1], url);
  1269. buf[len - 1] = '\0';
  1270. buffer_flush(w->url_path_decoded);
  1271. buffer_strcat(w->url_path_decoded, buf);
  1272. return func(host, w, buf);
  1273. }
  1274. }
  1275. buffer_flush(w->response.data);
  1276. w->response.data->content_type = CT_TEXT_HTML;
  1277. buffer_strcat(w->response.data, "This netdata does not maintain a database for host: ");
  1278. buffer_strcat_htmlescape(w->response.data, tok?tok:"");
  1279. return HTTP_RESP_NOT_FOUND;
  1280. }
  1281. int web_client_api_request_with_node_selection(RRDHOST *host, struct web_client *w, char *decoded_url_path) {
  1282. static uint32_t
  1283. hash_api = 0,
  1284. hash_host = 0,
  1285. hash_node = 0;
  1286. if(unlikely(!hash_api)) {
  1287. hash_api = simple_hash("api");
  1288. hash_host = simple_hash("host");
  1289. hash_node = simple_hash("node");
  1290. }
  1291. char *tok = strsep_skip_consecutive_separators(&decoded_url_path, "/?");
  1292. if(likely(tok && *tok)) {
  1293. uint32_t hash = simple_hash(tok);
  1294. if(unlikely(hash == hash_api && strcmp(tok, "api") == 0)) {
  1295. // current API
  1296. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
  1297. return check_host_and_call(host, w, decoded_url_path, web_client_api_request);
  1298. }
  1299. else if(unlikely((hash == hash_host && strcmp(tok, "host") == 0) || (hash == hash_node && strcmp(tok, "node") == 0))) {
  1300. // host switching
  1301. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
  1302. return web_client_switch_host(host, w, decoded_url_path, hash == hash_node, web_client_api_request_with_node_selection);
  1303. }
  1304. }
  1305. buffer_flush(w->response.data);
  1306. buffer_strcat(w->response.data, "Unknown API endpoint.");
  1307. w->response.data->content_type = CT_TEXT_HTML;
  1308. return HTTP_RESP_NOT_FOUND;
  1309. }
  1310. static inline int web_client_process_url(RRDHOST *host, struct web_client *w, char *decoded_url_path) {
  1311. if(unlikely(!service_running(ABILITY_WEB_REQUESTS)))
  1312. return web_client_permission_denied(w);
  1313. static uint32_t
  1314. hash_api = 0,
  1315. hash_netdata_conf = 0,
  1316. hash_host = 0,
  1317. hash_node = 0,
  1318. hash_v0 = 0,
  1319. hash_v1 = 0,
  1320. hash_v2 = 0;
  1321. #ifdef NETDATA_INTERNAL_CHECKS
  1322. static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
  1323. #endif
  1324. if(unlikely(!hash_api)) {
  1325. hash_api = simple_hash("api");
  1326. hash_netdata_conf = simple_hash("netdata.conf");
  1327. hash_host = simple_hash("host");
  1328. hash_node = simple_hash("node");
  1329. hash_v0 = simple_hash("v0");
  1330. hash_v1 = simple_hash("v1");
  1331. hash_v2 = simple_hash("v2");
  1332. #ifdef NETDATA_INTERNAL_CHECKS
  1333. hash_exit = simple_hash("exit");
  1334. hash_debug = simple_hash("debug");
  1335. hash_mirror = simple_hash("mirror");
  1336. #endif
  1337. }
  1338. // keep a copy of the decoded path, in case we need to serve it as a filename
  1339. char filename[FILENAME_MAX + 1];
  1340. strncpyz(filename, decoded_url_path ? decoded_url_path : "", FILENAME_MAX);
  1341. char *tok = strsep_skip_consecutive_separators(&decoded_url_path, "/?");
  1342. if(likely(tok && *tok)) {
  1343. uint32_t hash = simple_hash(tok);
  1344. netdata_log_debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
  1345. if(likely(hash == hash_api && strcmp(tok, "api") == 0)) { // current API
  1346. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: API request ...", w->id);
  1347. return check_host_and_call(host, w, decoded_url_path, web_client_api_request);
  1348. }
  1349. else if(unlikely((hash == hash_host && strcmp(tok, "host") == 0) || (hash == hash_node && strcmp(tok, "node") == 0))) { // host switching
  1350. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
  1351. return web_client_switch_host(host, w, decoded_url_path, hash == hash_node, web_client_process_url);
  1352. }
  1353. else if(unlikely(hash == hash_v2 && strcmp(tok, "v2") == 0)) {
  1354. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
  1355. return bad_request_multiple_dashboard_versions(w);
  1356. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V2);
  1357. return web_client_process_url(host, w, decoded_url_path);
  1358. }
  1359. else if(unlikely(hash == hash_v1 && strcmp(tok, "v1") == 0)) {
  1360. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
  1361. return bad_request_multiple_dashboard_versions(w);
  1362. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V1);
  1363. return web_client_process_url(host, w, decoded_url_path);
  1364. }
  1365. else if(unlikely(hash == hash_v0 && strcmp(tok, "v0") == 0)) {
  1366. if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
  1367. return bad_request_multiple_dashboard_versions(w);
  1368. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V0);
  1369. return web_client_process_url(host, w, decoded_url_path);
  1370. }
  1371. else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf
  1372. if(unlikely(!web_client_can_access_netdataconf(w)))
  1373. return web_client_permission_denied(w);
  1374. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id);
  1375. w->response.data->content_type = CT_TEXT_PLAIN;
  1376. buffer_flush(w->response.data);
  1377. config_generate(w->response.data, 0);
  1378. return HTTP_RESP_OK;
  1379. }
  1380. #ifdef NETDATA_INTERNAL_CHECKS
  1381. else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) {
  1382. if(unlikely(!web_client_can_access_netdataconf(w)))
  1383. return web_client_permission_denied(w);
  1384. w->response.data->content_type = CT_TEXT_PLAIN;
  1385. buffer_flush(w->response.data);
  1386. if(!netdata_exit)
  1387. buffer_strcat(w->response.data, "ok, will do...");
  1388. else
  1389. buffer_strcat(w->response.data, "I am doing it already");
  1390. netdata_log_error("web request to exit received.");
  1391. netdata_cleanup_and_exit(0);
  1392. return HTTP_RESP_OK;
  1393. }
  1394. else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) {
  1395. if(unlikely(!web_client_can_access_netdataconf(w)))
  1396. return web_client_permission_denied(w);
  1397. buffer_flush(w->response.data);
  1398. // get the name of the data to show
  1399. tok = strsep_skip_consecutive_separators(&decoded_url_path, "&");
  1400. if(tok && *tok) {
  1401. netdata_log_debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
  1402. // do we have such a data set?
  1403. RRDSET *st = rrdset_find_byname(host, tok);
  1404. if(!st) st = rrdset_find(host, tok);
  1405. if(!st) {
  1406. w->response.data->content_type = CT_TEXT_HTML;
  1407. buffer_strcat(w->response.data, "Chart is not found: ");
  1408. buffer_strcat_htmlescape(w->response.data, tok);
  1409. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
  1410. return HTTP_RESP_NOT_FOUND;
  1411. }
  1412. debug_flags |= D_RRD_STATS;
  1413. if(rrdset_flag_check(st, RRDSET_FLAG_DEBUG))
  1414. rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
  1415. else
  1416. rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
  1417. w->response.data->content_type = CT_TEXT_HTML;
  1418. buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
  1419. buffer_strcat_htmlescape(w->response.data, tok);
  1420. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
  1421. return HTTP_RESP_OK;
  1422. }
  1423. buffer_flush(w->response.data);
  1424. buffer_strcat(w->response.data, "debug which chart?\r\n");
  1425. return HTTP_RESP_BAD_REQUEST;
  1426. }
  1427. else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) {
  1428. if(unlikely(!web_client_can_access_netdataconf(w)))
  1429. return web_client_permission_denied(w);
  1430. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
  1431. // replace the zero bytes with spaces
  1432. buffer_char_replace(w->response.data, '\0', ' ');
  1433. // just leave the buffer as-is
  1434. // it will be copied back to the client
  1435. return HTTP_RESP_OK;
  1436. }
  1437. #endif /* NETDATA_INTERNAL_CHECKS */
  1438. }
  1439. buffer_flush(w->response.data);
  1440. return mysendfile(w, filename);
  1441. }
  1442. void web_client_process_request(struct web_client *w) {
  1443. // start timing us
  1444. web_client_timeout_checkpoint_init(w);
  1445. switch(http_request_validate(w)) {
  1446. case HTTP_VALIDATION_OK:
  1447. switch(w->mode) {
  1448. case WEB_CLIENT_MODE_STREAM:
  1449. if(unlikely(!web_client_can_access_stream(w))) {
  1450. web_client_permission_denied(w);
  1451. return;
  1452. }
  1453. w->response.code = rrdpush_receiver_thread_spawn(w, (char *)buffer_tostring(w->url_query_string_decoded));
  1454. return;
  1455. case WEB_CLIENT_MODE_OPTIONS:
  1456. if(unlikely(
  1457. !web_client_can_access_dashboard(w) &&
  1458. !web_client_can_access_registry(w) &&
  1459. !web_client_can_access_badges(w) &&
  1460. !web_client_can_access_mgmt(w) &&
  1461. !web_client_can_access_netdataconf(w)
  1462. )) {
  1463. web_client_permission_denied(w);
  1464. break;
  1465. }
  1466. w->response.data->content_type = CT_TEXT_PLAIN;
  1467. buffer_flush(w->response.data);
  1468. buffer_strcat(w->response.data, "OK");
  1469. w->response.code = HTTP_RESP_OK;
  1470. break;
  1471. case WEB_CLIENT_MODE_FILECOPY:
  1472. case WEB_CLIENT_MODE_POST:
  1473. case WEB_CLIENT_MODE_GET:
  1474. if(unlikely(
  1475. !web_client_can_access_dashboard(w) &&
  1476. !web_client_can_access_registry(w) &&
  1477. !web_client_can_access_badges(w) &&
  1478. !web_client_can_access_mgmt(w) &&
  1479. !web_client_can_access_netdataconf(w)
  1480. )) {
  1481. web_client_permission_denied(w);
  1482. break;
  1483. }
  1484. web_client_reset_path_flags(w);
  1485. // find if the URL path has a filename extension
  1486. char path[FILENAME_MAX + 1];
  1487. strncpyz(path, buffer_tostring(w->url_path_decoded), FILENAME_MAX);
  1488. char *s = path, *e = path;
  1489. // remove the query string and find the last char
  1490. for (; *e ; e++) {
  1491. if (*e == '?')
  1492. break;
  1493. }
  1494. if(e == s || (*(e - 1) == '/'))
  1495. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_TRAILING_SLASH);
  1496. // check if there is a filename extension
  1497. while (--e > s) {
  1498. if (*e == '/')
  1499. break;
  1500. if(*e == '.') {
  1501. web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_HAS_FILE_EXTENSION);
  1502. break;
  1503. }
  1504. }
  1505. w->response.code = (short)web_client_process_url(localhost, w, path);
  1506. break;
  1507. }
  1508. break;
  1509. case HTTP_VALIDATION_INCOMPLETE:
  1510. if(w->response.data->len > NETDATA_WEB_REQUEST_MAX_SIZE) {
  1511. buffer_flush(w->url_as_received);
  1512. buffer_strcat(w->url_as_received, "too big request");
  1513. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
  1514. size_t len = w->response.data->len;
  1515. buffer_flush(w->response.data);
  1516. buffer_sprintf(w->response.data, "Received request is too big (received %zu bytes, max is %zu bytes).\r\n", len, (size_t)NETDATA_WEB_REQUEST_MAX_SIZE);
  1517. w->response.code = HTTP_RESP_BAD_REQUEST;
  1518. }
  1519. else {
  1520. // wait for more data
  1521. // set to normal to prevent web_server_rcv_callback
  1522. // from going into stream mode
  1523. if (w->mode == WEB_CLIENT_MODE_STREAM)
  1524. w->mode = WEB_CLIENT_MODE_GET;
  1525. return;
  1526. }
  1527. break;
  1528. #ifdef ENABLE_HTTPS
  1529. case HTTP_VALIDATION_REDIRECT:
  1530. {
  1531. buffer_flush(w->response.data);
  1532. w->response.data->content_type = CT_TEXT_HTML;
  1533. buffer_strcat(w->response.data,
  1534. "<!DOCTYPE html><!-- SPDX-License-Identifier: GPL-3.0-or-later --><html>"
  1535. "<body onload=\"window.location.href ='https://'+ window.location.hostname +"
  1536. " ':' + window.location.port + window.location.pathname + window.location.search\">"
  1537. "Redirecting to safety connection, case your browser does not support redirection, please"
  1538. " click <a onclick=\"window.location.href ='https://'+ window.location.hostname + ':' "
  1539. " + window.location.port + window.location.pathname + window.location.search\">here</a>."
  1540. "</body></html>");
  1541. w->response.code = HTTP_RESP_HTTPS_UPGRADE;
  1542. break;
  1543. }
  1544. #endif
  1545. case HTTP_VALIDATION_MALFORMED_URL:
  1546. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Malformed URL '%s'.", w->id, w->response.data->buffer);
  1547. buffer_flush(w->response.data);
  1548. buffer_strcat(w->response.data, "Malformed URL...\r\n");
  1549. w->response.code = HTTP_RESP_BAD_REQUEST;
  1550. break;
  1551. case HTTP_VALIDATION_EXCESS_REQUEST_DATA:
  1552. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Excess data in request '%s'.", w->id, w->response.data->buffer);
  1553. buffer_flush(w->response.data);
  1554. buffer_strcat(w->response.data, "Excess data in request.\r\n");
  1555. w->response.code = HTTP_RESP_BAD_REQUEST;
  1556. break;
  1557. case HTTP_VALIDATION_TOO_MANY_READ_RETRIES:
  1558. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Too many retries to read request '%s'.", w->id, w->response.data->buffer);
  1559. buffer_flush(w->response.data);
  1560. buffer_strcat(w->response.data, "Too many retries to read request.\r\n");
  1561. w->response.code = HTTP_RESP_BAD_REQUEST;
  1562. break;
  1563. case HTTP_VALIDATION_NOT_SUPPORTED:
  1564. netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: HTTP method requested is not supported '%s'.", w->id, w->response.data->buffer);
  1565. buffer_flush(w->response.data);
  1566. buffer_strcat(w->response.data, "HTTP method requested is not supported...\r\n");
  1567. w->response.code = HTTP_RESP_BAD_REQUEST;
  1568. break;
  1569. }
  1570. // keep track of the processing time
  1571. web_client_timeout_checkpoint_response_ready(w, NULL);
  1572. w->response.sent = 0;
  1573. web_client_send_http_header(w);
  1574. // enable sending immediately if we have data
  1575. if(w->response.data->len) web_client_enable_wait_send(w);
  1576. else web_client_disable_wait_send(w);
  1577. switch(w->mode) {
  1578. case WEB_CLIENT_MODE_STREAM:
  1579. netdata_log_debug(D_WEB_CLIENT, "%llu: STREAM done.", w->id);
  1580. break;
  1581. case WEB_CLIENT_MODE_OPTIONS:
  1582. netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
  1583. break;
  1584. case WEB_CLIENT_MODE_POST:
  1585. case WEB_CLIENT_MODE_GET:
  1586. netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
  1587. break;
  1588. case WEB_CLIENT_MODE_FILECOPY:
  1589. if(w->response.rlen) {
  1590. netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
  1591. web_client_enable_wait_receive(w);
  1592. /*
  1593. // utilize the kernel sendfile() for copying the file to the socket.
  1594. // this block of code can be commented, without anything missing.
  1595. // when it is commented, the program will copy the data using async I/O.
  1596. {
  1597. long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
  1598. if(len != w->response.data->rbytes)
  1599. netdata_log_error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
  1600. else
  1601. web_client_request_done(w);
  1602. }
  1603. */
  1604. }
  1605. else
  1606. netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id);
  1607. break;
  1608. default:
  1609. fatal("%llu: Unknown client mode %u.", w->id, w->mode);
  1610. break;
  1611. }
  1612. }
  1613. ssize_t web_client_send_chunk_header(struct web_client *w, size_t len)
  1614. {
  1615. netdata_log_debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
  1616. char buf[24];
  1617. ssize_t bytes;
  1618. bytes = (ssize_t)sprintf(buf, "%zX\r\n", len);
  1619. buf[bytes] = 0x00;
  1620. bytes = web_client_send_data(w,buf,strlen(buf),0);
  1621. if(bytes > 0) {
  1622. netdata_log_debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
  1623. w->statistics.sent_bytes += bytes;
  1624. }
  1625. else if(bytes == 0) {
  1626. netdata_log_debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id);
  1627. }
  1628. else {
  1629. netdata_log_debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id);
  1630. WEB_CLIENT_IS_DEAD(w);
  1631. }
  1632. return bytes;
  1633. }
  1634. ssize_t web_client_send_chunk_close(struct web_client *w)
  1635. {
  1636. //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
  1637. ssize_t bytes;
  1638. bytes = web_client_send_data(w,"\r\n",2,0);
  1639. if(bytes > 0) {
  1640. netdata_log_debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
  1641. w->statistics.sent_bytes += bytes;
  1642. }
  1643. else if(bytes == 0) {
  1644. netdata_log_debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id);
  1645. }
  1646. else {
  1647. netdata_log_debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id);
  1648. WEB_CLIENT_IS_DEAD(w);
  1649. }
  1650. return bytes;
  1651. }
  1652. ssize_t web_client_send_chunk_finalize(struct web_client *w)
  1653. {
  1654. //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
  1655. ssize_t bytes;
  1656. bytes = web_client_send_data(w,"\r\n0\r\n\r\n",7,0);
  1657. if(bytes > 0) {
  1658. netdata_log_debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
  1659. w->statistics.sent_bytes += bytes;
  1660. }
  1661. else if(bytes == 0) {
  1662. netdata_log_debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id);
  1663. }
  1664. else {
  1665. netdata_log_debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id);
  1666. WEB_CLIENT_IS_DEAD(w);
  1667. }
  1668. return bytes;
  1669. }
  1670. ssize_t web_client_send_deflate(struct web_client *w)
  1671. {
  1672. ssize_t len = 0, t = 0;
  1673. // when using compression,
  1674. // w->response.sent is the amount of bytes passed through compression
  1675. netdata_log_debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
  1676. w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
  1677. if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
  1678. // there is nothing to send
  1679. netdata_log_debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
  1680. // finalize the chunk
  1681. if(w->response.sent != 0) {
  1682. t = web_client_send_chunk_finalize(w);
  1683. if(t < 0) return t;
  1684. }
  1685. if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) {
  1686. // we have to wait, more data will come
  1687. netdata_log_debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
  1688. web_client_disable_wait_send(w);
  1689. return t;
  1690. }
  1691. if(unlikely(!web_client_has_keepalive(w))) {
  1692. netdata_log_debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
  1693. WEB_CLIENT_IS_DEAD(w);
  1694. return t;
  1695. }
  1696. // reset the client
  1697. web_client_request_done(w);
  1698. netdata_log_debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id);
  1699. return t;
  1700. }
  1701. if(w->response.zhave == w->response.zsent) {
  1702. // compress more input data
  1703. // close the previous open chunk
  1704. if(w->response.sent != 0) {
  1705. t = web_client_send_chunk_close(w);
  1706. if(t < 0) return t;
  1707. }
  1708. netdata_log_debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in);
  1709. // give the compressor all the data not passed through the compressor yet
  1710. if(w->response.data->len > w->response.sent) {
  1711. w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in];
  1712. w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent);
  1713. }
  1714. // reset the compressor output buffer
  1715. w->response.zstream.next_out = w->response.zbuffer;
  1716. w->response.zstream.avail_out = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE;
  1717. // ask for FINISH if we have all the input
  1718. int flush = Z_SYNC_FLUSH;
  1719. if((w->mode == WEB_CLIENT_MODE_GET || w->mode == WEB_CLIENT_MODE_POST)
  1720. || (w->mode == WEB_CLIENT_MODE_FILECOPY && !web_client_has_wait_receive(w) && w->response.data->len == w->response.rlen)) {
  1721. flush = Z_FINISH;
  1722. netdata_log_debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
  1723. }
  1724. else {
  1725. netdata_log_debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id);
  1726. }
  1727. // compress
  1728. if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
  1729. netdata_log_error("%llu: Compression failed. Closing down client.", w->id);
  1730. web_client_request_done(w);
  1731. return(-1);
  1732. }
  1733. w->response.zhave = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE - w->response.zstream.avail_out;
  1734. w->response.zsent = 0;
  1735. // keep track of the bytes passed through the compressor
  1736. w->response.sent = w->response.data->len;
  1737. netdata_log_debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave);
  1738. // open a new chunk
  1739. ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave);
  1740. if(t2 < 0) return t2;
  1741. t += t2;
  1742. }
  1743. netdata_log_debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
  1744. len = web_client_send_data(w,&w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
  1745. if(len > 0) {
  1746. w->statistics.sent_bytes += len;
  1747. w->response.zsent += len;
  1748. len += t;
  1749. netdata_log_debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len);
  1750. }
  1751. else if(len == 0) {
  1752. netdata_log_debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).",
  1753. w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
  1754. }
  1755. else {
  1756. netdata_log_debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
  1757. WEB_CLIENT_IS_DEAD(w);
  1758. }
  1759. return(len);
  1760. }
  1761. ssize_t web_client_send(struct web_client *w) {
  1762. if(likely(w->response.zoutput)) return web_client_send_deflate(w);
  1763. ssize_t bytes;
  1764. if(unlikely(w->response.data->len - w->response.sent == 0)) {
  1765. // there is nothing to send
  1766. netdata_log_debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
  1767. // there can be two cases for this
  1768. // A. we have done everything
  1769. // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
  1770. if(w->mode == WEB_CLIENT_MODE_FILECOPY && web_client_has_wait_receive(w) && w->response.rlen && w->response.rlen > w->response.data->len) {
  1771. // we have to wait, more data will come
  1772. netdata_log_debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
  1773. web_client_disable_wait_send(w);
  1774. return 0;
  1775. }
  1776. if(unlikely(!web_client_has_keepalive(w))) {
  1777. netdata_log_debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
  1778. WEB_CLIENT_IS_DEAD(w);
  1779. return 0;
  1780. }
  1781. web_client_request_done(w);
  1782. netdata_log_debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id);
  1783. return 0;
  1784. }
  1785. bytes = web_client_send_data(w,&w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
  1786. if(likely(bytes > 0)) {
  1787. w->statistics.sent_bytes += bytes;
  1788. w->response.sent += bytes;
  1789. netdata_log_debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes);
  1790. }
  1791. else if(likely(bytes == 0)) {
  1792. netdata_log_debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
  1793. }
  1794. else {
  1795. netdata_log_debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
  1796. WEB_CLIENT_IS_DEAD(w);
  1797. }
  1798. return(bytes);
  1799. }
  1800. ssize_t web_client_read_file(struct web_client *w)
  1801. {
  1802. if(unlikely(w->response.rlen > w->response.data->size))
  1803. buffer_need_bytes(w->response.data, w->response.rlen - w->response.data->size);
  1804. if(unlikely(w->response.rlen <= w->response.data->len))
  1805. return 0;
  1806. ssize_t left = (ssize_t)(w->response.rlen - w->response.data->len);
  1807. ssize_t bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t)left);
  1808. if(likely(bytes > 0)) {
  1809. size_t old = w->response.data->len;
  1810. (void)old;
  1811. w->response.data->len += bytes;
  1812. w->response.data->buffer[w->response.data->len] = '\0';
  1813. netdata_log_debug(D_WEB_CLIENT, "%llu: Read %zd bytes.", w->id, bytes);
  1814. netdata_log_debug(D_WEB_DATA, "%llu: Read data: '%s'.", w->id, &w->response.data->buffer[old]);
  1815. web_client_enable_wait_send(w);
  1816. if(w->response.rlen && w->response.data->len >= w->response.rlen)
  1817. web_client_disable_wait_receive(w);
  1818. }
  1819. else if(likely(bytes == 0)) {
  1820. netdata_log_debug(D_WEB_CLIENT, "%llu: Out of input file data.", w->id);
  1821. // if we cannot read, it means we have an error on input.
  1822. // if however, we are copying a file from ifd to ofd, we should not return an error.
  1823. // in this case, the error should be generated when the file has been sent to the client.
  1824. // we are copying data from ifd to ofd
  1825. // let it finish copying...
  1826. web_client_disable_wait_receive(w);
  1827. netdata_log_debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
  1828. if(web_server_mode != WEB_SERVER_MODE_STATIC_THREADED) {
  1829. if (w->ifd != w->ofd) close(w->ifd);
  1830. }
  1831. w->ifd = w->ofd;
  1832. }
  1833. else {
  1834. netdata_log_debug(D_WEB_CLIENT, "%llu: read data failed.", w->id);
  1835. WEB_CLIENT_IS_DEAD(w);
  1836. }
  1837. return(bytes);
  1838. }
  1839. ssize_t web_client_receive(struct web_client *w)
  1840. {
  1841. if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
  1842. return web_client_read_file(w);
  1843. ssize_t bytes;
  1844. ssize_t left = (ssize_t)(w->response.data->size - w->response.data->len);
  1845. // do we have any space for more data?
  1846. buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_INITIAL_SIZE);
  1847. errno = 0;
  1848. #ifdef ENABLE_HTTPS
  1849. if ( (!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx) ) {
  1850. if (SSL_connection(&w->ssl)) {
  1851. bytes = netdata_ssl_read(&w->ssl, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
  1852. web_client_enable_wait_from_ssl(w);
  1853. }
  1854. else {
  1855. bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
  1856. }
  1857. }
  1858. else{
  1859. bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
  1860. }
  1861. #else
  1862. bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
  1863. #endif
  1864. if(likely(bytes > 0)) {
  1865. w->statistics.received_bytes += bytes;
  1866. size_t old = w->response.data->len;
  1867. (void)old;
  1868. w->response.data->len += bytes;
  1869. w->response.data->buffer[w->response.data->len] = '\0';
  1870. netdata_log_debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
  1871. netdata_log_debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
  1872. }
  1873. else if(unlikely(bytes < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))) {
  1874. web_client_enable_wait_receive(w);
  1875. return 0;
  1876. }
  1877. else if (bytes < 0) {
  1878. netdata_log_debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id);
  1879. WEB_CLIENT_IS_DEAD(w);
  1880. } else
  1881. netdata_log_debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
  1882. return(bytes);
  1883. }
  1884. void web_client_decode_path_and_query_string(struct web_client *w, const char *path_and_query_string) {
  1885. char buffer[NETDATA_WEB_REQUEST_URL_SIZE + 2];
  1886. buffer[0] = '\0';
  1887. buffer_flush(w->url_path_decoded);
  1888. buffer_flush(w->url_query_string_decoded);
  1889. if(buffer_strlen(w->url_as_received) == 0)
  1890. // do not overwrite this if it is already filled
  1891. buffer_strcat(w->url_as_received, path_and_query_string);
  1892. if(w->mode == WEB_CLIENT_MODE_STREAM) {
  1893. // in stream mode, there is no path
  1894. url_decode_r(buffer, path_and_query_string, NETDATA_WEB_REQUEST_URL_SIZE + 1);
  1895. buffer[NETDATA_WEB_REQUEST_URL_SIZE + 1] = '\0';
  1896. buffer_strcat(w->url_query_string_decoded, buffer);
  1897. }
  1898. else {
  1899. // in non-stream mode, there is a path
  1900. // FIXME - the way this is implemented, query string params never accept the symbol &, not even encoded as %26
  1901. // To support the symbol & in query string params, we need to turn the url_query_string_decoded into a
  1902. // dictionary and decode each of the parameters individually.
  1903. // OR: in url_query_string_decoded use as separator a control character that cannot appear in the URL.
  1904. url_decode_r(buffer, path_and_query_string, NETDATA_WEB_REQUEST_URL_SIZE + 1);
  1905. char *question_mark_start = strchr(buffer, '?');
  1906. if (question_mark_start) {
  1907. buffer_strcat(w->url_query_string_decoded, question_mark_start);
  1908. char c = *question_mark_start;
  1909. *question_mark_start = '\0';
  1910. buffer_strcat(w->url_path_decoded, buffer);
  1911. *question_mark_start = c;
  1912. } else {
  1913. buffer_strcat(w->url_query_string_decoded, "");
  1914. buffer_strcat(w->url_path_decoded, buffer);
  1915. }
  1916. }
  1917. }
  1918. void web_client_reuse_from_cache(struct web_client *w) {
  1919. // zero everything about it - but keep the buffers
  1920. web_client_reset_allocations(w, false);
  1921. // remember the pointers to the buffers
  1922. BUFFER *b1 = w->response.data;
  1923. BUFFER *b2 = w->response.header;
  1924. BUFFER *b3 = w->response.header_output;
  1925. BUFFER *b4 = w->url_path_decoded;
  1926. BUFFER *b5 = w->url_as_received;
  1927. BUFFER *b6 = w->url_query_string_decoded;
  1928. #ifdef ENABLE_HTTPS
  1929. NETDATA_SSL ssl = w->ssl;
  1930. #endif
  1931. size_t use_count = w->use_count;
  1932. size_t *statistics_memory_accounting = w->statistics.memory_accounting;
  1933. // zero everything
  1934. memset(w, 0, sizeof(struct web_client));
  1935. w->ifd = w->ofd = -1;
  1936. w->statistics.memory_accounting = statistics_memory_accounting;
  1937. w->use_count = use_count;
  1938. #ifdef ENABLE_HTTPS
  1939. w->ssl = ssl;
  1940. #endif
  1941. // restore the pointers of the buffers
  1942. w->response.data = b1;
  1943. w->response.header = b2;
  1944. w->response.header_output = b3;
  1945. w->url_path_decoded = b4;
  1946. w->url_as_received = b5;
  1947. w->url_query_string_decoded = b6;
  1948. }
  1949. struct web_client *web_client_create(size_t *statistics_memory_accounting) {
  1950. struct web_client *w = (struct web_client *)callocz(1, sizeof(struct web_client));
  1951. #ifdef ENABLE_HTTPS
  1952. w->ssl = NETDATA_SSL_UNSET_CONNECTION;
  1953. #endif
  1954. w->use_count = 1;
  1955. w->statistics.memory_accounting = statistics_memory_accounting;
  1956. w->url_as_received = buffer_create(NETDATA_WEB_DECODED_URL_INITIAL_SIZE, w->statistics.memory_accounting);
  1957. w->url_path_decoded = buffer_create(NETDATA_WEB_DECODED_URL_INITIAL_SIZE, w->statistics.memory_accounting);
  1958. w->url_query_string_decoded = buffer_create(NETDATA_WEB_DECODED_URL_INITIAL_SIZE, w->statistics.memory_accounting);
  1959. w->response.data = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, w->statistics.memory_accounting);
  1960. w->response.header = buffer_create(NETDATA_WEB_RESPONSE_HEADER_INITIAL_SIZE, w->statistics.memory_accounting);
  1961. w->response.header_output = buffer_create(NETDATA_WEB_RESPONSE_HEADER_INITIAL_SIZE, w->statistics.memory_accounting);
  1962. __atomic_add_fetch(w->statistics.memory_accounting, sizeof(struct web_client), __ATOMIC_RELAXED);
  1963. return w;
  1964. }
  1965. void web_client_free(struct web_client *w) {
  1966. #ifdef ENABLE_HTTPS
  1967. netdata_ssl_close(&w->ssl);
  1968. #endif
  1969. web_client_reset_allocations(w, true);
  1970. __atomic_sub_fetch(w->statistics.memory_accounting, sizeof(struct web_client), __ATOMIC_RELAXED);
  1971. freez(w);
  1972. }
  1973. inline void web_client_timeout_checkpoint_init(struct web_client *w) {
  1974. now_monotonic_high_precision_timeval(&w->timings.tv_in);
  1975. }
  1976. inline void web_client_timeout_checkpoint_set(struct web_client *w, int timeout_ms) {
  1977. w->timings.timeout_ut = timeout_ms * USEC_PER_MS;
  1978. if(!w->timings.tv_in.tv_sec)
  1979. web_client_timeout_checkpoint_init(w);
  1980. if(!w->timings.tv_timeout_last_checkpoint.tv_sec)
  1981. w->timings.tv_timeout_last_checkpoint = w->timings.tv_in;
  1982. }
  1983. inline usec_t web_client_timeout_checkpoint(struct web_client *w) {
  1984. struct timeval now;
  1985. now_monotonic_high_precision_timeval(&now);
  1986. if (!w->timings.tv_timeout_last_checkpoint.tv_sec)
  1987. w->timings.tv_timeout_last_checkpoint = w->timings.tv_in;
  1988. usec_t since_last_check_ut = dt_usec(&w->timings.tv_timeout_last_checkpoint, &now);
  1989. w->timings.tv_timeout_last_checkpoint = now;
  1990. return since_last_check_ut;
  1991. }
  1992. inline usec_t web_client_timeout_checkpoint_response_ready(struct web_client *w, usec_t *usec_since_last_checkpoint) {
  1993. usec_t since_last_check_ut = web_client_timeout_checkpoint(w);
  1994. if(usec_since_last_checkpoint)
  1995. *usec_since_last_checkpoint = since_last_check_ut;
  1996. w->timings.tv_ready = w->timings.tv_timeout_last_checkpoint;
  1997. // return the total time of the query
  1998. return dt_usec(&w->timings.tv_in, &w->timings.tv_ready);
  1999. }
  2000. inline bool web_client_timeout_checkpoint_and_check(struct web_client *w, usec_t *usec_since_last_checkpoint) {
  2001. usec_t since_last_check_ut = web_client_timeout_checkpoint(w);
  2002. if(usec_since_last_checkpoint)
  2003. *usec_since_last_checkpoint = since_last_check_ut;
  2004. if(!w->timings.timeout_ut)
  2005. return false;
  2006. usec_t since_reception_ut = dt_usec(&w->timings.tv_in, &w->timings.tv_timeout_last_checkpoint);
  2007. if (since_reception_ut >= w->timings.timeout_ut) {
  2008. buffer_flush(w->response.data);
  2009. buffer_strcat(w->response.data, "Query timeout exceeded");
  2010. w->response.code = HTTP_RESP_BACKEND_FETCH_FAILED;
  2011. return true;
  2012. }
  2013. return false;
  2014. }