http.c 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465
  1. /*
  2. http.c -- GoAhead HTTP engine
  3. This module implements an embedded HTTP/1.1 web server. It supports
  4. loadable URL handlers that define the nature of URL processing performed.
  5. Copyright (c) All Rights Reserved. See details at the end of the file.
  6. */
  7. /********************************* Includes ***********************************/
  8. #include "goahead.h"
  9. /********************************* Defines ************************************/
  10. #define WEBS_TIMEOUT (ME_GOAHEAD_LIMIT_TIMEOUT * 1000)
  11. #define PARSE_TIMEOUT (ME_GOAHEAD_LIMIT_PARSE_TIMEOUT * 1000)
  12. #define CHUNK_LOW 128 /* Low water mark for chunking */
  13. /************************************ Locals **********************************/
  14. static int websBackground; /* Run as a daemon */
  15. static int websDebug; /* Run in debug mode and defeat timeouts */
  16. static int defaultHttpPort; /* Default port number for http */
  17. static int defaultSslPort; /* Default port number for https */
  18. static int listens[WEBS_MAX_LISTEN]; /* Listen endpoints */;
  19. static int listenMax; /* Max entry in listens */
  20. static Webs **webs; /* Open connection list head */
  21. static WebsHash websMime; /* Set of mime types */
  22. static int websMax; /* List size */
  23. static char websHost[ME_MAX_IP]; /* Host name for the server */
  24. static char websIpAddr[ME_MAX_IP]; /* IP address for the server */
  25. static char *websHostUrl = NULL; /* URL to access server */
  26. static char *websIpAddrUrl = NULL; /* URL to access server */
  27. #define WEBS_ENCODE_HTML 0x1 /* Bit setting in charMatch[] */
  28. /*
  29. Character escape/descape matching codes. Generated by charGen.
  30. */
  31. static uchar charMatch[256] = {
  32. 0x00,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e,0x3c,0x3c,0x3c,0x3c,0x3c,
  33. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  34. 0x3c,0x0c,0x3f,0x28,0x2a,0x3c,0x2b,0x0f,0x0e,0x0e,0x0e,0x28,0x28,0x00,0x00,0x28,
  35. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x2a,0x3f,0x28,0x3f,0x2a,
  36. 0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  37. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0x3e,0x3a,0x3e,0x00,
  38. 0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  39. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x3e,0x3e,0x02,0x3c,
  40. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  41. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  42. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  43. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  44. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  45. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  46. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
  47. 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c
  48. };
  49. /*
  50. Addd entries to the MimeList as required for your content
  51. */
  52. static WebsMime websMimeList[] = {
  53. { "application/java", ".class" },
  54. { "application/java", ".jar" },
  55. { "text/html", ".asp" },
  56. { "text/html", ".htm" },
  57. { "text/html", ".html" },
  58. { "text/xml", ".xml" },
  59. { "image/gif", ".gif" },
  60. { "image/jpeg", ".jpg" },
  61. { "image/png", ".png" },
  62. { "image/vnd.microsoft.icon", ".ico" },
  63. { "text/css", ".css" },
  64. { "text/plain", ".txt" },
  65. { "application/x-javascript", ".js" },
  66. { "application/x-shockwave-flash", ".swf" },
  67. { "application/binary", ".exe" },
  68. { "application/compress", ".z" },
  69. { "application/gzip", ".gz" },
  70. { "application/octet-stream", ".bin" },
  71. { "application/oda", ".oda" },
  72. { "application/pdf", ".pdf" },
  73. { "application/postscript", ".ai" },
  74. { "application/postscript", ".eps" },
  75. { "application/postscript", ".ps" },
  76. { "application/rtf", ".rtf" },
  77. { "application/x-bcpio", ".bcpio" },
  78. { "application/x-cpio", ".cpio" },
  79. { "application/x-csh", ".csh" },
  80. { "application/x-dvi", ".dvi" },
  81. { "application/x-gtar", ".gtar" },
  82. { "application/x-hdf", ".hdf" },
  83. { "application/x-latex", ".latex" },
  84. { "application/x-mif", ".mif" },
  85. { "application/x-netcdf", ".nc" },
  86. { "application/x-netcdf", ".cdf" },
  87. { "application/x-ns-proxy-autoconfig", ".pac" },
  88. { "application/x-patch", ".patch" },
  89. { "application/x-sh", ".sh" },
  90. { "application/x-shar", ".shar" },
  91. { "application/x-sv4cpio", ".sv4cpio" },
  92. { "application/x-sv4crc", ".sv4crc" },
  93. { "application/x-tar", ".tar" },
  94. { "application/x-tgz", ".tgz" },
  95. { "application/x-tcl", ".tcl" },
  96. { "application/x-tex", ".tex" },
  97. { "application/x-texinfo", ".texinfo" },
  98. { "application/x-texinfo", ".texi" },
  99. { "application/x-troff", ".t" },
  100. { "application/x-troff", ".tr" },
  101. { "application/x-troff", ".roff" },
  102. { "application/x-troff-man", ".man" },
  103. { "application/x-troff-me", ".me" },
  104. { "application/x-troff-ms", ".ms" },
  105. { "application/x-ustar", ".ustar" },
  106. { "application/x-wais-source", ".src" },
  107. { "application/zip", ".zip" },
  108. { "audio/basic", ".au snd" },
  109. { "audio/x-aiff", ".aif" },
  110. { "audio/x-aiff", ".aiff" },
  111. { "audio/x-aiff", ".aifc" },
  112. { "audio/x-wav", ".wav" },
  113. { "audio/x-wav", ".ram" },
  114. { "image/ief", ".ief" },
  115. { "image/jpeg", ".jpeg" },
  116. { "image/jpeg", ".jpe" },
  117. { "image/tiff", ".tiff" },
  118. { "image/tiff", ".tif" },
  119. { "image/x-cmu-raster", ".ras" },
  120. { "image/x-portable-anymap", ".pnm" },
  121. { "image/x-portable-bitmap", ".pbm" },
  122. { "image/x-portable-graymap", ".pgm" },
  123. { "image/x-portable-pixmap", ".ppm" },
  124. { "image/x-rgb", ".rgb" },
  125. { "image/x-xbitmap", ".xbm" },
  126. { "image/x-xpixmap", ".xpm" },
  127. { "image/x-xwindowdump", ".xwd" },
  128. { "text/html", ".cfm" },
  129. { "text/html", ".shtm" },
  130. { "text/html", ".shtml" },
  131. { "text/richtext", ".rtx" },
  132. { "text/tab-separated-values", ".tsv" },
  133. { "text/x-setext", ".etx" },
  134. { "video/mpeg", ".mpeg" },
  135. { "video/mpeg", ".mpg" },
  136. { "video/mpeg", ".mpe" },
  137. { "video/quicktime", ".qt" },
  138. { "video/quicktime", ".mov" },
  139. { "video/mp4", ".mp4" },
  140. { "video/x-msvideo", ".avi" },
  141. { "video/x-sgi-movie", ".movie" },
  142. { NULL, NULL},
  143. };
  144. /*
  145. Standard HTTP error codes
  146. */
  147. static WebsError websErrors[] = {
  148. { 200, "OK" },
  149. { 201, "Created" },
  150. { 204, "No Content" },
  151. { 205, "Reset Content" },
  152. { 206, "Partial Content" },
  153. { 301, "Redirect" },
  154. { 302, "Redirect" },
  155. { 304, "Not Modified" },
  156. { 400, "Bad Request" },
  157. { 401, "Unauthorized" },
  158. { 402, "Payment required" },
  159. { 403, "Forbidden" },
  160. { 404, "Not Found" },
  161. { 405, "Access Denied" },
  162. { 406, "Not Acceptable" },
  163. { 408, "Request Timeout" },
  164. { 413, "Request too large" },
  165. { 500, "Internal Server Error" },
  166. { 501, "Not Implemented" },
  167. { 503, "Service Unavailable" },
  168. { 0, NULL }
  169. };
  170. #if ME_GOAHEAD_ACCESS_LOG && !ME_ROM
  171. static char accessLog[64] = "access.log"; /* Log filename */
  172. static int accessFd; /* Log file handle */
  173. #endif
  174. static WebsHash sessions = -1;
  175. static int sessionCount = 0;
  176. static int pruneId; /* Callback ID */
  177. /**************************** Forward Declarations ****************************/
  178. static void checkTimeout(void *arg, int id);
  179. static bool filterChunkData(Webs *wp);
  180. static int getTimeSinceMark(Webs *wp);
  181. static char *getToken(Webs *wp, char *delim);
  182. static void parseFirstLine(Webs *wp);
  183. static void parseHeaders(Webs *wp);
  184. static bool processContent(Webs *wp);
  185. static bool parseIncoming(Webs *wp);
  186. static void pruneSessions();
  187. static void freeSession(WebsSession *sp);
  188. static void freeSessions();
  189. static void readEvent(Webs *wp);
  190. static void reuseConn(Webs *wp);
  191. static void setFileLimits();
  192. static int setLocalHost();
  193. static void socketEvent(int sid, int mask, void *data);
  194. static void writeEvent(Webs *wp);
  195. #if ME_GOAHEAD_ACCESS_LOG
  196. static void logRequest(Webs *wp, int code);
  197. #endif
  198. /*********************************** Code *************************************/
  199. PUBLIC int websOpen(char *documents, char *routeFile)
  200. {
  201. WebsMime *mt;
  202. webs = NULL;
  203. websMax = 0;
  204. websOsOpen();
  205. websRuntimeOpen();
  206. websTimeOpen();
  207. websFsOpen();
  208. logOpen();
  209. setFileLimits();
  210. socketOpen();
  211. if (setLocalHost() < 0) {
  212. return -1;
  213. }
  214. #if ME_COM_SSL
  215. if (sslOpen() < 0) {
  216. return -1;
  217. }
  218. #endif
  219. if ((sessions = hashCreate(-1)) < 0) {
  220. return -1;
  221. }
  222. if (!websDebug) {
  223. pruneId = websStartEvent(WEBS_SESSION_PRUNE, (WebsEventProc) pruneSessions, 0);
  224. }
  225. if (documents) {
  226. websSetDocuments(documents);
  227. }
  228. if (websOpenRoute() < 0) {
  229. return -1;
  230. }
  231. #if ME_GOAHEAD_CGI
  232. websCgiOpen();
  233. #endif
  234. websOptionsOpen();
  235. websActionOpen();
  236. websFileOpen();
  237. #if ME_GOAHEAD_UPLOAD
  238. websUploadOpen();
  239. #endif
  240. #if ME_GOAHEAD_JAVASCRIPT
  241. websJstOpen();
  242. #endif
  243. #if ME_GOAHEAD_AUTH
  244. if (websOpenAuth(0) < 0) {
  245. return -1;
  246. }
  247. #endif
  248. if (websLoad(routeFile) < 0) {
  249. return -1;
  250. }
  251. /*
  252. Create a mime type lookup table for quickly determining the content type
  253. */
  254. websMime = hashCreate(WEBS_HASH_INIT * 4);
  255. assert(websMime >= 0);
  256. for (mt = websMimeList; mt->type; mt++) {
  257. hashEnter(websMime, mt->ext, valueString(mt->type, 0), 0);
  258. }
  259. #if ME_GOAHEAD_ACCESS_LOG && !ME_ROM
  260. if ((accessFd = open(accessLog, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, 0666)) < 0) {
  261. error("Cannot open access log %s", accessLog);
  262. return -1;
  263. }
  264. /* Some platforms don't implement O_APPEND (VXWORKS) */
  265. lseek(accessFd, 0, SEEK_END);
  266. #endif
  267. return 0;
  268. }
  269. PUBLIC void websClose()
  270. {
  271. Webs *wp;
  272. int i;
  273. websCloseRoute();
  274. #if ME_GOAHEAD_AUTH
  275. websCloseAuth();
  276. #endif
  277. if (pruneId >= 0) {
  278. websStopEvent(pruneId);
  279. pruneId = -1;
  280. }
  281. if (sessions >= 0) {
  282. freeSessions();
  283. }
  284. for (i = 0; i < listenMax; i++) {
  285. if (listens[i] >= 0) {
  286. socketCloseConnection(listens[i]);
  287. listens[i] = -1;
  288. }
  289. }
  290. listenMax = 0;
  291. for (i = websMax; webs && i >= 0; i--) {
  292. if ((wp = webs[i]) == NULL) {
  293. continue;
  294. }
  295. if (wp->sid >= 0) {
  296. socketCloseConnection(wp->sid);
  297. wp->sid = -1;
  298. }
  299. websFree(wp);
  300. }
  301. wfree(websHostUrl);
  302. wfree(websIpAddrUrl);
  303. websIpAddrUrl = websHostUrl = NULL;
  304. #if ME_COM_SSL
  305. sslClose();
  306. #endif
  307. #if ME_GOAHEAD_ACCESS_LOG
  308. if (accessFd >= 0) {
  309. close(accessFd);
  310. accessFd = -1;
  311. }
  312. #endif
  313. websFsClose();
  314. hashFree(websMime);
  315. socketClose();
  316. logClose();
  317. websTimeClose();
  318. websRuntimeClose();
  319. websOsClose();
  320. }
  321. static void initWebs(Webs *wp, int flags, int reuse)
  322. {
  323. WebsBuf rxbuf;
  324. void *ssl;
  325. char ipaddr[ME_MAX_IP], ifaddr[ME_MAX_IP];
  326. int wid, sid, timeout;
  327. assert(wp);
  328. if (reuse) {
  329. rxbuf = wp->rxbuf;
  330. wid = wp->wid;
  331. sid = wp->sid;
  332. timeout = wp->timeout;
  333. ssl = wp->ssl;
  334. scopy(ipaddr, sizeof(ipaddr), wp->ipaddr);
  335. scopy(ifaddr, sizeof(ifaddr), wp->ifaddr);
  336. } else {
  337. wid = sid = -1;
  338. timeout = -1;
  339. ssl = 0;
  340. }
  341. memset(wp, 0, sizeof(Webs));
  342. wp->flags = flags;
  343. wp->state = WEBS_BEGIN;
  344. wp->wid = wid;
  345. wp->sid = sid;
  346. wp->timeout = timeout;
  347. wp->docfd = -1;
  348. wp->txLen = -1;
  349. wp->rxLen = -1;
  350. wp->code = HTTP_CODE_OK;
  351. wp->ssl = ssl;
  352. #if !ME_ROM
  353. wp->putfd = -1;
  354. #endif
  355. #if ME_GOAHEAD_CGI
  356. wp->cgifd = -1;
  357. #endif
  358. #if ME_GOAHEAD_UPLOAD
  359. wp->files = -1;
  360. wp->upfd = -1;
  361. #endif
  362. if (reuse) {
  363. scopy(wp->ipaddr, sizeof(wp->ipaddr), ipaddr);
  364. scopy(wp->ifaddr, sizeof(wp->ifaddr), ifaddr);
  365. } else {
  366. wp->timeout = -1;
  367. }
  368. wp->vars = hashCreate(WEBS_HASH_INIT);
  369. /*
  370. Ring queues can never be totally full and are short one byte. Better to do even I/O and allocate
  371. a little more memory than required. The chunkbuf has extra room to fit chunk headers and trailers.
  372. */
  373. assert(ME_GOAHEAD_LIMIT_BUFFER >= 1024);
  374. bufCreate(&wp->output, ME_GOAHEAD_LIMIT_BUFFER + 1, ME_GOAHEAD_LIMIT_BUFFER + 1);
  375. bufCreate(&wp->chunkbuf, ME_GOAHEAD_LIMIT_BUFFER + 1, ME_GOAHEAD_LIMIT_BUFFER * 2);
  376. bufCreate(&wp->input, ME_GOAHEAD_LIMIT_BUFFER + 1, ME_GOAHEAD_LIMIT_PUT + 1);
  377. if (reuse) {
  378. wp->rxbuf = rxbuf;
  379. } else {
  380. bufCreate(&wp->rxbuf, ME_GOAHEAD_LIMIT_HEADERS, ME_GOAHEAD_LIMIT_HEADERS + ME_GOAHEAD_LIMIT_PUT);
  381. }
  382. }
  383. static void termWebs(Webs *wp, int reuse)
  384. {
  385. assert(wp);
  386. /*
  387. Some of this is done elsewhere, but keep this here for when a shutdown is done and there are open connections.
  388. */
  389. bufFree(&wp->input);
  390. bufFree(&wp->output);
  391. bufFree(&wp->chunkbuf);
  392. if (!reuse) {
  393. bufFree(&wp->rxbuf);
  394. if (wp->sid >= 0) {
  395. #if ME_COM_SSL
  396. sslFree(wp);
  397. #endif
  398. socketDeleteHandler(wp->sid);
  399. socketCloseConnection(wp->sid);
  400. wp->sid = -1;
  401. }
  402. }
  403. #if !ME_ROM
  404. if (wp->putfd >= 0) {
  405. close(wp->putfd);
  406. wp->putfd = -1;
  407. assert(wp->putname && wp->filename);
  408. if (rename(wp->putname, wp->filename) < 0) {
  409. error("Cannot rename PUT file from %s to %s", wp->putname, wp->filename);
  410. }
  411. }
  412. #endif
  413. #if ME_GOAHEAD_CGI
  414. if (wp->cgifd >= 0) {
  415. close(wp->cgifd);
  416. wp->cgifd = -1;
  417. }
  418. wfree(wp->cgiStdin);
  419. #endif
  420. #if ME_GOAHEAD_UPLOAD
  421. wfree(wp->clientFilename);
  422. #endif
  423. websPageClose(wp);
  424. if (wp->timeout >= 0 && !reuse) {
  425. websCancelTimeout(wp);
  426. }
  427. wfree(wp->authDetails);
  428. wfree(wp->authResponse);
  429. wfree(wp->authType);
  430. wfree(wp->contentType);
  431. wfree(wp->cookie);
  432. wfree(wp->decodedQuery);
  433. wfree(wp->digest);
  434. wfree(wp->ext);
  435. wfree(wp->filename);
  436. wfree(wp->host);
  437. wfree(wp->method);
  438. wfree(wp->password);
  439. wfree(wp->path);
  440. wfree(wp->protoVersion);
  441. wfree(wp->putname);
  442. wfree(wp->query);
  443. wfree(wp->realm);
  444. wfree(wp->referrer);
  445. wfree(wp->responseCookie);
  446. wfree(wp->url);
  447. wfree(wp->userAgent);
  448. wfree(wp->username);
  449. #if ME_GOAHEAD_UPLOAD
  450. wfree(wp->boundary);
  451. wfree(wp->uploadTmp);
  452. wfree(wp->uploadVar);
  453. #endif
  454. #if ME_GOAHEAD_DIGEST
  455. wfree(wp->cnonce);
  456. wfree(wp->digestUri);
  457. wfree(wp->opaque);
  458. wfree(wp->nc);
  459. wfree(wp->nonce);
  460. wfree(wp->qop);
  461. #endif
  462. hashFree(wp->vars);
  463. #if ME_GOAHEAD_UPLOAD
  464. if (wp->files >= 0) {
  465. websFreeUpload(wp);
  466. }
  467. #endif
  468. }
  469. PUBLIC int websAlloc(int sid)
  470. {
  471. Webs *wp;
  472. int wid;
  473. if ((wid = wallocObject(&webs, &websMax, sizeof(Webs))) < 0) {
  474. return -1;
  475. }
  476. wp = webs[wid];
  477. assert(wp);
  478. initWebs(wp, 0, 0);
  479. wp->wid = wid;
  480. wp->sid = sid;
  481. wp->timestamp = time(0);
  482. return wid;
  483. }
  484. static void reuseConn(Webs *wp)
  485. {
  486. assert(wp);
  487. assert(websValid(wp));
  488. bufCompact(&wp->rxbuf);
  489. if (bufLen(&wp->rxbuf)) {
  490. socketReservice(wp->sid);
  491. }
  492. termWebs(wp, 1);
  493. initWebs(wp, wp->flags & (WEBS_KEEP_ALIVE | WEBS_SECURE | WEBS_HTTP11), 1);
  494. }
  495. PUBLIC void websFree(Webs *wp)
  496. {
  497. assert(wp);
  498. assert(websValid(wp));
  499. termWebs(wp, 0);
  500. websMax = wfreeHandle(&webs, wp->wid);
  501. wfree(wp);
  502. assert(websMax >= 0);
  503. }
  504. /*
  505. Called when the request is complete. Note: it may not have fully drained from the tx buffer.
  506. */
  507. PUBLIC void websDone(Webs *wp)
  508. {
  509. WebsSocket *sp;
  510. assert(wp);
  511. assert(websValid(wp));
  512. if (wp->finalized) {
  513. return;
  514. }
  515. assert(WEBS_BEGIN <= wp->state && wp->state <= WEBS_COMPLETE);
  516. #if DEPRECATED || 1
  517. wp->flags |= WEBS_FINALIZED;
  518. #endif
  519. wp->finalized = 1;
  520. if (wp->state < WEBS_COMPLETE) {
  521. /*
  522. Initiate flush. If not all flushed, wait for output to drain via a socket event.
  523. */
  524. if (websFlush(wp, 0) == 0) {
  525. sp = socketPtr(wp->sid);
  526. socketCreateHandler(wp->sid, sp->handlerMask | SOCKET_WRITABLE, socketEvent, wp);
  527. }
  528. }
  529. #if ME_GOAHEAD_ACCESS_LOG
  530. logRequest(wp, wp->code);
  531. #endif
  532. if (!(wp->flags & WEBS_RESPONSE_TRACED)) {
  533. trace(3 | WEBS_RAW_MSG, "Request complete: code %d", wp->code);
  534. }
  535. }
  536. static int complete(Webs *wp, int reuse)
  537. {
  538. assert(wp);
  539. assert(websValid(wp));
  540. assert(wp->state == WEBS_BEGIN || wp->state == WEBS_COMPLETE);
  541. if (reuse && wp->flags & WEBS_KEEP_ALIVE && wp->rxRemaining == 0) {
  542. reuseConn(wp);
  543. socketCreateHandler(wp->sid, SOCKET_READABLE, socketEvent, wp);
  544. trace(5, "Keep connection alive");
  545. return 1;
  546. }
  547. trace(5, "Close connection");
  548. wp->state = WEBS_BEGIN;
  549. wp->flags |= WEBS_CLOSED;
  550. return 0;
  551. }
  552. PUBLIC int websListen(char *endpoint)
  553. {
  554. WebsSocket *sp;
  555. char *ip, *ipaddr;
  556. int port, secure, sid;
  557. assert(endpoint && *endpoint);
  558. if (listenMax >= WEBS_MAX_LISTEN) {
  559. error("Too many listen endpoints");
  560. return -1;
  561. }
  562. socketParseAddress(endpoint, &ip, &port, &secure, 80);
  563. if ((sid = socketListen(ip, port, websAccept, 0)) < 0) {
  564. error("Unable to open socket on port %d.", port);
  565. return -1;
  566. }
  567. sp = socketPtr(sid);
  568. sp->secure = secure;
  569. if (sp->secure) {
  570. if (!defaultSslPort) {
  571. defaultSslPort = port;
  572. }
  573. } else if (!defaultHttpPort) {
  574. defaultHttpPort = port;
  575. }
  576. listens[listenMax++] = sid;
  577. if (ip) {
  578. ipaddr = smatch(ip, "::") ? "[::]" : ip;
  579. } else {
  580. ipaddr = "*";
  581. }
  582. logmsg(2, "Started %s://%s:%d", secure ? "https" : "http", ipaddr, port);
  583. if (!websHostUrl) {
  584. if (port == 80) {
  585. websHostUrl = sclone(ip ? ip : websIpAddr);
  586. } else {
  587. websHostUrl = sfmt("%s:%d", ip ? ip : websIpAddr, port);
  588. }
  589. }
  590. if (!websIpAddrUrl) {
  591. if (port == 80) {
  592. websIpAddrUrl = sclone(websIpAddr);
  593. } else {
  594. websIpAddrUrl = sfmt("%s:%d", websIpAddr, port);
  595. }
  596. }
  597. wfree(ip);
  598. return sid;
  599. }
  600. /*
  601. Accept a new connection from ipaddr:port
  602. */
  603. PUBLIC int websAccept(int sid, char *ipaddr, int port, int listenSid)
  604. {
  605. Webs *wp;
  606. WebsSocket *lp;
  607. struct sockaddr_storage ifAddr;
  608. int wid, len;
  609. assert(sid >= 0);
  610. assert(ipaddr && *ipaddr);
  611. assert(listenSid >= 0);
  612. assert(port >= 0);
  613. /*
  614. Allocate a new handle for this accepted connection. This will allocate a Webs structure in the webs[] list
  615. */
  616. if ((wid = websAlloc(sid)) < 0) {
  617. return -1;
  618. }
  619. wp = webs[wid];
  620. assert(wp);
  621. wp->listenSid = listenSid;
  622. strncpy(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr) - 1, strlen(ipaddr)));
  623. /*
  624. Get the ip address of the interface that accept the connection.
  625. */
  626. len = sizeof(ifAddr);
  627. if (getsockname(socketPtr(sid)->sock, (struct sockaddr*) &ifAddr, (Socklen*) &len) < 0) {
  628. error("Cannot get sockname");
  629. return -1;
  630. }
  631. socketAddress((struct sockaddr*) &ifAddr, (int) len, wp->ifaddr, sizeof(wp->ifaddr), NULL);
  632. #if ME_GOAHEAD_LEGACY
  633. /*
  634. Check if this is a request from a browser on this system. This is useful to know for permitting administrative
  635. operations only for local access
  636. */
  637. if (strcmp(wp->ipaddr, "127.0.0.1") == 0 || strcmp(wp->ipaddr, websIpAddr) == 0 ||
  638. strcmp(wp->ipaddr, websHost) == 0) {
  639. wp->flags |= WEBS_LOCAL;
  640. }
  641. #endif
  642. /*
  643. Arrange for socketEvent to be called when read data is available
  644. */
  645. lp = socketPtr(listenSid);
  646. trace(4, "New connection from %s:%d to %s:%d", ipaddr, port, wp->ifaddr, lp->port);
  647. #if ME_COM_SSL
  648. if (lp->secure) {
  649. wp->flags |= WEBS_SECURE;
  650. trace(4, "Upgrade connection to TLS");
  651. if (sslUpgrade(wp) < 0) {
  652. error("Cannot upgrade to TLS");
  653. return -1;
  654. }
  655. }
  656. #endif
  657. assert(wp->timeout == -1);
  658. wp->timeout = websStartEvent(PARSE_TIMEOUT, checkTimeout, (void*) wp);
  659. socketEvent(sid, SOCKET_READABLE, wp);
  660. return 0;
  661. }
  662. /*
  663. The webs socket handler. Called in response to I/O. We just pass control to the relevant read or write handler. A
  664. pointer to the webs structure is passed as a (void*) in wptr.
  665. */
  666. static void socketEvent(int sid, int mask, void *wptr)
  667. {
  668. Webs *wp;
  669. wp = (Webs*) wptr;
  670. assert(wp);
  671. assert(websValid(wp));
  672. if (! websValid(wp)) {
  673. return;
  674. }
  675. if (mask & SOCKET_READABLE) {
  676. readEvent(wp);
  677. }
  678. if (mask & SOCKET_WRITABLE) {
  679. writeEvent(wp);
  680. }
  681. if (wp->flags & WEBS_CLOSED) {
  682. websFree(wp);
  683. /* WARNING: wp not valid here */
  684. }
  685. }
  686. /*
  687. Read from a connection. Return the number of bytes read if successful. This may be less than the requested "len" and
  688. may be zero. Return -1 for errors or EOF. Distinguish between error and EOF via socketEof().
  689. */
  690. static ssize websRead(Webs *wp, char *buf, ssize len)
  691. {
  692. assert(wp);
  693. assert(buf);
  694. assert(len > 0);
  695. #if ME_COM_SSL
  696. if (wp->flags & WEBS_SECURE) {
  697. return sslRead(wp, buf, len);
  698. }
  699. #endif
  700. return socketRead(wp->sid, buf, len);
  701. }
  702. /*
  703. The webs read handler. This is the primary read event loop. It uses a state machine to track progress while parsing
  704. the HTTP request. Note: we never block as the socket is always in non-blocking mode.
  705. */
  706. static void readEvent(Webs *wp)
  707. {
  708. WebsBuf *rxbuf;
  709. WebsSocket *sp;
  710. ssize nbytes;
  711. assert(wp);
  712. assert(websValid(wp));
  713. if (!websValid(wp)) {
  714. return;
  715. }
  716. websNoteRequestActivity(wp);
  717. rxbuf = &wp->rxbuf; //存储的是请求包中的所有数据 18432 //缓冲区的数据结构
  718. // printf("%d>>>>>>>>0000>>>>%d>>>\n",rxbuf->buflen, bufRoom(rxbuf));
  719. if (bufRoom(rxbuf) < (ME_GOAHEAD_LIMIT_BUFFER+1)) { //缓冲区不够了增加缓冲区的大小
  720. if (!bufGrow(rxbuf, (ME_GOAHEAD_LIMIT_BUFFER+1))) {
  721. websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot grow rxbuf");
  722. websPump(wp);
  723. return;
  724. }
  725. }
  726. //printf(">>>rxbuf->endp: %p\n",rxbuf->endp);
  727. // ME_GOAHEAD_LIMIT_BUFFER
  728. if ((nbytes = websRead(wp, (char*) rxbuf->endp, ME_GOAHEAD_LIMIT_BUFFER)) > 0) {//调用socketRead,读HTTP请求.rxbuf->endp是上一次的数据尾,每次读之后接上
  729. // printf("%d>>>>>>>>2222>>>>>>>\n",nbytes);//一次读了多少字节
  730. wp->lastRead = nbytes;//读了多少字节,数据的尾指针就加多少字节
  731. // printf("---> websRead return %d\n",nBytes);
  732. bufAdjustEnd(rxbuf, nbytes);//写字符串结束符
  733. bufAddNull(rxbuf);
  734. }
  735. // printf("%d>>>>>>>>56565656>>>>>>>\n",nbytes);
  736. if (nbytes > 0 || wp->state > WEBS_BEGIN) { //读到数据了,进来处理
  737. // printf("%d>>>>>>>>2222>>>>>>>\n",nbytes);
  738. websPump(wp);
  739. }
  740. //到这一步nbytes值是-1 为什么??
  741. // printf("%d>>>>>>>>>nbytes>>>>>>>>>>>\n",nbytes);
  742. // printf("%d>>>>>>>>>wp->sid>>>>>>>>>>>\n",wp->sid);
  743. if (wp->flags & WEBS_CLOSED) {
  744. return;//通过websPump处理完请求,需要关闭连接,return返回readEvent.数据结构依然保留。
  745. } else if (nbytes < 0 && socketEof(wp->sid)) {
  746. /* EOF or error. Allow running requests to continue. */
  747. // printf("%d>>>>>>>>>state>>>>>>>>>>>\n", wp->state);
  748. //state 值是1
  749. if (wp->state < WEBS_READY) {//ready 2
  750. if (wp->state > WEBS_BEGIN) {//begin 0
  751. websError(wp, HTTP_CODE_COMMS_ERROR, "Read error: connection lost");
  752. websPump(wp);
  753. } else {
  754. complete(wp, 0);
  755. }
  756. } else {
  757. socketDeleteHandler(wp->sid);
  758. }
  759. } else if (wp->state < WEBS_READY) {//如果是keep alive的请求,继续监听。
  760. sp = socketPtr(wp->sid);
  761. socketCreateHandler(wp->sid, sp->handlerMask | SOCKET_READABLE, socketEvent, wp);
  762. }
  763. }
  764. PUBLIC void websPump(Webs *wp)
  765. {
  766. bool canProceed;
  767. for (canProceed = 1; canProceed; ) {
  768. switch (wp->state) {
  769. case WEBS_BEGIN:
  770. canProceed = parseIncoming(wp);
  771. break;
  772. case WEBS_CONTENT:
  773. canProceed = processContent(wp);
  774. break;
  775. case WEBS_READY:
  776. if (!websRunRequest(wp)) {
  777. // printf("%d<<<<<<<<<<<<>>>>>>>>>*******\n", WEBS_READY);
  778. /* Reroute if the handler re-wrote the request */
  779. websRouteRequest(wp);
  780. wp->state = WEBS_READY;
  781. canProceed = 1;
  782. continue;
  783. }
  784. canProceed = (wp->state != WEBS_RUNNING);
  785. break;
  786. case WEBS_RUNNING:
  787. /* Nothing to do until websDone is called */
  788. return;
  789. case WEBS_COMPLETE:
  790. canProceed = complete(wp, 1);
  791. break;
  792. }
  793. }
  794. }
  795. static bool parseIncoming(Webs *wp)
  796. {
  797. WebsBuf *rxbuf;
  798. char *end, c;
  799. rxbuf = &wp->rxbuf;
  800. while (*rxbuf->servp == '\r' || *rxbuf->servp == '\n') {
  801. if (bufGetc(rxbuf) < 0) {
  802. break;
  803. }
  804. }
  805. if ((end = strstr((char*) wp->rxbuf.servp, "\r\n\r\n")) == 0) {
  806. if (bufLen(&wp->rxbuf) >= ME_GOAHEAD_LIMIT_HEADER) {
  807. websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Header too large");
  808. return 1;
  809. }
  810. return 0;
  811. }
  812. trace(3 | WEBS_RAW_MSG, "\n<<< Request\n");
  813. c = *end;
  814. *end = '\0';
  815. trace(3 | WEBS_RAW_MSG, "%s\n", wp->rxbuf.servp);
  816. *end = c;
  817. /*
  818. Parse the first line of the Http header
  819. */
  820. parseFirstLine(wp);
  821. if (wp->state == WEBS_COMPLETE) {
  822. return 1;
  823. }
  824. parseHeaders(wp);
  825. if (wp->state == WEBS_COMPLETE) {
  826. return 1;
  827. }
  828. wp->state = (wp->rxChunkState || wp->rxLen > 0) ? WEBS_CONTENT : WEBS_READY;
  829. websRouteRequest(wp);
  830. if (wp->state == WEBS_COMPLETE) {
  831. return 1;
  832. }
  833. #if ME_GOAHEAD_CGI
  834. if (wp->route && wp->route->handler && wp->route->handler->service == cgiHandler) {
  835. if (smatch(wp->method, "POST")) {
  836. wp->cgiStdin = websGetCgiCommName();
  837. if ((wp->cgifd = open(wp->cgiStdin, O_CREAT | O_WRONLY | O_BINARY | O_TRUNC, 0666)) < 0) {
  838. websError(wp, HTTP_CODE_NOT_FOUND | WEBS_CLOSE, "Cannot open CGI file");
  839. return 1;
  840. }
  841. }
  842. }
  843. #endif
  844. #if !ME_ROM
  845. if (smatch(wp->method, "PUT")) {
  846. WebsStat sbuf;
  847. wp->code = (stat(wp->filename, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) ? HTTP_CODE_NO_CONTENT : HTTP_CODE_CREATED;
  848. wfree(wp->putname);
  849. wp->putname = websTempFile(ME_GOAHEAD_PUT_DIR, "put");
  850. if ((wp->putfd = open(wp->putname, O_BINARY | O_WRONLY | O_CREAT | O_BINARY, 0644)) < 0) {
  851. error("Cannot create PUT filename %s", wp->putname);
  852. websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot create the put URI");
  853. wfree(wp->putname);
  854. return 1;
  855. }
  856. }
  857. #endif
  858. return 1;
  859. }
  860. /*
  861. Parse the first line of a HTTP request
  862. */
  863. static void parseFirstLine(Webs *wp)
  864. {
  865. char *op, *protoVer, *url, *host, *query, *path, *port, *ext, *buf;
  866. int listenPort;
  867. assert(wp);
  868. assert(websValid(wp));
  869. /*
  870. Determine the request type: GET, HEAD or POST
  871. */
  872. op = getToken(wp, 0);
  873. if (op == NULL || *op == '\0') {
  874. websError(wp, HTTP_CODE_NOT_FOUND | WEBS_CLOSE, "Bad HTTP request");
  875. return;
  876. }
  877. wp->method = supper(sclone(op));
  878. url = getToken(wp, 0);
  879. if (url == NULL || *url == '\0') {
  880. websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE, "Bad HTTP request");
  881. return;
  882. }
  883. if (strlen(url) > ME_GOAHEAD_LIMIT_URI) {
  884. websError(wp, HTTP_CODE_REQUEST_URL_TOO_LARGE | WEBS_CLOSE, "URI too big");
  885. return;
  886. }
  887. protoVer = getToken(wp, "\r\n");
  888. if (websGetLogLevel() == 2) {
  889. trace(2, "%s %s %s", wp->method, url, protoVer);
  890. }
  891. /*
  892. Parse the URL and store all the various URL components. websUrlParse returns an allocated buffer in buf which we
  893. must free. We support both proxied and non-proxied requests. Proxied requests will have http://host/ at the
  894. start of the URL. Non-proxied will just be local path names.
  895. */
  896. host = path = port = query = ext = NULL;
  897. if (websUrlParse(url, &buf, NULL, &host, &port, &path, &ext, NULL, &query) < 0) {
  898. error("Cannot parse URL: %s", url);
  899. websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE | WEBS_NOLOG, "Bad URL");
  900. return;
  901. }
  902. if ((wp->path = websValidateUriPath(path)) == 0) {
  903. websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE | WEBS_NOLOG, "Bad URL");
  904. wfree(buf);
  905. return;
  906. }
  907. wp->url = sclone(url);
  908. if (ext) {
  909. wp->ext = sclone(slower(ext));
  910. }
  911. wp->filename = sfmt("%s%s", websGetDocuments(), wp->path);
  912. wp->query = sclone(query);
  913. wp->host = sclone(host);
  914. wp->protocol = wp->flags & WEBS_SECURE ? "https" : "http";
  915. if (smatch(protoVer, "HTTP/1.1")) {
  916. wp->flags |= WEBS_KEEP_ALIVE | WEBS_HTTP11;
  917. } else if (smatch(protoVer, "HTTP/1.0")) {
  918. wp->flags &= ~(WEBS_HTTP11);
  919. } else {
  920. protoVer = "HTTP/1.1";
  921. websError(wp, WEBS_CLOSE | HTTP_CODE_NOT_ACCEPTABLE, "Unsupported HTTP protocol");
  922. }
  923. wp->protoVersion = sclone(protoVer);
  924. if ((listenPort = socketGetPort(wp->listenSid)) >= 0) {
  925. wp->port = listenPort;
  926. } else {
  927. wp->port = atoi(port);
  928. }
  929. wfree(buf);
  930. }
  931. /*
  932. Parse a full request
  933. */
  934. static void parseHeaders(Webs *wp)
  935. {
  936. char *combined, *prior, *upperKey, *cp, *key, *value, *tok;
  937. int count;
  938. assert(websValid(wp));
  939. /*
  940. Parse the header and create the Http header keyword variables
  941. We rewrite the header as we go for non-local requests. NOTE: this
  942. modifies the header string directly and tokenizes each line with '\0'.
  943. */
  944. for (count = 0; wp->rxbuf.servp[0] != '\r'; count++) {
  945. if (count >= ME_GOAHEAD_LIMIT_NUM_HEADERS) {
  946. websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Too many headers");
  947. return;
  948. }
  949. if ((key = getToken(wp, ":")) == NULL) {
  950. continue;
  951. }
  952. if ((value = getToken(wp, "\r\n")) == NULL) {
  953. value = "";
  954. }
  955. if (!key || !value) {
  956. websError(wp, HTTP_CODE_BAD_REQUEST | WEBS_CLOSE, "Bad header format");
  957. return;
  958. }
  959. while (isspace((uchar) *value)) {
  960. value++;
  961. }
  962. slower(key);
  963. /*
  964. Create a header variable for each line in the header
  965. */
  966. upperKey = sfmt("HTTP_%s", key);
  967. for (cp = upperKey; *cp; cp++) {
  968. if (*cp == '-') {
  969. *cp = '_';
  970. }
  971. }
  972. supper(upperKey);
  973. if ((prior = websGetVar(wp, upperKey, 0)) != 0) {
  974. combined = sfmt("%s, %s", prior, value);
  975. websSetVar(wp, upperKey, combined);
  976. wfree(combined);
  977. } else {
  978. websSetVar(wp, upperKey, value);
  979. }
  980. wfree(upperKey);
  981. /*
  982. Track the requesting agent (browser) type
  983. */
  984. if (strcmp(key, "user-agent") == 0) {
  985. wfree(wp->userAgent);
  986. wp->userAgent = sclone(value);
  987. } else if (scaselesscmp(key, "authorization") == 0) {
  988. wfree(wp->authType);
  989. wp->authType = sclone(value);
  990. ssplit(wp->authType, " \t", &tok);
  991. wfree(wp->authDetails);
  992. wp->authDetails = sclone(tok);
  993. slower(wp->authType);
  994. } else if (strcmp(key, "connection") == 0) {
  995. slower(value);
  996. if (strcmp(value, "keep-alive") == 0) {
  997. wp->flags |= WEBS_KEEP_ALIVE;
  998. } else if (strcmp(value, "close") == 0) {
  999. wp->flags &= ~WEBS_KEEP_ALIVE;
  1000. }
  1001. } else if (strcmp(key, "content-length") == 0) {
  1002. wp->rxLen = atoi(value);
  1003. if (smatch(wp->method, "PUT")) {
  1004. if (wp->rxLen > ME_GOAHEAD_LIMIT_PUT) {
  1005. websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Too big");
  1006. return;
  1007. }
  1008. } else {
  1009. // if (wp->rxLen > ME_GOAHEAD_LIMIT_POST) {
  1010. // websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Too big");
  1011. // return;
  1012. // }
  1013. }
  1014. if (wp->rxLen > 0 && !smatch(wp->method, "HEAD")) {
  1015. wp->rxRemaining = wp->rxLen;
  1016. }
  1017. } else if (strcmp(key, "content-type") == 0) {
  1018. wfree(wp->contentType);
  1019. wp->contentType = sclone(value);
  1020. // printf("%s>>>>>>>>>>>>>>>wp->contentType>>>>>\n", wp->contentType);
  1021. if (strstr(value, "application/x-www-form-urlencoded")) {
  1022. wp->flags |= WEBS_FORM;
  1023. } else if (strstr(value, "application/json")) {
  1024. wp->flags |= WEBS_JSON;
  1025. } else if (strstr(value, "multipart/form-data")) {
  1026. wp->flags |= WEBS_UPLOAD;
  1027. }
  1028. } else if (strcmp(key, "cookie") == 0) {
  1029. wp->flags |= WEBS_COOKIE;
  1030. if (wp->cookie) {
  1031. char *prior = wp->cookie;
  1032. wp->cookie = sfmt("%s; %s", prior, value);
  1033. wfree(prior);
  1034. } else {
  1035. wp->cookie = sclone(value);
  1036. }
  1037. } else if (strcmp(key, "host") == 0) {
  1038. if ((int) strspn(value, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.[]:")
  1039. < (int) slen(value)) {
  1040. websError(wp, WEBS_CLOSE | HTTP_CODE_BAD_REQUEST, "Bad host header");
  1041. return;
  1042. }
  1043. wfree(wp->host);
  1044. wp->host = sclone(value);
  1045. } else if (strcmp(key, "if-modified-since") == 0) {
  1046. if ((cp = strchr(value, ';')) != NULL) {
  1047. *cp = '\0';
  1048. }
  1049. websParseDateTime(&wp->since, value, 0);
  1050. /*
  1051. Yes Veronica, the HTTP spec does misspell Referrer
  1052. */
  1053. } else if (strcmp(key, "referer") == 0) {
  1054. wfree(wp->referrer);
  1055. wp->referrer = sclone(value);
  1056. } else if (strcmp(key, "transfer-encoding") == 0) {
  1057. if (scaselesscmp(value, "chunked") == 0) {
  1058. wp->rxChunkState = WEBS_CHUNK_START;
  1059. wp->rxRemaining = MAXINT;
  1060. }
  1061. }
  1062. }
  1063. if (!wp->rxChunkState) {
  1064. /*
  1065. Step over "\r\n" after headers.
  1066. Don't do this if chunked so that chunking can parse a single chunk delimiter of "\r\nSIZE ...\r\n"
  1067. */
  1068. assert(bufLen(&wp->rxbuf) >= 2);
  1069. wp->rxbuf.servp += 2;
  1070. }
  1071. wp->eof = (wp->rxRemaining == 0);
  1072. }
  1073. static bool processContent(Webs *wp)
  1074. {
  1075. bool canProceed;
  1076. canProceed = filterChunkData(wp);
  1077. if (!canProceed || wp->finalized) {
  1078. return canProceed;
  1079. }
  1080. #if ME_GOAHEAD_UPLOAD
  1081. if (wp->flags & WEBS_UPLOAD) {
  1082. // printf("<>>>>>>>>>tttttttttttt>>>>>>>>>\n");
  1083. canProceed = websProcessUploadData(wp);
  1084. if (!canProceed || wp->finalized) {
  1085. return canProceed;
  1086. }
  1087. }
  1088. #endif
  1089. #if !ME_ROM
  1090. if (wp->putfd >= 0) {
  1091. canProceed = websProcessPutData(wp);
  1092. if (!canProceed || wp->finalized) {
  1093. return canProceed;
  1094. }
  1095. }
  1096. #endif
  1097. #if ME_GOAHEAD_CGI
  1098. if (wp->cgifd >= 0) {
  1099. canProceed = websProcessCgiData(wp);
  1100. if (!canProceed || wp->finalized) {
  1101. return canProceed;
  1102. }
  1103. }
  1104. #endif
  1105. if (wp->eof) {
  1106. wp->state = WEBS_READY;
  1107. /*
  1108. Prevent reading content from the next request
  1109. The handler may not have been created if all the content was read in the initial read. No matter.
  1110. */
  1111. socketDeleteHandler(wp->sid);
  1112. }
  1113. return canProceed;
  1114. }
  1115. /*
  1116. Always called when data is consumed from the input buffer
  1117. */
  1118. PUBLIC void websConsumeInput(Webs *wp, ssize nbytes)
  1119. {
  1120. assert(wp);
  1121. assert(nbytes >= 0);
  1122. assert(bufLen(&wp->input) >= nbytes);
  1123. if (nbytes <= 0) {
  1124. return;
  1125. }
  1126. bufAdjustStart(&wp->input, nbytes);
  1127. if (bufLen(&wp->input) == 0) {
  1128. bufReset(&wp->input);
  1129. }
  1130. }
  1131. static bool filterChunkData(Webs *wp)
  1132. {
  1133. WebsBuf *rxbuf;
  1134. ssize chunkSize;
  1135. char *start, *cp;
  1136. ssize len, nbytes;
  1137. int bad;
  1138. assert(wp);
  1139. assert(wp->rxbuf.buf);
  1140. rxbuf = &wp->rxbuf;
  1141. while (bufLen(rxbuf) > 0) {
  1142. switch (wp->rxChunkState) {
  1143. case WEBS_CHUNK_UNCHUNKED:
  1144. len = min(wp->rxRemaining, bufLen(rxbuf));
  1145. // printf("---> bufPutBlk1 len = %d\n", len);
  1146. bufPutBlk(&wp->input, rxbuf->servp, len);
  1147. bufAddNull(&wp->input);
  1148. bufAdjustStart(rxbuf, len);
  1149. bufCompact(rxbuf);
  1150. wp->rxRemaining -= len;
  1151. if (wp->rxRemaining <= 0) {
  1152. wp->eof = 1;
  1153. }
  1154. assert(wp->rxRemaining >= 0);
  1155. return 1;
  1156. case WEBS_CHUNK_START:
  1157. /*
  1158. Expect: "\r\nSIZE.*\r\n"
  1159. */
  1160. if (bufLen(rxbuf) < 5) {
  1161. return 0;
  1162. }
  1163. start = rxbuf->servp;
  1164. bad = (start[0] != '\r' || start[1] != '\n');
  1165. for (cp = &start[2]; cp < rxbuf->endp && *cp != '\n'; cp++) {}
  1166. if (*cp != '\n' && (cp - start) < 80) {
  1167. /* Insufficient data */
  1168. return 0;
  1169. }
  1170. bad += (cp[-1] != '\r' || cp[0] != '\n');
  1171. if (bad) {
  1172. websError(wp, WEBS_CLOSE | HTTP_CODE_BAD_REQUEST, "Bad chunk specification");
  1173. return 1;
  1174. }
  1175. chunkSize = hextoi(&start[2]);
  1176. if (!isxdigit((uchar) start[2]) || chunkSize < 0) {
  1177. websError(wp, WEBS_CLOSE | HTTP_CODE_BAD_REQUEST, "Bad chunk specification");
  1178. return 1;
  1179. }
  1180. if (chunkSize == 0) {
  1181. /* On the last chunk, consume the final "\r\n" */
  1182. if ((cp + 2) >= rxbuf->endp) {
  1183. /* Insufficient data */
  1184. return 0;
  1185. }
  1186. cp += 2;
  1187. bad += (cp[-1] != '\r' || cp[0] != '\n');
  1188. if (bad) {
  1189. websError(wp, WEBS_CLOSE | HTTP_CODE_BAD_REQUEST, "Bad final chunk specification");
  1190. return 1;
  1191. }
  1192. }
  1193. bufAdjustStart(rxbuf, cp - start + 1);
  1194. wp->rxChunkSize = chunkSize;
  1195. wp->rxRemaining = chunkSize;
  1196. if (chunkSize == 0) {
  1197. #if ME_GOAHEAD_LEGACY
  1198. wfree(wp->query);
  1199. wp->query = sclone(bufStart(&wp->input));
  1200. #endif
  1201. wp->eof = 1;
  1202. return 1;
  1203. }
  1204. trace(7, "chunkFilter: start incoming chunk of %d bytes", chunkSize);
  1205. wp->rxChunkState = WEBS_CHUNK_DATA;
  1206. break;
  1207. case WEBS_CHUNK_DATA:
  1208. len = min(bufLen(rxbuf), wp->rxRemaining);
  1209. nbytes = min(bufRoom(&wp->input), len);
  1210. // printf("---> bufPutBlk2 len = %d\n", len);
  1211. if (len > 0 && (nbytes = bufPutBlk(&wp->input, rxbuf->servp, nbytes)) == 0) {
  1212. printf("<<<<<<<<<<<<<<>>42222>>>>>>>>>>>>\n" );
  1213. websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Too big");
  1214. return 1;
  1215. }
  1216. bufAddNull(&wp->input);
  1217. bufAdjustStart(rxbuf, nbytes);
  1218. wp->rxRemaining -= nbytes;
  1219. if (wp->rxRemaining <= 0) {
  1220. wp->rxChunkState = WEBS_CHUNK_START;
  1221. bufCompact(rxbuf);
  1222. }
  1223. break;
  1224. }
  1225. }
  1226. return 0;
  1227. }
  1228. /*
  1229. Basic event loop. SocketReady returns true when a socket is ready for service. SocketSelect will block until an
  1230. event occurs. SocketProcess will actually do the servicing.
  1231. */
  1232. PUBLIC void websServiceEvents(int *finished)
  1233. {
  1234. int delay, nextEvent;
  1235. if (finished) {
  1236. *finished = 0;
  1237. }
  1238. delay = 0;
  1239. while (!finished || !*finished) {
  1240. if (socketSelect(-1, delay)) {
  1241. socketProcess();
  1242. }
  1243. #if ME_GOAHEAD_CGI
  1244. delay = websCgiPoll();
  1245. #else
  1246. delay = MAXINT;
  1247. #endif
  1248. nextEvent = websRunEvents();
  1249. delay = min(delay, nextEvent);
  1250. }
  1251. }
  1252. /*
  1253. NOTE: the vars variable is modified
  1254. */
  1255. static void addFormVars(Webs *wp, char *vars)
  1256. {
  1257. WebsKey *sp;
  1258. char *keyword, *value, *prior, *tok;
  1259. assert(wp);
  1260. assert(vars);
  1261. keyword = stok(vars, "&", &tok);
  1262. while (keyword != NULL) {
  1263. if ((value = strchr(keyword, '=')) != NULL) {
  1264. *value++ = '\0';
  1265. websDecodeUrl(keyword, keyword, strlen(keyword));
  1266. websDecodeUrl(value, value, strlen(value));
  1267. } else {
  1268. value = "";
  1269. }
  1270. if (*keyword) {
  1271. /*
  1272. If keyword has already been set, append the new value to what has been stored.
  1273. */
  1274. if ((prior = websGetVar(wp, keyword, NULL)) != 0) {
  1275. sp = websSetVarFmt(wp, keyword, "%s %s", prior, value);
  1276. } else {
  1277. sp = websSetVar(wp, keyword, value);
  1278. }
  1279. /* Flag as untrusted keyword by setting arg to 1. This is used by CGI to prefix this keyword */
  1280. sp->arg = 1;
  1281. }
  1282. keyword = stok(NULL, "&", &tok);
  1283. }
  1284. }
  1285. /*
  1286. Set the variable (CGI) environment for this request. Create variables for all standard CGI variables. Also decode
  1287. the query string and create a variable for each name=value pair.
  1288. */
  1289. PUBLIC void websSetEnv(Webs *wp)
  1290. {
  1291. assert(wp);
  1292. assert(websValid(wp));
  1293. websSetVar(wp, "AUTH_TYPE", wp->authType);
  1294. websSetVarFmt(wp, "CONTENT_LENGTH", "%d", wp->rxLen);
  1295. websSetVar(wp, "CONTENT_TYPE", wp->contentType);
  1296. if (wp->route && wp->route->dir) {
  1297. websSetVar(wp, "DOCUMENT_ROOT", wp->route->dir);
  1298. }
  1299. websSetVar(wp, "GATEWAY_INTERFACE", "CGI/1.1");
  1300. websSetVar(wp, "PATH_INFO", wp->path);
  1301. websSetVar(wp, "PATH_TRANSLATED", wp->filename);
  1302. websSetVar(wp, "QUERY_STRING", wp->query);
  1303. websSetVar(wp, "REMOTE_ADDR", wp->ipaddr);
  1304. websSetVar(wp, "REMOTE_USER", wp->username);
  1305. websSetVar(wp, "REMOTE_HOST", wp->ipaddr);
  1306. websSetVar(wp, "REQUEST_METHOD", wp->method);
  1307. websSetVar(wp, "REQUEST_TRANSPORT", wp->protocol);
  1308. websSetVar(wp, "REQUEST_URI", wp->path);
  1309. websSetVar(wp, "SERVER_ADDR", wp->ifaddr);
  1310. websSetVar(wp, "SERVER_HOST", websHost);
  1311. websSetVar(wp, "SERVER_NAME", websHost);
  1312. websSetVarFmt(wp, "SERVER_PORT", "%d", wp->port);
  1313. websSetVar(wp, "SERVER_PROTOCOL", wp->protoVersion);
  1314. websSetVar(wp, "SERVER_URL", websHostUrl);
  1315. websSetVarFmt(wp, "SERVER_SOFTWARE", "GoAhead/%s", ME_VERSION);
  1316. }
  1317. PUBLIC void websSetFormVars(Webs *wp)
  1318. {
  1319. char *data;
  1320. if (wp->rxLen > 0 && bufLen(&wp->input) > 0) {
  1321. if (wp->flags & WEBS_FORM) {
  1322. data = sclone(wp->input.servp);
  1323. addFormVars(wp, data);
  1324. wfree(data);
  1325. }
  1326. }
  1327. }
  1328. PUBLIC void websSetQueryVars(Webs *wp)
  1329. {
  1330. /*
  1331. Decode and create an environment query variable for each query keyword. We split into pairs at each '&', then
  1332. split pairs at the '='. Note: we rely on wp->decodedQuery preserving the decoded values in the symbol table.
  1333. */
  1334. if (wp->query && *wp->query) {
  1335. wfree(wp->decodedQuery);
  1336. wp->decodedQuery = sclone(wp->query);
  1337. addFormVars(wp, wp->decodedQuery);
  1338. }
  1339. }
  1340. /*
  1341. Define a webs (CGI) variable for this connection. Also create in relevant scripting engines. Note: the incoming
  1342. value may be volatile.
  1343. */
  1344. PUBLIC WebsKey *websSetVarFmt(Webs *wp, char *var, char *fmt, ...)
  1345. {
  1346. WebsValue v;
  1347. va_list args;
  1348. assert(websValid(wp));
  1349. assert(var && *var);
  1350. if (fmt) {
  1351. va_start(args, fmt);
  1352. v = valueString(sfmtv(fmt, args), 0);
  1353. v.allocated = 1;
  1354. va_end(args);
  1355. } else {
  1356. v = valueString("", 0);
  1357. }
  1358. return hashEnter(wp->vars, var, v, 0);
  1359. }
  1360. PUBLIC WebsKey *websSetVar(Webs *wp, char *var, char *value)
  1361. {
  1362. WebsValue v;
  1363. assert(websValid(wp));
  1364. assert(var && *var);
  1365. if (value) {
  1366. v = valueString(value, VALUE_ALLOCATE);
  1367. } else {
  1368. v = valueString("", 0);
  1369. }
  1370. return hashEnter(wp->vars, var, v, 0);
  1371. }
  1372. /*
  1373. Return TRUE if a webs variable exists for this connection.
  1374. */
  1375. PUBLIC bool websTestVar(Webs *wp, char *var)
  1376. {
  1377. WebsKey *sp;
  1378. assert(websValid(wp));
  1379. assert(var && *var);
  1380. if (var == NULL || *var == '\0') {
  1381. return 0;
  1382. }
  1383. if ((sp = hashLookup(wp->vars, var)) == NULL) {
  1384. return 0;
  1385. }
  1386. return 1;
  1387. }
  1388. /*
  1389. Get a webs variable but return a default value if string not found. Note, defaultGetValue can be NULL to permit
  1390. testing existence.
  1391. */
  1392. PUBLIC char *websGetVar(Webs *wp, char *var, char *defaultGetValue)
  1393. {
  1394. WebsKey *sp;
  1395. assert(websValid(wp));
  1396. assert(var && *var);
  1397. if ((sp = hashLookup(wp->vars, var)) != NULL) {
  1398. assert(sp->content.type == string);
  1399. if (sp->content.value.string) {
  1400. return sp->content.value.string;
  1401. } else {
  1402. return "";
  1403. }
  1404. }
  1405. return defaultGetValue;
  1406. }
  1407. /*
  1408. Return TRUE if a webs variable is set to a given value
  1409. */
  1410. PUBLIC int websCompareVar(Webs *wp, char *var, char *value)
  1411. {
  1412. assert(websValid(wp));
  1413. assert(var && *var);
  1414. if (strcmp(value, websGetVar(wp, var, " __UNDEF__ ")) == 0) {
  1415. return 1;
  1416. }
  1417. return 0;
  1418. }
  1419. /*
  1420. Cancel the request timeout. Note may be called multiple times.
  1421. */
  1422. PUBLIC void websCancelTimeout(Webs *wp)
  1423. {
  1424. assert(websValid(wp));
  1425. if (wp->timeout >= 0) {
  1426. websStopEvent(wp->timeout);
  1427. wp->timeout = -1;
  1428. }
  1429. }
  1430. /*
  1431. Output a HTTP response back to the browser. If redirect is set to a URL, the browser will be sent to this location.
  1432. */
  1433. PUBLIC void websResponse(Webs *wp, int code, char *message)
  1434. {
  1435. ssize len;
  1436. assert(websValid(wp));
  1437. websSetStatus(wp, code);
  1438. if (!smatch(wp->method, "HEAD") && message && *message) {
  1439. len = slen(message);
  1440. websWriteHeaders(wp, len + 2, 0);
  1441. websWriteEndHeaders(wp);
  1442. websWriteBlock(wp, message, len);
  1443. websWriteBlock(wp, "\r\n", 2);
  1444. } else {
  1445. websWriteHeaders(wp, 0, 0);
  1446. websWriteEndHeaders(wp);
  1447. }
  1448. websDone(wp);
  1449. }
  1450. static char *makeUri(char *scheme, char *host, int port, char *path)
  1451. {
  1452. if (port <= 0) {
  1453. port = smatch(scheme, "https") ? defaultSslPort : defaultHttpPort;
  1454. }
  1455. if (port == 80 || port == 443) {
  1456. return sfmt("%s://%s%s", scheme, host, path);
  1457. }
  1458. return sfmt("%s://%s:%d%s", scheme, host, port, path);
  1459. }
  1460. /*
  1461. Redirect the user to another webs page
  1462. */
  1463. PUBLIC void websRedirect(Webs *wp, char *uri)
  1464. {
  1465. char *message, *location, *scheme, *host, *pstr;
  1466. char hostbuf[ME_GOAHEAD_LIMIT_STRING];
  1467. bool secure, fullyQualified;
  1468. ssize len;
  1469. int originalPort, port;
  1470. assert(websValid(wp));
  1471. assert(uri);
  1472. message = location = NULL;
  1473. originalPort = port = 0;
  1474. if ((host = (wp->host ? wp->host : websHostUrl)) != 0) {
  1475. scopy(hostbuf, sizeof(hostbuf), host);
  1476. pstr = strchr(hostbuf, ']');
  1477. pstr = pstr ? pstr : hostbuf;
  1478. if ((pstr = strchr(pstr, ':')) != 0) {
  1479. *pstr++ = '\0';
  1480. originalPort = atoi(pstr);
  1481. }
  1482. }
  1483. printf("---> originalPort: %d, hostbuf: %s\n", originalPort, hostbuf);
  1484. if (smatch(uri, "http://") || smatch(uri, "https://")) {
  1485. /* Protocol switch with existing Uri */
  1486. scheme = sncmp(uri, "https", 5) == 0 ? "https" : "http";
  1487. uri = location = makeUri(scheme, hostbuf, 0, wp->url);
  1488. }
  1489. secure = strstr(uri, "https://") != 0;
  1490. fullyQualified = strstr(uri, "http://") || strstr(uri, "https://");
  1491. if (!fullyQualified) {
  1492. port = originalPort;
  1493. if (wp->flags & WEBS_SECURE) {
  1494. secure = 1;
  1495. }
  1496. }
  1497. scheme = secure ? "https" : "http";
  1498. if (port <= 0) {
  1499. port = secure ? defaultSslPort : defaultHttpPort;
  1500. }
  1501. if (strstr(uri, "https:///")) {
  1502. /* Short-hand for redirect to https */
  1503. uri = location = makeUri(scheme, hostbuf, port, &uri[8]);
  1504. } else if (strstr(uri, "http:///")) {
  1505. uri = location = makeUri(scheme, hostbuf, port, &uri[7]);
  1506. } else if (!fullyQualified) {
  1507. uri = location = makeUri(scheme, hostbuf, port, uri);
  1508. }
  1509. message = sfmt("<html><head></head><body>\r\n\
  1510. This document has moved to a new <a href=\"%s\">location</a>.\r\n\
  1511. Please update your documents to reflect the new location.\r\n\
  1512. </body></html>\r\n", uri);
  1513. len = slen(message);
  1514. websSetStatus(wp, HTTP_CODE_MOVED_TEMPORARILY);
  1515. websWriteHeaders(wp, len + 2, uri);
  1516. websWriteEndHeaders(wp);
  1517. websWriteBlock(wp, message, len);
  1518. websWriteBlock(wp, "\r\n", 2);
  1519. websDone(wp);
  1520. wfree(message);
  1521. wfree(location);
  1522. }
  1523. PUBLIC int websRedirectByStatus(Webs *wp, int status)
  1524. {
  1525. WebsKey *key;
  1526. char code[16], *uri;
  1527. assert(wp);
  1528. assert(status >= 0);
  1529. if (wp->route && wp->route->redirects >= 0) {
  1530. itosbuf(code, sizeof(code), status, 10);
  1531. if ((key = hashLookup(wp->route->redirects, code)) != 0) {
  1532. uri = key->content.value.string;
  1533. } else {
  1534. return -1;
  1535. }
  1536. websRedirect(wp, uri);
  1537. } else {
  1538. if (status == HTTP_CODE_UNAUTHORIZED) {
  1539. websError(wp, status, "Access Denied. User not logged in.");
  1540. } else {
  1541. websError(wp, status, 0);
  1542. }
  1543. }
  1544. return 0;
  1545. }
  1546. /*
  1547. Escape HTML to escape defined characters (prevent cross-site scripting)
  1548. Returns an allocated string.
  1549. */
  1550. PUBLIC char *websEscapeHtml(char *html)
  1551. {
  1552. char *ip, *result, *op;
  1553. int len;
  1554. if (!html) {
  1555. return sclone("");
  1556. }
  1557. for (len = 1, ip = html; *ip; ip++, len++) {
  1558. if (charMatch[(int) (uchar) *ip] & WEBS_ENCODE_HTML) {
  1559. len += 5;
  1560. }
  1561. }
  1562. if ((result = walloc(len)) == 0) {
  1563. return 0;
  1564. }
  1565. /*
  1566. Leave room for the biggest expansion
  1567. */
  1568. op = result;
  1569. while (*html != '\0') {
  1570. if (charMatch[(uchar) *html] & WEBS_ENCODE_HTML) {
  1571. if (*html == '&') {
  1572. strcpy(op, "&amp;");
  1573. op += 5;
  1574. } else if (*html == '<') {
  1575. strcpy(op, "&lt;");
  1576. op += 4;
  1577. } else if (*html == '>') {
  1578. strcpy(op, "&gt;");
  1579. op += 4;
  1580. } else if (*html == '#') {
  1581. strcpy(op, "&#35;");
  1582. op += 5;
  1583. } else if (*html == '(') {
  1584. strcpy(op, "&#40;");
  1585. op += 5;
  1586. } else if (*html == ')') {
  1587. strcpy(op, "&#41;");
  1588. op += 5;
  1589. } else if (*html == '"') {
  1590. strcpy(op, "&quot;");
  1591. op += 6;
  1592. } else if (*html == '\'') {
  1593. strcpy(op, "&#39;");
  1594. op += 5;
  1595. } else {
  1596. assert(0);
  1597. }
  1598. html++;
  1599. } else {
  1600. *op++ = *html++;
  1601. }
  1602. }
  1603. assert(op < &result[len]);
  1604. *op = '\0';
  1605. return result;
  1606. }
  1607. PUBLIC int websWriteHeader(Webs *wp, char *key, char *fmt, ...)
  1608. {
  1609. va_list vargs;
  1610. char *buf;
  1611. assert(websValid(wp));
  1612. if (!(wp->flags & WEBS_RESPONSE_TRACED)) {
  1613. wp->flags |= WEBS_RESPONSE_TRACED;
  1614. trace(3 | WEBS_RAW_MSG, "\n>>> Response\n");
  1615. }
  1616. if (key) {
  1617. if (websWriteBlock(wp, key, strlen(key)) < 0) {
  1618. return -1;
  1619. }
  1620. if (websWriteBlock(wp, ": ", 2) < 0) {
  1621. return -1;
  1622. }
  1623. trace(3 | WEBS_RAW_MSG, "%s: ", key);
  1624. }
  1625. if (fmt) {
  1626. va_start(vargs, fmt);
  1627. if ((buf = sfmtv(fmt, vargs)) == 0) {
  1628. error("websWrite lost data, buffer overflow");
  1629. return -1;
  1630. }
  1631. va_end(vargs);
  1632. assert(strstr(buf, "UNION") == 0);
  1633. trace(3 | WEBS_RAW_MSG, "%s", buf);
  1634. if (websWriteBlock(wp, buf, strlen(buf)) < 0) {
  1635. return -1;
  1636. }
  1637. wfree(buf);
  1638. if (websWriteBlock(wp, "\r\n", 2) != 2) {
  1639. return -1;
  1640. }
  1641. }
  1642. trace(3 | WEBS_RAW_MSG, "\r\n");
  1643. return 0;
  1644. }
  1645. PUBLIC void websSetStatus(Webs *wp, int code)
  1646. {
  1647. wp->code = (code & WEBS_CODE_MASK);
  1648. if (code & WEBS_CLOSE) {
  1649. wp->flags &= ~WEBS_KEEP_ALIVE;
  1650. }
  1651. }
  1652. /*
  1653. Write a set of headers. Does not write the trailing blank line so callers can add more headers.
  1654. Set length to -1 if unknown and transfer-chunk-encoding will be employed.
  1655. */
  1656. PUBLIC void websWriteHeaders(Webs *wp, ssize length, char *location)
  1657. {
  1658. WebsKey *key;
  1659. char *date, *protoVersion;
  1660. assert(websValid(wp));
  1661. if (!(wp->flags & WEBS_HEADERS_CREATED)) {
  1662. protoVersion = wp->protoVersion;
  1663. if (!protoVersion) {
  1664. protoVersion = "HTTP/1.0";
  1665. wp->flags &= ~WEBS_KEEP_ALIVE;
  1666. }
  1667. websWriteHeader(wp, NULL, "%s %d %s", protoVersion, wp->code, websErrorMsg(wp->code));
  1668. #if !ME_GOAHEAD_STEALTH
  1669. websWriteHeader(wp, "Server", "GoAhead-http");
  1670. #endif
  1671. if ((date = websGetDateString(NULL)) != NULL) {
  1672. websWriteHeader(wp, "Date", "%s", date);
  1673. wfree(date);
  1674. }
  1675. if (wp->authResponse) {
  1676. websWriteHeader(wp, "WWW-Authenticate", "%s", wp->authResponse);
  1677. }
  1678. if (length >= 0) {
  1679. if (smatch(wp->method, "HEAD")) {
  1680. websWriteHeader(wp, "Content-Length", "%d", (int) length);
  1681. } else if (!((100 <= wp->code && wp->code <= 199) || wp->code == 204 || wp->code == 304)) {
  1682. /* Server must not emit a content length header for 1XX, 204 and 304 status */
  1683. websWriteHeader(wp, "Content-Length", "%d", (int) length);
  1684. }
  1685. }
  1686. wp->txLen = length;
  1687. if (wp->txLen < 0) {
  1688. websWriteHeader(wp, "Transfer-Encoding", "chunked");
  1689. }
  1690. if (wp->flags & WEBS_KEEP_ALIVE) {
  1691. websWriteHeader(wp, "Connection", "keep-alive");
  1692. } else {
  1693. websWriteHeader(wp, "Connection", "close");
  1694. }
  1695. if (location) {
  1696. websWriteHeader(wp, "Location", "%s", location);
  1697. } else if ((key = hashLookup(websMime, wp->ext)) != 0) {
  1698. websWriteHeader(wp, "Content-Type", "%s", key->content.value.string);
  1699. }
  1700. if (wp->responseCookie) {
  1701. websWriteHeader(wp, "Set-Cookie", "%s", wp->responseCookie);
  1702. websWriteHeader(wp, "Cache-Control", "%s", "no-cache=\"set-cookie\"");
  1703. }
  1704. #if defined(ME_GOAHEAD_CLIENT_CACHE)
  1705. if (wp->ext) {
  1706. char *etok = sfmt("%s,", &wp->ext[1]);
  1707. if (strstr(ME_GOAHEAD_CLIENT_CACHE ",", etok)) {
  1708. websWriteHeader(wp, "Cache-Control", "public, max-age=%d", ME_GOAHEAD_CLIENT_CACHE_LIFESPAN);
  1709. }
  1710. wfree(etok);
  1711. }
  1712. #endif
  1713. #ifdef ME_GOAHEAD_XFRAME_HEADER
  1714. if (*ME_GOAHEAD_XFRAME_HEADER) {
  1715. websWriteHeader(wp, "X-Frame-Options", "%s", ME_GOAHEAD_XFRAME_HEADER);
  1716. }
  1717. #endif
  1718. }
  1719. }
  1720. PUBLIC void websWriteEndHeaders(Webs *wp)
  1721. {
  1722. assert(wp);
  1723. /*
  1724. By omitting the "\r\n" delimiter after the headers, chunks can emit "\r\nSize\r\n" as a single chunk delimiter
  1725. */
  1726. if (wp->txLen >= 0) {
  1727. websWriteBlock(wp, "\r\n", 2);
  1728. }
  1729. wp->flags |= WEBS_HEADERS_CREATED;
  1730. if (wp->txLen < 0) {
  1731. wp->flags |= WEBS_CHUNKING;
  1732. }
  1733. }
  1734. PUBLIC void websSetTxLength(Webs *wp, ssize length)
  1735. {
  1736. assert(wp);
  1737. wp->txLen = length;
  1738. }
  1739. /*
  1740. Do formatted output to the browser. This is the public Javascript and form write procedure.
  1741. */
  1742. PUBLIC ssize websWrite(Webs *wp, char *fmt, ...)
  1743. {
  1744. va_list vargs;
  1745. char *buf;
  1746. ssize rc;
  1747. assert(websValid(wp));
  1748. assert(fmt && *fmt);
  1749. va_start(vargs, fmt);
  1750. buf = NULL;
  1751. rc = 0;
  1752. if ((buf = sfmtv(fmt, vargs)) == 0) {
  1753. error("websWrite lost data, buffer overflow");
  1754. }
  1755. va_end(vargs);
  1756. assert(buf);
  1757. if (buf) {
  1758. rc = websWriteBlock(wp, buf, strlen(buf));
  1759. wfree(buf);
  1760. }
  1761. return rc;
  1762. }
  1763. /*
  1764. Non-blocking write to socket.
  1765. Returns number of bytes written. Returns -1 on errors. May return short.
  1766. */
  1767. PUBLIC ssize websWriteSocket(Webs *wp, char *buf, ssize size)
  1768. {
  1769. ssize written;
  1770. assert(wp);
  1771. assert(buf);
  1772. assert(size >= 0);
  1773. if (wp->flags & WEBS_CLOSED) {
  1774. return -1;
  1775. }
  1776. #if ME_COM_SSL
  1777. if (wp->flags & WEBS_SECURE) {
  1778. if ((written = sslWrite(wp, buf, size)) < 0) {
  1779. return written;
  1780. }
  1781. } else
  1782. #endif
  1783. if ((written = socketWrite(wp->sid, buf, size)) < 0) {
  1784. return written;
  1785. }
  1786. wp->written += written;
  1787. websNoteRequestActivity(wp);
  1788. return written;
  1789. }
  1790. /*
  1791. Write some output using transfer chunk encoding if required.
  1792. Returns true if all the data was written. Otherwise return zero.
  1793. */
  1794. static bool flushChunkData(Webs *wp)
  1795. {
  1796. ssize len, written, room;
  1797. assert(wp);
  1798. while (bufLen(&wp->chunkbuf) > 0) {
  1799. /*
  1800. Stop if there is not room for a reasonable size chunk.
  1801. Subtract 16 to allow for the final trailer.
  1802. */
  1803. if ((room = bufRoom(&wp->output) - 16) <= CHUNK_LOW) {
  1804. bufGrow(&wp->output, CHUNK_LOW - room + 1);
  1805. if ((room = bufRoom(&wp->output) - 16) <= CHUNK_LOW) {
  1806. return 0;
  1807. }
  1808. }
  1809. switch (wp->txChunkState) {
  1810. default:
  1811. case WEBS_CHUNK_START:
  1812. /* Select the chunk size so that both the prefix and data will fit */
  1813. wp->txChunkLen = min(bufLen(&wp->chunkbuf), room - 16);
  1814. fmt(wp->txChunkPrefix, sizeof(wp->txChunkPrefix), "\r\n%x\r\n", wp->txChunkLen);
  1815. wp->txChunkPrefixLen = slen(wp->txChunkPrefix);
  1816. wp->txChunkPrefixNext = wp->txChunkPrefix;
  1817. wp->txChunkState = WEBS_CHUNK_HEADER;
  1818. break;
  1819. case WEBS_CHUNK_HEADER:
  1820. // printf("---> bufPutBlk3 len = %d\n", wp->txChunkPrefixLen);
  1821. if ((written = bufPutBlk(&wp->output, wp->txChunkPrefixNext, wp->txChunkPrefixLen)) < 0) {
  1822. return 0;
  1823. } else {
  1824. wp->txChunkPrefixNext += written;
  1825. wp->txChunkPrefixLen -= written;
  1826. if (wp->txChunkPrefixLen <= 0) {
  1827. wp->txChunkState = WEBS_CHUNK_DATA;
  1828. } else {
  1829. return 0;
  1830. }
  1831. }
  1832. break;
  1833. case WEBS_CHUNK_DATA:
  1834. if (wp->txChunkLen > 0) {
  1835. len = min(room, wp->txChunkLen);
  1836. // printf("---> bufPutBlk4 len = %d, room = %d, wp->txChunkLen = %d\n", len, room, wp->txChunkLen);
  1837. if ((written = bufPutBlk(&wp->output, wp->chunkbuf.servp, len)) != len) {
  1838. assert(0);
  1839. return -1;
  1840. }
  1841. bufAdjustStart(&wp->chunkbuf, written);
  1842. wp->txChunkLen -= written;
  1843. if (wp->txChunkLen <= 0) {
  1844. wp->txChunkState = WEBS_CHUNK_START;
  1845. bufCompact(&wp->chunkbuf);
  1846. }
  1847. bufAddNull(&wp->output);
  1848. }
  1849. }
  1850. }
  1851. return bufLen(&wp->chunkbuf) == 0;
  1852. }
  1853. /*
  1854. Initiate flushing output buffer. Returns true if all data is written to the socket and the buffer is empty.
  1855. Returns < 0 for errors
  1856. == 0 if there is output remaining to be flushed
  1857. == 1 if the output was fully written to the socket
  1858. */
  1859. PUBLIC int websFlush(Webs *wp, bool block)
  1860. {
  1861. WebsBuf *op;
  1862. ssize nbytes, written;
  1863. int errCode, wasBlocking;
  1864. if (block) {
  1865. wasBlocking = socketSetBlock(wp->sid, 1);
  1866. }
  1867. op = &wp->output;
  1868. if (wp->flags & WEBS_CHUNKING) {
  1869. trace(6, "websFlush chunking finalized %d", wp->finalized);
  1870. if (flushChunkData(wp) && wp->finalized) {
  1871. trace(6, "websFlush: write chunk trailer");
  1872. bufPutStr(op, "\r\n0\r\n\r\n");
  1873. bufAddNull(op);
  1874. wp->flags &= ~WEBS_CHUNKING;
  1875. }
  1876. }
  1877. trace(6, "websFlush: buflen %d", bufLen(op));
  1878. written = 0;
  1879. while ((nbytes = bufLen(op)) > 0) {
  1880. if ((written = websWriteSocket(wp, op->servp, nbytes)) < 0) {
  1881. errCode = socketGetError();
  1882. if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
  1883. /* Not an error */
  1884. written = 0;
  1885. break;
  1886. }
  1887. /*
  1888. Connection Error
  1889. */
  1890. wp->flags &= ~WEBS_KEEP_ALIVE;
  1891. bufFlush(op);
  1892. wp->state = WEBS_COMPLETE;
  1893. break;
  1894. } else if (written == 0) {
  1895. break;
  1896. }
  1897. trace(6, "websFlush: wrote %d to socket", written);
  1898. bufAdjustStart(op, written);
  1899. bufCompact(op);
  1900. nbytes = bufLen(op);
  1901. }
  1902. assert(websValid(wp));
  1903. if (bufLen(op) == 0 && wp->finalized) {
  1904. wp->state = WEBS_COMPLETE;
  1905. }
  1906. if (block) {
  1907. socketSetBlock(wp->sid, wasBlocking);
  1908. }
  1909. if (written < 0) {
  1910. /* I/O Error */
  1911. return -1;
  1912. }
  1913. return bufLen(op) == 0;
  1914. }
  1915. /*
  1916. Respond to a writable event. First write any tx buffer by calling websFlush.
  1917. Then write body data if writeProc is defined. If all written, ensure transition to complete state.
  1918. Calls websPump() to advance state.
  1919. */
  1920. static void writeEvent(Webs *wp)
  1921. {
  1922. WebsBuf *op;
  1923. op = &wp->output;
  1924. if (bufLen(op) > 0) {
  1925. websFlush(wp, 0);
  1926. }
  1927. if (bufLen(op) == 0 && wp->writeData) {
  1928. (wp->writeData)(wp);
  1929. }
  1930. if (wp->state != WEBS_RUNNING) {
  1931. websPump(wp);
  1932. }
  1933. }
  1934. PUBLIC void websSetBackgroundWriter(Webs *wp, WebsWriteProc proc)
  1935. {
  1936. WebsSocket *sp;
  1937. WebsBuf *op;
  1938. assert(proc);
  1939. wp->writeData = proc;
  1940. op = &wp->output;
  1941. if (bufLen(op) > 0) {
  1942. websFlush(wp, 0);
  1943. }
  1944. if (bufLen(op) == 0) {
  1945. (wp->writeData)(wp);
  1946. }
  1947. if (wp->sid >= 0 && wp->state < WEBS_COMPLETE) {
  1948. sp = socketPtr(wp->sid);
  1949. socketCreateHandler(wp->sid, sp->handlerMask | SOCKET_WRITABLE, socketEvent, wp);
  1950. }
  1951. }
  1952. /*
  1953. Write a block of data of length to the user's browser. Output is buffered and flushed via websFlush.
  1954. This routine will never return "short". i.e. it will return the requested size to write or -1.
  1955. Buffer data. Will flush as required. May return -1 on write errors.
  1956. */
  1957. PUBLIC ssize websWriteBlock(Webs *wp, char *buf, ssize size)
  1958. {
  1959. WebsBuf *op;
  1960. ssize written, thisWrite, len, room;
  1961. assert(wp);
  1962. assert(websValid(wp));
  1963. assert(buf);
  1964. assert(size >= 0);
  1965. if (wp->state >= WEBS_COMPLETE) {
  1966. return -1;
  1967. }
  1968. op = (wp->flags & WEBS_CHUNKING) ? &wp->chunkbuf : &wp->output;
  1969. written = len = 0;
  1970. while (size > 0 && wp->state < WEBS_COMPLETE) {
  1971. if (bufRoom(op) < size) {
  1972. /*
  1973. This will do a blocking I/O write. Will only ever fail for I/O errors.
  1974. */
  1975. if (websFlush(wp, 1) < 0) {
  1976. return -1;
  1977. }
  1978. }
  1979. if ((room = bufRoom(op)) == 0) {
  1980. break;
  1981. }
  1982. thisWrite = min(room, size);
  1983. // printf("---> bufPutBlk5 room = %d, size = %d, thisWrite = %d, buf = %s\n", room, size, thisWrite, buf);
  1984. bufPutBlk(op, buf, thisWrite);
  1985. size -= thisWrite;
  1986. buf += thisWrite;
  1987. written += thisWrite;
  1988. }
  1989. bufAddNull(op);
  1990. if (wp->state >= WEBS_COMPLETE && written == 0) {
  1991. return -1;
  1992. }
  1993. return written;
  1994. }
  1995. /*
  1996. Decode a URL (or part thereof). Allows insitu decoding.
  1997. */
  1998. PUBLIC void websDecodeUrl(char *decoded, char *input, ssize len)
  1999. {
  2000. char *ip, *op;
  2001. int num, i, c;
  2002. assert(decoded);
  2003. assert(input);
  2004. if (len < 0) {
  2005. len = strlen(input);
  2006. }
  2007. op = decoded;
  2008. for (ip = input; *ip && len > 0; ip++, op++) {
  2009. if (*ip == '+') {
  2010. *op = ' ';
  2011. } else if (*ip == '%' && isxdigit((uchar) ip[1]) && isxdigit((uchar) ip[2])) {
  2012. /*
  2013. Convert %nn to a single character
  2014. */
  2015. ip++;
  2016. for (i = 0, num = 0; i < 2; i++, ip++) {
  2017. c = tolower((uchar) *ip);
  2018. if (c >= 'a' && c <= 'f') {
  2019. num = (num * 16) + 10 + c - 'a';
  2020. } else {
  2021. num = (num * 16) + c - '0';
  2022. }
  2023. }
  2024. *op = (char) num;
  2025. ip--;
  2026. } else {
  2027. *op = *ip;
  2028. }
  2029. len--;
  2030. }
  2031. *op = '\0';
  2032. }
  2033. #if ME_GOAHEAD_ACCESS_LOG && !ME_ROM
  2034. /*
  2035. Output a log message in Common Log Format: See http://httpd.apache.org/docs/1.3/logs.html#common
  2036. */
  2037. static void logRequest(Webs *wp, int code)
  2038. {
  2039. char *buf, timeStr[28], zoneStr[6], dataStr[16];
  2040. ssize len;
  2041. WebsTime timer;
  2042. struct tm localt;
  2043. #if WINDOWS
  2044. DWORD dwRet;
  2045. TIME_ZONE_INFORMATION tzi;
  2046. #endif
  2047. assert(wp);
  2048. time(&timer);
  2049. #if WINDOWS
  2050. localtime_s(&localt, &timer);
  2051. #else
  2052. localtime_r(&timer, &localt);
  2053. #endif
  2054. strftime(timeStr, sizeof(timeStr), "%d/%b/%Y:%H:%M:%S", &localt);
  2055. timeStr[sizeof(timeStr) - 1] = '\0';
  2056. #if WINDOWS
  2057. dwRet = GetTimeZoneInformation(&tzi);
  2058. fmt(zoneStr, sizeof(zoneStr), "%+03d00", -(int) (tzi.Bias/60));
  2059. #elif !VXWORKS
  2060. fmt(zoneStr, sizeof(zoneStr), "%+03d00", (int) (localt.tm_gmtoff/3600));
  2061. #else
  2062. zoneStr[0] = '\0';
  2063. #endif
  2064. zoneStr[sizeof(zoneStr) - 1] = '\0';
  2065. if (wp->written != 0) {
  2066. fmt(dataStr, sizeof(dataStr), "%Ld", wp->written);
  2067. dataStr[sizeof(dataStr) - 1] = '\0';
  2068. } else {
  2069. dataStr[0] = '-'; dataStr[1] = '\0';
  2070. }
  2071. buf = NULL;
  2072. buf = sfmt("%s - %s [%s %s] \"%s %s %s\" %d %s\n",
  2073. wp->ipaddr, wp->username == NULL ? "-" : wp->username,
  2074. timeStr, zoneStr, wp->method, wp->path, wp->protoVersion, code, dataStr);
  2075. len = strlen(buf);
  2076. write(accessFd, buf, len);
  2077. wfree(buf);
  2078. }
  2079. #endif
  2080. /*
  2081. Request and connection timeout. The timeout triggers if we have not read any data from the
  2082. users browser in the last WEBS_TIMEOUT period. If we have heard from the browser, simply
  2083. re-issue the timeout.
  2084. */
  2085. static void checkTimeout(void *arg, int id)
  2086. {
  2087. Webs *wp;
  2088. int elapsed, delay;
  2089. wp = (Webs*) arg;
  2090. assert(websValid(wp));
  2091. elapsed = getTimeSinceMark(wp) * 1000;
  2092. if (websDebug) {
  2093. websRestartEvent(id, (int) WEBS_TIMEOUT);
  2094. return;
  2095. }
  2096. if (wp->state == WEBS_BEGIN) {
  2097. complete(wp, 0);
  2098. websFree(wp);
  2099. return;
  2100. }
  2101. if (elapsed >= WEBS_TIMEOUT) {
  2102. if (!(wp->flags & WEBS_HEADERS_CREATED)) {
  2103. if (wp->state > WEBS_BEGIN) {
  2104. websError(wp, HTTP_CODE_REQUEST_TIMEOUT, "Request exceeded timeout");
  2105. } else {
  2106. websError(wp, HTTP_CODE_REQUEST_TIMEOUT, "Idle connection closed");
  2107. }
  2108. }
  2109. wp->state = WEBS_COMPLETE;
  2110. complete(wp, 0);
  2111. websFree(wp);
  2112. /* WARNING: wp not valid here */
  2113. return;
  2114. }
  2115. delay = WEBS_TIMEOUT - elapsed;
  2116. assert(delay > 0);
  2117. websRestartEvent(id, delay);
  2118. }
  2119. static int get_local_ip(const char *eth_inf, char *ip)
  2120. {
  2121. int sd;
  2122. struct sockaddr_in sin;
  2123. struct ifreq ifr;
  2124. sd = socket(AF_INET, SOCK_DGRAM, 0);
  2125. if (-1 == sd)
  2126. {
  2127. error("socket error: %s\n", strerror(errno));
  2128. return -1;
  2129. }
  2130. strncpy(ifr.ifr_name, eth_inf, IFNAMSIZ);
  2131. ifr.ifr_name[IFNAMSIZ - 1] = 0;
  2132. // if error: No such device
  2133. if (ioctl(sd, SIOCGIFADDR, &ifr) < 0)
  2134. {
  2135. error("ioctl error: %s\n", strerror(errno));
  2136. close(sd);
  2137. return -1;
  2138. }
  2139. memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
  2140. snprintf(ip, 16, "%s", inet_ntoa(sin.sin_addr));
  2141. close(sd);
  2142. return 0;
  2143. }
  2144. static int setLocalHost()
  2145. {
  2146. // struct in_addr intaddr;
  2147. // char host[128], *ipaddr;
  2148. // if (gethostname(host, sizeof(host)) < 0) {
  2149. // error("Cannot get hostname: errno %d", errno);
  2150. // return -1;
  2151. // }
  2152. // #if VXWORKS
  2153. // intaddr.s_addr = (ulong) hostGetByName(host);
  2154. // ipaddr = inet_ntoa(intaddr);
  2155. // websSetIpAddr(ipaddr);
  2156. // websSetHost(ipaddr);
  2157. // #if _WRS_VXWORKS_MAJOR < 6
  2158. // free(ipaddr);
  2159. // #endif
  2160. // #elif ECOS
  2161. // ipaddr = inet_ntoa(eth0_bootp_data.bp_yiaddr);
  2162. // websSetIpAddr(ipaddr);
  2163. // websSetHost(ipaddr);
  2164. // #elif TIDSP
  2165. // {
  2166. // struct hostent *hp;
  2167. // if ((hp = gethostbyname(host)) == NULL) {
  2168. // error("Cannot get host address for host %s: errno %d", host, errno);
  2169. // return -1;
  2170. // }
  2171. // memcpy((char*) &intaddr, (char *) hp->h_addr[0], (size_t) hp->h_length);
  2172. // ipaddr = inet_ntoa(intaddr);
  2173. // websSetIpAddr(ipaddr);
  2174. // websSetHost(ipaddr);
  2175. // }
  2176. // #elif MACOSX
  2177. // {
  2178. // struct hostent *hp;
  2179. // if ((hp = gethostbyname(host)) == NULL) {
  2180. // if ((hp = gethostbyname(sfmt("%s.local", host))) == NULL) {
  2181. // error("Cannot get host address for host %s: errno %d", host, errno);
  2182. // return -1;
  2183. // }
  2184. // }
  2185. // memcpy((char*) &intaddr, (char *) hp->h_addr_list[0], (size_t) hp->h_length);
  2186. // ipaddr = inet_ntoa(intaddr);
  2187. // websSetIpAddr(ipaddr);
  2188. // websSetHost(ipaddr);
  2189. // }
  2190. // #else
  2191. // {
  2192. // struct hostent *hp;
  2193. // if ((hp = gethostbyname(host)) == NULL) {
  2194. // error("Cannot get host address for host %s: errno %d", host, errno);
  2195. // return -1;
  2196. // }
  2197. // memcpy((char*) &intaddr, (char *) hp->h_addr_list[0], (size_t) hp->h_length);
  2198. // ipaddr = inet_ntoa(intaddr);
  2199. // websSetIpAddr(ipaddr);
  2200. // websSetHost(ipaddr);
  2201. // }
  2202. // #endif
  2203. char ipaddr[16];
  2204. get_local_ip("eth0", ipaddr);
  2205. websSetIpAddr(ipaddr);
  2206. websSetHost(ipaddr);
  2207. printf("---> setLocalHost, ip = %s\n", ipaddr);
  2208. return 0;
  2209. }
  2210. PUBLIC void websSetHost(char *host)
  2211. {
  2212. scopy(websHost, sizeof(websHost), host);
  2213. }
  2214. PUBLIC void websSetHostUrl(char *url)
  2215. {
  2216. assert(url && *url);
  2217. wfree(websHostUrl);
  2218. websHostUrl = sclone(url);
  2219. }
  2220. PUBLIC void websSetIpAddr(char *ipaddr)
  2221. {
  2222. assert(ipaddr && *ipaddr);
  2223. scopy(websIpAddr, sizeof(websIpAddr), ipaddr);
  2224. }
  2225. #if ME_GOAHEAD_LEGACY
  2226. PUBLIC void websSetRequestFilename(Webs *wp, char *filename)
  2227. {
  2228. assert(websValid(wp));
  2229. assert(filename && *filename);
  2230. wfree(wp->filename);
  2231. wp->filename = sclone(filename);
  2232. websSetVar(wp, "PATH_TRANSLATED", wp->filename);
  2233. }
  2234. #endif
  2235. PUBLIC int websRewriteRequest(Webs *wp, char *url)
  2236. {
  2237. char *buf, *path;
  2238. wfree(wp->url);
  2239. wp->url = sclone(url);
  2240. wfree(wp->path);
  2241. wp->path = 0;
  2242. if (websUrlParse(url, &buf, NULL, NULL, NULL, &path, NULL, NULL, NULL) < 0) {
  2243. return -1;
  2244. }
  2245. wp->path = sclone(path);
  2246. wfree(wp->filename);
  2247. wp->filename = 0;
  2248. wp->flags |= WEBS_REROUTE;
  2249. wfree(buf);
  2250. return 0;
  2251. }
  2252. PUBLIC bool websValid(Webs *wp)
  2253. {
  2254. int wid;
  2255. for (wid = 0; wid < websMax; wid++) {
  2256. if (wp == webs[wid]) {
  2257. return 1;
  2258. }
  2259. }
  2260. return 0;
  2261. }
  2262. /*
  2263. Build an ASCII time string. If sbuf is NULL we use the current time, else we use the last modified time of sbuf;
  2264. */
  2265. PUBLIC char *websGetDateString(WebsFileInfo *sbuf)
  2266. {
  2267. WebsTime now;
  2268. struct tm tm;
  2269. char *cp;
  2270. if (sbuf == NULL) {
  2271. time(&now);
  2272. } else {
  2273. now = sbuf->mtime;
  2274. }
  2275. #if ME_UNIX_LIKE
  2276. gmtime_r(&now, &tm);
  2277. #else
  2278. {
  2279. struct tm *tp;
  2280. tp = gmtime(&now);
  2281. tm = *tp;
  2282. }
  2283. #endif
  2284. if ((cp = asctime(&tm)) != NULL) {
  2285. cp[strlen(cp) - 1] = '\0';
  2286. return sclone(cp);
  2287. }
  2288. return NULL;
  2289. }
  2290. /*
  2291. Take not of the request activity and mark the time. Set a timestamp so that, later, we can return the number of seconds
  2292. since we made the mark.
  2293. */
  2294. PUBLIC void websNoteRequestActivity(Webs *wp)
  2295. {
  2296. wp->timestamp = time(0);
  2297. }
  2298. /*
  2299. Get the number of seconds since the last mark.
  2300. */
  2301. static int getTimeSinceMark(Webs *wp)
  2302. {
  2303. return (int) (time(0) - wp->timestamp);
  2304. }
  2305. PUBLIC bool websValidUriChars(char *uri)
  2306. {
  2307. ssize pos;
  2308. if (uri == 0 || *uri == 0) {
  2309. return 1;
  2310. }
  2311. pos = strspn(uri, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%");
  2312. if (pos < slen(uri)) {
  2313. error("Bad character in URI at \"%s\"", &uri[pos]);
  2314. return 0;
  2315. }
  2316. return 1;
  2317. }
  2318. /*
  2319. Parse the URL. A single buffer is allocated to store the parsed URL in *pbuf. This must be freed by the caller.
  2320. */
  2321. PUBLIC int websUrlParse(char *url, char **pbuf, char **pscheme, char **phost, char **pport, char **ppath, char **pext,
  2322. char **preference, char **pquery)
  2323. {
  2324. char *tok, *delim, *host, *path, *port, *scheme, *reference, *query, *ext, *buf, *buf2;
  2325. ssize buflen, ulen, len;
  2326. int sep;
  2327. assert(pbuf);
  2328. if (url == 0) {
  2329. url = "";
  2330. }
  2331. /*
  2332. Allocate twice. Need to null terminate the host so have to copy the path.
  2333. */
  2334. ulen = strlen(url);
  2335. len = ulen + 1;
  2336. buflen = len * 2;
  2337. if ((buf = walloc(buflen)) == NULL) {
  2338. return -1;
  2339. }
  2340. buf2 = &buf[ulen + 1];
  2341. sncopy(buf, len, url, ulen);
  2342. sncopy(buf2, len, url, ulen);
  2343. url = buf;
  2344. scheme = 0;
  2345. host = 0;
  2346. port = 0;
  2347. path = 0;
  2348. ext = 0;
  2349. query = 0;
  2350. reference = 0;
  2351. tok = buf;
  2352. sep = '/';
  2353. /*
  2354. [scheme://][hostname[:port]][/path[.ext]][#ref][?query]
  2355. First trim query and then reference from the end
  2356. */
  2357. if ((query = strchr(tok, '?')) != NULL) {
  2358. *query++ = '\0';
  2359. }
  2360. if ((reference = strchr(tok, '#')) != NULL) {
  2361. *reference++ = '\0';
  2362. }
  2363. /*
  2364. [scheme://][hostname[:port]][/path]
  2365. */
  2366. if ((delim = strstr(tok, "://")) != 0) {
  2367. scheme = tok;
  2368. *delim = '\0';
  2369. tok = &delim[3];
  2370. }
  2371. /*
  2372. [hostname[:port]][/path]
  2373. */
  2374. if (*tok == '[' && ((delim = strchr(tok, ']')) != 0)) {
  2375. /* IPv6 [::] */
  2376. host = &tok[1];
  2377. *delim++ = '\0';
  2378. tok = delim;
  2379. } else if (*tok && *tok != '/' && *tok != ':' && (scheme || strchr(tok, ':'))) {
  2380. /*
  2381. Supported forms:
  2382. scheme://hostname
  2383. hostname[:port][/path]
  2384. */
  2385. host = tok;
  2386. if ((tok = strpbrk(tok, ":/")) == 0) {
  2387. tok = "";
  2388. }
  2389. /* Don't terminate the hostname yet, need to see if tok is a ':' for a port. */
  2390. assert(tok);
  2391. }
  2392. /* [:port][/path] */
  2393. if (*tok == ':') {
  2394. /* Terminate hostname */
  2395. *tok++ = '\0';
  2396. port = tok;
  2397. if ((tok = strchr(tok, '/')) == 0) {
  2398. tok = "";
  2399. }
  2400. }
  2401. /* [/path] */
  2402. if (*tok) {
  2403. /*
  2404. Terminate hostname. This zeros the leading path slash.
  2405. This will be repaired before returning if ppath is set
  2406. */
  2407. sep = *tok;
  2408. *tok++ = '\0';
  2409. path = tok;
  2410. /* path[.ext[/extra]] */
  2411. if ((tok = strrchr(path, '.')) != 0) {
  2412. if (tok[1]) {
  2413. if ((delim = strrchr(path, '/')) != 0) {
  2414. if (delim < tok) {
  2415. ext = tok;
  2416. }
  2417. } else {
  2418. ext = tok;
  2419. }
  2420. }
  2421. }
  2422. }
  2423. /*
  2424. Pass back the requested fields
  2425. */
  2426. *pbuf = buf;
  2427. if (pscheme) {
  2428. if (scheme == 0) {
  2429. scheme = "http";
  2430. }
  2431. *pscheme = scheme;
  2432. }
  2433. if (phost) {
  2434. if (host == 0) {
  2435. host = "localhost";
  2436. }
  2437. *phost = host;
  2438. }
  2439. if (pport) {
  2440. *pport = port;
  2441. }
  2442. if (ppath) {
  2443. if (path == 0) {
  2444. scopy(buf2, 1, "/");
  2445. path = buf2;
  2446. } else {
  2447. /* Copy path to reinsert leading slash */
  2448. scopy(&buf2[1], len - 1, path);
  2449. path = buf2;
  2450. *path = sep;
  2451. }
  2452. *ppath = path;
  2453. }
  2454. if (pquery) {
  2455. *pquery = query;
  2456. }
  2457. if (preference) {
  2458. *preference = reference;
  2459. }
  2460. if (pext) {
  2461. #if ME_WIN_LIKE
  2462. slower(ext);
  2463. #endif
  2464. *pext = ext;
  2465. }
  2466. return 0;
  2467. }
  2468. /*
  2469. Normalize a URI path to remove "./", "../" and redundant separators.
  2470. Note: this does not make an abs path and does not map separators nor change case.
  2471. This validates the URI and expects it to begin with "/".
  2472. Returns an allocated path, caller must free.
  2473. */
  2474. PUBLIC char *websNormalizeUriPath(char *pathArg)
  2475. {
  2476. char *dupPath, *path, *sp, *dp, *mark, **segments;
  2477. int firstc, j, i, nseg, len;
  2478. if (pathArg == 0 || *pathArg == '\0') {
  2479. return sclone("");
  2480. }
  2481. len = (int) slen(pathArg);
  2482. if ((dupPath = walloc(len + 2)) == 0) {
  2483. return NULL;
  2484. }
  2485. strcpy(dupPath, pathArg);
  2486. if ((segments = walloc(sizeof(char*) * (len + 1))) == 0) {
  2487. wfree(dupPath);
  2488. return NULL;
  2489. }
  2490. nseg = len = 0;
  2491. firstc = *dupPath;
  2492. for (mark = sp = dupPath; *sp; sp++) {
  2493. if (*sp == '/') {
  2494. *sp = '\0';
  2495. while (sp[1] == '/') {
  2496. sp++;
  2497. }
  2498. segments[nseg++] = mark;
  2499. len += (int) (sp - mark);
  2500. mark = sp + 1;
  2501. }
  2502. }
  2503. segments[nseg++] = mark;
  2504. len += (int) (sp - mark);
  2505. for (j = i = 0; i < nseg; i++, j++) {
  2506. sp = segments[i];
  2507. if (sp[0] == '.') {
  2508. if (sp[1] == '\0') {
  2509. if ((i+1) == nseg) {
  2510. /* Trim trailing "." */
  2511. segments[j] = "";
  2512. } else {
  2513. j--;
  2514. }
  2515. } else if (sp[1] == '.' && sp[2] == '\0') {
  2516. j = max(j - 2, -1);
  2517. if ((i+1) == nseg) {
  2518. nseg--;
  2519. }
  2520. } else {
  2521. /* .more-chars */
  2522. segments[j] = segments[i];
  2523. }
  2524. } else {
  2525. segments[j] = segments[i];
  2526. }
  2527. }
  2528. nseg = j;
  2529. assert(nseg >= 0);
  2530. if ((path = walloc(len + nseg + 1)) != 0) {
  2531. for (i = 0, dp = path; i < nseg; ) {
  2532. strcpy(dp, segments[i]);
  2533. len = (int) slen(segments[i]);
  2534. dp += len;
  2535. if (++i < nseg || (nseg == 1 && *segments[0] == '\0' && firstc == '/')) {
  2536. *dp++ = '/';
  2537. }
  2538. }
  2539. *dp = '\0';
  2540. }
  2541. wfree(dupPath);
  2542. wfree(segments);
  2543. return path;
  2544. }
  2545. /*
  2546. Validate a URI path for use in a HTTP request line
  2547. The URI must contain only valid characters and must being with "/" both before and after decoding.
  2548. A decoded, normalized URI path is returned.
  2549. The uri is modified. Returns an allocated path. Caller must free.
  2550. */
  2551. PUBLIC char *websValidateUriPath(char *uri)
  2552. {
  2553. if (uri == 0 || *uri != '/') {
  2554. return 0;
  2555. }
  2556. if (!websValidUriChars(uri)) {
  2557. return 0;
  2558. }
  2559. websDecodeUrl(uri, uri, -1);
  2560. if ((uri = websNormalizeUriPath(uri)) == 0) {
  2561. return 0;
  2562. }
  2563. if (*uri != '/' || strchr(uri, '\\')) {
  2564. wfree(uri);
  2565. return 0;
  2566. }
  2567. return uri;
  2568. }
  2569. /*
  2570. Open a web page. filename is the local filename. path is the URL path name.
  2571. */
  2572. PUBLIC int websPageOpen(Webs *wp, int mode, int perm)
  2573. {
  2574. assert(websValid(wp));
  2575. return (wp->docfd = websOpenFile(wp->filename, mode, perm));
  2576. }
  2577. PUBLIC void websPageClose(Webs *wp)
  2578. {
  2579. assert(websValid(wp));
  2580. if (wp->docfd >= 0) {
  2581. websCloseFile(wp->docfd);
  2582. wp->docfd = -1;
  2583. }
  2584. }
  2585. PUBLIC int websPageStat(Webs *wp, WebsFileInfo *sbuf)
  2586. {
  2587. return websStatFile(wp->filename, sbuf);
  2588. }
  2589. PUBLIC int websPageIsDirectory(Webs *wp)
  2590. {
  2591. WebsFileInfo sbuf;
  2592. if (websStatFile(wp->filename, &sbuf) >= 0) {
  2593. return(sbuf.isDir);
  2594. }
  2595. return 0;
  2596. }
  2597. /*
  2598. Read a web page. Returns the number of _bytes_ read. len is the size of buf, in bytes.
  2599. */
  2600. PUBLIC ssize websPageReadData(Webs *wp, char *buf, ssize nBytes)
  2601. {
  2602. assert(websValid(wp));
  2603. return websReadFile(wp->docfd, buf, nBytes);
  2604. }
  2605. /*
  2606. Move file pointer offset bytes.
  2607. */
  2608. PUBLIC void websPageSeek(Webs *wp, Offset offset, int origin)
  2609. {
  2610. assert(websValid(wp));
  2611. websSeekFile(wp->docfd, offset, origin);
  2612. }
  2613. PUBLIC void websSetCookie(Webs *wp, char *name, char *value, char *path, char *cookieDomain, int lifespan, int flags)
  2614. {
  2615. WebsTime when;
  2616. char *cp, *expiresAtt, *expires, *domainAtt, *domain, *secure, *httponly, *cookie, *old;
  2617. assert(wp);
  2618. assert(name && *name);
  2619. if (path == 0) {
  2620. path = "/";
  2621. }
  2622. if (!cookieDomain) {
  2623. domain = sclone(wp->host);
  2624. if ((cp = strchr(domain, ':')) != 0) {
  2625. /* Strip port */
  2626. *cp = '\0';
  2627. }
  2628. if (*domain && domain[strlen(domain) - 1] == '.') {
  2629. /* Cleanup bonjour addresses with trailing dot */
  2630. domain[strlen(domain) - 1] = '\0';
  2631. }
  2632. } else {
  2633. domain = sclone(cookieDomain);
  2634. }
  2635. domainAtt = "";
  2636. if (smatch(domain, "localhost")) {
  2637. wfree(domain);
  2638. domain = sclone("");
  2639. } else {
  2640. domainAtt = "; domain=";
  2641. if (!strchr(domain, '.')) {
  2642. old = domain;
  2643. domain = sfmt(".%s", domain);
  2644. wfree(old);
  2645. }
  2646. }
  2647. if (lifespan > 0) {
  2648. expiresAtt = "; expires=";
  2649. when = time(0) + lifespan;
  2650. if ((expires = ctime(&when)) != NULL) {
  2651. expires[strlen(expires) - 1] = '\0';
  2652. }
  2653. } else {
  2654. expiresAtt = "";
  2655. expires = "";
  2656. }
  2657. /*
  2658. Allow multiple cookie headers. Even if the same name. Later definitions take precedence
  2659. */
  2660. secure = (flags & WEBS_COOKIE_SECURE) ? "; secure" : "";
  2661. httponly = (flags & WEBS_COOKIE_HTTP) ? "; httponly" : "";
  2662. cookie = sfmt("%s=%s; path=%s%s%s%s%s%s%s", name, value, path, domainAtt, domain, expiresAtt, expires, secure,
  2663. httponly);
  2664. if (wp->responseCookie) {
  2665. old = wp->responseCookie;
  2666. wp->responseCookie = sfmt("%s %s", wp->responseCookie, cookie);
  2667. wfree(old);
  2668. wfree(cookie);
  2669. } else {
  2670. wp->responseCookie = cookie;
  2671. }
  2672. wfree(domain);
  2673. }
  2674. /*
  2675. Return the next token in the input stream. Does not allocate
  2676. */
  2677. static char *getToken(Webs *wp, char *delim)
  2678. {
  2679. WebsBuf *buf;
  2680. char *token, *nextToken, *endToken;
  2681. assert(wp);
  2682. buf = &wp->rxbuf;
  2683. nextToken = (char*) buf->endp;
  2684. for (token = (char*) buf->servp; (*token == ' ' || *token == '\t') && token < (char*) buf->endp; token++) {}
  2685. if (delim == 0) {
  2686. delim = " \t";
  2687. if ((endToken = strpbrk(token, delim)) != 0) {
  2688. nextToken = endToken + strspn(endToken, delim);
  2689. *endToken = '\0';
  2690. }
  2691. } else {
  2692. if ((endToken = strstr(token, delim)) != 0) {
  2693. *endToken = '\0';
  2694. /* Only eat one occurence of the delimiter */
  2695. nextToken = endToken + strlen(delim);
  2696. } else {
  2697. nextToken = buf->endp;
  2698. }
  2699. }
  2700. buf->servp = nextToken;
  2701. return token;
  2702. }
  2703. PUBLIC int websGetBackground()
  2704. {
  2705. return websBackground;
  2706. }
  2707. PUBLIC void websSetBackground(int on)
  2708. {
  2709. websBackground = on;
  2710. }
  2711. PUBLIC int websGetDebug()
  2712. {
  2713. return websDebug;
  2714. }
  2715. PUBLIC void websSetDebug(int on)
  2716. {
  2717. websDebug = on;
  2718. }
  2719. static char *makeSessionID(Webs *wp)
  2720. {
  2721. char idBuf[64];
  2722. static int nextSession = 0;
  2723. assert(wp);
  2724. fmt(idBuf, sizeof(idBuf), "%08x%08x%d", PTOI(wp) + PTOI(wp->url), (int) time(0), nextSession++);
  2725. return websMD5Block(idBuf, slen(idBuf), "::webs.session::");
  2726. }
  2727. PUBLIC void websDestroySession(Webs *wp)
  2728. {
  2729. websGetSession(wp, 0);
  2730. if (wp->session) {
  2731. hashDelete(sessions, wp->session->id);
  2732. sessionCount--;
  2733. freeSession(wp->session);
  2734. wp->session = 0;
  2735. }
  2736. }
  2737. PUBLIC WebsSession *websCreateSession(Webs *wp)
  2738. {
  2739. websDestroySession(wp);
  2740. return websGetSession(wp, 1);
  2741. }
  2742. WebsSession *websAllocSession(Webs *wp, char *id, int lifespan)
  2743. {
  2744. WebsSession *sp;
  2745. assert(wp);
  2746. if ((sp = walloc(sizeof(WebsSession))) == 0) {
  2747. return 0;
  2748. }
  2749. sp->lifespan = lifespan;
  2750. sp->expires = time(0) + lifespan;
  2751. if (id == 0) {
  2752. sp->id = makeSessionID(wp);
  2753. } else {
  2754. sp->id = sclone(id);
  2755. }
  2756. if ((sp->cache = hashCreate(WEBS_SESSION_HASH)) == 0) {
  2757. wfree(sp->id);
  2758. wfree(sp);
  2759. return 0;
  2760. }
  2761. if (hashEnter(sessions, sp->id, valueSymbol(sp), 0) == 0) {
  2762. wfree(sp->id);
  2763. wfree(sp);
  2764. return 0;
  2765. }
  2766. return sp;
  2767. }
  2768. static void freeSession(WebsSession *sp)
  2769. {
  2770. assert(sp);
  2771. if (sp->cache >= 0) {
  2772. hashFree(sp->cache);
  2773. sp->cache = -1;
  2774. }
  2775. wfree(sp->id);
  2776. wfree(sp);
  2777. }
  2778. WebsSession *websGetSession(Webs *wp, int create)
  2779. {
  2780. WebsKey *sym;
  2781. char *id;
  2782. assert(wp);
  2783. if (!wp->session) {
  2784. id = websGetSessionID(wp);
  2785. if ((sym = hashLookup(sessions, id)) == 0) {
  2786. if (!create) {
  2787. wfree(id);
  2788. return 0;
  2789. }
  2790. if (sessionCount > ME_GOAHEAD_LIMIT_SESSION_COUNT) {
  2791. error("Too many sessions %d/%d", sessionCount, ME_GOAHEAD_LIMIT_SESSION_COUNT);
  2792. wfree(id);
  2793. return 0;
  2794. }
  2795. sessionCount++;
  2796. if ((wp->session = websAllocSession(wp, id, ME_GOAHEAD_LIMIT_SESSION_LIFE)) == 0) {
  2797. wfree(id);
  2798. return 0;
  2799. }
  2800. websSetCookie(wp, WEBS_SESSION, wp->session->id, "/", NULL, 0, 0);
  2801. } else {
  2802. wp->session = (WebsSession*) sym->content.value.symbol;
  2803. }
  2804. wfree(id);
  2805. }
  2806. if (wp->session) {
  2807. wp->session->expires = time(0) + wp->session->lifespan;
  2808. }
  2809. return wp->session;
  2810. }
  2811. static char *websParseCookie(Webs *wp, char *name)
  2812. {
  2813. cchar *cookie;
  2814. char *cp, *value;
  2815. ssize nlen;
  2816. int quoted;
  2817. assert(wp);
  2818. if ((cookie = wp->cookie) == 0 || name == 0 || *name == '\0') {
  2819. return 0;
  2820. }
  2821. nlen = slen(name);
  2822. while ((value = strstr(cookie, name)) != 0) {
  2823. /* Ignore corrupt cookies of the form "name=;" */
  2824. if ((value == cookie || value[-1] == ' ' || value[-1] == ';') && value[nlen] == '=' && value[nlen+1] != ';') {
  2825. break;
  2826. }
  2827. cookie += nlen;
  2828. }
  2829. if (value == 0) {
  2830. return 0;
  2831. }
  2832. value += nlen;
  2833. while (isspace((uchar) *value) || *value == '=') {
  2834. value++;
  2835. }
  2836. quoted = 0;
  2837. if (*value == '"') {
  2838. value++;
  2839. quoted++;
  2840. }
  2841. for (cp = value; *cp; cp++) {
  2842. if (quoted) {
  2843. if (*cp == '"' && cp[-1] != '\\') {
  2844. break;
  2845. }
  2846. } else {
  2847. if ((*cp == ',' || *cp == ';') && cp[-1] != '\\') {
  2848. break;
  2849. }
  2850. }
  2851. }
  2852. return snclone(value, cp - value);
  2853. }
  2854. PUBLIC char *websGetSessionID(Webs *wp)
  2855. {
  2856. assert(wp);
  2857. if (wp->session) {
  2858. return wp->session->id;
  2859. }
  2860. return websParseCookie(wp, WEBS_SESSION);
  2861. }
  2862. PUBLIC char *websGetSessionVar(Webs *wp, char *key, char *defaultValue)
  2863. {
  2864. WebsSession *sp;
  2865. WebsKey *sym;
  2866. assert(wp);
  2867. assert(key && *key);
  2868. if ((sp = websGetSession(wp, 1)) != 0) {
  2869. if ((sym = hashLookup(sp->cache, key)) == 0) {
  2870. return defaultValue;
  2871. }
  2872. return (char*) sym->content.value.symbol;
  2873. }
  2874. return 0;
  2875. }
  2876. PUBLIC void websRemoveSessionVar(Webs *wp, char *key)
  2877. {
  2878. WebsSession *sp;
  2879. assert(wp);
  2880. assert(key && *key);
  2881. if ((sp = websGetSession(wp, 1)) != 0) {
  2882. hashDelete(sp->cache, key);
  2883. }
  2884. }
  2885. PUBLIC int websSetSessionVar(Webs *wp, char *key, char *value)
  2886. {
  2887. WebsSession *sp;
  2888. assert(wp);
  2889. assert(key && *key);
  2890. assert(value);
  2891. if ((sp = websGetSession(wp, 1)) == 0) {
  2892. return 0;
  2893. }
  2894. if (hashEnter(sp->cache, key, valueString(value, VALUE_ALLOCATE), 0) == 0) {
  2895. return -1;
  2896. }
  2897. return 0;
  2898. }
  2899. static void pruneSessions()
  2900. {
  2901. WebsSession *sp;
  2902. WebsTime when;
  2903. WebsKey *sym, *next;
  2904. int oldCount;
  2905. if (sessions >= 0) {
  2906. oldCount = sessionCount;
  2907. when = time(0);
  2908. for (sym = hashFirst(sessions); sym; sym = next) {
  2909. next = hashNext(sessions, sym);
  2910. sp = (WebsSession*) sym->content.value.symbol;
  2911. if (sp->expires <= when) {
  2912. hashDelete(sessions, sp->id);
  2913. sessionCount--;
  2914. freeSession(sp);
  2915. }
  2916. }
  2917. if (oldCount != sessionCount || sessionCount) {
  2918. trace(4, "Prune %d sessions. Remaining: %d", oldCount - sessionCount, sessionCount);
  2919. }
  2920. }
  2921. websRestartEvent(pruneId, WEBS_SESSION_PRUNE);
  2922. }
  2923. static void freeSessions()
  2924. {
  2925. WebsSession *sp;
  2926. WebsKey *sym, *next;
  2927. if (sessions >= 0) {
  2928. for (sym = hashFirst(sessions); sym; sym = next) {
  2929. next = hashNext(sessions, sym);
  2930. sp = (WebsSession*) sym->content.value.symbol;
  2931. hashDelete(sessions, sp->id);
  2932. freeSession(sp);
  2933. }
  2934. hashFree(sessions);
  2935. sessions = -1;
  2936. }
  2937. }
  2938. /*
  2939. One line embedding
  2940. */
  2941. PUBLIC int websServer(char *endpoint, char *documents)
  2942. {
  2943. int finished = 0;
  2944. if (websOpen(documents, "route.txt") < 0) {
  2945. error("Cannot initialize server. Exiting.");
  2946. return -1;
  2947. }
  2948. if (websLoad("auth.txt") < 0) {
  2949. error("Cannot load auth.txt");
  2950. return -1;
  2951. }
  2952. if (websListen(endpoint) < 0) {
  2953. return -1;
  2954. }
  2955. websServiceEvents(&finished);
  2956. websClose();
  2957. return 0;
  2958. }
  2959. static void setFileLimits()
  2960. {
  2961. #if ME_UNIX_LIKE
  2962. struct rlimit r;
  2963. int i, limit;
  2964. limit = ME_GOAHEAD_LIMIT_FILES;
  2965. if (limit == 0) {
  2966. /*
  2967. We need to determine a reasonable maximum possible limit value.
  2968. There is no #define we can use for this, so we test to determine it empirically
  2969. */
  2970. for (limit = 0x40000000; limit > 0; limit >>= 1) {
  2971. r.rlim_cur = r.rlim_max = limit;
  2972. if (setrlimit(RLIMIT_NOFILE, &r) == 0) {
  2973. for (i = (limit >> 4) * 15; i > 0; i--) {
  2974. r.rlim_max = r.rlim_cur = limit + i;
  2975. if (setrlimit(RLIMIT_NOFILE, &r) == 0) {
  2976. limit = 0;
  2977. break;
  2978. }
  2979. }
  2980. break;
  2981. }
  2982. }
  2983. } else {
  2984. r.rlim_cur = r.rlim_max = limit;
  2985. if (setrlimit(RLIMIT_NOFILE, &r) < 0) {
  2986. error("Cannot set file limit to %d", limit);
  2987. }
  2988. }
  2989. getrlimit(RLIMIT_NOFILE, &r);
  2990. trace(6, "Max files soft %d, max %d", r.rlim_cur, r.rlim_max);
  2991. #endif
  2992. }
  2993. /*
  2994. Output an error message and cleanup
  2995. */
  2996. PUBLIC void websError(Webs *wp, int code, char *fmt, ...)
  2997. {
  2998. va_list args;
  2999. char *msg, *buf;
  3000. char *encoded;
  3001. int status;
  3002. assert(wp);
  3003. wp->error++;
  3004. if (code & WEBS_CLOSE) {
  3005. wp->flags &= ~WEBS_KEEP_ALIVE;
  3006. wp->connError++;
  3007. }
  3008. status = code & WEBS_CODE_MASK;
  3009. #if !ME_ROM
  3010. if (wp->putfd >= 0) {
  3011. close(wp->putfd);
  3012. wp->putfd = -1;
  3013. }
  3014. #endif
  3015. if (wp->rxRemaining && status != 200 && status != 301 && status != 302 && status != 401) {
  3016. /* Close connection so we don't have to consume remaining content */
  3017. wp->flags &= ~WEBS_KEEP_ALIVE;
  3018. }
  3019. encoded = websEscapeHtml(wp->url);
  3020. wfree(wp->url);
  3021. wp->url = encoded;
  3022. if (fmt) {
  3023. if (!(code & WEBS_NOLOG)) {
  3024. va_start(args, fmt);
  3025. msg = sfmtv(fmt, args);
  3026. va_end(args);
  3027. trace(2, "%s", msg);
  3028. wfree(msg);
  3029. }
  3030. buf = sfmt("\
  3031. <html>\r\n\
  3032. <head><title>Document Error: %s</title></head>\r\n\
  3033. <body>\r\n\
  3034. <h2>Access Error: %s</h2>\r\n\
  3035. </body>\r\n\
  3036. </html>\r\n", websErrorMsg(code), websErrorMsg(code));
  3037. } else {
  3038. buf = 0;
  3039. }
  3040. websResponse(wp, code, buf);
  3041. wfree(buf);
  3042. }
  3043. /*
  3044. Return the error message for a given code
  3045. */
  3046. PUBLIC char *websErrorMsg(int code)
  3047. {
  3048. WebsError *ep;
  3049. assert(code >= 0);
  3050. code &= WEBS_CODE_MASK;
  3051. for (ep = websErrors; ep->code; ep++) {
  3052. if (code == ep->code) {
  3053. return ep->msg;
  3054. }
  3055. }
  3056. return websErrorMsg(HTTP_CODE_INTERNAL_SERVER_ERROR);
  3057. }
  3058. /*
  3059. Accessors
  3060. */
  3061. PUBLIC char *websGetCookie(Webs *wp) { return wp->cookie; }
  3062. PUBLIC char *websGetDir(Webs *wp) { return wp->route && wp->route->dir ? wp->route->dir : websGetDocuments(); }
  3063. PUBLIC int websGetEof(Webs *wp) { return wp->eof; }
  3064. PUBLIC char *websGetExt(Webs *wp) { return wp->ext; }
  3065. PUBLIC char *websGetFilename(Webs *wp) { return wp->filename; }
  3066. PUBLIC char *websGetHost(Webs *wp) { return wp->host; }
  3067. PUBLIC char *websGetIfaddr(Webs *wp) { return wp->ifaddr; }
  3068. PUBLIC char *websGetIpaddr(Webs *wp) { return wp->ipaddr; }
  3069. PUBLIC char *websGetMethod(Webs *wp) { return wp->method; }
  3070. PUBLIC char *websGetPassword(Webs *wp) { return wp->password; }
  3071. PUBLIC char *websGetPath(Webs *wp) { return wp->path; }
  3072. PUBLIC int websGetPort(Webs *wp) { return wp->port; }
  3073. PUBLIC char *websGetProtocol(Webs *wp) { return wp->protocol; }
  3074. PUBLIC char *websGetQuery(Webs *wp) { return wp->query; }
  3075. PUBLIC char *websGetServer() { return websHost; }
  3076. PUBLIC char *websGetServerAddress() { return websIpAddr; }
  3077. PUBLIC char *websGetServerAddressUrl() { return websIpAddrUrl; }
  3078. PUBLIC char *websGetServerUrl() { return websHostUrl; }
  3079. PUBLIC char *websGetUrl(Webs *wp) { return wp->url; }
  3080. PUBLIC char *websGetUserAgent(Webs *wp) { return wp->userAgent; }
  3081. PUBLIC char *websGetUsername(Webs *wp) { return wp->username; }
  3082. /*
  3083. Copyright (c) Embedthis Software. All Rights Reserved.
  3084. This software is distributed under commercial and open source licenses.
  3085. You may use the Embedthis GoAhead open source license or you may acquire
  3086. a commercial license from Embedthis Software. You agree to be fully bound
  3087. by the terms of either license. Consult the LICENSE.md distributed with
  3088. this software for full details and other copyrights.
  3089. */