web_client.c 86 KB

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