web_client.c 76 KB

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