unit_test.c 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651
  1. #include "mongoose.h"
  2. #include "float.h" // For DBL_EPSILON and HUGE_VAL
  3. #include "math.h"
  4. static int s_num_tests = 0;
  5. #define ASSERT(expr) \
  6. do { \
  7. s_num_tests++; \
  8. if (!(expr)) { \
  9. printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
  10. abort(); \
  11. } \
  12. } while (0)
  13. #define FETCH_BUF_SIZE (256 * 1024)
  14. // Important: we use different port numbers for the Windows bug workaround. See
  15. // https://support.microsoft.com/en-ae/help/3039044/error-10013-wsaeacces-is-returned-when-a-second-bind-to-a-excluded-por
  16. static void test_globmatch(void) {
  17. ASSERT(mg_globmatch("", 0, "", 0) == 1);
  18. ASSERT(mg_globmatch("*", 1, "a", 1) == 1);
  19. ASSERT(mg_globmatch("*", 1, "ab", 2) == 1);
  20. ASSERT(mg_globmatch("", 0, "a", 1) == 0);
  21. ASSERT(mg_globmatch("/", 1, "/foo", 4) == 0);
  22. ASSERT(mg_globmatch("/*/foo", 6, "/x/bar", 6) == 0);
  23. ASSERT(mg_globmatch("/*/foo", 6, "/x/foo", 6) == 1);
  24. ASSERT(mg_globmatch("/*/foo", 6, "/x/foox", 7) == 0);
  25. ASSERT(mg_globmatch("/*/foo*", 7, "/x/foox", 7) == 1);
  26. ASSERT(mg_globmatch("/*", 2, "/abc", 4) == 1);
  27. ASSERT(mg_globmatch("/*", 2, "/ab/", 4) == 0);
  28. ASSERT(mg_globmatch("/*", 2, "/", 1) == 1);
  29. ASSERT(mg_globmatch("/x/*", 4, "/x/2", 4) == 1);
  30. ASSERT(mg_globmatch("/x/*", 4, "/x/2/foo", 8) == 0);
  31. ASSERT(mg_globmatch("/x/*/*", 6, "/x/2/foo", 8) == 1);
  32. ASSERT(mg_globmatch("#", 1, "///", 3) == 1);
  33. ASSERT(mg_globmatch("/api/*", 6, "/api/foo", 8) == 1);
  34. ASSERT(mg_globmatch("/api/*", 6, "/api/log/static", 15) == 0);
  35. ASSERT(mg_globmatch("/api/#", 6, "/api/log/static", 15) == 1);
  36. ASSERT(mg_globmatch("#.shtml", 7, "/ssi/index.shtml", 16) == 1);
  37. ASSERT(mg_globmatch("#.c", 3, ".c", 2) == 1);
  38. ASSERT(mg_globmatch("abc", 3, "ab", 2) == 0);
  39. ASSERT(mg_globmatch("#.c", 3, "a.c", 3) == 1);
  40. ASSERT(mg_globmatch("#.c", 3, "..c", 3) == 1);
  41. ASSERT(mg_globmatch("#.c", 3, "/.c", 3) == 1);
  42. ASSERT(mg_globmatch("#.c", 3, "//a.c", 5) == 1);
  43. ASSERT(mg_globmatch("#.c", 3, "x/a.c", 5) == 1);
  44. ASSERT(mg_globmatch("#.c", 3, "./a.c", 5) == 1);
  45. ASSERT(mg_globmatch("#.shtml", 7, "./ssi/index.shtml", 17) == 1);
  46. ASSERT(mg_globmatch("#aa#bb#", 7, "caabba", 6) == 1);
  47. ASSERT(mg_globmatch("#aa#bb#", 7, "caabxa", 6) == 0);
  48. ASSERT(mg_globmatch("a*b*c", 5, "a__b_c", 6) == 1);
  49. {
  50. struct mg_str caps[3];
  51. ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
  52. ASSERT(mg_match(mg_str("a"), mg_str("#"), caps) == true);
  53. ASSERT(mg_strcmp(caps[0], mg_str("a")) == 0);
  54. ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), caps) == true);
  55. ASSERT(mg_match(mg_str("a_b_c_"), mg_str("a*b*c"), caps) == false);
  56. ASSERT(mg_match(mg_str("a__b_c"), mg_str("a*b*c"), caps) == true);
  57. ASSERT(mg_strcmp(caps[0], mg_str("__")) == 0);
  58. ASSERT(mg_strcmp(caps[1], mg_str("_")) == 0);
  59. ASSERT(mg_match(mg_str("a_b_c__c"), mg_str("a*b*c"), caps) == true);
  60. ASSERT(mg_strcmp(caps[0], mg_str("_")) == 0);
  61. ASSERT(mg_strcmp(caps[1], mg_str("_c__")) == 0);
  62. ASSERT(mg_match(mg_str("a_xb_.c__c"), mg_str("a*b*c"), caps) == true);
  63. ASSERT(mg_strcmp(caps[0], mg_str("_x")) == 0);
  64. ASSERT(mg_strcmp(caps[1], mg_str("_.c__")) == 0);
  65. ASSERT(mg_match(mg_str("a"), mg_str("#a"), caps) == true);
  66. ASSERT(mg_strcmp(caps[0], mg_str("")) == 0);
  67. ASSERT(mg_match(mg_str(".aa..b...b"), mg_str("#a#b"), caps) == true);
  68. ASSERT(mg_strcmp(caps[0], mg_str(".")) == 0);
  69. ASSERT(mg_strcmp(caps[1], mg_str("a..b...")) == 0);
  70. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  71. ASSERT(mg_match(mg_str("/foo/bar"), mg_str("/*/*"), caps) == true);
  72. ASSERT(mg_strcmp(caps[0], mg_str("foo")) == 0);
  73. ASSERT(mg_strcmp(caps[1], mg_str("bar")) == 0);
  74. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  75. ASSERT(mg_match(mg_str("/foo/"), mg_str("/*/*"), caps) == true);
  76. ASSERT(mg_strcmp(caps[0], mg_str("foo")) == 0);
  77. ASSERT(mg_strcmp(caps[1], mg_str("")) == 0);
  78. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  79. ASSERT(mg_match(mg_str("abc"), mg_str("?#"), caps) == true);
  80. ASSERT(mg_strcmp(caps[0], mg_str("a")) == 0);
  81. ASSERT(mg_strcmp(caps[1], mg_str("bc")) == 0);
  82. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  83. }
  84. }
  85. static void test_commalist(void) {
  86. struct mg_str k, v, s1 = mg_str(""), s2 = mg_str("a"), s3 = mg_str("a,b");
  87. struct mg_str s4 = mg_str("a=123"), s5 = mg_str("a,b=123");
  88. ASSERT(mg_commalist(&s1, &k, &v) == false);
  89. ASSERT(mg_commalist(&s2, &k, &v) == true);
  90. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  91. ASSERT(mg_commalist(&s2, &k, &v) == false);
  92. ASSERT(mg_commalist(&s3, &k, &v) == true);
  93. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  94. ASSERT(mg_commalist(&s3, &k, &v) == true);
  95. ASSERT(v.len == 0 && mg_vcmp(&k, "b") == 0);
  96. ASSERT(mg_commalist(&s3, &k, &v) == false);
  97. ASSERT(mg_commalist(&s4, &k, &v) == true);
  98. ASSERT(mg_vcmp(&k, "a") == 0 && mg_vcmp(&v, "123") == 0);
  99. ASSERT(mg_commalist(&s4, &k, &v) == false);
  100. ASSERT(mg_commalist(&s4, &k, &v) == false);
  101. ASSERT(mg_commalist(&s5, &k, &v) == true);
  102. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  103. ASSERT(mg_commalist(&s5, &k, &v) == true);
  104. ASSERT(mg_vcmp(&k, "b") == 0 && mg_vcmp(&v, "123") == 0);
  105. ASSERT(mg_commalist(&s4, &k, &v) == false);
  106. }
  107. static void test_http_get_var(void) {
  108. char buf[256];
  109. struct mg_str body;
  110. body = mg_str("key1=value1&key2=value2&key3=value%203&key4=value+4");
  111. ASSERT(mg_http_get_var(&body, "key1", buf, sizeof(buf)) == 6);
  112. ASSERT(strcmp(buf, "value1") == 0);
  113. ASSERT(mg_http_get_var(&body, "KEY1", buf, sizeof(buf)) == 6);
  114. ASSERT(strcmp(buf, "value1") == 0);
  115. ASSERT(mg_http_get_var(&body, "key2", buf, sizeof(buf)) == 6);
  116. ASSERT(strcmp(buf, "value2") == 0);
  117. ASSERT(mg_http_get_var(&body, "key3", buf, sizeof(buf)) == 7);
  118. ASSERT(strcmp(buf, "value 3") == 0);
  119. ASSERT(mg_http_get_var(&body, "key4", buf, sizeof(buf)) == 7);
  120. ASSERT(strcmp(buf, "value 4") == 0);
  121. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -4);
  122. ASSERT(mg_http_get_var(&body, "key1", NULL, sizeof(buf)) == -2);
  123. ASSERT(mg_http_get_var(&body, "key1", buf, 0) == -2);
  124. ASSERT(mg_http_get_var(&body, NULL, buf, sizeof(buf)) == -1);
  125. ASSERT(mg_http_get_var(&body, "key1", buf, 1) == -3);
  126. body = mg_str("key=broken%2");
  127. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  128. body = mg_str("key=broken%2x");
  129. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  130. ASSERT(mg_http_get_var(&body, "inexistent", buf, sizeof(buf)) == -4);
  131. body = mg_str("key=%");
  132. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  133. body = mg_str("&&&kEy=%");
  134. ASSERT(mg_http_get_var(&body, "kEy", buf, sizeof(buf)) == -3);
  135. }
  136. static int vcmp(struct mg_str s1, const char *s2) {
  137. // MG_INFO(("->%.*s<->%s<- %d %d %d", (int) s1.len, s1.ptr, s2,
  138. //(int) s1.len, strncmp(s1.ptr, s2, s1.len), mg_vcmp(&s1, s2)));
  139. return mg_vcmp(&s1, s2) == 0;
  140. }
  141. static void test_url(void) {
  142. // Host
  143. ASSERT(vcmp(mg_url_host("foo"), "foo"));
  144. ASSERT(vcmp(mg_url_host("//foo"), "foo"));
  145. ASSERT(vcmp(mg_url_host("foo:1234"), "foo"));
  146. ASSERT(vcmp(mg_url_host(":1234"), ""));
  147. ASSERT(vcmp(mg_url_host("//foo:1234"), "foo"));
  148. ASSERT(vcmp(mg_url_host("p://foo"), "foo"));
  149. ASSERT(vcmp(mg_url_host("p://foo/"), "foo"));
  150. ASSERT(vcmp(mg_url_host("p://foo/x"), "foo"));
  151. ASSERT(vcmp(mg_url_host("p://foo/x/"), "foo"));
  152. ASSERT(vcmp(mg_url_host("p://foo/x//"), "foo"));
  153. ASSERT(vcmp(mg_url_host("p://foo//x"), "foo"));
  154. ASSERT(vcmp(mg_url_host("p://foo///x"), "foo"));
  155. ASSERT(vcmp(mg_url_host("p://foo///x//"), "foo"));
  156. ASSERT(vcmp(mg_url_host("p://bar:1234"), "bar"));
  157. ASSERT(vcmp(mg_url_host("p://bar:1234/"), "bar"));
  158. ASSERT(vcmp(mg_url_host("p://bar:1234/a"), "bar"));
  159. ASSERT(vcmp(mg_url_host("p://u@bar:1234/a"), "bar"));
  160. ASSERT(vcmp(mg_url_host("p://u:p@bar:1234/a"), "bar"));
  161. ASSERT(vcmp(mg_url_host("p://u:p@[::1]:1234/a"), "[::1]"));
  162. ASSERT(vcmp(mg_url_host("p://u:p@[1:2::3]:1234/a"), "[1:2::3]"));
  163. ASSERT(vcmp(mg_url_host("p://foo/x:y/z"), "foo"));
  164. // Port
  165. ASSERT(mg_url_port("foo:1234") == 1234);
  166. ASSERT(mg_url_port(":1234") == 1234);
  167. ASSERT(mg_url_port("x://foo:1234") == 1234);
  168. ASSERT(mg_url_port("x://foo:1234/") == 1234);
  169. ASSERT(mg_url_port("x://foo:1234/xx") == 1234);
  170. ASSERT(mg_url_port("x://foo:1234") == 1234);
  171. ASSERT(mg_url_port("p://bar:1234/a") == 1234);
  172. ASSERT(mg_url_port("p://bar:1234/a:b") == 1234);
  173. ASSERT(mg_url_port("http://bar") == 80);
  174. ASSERT(mg_url_port("http://localhost:1234") == 1234);
  175. ASSERT(mg_url_port("https://bar") == 443);
  176. ASSERT(mg_url_port("wss://bar") == 443);
  177. ASSERT(mg_url_port("wss://u:p@bar") == 443);
  178. ASSERT(mg_url_port("wss://u:p@bar:123") == 123);
  179. ASSERT(mg_url_port("wss://u:p@bar:123/") == 123);
  180. ASSERT(mg_url_port("wss://u:p@bar:123/abc") == 123);
  181. ASSERT(mg_url_port("http://u:p@[::1]/abc") == 80);
  182. ASSERT(mg_url_port("http://u:p@[::1]:2121/abc") == 2121);
  183. ASSERT(mg_url_port("http://u:p@[::1]:2121/abc/cd:ef") == 2121);
  184. // User / pass
  185. ASSERT(vcmp(mg_url_user("p://foo"), ""));
  186. ASSERT(vcmp(mg_url_pass("p://foo"), ""));
  187. ASSERT(vcmp(mg_url_user("p://:@foo"), ""));
  188. ASSERT(vcmp(mg_url_pass("p://:@foo"), ""));
  189. ASSERT(vcmp(mg_url_user("p://u@foo"), "u"));
  190. ASSERT(vcmp(mg_url_pass("p://u@foo"), ""));
  191. ASSERT(vcmp(mg_url_user("p://u:@foo"), "u"));
  192. ASSERT(vcmp(mg_url_pass("p://u:@foo"), ""));
  193. ASSERT(vcmp(mg_url_user("p://:p@foo"), ""));
  194. ASSERT(vcmp(mg_url_pass("p://:p@foo"), "p"));
  195. ASSERT(vcmp(mg_url_user("p://u:p@foo"), "u"));
  196. ASSERT(vcmp(mg_url_pass("p://u:p@foo"), "p"));
  197. ASSERT(vcmp(mg_url_pass("p://u:p@foo//a@b"), "p"));
  198. ASSERT(vcmp(mg_url_user("p://foo/q?mail=a@b.c"), ""));
  199. ASSERT(vcmp(mg_url_pass("p://foo/q?mail=a@b.c"), ""));
  200. // URI
  201. ASSERT(strcmp(mg_url_uri("p://foo"), "/") == 0);
  202. ASSERT(strcmp(mg_url_uri("p://foo/"), "/") == 0);
  203. ASSERT(strcmp(mg_url_uri("p://foo:12/"), "/") == 0);
  204. ASSERT(strcmp(mg_url_uri("p://foo:12/abc"), "/abc") == 0);
  205. ASSERT(strcmp(mg_url_uri("p://foo:12/a/b/c"), "/a/b/c") == 0);
  206. ASSERT(strcmp(mg_url_uri("p://[::1]:12/a/b/c"), "/a/b/c") == 0);
  207. ASSERT(strcmp(mg_url_uri("p://[ab::1]:12/a/b/c"), "/a/b/c") == 0);
  208. ASSERT(strcmp(mg_url_uri("p://foo/q?mail=a@b.c"), "/q?mail=a@b.c") == 0);
  209. }
  210. static void test_base64(void) {
  211. char buf[128];
  212. ASSERT(mg_base64_encode((uint8_t *) "", 0, buf) == 0);
  213. ASSERT(strcmp(buf, "") == 0);
  214. ASSERT(mg_base64_encode((uint8_t *) "x", 1, buf) == 4);
  215. ASSERT(strcmp(buf, "eA==") == 0);
  216. ASSERT(mg_base64_encode((uint8_t *) "xyz", 3, buf) == 4);
  217. ASSERT(strcmp(buf, "eHl6") == 0);
  218. ASSERT(mg_base64_encode((uint8_t *) "abcdef", 6, buf) == 8);
  219. ASSERT(strcmp(buf, "YWJjZGVm") == 0);
  220. ASSERT(mg_base64_encode((uint8_t *) "ы", 2, buf) == 4);
  221. ASSERT(strcmp(buf, "0Ys=") == 0);
  222. ASSERT(mg_base64_encode((uint8_t *) "xy", 3, buf) == 4);
  223. ASSERT(strcmp(buf, "eHkA") == 0);
  224. ASSERT(mg_base64_encode((uint8_t *) "test", 4, buf) == 8);
  225. ASSERT(strcmp(buf, "dGVzdA==") == 0);
  226. ASSERT(mg_base64_encode((uint8_t *) "abcde", 5, buf) == 8);
  227. ASSERT(strcmp(buf, "YWJjZGU=") == 0);
  228. ASSERT(mg_base64_decode("кю", 4, buf) == 0);
  229. ASSERT(mg_base64_decode("A", 1, buf) == 0);
  230. ASSERT(mg_base64_decode("A=", 2, buf) == 0);
  231. ASSERT(mg_base64_decode("AA=", 3, buf) == 0);
  232. ASSERT(mg_base64_decode("AAA=", 4, buf) == 2);
  233. ASSERT(mg_base64_decode("AAAA====", 8, buf) == 0);
  234. ASSERT(mg_base64_decode("AAAA----", 8, buf) == 0);
  235. ASSERT(mg_base64_decode("Q2VzYW50YQ==", 12, buf) == 7);
  236. ASSERT(strcmp(buf, "Cesanta") == 0);
  237. }
  238. static void test_iobuf(void) {
  239. struct mg_iobuf io = {0, 0, 0, 10};
  240. ASSERT(io.buf == NULL && io.size == 0 && io.len == 0);
  241. mg_iobuf_resize(&io, 1);
  242. ASSERT(io.buf != NULL && io.size == 10 && io.len == 0);
  243. ASSERT(memcmp(io.buf, "\x00", 1) == 0);
  244. mg_iobuf_add(&io, 3, "hi", 2);
  245. ASSERT(io.buf != NULL && io.size == 10 && io.len == 5);
  246. ASSERT(memcmp(io.buf, "\x00\x00\x00hi", 5) == 0);
  247. mg_iobuf_add(&io, io.len, "!", 1);
  248. ASSERT(io.buf != NULL && io.size == 10 && io.len == 6);
  249. ASSERT(memcmp(io.buf, "\x00\x00\x00hi!", 6) == 0);
  250. mg_iobuf_add(&io, 0, "x", 1);
  251. ASSERT(memcmp(io.buf, "x\x00\x00\x00hi!", 7) == 0);
  252. ASSERT(io.buf != NULL && io.size == 10 && io.len == 7);
  253. mg_iobuf_del(&io, 1, 3);
  254. ASSERT(io.buf != NULL && io.size == 10 && io.len == 4);
  255. ASSERT(memcmp(io.buf, "xhi!", 3) == 0);
  256. mg_iobuf_del(&io, 10, 100);
  257. ASSERT(io.buf != NULL && io.size == 10 && io.len == 4);
  258. ASSERT(memcmp(io.buf, "xhi!", 3) == 0);
  259. free(io.buf);
  260. }
  261. static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
  262. if (ev == MG_EV_SNTP_TIME) {
  263. int64_t received = *(int64_t *) evd;
  264. *(int64_t *) fnd = received;
  265. MG_DEBUG(("got time: %lld", received));
  266. #if MG_ARCH == MG_ARCH_UNIX
  267. struct timeval tv = {0, 0};
  268. gettimeofday(&tv, 0);
  269. int64_t ms = (int64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
  270. int64_t diff = ms > received ? ms - received : received - ms;
  271. MG_DEBUG(("diff: %lld", diff));
  272. // ASSERT(diff < 100);
  273. #endif
  274. } else if (ev == MG_EV_OPEN) {
  275. c->is_hexdumping = 1;
  276. }
  277. (void) c;
  278. }
  279. static void test_sntp_server(const char *url) {
  280. int64_t ms = 0;
  281. struct mg_mgr mgr;
  282. struct mg_connection *c = NULL;
  283. int i;
  284. mg_mgr_init(&mgr);
  285. c = mg_sntp_connect(&mgr, url, sntp_cb, &ms);
  286. ASSERT(c != NULL);
  287. ASSERT(c->is_udp == 1);
  288. for (i = 0; i < 60 && ms == 0; i++) mg_mgr_poll(&mgr, 50);
  289. MG_DEBUG(("server: %s, ms: %lld", url ? url : "(default)", ms));
  290. ASSERT(ms > 0);
  291. mg_mgr_free(&mgr);
  292. }
  293. static void test_sntp(void) {
  294. const unsigned char bad[] =
  295. "\x55\x02\x00\xeb\x00\x00\x00\x1e\x00\x00\x07\xb6\x3e\xc9\xd6\xa2"
  296. "\xdb\xde\xea\x30\x91\x86\xb7\x10\xdb\xde\xed\x98\x00\x00\x00\xde"
  297. "\xdb\xde\xed\x99\x0a\xe2\xc7\x96\xdb\xde\xed\x99\x0a\xe4\x6b\xda";
  298. ASSERT(mg_sntp_parse(bad, sizeof(bad)) < 0);
  299. ASSERT(mg_sntp_parse(NULL, 0) == -1);
  300. test_sntp_server("udp://time.windows.com:123");
  301. // NOTE(cpq): temporarily disabled until Github Actions fix their NTP
  302. // port blockage issue, https://github.com/actions/runner-images/issues/5615
  303. // test_sntp_server("udp://time.apple.com:123");
  304. // test_sntp_server(NULL);
  305. }
  306. struct mqtt_data {
  307. char *buf;
  308. int subscribed;
  309. int published;
  310. };
  311. static void mqtt_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
  312. struct mqtt_data *test_data = (struct mqtt_data *) fnd;
  313. char *buf = test_data->buf;
  314. if (ev == MG_EV_MQTT_OPEN) {
  315. buf[0] = *(int *) evd == 0 ? 'X' : 'Y';
  316. } else if (ev == MG_EV_MQTT_CMD) {
  317. struct mg_mqtt_message *mm = (struct mg_mqtt_message *) evd;
  318. if (mm->cmd == MQTT_CMD_SUBACK) {
  319. test_data->subscribed = 1;
  320. }
  321. if (mm->cmd == MQTT_CMD_PUBACK) {
  322. test_data->published = 1;
  323. }
  324. } else if (ev == MG_EV_MQTT_MSG) {
  325. struct mg_mqtt_message *mm = (struct mg_mqtt_message *) evd;
  326. sprintf(buf + 1, "%.*s/%.*s", (int) mm->topic.len, mm->topic.ptr,
  327. (int) mm->data.len, mm->data.ptr);
  328. }
  329. (void) c;
  330. }
  331. static void test_mqtt_ver(uint8_t mqtt_version) {
  332. char buf[50] = {0}, client_id[16], will_topic[16];
  333. struct mqtt_data test_data = {buf, 0, 0};
  334. struct mg_mgr mgr;
  335. struct mg_str topic = mg_str("x/f12"), data = mg_str("hi");
  336. struct mg_connection *c;
  337. struct mg_mqtt_opts opts;
  338. const char *url = "mqtt://broker.hivemq.com:1883";
  339. int i;
  340. mg_mgr_init(&mgr);
  341. // Connect with empty client ID
  342. c = mg_mqtt_connect(&mgr, url, NULL, mqtt_cb, &test_data);
  343. for (i = 0; i < 300 && buf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
  344. if (buf[0] != 'X') MG_INFO(("[%s]", buf));
  345. ASSERT(buf[0] == 'X');
  346. ASSERT(test_data.subscribed == 0);
  347. mg_mqtt_sub(c, topic, 1);
  348. for (i = 0; i < 500 && test_data.subscribed == 0; i++) mg_mgr_poll(&mgr, 10);
  349. ASSERT(test_data.subscribed == 1);
  350. ASSERT(test_data.published == 0);
  351. mg_mqtt_pub(c, topic, data, 1, false);
  352. for (i = 0; i < 500 && test_data.published == 0; i++) mg_mgr_poll(&mgr, 10);
  353. ASSERT(test_data.published == 1);
  354. for (i = 0; i < 500 && buf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  355. if (strcmp(buf, "Xx/f12/hi") != 0) MG_INFO(("[%s]", buf));
  356. ASSERT(strcmp(buf, "Xx/f12/hi") == 0);
  357. // Set params
  358. test_data.subscribed = 0;
  359. test_data.published = 0;
  360. memset(buf, 0, sizeof(buf));
  361. memset(&opts, 0, sizeof(opts));
  362. opts.clean = true;
  363. opts.will_qos = 1;
  364. opts.will_retain = true;
  365. opts.keepalive = 20;
  366. opts.version = mqtt_version;
  367. opts.will_topic = mg_str(mg_random_str(will_topic, sizeof(will_topic)));
  368. opts.will_message = mg_str("mg_will_messsage");
  369. opts.client_id = mg_str(mg_random_str(client_id, sizeof(client_id)));
  370. c = mg_mqtt_connect(&mgr, url, &opts, mqtt_cb, &test_data);
  371. for (i = 0; i < 300 && buf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
  372. if (buf[0] != 'X') MG_INFO(("[%s]", buf));
  373. ASSERT(buf[0] == 'X');
  374. ASSERT(test_data.subscribed == 0);
  375. mg_mqtt_sub(c, topic, 1);
  376. for (i = 0; i < 500 && test_data.subscribed == 0; i++) mg_mgr_poll(&mgr, 10);
  377. ASSERT(test_data.subscribed == 1);
  378. ASSERT(test_data.published == 0);
  379. mg_mqtt_pub(c, topic, data, 1, false);
  380. for (i = 0; i < 500 && test_data.published == 0; i++) mg_mgr_poll(&mgr, 10);
  381. ASSERT(test_data.published == 1);
  382. for (i = 0; i < 500 && buf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  383. if (strcmp(buf, "Xx/f12/hi") != 0) MG_INFO(("[%s]", buf));
  384. ASSERT(strcmp(buf, "Xx/f12/hi") == 0);
  385. mg_mgr_free(&mgr);
  386. ASSERT(mgr.conns == NULL);
  387. }
  388. static void test_mqtt(void) {
  389. test_mqtt_ver(5);
  390. test_mqtt_ver(4);
  391. }
  392. static void eh1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  393. struct mg_tls_opts *topts = (struct mg_tls_opts *) fn_data;
  394. if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
  395. if (ev == MG_EV_HTTP_MSG) {
  396. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  397. MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr,
  398. (int) hm->uri.len, hm->uri.ptr, (int) hm->message.len));
  399. if (mg_http_match_uri(hm, "/foo/*")) {
  400. mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.ptr + 5);
  401. } else if (mg_http_match_uri(hm, "/ws")) {
  402. mg_ws_upgrade(c, hm, NULL);
  403. } else if (mg_http_match_uri(hm, "/body")) {
  404. mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.ptr);
  405. } else if (mg_http_match_uri(hm, "/bar")) {
  406. mg_http_reply(c, 404, "", "not found");
  407. } else if (mg_http_match_uri(hm, "/no_reason")) {
  408. mg_printf(c, "%s", "HTTP/1.0 200\r\nContent-Length: 2\r\n\r\nok");
  409. } else if (mg_http_match_uri(hm, "/badroot")) {
  410. struct mg_http_serve_opts sopts;
  411. memset(&sopts, 0, sizeof(sopts));
  412. sopts.root_dir = "/BAAADDD!";
  413. mg_http_serve_dir(c, hm, &sopts);
  414. } else if (mg_http_match_uri(hm, "/creds")) {
  415. char user[100], pass[100];
  416. mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
  417. mg_http_reply(c, 200, "", "[%s]:[%s]", user, pass);
  418. } else if (mg_http_match_uri(hm, "/upload")) {
  419. char path[80], name[64];
  420. mg_http_get_var(&hm->query, "name", name, sizeof(name));
  421. if (name[0] == '\0') {
  422. mg_http_reply(c, 400, "", "%s", "name required");
  423. } else {
  424. mg_snprintf(path, sizeof(path), "./%s", name);
  425. mg_http_upload(c, hm, &mg_fs_posix, mg_remove_double_dots(path), 99999);
  426. c->is_hexdumping = 1;
  427. }
  428. } else if (mg_http_match_uri(hm, "/test/")) {
  429. struct mg_http_serve_opts sopts;
  430. memset(&sopts, 0, sizeof(sopts));
  431. sopts.root_dir = ".";
  432. sopts.extra_headers = "A: B\r\nC: D\r\n";
  433. mg_http_serve_dir(c, hm, &sopts);
  434. } else if (mg_http_match_uri(hm, "/servefile")) {
  435. struct mg_http_serve_opts sopts;
  436. memset(&sopts, 0, sizeof(sopts));
  437. sopts.mime_types = "foo=a/b,txt=c/d";
  438. mg_http_serve_file(c, hm, "test/data/a.txt", &sopts);
  439. } else {
  440. struct mg_http_serve_opts sopts;
  441. memset(&sopts, 0, sizeof(sopts));
  442. sopts.root_dir = "./test/data";
  443. sopts.ssi_pattern = "#.shtml";
  444. sopts.extra_headers = "C: D\r\n";
  445. mg_http_serve_dir(c, hm, &sopts);
  446. }
  447. } else if (ev == MG_EV_WS_OPEN) {
  448. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  449. ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
  450. mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
  451. } else if (ev == MG_EV_WS_MSG) {
  452. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  453. mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_BINARY);
  454. }
  455. }
  456. struct fetch_data {
  457. char *buf;
  458. int code, closed;
  459. };
  460. static void fcb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  461. struct fetch_data *fd = (struct fetch_data *) fn_data;
  462. if (ev == MG_EV_HTTP_MSG) {
  463. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  464. snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
  465. hm->message.ptr);
  466. fd->code = atoi(hm->uri.ptr);
  467. fd->closed = 1;
  468. c->is_closing = 1;
  469. (void) c;
  470. } else if (ev == MG_EV_CLOSE) {
  471. fd->closed = 1;
  472. }
  473. }
  474. static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
  475. const char *fmt, ...) {
  476. struct fetch_data fd = {buf, 0, 0};
  477. int i;
  478. struct mg_connection *c = mg_http_connect(mgr, url, fcb, &fd);
  479. va_list ap;
  480. ASSERT(c != NULL);
  481. if (mg_url_is_ssl(url)) {
  482. struct mg_tls_opts opts;
  483. struct mg_str host = mg_url_host(url);
  484. memset(&opts, 0, sizeof(opts));
  485. opts.ca = "./test/data/ca.pem";
  486. if (strstr(url, "127.0.0.1") != NULL) {
  487. // Local connection, use self-signed certificates
  488. opts.ca = "./test/data/ss_ca.pem";
  489. opts.cert = "./test/data/ss_client.pem";
  490. } else {
  491. opts.srvname = host;
  492. }
  493. mg_tls_init(c, &opts);
  494. if (c->tls == NULL) fd.closed = 1;
  495. }
  496. // c->is_hexdumping = 1;
  497. va_start(ap, fmt);
  498. mg_vprintf(c, fmt, ap);
  499. va_end(ap);
  500. buf[0] = '\0';
  501. for (i = 0; i < 50 && buf[0] == '\0'; i++) mg_mgr_poll(mgr, 1);
  502. if (!fd.closed) c->is_closing = 1;
  503. mg_mgr_poll(mgr, 1);
  504. return fd.code;
  505. }
  506. static int cmpbody(const char *buf, const char *str) {
  507. struct mg_http_message hm;
  508. struct mg_str s = mg_str(str);
  509. size_t len = strlen(buf);
  510. mg_http_parse(buf, len, &hm);
  511. if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.ptr - buf);
  512. return mg_strcmp(hm.body, s);
  513. }
  514. static bool cmpheader(const char *buf, const char *name, const char *value) {
  515. struct mg_http_message hm;
  516. struct mg_str *h;
  517. size_t len = strlen(buf);
  518. mg_http_parse(buf, len, &hm);
  519. h = mg_http_get_header(&hm, name);
  520. return h != NULL && mg_strcmp(*h, mg_str(value)) == 0;
  521. }
  522. static void wcb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  523. int *p = (int *) fn_data;
  524. if (ev == MG_EV_WS_OPEN) {
  525. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  526. struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
  527. ASSERT(wsproto != NULL);
  528. mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%.3s", "boo!!!!");
  529. mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%s", "foobar");
  530. mg_ws_send(c, "", 0, WEBSOCKET_OP_PING);
  531. p[0] += 100;
  532. } else if (ev == MG_EV_WS_MSG) {
  533. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  534. if (mg_strstr(wm->data, mg_str("foobar")))
  535. mg_ws_send(c, "", 0, WEBSOCKET_OP_CLOSE);
  536. if (mg_strstr(wm->data, mg_str("boo"))) p[0] += 2;
  537. if (mg_strstr(wm->data, mg_str("foobar"))) p[0] += 3;
  538. } else if (ev == MG_EV_CLOSE) {
  539. p[0] += 10;
  540. }
  541. }
  542. static void ew2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  543. size_t size = 65 * 1024 + 737;
  544. if (ev == MG_EV_WS_OPEN) {
  545. char *msg = (char *) calloc(1, size + 1);
  546. memset(msg, 'A', size);
  547. mg_ws_printf(c, WEBSOCKET_OP_TEXT, "%s", msg);
  548. free(msg);
  549. } else if (ev == MG_EV_WS_MSG) {
  550. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  551. if (wm->data.len == 6) {
  552. // Ignore the "opened" message from server
  553. } else {
  554. size_t ok = 1, i;
  555. ASSERT(wm->data.len == size);
  556. for (i = 0; i < size; i++) {
  557. if (wm->data.ptr[i] != 'A') ok = 0;
  558. }
  559. ASSERT(ok == 1);
  560. *(int *) fn_data = 1;
  561. }
  562. }
  563. }
  564. static void test_ws(void) {
  565. char buf[FETCH_BUF_SIZE];
  566. const char *url = "ws://LOCALHOST:12343/ws";
  567. struct mg_mgr mgr;
  568. int i, done = 0;
  569. mg_mgr_init(&mgr);
  570. ASSERT(mg_http_listen(&mgr, url, eh1, NULL) != NULL);
  571. mg_ws_connect(&mgr, url, wcb, &done, "%s", "Sec-WebSocket-Protocol: meh\r\n");
  572. for (i = 0; i < 30; i++) mg_mgr_poll(&mgr, 1);
  573. // MG_INFO(("--> %d", done));
  574. ASSERT(done == 115);
  575. // Test that non-WS requests fail
  576. ASSERT(fetch(&mgr, buf, url, "GET /ws HTTP/1.0\r\n\n") == 426);
  577. // Test large WS frames, over 64k
  578. done = 0;
  579. mg_ws_connect(&mgr, url, ew2, &done, NULL);
  580. for (i = 0; i < 1000 && done == 0; i++) mg_mgr_poll(&mgr, 1);
  581. ASSERT(done == 1);
  582. mg_mgr_free(&mgr);
  583. ASSERT(mgr.conns == NULL);
  584. }
  585. static void eh9(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  586. if (ev == MG_EV_ERROR) {
  587. ASSERT(!strcmp((char *) ev_data, "socket error"));
  588. *(int *) fn_data = 7;
  589. }
  590. (void) c;
  591. }
  592. static void test_http_server(void) {
  593. struct mg_mgr mgr;
  594. const char *url = "http://127.0.0.1:12346";
  595. char buf[FETCH_BUF_SIZE];
  596. mg_mgr_init(&mgr);
  597. mg_http_listen(&mgr, url, eh1, NULL);
  598. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  599. ASSERT(cmpbody(buf, "hello\n") == 0);
  600. ASSERT(fetch(&mgr, buf, url, "GET /%%61.txt HTTP/1.0\n\n") == 200);
  601. ASSERT(cmpbody(buf, "hello\n") == 0);
  602. // Responses with missing reason phrase must also work
  603. ASSERT(fetch(&mgr, buf, url, "GET /no_reason HTTP/1.0\n\n") == 200);
  604. ASSERT(cmpbody(buf, "ok") == 0);
  605. // Fetch file with unicode chars in filename
  606. ASSERT(fetch(&mgr, buf, url, "GET /київ.txt HTTP/1.0\n\n") == 200);
  607. ASSERT(cmpbody(buf, "є\n") == 0);
  608. ASSERT(fetch(&mgr, buf, url, "GET /../fuzz.c HTTP/1.0\n\n") == 404);
  609. ASSERT(fetch(&mgr, buf, url, "GET /.%%2e/fuzz.c HTTP/1.0\n\n") == 404);
  610. ASSERT(fetch(&mgr, buf, url, "GET /.%%2e%%2ffuzz.c HTTP/1.0\n\n") == 404);
  611. ASSERT(fetch(&mgr, buf, url, "GET /..%%2f%%20fuzz.c HTTP/1.0\n\n") == 404);
  612. ASSERT(fetch(&mgr, buf, url, "GET /..%%2ffuzz.c%%20 HTTP/1.0\n\n") == 404);
  613. ASSERT(fetch(&mgr, buf, url, "GET /dredir HTTP/1.0\n\n") == 301);
  614. ASSERT(cmpheader(buf, "Location", "/dredir/"));
  615. ASSERT(fetch(&mgr, buf, url, "GET /dredir/ HTTP/1.0\n\n") == 200);
  616. ASSERT(cmpbody(buf, "hi\n") == 0);
  617. ASSERT(fetch(&mgr, buf, url, "GET /dredirgz/ HTTP/1.0\n\n") == 200);
  618. ASSERT(cmpheader(buf, "Content-Type", "text/html; charset=utf-8"));
  619. ASSERT(cmpheader(buf, "Content-Encoding", "gzip"));
  620. ASSERT(fetch(&mgr, buf, url, "GET /..ddot HTTP/1.0\n\n") == 301);
  621. ASSERT(fetch(&mgr, buf, url, "GET /..ddot/ HTTP/1.0\n\n") == 200);
  622. ASSERT(cmpbody(buf, "hi\n") == 0);
  623. {
  624. extern char *mg_http_etag(char *, size_t, size_t, time_t);
  625. struct mg_http_message hm;
  626. char etag[100];
  627. size_t size = 0;
  628. time_t mtime = 0;
  629. ASSERT(mg_fs_posix.st("./test/data/a.txt", &size, &mtime) != 0);
  630. ASSERT(mg_http_etag(etag, sizeof(etag), size, mtime) == etag);
  631. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nIf-None-Match: %s\n\n",
  632. etag) == 304);
  633. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  634. MG_INFO(("%s", buf));
  635. ASSERT(mg_http_get_header(&hm, "C") != NULL);
  636. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "C"), mg_str("D")) == 0);
  637. }
  638. // Text mime type override
  639. ASSERT(fetch(&mgr, buf, url, "GET /servefile HTTP/1.0\n\n") == 200);
  640. ASSERT(cmpbody(buf, "hello\n") == 0);
  641. {
  642. struct mg_http_message hm;
  643. mg_http_parse(buf, strlen(buf), &hm);
  644. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  645. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"), mg_str("c/d")) ==
  646. 0);
  647. }
  648. ASSERT(fetch(&mgr, buf, url, "GET /foo/1 HTTP/1.0\r\n\n") == 200);
  649. // MG_INFO(("%d %.*s", (int) hm.len, (int) hm.len, hm.buf));
  650. ASSERT(cmpbody(buf, "uri: 1") == 0);
  651. ASSERT(fetch(&mgr, buf, url, "%s",
  652. "POST /body HTTP/1.1\r\n"
  653. "Content-Length: 4\r\n\r\nkuku") == 200);
  654. ASSERT(cmpbody(buf, "kuku") == 0);
  655. ASSERT(fetch(&mgr, buf, url, "GET /ssi HTTP/1.1\r\n\r\n") == 301);
  656. ASSERT(fetch(&mgr, buf, url, "GET /ssi/ HTTP/1.1\r\n\r\n") == 200);
  657. ASSERT(cmpbody(buf,
  658. "this is index\n"
  659. "this is nested\n\n"
  660. "this is f1\n\n\n\n"
  661. "recurse\n\n"
  662. "recurse\n\n"
  663. "recurse\n\n"
  664. "recurse\n\n"
  665. "recurse\n\n") == 0);
  666. {
  667. struct mg_http_message hm;
  668. mg_http_parse(buf, strlen(buf), &hm);
  669. ASSERT(mg_http_get_header(&hm, "Content-Length") != NULL);
  670. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  671. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"),
  672. mg_str("text/html; charset=utf-8")) == 0);
  673. }
  674. ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 404);
  675. // ASSERT(cmpbody(buf, "Invalid web root [/BAAADDD!]\n") == 0);
  676. {
  677. char *data = mg_file_read(&mg_fs_posix, "./test/data/ca.pem", NULL);
  678. ASSERT(fetch(&mgr, buf, url, "GET /ca.pem HTTP/1.0\r\n\n") == 200);
  679. ASSERT(cmpbody(buf, data) == 0);
  680. free(data);
  681. }
  682. {
  683. // Test mime type
  684. struct mg_http_message hm;
  685. ASSERT(fetch(&mgr, buf, url, "GET /empty.js HTTP/1.0\r\n\n") == 200);
  686. mg_http_parse(buf, strlen(buf), &hm);
  687. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  688. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"),
  689. mg_str("text/javascript; charset=utf-8")) == 0);
  690. }
  691. {
  692. // Test connection refused
  693. int i, errored = 0;
  694. mg_connect(&mgr, "tcp://127.0.0.1:55117", eh9, &errored);
  695. // Give it a couple of seconds, see #1605
  696. for (i = 0; i < 200 && errored == 0; i++) mg_mgr_poll(&mgr, 10);
  697. MG_INFO(("errored: %d, expected: 7", errored));
  698. ASSERT(errored == 7);
  699. }
  700. // Directory listing
  701. fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n");
  702. ASSERT(fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n") == 200);
  703. ASSERT(mg_strstr(mg_str(buf), mg_str(">Index of /test/<")) != NULL);
  704. ASSERT(mg_strstr(mg_str(buf), mg_str(">fuzz.c<")) != NULL);
  705. {
  706. // Credentials
  707. struct mg_http_message hm;
  708. ASSERT(fetch(&mgr, buf, url, "%s",
  709. "GET /creds?access_token=x HTTP/1.0\r\n\r\n") == 200);
  710. mg_http_parse(buf, strlen(buf), &hm);
  711. ASSERT(mg_strcmp(hm.body, mg_str("[]:[x]")) == 0);
  712. ASSERT(fetch(&mgr, buf, url, "%s",
  713. "GET /creds HTTP/1.0\r\n"
  714. "Authorization: Bearer x\r\n\r\n") == 200);
  715. mg_http_parse(buf, strlen(buf), &hm);
  716. ASSERT(mg_strcmp(hm.body, mg_str("[]:[x]")) == 0);
  717. ASSERT(fetch(&mgr, buf, url, "%s",
  718. "GET /creds HTTP/1.0\r\n"
  719. "Authorization: Basic Zm9vOmJhcg==\r\n\r\n") == 200);
  720. mg_http_parse(buf, strlen(buf), &hm);
  721. ASSERT(mg_strcmp(hm.body, mg_str("[foo]:[bar]")) == 0);
  722. ASSERT(fetch(&mgr, buf, url, "%s",
  723. "GET /creds HTTP/1.0\r\n"
  724. "Cookie: blah; access_token=hello\r\n\r\n") == 200);
  725. mg_http_parse(buf, strlen(buf), &hm);
  726. ASSERT(mg_strcmp(hm.body, mg_str("[]:[hello]")) == 0);
  727. }
  728. {
  729. // Test upload
  730. char *p;
  731. remove("uploaded.txt");
  732. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
  733. ASSERT(fetch(&mgr, buf, url,
  734. "POST /upload HTTP/1.0\n"
  735. "Content-Length: 1\n\nx") == 400);
  736. ASSERT(fetch(&mgr, buf, url,
  737. "POST /upload?name=uploaded.txt HTTP/1.0\r\n"
  738. "Content-Length: 5\r\n"
  739. "\r\nhello") == 200);
  740. ASSERT(fetch(&mgr, buf, url,
  741. "POST /upload?name=uploaded.txt&offset=5 HTTP/1.0\r\n"
  742. "Content-Length: 6\r\n"
  743. "\r\n\nworld") == 200);
  744. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL);
  745. ASSERT(strcmp(p, "hello\nworld") == 0);
  746. free(p);
  747. remove("uploaded.txt");
  748. }
  749. {
  750. // Test upload directory traversal
  751. char *p;
  752. remove("uploaded.txt");
  753. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
  754. ASSERT(fetch(&mgr, buf, url,
  755. "POST /upload?name=../uploaded.txt HTTP/1.0\r\n"
  756. "Content-Length: 5\r\n"
  757. "\r\nhello") == 200);
  758. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL);
  759. ASSERT(strcmp(p, "hello") == 0);
  760. free(p);
  761. remove("uploaded.txt");
  762. }
  763. // HEAD request
  764. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  765. ASSERT(fetch(&mgr, buf, url, "HEAD /a.txt HTTP/1.0\n\n") == 200);
  766. // Pre-compressed files
  767. {
  768. struct mg_http_message hm;
  769. ASSERT(fetch(&mgr, buf, url, "HEAD /hello.txt HTTP/1.0\n\n") == 200);
  770. mg_http_parse(buf, strlen(buf), &hm);
  771. ASSERT(mg_http_get_header(&hm, "Content-Encoding") != NULL);
  772. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Encoding"),
  773. mg_str("gzip")) == 0);
  774. }
  775. #if MG_ENABLE_IPV6
  776. {
  777. const char *url6 = "http://[::1]:12366";
  778. ASSERT(mg_http_listen(&mgr, url6, eh1, NULL) != NULL);
  779. ASSERT(fetch(&mgr, buf, url6, "GET /a.txt HTTP/1.0\n\n") == 200);
  780. ASSERT(cmpbody(buf, "hello\n") == 0);
  781. }
  782. #endif
  783. mg_mgr_free(&mgr);
  784. ASSERT(mgr.conns == NULL);
  785. }
  786. static void h4(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  787. if (ev == MG_EV_HTTP_MSG) {
  788. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  789. MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr,
  790. (int) hm->uri.len, hm->uri.ptr, (int) hm->message.len));
  791. if (mg_http_match_uri(hm, "/a/#")) {
  792. struct mg_http_serve_opts opts;
  793. memset(&opts, 0, sizeof(opts));
  794. opts.root_dir = "/a=./test/data";
  795. opts.page404 = "./test/data/404.html"; // existing 404 page
  796. mg_http_serve_dir(c, hm, &opts);
  797. } else if (mg_http_match_uri(hm, "/b/#")) {
  798. struct mg_http_serve_opts opts;
  799. memset(&opts, 0, sizeof(opts));
  800. opts.root_dir = "/b=./test/data";
  801. opts.page404 = "./test/data/nooooo.html"; // non-existing 404 page
  802. mg_http_serve_dir(c, hm, &opts);
  803. } else { // null 404 page
  804. struct mg_http_serve_opts opts;
  805. memset(&opts, 0, sizeof(opts));
  806. opts.root_dir = "./test/data";
  807. mg_http_serve_dir(c, hm, &opts);
  808. }
  809. }
  810. (void) fn_data;
  811. }
  812. static void test_http_404(void) {
  813. struct mg_mgr mgr;
  814. const char *url = "http://127.0.0.1:22343";
  815. char buf[FETCH_BUF_SIZE];
  816. mg_mgr_init(&mgr);
  817. mg_http_listen(&mgr, url, h4, NULL);
  818. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  819. ASSERT(cmpbody(buf, "hello\n") == 0);
  820. ASSERT(fetch(&mgr, buf, url, "GET /a/a.txt HTTP/1.0\n\n") == 200);
  821. ASSERT(cmpbody(buf, "hello\n") == 0);
  822. ASSERT(fetch(&mgr, buf, url, "GET /b/a.txt HTTP/1.0\n\n") == 200);
  823. ASSERT(cmpbody(buf, "hello\n") == 0);
  824. ASSERT(fetch(&mgr, buf, url, "GET /xx.txt HTTP/1.0\n\n") == 404);
  825. ASSERT(cmpbody(buf, "Not found\n") == 0);
  826. ASSERT(fetch(&mgr, buf, url, "GET /a/xx.txt HTTP/1.0\n\n") == 200);
  827. ASSERT(cmpbody(buf, "boo\n") == 0);
  828. ASSERT(fetch(&mgr, buf, url, "GET /b/xx.txt HTTP/1.0\n\n") == 404);
  829. ASSERT(cmpbody(buf, "Not found\n") == 0);
  830. mg_mgr_free(&mgr);
  831. ASSERT(mgr.conns == NULL);
  832. }
  833. static void test_tls(void) {
  834. #if MG_ENABLE_MBEDTLS || MG_ENABLE_OPENSSL
  835. struct mg_tls_opts opts = {.ca = "./test/data/ss_ca.pem",
  836. .cert = "./test/data/ss_server.pem",
  837. .certkey = "./test/data/ss_server.pem"};
  838. struct mg_mgr mgr;
  839. struct mg_connection *c;
  840. const char *url = "https://127.0.0.1:12347";
  841. char buf[FETCH_BUF_SIZE];
  842. mg_mgr_init(&mgr);
  843. c = mg_http_listen(&mgr, url, eh1, (void *) &opts);
  844. ASSERT(c != NULL);
  845. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  846. // MG_INFO(("%s", buf));
  847. ASSERT(cmpbody(buf, "hello\n") == 0);
  848. mg_mgr_free(&mgr);
  849. ASSERT(mgr.conns == NULL);
  850. #endif
  851. }
  852. static void f3(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  853. int *ok = (int *) fn_data;
  854. // MG_INFO(("%d", ev));
  855. if (ev == MG_EV_CONNECT) {
  856. // c->is_hexdumping = 1;
  857. mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
  858. c->rem.is_ip6 ? "" : "/robots.txt",
  859. c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com");
  860. } else if (ev == MG_EV_HTTP_MSG) {
  861. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  862. // MG_INFO(("-->[%.*s]", (int) hm->message.len, hm->message.ptr));
  863. // ASSERT(mg_vcmp(&hm->method, "HTTP/1.1") == 0);
  864. // ASSERT(mg_vcmp(&hm->uri, "301") == 0);
  865. *ok = mg_http_status(hm);
  866. } else if (ev == MG_EV_CLOSE) {
  867. if (*ok == 0) *ok = 888;
  868. } else if (ev == MG_EV_ERROR) {
  869. if (*ok == 0) *ok = 777;
  870. }
  871. }
  872. static void test_http_client(void) {
  873. struct mg_mgr mgr;
  874. struct mg_connection *c;
  875. int i, ok = 0;
  876. mg_mgr_init(&mgr);
  877. c = mg_http_connect(&mgr, "http://cesanta.com", f3, &ok);
  878. ASSERT(c != NULL);
  879. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  880. ASSERT(ok == 301);
  881. c->is_closing = 1;
  882. mg_mgr_poll(&mgr, 0);
  883. ok = 0;
  884. #if MG_ENABLE_MBEDTLS || MG_ENABLE_OPENSSL
  885. {
  886. const char *url = "https://cesanta.com";
  887. struct mg_str host = mg_url_host(url);
  888. struct mg_tls_opts opts = {.ca = "./test/data/ca.pem", .srvname = host};
  889. c = mg_http_connect(&mgr, url, f3, &ok);
  890. ASSERT(c != NULL);
  891. mg_tls_init(c, &opts);
  892. for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1000);
  893. ASSERT(ok == 200);
  894. c->is_closing = 1;
  895. mg_mgr_poll(&mgr, 1);
  896. // Test failed host validation
  897. ok = 0;
  898. opts.srvname = mg_str("dummy");
  899. c = mg_http_connect(&mgr, url, f3, &ok);
  900. ASSERT(c != NULL);
  901. mg_tls_init(c, &opts);
  902. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  903. ASSERT(ok == 777);
  904. mg_mgr_poll(&mgr, 1);
  905. }
  906. #endif
  907. #if MG_ENABLE_IPV6
  908. ok = 0;
  909. // ipv6.google.com does not have IPv4 address, only IPv6, therefore
  910. // it is guaranteed to hit IPv6 resolution path.
  911. c = mg_http_connect(&mgr, "http://ipv6.google.com", f3, &ok);
  912. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  913. ASSERT(ok == 200);
  914. #endif
  915. mg_mgr_free(&mgr);
  916. ASSERT(mgr.conns == NULL);
  917. }
  918. static void f4(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  919. if (ev == MG_EV_HTTP_MSG) {
  920. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  921. mg_printf(c, "HTTP/1.0 200 OK\n\n%.*s/%s", (int) hm->uri.len, hm->uri.ptr,
  922. "abcdef");
  923. strcat((char *) fn_data, "m");
  924. c->is_draining = 1;
  925. } else if (ev == MG_EV_HTTP_CHUNK) {
  926. strcat((char *) fn_data, "f");
  927. } else if (ev == MG_EV_CLOSE) {
  928. strcat((char *) fn_data, "c");
  929. }
  930. }
  931. static void f4c(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  932. if (ev == MG_EV_CONNECT) {
  933. mg_printf(c, "GET /foo/bar HTTP/1.0\n\n");
  934. } else if (ev == MG_EV_HTTP_MSG) {
  935. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  936. ASSERT(mg_strcmp(hm->body, mg_str("/foo/bar/abcdef")) == 0);
  937. strcat((char *) fn_data, "m");
  938. } else if (ev == MG_EV_HTTP_CHUNK) {
  939. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  940. MG_INFO(("FS [%.*s]", (int) hm->chunk.len, hm->chunk.ptr));
  941. strcat((char *) fn_data, "f");
  942. } else if (ev == MG_EV_CLOSE) {
  943. strcat((char *) fn_data, "c");
  944. }
  945. }
  946. static void test_http_no_content_length(void) {
  947. char buf1[10] = {0}, buf2[10] = {0};
  948. struct mg_mgr mgr;
  949. const char *url = "http://127.0.0.1:12348";
  950. int i;
  951. mg_mgr_init(&mgr);
  952. mg_http_listen(&mgr, url, f4, (void *) buf1);
  953. mg_http_connect(&mgr, url, f4c, (void *) buf2);
  954. for (i = 0; i < 1000 && strchr(buf2, 'c') == NULL; i++) mg_mgr_poll(&mgr, 10);
  955. MG_INFO(("[%s] [%s]", buf1, buf2));
  956. ASSERT(strcmp(buf1, "fmc") == 0);
  957. ASSERT(strcmp(buf2, "fcfm") == 0); // See #1475
  958. mg_mgr_free(&mgr);
  959. ASSERT(mgr.conns == NULL);
  960. }
  961. static void f5(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  962. if (ev == MG_EV_HTTP_MSG) {
  963. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  964. mg_http_reply(c, 200, "", "%.*s", (int) hm->uri.len, hm->uri.ptr);
  965. (*(int *) fn_data)++;
  966. }
  967. }
  968. static void test_http_pipeline(void) {
  969. struct mg_mgr mgr;
  970. const char *url = "http://127.0.0.1:12377";
  971. struct mg_connection *c;
  972. int i, ok = 0;
  973. mg_mgr_init(&mgr);
  974. mg_http_listen(&mgr, url, f5, (void *) &ok);
  975. c = mg_http_connect(&mgr, url, NULL, NULL);
  976. mg_printf(c, "POST / HTTP/1.0\nContent-Length: 5\n\n12345GET / HTTP/1.0\n\n");
  977. for (i = 0; i < 20; i++) mg_mgr_poll(&mgr, 1);
  978. // MG_INFO(("-----> [%d]", ok));
  979. ASSERT(ok == 2);
  980. mg_mgr_free(&mgr);
  981. ASSERT(mgr.conns == NULL);
  982. }
  983. static void test_http_parse(void) {
  984. struct mg_str *v;
  985. struct mg_http_message req;
  986. {
  987. const char *s = "GET / HTTP/1.0\n\n";
  988. ASSERT(mg_http_parse("\b23", 3, &req) == -1);
  989. ASSERT(mg_http_parse("get\n\n", 5, &req) == -1);
  990. ASSERT(mg_http_parse(s, strlen(s) - 1, &req) == 0);
  991. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  992. ASSERT(req.message.len == strlen(s));
  993. ASSERT(req.body.len == 0);
  994. }
  995. {
  996. const char *s = "GET /blah HTTP/1.0\r\nFoo: bar \r\n\r\n";
  997. size_t idx, len = strlen(s);
  998. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) len);
  999. ASSERT(mg_vcmp(&req.headers[0].name, "Foo") == 0);
  1000. ASSERT(mg_vcmp(&req.headers[0].value, "bar") == 0);
  1001. ASSERT(req.headers[1].name.len == 0);
  1002. ASSERT(req.headers[1].name.ptr == NULL);
  1003. ASSERT(req.query.len == 0);
  1004. ASSERT(req.message.len == len);
  1005. ASSERT(req.body.len == 0);
  1006. for (idx = 0; idx < len; idx++) ASSERT(mg_http_parse(s, idx, &req) == 0);
  1007. }
  1008. {
  1009. static const char *s = "get b c\nz : k \nb: t\nvvv\n\n xx";
  1010. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1011. ASSERT(req.headers[2].name.len == 0);
  1012. ASSERT(mg_vcmp(&req.headers[0].value, "k") == 0);
  1013. ASSERT(mg_vcmp(&req.headers[1].value, "t") == 0);
  1014. ASSERT(req.body.len == 0);
  1015. }
  1016. {
  1017. const char *s = "a b c\r\nContent-Length: 21 \r\nb: t\r\nvvv\r\n\r\nabc";
  1018. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1019. ASSERT(req.body.len == 21);
  1020. ASSERT(req.message.len == 21 - 3 + strlen(s));
  1021. ASSERT(mg_http_get_header(&req, "foo") == NULL);
  1022. ASSERT((v = mg_http_get_header(&req, "contENT-Length")) != NULL);
  1023. ASSERT(mg_vcmp(v, "21") == 0);
  1024. ASSERT((v = mg_http_get_header(&req, "B")) != NULL);
  1025. ASSERT(mg_vcmp(v, "t") == 0);
  1026. }
  1027. {
  1028. const char *s = "GET /foo?a=b&c=d HTTP/1.0\n\n";
  1029. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1030. ASSERT(mg_vcmp(&req.uri, "/foo") == 0);
  1031. ASSERT(mg_vcmp(&req.query, "a=b&c=d") == 0);
  1032. }
  1033. {
  1034. const char *s = "POST /x HTTP/1.0\n\n";
  1035. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1036. ASSERT(req.body.len == (size_t) ~0);
  1037. }
  1038. {
  1039. const char *s = "WOHOO /x HTTP/1.0\n\n";
  1040. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1041. ASSERT(req.body.len == 0);
  1042. }
  1043. {
  1044. const char *s = "HTTP/1.0 200 OK\n\n";
  1045. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1046. ASSERT(mg_vcmp(&req.method, "HTTP/1.0") == 0);
  1047. ASSERT(mg_vcmp(&req.uri, "200") == 0);
  1048. ASSERT(mg_vcmp(&req.proto, "OK") == 0);
  1049. ASSERT(req.body.len == (size_t) ~0);
  1050. }
  1051. {
  1052. static const char *s = "HTTP/1.0 999 OMGWTFBBQ\n\n";
  1053. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1054. }
  1055. {
  1056. const char *s =
  1057. "GET / HTTP/1.0\r\nhost:127.0.0.1:18888\r\nCookie:\r\nX-PlayID: "
  1058. "45455\r\nRange: 0-1 \r\n\r\n";
  1059. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1060. ASSERT((v = mg_http_get_header(&req, "Host")) != NULL);
  1061. ASSERT(mg_vcmp(v, "127.0.0.1:18888") == 0);
  1062. ASSERT((v = mg_http_get_header(&req, "Cookie")) != NULL);
  1063. ASSERT(v->len == 0);
  1064. ASSERT((v = mg_http_get_header(&req, "X-PlayID")) != NULL);
  1065. ASSERT(mg_vcmp(v, "45455") == 0);
  1066. ASSERT((v = mg_http_get_header(&req, "Range")) != NULL);
  1067. ASSERT(mg_vcmp(v, "0-1") == 0);
  1068. }
  1069. {
  1070. static const char *s = "a b c\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
  1071. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1072. ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
  1073. ASSERT(mg_vcmp(v, "5") == 0);
  1074. ASSERT((v = mg_http_get_header(&req, "h")) == NULL);
  1075. }
  1076. {
  1077. struct mg_connection c;
  1078. struct mg_str s,
  1079. res = mg_str("GET /\r\nAuthorization: Basic Zm9vOmJhcg==\r\n\r\n");
  1080. memset(&c, 0, sizeof(c));
  1081. mg_printf(&c, "%s", "GET /\r\n");
  1082. mg_http_bauth(&c, "foo", "bar");
  1083. mg_printf(&c, "%s", "\r\n");
  1084. s = mg_str_n((char *) c.send.buf, c.send.len);
  1085. ASSERT(mg_strcmp(s, res) == 0);
  1086. mg_iobuf_free(&c.send);
  1087. }
  1088. {
  1089. struct mg_http_message hm;
  1090. const char *s = "GET /foo?bar=baz HTTP/1.0\n\n ";
  1091. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s) - 1);
  1092. ASSERT(mg_strcmp(hm.uri, mg_str("/foo")) == 0);
  1093. ASSERT(mg_strcmp(hm.query, mg_str("bar=baz")) == 0);
  1094. }
  1095. {
  1096. struct mg_http_message hm;
  1097. const char *s = "a b c\n\n";
  1098. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
  1099. s = "a b\nc\n\n";
  1100. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
  1101. s = "a\nb\nc\n\n";
  1102. ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
  1103. }
  1104. }
  1105. static void ehr(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1106. if (ev == MG_EV_HTTP_MSG) {
  1107. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1108. struct mg_http_serve_opts opts;
  1109. memset(&opts, 0, sizeof(opts));
  1110. opts.root_dir = "./test/data";
  1111. mg_http_serve_dir(c, hm, &opts);
  1112. }
  1113. (void) fn_data;
  1114. }
  1115. static void test_http_range(void) {
  1116. struct mg_mgr mgr;
  1117. const char *url = "http://127.0.0.1:12349";
  1118. struct mg_http_message hm;
  1119. char buf[FETCH_BUF_SIZE];
  1120. mg_mgr_init(&mgr);
  1121. mg_http_listen(&mgr, url, ehr, NULL);
  1122. ASSERT(fetch(&mgr, buf, url, "GET /range.txt HTTP/1.0\n\n") == 200);
  1123. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1124. ASSERT(hm.body.len == 312);
  1125. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=5-10\n\n");
  1126. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1127. ASSERT(mg_strcmp(hm.uri, mg_str("206")) == 0);
  1128. ASSERT(mg_strcmp(hm.proto, mg_str("Partial Content")) == 0);
  1129. ASSERT(mg_strcmp(hm.body, mg_str(" of co")) == 0);
  1130. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Range"),
  1131. mg_str("bytes 5-10/312")) == 0);
  1132. // Fetch till EOF
  1133. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=300-\n\n");
  1134. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1135. ASSERT(mg_strcmp(hm.uri, mg_str("206")) == 0);
  1136. ASSERT(mg_strcmp(hm.body, mg_str("is disease.\n")) == 0);
  1137. // MG_INFO(("----%d\n[%s]", (int) hm.body.len, buf));
  1138. // Fetch past EOF, must trigger 416 response
  1139. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=999-\n\n");
  1140. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1141. ASSERT(mg_strcmp(hm.uri, mg_str("416")) == 0);
  1142. ASSERT(hm.body.len == 0);
  1143. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Range"),
  1144. mg_str("bytes */312")) == 0);
  1145. fetch(&mgr, buf, url, "%s",
  1146. "GET /range.txt HTTP/1.0\nRange: bytes=0-312\n\n");
  1147. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1148. ASSERT(mg_strcmp(hm.uri, mg_str("416")) == 0);
  1149. mg_mgr_free(&mgr);
  1150. ASSERT(mgr.conns == NULL);
  1151. }
  1152. static void f1(void *arg) {
  1153. (*(int *) arg)++;
  1154. }
  1155. static void test_timer(void) {
  1156. int v1 = 0, v2 = 0, v3 = 0;
  1157. struct mg_timer t1, t2, t3, *head = NULL;
  1158. mg_timer_init(&head, &t1, 5, MG_TIMER_REPEAT, f1, &v1);
  1159. mg_timer_init(&head, &t2, 15, MG_TIMER_ONCE, f1, &v2);
  1160. mg_timer_init(&head, &t3, 10, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, f1, &v3);
  1161. ASSERT(head == &t3);
  1162. ASSERT(head->next == &t2);
  1163. mg_timer_poll(&head, 0);
  1164. ASSERT(v1 == 0);
  1165. ASSERT(v2 == 0);
  1166. ASSERT(v3 == 1);
  1167. mg_timer_poll(&head, 1);
  1168. ASSERT(v1 == 0);
  1169. ASSERT(v2 == 0);
  1170. ASSERT(v3 == 1);
  1171. mg_timer_poll(&head, 5);
  1172. ASSERT(v1 == 1);
  1173. ASSERT(v2 == 0);
  1174. ASSERT(v3 == 1);
  1175. // Simulate long delay - timers must invalidate expiration times
  1176. mg_timer_poll(&head, 100);
  1177. ASSERT(v1 == 2);
  1178. ASSERT(v2 == 1);
  1179. ASSERT(v3 == 2);
  1180. mg_timer_poll(&head, 107);
  1181. ASSERT(v1 == 3);
  1182. ASSERT(v2 == 1);
  1183. ASSERT(v3 == 2);
  1184. mg_timer_poll(&head, 114);
  1185. ASSERT(v1 == 4);
  1186. ASSERT(v2 == 1);
  1187. ASSERT(v3 == 3);
  1188. mg_timer_poll(&head, 115);
  1189. ASSERT(v1 == 5);
  1190. ASSERT(v2 == 1);
  1191. ASSERT(v3 == 3);
  1192. mg_timer_free(&head, &t2);
  1193. mg_timer_init(&head, &t2, 3, 0, f1, &v2);
  1194. ASSERT(head == &t2);
  1195. ASSERT(head->next == &t3);
  1196. ASSERT(head->next->next == &t1);
  1197. ASSERT(head->next->next->next == NULL);
  1198. mg_timer_poll(&head, 120);
  1199. ASSERT(v1 == 6);
  1200. ASSERT(v2 == 1);
  1201. ASSERT(v3 == 4);
  1202. mg_timer_poll(&head, 125);
  1203. ASSERT(v1 == 7);
  1204. ASSERT(v2 == 2);
  1205. ASSERT(v3 == 4);
  1206. // Test millisecond counter wrap - when time goes back.
  1207. mg_timer_poll(&head, 0);
  1208. ASSERT(v1 == 7);
  1209. ASSERT(v2 == 2);
  1210. ASSERT(v3 == 4);
  1211. mg_timer_poll(&head, 7);
  1212. ASSERT(v1 == 8);
  1213. ASSERT(v2 == 2);
  1214. ASSERT(v3 == 4);
  1215. mg_timer_poll(&head, 11);
  1216. ASSERT(v1 == 9);
  1217. ASSERT(v2 == 2);
  1218. ASSERT(v3 == 5);
  1219. mg_timer_free(&head, &t1);
  1220. ASSERT(head == &t2);
  1221. ASSERT(head->next == &t3);
  1222. ASSERT(head->next->next == NULL);
  1223. mg_timer_free(&head, &t2);
  1224. ASSERT(head == &t3);
  1225. ASSERT(head->next == NULL);
  1226. mg_timer_free(&head, &t3);
  1227. ASSERT(head == NULL);
  1228. // Test proper timer deallocation, see #1539
  1229. {
  1230. struct mg_mgr mgr;
  1231. mg_mgr_init(&mgr);
  1232. mg_timer_add(&mgr, 1, MG_TIMER_REPEAT, f1, NULL);
  1233. mg_mgr_free(&mgr);
  1234. ASSERT(mgr.conns == NULL);
  1235. }
  1236. }
  1237. static bool sn(const char *fmt, ...) {
  1238. char buf[100], tmp[1] = {0}, buf2[sizeof(buf)];
  1239. size_t n, n2, n1;
  1240. va_list ap;
  1241. bool result;
  1242. va_start(ap, fmt);
  1243. n = (size_t) vsnprintf(buf2, sizeof(buf2), fmt, ap);
  1244. va_end(ap);
  1245. va_start(ap, fmt);
  1246. n1 = mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
  1247. va_end(ap);
  1248. va_start(ap, fmt);
  1249. n2 = mg_vsnprintf(tmp, 0, fmt, &ap);
  1250. va_end(ap);
  1251. result = n1 == n2 && n1 == n && strcmp(buf, buf2) == 0;
  1252. if (!result)
  1253. MG_ERROR(("[%s] -> [%s] != [%s] %d %d %d\n", fmt, buf, buf2, (int) n1,
  1254. (int) n2, (int) n));
  1255. return result;
  1256. }
  1257. static bool sccmp(const char *s1, const char *s2, int expected) {
  1258. int n1 = mg_casecmp(s1, s2);
  1259. // MG_INFO(("[%s] [%s] %d %d", s1, s2, n1, expected));
  1260. return n1 == expected;
  1261. }
  1262. static size_t pf1(void (*out)(char, void *), void *ptr, va_list *ap) {
  1263. int a = va_arg(*ap, int);
  1264. int b = va_arg(*ap, int);
  1265. return mg_xprintf(out, ptr, "%d", a + b);
  1266. }
  1267. static size_t pf2(void (*out)(char, void *), void *ptr, va_list *ap) {
  1268. int cnt = va_arg(*ap, int);
  1269. size_t n = 0;
  1270. while (cnt-- > 0) n += mg_xprintf(out, ptr, "%d", cnt);
  1271. return n;
  1272. }
  1273. static bool chkdbl(struct mg_str s, double val) {
  1274. double d, tolerance = 1e-14;
  1275. return mg_json_get_num(s, "$", &d) && fabs(val - d) < tolerance;
  1276. }
  1277. static void test_str(void) {
  1278. {
  1279. struct mg_str s = mg_strdup(mg_str("a"));
  1280. ASSERT(mg_strcmp(s, mg_str("a")) == 0);
  1281. free((void *) s.ptr);
  1282. }
  1283. ASSERT(mg_strcmp(mg_str(""), mg_str(NULL)) == 0);
  1284. ASSERT(mg_strcmp(mg_str("a"), mg_str("b")) < 0);
  1285. ASSERT(mg_strcmp(mg_str("b"), mg_str("a")) > 0);
  1286. ASSERT(mg_strstr(mg_str("abc"), mg_str("d")) == NULL);
  1287. ASSERT(mg_strstr(mg_str("abc"), mg_str("b")) != NULL);
  1288. ASSERT(mg_strcmp(mg_str("hi"), mg_strstrip(mg_str(" \thi\r\n"))) == 0);
  1289. ASSERT(sccmp("", "", 0));
  1290. ASSERT(sccmp("", "1", -49));
  1291. ASSERT(sccmp("a", "A", 0));
  1292. ASSERT(sccmp("a1", "A", 49));
  1293. ASSERT(sccmp("a", "A1", -49));
  1294. {
  1295. ASSERT(chkdbl(mg_str_n("1.23", 3), 1.2));
  1296. ASSERT(chkdbl(mg_str("1.23 "), 1.23));
  1297. ASSERT(chkdbl(mg_str("-0.01 "), -0.01));
  1298. ASSERT(chkdbl(mg_str("-0.5e2"), -50.0));
  1299. ASSERT(chkdbl(mg_str("123e-3"), 0.123));
  1300. }
  1301. ASSERT(sn("%d", 0));
  1302. ASSERT(sn("%d", 1));
  1303. ASSERT(sn("%d", -1));
  1304. ASSERT(sn("%.*s", 0, "ab"));
  1305. ASSERT(sn("%.*s", 1, "ab"));
  1306. ASSERT(sn("%.1s", "ab"));
  1307. ASSERT(sn("%.99s", "a"));
  1308. ASSERT(sn("%11s", "a"));
  1309. ASSERT(sn("%s", "a\0b"));
  1310. ASSERT(sn("%2s", "a"));
  1311. ASSERT(sn("%.*s", 3, "a\0b"));
  1312. ASSERT(sn("%d", 7));
  1313. ASSERT(sn("%d", 123));
  1314. #if MG_ARCH == MG_ARCH_UNIX
  1315. ASSERT(sn("%lld", (uint64_t) 0xffffffffff));
  1316. ASSERT(sn("%lld", (uint64_t) -1));
  1317. ASSERT(sn("%llu", (uint64_t) -1));
  1318. ASSERT(sn("%llx", (uint64_t) 0xffffffffff));
  1319. ASSERT(sn("%p", (void *) (size_t) 7));
  1320. #endif
  1321. ASSERT(sn("%lx", (unsigned long) 0x6204d754));
  1322. ASSERT(sn("ab"));
  1323. ASSERT(sn("%dx", 1));
  1324. ASSERT(sn("%sx", "a"));
  1325. ASSERT(sn("%cx", 32));
  1326. ASSERT(sn("%x", 15));
  1327. ASSERT(sn("%2x", 15));
  1328. ASSERT(sn("%02x", 15));
  1329. ASSERT(sn("%hx:%hhx", (short) 1, (char) 2));
  1330. ASSERT(sn("%hx:%hhx", (short) 1, (char) 2));
  1331. ASSERT(sn("%%"));
  1332. ASSERT(sn("%x", 15));
  1333. ASSERT(sn("%#x", 15));
  1334. ASSERT(sn("%#6x", 15));
  1335. ASSERT(sn("%#06x", 15));
  1336. ASSERT(sn("%#-6x", 15));
  1337. ASSERT(sn("%-2s!", "a"));
  1338. ASSERT(sn("%s %s", "a", "b"));
  1339. ASSERT(sn("%s %s", "a", "b"));
  1340. ASSERT(sn("ab%dc", 123));
  1341. ASSERT(sn("%s ", "a"));
  1342. ASSERT(sn("%s %s", "a", "b"));
  1343. ASSERT(sn("%2s %s", "a", "b"));
  1344. // Non-standard formatting
  1345. {
  1346. char buf[100], *p = NULL;
  1347. struct mg_iobuf io = {0, 0, 0, 16};
  1348. const char *expected;
  1349. expected = "\"\"";
  1350. mg_snprintf(buf, sizeof(buf), "%Q", "");
  1351. ASSERT(strcmp(buf, expected) == 0);
  1352. expected = "";
  1353. mg_snprintf(buf, 1, "%s", "abc");
  1354. ASSERT(strcmp(buf, expected) == 0);
  1355. expected = "a";
  1356. mg_snprintf(buf, 2, "%s", "abc");
  1357. ASSERT(strcmp(buf, expected) == 0);
  1358. expected = "\"hi, \\\"\"";
  1359. mg_snprintf(buf, sizeof(buf), "\"hi, %q\"", "\"");
  1360. MG_INFO(("[%s] [%s]", buf, expected));
  1361. ASSERT(strcmp(buf, expected) == 0);
  1362. expected = "\"a'b\"";
  1363. mg_snprintf(buf, sizeof(buf), "%Q", "a'b");
  1364. ASSERT(strcmp(buf, expected) == 0);
  1365. expected = "\"a\\b\\n\\f\\r\\t\\\"\"";
  1366. mg_snprintf(buf, sizeof(buf), "%Q", "a\b\n\f\r\t\"");
  1367. ASSERT(strcmp(buf, expected) == 0);
  1368. expected = "\"abc\"";
  1369. mg_snprintf(buf, sizeof(buf), "%.*Q", 3, "abcdef");
  1370. ASSERT(strcmp(buf, expected) == 0);
  1371. p = mg_mprintf("[%s,%M,%s]", "null", pf1, 2, 3, "hi");
  1372. ASSERT(strcmp(p, "[null,5,hi]") == 0);
  1373. free(p);
  1374. p = mg_mprintf("[%M,%d]", pf2, 10, 7);
  1375. ASSERT(strcmp(p, "[9876543210,7]") == 0);
  1376. free(p);
  1377. mg_xprintf(mg_pfn_iobuf, &io, "[%M", pf2, 10);
  1378. mg_xprintf(mg_pfn_iobuf, &io, ",");
  1379. mg_xprintf(mg_pfn_iobuf, &io, "%d]", 7);
  1380. ASSERT(strcmp((char *) io.buf, "[9876543210,7]") == 0);
  1381. mg_iobuf_free(&io);
  1382. }
  1383. {
  1384. char tmp[40];
  1385. #define DBLWIDTH(a, b) a, b
  1386. #define TESTDOUBLE(fmt_, num_, res_) \
  1387. do { \
  1388. const char *N = #num_; \
  1389. size_t n = mg_snprintf(tmp, sizeof(tmp), fmt_, num_); \
  1390. if (0) printf("[%s] [%s] -> [%s] [%.*s]\n", fmt_, N, res_, (int) n, tmp); \
  1391. ASSERT(n == strlen(res_)); \
  1392. ASSERT(strcmp(tmp, res_) == 0); \
  1393. } while (0)
  1394. TESTDOUBLE("%g", 0.0, "0");
  1395. TESTDOUBLE("%g", 0.123, "0.123");
  1396. TESTDOUBLE("%g", 0.00123, "0.00123");
  1397. TESTDOUBLE("%g", 0.123456333, "0.123456");
  1398. TESTDOUBLE("%g", 123.0, "123");
  1399. TESTDOUBLE("%g", 11.5454, "11.5454");
  1400. TESTDOUBLE("%g", 11.0001, "11.0001");
  1401. TESTDOUBLE("%g", 0.999, "0.999");
  1402. TESTDOUBLE("%g", 0.999999, "0.999999");
  1403. TESTDOUBLE("%g", 0.9999999, "1");
  1404. TESTDOUBLE("%g", 10.9, "10.9");
  1405. TESTDOUBLE("%g", 10.01, "10.01");
  1406. TESTDOUBLE("%g", 1.0, "1");
  1407. TESTDOUBLE("%g", 10.0, "10");
  1408. TESTDOUBLE("%g", 100.0, "100");
  1409. TESTDOUBLE("%g", 1000.0, "1000");
  1410. TESTDOUBLE("%g", 10000.0, "10000");
  1411. TESTDOUBLE("%g", 100000.0, "100000");
  1412. TESTDOUBLE("%g", 1000000.0, "1e+06");
  1413. TESTDOUBLE("%g", 10000000.0, "1e+07");
  1414. TESTDOUBLE("%g", 100000001.0, "1e+08");
  1415. TESTDOUBLE("%g", 10.5454, "10.5454");
  1416. TESTDOUBLE("%g", 999999.0, "999999");
  1417. TESTDOUBLE("%g", 9999999.0, "1e+07");
  1418. TESTDOUBLE("%g", 44556677.0, "4.45567e+07");
  1419. TESTDOUBLE("%g", 1234567.2, "1.23457e+06");
  1420. TESTDOUBLE("%g", -987.65432, "-987.654");
  1421. TESTDOUBLE("%g", 0.0000000001, "1e-10");
  1422. TESTDOUBLE("%g", 2.34567e-57, "2.34567e-57");
  1423. TESTDOUBLE("%.*g", DBLWIDTH(7, 9999999.0), "9999999");
  1424. TESTDOUBLE("%.*g", DBLWIDTH(10, 0.123456333), "0.123456333");
  1425. TESTDOUBLE("%g", 123.456222, "123.456");
  1426. TESTDOUBLE("%.*g", DBLWIDTH(10, 123.456222), "123.456222");
  1427. TESTDOUBLE("%g", 600.1234, "600.123");
  1428. TESTDOUBLE("%g", -600.1234, "-600.123");
  1429. TESTDOUBLE("%g", 599.1234, "599.123");
  1430. TESTDOUBLE("%g", -599.1234, "-599.123");
  1431. #ifndef _WIN32
  1432. TESTDOUBLE("%g", (double) INFINITY, "inf");
  1433. TESTDOUBLE("%g", (double) -INFINITY, "-inf");
  1434. TESTDOUBLE("%g", (double) NAN, "nan");
  1435. #else
  1436. TESTDOUBLE("%g", HUGE_VAL, "inf");
  1437. TESTDOUBLE("%g", -HUGE_VAL, "-inf");
  1438. #endif
  1439. }
  1440. {
  1441. const char *expected = "[\"MA==\",\"MAo=\",\"MAr+\",\"MAr+Zw==\"]";
  1442. char tmp[100], s[] = "0\n\xfeg";
  1443. ASSERT(mg_snprintf(tmp, sizeof(tmp), "[%V,%V,%V,%V]", 1, s, 2, s, 3, s, 4,
  1444. s) == 33);
  1445. ASSERT(strcmp(tmp, expected) == 0);
  1446. }
  1447. {
  1448. const char *expected = "\"002001200220616263\"";
  1449. char tmp[100], s[] = "\x00 \x01 \x02 abc";
  1450. ASSERT(mg_snprintf(tmp, sizeof(tmp), "%H", 9, s) == 20);
  1451. ASSERT(strcmp(tmp, expected) == 0);
  1452. }
  1453. {
  1454. char tmp[3];
  1455. ASSERT(mg_snprintf(tmp, sizeof(tmp), "%s", "0123456789") == 10);
  1456. ASSERT(strcmp(tmp, "01") == 0);
  1457. ASSERT(tmp[2] == '\0');
  1458. }
  1459. }
  1460. static void fn1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1461. if (ev == MG_EV_ERROR) sprintf((char *) fn_data, "%s", (char *) ev_data);
  1462. (void) c;
  1463. }
  1464. static void test_dns_error(const char *dns_server_url, const char *errstr) {
  1465. // Test timeout
  1466. struct mg_mgr mgr;
  1467. char buf[100] = "";
  1468. int i;
  1469. mg_mgr_init(&mgr);
  1470. mgr.dns4.url = dns_server_url;
  1471. mgr.dnstimeout = 10;
  1472. MG_DEBUG(("opening dummy DNS listener @ [%s]...", dns_server_url));
  1473. mg_listen(&mgr, mgr.dns4.url, NULL, NULL); // Just discard our queries
  1474. mg_http_connect(&mgr, "http://google.com", fn1, buf);
  1475. for (i = 0; i < 50 && buf[0] == '\0'; i++) mg_mgr_poll(&mgr, 1);
  1476. mg_mgr_free(&mgr);
  1477. // MG_DEBUG(("buf: [%s] [%s]", buf, errstr));
  1478. ASSERT(strcmp(buf, errstr) == 0);
  1479. }
  1480. static void test_dns(void) {
  1481. struct mg_dns_message dm;
  1482. // txid flags numQ numA numAP numOP
  1483. // 0000 00 01 81 80 00 01 00 01 00 00 00 00 07 63 65 73 .............ces
  1484. // 0010 61 6e 74 61 03 63 6f 6d 00 00 01 00 01 c0 0c 00 anta.com........
  1485. // 0020 01 00 01 00 00 02 57 00 04 94 fb 36 ec ......W....6.
  1486. uint8_t data[] = {0, 1, 0x81, 0x80, 0, 1, 0, 1, 0,
  1487. 0, 0, 0, 7, 0x63, 0x65, 0x73, 0x61, 0x6e,
  1488. 0x74, 0x61, 0x03, 0x63, 0x6f, 0x6d, 0, 0, 1,
  1489. 0, 1, 0xc0, 0x0c, 0, 1, 0, 1, 0,
  1490. 0, 2, 0x57, 0, 4, 0x94, 0xfb, 0x36, 0xec};
  1491. ASSERT(mg_dns_parse(NULL, 0, &dm) == 0);
  1492. ASSERT(mg_dns_parse(data, sizeof(data), &dm) == 1);
  1493. ASSERT(strcmp(dm.name, "cesanta.com") == 0);
  1494. data[30] = 29; // Point a pointer to itself
  1495. memset(&dm, 0, sizeof(dm));
  1496. ASSERT(mg_dns_parse(data, sizeof(data), &dm) == 1);
  1497. ASSERT(strcmp(dm.name, "") == 0);
  1498. {
  1499. // 0000 00 01 81 80 00 01 00 04 00 00 00 00 05 79 61 68 .............yah
  1500. // 0010 6f 6f 05 63 31 31 32 36 03 63 6f 6d 00 00 01 00 oo.c1126.com....
  1501. // 0020 01 c0 0c 00 05 00 01 00 00 0d 34 00 0c 03 77 77 ..........4...ww
  1502. // 0030 77 05 79 61 68 6f 6f c0 18 c0 2d 00 05 00 01 00 w.yahoo...-.....
  1503. // 0040 00 00 01 00 14 0b 6e 65 77 2d 66 70 2d 73 68 65 ......new-fp-she
  1504. // 0050 64 03 77 67 31 01 62 c0 31 c0 45 00 01 00 01 00 d.wg1.b.1.E.....
  1505. // 0060 00 00 0a 00 04 57 f8 64 d8 c0 45 00 01 00 01 00 .....W.d..E.....
  1506. // 0070 00 00 0a 00 04 57 f8 64 d7 .....W.d.
  1507. uint8_t d[] = {
  1508. 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
  1509. 0x00, 0x05, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x05, 0x63, 0x31, 0x31,
  1510. 0x32, 0x36, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
  1511. 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x34, 0x00,
  1512. 0x0c, 0x03, 0x77, 0x77, 0x77, 0x05, 0x79, 0x61, 0x68, 0x6f, 0x6f,
  1513. 0xc0, 0x18, 0xc0, 0x2d, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00,
  1514. 0x01, 0x00, 0x14, 0x0b, 0x6e, 0x65, 0x77, 0x2d, 0x66, 0x70, 0x2d,
  1515. 0x73, 0x68, 0x65, 0x64, 0x03, 0x77, 0x67, 0x31, 0x01, 0x62, 0xc0,
  1516. 0x31, 0xc0, 0x45, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a,
  1517. 0x00, 0x04, 0x57, 0xf8, 0x64, 0xd8, 0xc0, 0x45, 0x00, 0x01, 0x00,
  1518. 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x57, 0xf8, 0x64, 0xd7,
  1519. };
  1520. ASSERT(mg_dns_parse(d, sizeof(d), &dm) == 1);
  1521. // MG_INFO(("[%s]", dm.name));
  1522. ASSERT(strcmp(dm.name, "new-fp-shed.wg1.b.yahoo.com") == 0);
  1523. }
  1524. test_dns_error("udp://127.0.0.1:12345", "DNS timeout");
  1525. test_dns_error("", "resolver");
  1526. test_dns_error("tcp://0.0.0.0:0", "DNS error");
  1527. }
  1528. static void test_util(void) {
  1529. char buf[100], *p, *s;
  1530. struct mg_addr a;
  1531. memset(&a, 0, sizeof(a));
  1532. ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true);
  1533. // if (system("ls -l") != 0) (void) 0;
  1534. ASSERT((p = mg_file_read(&mg_fs_posix, "data.txt", NULL)) != NULL);
  1535. ASSERT(strcmp(p, "hi") == 0);
  1536. free(p);
  1537. remove("data.txt");
  1538. ASSERT(mg_aton(mg_str("0"), &a) == false);
  1539. ASSERT(mg_aton(mg_str("0.0.0."), &a) == false);
  1540. ASSERT(mg_aton(mg_str("0.0.0.256"), &a) == false);
  1541. ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
  1542. ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
  1543. ASSERT(a.is_ip6 == false);
  1544. ASSERT(a.ip == 0x100007f);
  1545. ASSERT(strcmp(mg_ntoa(&a, buf, sizeof(buf)), "127.0.0.1") == 0);
  1546. ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
  1547. ASSERT(a.is_ip6 == true);
  1548. ASSERT(
  1549. memcmp(a.ip6,
  1550. "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08",
  1551. sizeof(a.ip6)) == 0);
  1552. memset(a.ip6, 0xaa, sizeof(a.ip6));
  1553. ASSERT(mg_aton(mg_str("1::1"), &a) == true);
  1554. ASSERT(a.is_ip6 == true);
  1555. ASSERT(
  1556. memcmp(a.ip6,
  1557. "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
  1558. sizeof(a.ip6)) == 0);
  1559. memset(a.ip6, 0xaa, sizeof(a.ip6));
  1560. ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
  1561. ASSERT(a.is_ip6 == true);
  1562. ASSERT(memcmp(a.ip6,
  1563. "\x00\x00\x00\x00\x00\x00\x00\x00"
  1564. "\x00\x00\xff\xff\x01\x02\x03\x04",
  1565. sizeof(a.ip6)) == 0);
  1566. memset(a.ip6, 0xaa, sizeof(a.ip6));
  1567. ASSERT(mg_aton(mg_str("::1"), &a) == true);
  1568. ASSERT(a.is_ip6 == true);
  1569. ASSERT(
  1570. memcmp(a.ip6,
  1571. "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
  1572. sizeof(a.ip6)) == 0);
  1573. memset(a.ip6, 0xaa, sizeof(a.ip6));
  1574. ASSERT(mg_aton(mg_str("1::"), &a) == true);
  1575. ASSERT(a.is_ip6 == true);
  1576. ASSERT(
  1577. memcmp(a.ip6,
  1578. "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
  1579. sizeof(a.ip6)) == 0);
  1580. memset(a.ip6, 0xaa, sizeof(a.ip6));
  1581. ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
  1582. ASSERT(a.is_ip6 == true);
  1583. ASSERT(
  1584. memcmp(a.ip6,
  1585. "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88",
  1586. sizeof(a.ip6)) == 0);
  1587. ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0);
  1588. ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
  1589. ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
  1590. {
  1591. size_t n;
  1592. ASSERT((n = mg_url_encode("", 0, buf, sizeof(buf))) == 0);
  1593. ASSERT((n = mg_url_encode("a", 1, buf, 0)) == 0);
  1594. ASSERT((n = mg_url_encode("a", 1, buf, sizeof(buf))) == 1);
  1595. ASSERT(strncmp(buf, "a", n) == 0);
  1596. ASSERT((n = mg_url_encode("._-~", 4, buf, sizeof(buf))) == 4);
  1597. ASSERT(strncmp(buf, "._-~", n) == 0);
  1598. ASSERT((n = mg_url_encode("a@%>", 4, buf, sizeof(buf))) == 10);
  1599. ASSERT(strncmp(buf, "a%40%25%3e", n) == 0);
  1600. ASSERT((n = mg_url_encode("a@b.c", 5, buf, sizeof(buf))) == 7);
  1601. ASSERT(strncmp(buf, "a%40b.c", n) == 0);
  1602. }
  1603. {
  1604. s = mg_mprintf("%3d", 123);
  1605. ASSERT(strcmp(s, "123") == 0);
  1606. free(s);
  1607. }
  1608. ASSERT(mg_to64(mg_str("-9223372036854775809")) == 0);
  1609. ASSERT(mg_to64(mg_str("9223372036854775800")) == 0);
  1610. ASSERT(mg_to64(mg_str("9223372036854775700")) > 0);
  1611. ASSERT(mg_tou64(mg_str("0")) == 0);
  1612. ASSERT(mg_tou64(mg_str("123")) == 123);
  1613. ASSERT(mg_tou64(mg_str("")) == 0);
  1614. ASSERT(mg_tou64(mg_str("-")) == 0);
  1615. ASSERT(mg_tou64(mg_str("18446744073709551615")) == 18446744073709551615U);
  1616. {
  1617. size_t i;
  1618. memset(buf, ' ', sizeof(buf));
  1619. mg_random_str(buf, 0);
  1620. ASSERT(buf[0] == ' ');
  1621. mg_random_str(buf, 1);
  1622. ASSERT(buf[0] == '\0');
  1623. ASSERT(buf[1] == ' ');
  1624. mg_random_str(buf, sizeof(buf));
  1625. ASSERT(buf[sizeof(buf) - 1] == '\0');
  1626. for (i = 0; i < sizeof(buf) - 1; i++) ASSERT(isalnum((uint8_t) buf[i]));
  1627. }
  1628. }
  1629. static void test_crc32(void) {
  1630. // echo -n aaa | cksum -o3
  1631. ASSERT(mg_crc32(0, 0, 0) == 0);
  1632. ASSERT(mg_crc32(0, "a", 1) == 3904355907);
  1633. ASSERT(mg_crc32(0, "abc", 3) == 891568578);
  1634. ASSERT(mg_crc32(mg_crc32(0, "ab", 2), "c", 1) == 891568578);
  1635. }
  1636. static void us(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1637. int del = *(int *) fn_data;
  1638. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1639. if (ev == MG_EV_HTTP_CHUNK && mg_http_match_uri(hm, "/upload")) {
  1640. MG_DEBUG(("Got chunk len %lu", (unsigned long) hm->chunk.len));
  1641. MG_DEBUG(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
  1642. // MG_DEBUG(("Chunk data:\n%.*s", (int) hm->chunk.len, hm->chunk.ptr));
  1643. if (del) {
  1644. mg_http_delete_chunk(c, hm);
  1645. if (hm->chunk.len == 0) {
  1646. MG_DEBUG(("Last chunk received, sending response"));
  1647. mg_http_reply(c, 200, "", "ok (chunked)\n");
  1648. }
  1649. }
  1650. } else if (ev == MG_EV_HTTP_MSG && mg_http_match_uri(hm, "/upload")) {
  1651. MG_DEBUG(("Got all %lu bytes!", (unsigned long) hm->body.len));
  1652. MG_DEBUG(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
  1653. // MG_DEBUG(("Body:\n%.*s", (int) hm->body.len, hm->body.ptr));
  1654. mg_http_reply(c, 200, "", "ok (%d %.*s)\n", (int) hm->body.len,
  1655. (int) hm->body.len, hm->body.ptr);
  1656. } else if (ev == MG_EV_HTTP_MSG) {
  1657. mg_http_reply(c, 200, "", "ok\n");
  1658. }
  1659. (void) fn_data;
  1660. }
  1661. static void uc(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1662. const char **s = (const char **) fn_data;
  1663. if (ev == MG_EV_OPEN) {
  1664. c->is_hexdumping = 1;
  1665. } else if (ev == MG_EV_CONNECT) {
  1666. mg_printf(c,
  1667. "POST /upload HTTP/1.0\r\n"
  1668. "Transfer-Encoding: chunked\r\n\r\n");
  1669. mg_http_printf_chunk(c, "%s", "foo\n");
  1670. mg_http_printf_chunk(c, "%s", "bar\n");
  1671. mg_http_printf_chunk(c, "");
  1672. } else if (ev == MG_EV_HTTP_MSG) {
  1673. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1674. ASSERT(mg_strcmp(hm->body, mg_str(*s)) == 0);
  1675. *s = NULL;
  1676. }
  1677. (void) fn_data;
  1678. }
  1679. static void test_http_upload(void) {
  1680. struct mg_mgr mgr;
  1681. const char *url = "http://127.0.0.1:12352";
  1682. int i, del = 1;
  1683. const char *s1 = "ok (chunked)\n";
  1684. const char *s2 = "ok (8 foo\nbar\n)\n";
  1685. mg_mgr_init(&mgr);
  1686. mg_http_listen(&mgr, url, us, (void *) &del);
  1687. mg_http_connect(&mgr, url, uc, (void *) &s1);
  1688. for (i = 0; i < 20; i++) mg_mgr_poll(&mgr, 5);
  1689. ASSERT(s1 == NULL);
  1690. del = 0;
  1691. mg_http_connect(&mgr, url, uc, (void *) &s2);
  1692. for (i = 0; i < 20; i++) mg_mgr_poll(&mgr, 5);
  1693. ASSERT(s2 == NULL);
  1694. mg_mgr_free(&mgr);
  1695. ASSERT(mgr.conns == NULL);
  1696. }
  1697. #define LONG_CHUNK "chunk with length taking up more than two hex digits"
  1698. static void eX(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1699. if (ev == MG_EV_HTTP_MSG) {
  1700. mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
  1701. c->label[0] = 1;
  1702. c->is_hexdumping = 1;
  1703. } else if (ev == MG_EV_POLL && c->label[0] != 0) {
  1704. c->label[0]++;
  1705. if (c->label[0] == 10) mg_http_printf_chunk(c, "a");
  1706. if (c->label[0] == 20) {
  1707. mg_http_printf_chunk(c, "b");
  1708. mg_http_printf_chunk(c, "c");
  1709. }
  1710. if (c->label[0] == 30) {
  1711. mg_http_printf_chunk(c, "d");
  1712. mg_http_printf_chunk(c, "");
  1713. c->label[0] = 0;
  1714. }
  1715. }
  1716. (void) ev_data, (void) fn_data;
  1717. }
  1718. static void eY(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1719. if (ev == MG_EV_HTTP_MSG) {
  1720. mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n");
  1721. c->label[0] = 1;
  1722. } else if (ev == MG_EV_POLL && c->label[0] != 0) {
  1723. c->label[0]++;
  1724. if (c->label[0] == 10) mg_send(c, "a", 1);
  1725. if (c->label[0] == 12) mg_send(c, "bc", 2);
  1726. if (c->label[0] == 30) mg_send(c, "d", 1), c->is_resp = 0, c->label[0] = 0;
  1727. }
  1728. (void) ev_data, (void) fn_data;
  1729. }
  1730. static void eZ(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1731. if (ev == MG_EV_HTTP_MSG) {
  1732. mg_http_reply(c, 200, "", "abcd");
  1733. }
  1734. (void) ev_data, (void) fn_data;
  1735. }
  1736. // Do not delete chunks as they arrive
  1737. static void eh4(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1738. uint32_t *crc = (uint32_t *) fn_data;
  1739. if (ev == MG_EV_HTTP_CHUNK) {
  1740. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1741. *crc = mg_crc32(*crc, hm->chunk.ptr, hm->chunk.len);
  1742. *crc = mg_crc32(*crc, "x", 1);
  1743. MG_INFO(("%lu C [%.*s]", c->id, (int) hm->chunk.len, hm->chunk.ptr));
  1744. } else if (ev == MG_EV_HTTP_MSG) {
  1745. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1746. *crc = mg_crc32(*crc, hm->body.ptr, hm->body.len);
  1747. MG_INFO(("%lu M [%.*s]", c->id, (int) hm->body.len, hm->body.ptr));
  1748. }
  1749. }
  1750. // Streaming client event handler. Delete chunks as they arrive
  1751. static void eh5(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1752. uint32_t *crc = (uint32_t *) fn_data;
  1753. if (ev == MG_EV_HTTP_CHUNK) {
  1754. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1755. *crc = mg_crc32(*crc, hm->chunk.ptr, hm->chunk.len);
  1756. *crc = mg_crc32(*crc, "x", 1);
  1757. MG_INFO(("%lu DELC [%.*s]", c->id, (int) hm->chunk.len, hm->chunk.ptr));
  1758. mg_http_delete_chunk(c, hm);
  1759. } else if (ev == MG_EV_HTTP_MSG) {
  1760. ASSERT(0); // Must not be here, MSG must not be fired: chunks deleted!
  1761. }
  1762. }
  1763. static void test_http_chunked_case(mg_event_handler_t s, mg_event_handler_t c,
  1764. int req_count, const char *expected) {
  1765. struct mg_mgr mgr;
  1766. const char *url = "http://127.0.0.1:12344";
  1767. uint32_t i, crc = 0, expected_crc = mg_crc32(0, expected, strlen(expected));
  1768. struct mg_connection *conn;
  1769. mg_mgr_init(&mgr);
  1770. mg_http_listen(&mgr, url, s, NULL);
  1771. conn = mg_http_connect(&mgr, url, c, &crc);
  1772. while (conn != NULL && req_count-- > 0) {
  1773. mg_printf(conn, "GET / HTTP/1.0\n\n");
  1774. }
  1775. for (i = 0; i < 100 && crc != expected_crc; i++) {
  1776. mg_mgr_poll(&mgr, 1);
  1777. }
  1778. ASSERT(i < 100);
  1779. ASSERT(crc == expected_crc);
  1780. mg_mgr_free(&mgr);
  1781. ASSERT(mgr.conns == NULL);
  1782. }
  1783. static void test_http_chunked(void) {
  1784. // Non-chunked encoding
  1785. test_http_chunked_case(eY, eh4, 1, "axbcxdxxabcd"); // Chunks not deleted
  1786. test_http_chunked_case(eY, eh4, 2, "axbcxdxxabcdaxbcxdxxabcd");
  1787. test_http_chunked_case(eY, eh5, 1, "axbcxdxx"); // Chunks deleted
  1788. test_http_chunked_case(eY, eh5, 2, "axbcxdxxaxbcxdxx");
  1789. test_http_chunked_case(eZ, eh4, 1, "abcdxxabcd"); // Not deleted
  1790. test_http_chunked_case(eZ, eh4, 2, "abcdxxabcdabcdxxabcd");
  1791. test_http_chunked_case(eZ, eh5, 1, "abcdxx"); // Deleted
  1792. test_http_chunked_case(eZ, eh5, 2, "abcdxxabcdxx");
  1793. // Chunked encoding
  1794. test_http_chunked_case(eX, eh4, 1, "axbxcxdxxabcd"); // Chunks not deleted
  1795. test_http_chunked_case(eX, eh5, 1, "axbxcxdxx"); // Chunks deleted
  1796. test_http_chunked_case(eX, eh4, 2, "axbxcxdxxabcdaxbxcxdxxabcd");
  1797. test_http_chunked_case(eX, eh5, 2, "axbxcxdxxaxbxcxdxx");
  1798. }
  1799. static void test_invalid_listen_addr(void) {
  1800. struct mg_mgr mgr;
  1801. struct mg_connection *c;
  1802. mg_mgr_init(&mgr);
  1803. c = mg_http_listen(&mgr, "invalid:31:14", eh1, NULL);
  1804. ASSERT(c == NULL);
  1805. mg_mgr_free(&mgr);
  1806. ASSERT(mgr.conns == NULL);
  1807. }
  1808. struct stream_status {
  1809. uint32_t polls;
  1810. size_t sent;
  1811. size_t received;
  1812. uint32_t send_crc;
  1813. uint32_t recv_crc;
  1814. };
  1815. // Consume recv buffer after letting it reach MG_MAX_RECV_SIZE
  1816. static void eh8(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1817. struct stream_status *status = (struct stream_status *) fn_data;
  1818. if (c->is_listening) return;
  1819. ASSERT(c->recv.len <= MG_MAX_RECV_SIZE);
  1820. if (ev == MG_EV_ACCEPT) {
  1821. // Optimize recv buffer size near max to speed up test
  1822. mg_iobuf_resize(&c->recv, MG_MAX_RECV_SIZE - MG_IO_SIZE);
  1823. status->received = 0;
  1824. status->recv_crc = 0;
  1825. }
  1826. if (ev == MG_EV_CLOSE) {
  1827. ASSERT(status->received == status->sent);
  1828. }
  1829. // Let buffer fill up and start consuming after 10 full buffer poll events
  1830. if (status->polls >= 10 && ev == MG_EV_POLL) {
  1831. // consume at most a third of MG_MAX_RECV_SIZE on each poll
  1832. size_t consume;
  1833. if (MG_MAX_RECV_SIZE / 3 >= c->recv.len)
  1834. consume = c->recv.len;
  1835. else
  1836. consume = MG_MAX_RECV_SIZE / 3;
  1837. status->received += consume;
  1838. status->recv_crc =
  1839. mg_crc32(status->recv_crc, (const char *) c->recv.buf, consume);
  1840. mg_iobuf_del(&c->recv, 0, consume);
  1841. }
  1842. // count polls with full buffer to ensure c->is_full prevents reads
  1843. if (ev == MG_EV_POLL && c->recv.len == MG_MAX_RECV_SIZE) status->polls += 1;
  1844. (void) ev_data;
  1845. }
  1846. // Toggle c->is_full to prevent max_recv_buf_size reached read errors
  1847. static void eh10(struct mg_connection *c, int ev, void *ev_data,
  1848. void *fn_data) {
  1849. if (c->recv.len >= MG_MAX_RECV_SIZE && ev == MG_EV_READ) c->is_full = true;
  1850. eh8(c, ev, ev_data, fn_data);
  1851. if (c->recv.len < MG_MAX_RECV_SIZE && ev == MG_EV_POLL) c->is_full = false;
  1852. }
  1853. // Send buffer larger than MG_MAX_RECV_SIZE to server
  1854. static void eh11(struct mg_connection *c, int ev, void *ev_data,
  1855. void *fn_data) {
  1856. struct stream_status *status = (struct stream_status *) fn_data;
  1857. if (ev == MG_EV_CONNECT) {
  1858. size_t len = MG_MAX_RECV_SIZE * 2;
  1859. struct mg_iobuf buf = {NULL, 0, 0, 0};
  1860. mg_iobuf_init(&buf, len, 0);
  1861. mg_random(buf.buf, buf.size);
  1862. buf.len = buf.size;
  1863. mg_send(c, buf.buf, buf.len);
  1864. status->sent = buf.len;
  1865. status->send_crc = mg_crc32(0, (const char *) buf.buf, buf.len);
  1866. mg_iobuf_free(&buf);
  1867. }
  1868. (void) ev_data;
  1869. (void) fn_data;
  1870. }
  1871. static void test_http_stream_buffer(void) {
  1872. struct mg_mgr mgr;
  1873. const char *url = "tcp://127.0.0.1:12344";
  1874. uint32_t i;
  1875. struct stream_status status;
  1876. mg_mgr_init(&mgr);
  1877. mg_listen(&mgr, url, eh10, &status);
  1878. status.polls = 0;
  1879. mg_connect(&mgr, url, eh11, &status);
  1880. for (i = 0; i < (MG_MAX_RECV_SIZE / MG_IO_SIZE) * 50; i++) {
  1881. mg_mgr_poll(&mgr, 1);
  1882. if (status.polls >= 10 && status.sent == status.received) break;
  1883. }
  1884. ASSERT(status.sent == status.received);
  1885. ASSERT(status.send_crc == status.recv_crc);
  1886. mg_mgr_free(&mgr);
  1887. ASSERT(mgr.conns == NULL);
  1888. }
  1889. static void test_multipart(void) {
  1890. struct mg_http_part part;
  1891. size_t ofs;
  1892. const char *s =
  1893. "--xyz\r\n"
  1894. "Content-Disposition: form-data; name=\"val\"\r\n"
  1895. "\r\n"
  1896. "abc\r\ndef\r\n"
  1897. "--xyz\r\n"
  1898. "Content-Disposition: form-data; name=\"foo\"; filename=\"a b.txt\"\r\n"
  1899. "Content-Type: text/plain\r\n"
  1900. "\r\n"
  1901. "hello world\r\n"
  1902. "\r\n"
  1903. "--xyz--\r\n";
  1904. ASSERT(mg_http_next_multipart(mg_str(""), 0, NULL) == 0);
  1905. ASSERT((ofs = mg_http_next_multipart(mg_str(s), 0, &part)) > 0);
  1906. ASSERT(mg_strcmp(part.name, mg_str("val")) == 0);
  1907. // MG_INFO(("--> [%.*s]", (int) part.body.len, part.body.ptr));
  1908. ASSERT(mg_strcmp(part.body, mg_str("abc\r\ndef")) == 0);
  1909. ASSERT(part.filename.len == 0);
  1910. ASSERT((ofs = mg_http_next_multipart(mg_str(s), ofs, &part)) > 0);
  1911. ASSERT(mg_strcmp(part.name, mg_str("foo")) == 0);
  1912. // MG_INFO(("--> [%.*s]", (int) part.filename.len, part.filename.ptr));
  1913. ASSERT(mg_strcmp(part.filename, mg_str("a b.txt")) == 0);
  1914. ASSERT(mg_strcmp(part.body, mg_str("hello world\r\n")) == 0);
  1915. ASSERT(mg_http_next_multipart(mg_str(s), ofs, &part) == 0);
  1916. }
  1917. static void eh7(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1918. if (ev == MG_EV_HTTP_MSG) {
  1919. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1920. struct mg_http_serve_opts sopts;
  1921. memset(&sopts, 0, sizeof(sopts));
  1922. sopts.root_dir = "/";
  1923. sopts.fs = &mg_fs_packed;
  1924. mg_http_serve_dir(c, hm, &sopts);
  1925. }
  1926. (void) fn_data;
  1927. }
  1928. static void test_packed(void) {
  1929. struct mg_mgr mgr;
  1930. const char *url = "http://127.0.0.1:12351";
  1931. char buf[FETCH_BUF_SIZE],
  1932. *data = mg_file_read(&mg_fs_posix, "Makefile", NULL);
  1933. mg_mgr_init(&mgr);
  1934. mg_http_listen(&mgr, url, eh7, NULL);
  1935. // Load top level file directly
  1936. // fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n");
  1937. // printf("---> %s\n", buf);
  1938. ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200);
  1939. ASSERT(cmpbody(buf, data) == 0);
  1940. free(data);
  1941. // Load file deeper in the FS tree directly
  1942. data = mg_file_read(&mg_fs_posix, "src/ssi.h", NULL);
  1943. ASSERT(fetch(&mgr, buf, url, "GET /src/ssi.h HTTP/1.0\n\n") == 200);
  1944. ASSERT(cmpbody(buf, data) == 0);
  1945. free(data);
  1946. // List root dir
  1947. ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200);
  1948. // printf("--------\n%s\n", buf);
  1949. // List nested dir
  1950. ASSERT(fetch(&mgr, buf, url, "GET /test HTTP/1.0\n\n") == 301);
  1951. ASSERT(fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n") == 200);
  1952. // printf("--------\n%s\n", buf);
  1953. mg_mgr_free(&mgr);
  1954. ASSERT(mgr.conns == NULL);
  1955. }
  1956. static void eh6(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1957. if (ev == MG_EV_READ) *(int *) fn_data = 1;
  1958. (void) c, (void) ev_data;
  1959. }
  1960. #if defined(__arm__) || defined(__riscv)
  1961. int send(int sock, const void *buf, size_t len, int flags);
  1962. int send(int sock, const void *buf, size_t len, int flags) {
  1963. (void) sock, (void) buf, (void) len, (void) flags;
  1964. return -1;
  1965. }
  1966. #endif
  1967. static void test_pipe_proto(bool is_udp) {
  1968. struct mg_mgr mgr;
  1969. int i, sock, done = 0;
  1970. mg_mgr_init(&mgr);
  1971. ASSERT((sock = mg_mkpipe(&mgr, eh6, (void *) &done, is_udp)) >= 0);
  1972. ASSERT(send(sock, "hi", 2, 0) == 2);
  1973. for (i = 0; i < 10 && done == 0; i++) mg_mgr_poll(&mgr, 1);
  1974. ASSERT(done == 1);
  1975. mg_mgr_free(&mgr);
  1976. ASSERT(mgr.conns == NULL);
  1977. }
  1978. static void test_pipe(void) {
  1979. test_pipe_proto(true);
  1980. test_pipe_proto(false);
  1981. }
  1982. static void u1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  1983. if (ev == MG_EV_CONNECT) {
  1984. ((int *) fn_data)[0] += 1;
  1985. mg_send(c, "hi", 2);
  1986. } else if (ev == MG_EV_WRITE) {
  1987. ((int *) fn_data)[0] += 100;
  1988. } else if (ev == MG_EV_READ) {
  1989. ((int *) fn_data)[0] += 10;
  1990. mg_iobuf_free(&c->recv);
  1991. }
  1992. (void) ev_data;
  1993. }
  1994. static void test_udp(void) {
  1995. struct mg_mgr mgr;
  1996. const char *url = "udp://127.0.0.1:12353";
  1997. int i, done = 0;
  1998. mg_mgr_init(&mgr);
  1999. mg_listen(&mgr, url, u1, (void *) &done);
  2000. mg_connect(&mgr, url, u1, (void *) &done);
  2001. for (i = 0; i < 5; i++) mg_mgr_poll(&mgr, 1);
  2002. // MG_INFO(("%d", done));
  2003. ASSERT(done == 111);
  2004. mg_mgr_free(&mgr);
  2005. ASSERT(mgr.conns == NULL);
  2006. }
  2007. static void test_check_ip_acl(void) {
  2008. uint32_t ip = mg_htonl(0x01020304);
  2009. ASSERT(mg_check_ip_acl(mg_str(NULL), ip) == 1);
  2010. ASSERT(mg_check_ip_acl(mg_str(""), ip) == 1);
  2011. ASSERT(mg_check_ip_acl(mg_str("invalid"), ip) == -1);
  2012. ASSERT(mg_check_ip_acl(mg_str("+hi"), ip) == -2);
  2013. ASSERT(mg_check_ip_acl(mg_str("+//"), ip) == -2);
  2014. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0"), ip) == 0);
  2015. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.0.0.0/8"), ip) == 1);
  2016. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.2.3.4"), ip) == 1);
  2017. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.0.0.0/16"), ip) == 0);
  2018. }
  2019. static void w3(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  2020. // MG_INFO(("ev %d", ev));
  2021. if (ev == MG_EV_WS_OPEN) {
  2022. char buf[8192];
  2023. memset(buf, 'A', sizeof(buf));
  2024. mg_ws_send(c, "hi there!", 9, WEBSOCKET_OP_TEXT);
  2025. mg_printf(c, "%s", "boo");
  2026. mg_ws_wrap(c, 3, WEBSOCKET_OP_TEXT);
  2027. mg_ws_send(c, buf, sizeof(buf), WEBSOCKET_OP_TEXT);
  2028. } else if (ev == MG_EV_WS_MSG) {
  2029. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  2030. ASSERT(mg_strcmp(wm->data, mg_str("lebowski")) == 0);
  2031. ((int *) fn_data)[0]++;
  2032. } else if (ev == MG_EV_CLOSE) {
  2033. ((int *) fn_data)[0] += 10;
  2034. }
  2035. }
  2036. static void w2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  2037. struct mg_str msg = mg_str_n("lebowski", 8);
  2038. if (ev == MG_EV_HTTP_MSG) {
  2039. mg_ws_upgrade(c, (struct mg_http_message *) ev_data, NULL);
  2040. } else if (ev == MG_EV_WS_OPEN) {
  2041. mg_ws_send(c, "x", 1, WEBSOCKET_OP_PONG);
  2042. } else if (ev == MG_EV_POLL && c->is_websocket) {
  2043. size_t ofs, n = (size_t) fn_data;
  2044. if (n < msg.len) {
  2045. // Send "msg" char by char using fragmented frames
  2046. // mg_ws_send() sets the FIN flag in the WS header. Clean it
  2047. // to send fragmented packet. Insert PONG messages between frames
  2048. uint8_t op = n == 0 ? WEBSOCKET_OP_TEXT : WEBSOCKET_OP_CONTINUE;
  2049. mg_ws_send(c, ":->", 3, WEBSOCKET_OP_PING);
  2050. ofs = c->send.len;
  2051. mg_ws_send(c, &msg.ptr[n], 1, op);
  2052. if (n < msg.len - 1) c->send.buf[ofs] = op; // Clear FIN flag
  2053. c->fn_data = (void *) (n + 1); // Point to the next char
  2054. } else {
  2055. mg_ws_send(c, "", 0, WEBSOCKET_OP_CLOSE);
  2056. }
  2057. } else if (ev == MG_EV_WS_MSG) {
  2058. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  2059. MG_INFO(("Got WS, %lu", wm->data.len));
  2060. mg_hexdump(wm->data.ptr, wm->data.len);
  2061. if (wm->data.len == 9) {
  2062. ASSERT(mg_strcmp(wm->data, mg_str("hi there!")) == 0);
  2063. } else if (wm->data.len == 3) {
  2064. ASSERT(mg_strcmp(wm->data, mg_str("boo")) == 0);
  2065. } else {
  2066. MG_INFO(("%lu", wm->data.len));
  2067. ASSERT(wm->data.len == 8192);
  2068. }
  2069. }
  2070. }
  2071. static void test_ws_fragmentation(void) {
  2072. const char *url = "ws://localhost:12357/ws";
  2073. struct mg_mgr mgr;
  2074. int i, done = 0;
  2075. mg_mgr_init(&mgr);
  2076. ASSERT(mg_http_listen(&mgr, url, w2, NULL) != NULL);
  2077. mg_ws_connect(&mgr, url, w3, &done, "%s", "Sec-WebSocket-Protocol: echo\r\n");
  2078. for (i = 0; i < 25; i++) mg_mgr_poll(&mgr, 1);
  2079. // MG_INFO(("--> %d", done));
  2080. ASSERT(done == 11);
  2081. mg_mgr_free(&mgr);
  2082. ASSERT(mgr.conns == NULL);
  2083. }
  2084. static void h7(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  2085. if (ev == MG_EV_HTTP_MSG) {
  2086. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2087. struct mg_http_serve_opts opts;
  2088. memset(&opts, 0, sizeof(opts));
  2089. opts.root_dir = "./test/data,/foo=./src";
  2090. mg_http_serve_dir(c, hm, &opts);
  2091. }
  2092. (void) fn_data;
  2093. }
  2094. static void test_rewrites(void) {
  2095. char buf[FETCH_BUF_SIZE];
  2096. const char *url = "http://LOCALHOST:12358";
  2097. const char *expected = "#define MG_VERSION \"" MG_VERSION "\"\n";
  2098. struct mg_mgr mgr;
  2099. mg_mgr_init(&mgr);
  2100. ASSERT(mg_http_listen(&mgr, url, h7, NULL) != NULL);
  2101. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  2102. ASSERT(cmpbody(buf, "hello\n") == 0);
  2103. ASSERT(fetch(&mgr, buf, url, "GET /foo/version.h HTTP/1.0\n\n") == 200);
  2104. ASSERT(cmpbody(buf, expected) == 0);
  2105. ASSERT(fetch(&mgr, buf, url, "GET /foo HTTP/1.0\n\n") == 301);
  2106. ASSERT(fetch(&mgr, buf, url, "GET /foo/ HTTP/1.0\n\n") == 200);
  2107. // printf("-->[%s]\n", buf);
  2108. mg_mgr_free(&mgr);
  2109. ASSERT(mgr.conns == NULL);
  2110. }
  2111. static void test_get_header_var(void) {
  2112. struct mg_str empty = mg_str(""), bar = mg_str("bar"), baz = mg_str("baz");
  2113. struct mg_str header = mg_str("Digest foo=\"bar\", blah,boo=baz, x=\"yy\"");
  2114. struct mg_str yy = mg_str("yy");
  2115. // struct mg_str x = mg_http_get_header_var(header, mg_str("x"));
  2116. // MG_INFO(("--> [%d] [%d]", (int) x.len, yy.len));
  2117. ASSERT(mg_strcmp(empty, mg_http_get_header_var(empty, empty)) == 0);
  2118. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, empty)) == 0);
  2119. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("fooo"))) == 0);
  2120. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("fo"))) == 0);
  2121. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("blah"))) == 0);
  2122. ASSERT(mg_strcmp(bar, mg_http_get_header_var(header, mg_str("foo"))) == 0);
  2123. ASSERT(mg_strcmp(baz, mg_http_get_header_var(header, mg_str("boo"))) == 0);
  2124. ASSERT(mg_strcmp(yy, mg_http_get_header_var(header, mg_str("x"))) == 0);
  2125. }
  2126. static void test_json(void) {
  2127. const char *s1 = "{\"a\":{},\"b\":7,\"c\":[[],2]}";
  2128. const char *s2 = "{\"a\":{\"b1\":{}},\"c\":7,\"d\":{\"b2\":{}}}";
  2129. int n;
  2130. struct mg_str json;
  2131. ASSERT(mg_json_get(mg_str_n(" true ", 6), "", &n) == MG_JSON_INVALID);
  2132. ASSERT(mg_json_get(mg_str_n(" true ", 6), "$", &n) == 1 && n == 4);
  2133. ASSERT(mg_json_get(mg_str_n("null ", 5), "$", &n) == 0 && n == 4);
  2134. json = mg_str(" \"hi\\nthere\"");
  2135. ASSERT(mg_json_get(json, "$", &n) == 2 && n == 11);
  2136. ASSERT(mg_json_get(mg_str_n(" { } ", 5), "$", &n) == 1);
  2137. ASSERT(mg_json_get(mg_str_n(" [[]]", 5), "$", &n) == 1);
  2138. ASSERT(mg_json_get(mg_str_n(" [ ] ", 5), "$", &n) == 1);
  2139. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$", &n) == 0 && n == 5);
  2140. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[0]", &n) == 1 && n == 1);
  2141. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[1]", &n) == 3 && n == 1);
  2142. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[3]", &n) == MG_JSON_NOT_FOUND);
  2143. json = mg_str("{\"a\":[]}");
  2144. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2145. json = mg_str("{\"a\":[1,2]}");
  2146. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2147. json = mg_str("{\"a\":[1,[1]]}");
  2148. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2149. json = mg_str("{\"a\":[[]]}");
  2150. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2151. json = mg_str("{\"a\":[[1,2]]}");
  2152. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2153. json = mg_str("{\"a\":{}}");
  2154. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2155. json = mg_str("{\"a\":{\"a\":{}}}");
  2156. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2157. json = mg_str("{\"a\":{\"a\":[]}}");
  2158. ASSERT(mg_json_get(json, "$.a", &n) == 5);
  2159. json = mg_str("[[1,[2,3]],4]");
  2160. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 13);
  2161. ASSERT(mg_json_get(json, "$[0]", &n) == 1 && n == 9);
  2162. ASSERT(mg_json_get(json, "$[1]", &n) == 11);
  2163. ASSERT(mg_json_get(json, "$[1]", &n) == 11 && n == 1);
  2164. ASSERT(mg_json_get(json, "$[2]", &n) == MG_JSON_NOT_FOUND);
  2165. ASSERT(mg_json_get(json, "$[0][0]", &n) == 2 && n == 1);
  2166. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 5);
  2167. ASSERT(mg_json_get(json, "$[0][2]", &n) == MG_JSON_NOT_FOUND);
  2168. ASSERT(mg_json_get(json, "$[0][1][0]", &n) == 5 && n == 1);
  2169. ASSERT(mg_json_get(json, "$[0][1][1]", &n) == 7 && n == 1);
  2170. json = mg_str("[[1,2],3]");
  2171. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 9);
  2172. ASSERT(mg_json_get(json, "$[0][0]", &n) == 2 && n == 1);
  2173. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 1);
  2174. ASSERT(mg_json_get(json, "$[0][2]", &n) == MG_JSON_NOT_FOUND);
  2175. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2176. ASSERT(mg_json_get(json, "$[1]", &n) == 7 && n == 1);
  2177. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2178. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 9);
  2179. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2180. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 1);
  2181. json = mg_str(s1);
  2182. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2183. ASSERT(mg_json_get(json, "$.b", &n) == 12 && n == 1);
  2184. ASSERT(mg_json_get(json, "$.c", &n) == 18 && n == 6);
  2185. ASSERT(mg_json_get(json, "$.c[0]", &n) == 19 && n == 2);
  2186. ASSERT(mg_json_get(json, "$.c[1]", &n) == 22 && n == 1);
  2187. ASSERT(mg_json_get(json, "$.c[3]", &n) == MG_JSON_NOT_FOUND);
  2188. json = mg_str(s2);
  2189. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 9);
  2190. ASSERT(mg_json_get(json, "$.a.b1", &n) == 11 && n == 2);
  2191. ASSERT(mg_json_get(json, "$.a.b2", &n) == MG_JSON_NOT_FOUND);
  2192. ASSERT(mg_json_get(json, "$.a.b", &n) == MG_JSON_NOT_FOUND);
  2193. ASSERT(mg_json_get(json, "$.a1", &n) == MG_JSON_NOT_FOUND);
  2194. ASSERT(mg_json_get(json, "$.c", &n) == 19 && n == 1);
  2195. {
  2196. double d = 0;
  2197. bool b = false;
  2198. int len;
  2199. char *str = NULL;
  2200. json = mg_str("{\"a\":\"b\"}");
  2201. str = mg_json_get_str(json, "$.a");
  2202. ASSERT(str != NULL);
  2203. // printf("---> [%s]\n", str);
  2204. ASSERT(strcmp(str, "b") == 0);
  2205. free(str);
  2206. json = mg_str("{\"a\": \"hi\\nthere\",\"b\": [12345, true]}");
  2207. str = mg_json_get_str(json, "$.a");
  2208. ASSERT(str != NULL);
  2209. ASSERT(strcmp(str, "hi\nthere") == 0);
  2210. free(str);
  2211. ASSERT(mg_json_get_long(json, "$.foo", -42) == -42);
  2212. ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 12345);
  2213. ASSERT(mg_json_get_num(json, "$.a", &d) == false);
  2214. ASSERT(mg_json_get_num(json, "$.c", &d) == false);
  2215. ASSERT(mg_json_get_num(json, "$.b[0]", &d) == true);
  2216. ASSERT(d == 12345);
  2217. ASSERT(mg_json_get_bool(json, "$.b", &b) == false);
  2218. ASSERT(mg_json_get_bool(json, "$.b[0]", &b) == false);
  2219. ASSERT(mg_json_get_bool(json, "$.b[1]", &b) == true);
  2220. ASSERT(b == true);
  2221. ASSERT(mg_json_get(json, "$.b[2]", &len) < 0);
  2222. json = mg_str("[\"YWJj\", \"0100026869\"]");
  2223. ASSERT((str = mg_json_get_b64(json, "$[0]", &len)) != NULL);
  2224. ASSERT(len == 3 && memcmp(str, "abc", (size_t) len) == 0);
  2225. free(str);
  2226. ASSERT((str = mg_json_get_hex(json, "$[1]", &len)) != NULL);
  2227. ASSERT(len == 5 && memcmp(str, "\x01\x00\x02hi", (size_t) len) == 0);
  2228. free(str);
  2229. json = mg_str("{\"a\":[1,2,3], \"ab\": 2}");
  2230. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2231. ASSERT(mg_json_get_long(json, "$.ab", -42) == 2);
  2232. ASSERT(mg_json_get_long(json, "$.ac", -42) == -42);
  2233. json = mg_str("{\"a\":[],\"b\":[1,2]}");
  2234. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == -42);
  2235. ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 1);
  2236. ASSERT(mg_json_get_long(json, "$.b[1]", -42) == 2);
  2237. ASSERT(mg_json_get_long(json, "$.b[2]", -42) == -42);
  2238. json = mg_str("[{\"a\":1,\"b\":2},{\"a\":3, \"b\":4}]");
  2239. ASSERT(mg_json_get_long(json, "$[0].a", -42) == 1);
  2240. ASSERT(mg_json_get_long(json, "$[0].b", -42) == 2);
  2241. ASSERT(mg_json_get_long(json, "$[1].a", -42) == 3);
  2242. ASSERT(mg_json_get_long(json, "$[1].b", -42) == 4);
  2243. ASSERT(mg_json_get_long(json, "$[2].a", -42) == -42);
  2244. json = mg_str("{\"a\":[1],\"b\":[2,3]}");
  2245. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2246. ASSERT(mg_json_get_long(json, "$.a[1]", -42) == -42);
  2247. json = mg_str("{\"a\":[1,[2,3], 4]}");
  2248. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2249. ASSERT(mg_json_get_long(json, "$.a[1][0]", -42) == 2);
  2250. ASSERT(mg_json_get_long(json, "$.a[1][1]", -42) == 3);
  2251. ASSERT(mg_json_get_long(json, "$.a[1][2]", -42) == -42);
  2252. ASSERT(mg_json_get_long(json, "$.a[2]", -42) == 4);
  2253. ASSERT(mg_json_get_long(json, "$.a[3]", -42) == -42);
  2254. }
  2255. }
  2256. static void resp_rpc(struct mg_rpc_req *r) {
  2257. int len = 0, off = mg_json_get(r->frame, "$.result", &len);
  2258. mg_xprintf(r->pfn, r->pfn_data, "%.*s", len, &r->frame.ptr[off]);
  2259. }
  2260. static void test_rpc(void) {
  2261. struct mg_rpc *head = NULL;
  2262. struct mg_iobuf io = {0, 0, 0, 256};
  2263. struct mg_rpc_req req = {&head, 0, mg_pfn_iobuf, &io, 0, {0, 0}};
  2264. mg_rpc_add(&head, mg_str("rpc.list"), mg_rpc_list, NULL);
  2265. {
  2266. req.frame = mg_str("{\"method\":\"rpc.list\"}");
  2267. mg_rpc_process(&req);
  2268. ASSERT(io.buf == NULL);
  2269. }
  2270. {
  2271. const char *resp = "{\"id\":1,\"result\":[\"rpc.list\"]}";
  2272. req.frame = mg_str("{\"id\": 1,\"method\":\"rpc.list\"}");
  2273. mg_rpc_process(&req);
  2274. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2275. mg_iobuf_free(&io);
  2276. }
  2277. {
  2278. const char *resp =
  2279. "{\"id\":true,\"error\":{\"code\":-32601,\"message\":\"foo not "
  2280. "found\"}}";
  2281. req.frame = mg_str("{\"id\": true,\"method\":\"foo\"}");
  2282. mg_rpc_process(&req);
  2283. // MG_INFO(("-> %s", io.buf));
  2284. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2285. mg_iobuf_free(&io);
  2286. }
  2287. {
  2288. const char *resp =
  2289. "{\"id\":true,\"error\":{\"code\":-32601,\"message\":\"foo not "
  2290. "found\"}}";
  2291. req.frame = mg_str("{\"id\": true,\"method\":\"foo\"}");
  2292. req.head = NULL;
  2293. mg_rpc_process(&req);
  2294. // MG_INFO(("-> %s", io.buf));
  2295. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2296. mg_iobuf_free(&io);
  2297. req.head = &head;
  2298. }
  2299. {
  2300. const char *resp = "{\"error\":{\"code\":-32700,\"message\":\"haha\"}}";
  2301. req.frame = mg_str("haha");
  2302. mg_rpc_process(&req);
  2303. // MG_INFO(("-> %s", io.buf));
  2304. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2305. mg_iobuf_free(&io);
  2306. }
  2307. {
  2308. const char *resp =
  2309. "{\"id\":1,\"error\":{\"code\":-32601,\"message\":\" not found\"}}";
  2310. req.frame = mg_str("{\"id\":1,\"result\":123}");
  2311. mg_rpc_process(&req);
  2312. // MG_INFO(("-> %s", io.buf));
  2313. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2314. mg_iobuf_free(&io);
  2315. }
  2316. {
  2317. req.frame = mg_str("{\"id\":1,\"result\":123}");
  2318. mg_rpc_add(&head, mg_str(""), resp_rpc, NULL);
  2319. mg_rpc_process(&req);
  2320. MG_INFO(("-> %s", io.buf));
  2321. ASSERT(strcmp((char *) io.buf, "123") == 0);
  2322. mg_iobuf_free(&io);
  2323. }
  2324. mg_rpc_del(&head, NULL);
  2325. ASSERT(head == NULL);
  2326. }
  2327. int main(void) {
  2328. const char *debug_level = getenv("V");
  2329. if (debug_level == NULL) debug_level = "3";
  2330. mg_log_set(atoi(debug_level));
  2331. test_json();
  2332. test_rpc();
  2333. test_str();
  2334. test_globmatch();
  2335. test_get_header_var();
  2336. test_rewrites();
  2337. test_check_ip_acl();
  2338. test_udp();
  2339. test_pipe();
  2340. test_packed();
  2341. test_crc32();
  2342. test_multipart();
  2343. test_invalid_listen_addr();
  2344. test_http_chunked();
  2345. test_http_upload();
  2346. test_http_stream_buffer();
  2347. test_http_parse();
  2348. test_util();
  2349. test_dns();
  2350. test_timer();
  2351. test_url();
  2352. test_iobuf();
  2353. test_commalist();
  2354. test_base64();
  2355. test_http_get_var();
  2356. test_tls();
  2357. test_ws();
  2358. test_ws_fragmentation();
  2359. test_http_client();
  2360. test_http_server();
  2361. test_http_404();
  2362. test_http_no_content_length();
  2363. test_http_pipeline();
  2364. test_http_range();
  2365. test_sntp();
  2366. test_mqtt();
  2367. printf("SUCCESS. Total tests: %d\n", s_num_tests);
  2368. return EXIT_SUCCESS;
  2369. }