unit_test.c 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295
  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. // Self-signed CA, CERT, KEY
  15. const char *s_tls_ca =
  16. "-----BEGIN CERTIFICATE-----\n"
  17. "MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw\n"
  18. "RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
  19. "YTESMBAGA1UEAwwJVGVzdCBSb290MCAXDTIwMDUwOTIxNTE0NFoYDzIwNTAwNTA5\n"
  20. "MjE1MTQ0WjBEMQswCQYDVQQGEwJJRTEPMA0GA1UEBwwGRHVibGluMRAwDgYDVQQK\n"
  21. "DAdDZXNhbnRhMRIwEAYDVQQDDAlUZXN0IFJvb3QwWTATBgcqhkjOPQIBBggqhkjO\n"
  22. "PQMBBwNCAAQsq9ECZiSW1xI+CVBP8VDuUehVA166sR2YsnJ5J6gbMQ1dUCH/QvLa\n"
  23. "dBdeU7JlQcH8hN5KEbmM9BnZxMor6ussox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud\n"
  24. "DwQEAwIBrjAKBggqhkjOPQQDAgNJADBGAiEAnHFsAIwGQQyRL81B04dH6d86Iq0l\n"
  25. "fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==\n"
  26. "-----END CERTIFICATE-----\n";
  27. const char *s_tls_cert =
  28. "-----BEGIN CERTIFICATE-----\n"
  29. "MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw\n"
  30. "RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
  31. "YTESMBAGA1UEAwwJVGVzdCBSb290MB4XDTIwMDUwOTIxNTE0OVoXDTMwMDUwOTIx\n"
  32. "NTE0OVowETEPMA0GA1UEAwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n"
  33. "QgAEkuBGnInDN6l06zVVQ1VcrOvH5FDu9MC6FwJc2e201P8hEpq0Q/SJS2nkbSuW\n"
  34. "H/wBTTBaeXN2uhlBzMUWK790KKMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gw\n"
  35. "EwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDSQAwRgIhAPo6xx7LjCdZ\n"
  36. "QY133XvLjAgVFrlucOZHONFVQuDXZsjwAiEAzHBNligA08c5U3SySYcnkhurGg50\n"
  37. "BllCI0eYQ9ggp/o=\n"
  38. "-----END CERTIFICATE-----\n";
  39. const char *s_tls_key =
  40. "-----BEGIN PRIVATE KEY-----\n"
  41. "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w\n"
  42. "kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70\n"
  43. "wLoXAlzZ7bTU/yESmrRD9IlLaeRtK5Yf/AFNMFp5c3a6GUHMxRYrv3Qo\n"
  44. "-----END PRIVATE KEY-----\n";
  45. // Important: we use different port numbers for the Windows bug workaround. See
  46. // https://support.microsoft.com/en-ae/help/3039044/error-10013-wsaeacces-is-returned-when-a-second-bind-to-a-excluded-por
  47. static void test_globmatch(void) {
  48. ASSERT(mg_globmatch("", 0, "", 0) == 1);
  49. ASSERT(mg_globmatch("*", 1, "a", 1) == 1);
  50. ASSERT(mg_globmatch("*", 1, "ab", 2) == 1);
  51. ASSERT(mg_globmatch("", 0, "a", 1) == 0);
  52. ASSERT(mg_globmatch("/", 1, "/foo", 4) == 0);
  53. ASSERT(mg_globmatch("/*/foo", 6, "/x/bar", 6) == 0);
  54. ASSERT(mg_globmatch("/*/foo", 6, "/x/foo", 6) == 1);
  55. ASSERT(mg_globmatch("/*/foo", 6, "/x/foox", 7) == 0);
  56. ASSERT(mg_globmatch("/*/foo*", 7, "/x/foox", 7) == 1);
  57. ASSERT(mg_globmatch("/*", 2, "/abc", 4) == 1);
  58. ASSERT(mg_globmatch("/*", 2, "/ab/", 4) == 0);
  59. ASSERT(mg_globmatch("/*", 2, "/", 1) == 1);
  60. ASSERT(mg_globmatch("/x/*", 4, "/x/2", 4) == 1);
  61. ASSERT(mg_globmatch("/x/*", 4, "/x/2/foo", 8) == 0);
  62. ASSERT(mg_globmatch("/x/*/*", 6, "/x/2/foo", 8) == 1);
  63. ASSERT(mg_globmatch("#", 1, "///", 3) == 1);
  64. ASSERT(mg_globmatch("/api/*", 6, "/api/foo", 8) == 1);
  65. ASSERT(mg_globmatch("/api/*", 6, "/api/log/static", 15) == 0);
  66. ASSERT(mg_globmatch("/api/#", 6, "/api/log/static", 15) == 1);
  67. ASSERT(mg_globmatch("#.shtml", 7, "/ssi/index.shtml", 16) == 1);
  68. ASSERT(mg_globmatch("#.c", 3, ".c", 2) == 1);
  69. ASSERT(mg_globmatch("abc", 3, "ab", 2) == 0);
  70. ASSERT(mg_globmatch("#.c", 3, "a.c", 3) == 1);
  71. ASSERT(mg_globmatch("#.c", 3, "..c", 3) == 1);
  72. ASSERT(mg_globmatch("#.c", 3, "/.c", 3) == 1);
  73. ASSERT(mg_globmatch("#.c", 3, "//a.c", 5) == 1);
  74. ASSERT(mg_globmatch("#.c", 3, "x/a.c", 5) == 1);
  75. ASSERT(mg_globmatch("#.c", 3, "./a.c", 5) == 1);
  76. ASSERT(mg_globmatch("#.shtml", 7, "./ssi/index.shtml", 17) == 1);
  77. ASSERT(mg_globmatch("#aa#bb#", 7, "caabba", 6) == 1);
  78. ASSERT(mg_globmatch("#aa#bb#", 7, "caabxa", 6) == 0);
  79. ASSERT(mg_globmatch("a*b*c", 5, "a__b_c", 6) == 1);
  80. {
  81. struct mg_str caps[3];
  82. ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
  83. ASSERT(mg_match(mg_str("a"), mg_str("#"), caps) == true);
  84. ASSERT(mg_strcmp(caps[0], mg_str("a")) == 0);
  85. ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), caps) == true);
  86. ASSERT(mg_match(mg_str("a_b_c_"), mg_str("a*b*c"), caps) == false);
  87. ASSERT(mg_match(mg_str("a__b_c"), mg_str("a*b*c"), caps) == true);
  88. ASSERT(mg_strcmp(caps[0], mg_str("__")) == 0);
  89. ASSERT(mg_strcmp(caps[1], mg_str("_")) == 0);
  90. ASSERT(mg_match(mg_str("a_b_c__c"), mg_str("a*b*c"), caps) == true);
  91. ASSERT(mg_strcmp(caps[0], mg_str("_")) == 0);
  92. ASSERT(mg_strcmp(caps[1], mg_str("_c__")) == 0);
  93. ASSERT(mg_match(mg_str("a_xb_.c__c"), mg_str("a*b*c"), caps) == true);
  94. ASSERT(mg_strcmp(caps[0], mg_str("_x")) == 0);
  95. ASSERT(mg_strcmp(caps[1], mg_str("_.c__")) == 0);
  96. ASSERT(mg_match(mg_str("a"), mg_str("#a"), caps) == true);
  97. ASSERT(mg_strcmp(caps[0], mg_str("")) == 0);
  98. ASSERT(mg_match(mg_str(".aa..b...b"), mg_str("#a#b"), caps) == true);
  99. ASSERT(mg_strcmp(caps[0], mg_str(".")) == 0);
  100. ASSERT(mg_strcmp(caps[1], mg_str("a..b...")) == 0);
  101. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  102. ASSERT(mg_match(mg_str("/foo/bar"), mg_str("/*/*"), caps) == true);
  103. ASSERT(mg_strcmp(caps[0], mg_str("foo")) == 0);
  104. ASSERT(mg_strcmp(caps[1], mg_str("bar")) == 0);
  105. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  106. ASSERT(mg_match(mg_str("/foo/"), mg_str("/*/*"), caps) == true);
  107. ASSERT(mg_strcmp(caps[0], mg_str("foo")) == 0);
  108. ASSERT(mg_strcmp(caps[1], mg_str("")) == 0);
  109. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  110. ASSERT(mg_match(mg_str("abc"), mg_str("?#"), caps) == true);
  111. ASSERT(mg_strcmp(caps[0], mg_str("a")) == 0);
  112. ASSERT(mg_strcmp(caps[1], mg_str("bc")) == 0);
  113. ASSERT(mg_strcmp(caps[2], mg_str("")) == 0);
  114. }
  115. }
  116. static void test_commalist(void) {
  117. struct mg_str k, v, s1 = mg_str(""), s2 = mg_str("a"), s3 = mg_str("a,b");
  118. struct mg_str s4 = mg_str("a=123"), s5 = mg_str("a,b=123");
  119. ASSERT(mg_commalist(&s1, &k, &v) == false);
  120. v.len = k.len = 42;
  121. ASSERT(mg_commalist(&s2, &k, &v) == true);
  122. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  123. ASSERT(mg_commalist(&s2, &k, &v) == false);
  124. v.len = k.len = 42;
  125. ASSERT(mg_commalist(&s3, &k, &v) == true);
  126. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  127. v.len = k.len = 42;
  128. ASSERT(mg_commalist(&s3, &k, &v) == true);
  129. ASSERT(v.len == 0 && mg_vcmp(&k, "b") == 0);
  130. ASSERT(mg_commalist(&s3, &k, &v) == false);
  131. v.len = k.len = 42;
  132. ASSERT(mg_commalist(&s4, &k, &v) == true);
  133. ASSERT(mg_vcmp(&k, "a") == 0 && mg_vcmp(&v, "123") == 0);
  134. ASSERT(mg_commalist(&s4, &k, &v) == false);
  135. ASSERT(mg_commalist(&s4, &k, &v) == false);
  136. v.len = k.len = 42;
  137. ASSERT(mg_commalist(&s5, &k, &v) == true);
  138. ASSERT(v.len == 0 && mg_vcmp(&k, "a") == 0);
  139. ASSERT(mg_commalist(&s5, &k, &v) == true);
  140. ASSERT(mg_vcmp(&k, "b") == 0 && mg_vcmp(&v, "123") == 0);
  141. ASSERT(mg_commalist(&s4, &k, &v) == false);
  142. }
  143. static void test_http_get_var(void) {
  144. char buf[256];
  145. struct mg_str body;
  146. body = mg_str("key1=value1&key2=value2&key3=value%203&key4=value+4");
  147. ASSERT(mg_http_get_var(&body, "key1", buf, sizeof(buf)) == 6);
  148. ASSERT(strcmp(buf, "value1") == 0);
  149. ASSERT(mg_http_get_var(&body, "KEY1", buf, sizeof(buf)) == 6);
  150. ASSERT(strcmp(buf, "value1") == 0);
  151. ASSERT(mg_http_get_var(&body, "key2", buf, sizeof(buf)) == 6);
  152. ASSERT(strcmp(buf, "value2") == 0);
  153. ASSERT(mg_http_get_var(&body, "key3", buf, sizeof(buf)) == 7);
  154. ASSERT(strcmp(buf, "value 3") == 0);
  155. ASSERT(mg_http_get_var(&body, "key4", buf, sizeof(buf)) == 7);
  156. ASSERT(strcmp(buf, "value 4") == 0);
  157. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -4);
  158. ASSERT(mg_http_get_var(&body, "key1", NULL, sizeof(buf)) == -2);
  159. ASSERT(mg_http_get_var(&body, "key1", buf, 0) == -2);
  160. ASSERT(mg_http_get_var(&body, NULL, buf, sizeof(buf)) == -1);
  161. ASSERT(mg_http_get_var(&body, "key1", buf, 1) == -3);
  162. body = mg_str("key=broken%2");
  163. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  164. body = mg_str("key=broken%2x");
  165. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  166. ASSERT(mg_http_get_var(&body, "inexistent", buf, sizeof(buf)) == -4);
  167. body = mg_str("key=%");
  168. ASSERT(mg_http_get_var(&body, "key", buf, sizeof(buf)) == -3);
  169. body = mg_str("&&&kEy=%");
  170. ASSERT(mg_http_get_var(&body, "kEy", buf, sizeof(buf)) == -3);
  171. }
  172. static int vcmp(struct mg_str s1, const char *s2) {
  173. // MG_INFO(("->%.*s<->%s<- %d %d %d", (int) s1.len, s1.ptr, s2,
  174. //(int) s1.len, strncmp(s1.ptr, s2, s1.len), mg_vcmp(&s1, s2)));
  175. return mg_vcmp(&s1, s2) == 0;
  176. }
  177. static void test_url(void) {
  178. // Host
  179. ASSERT(vcmp(mg_url_host("foo"), "foo"));
  180. ASSERT(vcmp(mg_url_host("//foo"), "foo"));
  181. ASSERT(vcmp(mg_url_host("foo:1234"), "foo"));
  182. ASSERT(vcmp(mg_url_host(":1234"), ""));
  183. ASSERT(vcmp(mg_url_host("//foo:1234"), "foo"));
  184. ASSERT(vcmp(mg_url_host("p://foo"), "foo"));
  185. ASSERT(vcmp(mg_url_host("p://foo/"), "foo"));
  186. ASSERT(vcmp(mg_url_host("p://foo/x"), "foo"));
  187. ASSERT(vcmp(mg_url_host("p://foo/x/"), "foo"));
  188. ASSERT(vcmp(mg_url_host("p://foo/x//"), "foo"));
  189. ASSERT(vcmp(mg_url_host("p://foo//x"), "foo"));
  190. ASSERT(vcmp(mg_url_host("p://foo///x"), "foo"));
  191. ASSERT(vcmp(mg_url_host("p://foo///x//"), "foo"));
  192. ASSERT(vcmp(mg_url_host("p://bar:1234"), "bar"));
  193. ASSERT(vcmp(mg_url_host("p://bar:1234/"), "bar"));
  194. ASSERT(vcmp(mg_url_host("p://bar:1234/a"), "bar"));
  195. ASSERT(vcmp(mg_url_host("p://u@bar:1234/a"), "bar"));
  196. ASSERT(vcmp(mg_url_host("p://u:p@bar:1234/a"), "bar"));
  197. ASSERT(vcmp(mg_url_host("p://u:p@[::1]:1234/a"), "[::1]"));
  198. ASSERT(vcmp(mg_url_host("p://u:p@[1:2::3]:1234/a"), "[1:2::3]"));
  199. ASSERT(vcmp(mg_url_host("p://foo/x:y/z"), "foo"));
  200. // Port
  201. ASSERT(mg_url_port("foo:1234") == 1234);
  202. ASSERT(mg_url_port(":1234") == 1234);
  203. ASSERT(mg_url_port("x://foo:1234") == 1234);
  204. ASSERT(mg_url_port("x://foo:1234/") == 1234);
  205. ASSERT(mg_url_port("x://foo:1234/xx") == 1234);
  206. ASSERT(mg_url_port("x://foo:1234") == 1234);
  207. ASSERT(mg_url_port("p://bar:1234/a") == 1234);
  208. ASSERT(mg_url_port("p://bar:1234/a:b") == 1234);
  209. ASSERT(mg_url_port("http://bar") == 80);
  210. ASSERT(mg_url_port("http://localhost:1234") == 1234);
  211. ASSERT(mg_url_port("https://bar") == 443);
  212. ASSERT(mg_url_port("wss://bar") == 443);
  213. ASSERT(mg_url_port("wss://u:p@bar") == 443);
  214. ASSERT(mg_url_port("wss://u:p@bar:123") == 123);
  215. ASSERT(mg_url_port("wss://u:p@bar:123/") == 123);
  216. ASSERT(mg_url_port("wss://u:p@bar:123/abc") == 123);
  217. ASSERT(mg_url_port("http://u:p@[::1]/abc") == 80);
  218. ASSERT(mg_url_port("http://u:p@[::1]:2121/abc") == 2121);
  219. ASSERT(mg_url_port("http://u:p@[::1]:2121/abc/cd:ef") == 2121);
  220. // User / pass
  221. ASSERT(vcmp(mg_url_user("p://foo"), ""));
  222. ASSERT(vcmp(mg_url_pass("p://foo"), ""));
  223. ASSERT(vcmp(mg_url_user("p://:@foo"), ""));
  224. ASSERT(vcmp(mg_url_pass("p://:@foo"), ""));
  225. ASSERT(vcmp(mg_url_user("p://u@foo"), "u"));
  226. ASSERT(vcmp(mg_url_pass("p://u@foo"), ""));
  227. ASSERT(vcmp(mg_url_user("p://u:@foo"), "u"));
  228. ASSERT(vcmp(mg_url_pass("p://u:@foo"), ""));
  229. ASSERT(vcmp(mg_url_user("p://:p@foo"), ""));
  230. ASSERT(vcmp(mg_url_pass("p://:p@foo"), "p"));
  231. ASSERT(vcmp(mg_url_user("p://u:p@foo"), "u"));
  232. ASSERT(vcmp(mg_url_pass("p://u:p@foo"), "p"));
  233. ASSERT(vcmp(mg_url_pass("p://u:p@foo//a@b"), "p"));
  234. ASSERT(vcmp(mg_url_user("p://foo/q?mail=a@b.c"), ""));
  235. ASSERT(vcmp(mg_url_pass("p://foo/q?mail=a@b.c"), ""));
  236. // URI
  237. ASSERT(strcmp(mg_url_uri("p://foo"), "/") == 0);
  238. ASSERT(strcmp(mg_url_uri("p://foo/"), "/") == 0);
  239. ASSERT(strcmp(mg_url_uri("p://foo:12/"), "/") == 0);
  240. ASSERT(strcmp(mg_url_uri("p://foo:12/abc"), "/abc") == 0);
  241. ASSERT(strcmp(mg_url_uri("p://foo:12/a/b/c"), "/a/b/c") == 0);
  242. ASSERT(strcmp(mg_url_uri("p://[::1]:12/a/b/c"), "/a/b/c") == 0);
  243. ASSERT(strcmp(mg_url_uri("p://[ab::1]:12/a/b/c"), "/a/b/c") == 0);
  244. ASSERT(strcmp(mg_url_uri("p://foo/q?mail=a@b.c"), "/q?mail=a@b.c") == 0);
  245. }
  246. static void test_base64(void) {
  247. char buf[128];
  248. ASSERT(mg_base64_encode((uint8_t *) "", 0, buf, sizeof(buf)) == 0);
  249. ASSERT(strcmp(buf, "") == 0);
  250. ASSERT(mg_base64_encode((uint8_t *) "x", 1, buf, sizeof(buf)) == 4);
  251. ASSERT(strcmp(buf, "eA==") == 0);
  252. ASSERT(mg_base64_encode((uint8_t *) "xyz", 3, buf, sizeof(buf)) == 4);
  253. ASSERT(strcmp(buf, "eHl6") == 0);
  254. ASSERT(mg_base64_encode((uint8_t *) "abcdef", 6, buf, sizeof(buf)) == 8);
  255. ASSERT(strcmp(buf, "YWJjZGVm") == 0);
  256. ASSERT(mg_base64_encode((uint8_t *) "ы", 2, buf, sizeof(buf)) == 4);
  257. ASSERT(strcmp(buf, "0Ys=") == 0);
  258. ASSERT(mg_base64_encode((uint8_t *) "xy", 3, buf, sizeof(buf)) == 4);
  259. ASSERT(strcmp(buf, "eHkA") == 0);
  260. ASSERT(mg_base64_encode((uint8_t *) "test", 4, buf, sizeof(buf)) == 8);
  261. ASSERT(strcmp(buf, "dGVzdA==") == 0);
  262. ASSERT(mg_base64_encode((uint8_t *) "abcde", 5, buf, sizeof(buf)) == 8);
  263. ASSERT(strcmp(buf, "YWJjZGU=") == 0);
  264. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 0) == 0);
  265. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 1) == 0);
  266. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 2) == 0);
  267. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 3) == 0);
  268. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 4) == 0);
  269. ASSERT(mg_base64_encode((uint8_t *) "a", 1, buf, 5) == 4);
  270. ASSERT(mg_base64_decode("кю", 4, buf, sizeof(buf)) == 0);
  271. ASSERT(mg_base64_decode("A", 1, buf, sizeof(buf)) == 0);
  272. ASSERT(mg_base64_decode("A=", 2, buf, sizeof(buf)) == 0);
  273. ASSERT(mg_base64_decode("AA=", 3, buf, sizeof(buf)) == 0);
  274. ASSERT(mg_base64_decode("AAA=", 4, buf, sizeof(buf)) == 2);
  275. ASSERT(mg_base64_decode("AAAA====", 8, buf, sizeof(buf)) == 0);
  276. ASSERT(mg_base64_decode("AAAA----", 8, buf, sizeof(buf)) == 0);
  277. ASSERT(mg_base64_decode("Q2VzYW50YQ==", 12, buf, sizeof(buf)) == 7);
  278. ASSERT(strcmp(buf, "Cesanta") == 0);
  279. ASSERT(mg_base64_decode("AAA=", 4, buf, 0) == 0);
  280. ASSERT(mg_base64_decode("AAA=", 4, buf, 1) == 0);
  281. ASSERT(mg_base64_decode("AAA=", 4, buf, 2) == 0);
  282. ASSERT(mg_base64_decode("AAA=", 4, buf, 3) == 0);
  283. ASSERT(mg_base64_decode("AAA=", 4, buf, 4) == 2);
  284. }
  285. static void test_iobuf(void) {
  286. struct mg_iobuf io = {0, 0, 0, 10};
  287. ASSERT(io.buf == NULL && io.size == 0 && io.len == 0);
  288. mg_iobuf_resize(&io, 1);
  289. ASSERT(io.buf != NULL && io.size == 10 && io.len == 0);
  290. ASSERT(memcmp(io.buf, "\x00", 1) == 0);
  291. mg_iobuf_add(&io, 3, "hi", 2);
  292. ASSERT(io.buf != NULL && io.size == 10 && io.len == 5);
  293. ASSERT(memcmp(io.buf, "\x00\x00\x00hi", 5) == 0);
  294. mg_iobuf_add(&io, io.len, "!", 1);
  295. ASSERT(io.buf != NULL && io.size == 10 && io.len == 6);
  296. ASSERT(memcmp(io.buf, "\x00\x00\x00hi!", 6) == 0);
  297. mg_iobuf_add(&io, 0, "x", 1);
  298. ASSERT(memcmp(io.buf, "x\x00\x00\x00hi!", 7) == 0);
  299. ASSERT(io.buf != NULL && io.size == 10 && io.len == 7);
  300. mg_iobuf_del(&io, 1, 3);
  301. ASSERT(io.buf != NULL && io.size == 10 && io.len == 4);
  302. ASSERT(memcmp(io.buf, "xhi!", 3) == 0);
  303. mg_iobuf_del(&io, 10, 100);
  304. ASSERT(io.buf != NULL && io.size == 10 && io.len == 4);
  305. ASSERT(memcmp(io.buf, "xhi!", io.len) == 0);
  306. mg_iobuf_add(&io, io.len, "123456", 6);
  307. ASSERT(io.buf != NULL && io.size == 10 && io.len == 10);
  308. mg_iobuf_add(&io, io.len, "a", 1);
  309. ASSERT(io.buf != NULL && io.size == 20 && io.len == 11);
  310. ASSERT(memcmp(io.buf, "xhi!123456a", io.len) == 0);
  311. mg_iobuf_free(&io);
  312. }
  313. static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) {
  314. if (ev == MG_EV_SNTP_TIME) {
  315. int64_t received = *(int64_t *) ev_data;
  316. *(int64_t *) c->fn_data = received;
  317. MG_DEBUG(("got time: %lld", received));
  318. #if MG_ARCH == MG_ARCH_UNIX
  319. struct timeval tv = {0, 0};
  320. gettimeofday(&tv, 0);
  321. int64_t ms = (int64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
  322. int64_t diff = ms > received ? ms - received : received - ms;
  323. MG_DEBUG(("diff: %lld", diff));
  324. // ASSERT(diff < 100);
  325. #endif
  326. } else if (ev == MG_EV_OPEN) {
  327. c->is_hexdumping = 1;
  328. }
  329. (void) c;
  330. }
  331. static void test_sntp_server(const char *url) {
  332. int64_t ms = 0;
  333. struct mg_mgr mgr;
  334. struct mg_connection *c = NULL;
  335. int i;
  336. mg_mgr_init(&mgr);
  337. c = mg_sntp_connect(&mgr, url, sntp_cb, &ms);
  338. ASSERT(c != NULL);
  339. ASSERT(c->is_udp == 1);
  340. for (i = 0; i < 60 && ms == 0; i++) mg_mgr_poll(&mgr, 50);
  341. MG_DEBUG(("server: %s, ms: %lld", url ? url : "(default)", ms));
  342. #if !defined(NO_SNTP_CHECK)
  343. ASSERT(ms > 0);
  344. #endif
  345. mg_mgr_free(&mgr);
  346. }
  347. static void test_sntp(void) {
  348. const unsigned char bad[] =
  349. "\x55\x02\x00\xeb\x00\x00\x00\x1e\x00\x00\x07\xb6\x3e\xc9\xd6\xa2"
  350. "\xdb\xde\xea\x30\x91\x86\xb7\x10\xdb\xde\xed\x98\x00\x00\x00\xde"
  351. "\xdb\xde\xed\x99\x0a\xe2\xc7\x96\xdb\xde\xed\x99\x0a\xe4\x6b\xda";
  352. ASSERT(mg_sntp_parse(bad, sizeof(bad)) < 0);
  353. ASSERT(mg_sntp_parse(NULL, 0) == -1);
  354. // NOTE(cpq): temporarily disabled until Github Actions fix their NTP
  355. // port blockage issue, https://github.com/actions/runner-images/issues/5615
  356. // test_sntp_server("udp://time.apple.com:123");
  357. test_sntp_server("udp://time.windows.com:123");
  358. test_sntp_server(NULL);
  359. }
  360. struct mqtt_data {
  361. char *topic;
  362. char *msg;
  363. size_t topicsize;
  364. size_t msgsize;
  365. int flags;
  366. };
  367. #define flags_subscribed (1 << 0)
  368. #define flags_published (1 << 1)
  369. #define flags_received (1 << 2)
  370. #define flags_released (1 << 3)
  371. #define flags_completed (1 << 4)
  372. static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
  373. struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data;
  374. char *buf = test_data->msg;
  375. if (ev == MG_EV_MQTT_OPEN) {
  376. buf[0] = *(int *) ev_data == 0 ? 'X' : 'Y';
  377. } else if (ev == MG_EV_CLOSE) {
  378. buf[0] = 0;
  379. } else if (ev == MG_EV_MQTT_CMD) {
  380. struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
  381. if (mm->cmd == MQTT_CMD_SUBACK) {
  382. test_data->flags = flags_subscribed;
  383. } else if (mm->cmd == MQTT_CMD_PUBACK) { // here we assume the broker
  384. test_data->flags = flags_published; // reported no errors,
  385. } else if (mm->cmd == MQTT_CMD_PUBREC) { // either no var header or
  386. test_data->flags |= flags_received; // reason code 0x00
  387. } else if (mm->cmd == MQTT_CMD_PUBREL) {
  388. test_data->flags |= flags_released;
  389. } else if (mm->cmd == MQTT_CMD_PUBCOMP) {
  390. test_data->flags |= flags_completed;
  391. }
  392. } else if (ev == MG_EV_MQTT_MSG) {
  393. struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
  394. snprintf(test_data->topic, test_data->topicsize, "%.*s",
  395. (int) mm->topic.len, mm->topic.ptr);
  396. snprintf(buf + 1, test_data->msgsize - 2, "%.*s", (int) mm->data.len,
  397. mm->data.ptr);
  398. if (mm->cmd == MQTT_CMD_PUBLISH && c->is_mqtt5) {
  399. size_t pos = 0;
  400. struct mg_mqtt_prop prop;
  401. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
  402. ASSERT(prop.iv == 10 && prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL);
  403. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
  404. ASSERT(prop.id == MQTT_PROP_PAYLOAD_FORMAT_INDICATOR);
  405. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
  406. ASSERT(prop.id == MQTT_PROP_CONTENT_TYPE);
  407. ASSERT(strncmp(prop.val.ptr, "test_content_val_2", prop.val.len) == 0 &&
  408. prop.val.len == strlen("test_content_val_2"));
  409. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
  410. ASSERT(prop.id == MQTT_PROP_USER_PROPERTY);
  411. ASSERT(strncmp(prop.key.ptr, "test_key_1", prop.key.len) == 0 &&
  412. prop.key.len == strlen("test_key_1"));
  413. ASSERT(strncmp(prop.val.ptr, "test_value_1", prop.val.len) == 0 &&
  414. prop.val.len == strlen("test_value_1"));
  415. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
  416. ASSERT(prop.id == MQTT_PROP_USER_PROPERTY);
  417. ASSERT(strncmp(prop.key.ptr, "test_key_2", prop.key.len) == 0 &&
  418. prop.key.len == strlen("test_key_2"));
  419. ASSERT(strncmp(prop.val.ptr, "test_value_2", prop.val.len) == 0 &&
  420. prop.val.len == strlen("test_value_2"));
  421. ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) == 0);
  422. }
  423. }
  424. (void) c;
  425. }
  426. static void construct_props(struct mg_mqtt_prop *props) {
  427. props[0].id = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL;
  428. props[0].iv = 10;
  429. props[1].id = MQTT_PROP_USER_PROPERTY;
  430. props[1].key = mg_str("test_key_1");
  431. props[1].val = mg_str("test_value_1");
  432. props[2].id = MQTT_PROP_USER_PROPERTY;
  433. props[2].key = mg_str("test_key_2");
  434. props[2].val = mg_str("test_value_2");
  435. props[3].id = MQTT_PROP_CONTENT_TYPE;
  436. props[3].val = mg_str("test_content_val_2");
  437. props[4].id = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR;
  438. props[4].iv = 1;
  439. }
  440. static void test_mqtt_base(void);
  441. static void test_mqtt_base(void) {
  442. char buf[10] = {0}; // we won't use it
  443. struct mqtt_data test_data = {buf, buf, 10, 10, 0};
  444. struct mg_mgr mgr;
  445. struct mg_connection *c;
  446. const char *url = "mqtt://broker.hivemq.com:1883";
  447. int i;
  448. mg_mgr_init(&mgr);
  449. // Ping the client
  450. c = mg_mqtt_connect(&mgr, url, NULL, mqtt_cb, &test_data);
  451. mg_mqtt_ping(c);
  452. for (i = 0; i < 300 && !(c->is_client && !c->is_connecting); i++)
  453. mg_mgr_poll(&mgr, 10);
  454. ASSERT(c->is_client && !c->is_connecting);
  455. mg_mgr_free(&mgr);
  456. ASSERT(mgr.conns == NULL);
  457. }
  458. static void check_mqtt_message(struct mg_mqtt_opts *opts,
  459. struct mqtt_data *data, bool enforce) {
  460. if (opts->topic.len != strlen(data->topic) ||
  461. strcmp(opts->topic.ptr, data->topic)) {
  462. MG_INFO(("TOPIC[%s]", data->topic));
  463. if (enforce) ASSERT(0);
  464. }
  465. if (*data->msg != 'X' || opts->message.len != (strlen(&data->msg[1])) ||
  466. strcmp(opts->message.ptr, &data->msg[1])) {
  467. MG_INFO(("MSG[%s]", data->msg));
  468. if (enforce) ASSERT(0);
  469. }
  470. }
  471. // generate a random string ending in three digits taken from current time
  472. static struct mg_str genstring(char *t, unsigned int sz) {
  473. mg_random_str(t, sz - 3);
  474. snprintf(t + sz - 4, 4, "%03u", (unsigned int) mg_millis() % 1000);
  475. return mg_str(t);
  476. }
  477. static void test_mqtt_basic(void) {
  478. char tbuf[16], mbuf[50] = {0}, topic[16];
  479. struct mqtt_data test_data = {tbuf, mbuf, 16, 50, 0};
  480. struct mg_mgr mgr;
  481. struct mg_connection *c;
  482. struct mg_mqtt_opts opts;
  483. const char *url = "mqtt://broker.hivemq.com:1883";
  484. int i, retries;
  485. // Connect with empty client ID, no options, ergo MQTT = 3.1.1
  486. mg_mgr_init(&mgr);
  487. c = mg_mqtt_connect(&mgr, url, NULL, mqtt_cb, &test_data);
  488. for (i = 0; i < 300 && mbuf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
  489. if (mbuf[0] != 'X') MG_INFO(("[%s]", mbuf));
  490. ASSERT(mbuf[0] == 'X');
  491. ASSERT(test_data.flags == 0);
  492. // Subscribe with QoS1
  493. opts.topic = genstring(topic, sizeof(topic));
  494. opts.qos = 1;
  495. mg_mqtt_sub(c, &opts);
  496. for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
  497. ASSERT(test_data.flags == flags_subscribed);
  498. test_data.flags = 0;
  499. // Publish with QoS0 to subscribed topic and check reception
  500. // keep former opts.topic
  501. opts.message = mg_str("hi0"), opts.qos = 0, opts.retain = false;
  502. mg_mqtt_pub(c, &opts);
  503. for (i = 0; i < 500 && mbuf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  504. ASSERT(!(test_data.flags & flags_published)); // No PUBACK for QoS0
  505. check_mqtt_message(&opts, &test_data, false); // We may not get the msg
  506. memset(mbuf + 1, 0, sizeof(mbuf) - 1);
  507. test_data.flags = 0;
  508. // Publish with QoS1 to subscribed topic and check reception
  509. // keep former opts.topic
  510. opts.message = mg_str("hi1"), opts.qos = 1, opts.retain = false;
  511. retries = 0; // don't do retries for test speed
  512. do { // retry on failure after an expected timeout
  513. mg_mqtt_pub(c, &opts);
  514. for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
  515. } while (test_data.flags == 0 && retries--);
  516. ASSERT(test_data.flags == flags_published);
  517. for (i = 0; i < 500 && mbuf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  518. check_mqtt_message(&opts, &test_data, true);
  519. memset(mbuf + 1, 0, sizeof(mbuf) - 1);
  520. test_data.flags = 0;
  521. // Clean Disconnect !
  522. mg_mqtt_disconnect(c, NULL);
  523. for (i = 0; i < 10 && mbuf[0] != 0; i++) mg_mgr_poll(&mgr, 10);
  524. mg_mgr_free(&mgr);
  525. ASSERT(mgr.conns == NULL);
  526. }
  527. static void test_mqtt_ver(uint8_t mqtt_version) {
  528. char tbuf[16], mbuf[50] = {0}, client_id[16], topic[16];
  529. struct mqtt_data test_data = {tbuf, mbuf, 16, 50, 0};
  530. struct mg_mgr mgr;
  531. struct mg_connection *c;
  532. struct mg_mqtt_opts opts;
  533. struct mg_mqtt_prop properties[5];
  534. const char *url = "mqtt://broker.hivemq.com:1883";
  535. int i, retries;
  536. // Connect with options: version, clean session, last will, keepalive
  537. // time. Don't set retain, some runners are not random
  538. test_data.flags = 0;
  539. memset(mbuf, 0, sizeof(mbuf));
  540. memset(&opts, 0, sizeof(opts));
  541. mg_mgr_init(&mgr);
  542. opts.clean = true, opts.qos = 1, opts.retain = false, opts.keepalive = 20;
  543. opts.version = mqtt_version;
  544. opts.topic = genstring(topic, sizeof(topic));
  545. opts.message = mg_str("mg_will_messsage");
  546. opts.client_id = genstring(client_id, sizeof(client_id));
  547. c = mg_mqtt_connect(&mgr, url, &opts, mqtt_cb, &test_data);
  548. for (i = 0; i < 300 && mbuf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
  549. if (mbuf[0] != 'X') MG_INFO(("[%s]", mbuf));
  550. ASSERT(mbuf[0] == 'X');
  551. ASSERT(test_data.flags == 0);
  552. // Subscribe with QoS2 (reception downgrades to published QoS)
  553. opts.topic = genstring(topic, sizeof(topic));
  554. opts.qos = 2;
  555. mg_mqtt_sub(c, &opts);
  556. for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
  557. ASSERT(test_data.flags == flags_subscribed);
  558. test_data.flags = 0;
  559. // Publish with QoS1 to subscribed topic and check reception
  560. // keep former opts.topic
  561. opts.message = mg_str("hi1"), opts.qos = 1, opts.retain = false;
  562. if (mqtt_version == 5) {
  563. opts.props = properties;
  564. opts.num_props = 5;
  565. construct_props(properties);
  566. }
  567. retries = 0; // don't do retries for test speed
  568. do { // retry on failure after an expected timeout
  569. mg_mqtt_pub(c, &opts);
  570. for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
  571. } while (test_data.flags == 0 && retries--);
  572. ASSERT(test_data.flags == flags_published);
  573. for (i = 0; i < 500 && mbuf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  574. check_mqtt_message(&opts, &test_data, true);
  575. memset(mbuf + 1, 0, sizeof(mbuf) - 1);
  576. test_data.flags = 0;
  577. // Publish with QoS2 to subscribed topic and check (simultaneous) reception
  578. // keep former opts.topic
  579. opts.message = mg_str("hi2"), opts.qos = 2, opts.retain = false;
  580. if (mqtt_version == 5) {
  581. opts.props = properties;
  582. opts.num_props = 5;
  583. construct_props(properties);
  584. }
  585. retries = 0; // don't do retries for test speed
  586. do { // retry on failure after an expected timeout
  587. mg_mqtt_pub(c, &opts);
  588. for (i = 0; i < 500 && !(test_data.flags & flags_received); i++)
  589. mg_mgr_poll(&mgr, 10);
  590. } while (!(test_data.flags & flags_received) && retries--);
  591. ASSERT(test_data.flags & flags_received);
  592. test_data.flags &= ~flags_received;
  593. // Mongoose sent PUBREL, wait for PUBCOMP
  594. for (i = 0; i < 500 && !(test_data.flags & flags_completed); i++)
  595. mg_mgr_poll(&mgr, 10);
  596. // TODO(): retry sending PUBREL on failure after an expected timeout
  597. // or broker sends PUBREC again
  598. ASSERT(test_data.flags & flags_completed);
  599. for (i = 0; i < 500 && mbuf[1] == 0; i++) mg_mgr_poll(&mgr, 10);
  600. check_mqtt_message(&opts, &test_data, true);
  601. for (i = 0; i < 500 && !(test_data.flags & flags_released); i++)
  602. mg_mgr_poll(&mgr, 10);
  603. ASSERT(test_data.flags & flags_released); // Mongoose sent PUBCOMP
  604. memset(mbuf + 1, 0, sizeof(mbuf) - 1);
  605. test_data.flags = 0;
  606. // dirty disconnect
  607. mg_mgr_free(&mgr);
  608. ASSERT(mgr.conns == NULL);
  609. }
  610. static void test_mqtt(void) {
  611. test_mqtt_base();
  612. test_mqtt_basic();
  613. test_mqtt_ver(4);
  614. test_mqtt_ver(5);
  615. }
  616. static void eh1(struct mg_connection *c, int ev, void *ev_data) {
  617. struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data;
  618. if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
  619. if (ev == MG_EV_HTTP_MSG) {
  620. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  621. MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr,
  622. (int) hm->uri.len, hm->uri.ptr, (int) hm->message.len));
  623. if (mg_http_match_uri(hm, "/foo/*")) {
  624. mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.ptr + 5);
  625. } else if (mg_http_match_uri(hm, "/ws")) {
  626. mg_ws_upgrade(c, hm, NULL);
  627. } else if (mg_http_match_uri(hm, "/body")) {
  628. mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.ptr);
  629. } else if (mg_http_match_uri(hm, "/bar")) {
  630. mg_http_reply(c, 404, "", "not found");
  631. } else if (mg_http_match_uri(hm, "/no_reason")) {
  632. mg_printf(c, "%s", "HTTP/1.0 200\r\nContent-Length: 2\r\n\r\nok");
  633. } else if (mg_http_match_uri(hm, "/badroot")) {
  634. struct mg_http_serve_opts sopts;
  635. memset(&sopts, 0, sizeof(sopts));
  636. sopts.root_dir = "/BAAADDD!";
  637. mg_http_serve_dir(c, hm, &sopts);
  638. } else if (mg_http_match_uri(hm, "/creds")) {
  639. char user[100], pass[100];
  640. mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
  641. mg_http_reply(c, 200, "", "[%s]:[%s]", user, pass);
  642. } else if (mg_http_match_uri(hm, "/upload")) {
  643. char path[80], name[64];
  644. mg_http_get_var(&hm->query, "name", name, sizeof(name));
  645. mg_snprintf(path, sizeof(path), "./%s", name);
  646. if (name[0] == '\0') {
  647. mg_http_reply(c, 400, "", "%s", "name required");
  648. } else if (!mg_path_is_sane(path)) {
  649. mg_http_reply(c, 400, "", "%s", "invalid path");
  650. } else {
  651. mg_http_upload(c, hm, &mg_fs_posix, path, 99999);
  652. c->is_hexdumping = 1;
  653. }
  654. } else if (mg_http_match_uri(hm, "/test/")) {
  655. struct mg_http_serve_opts sopts;
  656. memset(&sopts, 0, sizeof(sopts));
  657. sopts.root_dir = ".";
  658. sopts.extra_headers = "A: B\r\nC: D\r\n";
  659. mg_http_serve_dir(c, hm, &sopts);
  660. } else if (mg_http_match_uri(hm, "/servefile")) {
  661. struct mg_http_serve_opts sopts;
  662. memset(&sopts, 0, sizeof(sopts));
  663. sopts.mime_types = "foo=a/b,txt=c/d";
  664. mg_http_serve_file(c, hm, "test/data/a.txt", &sopts);
  665. } else {
  666. struct mg_http_serve_opts sopts;
  667. memset(&sopts, 0, sizeof(sopts));
  668. sopts.root_dir = "./test/data";
  669. sopts.ssi_pattern = "#.shtml";
  670. sopts.extra_headers = "C: D\r\n";
  671. mg_http_serve_dir(c, hm, &sopts);
  672. }
  673. } else if (ev == MG_EV_WS_OPEN) {
  674. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  675. ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
  676. mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
  677. } else if (ev == MG_EV_WS_MSG) {
  678. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  679. mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_BINARY);
  680. }
  681. }
  682. struct fetch_data {
  683. char *buf;
  684. int code, closed;
  685. };
  686. static void fcb(struct mg_connection *c, int ev, void *ev_data) {
  687. struct fetch_data *fd = (struct fetch_data *) c->fn_data;
  688. if (ev == MG_EV_HTTP_MSG) {
  689. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  690. snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
  691. hm->message.ptr);
  692. fd->code = atoi(hm->uri.ptr);
  693. fd->closed = 1;
  694. c->is_closing = 1;
  695. (void) c;
  696. } else if (ev == MG_EV_CLOSE) {
  697. fd->closed = 1;
  698. }
  699. }
  700. static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
  701. const char *fmt, ...) {
  702. struct fetch_data fd = {buf, 0, 0};
  703. int i;
  704. struct mg_connection *c = NULL;
  705. va_list ap;
  706. c = mg_http_connect(mgr, url, fcb, &fd);
  707. ASSERT(c != NULL);
  708. if (c != NULL && mg_url_is_ssl(url)) {
  709. struct mg_tls_opts opts;
  710. memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
  711. opts.ca = mg_unpacked("test/data/ca.pem");
  712. if (strstr(url, "127.0.0.1") != NULL) {
  713. // Local connection, use self-signed certificates
  714. opts.ca = mg_str(s_tls_ca);
  715. // opts.cert = mg_str(s_tls_cert);
  716. // opts.key = mg_str(s_tls_key);
  717. }
  718. mg_tls_init(c, &opts);
  719. }
  720. // c->is_hexdumping = 1;
  721. va_start(ap, fmt);
  722. mg_vprintf(c, fmt, &ap);
  723. va_end(ap);
  724. buf[0] = '\0';
  725. for (i = 0; i < 50 && buf[0] == '\0'; i++) mg_mgr_poll(mgr, 1);
  726. if (!fd.closed) c->is_closing = 1;
  727. mg_mgr_poll(mgr, 1);
  728. return fd.code;
  729. }
  730. static struct mg_http_message gethm(const char *buf) {
  731. struct mg_http_message hm;
  732. memset(&hm, 0, sizeof(hm));
  733. mg_http_parse(buf, strlen(buf), &hm);
  734. return hm;
  735. }
  736. static int cmpbody(const char *buf, const char *str) {
  737. struct mg_str s = mg_str(str);
  738. struct mg_http_message hm = gethm(buf);
  739. size_t len = strlen(buf);
  740. // mg_http_parse(buf, len, &hm);
  741. if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.ptr - buf);
  742. return mg_strcmp(hm.body, s);
  743. }
  744. static bool cmpheader(const char *buf, const char *name, const char *value) {
  745. struct mg_http_message hm = gethm(buf);
  746. struct mg_str *h = mg_http_get_header(&hm, name);
  747. return h != NULL && mg_strcmp(*h, mg_str(value)) == 0;
  748. }
  749. static void wcb(struct mg_connection *c, int ev, void *ev_data) {
  750. int *p = (int *) c->fn_data;
  751. if (ev == MG_EV_WS_OPEN) {
  752. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  753. struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
  754. ASSERT(wsproto != NULL);
  755. mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%.3s", "boo!!!!");
  756. mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%s", "foobar");
  757. mg_ws_send(c, "", 0, WEBSOCKET_OP_PING);
  758. p[0] += 100;
  759. } else if (ev == MG_EV_WS_MSG) {
  760. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  761. if (mg_strstr(wm->data, mg_str("foobar")))
  762. mg_ws_send(c, "", 0, WEBSOCKET_OP_CLOSE);
  763. if (mg_strstr(wm->data, mg_str("boo"))) p[0] += 2;
  764. if (mg_strstr(wm->data, mg_str("foobar"))) p[0] += 3;
  765. } else if (ev == MG_EV_CLOSE) {
  766. p[0] += 10;
  767. }
  768. }
  769. static void ew2(struct mg_connection *c, int ev, void *ev_data) {
  770. size_t size = 65 * 1024 + 737;
  771. if (ev == MG_EV_WS_OPEN) {
  772. char *msg = (char *) calloc(1, size + 1);
  773. memset(msg, 'A', size);
  774. mg_ws_printf(c, WEBSOCKET_OP_TEXT, "%s", msg);
  775. free(msg);
  776. } else if (ev == MG_EV_WS_MSG) {
  777. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  778. if (wm->data.len == 6) {
  779. // Ignore the "opened" message from server
  780. } else {
  781. size_t ok = 1, i;
  782. ASSERT(wm->data.len == size);
  783. for (i = 0; i < size; i++) {
  784. if (wm->data.ptr[i] != 'A') ok = 0;
  785. }
  786. ASSERT(ok == 1);
  787. *(int *) c->fn_data = 1;
  788. }
  789. }
  790. }
  791. static void test_ws(void) {
  792. char buf[FETCH_BUF_SIZE];
  793. const char *url = "ws://LOCALHOST:12343/ws";
  794. struct mg_mgr mgr;
  795. int i, done = 0;
  796. mg_mgr_init(&mgr);
  797. ASSERT(mg_http_listen(&mgr, url, eh1, NULL) != NULL);
  798. mg_ws_connect(&mgr, url, wcb, &done, "%s", "Sec-WebSocket-Protocol: meh\r\n");
  799. for (i = 0; i < 30; i++) mg_mgr_poll(&mgr, 1);
  800. // MG_INFO(("--> %d", done));
  801. ASSERT(done == 115);
  802. // Test that non-WS requests fail
  803. ASSERT(fetch(&mgr, buf, url, "GET /ws HTTP/1.0\r\n\n") == 426);
  804. // Test large WS frames, over 64k
  805. done = 0;
  806. mg_ws_connect(&mgr, url, ew2, &done, NULL);
  807. for (i = 0; i < 1000 && done == 0; i++) mg_mgr_poll(&mgr, 1);
  808. ASSERT(done == 1);
  809. mg_mgr_free(&mgr);
  810. ASSERT(mgr.conns == NULL);
  811. }
  812. static void eh9(struct mg_connection *c, int ev, void *ev_data) {
  813. if (ev == MG_EV_ERROR) {
  814. ASSERT(!strcmp((char *) ev_data, "socket error"));
  815. *(int *) c->fn_data = 7;
  816. }
  817. (void) c;
  818. }
  819. static void test_http_server(void) {
  820. struct mg_mgr mgr;
  821. const char *url = "http://127.0.0.1:12346";
  822. char buf[FETCH_BUF_SIZE];
  823. mg_mgr_init(&mgr);
  824. mg_http_listen(&mgr, url, eh1, NULL);
  825. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  826. ASSERT(cmpbody(buf, "hello\n") == 0);
  827. // Invalid header: failure
  828. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nA B\n\n") == 0);
  829. ASSERT(fetch(&mgr, buf, url, "GET /%%61.txt HTTP/1.0\n\n") == 200);
  830. ASSERT(cmpbody(buf, "hello\n") == 0);
  831. // Responses with missing reason phrase must also work
  832. ASSERT(fetch(&mgr, buf, url, "GET /no_reason HTTP/1.0\n\n") == 200);
  833. ASSERT(cmpbody(buf, "ok") == 0);
  834. // Fetch file with unicode chars in filename
  835. ASSERT(fetch(&mgr, buf, url, "GET /київ.txt HTTP/1.0\n\n") == 200);
  836. MG_INFO(("%s", buf));
  837. ASSERT(cmpbody(buf, "є\n") == 0);
  838. ASSERT(fetch(&mgr, buf, url, "GET /../fuzz.c HTTP/1.0\n\n") == 400);
  839. ASSERT(fetch(&mgr, buf, url, "GET /.%%2e/fuzz.c HTTP/1.0\n\n") == 400);
  840. ASSERT(fetch(&mgr, buf, url, "GET /.%%2e%%2ffuzz.c HTTP/1.0\n\n") == 400);
  841. ASSERT(fetch(&mgr, buf, url, "GET /..%%2f%%20fuzz.c HTTP/1.0\n\n") == 400);
  842. ASSERT(fetch(&mgr, buf, url, "GET /..%%2ffuzz.c%%20 HTTP/1.0\n\n") == 400);
  843. ASSERT(fetch(&mgr, buf, url, "GET /dredir HTTP/1.0\n\n") == 301);
  844. ASSERT(cmpheader(buf, "Location", "/dredir/"));
  845. ASSERT(fetch(&mgr, buf, url, "GET /dredir/ HTTP/1.0\n\n") == 200);
  846. ASSERT(cmpbody(buf, "hi\n") == 0);
  847. ASSERT(fetch(&mgr, buf, url,
  848. "GET /dredirgz/ HTTP/1.0\n"
  849. "Accept-Encoding: gzip\n\n") == 200);
  850. ASSERT(cmpheader(buf, "Content-Type", "text/html; charset=utf-8"));
  851. ASSERT(cmpheader(buf, "Content-Encoding", "gzip"));
  852. ASSERT(fetch(&mgr, buf, url, "GET /gzip.txt HTTP/1.0\n\n") == 200);
  853. ASSERT(cmpbody(buf, "hi\n") == 0);
  854. ASSERT(gethm(buf).body.len == 3);
  855. ASSERT(cmpheader(buf, "Content-Encoding", "gzip") == false);
  856. ASSERT(fetch(&mgr, buf, url,
  857. "GET /gzip.txt HTTP/1.0\n"
  858. "Accept-Encoding: foo,gzip\n\n") == 200);
  859. mg_hexdump(buf, strlen(buf));
  860. ASSERT(cmpheader(buf, "Content-Encoding", "gzip") == true);
  861. ASSERT(gethm(buf).body.len == 23);
  862. ASSERT(fetch(&mgr, buf, url, "GET /..ddot HTTP/1.0\n\n") == 400);
  863. ASSERT(fetch(&mgr, buf, url, "GET /..ddot/ HTTP/1.0\n\n") == 400);
  864. ASSERT(fetch(&mgr, buf, url,
  865. "GET /a.txt HTTP/1.0\n"
  866. "Content-Length: -123\n\n") == 0);
  867. ASSERT(fetch(&mgr, buf, url,
  868. "POST /a.txt HTTP/1.0\n"
  869. "Content-Length: -123\n\n") == 0);
  870. ASSERT(fetch(&mgr, buf, url,
  871. "GET /a.txt HTTP/1.0\n"
  872. "Content-Length: 19000000000000000000\n\n") == 0);
  873. ASSERT(fetch(&mgr, buf, url,
  874. "POST /a.txt HTTP/1.0\n"
  875. "Content-Length: 19000000000000000000\n\n") == 0);
  876. ASSERT(fetch(&mgr, buf, url,
  877. "GET /a.txt HTTP/1.0\n"
  878. ":\n" // truncated header
  879. "Content-Length: 1\n\n") == 0);
  880. {
  881. extern char *mg_http_etag(char *, size_t, size_t, time_t);
  882. struct mg_http_message hm;
  883. char etag[100];
  884. size_t size = 0;
  885. time_t mtime = 0;
  886. ASSERT(mg_fs_posix.st("./test/data/a.txt", &size, &mtime) != 0);
  887. ASSERT(mg_http_etag(etag, sizeof(etag), size, mtime) == etag);
  888. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nIf-None-Match: %s\n\n",
  889. etag) == 304);
  890. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  891. MG_INFO(("%s", buf));
  892. ASSERT(mg_http_get_header(&hm, "C") != NULL);
  893. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "C"), mg_str("D")) == 0);
  894. }
  895. // Text mime type override
  896. ASSERT(fetch(&mgr, buf, url, "GET /servefile HTTP/1.0\n\n") == 200);
  897. ASSERT(cmpbody(buf, "hello\n") == 0);
  898. {
  899. struct mg_http_message hm;
  900. mg_http_parse(buf, strlen(buf), &hm);
  901. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  902. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"), mg_str("c/d")) ==
  903. 0);
  904. }
  905. ASSERT(fetch(&mgr, buf, url, "GET /foo/1 HTTP/1.0\r\n\n") == 200);
  906. // MG_INFO(("%d %.*s", (int) hm.len, (int) hm.len, hm.buf));
  907. ASSERT(cmpbody(buf, "uri: 1") == 0);
  908. ASSERT(fetch(&mgr, buf, url, "%s",
  909. "POST /body HTTP/1.1\r\n"
  910. "Content-Length: 4\r\n\r\nkuku") == 200);
  911. ASSERT(cmpbody(buf, "kuku") == 0);
  912. ASSERT(fetch(&mgr, buf, url, "GET /ssi HTTP/1.1\r\n\r\n") == 301);
  913. ASSERT(fetch(&mgr, buf, url, "GET /ssi/ HTTP/1.1\r\n\r\n") == 200);
  914. ASSERT(cmpbody(buf,
  915. "this is index\n"
  916. "this is nested\n\n"
  917. "this is f1\n\n\n\n"
  918. "recurse\n\n"
  919. "recurse\n\n"
  920. "recurse\n\n"
  921. "recurse\n\n"
  922. "recurse\n\n") == 0);
  923. {
  924. struct mg_http_message hm;
  925. mg_http_parse(buf, strlen(buf), &hm);
  926. ASSERT(mg_http_get_header(&hm, "Content-Length") != NULL);
  927. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  928. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"),
  929. mg_str("text/html; charset=utf-8")) == 0);
  930. }
  931. ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 404);
  932. // ASSERT(cmpbody(buf, "Invalid web root [/BAAADDD!]\n") == 0);
  933. {
  934. char *data = mg_file_read(&mg_fs_posix, "./test/data/ca.pem", NULL);
  935. ASSERT(fetch(&mgr, buf, url, "GET /ca.pem HTTP/1.0\r\n\n") == 200);
  936. ASSERT(cmpbody(buf, data) == 0);
  937. free(data);
  938. }
  939. {
  940. // Test mime type
  941. struct mg_http_message hm;
  942. ASSERT(fetch(&mgr, buf, url, "GET /empty.js HTTP/1.0\r\n\n") == 200);
  943. mg_http_parse(buf, strlen(buf), &hm);
  944. ASSERT(mg_http_get_header(&hm, "Content-Type") != NULL);
  945. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Type"),
  946. mg_str("text/javascript; charset=utf-8")) == 0);
  947. }
  948. {
  949. // Test connection refused
  950. int i, errored = 0;
  951. mg_connect(&mgr, "tcp://127.0.0.1:55117", eh9, &errored);
  952. // Give it a couple of seconds, see #1605
  953. for (i = 0; i < 200 && errored == 0; i++) mg_mgr_poll(&mgr, 10);
  954. MG_INFO(("errored: %d, expected: 7", errored));
  955. ASSERT(errored == 7);
  956. }
  957. // Directory listing
  958. fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n");
  959. ASSERT(fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n") == 200);
  960. ASSERT(mg_strstr(mg_str(buf), mg_str(">Index of /test/<")) != NULL);
  961. ASSERT(mg_strstr(mg_str(buf), mg_str(">fuzz.c<")) != NULL);
  962. {
  963. // Credentials
  964. struct mg_http_message hm;
  965. ASSERT(fetch(&mgr, buf, url, "%s",
  966. "GET /creds?access_token=x HTTP/1.0\r\n\r\n") == 200);
  967. mg_http_parse(buf, strlen(buf), &hm);
  968. ASSERT(mg_strcmp(hm.body, mg_str("[]:[x]")) == 0);
  969. ASSERT(fetch(&mgr, buf, url, "%s",
  970. "GET /creds HTTP/1.0\r\n"
  971. "Authorization: Bearer x\r\n\r\n") == 200);
  972. mg_http_parse(buf, strlen(buf), &hm);
  973. ASSERT(mg_strcmp(hm.body, mg_str("[]:[x]")) == 0);
  974. ASSERT(fetch(&mgr, buf, url, "%s",
  975. "GET /creds HTTP/1.0\r\n"
  976. "Authorization: Basic Zm9vOmJhcg==\r\n\r\n") == 200);
  977. mg_http_parse(buf, strlen(buf), &hm);
  978. ASSERT(mg_strcmp(hm.body, mg_str("[foo]:[bar]")) == 0);
  979. ASSERT(fetch(&mgr, buf, url, "%s",
  980. "GET /creds HTTP/1.0\r\n"
  981. "Cookie: blah; access_token=hello\r\n\r\n") == 200);
  982. mg_http_parse(buf, strlen(buf), &hm);
  983. ASSERT(mg_strcmp(hm.body, mg_str("[]:[hello]")) == 0);
  984. }
  985. {
  986. // Test upload
  987. char *p;
  988. remove("uploaded.txt");
  989. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
  990. ASSERT(fetch(&mgr, buf, url,
  991. "POST /upload HTTP/1.0\n"
  992. "Content-Length: 1\n\nx") == 400);
  993. ASSERT(fetch(&mgr, buf, url,
  994. "POST /upload?name=uploaded.txt HTTP/1.0\r\n"
  995. "Content-Length: 5\r\n"
  996. "\r\nhello") == 200);
  997. ASSERT(fetch(&mgr, buf, url,
  998. "POST /upload?name=uploaded.txt&offset=5 HTTP/1.0\r\n"
  999. "Content-Length: 6\r\n"
  1000. "\r\n\nworld") == 200);
  1001. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL);
  1002. ASSERT(strcmp(p, "hello\nworld") == 0);
  1003. free(p);
  1004. remove("uploaded.txt");
  1005. }
  1006. {
  1007. // Test upload directory traversal
  1008. char *p;
  1009. remove("uploaded.txt");
  1010. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL);
  1011. ASSERT(fetch(&mgr, buf, url,
  1012. "POST /upload?name=uploaded.txt HTTP/1.0\r\n"
  1013. "Content-Length: 5\r\n"
  1014. "\r\nhello") == 200);
  1015. ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL);
  1016. ASSERT(strcmp(p, "hello") == 0);
  1017. free(p);
  1018. remove("uploaded.txt");
  1019. }
  1020. // HEAD request
  1021. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  1022. ASSERT(fetch(&mgr, buf, url, "HEAD /a.txt HTTP/1.0\n\n") == 200);
  1023. // Pre-compressed files
  1024. {
  1025. struct mg_http_message hm;
  1026. ASSERT(fetch(&mgr, buf, url,
  1027. "HEAD /hello.txt HTTP/1.0\n"
  1028. "Accept-Encoding: gzip\n\n") == 200);
  1029. mg_http_parse(buf, strlen(buf), &hm);
  1030. ASSERT(mg_http_get_header(&hm, "Content-Encoding") != NULL);
  1031. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Encoding"),
  1032. mg_str("gzip")) == 0);
  1033. }
  1034. #if MG_ENABLE_IPV6
  1035. {
  1036. const char *url6 = "http://[::1]:12366";
  1037. ASSERT(mg_http_listen(&mgr, url6, eh1, NULL) != NULL);
  1038. ASSERT(fetch(&mgr, buf, url6, "GET /a.txt HTTP/1.0\n\n") == 200);
  1039. ASSERT(cmpbody(buf, "hello\n") == 0);
  1040. }
  1041. #endif
  1042. mg_mgr_free(&mgr);
  1043. ASSERT(mgr.conns == NULL);
  1044. }
  1045. static void h4(struct mg_connection *c, int ev, void *ev_data) {
  1046. if (ev == MG_EV_HTTP_MSG) {
  1047. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1048. MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr,
  1049. (int) hm->uri.len, hm->uri.ptr, (int) hm->message.len));
  1050. if (mg_http_match_uri(hm, "/a/#")) {
  1051. struct mg_http_serve_opts opts;
  1052. memset(&opts, 0, sizeof(opts));
  1053. opts.root_dir = "/a=./test/data";
  1054. opts.page404 = "./test/data/404.html"; // existing 404 page
  1055. mg_http_serve_dir(c, hm, &opts);
  1056. } else if (mg_http_match_uri(hm, "/b/#")) {
  1057. struct mg_http_serve_opts opts;
  1058. memset(&opts, 0, sizeof(opts));
  1059. opts.root_dir = "/b=./test/data";
  1060. opts.page404 = "./test/data/nooooo.html"; // non-existing 404 page
  1061. mg_http_serve_dir(c, hm, &opts);
  1062. } else { // null 404 page
  1063. struct mg_http_serve_opts opts;
  1064. memset(&opts, 0, sizeof(opts));
  1065. opts.root_dir = "./test/data";
  1066. mg_http_serve_dir(c, hm, &opts);
  1067. }
  1068. }
  1069. }
  1070. static void test_http_404(void) {
  1071. struct mg_mgr mgr;
  1072. const char *url = "http://127.0.0.1:22343";
  1073. char buf[FETCH_BUF_SIZE];
  1074. mg_mgr_init(&mgr);
  1075. mg_http_listen(&mgr, url, h4, NULL);
  1076. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  1077. ASSERT(cmpbody(buf, "hello\n") == 0);
  1078. ASSERT(fetch(&mgr, buf, url, "GET /a/a.txt HTTP/1.0\n\n") == 200);
  1079. ASSERT(cmpbody(buf, "hello\n") == 0);
  1080. ASSERT(fetch(&mgr, buf, url, "GET /b/a.txt HTTP/1.0\n\n") == 200);
  1081. ASSERT(cmpbody(buf, "hello\n") == 0);
  1082. ASSERT(fetch(&mgr, buf, url, "GET /xx.txt HTTP/1.0\n\n") == 404);
  1083. ASSERT(cmpbody(buf, "Not found\n") == 0);
  1084. ASSERT(fetch(&mgr, buf, url, "GET /a/xx.txt HTTP/1.0\n\n") == 200);
  1085. ASSERT(cmpbody(buf, "boo\n") == 0);
  1086. ASSERT(fetch(&mgr, buf, url, "GET /b/xx.txt HTTP/1.0\n\n") == 404);
  1087. ASSERT(cmpbody(buf, "Not found\n") == 0);
  1088. mg_mgr_free(&mgr);
  1089. ASSERT(mgr.conns == NULL);
  1090. }
  1091. static void test_tls(void) {
  1092. // return;
  1093. #if MG_TLS
  1094. struct mg_mgr mgr;
  1095. struct mg_connection *c;
  1096. const char *url = "https://127.0.0.1:12347";
  1097. char buf[FETCH_BUF_SIZE];
  1098. struct mg_tls_opts opts;
  1099. memset(&opts, 0, sizeof(opts));
  1100. // opts.ca = mg_str(s_tls_ca);
  1101. opts.cert = mg_str(s_tls_cert);
  1102. opts.key = mg_str(s_tls_key);
  1103. mg_mgr_init(&mgr);
  1104. c = mg_http_listen(&mgr, url, eh1, &opts);
  1105. ASSERT(c != NULL);
  1106. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  1107. // MG_INFO(("%s", buf));
  1108. ASSERT(cmpbody(buf, "hello\n") == 0);
  1109. mg_mgr_free(&mgr);
  1110. ASSERT(mgr.conns == NULL);
  1111. #endif
  1112. }
  1113. static void f3(struct mg_connection *c, int ev, void *ev_data) {
  1114. int *ok = (int *) c->fn_data;
  1115. // MG_INFO(("%d", ev));
  1116. if (ev == MG_EV_CONNECT) {
  1117. // c->is_hexdumping = 1;
  1118. mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
  1119. c->rem.is_ip6 ? "" : "/robots.txt",
  1120. c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com");
  1121. } else if (ev == MG_EV_HTTP_MSG) {
  1122. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1123. // MG_INFO(("-->[%.*s]", (int) hm->message.len, hm->message.ptr));
  1124. // ASSERT(mg_vcmp(&hm->method, "HTTP/1.1") == 0);
  1125. // ASSERT(mg_vcmp(&hm->uri, "301") == 0);
  1126. *ok = mg_http_status(hm);
  1127. } else if (ev == MG_EV_CLOSE) {
  1128. if (*ok == 0) *ok = 888;
  1129. } else if (ev == MG_EV_ERROR) {
  1130. if (*ok == 0) *ok = 777;
  1131. }
  1132. }
  1133. static void test_http_client(void) {
  1134. struct mg_mgr mgr;
  1135. struct mg_connection *c = NULL;
  1136. const char *url = "http://cesanta.com";
  1137. int i, ok = 0;
  1138. size_t size = 0; // read CA certs from plain file
  1139. char *data = mg_file_read(&mg_fs_posix, "test/data/ca.pem", &size);
  1140. struct mg_tls_opts opts;
  1141. memset(&opts, 0, sizeof(opts));
  1142. mg_mgr_init(&mgr);
  1143. c = mg_http_connect(&mgr, url, f3, &ok);
  1144. ASSERT(c != NULL);
  1145. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
  1146. MG_INFO(("%d", ok));
  1147. ASSERT(ok == 301);
  1148. c->is_closing = 1;
  1149. mg_mgr_poll(&mgr, 0);
  1150. ok = 0;
  1151. #if MG_TLS
  1152. c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
  1153. ASSERT(c != NULL);
  1154. if (c != NULL) {
  1155. opts.ca = mg_str_n(data, size);
  1156. // opts.name = mg_url_host(url);
  1157. mg_tls_init(c, &opts);
  1158. }
  1159. for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
  1160. ASSERT(ok == 200);
  1161. c->is_closing = 1;
  1162. mg_mgr_poll(&mgr, 1);
  1163. #if 1
  1164. // Test failed host validation
  1165. c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
  1166. ASSERT(c != NULL);
  1167. opts.name = mg_str("dummy"); // Set some invalid hostname value
  1168. mg_tls_init(c, &opts);
  1169. ok = 0;
  1170. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  1171. MG_INFO(("OK: %d", ok));
  1172. ASSERT(ok == 777);
  1173. mg_mgr_poll(&mgr, 1);
  1174. opts.name = mg_str("cesanta.com");
  1175. opts.ca = mg_str("");
  1176. c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
  1177. mg_tls_init(c, &opts);
  1178. ok = 0;
  1179. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  1180. MG_INFO(("OK: %d", ok));
  1181. ASSERT(ok == 200);
  1182. mg_mgr_poll(&mgr, 1);
  1183. #endif
  1184. #endif
  1185. #if MG_ENABLE_IPV6
  1186. ok = 0;
  1187. // ipv6.google.com does not have IPv4 address, only IPv6, therefore
  1188. // it is guaranteed to hit IPv6 resolution path.
  1189. c = mg_http_connect(&mgr, "http://ipv6.google.com", f3, &ok);
  1190. for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  1191. ASSERT(ok == 200);
  1192. #endif
  1193. mg_mgr_free(&mgr);
  1194. ASSERT(mgr.conns == NULL);
  1195. free(data);
  1196. }
  1197. // Test host validation only (no CA, no cert)
  1198. static void test_host_validation(void) {
  1199. #if MG_TLS
  1200. const char *url = "https://cesanta.com";
  1201. struct mg_tls_opts opts;
  1202. struct mg_mgr mgr;
  1203. struct mg_connection *c = NULL;
  1204. int i, ok = 0;
  1205. memset(&opts, 0, sizeof(opts));
  1206. mg_mgr_init(&mgr);
  1207. ok = 0;
  1208. c = mg_http_connect(&mgr, url, f3, &ok);
  1209. ASSERT(c != NULL);
  1210. opts.ca = mg_unpacked("test/data/ca.pem");
  1211. mg_tls_init(c, &opts);
  1212. for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
  1213. ASSERT(ok == 200);
  1214. c->is_closing = 1;
  1215. mg_mgr_poll(&mgr, 1);
  1216. mg_mgr_free(&mgr);
  1217. ASSERT(mgr.conns == NULL);
  1218. #endif
  1219. }
  1220. static void f4(struct mg_connection *c, int ev, void *ev_data) {
  1221. if (ev == MG_EV_HTTP_MSG) {
  1222. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1223. mg_printf(c, "HTTP/1.0 200 OK\n\n%.*s/%s", (int) hm->uri.len, hm->uri.ptr,
  1224. "abcdef");
  1225. strcat((char *) c->fn_data, "m");
  1226. c->is_draining = 1;
  1227. } else if (ev == MG_EV_CLOSE) {
  1228. strcat((char *) c->fn_data, "c");
  1229. }
  1230. }
  1231. static void f4c(struct mg_connection *c, int ev, void *ev_data) {
  1232. if (ev == MG_EV_CONNECT) {
  1233. mg_printf(c, "GET /foo/bar HTTP/1.0\n\n");
  1234. } else if (ev == MG_EV_HTTP_MSG) {
  1235. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1236. ASSERT(mg_strcmp(hm->body, mg_str("/foo/bar/abcdef")) == 0);
  1237. strcat((char *) c->fn_data, "m");
  1238. } else if (ev == MG_EV_CLOSE) {
  1239. strcat((char *) c->fn_data, "c");
  1240. }
  1241. }
  1242. static void test_http_no_content_length(void) {
  1243. char buf1[10] = {0}, buf2[10] = {0};
  1244. struct mg_mgr mgr;
  1245. const char *url = "http://127.0.0.1:12348";
  1246. int i;
  1247. mg_mgr_init(&mgr);
  1248. mg_http_listen(&mgr, url, f4, (void *) buf1);
  1249. mg_http_connect(&mgr, url, f4c, (void *) buf2);
  1250. for (i = 0; i < 1000 && strchr(buf2, 'c') == NULL; i++) mg_mgr_poll(&mgr, 10);
  1251. MG_INFO(("[%s] [%s]", buf1, buf2));
  1252. ASSERT(strcmp(buf1, "mc") == 0);
  1253. ASSERT(strcmp(buf2, "cm") == 0); // See #1475
  1254. mg_mgr_free(&mgr);
  1255. ASSERT(mgr.conns == NULL);
  1256. }
  1257. static void f5(struct mg_connection *c, int ev, void *ev_data) {
  1258. if (ev == MG_EV_HTTP_MSG) {
  1259. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1260. mg_http_reply(c, 200, "", "%.*s", (int) hm->uri.len, hm->uri.ptr);
  1261. (*(int *) c->fn_data)++;
  1262. }
  1263. }
  1264. static void test_http_pipeline(void) {
  1265. struct mg_mgr mgr;
  1266. const char *url = "http://127.0.0.1:12377";
  1267. struct mg_connection *c;
  1268. int i, ok = 0;
  1269. mg_mgr_init(&mgr);
  1270. mg_http_listen(&mgr, url, f5, (void *) &ok);
  1271. c = mg_http_connect(&mgr, url, NULL, NULL);
  1272. mg_printf(c, "POST / HTTP/1.0\nContent-Length: 5\n\n12345GET / HTTP/1.0\n\n");
  1273. for (i = 0; i < 20; i++) mg_mgr_poll(&mgr, 1);
  1274. // MG_INFO(("-----> [%d]", ok));
  1275. ASSERT(ok == 2);
  1276. mg_mgr_free(&mgr);
  1277. ASSERT(mgr.conns == NULL);
  1278. }
  1279. static void test_http_parse(void) {
  1280. struct mg_str *v;
  1281. struct mg_http_message req;
  1282. {
  1283. const char *s = "GET / HTTP/1.0\n\n";
  1284. ASSERT(mg_http_parse("\b23", 3, &req) == -1);
  1285. ASSERT(mg_http_parse("get\n\n", 5, &req) == -1);
  1286. ASSERT(mg_http_parse(s, strlen(s) - 1, &req) == 0);
  1287. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1288. ASSERT(req.message.len == strlen(s));
  1289. ASSERT(req.body.len == 0);
  1290. }
  1291. {
  1292. const char *s = "GET /blah HTTP/1.0\r\nFoo: bar \r\n\r\n";
  1293. size_t idx, len = strlen(s);
  1294. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) len);
  1295. ASSERT(mg_vcmp(&req.headers[0].name, "Foo") == 0);
  1296. ASSERT(mg_vcmp(&req.headers[0].value, "bar") == 0);
  1297. ASSERT(req.headers[1].name.len == 0);
  1298. ASSERT(req.headers[1].name.ptr == NULL);
  1299. ASSERT(req.query.len == 0);
  1300. ASSERT(req.message.len == len);
  1301. ASSERT(req.body.len == 0);
  1302. ASSERT(mg_vcmp(&req.method, "GET") == 0);
  1303. ASSERT(mg_vcmp(&req.uri, "/blah") == 0);
  1304. ASSERT(mg_vcmp(&req.proto, "HTTP/1.0") == 0);
  1305. for (idx = 0; idx < len; idx++) ASSERT(mg_http_parse(s, idx, &req) == 0);
  1306. }
  1307. {
  1308. const char *s = "get b c\nb: t\nv:vv\n\n xx";
  1309. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1310. }
  1311. {
  1312. const char *s = "get b c\nb: t\nv:\n\n xx";
  1313. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1314. }
  1315. {
  1316. const char *s = "get b c\nb: t\nv v\n\n xx";
  1317. ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
  1318. }
  1319. {
  1320. const char *s = "get b c\nb: t\n : aa\n\n";
  1321. ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
  1322. }
  1323. {
  1324. const char *s = "get b c\nz: k \nb: t\nv:k\n\n xx";
  1325. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1326. ASSERT(req.headers[3].name.len == 0);
  1327. ASSERT(mg_vcmp(&req.headers[0].name, "z") == 0);
  1328. ASSERT(mg_vcmp(&req.headers[0].value, "k") == 0);
  1329. ASSERT(mg_vcmp(&req.headers[1].name, "b") == 0);
  1330. ASSERT(mg_vcmp(&req.headers[1].value, "t") == 0);
  1331. ASSERT(mg_vcmp(&req.headers[2].name, "v") == 0);
  1332. ASSERT(mg_vcmp(&req.headers[2].value, "k") == 0);
  1333. ASSERT(req.body.len == 0);
  1334. }
  1335. // #2292: fail on stray \r inside the headers
  1336. ASSERT(mg_http_parse("a є\n\n", 6, &req) == 6);
  1337. ASSERT(mg_http_parse("a b\n\n", 5, &req) == 5);
  1338. ASSERT(mg_http_parse("a b\na:\n\n", 8, &req) > 0);
  1339. ASSERT(mg_http_parse("a b\na:\r\n\n", 9, &req) > 0);
  1340. ASSERT(mg_http_parse("a b\n\ra:\r\n\n", 10, &req) == -1);
  1341. ASSERT(mg_http_parse("a b\na:\r1\n\n", 10, &req) == -1);
  1342. ASSERT(mg_http_parse("a b\na: \r1\n\n", 11, &req) == -1);
  1343. ASSERT(mg_http_parse("a b\na: \rb:\n\n", 12, &req) == -1);
  1344. ASSERT(mg_http_parse("a b\na: \nb:\n\n", 12, &req) > 0);
  1345. {
  1346. const char *s = "ґєт /слеш вах вах\nмісто: кіїв \n\n";
  1347. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1348. ASSERT(req.body.len == 0);
  1349. ASSERT(req.headers[1].name.len == 0);
  1350. ASSERT(mg_vcmp(&req.headers[0].name, "місто") == 0);
  1351. ASSERT(mg_vcmp(&req.headers[0].value, "кіїв") == 0);
  1352. ASSERT((v = mg_http_get_header(&req, "місто")) != NULL);
  1353. ASSERT(mg_vcmp(&req.method, "ґєт") == 0);
  1354. ASSERT(mg_vcmp(&req.uri, "/слеш") == 0);
  1355. ASSERT(mg_vcmp(&req.proto, "вах вах") == 0);
  1356. }
  1357. {
  1358. const char *s = "a b c\r\nContent-Length: 21 \r\nb: t\r\nv:v\r\n\r\nabc";
  1359. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s) - 3);
  1360. ASSERT(req.body.len == 21);
  1361. ASSERT(req.message.len == 21 - 3 + strlen(s));
  1362. ASSERT(mg_http_get_header(&req, "foo") == NULL);
  1363. ASSERT((v = mg_http_get_header(&req, "contENT-Length")) != NULL);
  1364. ASSERT(mg_vcmp(v, "21") == 0);
  1365. ASSERT((v = mg_http_get_header(&req, "B")) != NULL);
  1366. ASSERT(mg_vcmp(v, "t") == 0);
  1367. }
  1368. {
  1369. const char *s = "GET /foo?a=b&c=d HTTP/1.0\n\n";
  1370. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1371. ASSERT(mg_vcmp(&req.uri, "/foo") == 0);
  1372. ASSERT(mg_vcmp(&req.query, "a=b&c=d") == 0);
  1373. }
  1374. {
  1375. const char *s = "POST /x HTTP/1.0\n\n";
  1376. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1377. ASSERT(req.body.len == (size_t) ~0);
  1378. }
  1379. {
  1380. const char *s = "WOHOO /x HTTP/1.0\n\n";
  1381. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1382. ASSERT(req.body.len == 0);
  1383. }
  1384. {
  1385. const char *s = "HTTP/1.0 200 OK\n\n";
  1386. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1387. ASSERT(mg_vcmp(&req.method, "HTTP/1.0") == 0);
  1388. ASSERT(mg_vcmp(&req.uri, "200") == 0);
  1389. ASSERT(mg_vcmp(&req.proto, "OK") == 0);
  1390. ASSERT(req.body.len == (size_t) ~0);
  1391. }
  1392. {
  1393. static const char *s = "HTTP/1.0 999 OMGWTFBBQ\n\n";
  1394. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1395. }
  1396. {
  1397. const char *s =
  1398. "GET / HTTP/1.0\r\nhost:127.0.0.1:18888\r\nCookie:\r\nX-PlayID: "
  1399. "45455\r\nRange: 0-1 \r\n\r\n";
  1400. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1401. ASSERT((v = mg_http_get_header(&req, "Host")) != NULL);
  1402. ASSERT(mg_vcmp(v, "127.0.0.1:18888") == 0);
  1403. ASSERT((v = mg_http_get_header(&req, "Cookie")) != NULL);
  1404. ASSERT(v->len == 0);
  1405. ASSERT((v = mg_http_get_header(&req, "X-PlayID")) != NULL);
  1406. ASSERT(mg_vcmp(v, "45455") == 0);
  1407. ASSERT((v = mg_http_get_header(&req, "Range")) != NULL);
  1408. ASSERT(mg_vcmp(v, "0-1") == 0);
  1409. }
  1410. {
  1411. 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";
  1412. ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
  1413. ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
  1414. ASSERT(mg_vcmp(v, "5") == 0);
  1415. ASSERT((v = mg_http_get_header(&req, "h")) == NULL);
  1416. }
  1417. {
  1418. struct mg_connection c;
  1419. struct mg_str s,
  1420. res = mg_str("GET /\r\nAuthorization: Basic Zm9vOmJhcg==\r\n\r\n");
  1421. memset(&c, 0, sizeof(c));
  1422. mg_printf(&c, "%s", "GET /\r\n");
  1423. mg_http_bauth(&c, "foo", "bar");
  1424. mg_printf(&c, "%s", "\r\n");
  1425. s = mg_str_n((char *) c.send.buf, c.send.len);
  1426. ASSERT(mg_strcmp(s, res) == 0);
  1427. mg_iobuf_free(&c.send);
  1428. }
  1429. {
  1430. struct mg_http_message hm;
  1431. const char *s = "GET /foo?bar=baz HTTP/1.0\n\n ";
  1432. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s) - 1);
  1433. ASSERT(mg_strcmp(hm.uri, mg_str("/foo")) == 0);
  1434. ASSERT(mg_strcmp(hm.query, mg_str("bar=baz")) == 0);
  1435. }
  1436. {
  1437. struct mg_http_message hm;
  1438. const char *s = "a b c\n\n";
  1439. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
  1440. s = "a b\nc:d\n\n";
  1441. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
  1442. s = "a\nb:b\nc:c\n\n";
  1443. ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
  1444. s = "a b\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
  1445. ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
  1446. ASSERT((v = mg_http_get_header(&hm, "c")) != NULL);
  1447. ASSERT(mg_vcmp(v, "\xc0") == 0);
  1448. s = "a b\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
  1449. ASSERT(mg_http_parse(s, strlen(s), &hm) == -1);
  1450. }
  1451. }
  1452. static void ehr(struct mg_connection *c, int ev, void *ev_data) {
  1453. if (ev == MG_EV_HTTP_MSG) {
  1454. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  1455. struct mg_http_serve_opts opts;
  1456. memset(&opts, 0, sizeof(opts));
  1457. opts.root_dir = "./test/data";
  1458. mg_http_serve_dir(c, hm, &opts);
  1459. }
  1460. }
  1461. static void test_http_range(void) {
  1462. struct mg_mgr mgr;
  1463. const char *url = "http://127.0.0.1:12349";
  1464. struct mg_http_message hm;
  1465. char buf[FETCH_BUF_SIZE];
  1466. mg_mgr_init(&mgr);
  1467. mg_http_listen(&mgr, url, ehr, NULL);
  1468. ASSERT(fetch(&mgr, buf, url, "GET /range.txt HTTP/1.0\n\n") == 200);
  1469. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1470. ASSERT(hm.body.len == 312);
  1471. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=5-10\n\n");
  1472. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1473. printf("%s", buf);
  1474. ASSERT(mg_strcmp(hm.uri, mg_str("206")) == 0);
  1475. ASSERT(mg_strcmp(hm.proto, mg_str("Partial Content")) == 0);
  1476. ASSERT(mg_strcmp(hm.body, mg_str(" of co")) == 0);
  1477. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Range"),
  1478. mg_str("bytes 5-10/312")) == 0);
  1479. // Fetch till EOF
  1480. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=300-\n\n");
  1481. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1482. ASSERT(mg_strcmp(hm.uri, mg_str("206")) == 0);
  1483. ASSERT(mg_strcmp(hm.body, mg_str("is disease.\n")) == 0);
  1484. // MG_INFO(("----%d\n[%s]", (int) hm.body.len, buf));
  1485. // Fetch past EOF, must trigger 416 response
  1486. fetch(&mgr, buf, url, "%s", "GET /range.txt HTTP/1.0\nRange: bytes=999-\n\n");
  1487. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1488. ASSERT(mg_strcmp(hm.uri, mg_str("416")) == 0);
  1489. ASSERT(hm.body.len == 0);
  1490. ASSERT(mg_strcmp(*mg_http_get_header(&hm, "Content-Range"),
  1491. mg_str("bytes */312")) == 0);
  1492. fetch(&mgr, buf, url, "%s",
  1493. "GET /range.txt HTTP/1.0\nRange: bytes=0-312\n\n");
  1494. ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
  1495. ASSERT(mg_strcmp(hm.uri, mg_str("416")) == 0);
  1496. mg_mgr_free(&mgr);
  1497. ASSERT(mgr.conns == NULL);
  1498. }
  1499. static void f1(void *arg) {
  1500. (*(int *) arg)++;
  1501. }
  1502. static void test_timer(void) {
  1503. int v1 = 0, v2 = 0, v3 = 0;
  1504. struct mg_timer t1, t2, t3, *head = NULL;
  1505. mg_timer_init(&head, &t1, 5, MG_TIMER_REPEAT, f1, &v1);
  1506. mg_timer_init(&head, &t2, 15, MG_TIMER_ONCE, f1, &v2);
  1507. mg_timer_init(&head, &t3, 10, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, f1, &v3);
  1508. ASSERT(head == &t3);
  1509. ASSERT(head->next == &t2);
  1510. mg_timer_poll(&head, 0);
  1511. ASSERT(v1 == 0);
  1512. ASSERT(v2 == 0);
  1513. ASSERT(v3 == 1);
  1514. mg_timer_poll(&head, 1);
  1515. ASSERT(v1 == 0);
  1516. ASSERT(v2 == 0);
  1517. ASSERT(v3 == 1);
  1518. mg_timer_poll(&head, 5);
  1519. ASSERT(v1 == 1);
  1520. ASSERT(v2 == 0);
  1521. ASSERT(v3 == 1);
  1522. // Simulate long delay - timers must invalidate expiration times
  1523. mg_timer_poll(&head, 100);
  1524. ASSERT(v1 == 2);
  1525. ASSERT(v2 == 1);
  1526. ASSERT(v3 == 2);
  1527. mg_timer_poll(&head, 107);
  1528. ASSERT(v1 == 3);
  1529. ASSERT(v2 == 1);
  1530. ASSERT(v3 == 2);
  1531. mg_timer_poll(&head, 114);
  1532. ASSERT(v1 == 4);
  1533. ASSERT(v2 == 1);
  1534. ASSERT(v3 == 3);
  1535. mg_timer_poll(&head, 115);
  1536. ASSERT(v1 == 5);
  1537. ASSERT(v2 == 1);
  1538. ASSERT(v3 == 3);
  1539. mg_timer_free(&head, &t2);
  1540. mg_timer_init(&head, &t2, 3, 0, f1, &v2);
  1541. ASSERT(head == &t2);
  1542. ASSERT(head->next == &t3);
  1543. ASSERT(head->next->next == &t1);
  1544. ASSERT(head->next->next->next == NULL);
  1545. mg_timer_poll(&head, 120);
  1546. ASSERT(v1 == 6);
  1547. ASSERT(v2 == 1);
  1548. ASSERT(v3 == 4);
  1549. mg_timer_poll(&head, 125);
  1550. ASSERT(v1 == 7);
  1551. ASSERT(v2 == 2);
  1552. ASSERT(v3 == 4);
  1553. // Test millisecond counter wrap - when time goes back.
  1554. mg_timer_poll(&head, 0);
  1555. ASSERT(v1 == 7);
  1556. ASSERT(v2 == 2);
  1557. ASSERT(v3 == 4);
  1558. mg_timer_poll(&head, 7);
  1559. ASSERT(v1 == 8);
  1560. ASSERT(v2 == 2);
  1561. ASSERT(v3 == 4);
  1562. mg_timer_poll(&head, 11);
  1563. ASSERT(v1 == 9);
  1564. ASSERT(v2 == 2);
  1565. ASSERT(v3 == 5);
  1566. mg_timer_free(&head, &t1);
  1567. ASSERT(head == &t2);
  1568. ASSERT(head->next == &t3);
  1569. ASSERT(head->next->next == NULL);
  1570. mg_timer_free(&head, &t2);
  1571. ASSERT(head == &t3);
  1572. ASSERT(head->next == NULL);
  1573. mg_timer_free(&head, &t3);
  1574. ASSERT(head == NULL);
  1575. // Start a timer, then shift system time a long time back and long time forth
  1576. v1 = 0;
  1577. mg_timer_init(&head, &t1, 5, MG_TIMER_REPEAT, f1, &v1);
  1578. mg_timer_poll(&head, 0);
  1579. ASSERT(v1 == 0);
  1580. // Shift a long time forth, make sure it ticks
  1581. mg_timer_poll(&head, 100);
  1582. ASSERT(v1 == 1);
  1583. mg_timer_poll(&head, 101);
  1584. ASSERT(v1 == 1);
  1585. mg_timer_poll(&head, 102);
  1586. ASSERT(v1 == 1);
  1587. mg_timer_poll(&head, 103);
  1588. ASSERT(v1 == 1);
  1589. mg_timer_poll(&head, 104);
  1590. ASSERT(v1 == 1);
  1591. mg_timer_poll(&head, 105);
  1592. ASSERT(v1 == 2);
  1593. // Shift a long time back, make sure it ticks
  1594. mg_timer_poll(&head, 50);
  1595. ASSERT(v1 == 2);
  1596. mg_timer_poll(&head, 60);
  1597. ASSERT(v1 == 3);
  1598. mg_timer_free(&head, &t1);
  1599. ASSERT(head == NULL);
  1600. // Test proper timer deallocation, see #1539
  1601. {
  1602. struct mg_mgr mgr;
  1603. mg_mgr_init(&mgr);
  1604. mg_timer_add(&mgr, 1, MG_TIMER_REPEAT, f1, NULL);
  1605. ASSERT(mgr.timers != NULL);
  1606. mg_mgr_free(&mgr);
  1607. ASSERT(mgr.timers == NULL);
  1608. ASSERT(mgr.conns == NULL);
  1609. }
  1610. }
  1611. static bool sn(const char *fmt, ...) {
  1612. char buf[100], tmp[1] = {0}, buf2[sizeof(buf)];
  1613. size_t n, n2, n1;
  1614. va_list ap;
  1615. bool result;
  1616. va_start(ap, fmt);
  1617. n = (size_t) vsnprintf(buf2, sizeof(buf2), fmt, ap);
  1618. va_end(ap);
  1619. va_start(ap, fmt);
  1620. n1 = mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
  1621. va_end(ap);
  1622. va_start(ap, fmt);
  1623. n2 = mg_vsnprintf(tmp, 0, fmt, &ap);
  1624. va_end(ap);
  1625. result = n1 == n2 && n1 == n && strcmp(buf, buf2) == 0;
  1626. if (!result)
  1627. MG_ERROR(("[%s] -> [%s] != [%s] %d %d %d\n", fmt, buf, buf2, (int) n1,
  1628. (int) n2, (int) n));
  1629. return result;
  1630. }
  1631. static bool sccmp(const char *s1, const char *s2, int expected) {
  1632. int n1 = mg_casecmp(s1, s2);
  1633. // MG_INFO(("[%s] [%s] %d %d", s1, s2, n1, expected));
  1634. return n1 == expected;
  1635. }
  1636. static size_t pf1(void (*out)(char, void *), void *ptr, va_list *ap) {
  1637. int a = va_arg(*ap, int);
  1638. int b = va_arg(*ap, int);
  1639. return mg_xprintf(out, ptr, "%d", a + b);
  1640. }
  1641. static size_t pf2(void (*out)(char, void *), void *ptr, va_list *ap) {
  1642. int cnt = va_arg(*ap, int);
  1643. size_t n = 0;
  1644. while (cnt-- > 0) n += mg_xprintf(out, ptr, "%d", cnt);
  1645. return n;
  1646. }
  1647. static bool chkdbl(struct mg_str s, double val) {
  1648. double d, tolerance = 1e-14;
  1649. return mg_json_get_num(s, "$", &d) && fabs(val - d) < tolerance;
  1650. }
  1651. static void test_str(void) {
  1652. {
  1653. struct mg_str s = mg_strdup(mg_str("a"));
  1654. ASSERT(mg_strcmp(s, mg_str("a")) == 0);
  1655. free((void *) s.ptr);
  1656. }
  1657. {
  1658. const char *s;
  1659. struct mg_str a = mg_str("hello"), b = mg_str("a"), c = mg_str(NULL);
  1660. ASSERT((s = mg_strstr(a, b)) == NULL);
  1661. ASSERT((s = mg_strstr(a, c)) != NULL);
  1662. ASSERT(s == a.ptr);
  1663. }
  1664. ASSERT(mg_strcmp(mg_str(""), mg_str(NULL)) == 0);
  1665. ASSERT(mg_strcmp(mg_str("a"), mg_str("b")) < 0);
  1666. ASSERT(mg_strcmp(mg_str("b"), mg_str("a")) > 0);
  1667. ASSERT(mg_strstr(mg_str("abc"), mg_str("d")) == NULL);
  1668. ASSERT(mg_strstr(mg_str("abc"), mg_str("b")) != NULL);
  1669. ASSERT(mg_strcmp(mg_str("hi"), mg_strstrip(mg_str(" \thi\r\n"))) == 0);
  1670. ASSERT(sccmp("", "", 0));
  1671. ASSERT(sccmp("", "1", -49));
  1672. ASSERT(sccmp("a", "A", 0));
  1673. ASSERT(sccmp("a1", "A", 49));
  1674. ASSERT(sccmp("a", "A1", -49));
  1675. {
  1676. ASSERT(chkdbl(mg_str_n("1.23", 3), 1.2));
  1677. ASSERT(chkdbl(mg_str("1.23 "), 1.23));
  1678. ASSERT(chkdbl(mg_str("-0.01 "), -0.01));
  1679. ASSERT(chkdbl(mg_str("-0.5e2"), -50.0));
  1680. ASSERT(chkdbl(mg_str("123e-3"), 0.123));
  1681. }
  1682. ASSERT(sn("%d", 0));
  1683. ASSERT(sn("%d", 1));
  1684. ASSERT(sn("%d", -1));
  1685. ASSERT(sn("%.*s", 0, "ab"));
  1686. ASSERT(sn("%.*s", 1, "ab"));
  1687. ASSERT(sn("%.1s", "ab"));
  1688. ASSERT(sn("%.99s", "a"));
  1689. ASSERT(sn("%11s", "a"));
  1690. ASSERT(sn("%s", "a\0b"));
  1691. ASSERT(sn("%2s", "a"));
  1692. ASSERT(sn("%.*s", 3, "a\0b"));
  1693. ASSERT(sn("%d", 7));
  1694. ASSERT(sn("%d", 123));
  1695. #if MG_ARCH == MG_ARCH_UNIX
  1696. ASSERT(sn("%lld", (uint64_t) 0xffffffffff));
  1697. ASSERT(sn("%lld", (uint64_t) -1));
  1698. ASSERT(sn("%llu", (uint64_t) -1));
  1699. ASSERT(sn("%llx", (uint64_t) 0xffffffffff));
  1700. ASSERT(sn("%p", (void *) (size_t) 7));
  1701. #endif
  1702. ASSERT(sn("%lx", (unsigned long) 0x6204d754));
  1703. ASSERT(sn("ab"));
  1704. ASSERT(sn("%dx", 1));
  1705. ASSERT(sn("%sx", "a"));
  1706. ASSERT(sn("%cx", 32));
  1707. ASSERT(sn("%x", 15));
  1708. ASSERT(sn("%2x", 15));
  1709. ASSERT(sn("%02x", 15));
  1710. ASSERT(sn("%hx:%hhx", (short) 1, (char) 2));
  1711. ASSERT(sn("%hx:%hhx", (short) 1, (char) 2));
  1712. ASSERT(sn("%%"));
  1713. ASSERT(sn("%x", 15));
  1714. ASSERT(sn("%#x", 15));
  1715. ASSERT(sn("%#6x", 15));
  1716. ASSERT(sn("%#06x", 15));
  1717. ASSERT(sn("%#-6x", 15));
  1718. ASSERT(sn("%-2s!", "a"));
  1719. ASSERT(sn("%s %s", "a", "b"));
  1720. ASSERT(sn("%s %s", "a", "b"));
  1721. ASSERT(sn("ab%dc", 123));
  1722. ASSERT(sn("%s ", "a"));
  1723. ASSERT(sn("%s %s", "a", "b"));
  1724. ASSERT(sn("%2s %s", "a", "b"));
  1725. // Non-standard formatting
  1726. {
  1727. char buf[100], *p = NULL;
  1728. struct mg_iobuf io = {0, 0, 0, 16};
  1729. const char *expected;
  1730. expected = "\"\"";
  1731. mg_snprintf(buf, sizeof(buf), "%m", mg_print_esc, 0, "");
  1732. ASSERT(strcmp(buf, expected) == 0);
  1733. expected = "";
  1734. mg_snprintf(buf, 1, "%s", "abc");
  1735. ASSERT(strcmp(buf, expected) == 0);
  1736. expected = "a";
  1737. mg_snprintf(buf, 2, "%s", "abc");
  1738. ASSERT(strcmp(buf, expected) == 0);
  1739. expected = "\"hi, \\\"\"";
  1740. mg_snprintf(buf, sizeof(buf), "\"hi, %M\"", mg_print_esc, 0, "\"");
  1741. MG_INFO(("[%s] [%s]", buf, expected));
  1742. ASSERT(strcmp(buf, expected) == 0);
  1743. expected = "\"a'b\"";
  1744. mg_snprintf(buf, sizeof(buf), "%m", mg_print_esc, 0, "a'b");
  1745. ASSERT(strcmp(buf, expected) == 0);
  1746. expected = "\"a\\b\\n\\f\\r\\t\\\"\"";
  1747. mg_snprintf(buf, sizeof(buf), "%m", mg_print_esc, 0, "a\b\n\f\r\t\"");
  1748. ASSERT(strcmp(buf, expected) == 0);
  1749. expected = "\"abc\"";
  1750. mg_snprintf(buf, sizeof(buf), "%m", mg_print_esc, 3, "abcdef");
  1751. ASSERT(strcmp(buf, expected) == 0);
  1752. p = mg_mprintf("[%s,%M,%s]", "null", pf1, 2, 3, "hi");
  1753. ASSERT(strcmp(p, "[null,5,hi]") == 0);
  1754. free(p);
  1755. p = mg_mprintf("[%M,%d]", pf2, 10, 7);
  1756. ASSERT(strcmp(p, "[9876543210,7]") == 0);
  1757. free(p);
  1758. mg_xprintf(mg_pfn_iobuf, &io, "[%M", pf2, 10);
  1759. mg_xprintf(mg_pfn_iobuf, &io, ",");
  1760. mg_xprintf(mg_pfn_iobuf, &io, "%d]", 7);
  1761. ASSERT(strcmp((char *) io.buf, "[9876543210,7]") == 0);
  1762. mg_iobuf_free(&io);
  1763. }
  1764. {
  1765. #if MG_ARCH == MG_ARCH_WIN32
  1766. bool is_windows = true;
  1767. #else
  1768. bool is_windows = false;
  1769. #endif
  1770. #define DBLWIDTH(a, b) a, b
  1771. #define TESTDOUBLE(fmt_, num_, res_) \
  1772. do { \
  1773. char t1[40] = "", t2[40] = ""; \
  1774. const char *N = #num_; \
  1775. mg_snprintf(t1, sizeof(t1), fmt_, num_); \
  1776. snprintf(t2, sizeof(t2), fmt_, num_); \
  1777. printf("[%s,%s] : [%s] [%s] [%s]\n", fmt_, N, res_, t2, t1); \
  1778. ASSERT(strcmp(t1, res_) == 0); \
  1779. if (!is_windows) ASSERT(strcmp(t1, t2) == 0); \
  1780. } while (0)
  1781. TESTDOUBLE("%g", 0.0, "0");
  1782. TESTDOUBLE("%g", 0.123, "0.123");
  1783. TESTDOUBLE("%g", 0.00123, "0.00123");
  1784. TESTDOUBLE("%g", 0.123456333, "0.123456");
  1785. TESTDOUBLE("%g", 123.0, "123");
  1786. TESTDOUBLE("%g", 11.5454, "11.5454");
  1787. TESTDOUBLE("%g", 11.0001, "11.0001");
  1788. TESTDOUBLE("%g", 0.999, "0.999");
  1789. TESTDOUBLE("%g", 0.999999, "0.999999");
  1790. TESTDOUBLE("%g", 0.9999999, "1");
  1791. TESTDOUBLE("%g", 10.9, "10.9");
  1792. TESTDOUBLE("%g", 10.01, "10.01");
  1793. TESTDOUBLE("%g", 1.0, "1");
  1794. TESTDOUBLE("%g", 10.0, "10");
  1795. TESTDOUBLE("%g", 100.0, "100");
  1796. TESTDOUBLE("%g", 1000.0, "1000");
  1797. TESTDOUBLE("%g", 10000.0, "10000");
  1798. TESTDOUBLE("%g", 100000.0, "100000");
  1799. TESTDOUBLE("%g", 1000000.0, "1e+06");
  1800. TESTDOUBLE("%g", 10000000.0, "1e+07");
  1801. TESTDOUBLE("%g", 100000001.0, "1e+08");
  1802. TESTDOUBLE("%g", 10.5454, "10.5454");
  1803. TESTDOUBLE("%g", 999999.0, "999999");
  1804. TESTDOUBLE("%g", 9999999.0, "1e+07");
  1805. TESTDOUBLE("%g", 44556677.0, "4.45567e+07");
  1806. TESTDOUBLE("%g", 1234567.2, "1.23457e+06");
  1807. TESTDOUBLE("%g", -987.65432, "-987.654");
  1808. TESTDOUBLE("%g", 0.0000000001, "1e-10");
  1809. TESTDOUBLE("%g", 2.34567e-57, "2.34567e-57");
  1810. TESTDOUBLE("%.*g", DBLWIDTH(7, 9999999.0), "9999999");
  1811. TESTDOUBLE("%.*g", DBLWIDTH(10, 0.123456333), "0.123456333");
  1812. TESTDOUBLE("%g", 123.456222, "123.456");
  1813. TESTDOUBLE("%.*g", DBLWIDTH(10, 123.456222), "123.456222");
  1814. TESTDOUBLE("%g", 600.1234, "600.123");
  1815. TESTDOUBLE("%g", -600.1234, "-600.123");
  1816. TESTDOUBLE("%g", 599.1234, "599.123");
  1817. TESTDOUBLE("%g", -599.1234, "-599.123");
  1818. TESTDOUBLE("%g", 0.14, "0.14");
  1819. TESTDOUBLE("%f", 0.14, "0.140000");
  1820. TESTDOUBLE("%.*f", DBLWIDTH(4, 0.14), "0.1400");
  1821. TESTDOUBLE("%.*f", DBLWIDTH(3, 0.14), "0.140");
  1822. TESTDOUBLE("%.*f", DBLWIDTH(2, 0.14), "0.14");
  1823. TESTDOUBLE("%.*f", DBLWIDTH(1, 0.14), "0.1");
  1824. TESTDOUBLE("%.*f", DBLWIDTH(1, 0.19), "0.2");
  1825. TESTDOUBLE("%.*f", DBLWIDTH(1, 0.16), "0.2");
  1826. // TESTDOUBLE("%.*f", DBLWIDTH(1, 0.15), "0.1");
  1827. #ifndef _WIN32
  1828. TESTDOUBLE("%g", (double) INFINITY, "inf");
  1829. TESTDOUBLE("%g", (double) -INFINITY, "-inf");
  1830. TESTDOUBLE("%g", (double) NAN, "nan");
  1831. #else
  1832. TESTDOUBLE("%g", HUGE_VAL, "inf");
  1833. TESTDOUBLE("%g", -HUGE_VAL, "-inf");
  1834. #endif
  1835. }
  1836. {
  1837. const char *expected = "[\"MA==\",\"MAo=\",\"MAr+\",\"MAr+Zw==\"]";
  1838. char tmp[100], s[] = "0\n\xfeg";
  1839. ASSERT(mg_snprintf(tmp, sizeof(tmp), "[%m,%m,%m,%m]", mg_print_base64, 1, s,
  1840. mg_print_base64, 2, s, mg_print_base64, 3, s,
  1841. mg_print_base64, 4, s) == 33);
  1842. ASSERT(strcmp(tmp, expected) == 0);
  1843. }
  1844. {
  1845. const char *expected = "\"002001200220616263\"";
  1846. char tmp[100], s[] = "\x00 \x01 \x02 abc";
  1847. ASSERT(mg_snprintf(tmp, sizeof(tmp), "%m", mg_print_hex, 9, s) == 20);
  1848. ASSERT(strcmp(tmp, expected) == 0);
  1849. }
  1850. {
  1851. char tmp[3];
  1852. ASSERT(mg_snprintf(tmp, sizeof(tmp), "%s", "0123456789") == 10);
  1853. ASSERT(strcmp(tmp, "01") == 0);
  1854. ASSERT(tmp[2] == '\0');
  1855. }
  1856. {
  1857. char buf[100];
  1858. struct mg_addr a;
  1859. uint32_t addr = mg_htonl(0x2000001);
  1860. memcpy(a.ip, &addr, sizeof(uint32_t));
  1861. a.port = mg_htons(3);
  1862. a.is_ip6 = false;
  1863. ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 9);
  1864. ASSERT(strcmp(buf, "2.0.0.1 7") == 0);
  1865. ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip_port, &a, 7) ==
  1866. 11);
  1867. ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0);
  1868. memset(a.ip, 0, sizeof(a.ip));
  1869. a.ip[0] = 1, a.ip[1] = 100, a.ip[2] = 33;
  1870. a.is_ip6 = true;
  1871. ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24);
  1872. ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0);
  1873. ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip_port, &a, 7) ==
  1874. 26);
  1875. ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0]:3 7") == 0);
  1876. }
  1877. }
  1878. static void fn1(struct mg_connection *c, int ev, void *ev_data) {
  1879. if (ev == MG_EV_ERROR) {
  1880. free(*(char **) c->fn_data); // See #2263
  1881. *(char **) c->fn_data = mg_mprintf("%s", (char *) ev_data);
  1882. }
  1883. (void) c;
  1884. }
  1885. static void test_dns_error(const char *dns_server_url, const char *errstr) {
  1886. // Test timeout
  1887. struct mg_mgr mgr;
  1888. char *buf = NULL;
  1889. int i;
  1890. mg_mgr_init(&mgr);
  1891. mgr.dns4.url = dns_server_url;
  1892. mgr.dnstimeout = 10;
  1893. MG_DEBUG(("opening dummy DNS listener @ [%s]...", dns_server_url));
  1894. mg_listen(&mgr, mgr.dns4.url, NULL, NULL); // Just discard our queries
  1895. mg_http_connect(&mgr, "http://google.com", fn1, &buf);
  1896. for (i = 0; i < 50 && buf == NULL; i++) mg_mgr_poll(&mgr, 1);
  1897. mg_mgr_free(&mgr);
  1898. // MG_DEBUG(("buf: [%s] [%s]", buf, errstr));
  1899. ASSERT(buf != NULL && strcmp(buf, errstr) == 0);
  1900. free(buf);
  1901. }
  1902. static void test_dns(void) {
  1903. struct mg_dns_message dm;
  1904. // txid flags numQ numA numAP numOP
  1905. // 0000 00 01 81 80 00 01 00 01 00 00 00 00 07 63 65 73 .............ces
  1906. // 0010 61 6e 74 61 03 63 6f 6d 00 00 01 00 01 c0 0c 00 anta.com........
  1907. // 0020 01 00 01 00 00 02 57 00 04 94 fb 36 ec ......W....6.
  1908. uint8_t data[] = {0, 1, 0x81, 0x80, 0, 1, 0, 1, 0,
  1909. 0, 0, 0, 7, 0x63, 0x65, 0x73, 0x61, 0x6e,
  1910. 0x74, 0x61, 0x03, 0x63, 0x6f, 0x6d, 0, 0, 1,
  1911. 0, 1, 0xc0, 0x0c, 0, 1, 0, 1, 0,
  1912. 0, 2, 0x57, 0, 4, 0x94, 0xfb, 0x36, 0xec};
  1913. ASSERT(mg_dns_parse(NULL, 0, &dm) == 0);
  1914. ASSERT(mg_dns_parse(data, sizeof(data), &dm) == 1);
  1915. ASSERT(strcmp(dm.name, "cesanta.com") == 0);
  1916. data[30] = 29; // Point a pointer to itself
  1917. memset(&dm, 0, sizeof(dm));
  1918. ASSERT(mg_dns_parse(data, sizeof(data), &dm) == 1);
  1919. ASSERT(strcmp(dm.name, "") == 0);
  1920. {
  1921. // 0000 00 01 81 80 00 01 00 04 00 00 00 00 05 79 61 68 .............yah
  1922. // 0010 6f 6f 05 63 31 31 32 36 03 63 6f 6d 00 00 01 00 oo.c1126.com....
  1923. // 0020 01 c0 0c 00 05 00 01 00 00 0d 34 00 0c 03 77 77 ..........4...ww
  1924. // 0030 77 05 79 61 68 6f 6f c0 18 c0 2d 00 05 00 01 00 w.yahoo...-.....
  1925. // 0040 00 00 01 00 14 0b 6e 65 77 2d 66 70 2d 73 68 65 ......new-fp-she
  1926. // 0050 64 03 77 67 31 01 62 c0 31 c0 45 00 01 00 01 00 d.wg1.b.1.E.....
  1927. // 0060 00 00 0a 00 04 57 f8 64 d8 c0 45 00 01 00 01 00 .....W.d..E.....
  1928. // 0070 00 00 0a 00 04 57 f8 64 d7 .....W.d.
  1929. uint8_t d[] = {
  1930. 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
  1931. 0x00, 0x05, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x05, 0x63, 0x31, 0x31,
  1932. 0x32, 0x36, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
  1933. 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x34, 0x00,
  1934. 0x0c, 0x03, 0x77, 0x77, 0x77, 0x05, 0x79, 0x61, 0x68, 0x6f, 0x6f,
  1935. 0xc0, 0x18, 0xc0, 0x2d, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00,
  1936. 0x01, 0x00, 0x14, 0x0b, 0x6e, 0x65, 0x77, 0x2d, 0x66, 0x70, 0x2d,
  1937. 0x73, 0x68, 0x65, 0x64, 0x03, 0x77, 0x67, 0x31, 0x01, 0x62, 0xc0,
  1938. 0x31, 0xc0, 0x45, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a,
  1939. 0x00, 0x04, 0x57, 0xf8, 0x64, 0xd8, 0xc0, 0x45, 0x00, 0x01, 0x00,
  1940. 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x57, 0xf8, 0x64, 0xd7,
  1941. };
  1942. ASSERT(mg_dns_parse(d, sizeof(d), &dm) == 1);
  1943. // MG_INFO(("[%s]", dm.name));
  1944. ASSERT(strcmp(dm.name, "new-fp-shed.wg1.b.yahoo.com") == 0);
  1945. }
  1946. test_dns_error("udp://127.0.0.1:12345", "DNS timeout");
  1947. test_dns_error("", "resolver");
  1948. test_dns_error("tcp://0.0.0.0:0", "DNS error");
  1949. }
  1950. static void test_util(void) {
  1951. const char *e;
  1952. char buf[100], *p, *s;
  1953. struct mg_addr a;
  1954. uint32_t ipv4;
  1955. memset(&a, 0xa5, sizeof(a));
  1956. ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true);
  1957. // if (system("ls -l") != 0) (void) 0;
  1958. ASSERT((p = mg_file_read(&mg_fs_posix, "data.txt", NULL)) != NULL);
  1959. ASSERT(strcmp(p, "hi") == 0);
  1960. free(p);
  1961. remove("data.txt");
  1962. ASSERT(mg_aton(mg_str("0"), &a) == false);
  1963. ASSERT(mg_aton(mg_str("0.0.0."), &a) == false);
  1964. ASSERT(mg_aton(mg_str("0.0.0.256"), &a) == false);
  1965. ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
  1966. ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
  1967. ASSERT(a.is_ip6 == false);
  1968. memcpy(&ipv4, a.ip, sizeof(ipv4));
  1969. ASSERT(ipv4 == mg_htonl(0x7f000001));
  1970. memset(a.ip, 0xa5, sizeof(a.ip));
  1971. ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
  1972. ASSERT(a.is_ip6 == true);
  1973. e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08";
  1974. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  1975. memset(a.ip, 0xa5, sizeof(a.ip));
  1976. ASSERT(mg_aton(mg_str("1:2::3"), &a) == true);
  1977. ASSERT(a.is_ip6 == true);
  1978. e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03";
  1979. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  1980. memset(a.ip, 0xaa, sizeof(a.ip));
  1981. ASSERT(mg_aton(mg_str("1::1"), &a) == true);
  1982. ASSERT(a.is_ip6 == true);
  1983. e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
  1984. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  1985. memset(a.ip, 0xaa, sizeof(a.ip));
  1986. ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
  1987. ASSERT(a.is_ip6 == true);
  1988. e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04";
  1989. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  1990. memset(a.ip, 0xaa, sizeof(a.ip));
  1991. ASSERT(mg_aton(mg_str("::1"), &a) == true);
  1992. ASSERT(a.is_ip6 == true);
  1993. ASSERT(a.scope_id == 0);
  1994. e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
  1995. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  1996. memset(a.ip, 0xaa, sizeof(a.ip));
  1997. ASSERT(mg_aton(mg_str("1::"), &a) == true);
  1998. ASSERT(a.is_ip6 == true);
  1999. e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  2000. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  2001. memset(a.ip, 0xaa, sizeof(a.ip));
  2002. ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
  2003. ASSERT(a.is_ip6 == true);
  2004. e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88";
  2005. ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0);
  2006. ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0);
  2007. ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
  2008. ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
  2009. memset(a.ip, 0xaa, sizeof(a.ip));
  2010. ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
  2011. ASSERT(a.is_ip6 == true);
  2012. ASSERT(a.scope_id == 1);
  2013. memset(a.ip, 0xaa, sizeof(a.ip));
  2014. ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true);
  2015. ASSERT(a.is_ip6 == true);
  2016. ASSERT(a.scope_id == 17);
  2017. memset(a.ip, 0xaa, sizeof(a.ip));
  2018. ASSERT(mg_aton(mg_str("::1%17"), &a) == true);
  2019. ASSERT(a.is_ip6 == true);
  2020. ASSERT(a.scope_id == 17);
  2021. memset(a.ip, 0xaa, sizeof(a.ip));
  2022. ASSERT(mg_aton(mg_str("::1%255"), &a) == true);
  2023. ASSERT(a.is_ip6 == true);
  2024. ASSERT(a.scope_id == 255);
  2025. {
  2026. size_t n;
  2027. ASSERT((n = mg_url_encode("", 0, buf, sizeof(buf))) == 0);
  2028. ASSERT((n = mg_url_encode("a", 1, buf, 0)) == 0);
  2029. ASSERT((n = mg_url_encode("a", 1, buf, sizeof(buf))) == 1);
  2030. ASSERT(strncmp(buf, "a", n) == 0);
  2031. ASSERT((n = mg_url_encode("._-~", 4, buf, sizeof(buf))) == 4);
  2032. ASSERT(strncmp(buf, "._-~", n) == 0);
  2033. ASSERT((n = mg_url_encode("a@%>", 4, buf, sizeof(buf))) == 10);
  2034. ASSERT(strncmp(buf, "a%40%25%3e", n) == 0);
  2035. ASSERT((n = mg_url_encode("a@b.c", 5, buf, sizeof(buf))) == 7);
  2036. ASSERT(strncmp(buf, "a%40b.c", n) == 0);
  2037. }
  2038. {
  2039. s = mg_mprintf("%3d", 123);
  2040. ASSERT(strcmp(s, "123") == 0);
  2041. free(s);
  2042. }
  2043. {
  2044. extern bool mg_to_size_t(struct mg_str, size_t *);
  2045. size_t val, max = (size_t) -1;
  2046. ASSERT(mg_to_size_t(mg_str("0"), &val) && val == 0);
  2047. ASSERT(mg_to_size_t(mg_str("123"), &val) && val == 123);
  2048. ASSERT(mg_to_size_t(mg_str(" 123 \t"), &val) && val == 123);
  2049. ASSERT(mg_to_size_t(mg_str(""), &val) == false);
  2050. ASSERT(mg_to_size_t(mg_str(" 123x"), &val) == false);
  2051. ASSERT(mg_to_size_t(mg_str("-"), &val) == false);
  2052. mg_snprintf(buf, sizeof(buf), sizeof(max) == 8 ? "%llu" : "%lu", max);
  2053. ASSERT(mg_to_size_t(mg_str(buf), &val) && val == max);
  2054. }
  2055. {
  2056. size_t i;
  2057. memset(buf, ' ', sizeof(buf));
  2058. mg_random_str(buf, 0);
  2059. ASSERT(buf[0] == ' ');
  2060. mg_random_str(buf, 1);
  2061. ASSERT(buf[0] == '\0');
  2062. ASSERT(buf[1] == ' ');
  2063. mg_random_str(buf, sizeof(buf));
  2064. ASSERT(buf[sizeof(buf) - 1] == '\0');
  2065. for (i = 0; i < sizeof(buf) - 1; i++) ASSERT(isalnum((uint8_t) buf[i]));
  2066. }
  2067. }
  2068. static void test_crc32(void) {
  2069. // echo -n aaa | cksum -o3
  2070. ASSERT(mg_crc32(0, 0, 0) == 0);
  2071. ASSERT(mg_crc32(0, "a", 1) == 3904355907);
  2072. ASSERT(mg_crc32(0, "abc", 3) == 891568578);
  2073. ASSERT(mg_crc32(mg_crc32(0, "ab", 2), "c", 1) == 891568578);
  2074. }
  2075. static void us(struct mg_connection *c, int ev, void *ev_data) {
  2076. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2077. if (ev == MG_EV_HTTP_MSG && mg_http_match_uri(hm, "/upload")) {
  2078. MG_DEBUG(("Got all %lu bytes!", (unsigned long) hm->body.len));
  2079. MG_DEBUG(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
  2080. // MG_DEBUG(("Body:\n%.*s", (int) hm->body.len, hm->body.ptr));
  2081. mg_http_reply(c, 200, "", "ok (%d %.*s)\n", (int) hm->body.len,
  2082. (int) hm->body.len, hm->body.ptr);
  2083. } else if (ev == MG_EV_HTTP_MSG) {
  2084. mg_http_reply(c, 200, "", "ok\n");
  2085. }
  2086. }
  2087. static void uc(struct mg_connection *c, int ev, void *ev_data) {
  2088. const char **s = (const char **) c->fn_data;
  2089. if (ev == MG_EV_OPEN) {
  2090. // c->is_hexdumping = 1;
  2091. } else if (ev == MG_EV_CONNECT) {
  2092. mg_printf(c,
  2093. "POST /upload HTTP/1.0\r\n"
  2094. "Transfer-Encoding: chunked\r\n\r\n");
  2095. mg_http_printf_chunk(c, "%s", "foo\n");
  2096. mg_http_printf_chunk(c, "%s", "bar\n");
  2097. mg_http_printf_chunk(c, "");
  2098. } else if (ev == MG_EV_HTTP_MSG) {
  2099. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2100. // MG_INFO(("---> [%s] [%.*s]", *s, hm->body.len, hm->body.ptr));
  2101. ASSERT(mg_strcmp(hm->body, mg_str(*s)) == 0);
  2102. *s = NULL;
  2103. }
  2104. }
  2105. static void test_http_upload(void) {
  2106. struct mg_mgr mgr;
  2107. const char *url = "http://127.0.0.1:12352";
  2108. int i;
  2109. const char *s = "ok (8 foo\nbar\n)\n";
  2110. mg_mgr_init(&mgr);
  2111. mg_http_listen(&mgr, url, us, NULL);
  2112. mg_http_connect(&mgr, url, uc, (void *) &s);
  2113. for (i = 0; i < 20; i++) mg_mgr_poll(&mgr, 5);
  2114. ASSERT(s == NULL);
  2115. mg_mgr_free(&mgr);
  2116. ASSERT(mgr.conns == NULL);
  2117. }
  2118. #define LONG_CHUNK "chunk with length taking up more than two hex digits"
  2119. static void eX(struct mg_connection *c, int ev, void *ev_data) {
  2120. if (ev == MG_EV_HTTP_MSG) {
  2121. mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
  2122. c->data[0] = 1;
  2123. // c->is_hexdumping = 1;
  2124. } else if (ev == MG_EV_POLL && c->data[0] != 0) {
  2125. c->data[0]++;
  2126. if (c->data[0] == 10) mg_http_printf_chunk(c, "a");
  2127. if (c->data[0] == 20) {
  2128. mg_http_printf_chunk(c, "b");
  2129. mg_http_printf_chunk(c, "c");
  2130. }
  2131. if (c->data[0] == 30) {
  2132. mg_http_printf_chunk(c, "d");
  2133. mg_http_printf_chunk(c, "");
  2134. c->data[0] = 0;
  2135. }
  2136. }
  2137. (void) ev_data;
  2138. }
  2139. static void eY(struct mg_connection *c, int ev, void *ev_data) {
  2140. if (ev == MG_EV_HTTP_MSG) {
  2141. mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n");
  2142. c->data[0] = 1;
  2143. } else if (ev == MG_EV_POLL && c->data[0] != 0) {
  2144. c->data[0]++;
  2145. if (c->data[0] == 10) mg_send(c, "a", 1);
  2146. if (c->data[0] == 12) mg_send(c, "bc", 2);
  2147. if (c->data[0] == 30) mg_send(c, "d", 1), c->is_resp = 0, c->data[0] = 0;
  2148. }
  2149. (void) ev_data;
  2150. }
  2151. static void eZ(struct mg_connection *c, int ev, void *ev_data) {
  2152. if (ev == MG_EV_HTTP_MSG) {
  2153. mg_http_reply(c, 200, "", "abcd");
  2154. }
  2155. (void) ev_data;
  2156. }
  2157. // Do not delete chunks as they arrive
  2158. static void eh4(struct mg_connection *c, int ev, void *ev_data) {
  2159. uint32_t *crc = (uint32_t *) c->fn_data;
  2160. if (ev == MG_EV_HTTP_MSG) {
  2161. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2162. *crc = mg_crc32(*crc, hm->body.ptr, hm->body.len);
  2163. MG_INFO(("%lu M [%.*s]", c->id, (int) hm->body.len, hm->body.ptr));
  2164. }
  2165. }
  2166. static void test_http_chunked_case(mg_event_handler_t s, mg_event_handler_t c,
  2167. int req_count, const char *expected) {
  2168. char url[100];
  2169. struct mg_mgr mgr;
  2170. uint32_t i, crc = 0, expected_crc = mg_crc32(0, expected, strlen(expected));
  2171. struct mg_connection *conn;
  2172. static uint16_t port = 32344; // To prevent bind errors on Windows
  2173. mg_snprintf(url, sizeof(url), "http://127.0.0.1:%d", port++);
  2174. mg_mgr_init(&mgr);
  2175. mg_http_listen(&mgr, url, s, NULL);
  2176. conn = mg_http_connect(&mgr, url, c, &crc);
  2177. while (conn != NULL && req_count-- > 0) {
  2178. mg_printf(conn, "GET / HTTP/1.0\n\n");
  2179. }
  2180. for (i = 0; i < 100 && crc != expected_crc; i++) {
  2181. mg_mgr_poll(&mgr, 1);
  2182. }
  2183. // MG_INFO(("-------- %d [%s]", i, expected));
  2184. ASSERT(i < 100);
  2185. ASSERT(crc == expected_crc);
  2186. mg_mgr_free(&mgr);
  2187. ASSERT(mgr.conns == NULL);
  2188. }
  2189. static void test_http_chunked(void) {
  2190. // Non-chunked encoding
  2191. test_http_chunked_case(eY, eh4, 1, "abcd"); // Chunks not deleted
  2192. test_http_chunked_case(eY, eh4, 2, "abcdabcd");
  2193. test_http_chunked_case(eZ, eh4, 1, "abcd"); // Not deleted
  2194. test_http_chunked_case(eZ, eh4, 2, "abcdabcd");
  2195. // Chunked encoding
  2196. test_http_chunked_case(eX, eh4, 1, "abcd"); // Chunks not deleted
  2197. test_http_chunked_case(eX, eh4, 2, "abcdabcd");
  2198. }
  2199. static void test_invalid_listen_addr(void) {
  2200. struct mg_mgr mgr;
  2201. struct mg_connection *c;
  2202. mg_mgr_init(&mgr);
  2203. c = mg_http_listen(&mgr, "invalid:31:14", eh1, NULL);
  2204. ASSERT(c == NULL);
  2205. mg_mgr_free(&mgr);
  2206. ASSERT(mgr.conns == NULL);
  2207. }
  2208. struct stream_status {
  2209. uint32_t polls;
  2210. size_t sent;
  2211. size_t received;
  2212. uint32_t send_crc;
  2213. uint32_t recv_crc;
  2214. };
  2215. // Consume recv buffer after letting it reach MG_MAX_RECV_SIZE
  2216. static void eh8(struct mg_connection *c, int ev, void *ev_data) {
  2217. struct stream_status *status = (struct stream_status *) c->fn_data;
  2218. if (c->is_listening) return;
  2219. ASSERT(c->recv.len <= MG_MAX_RECV_SIZE);
  2220. if (ev == MG_EV_ACCEPT) {
  2221. // Optimize recv buffer size near max to speed up test
  2222. mg_iobuf_resize(&c->recv, MG_MAX_RECV_SIZE - MG_IO_SIZE);
  2223. status->received = 0;
  2224. status->recv_crc = 0;
  2225. }
  2226. if (ev == MG_EV_CLOSE) {
  2227. ASSERT(status->received == status->sent);
  2228. }
  2229. // Let buffer fill up and start consuming after 10 full buffer poll events
  2230. if (status->polls >= 10 && ev == MG_EV_POLL) {
  2231. // consume at most a third of MG_MAX_RECV_SIZE on each poll
  2232. size_t consume;
  2233. if (MG_MAX_RECV_SIZE / 3 >= c->recv.len)
  2234. consume = c->recv.len;
  2235. else
  2236. consume = MG_MAX_RECV_SIZE / 3;
  2237. status->received += consume;
  2238. status->recv_crc =
  2239. mg_crc32(status->recv_crc, (const char *) c->recv.buf, consume);
  2240. mg_iobuf_del(&c->recv, 0, consume);
  2241. }
  2242. // count polls with full buffer to ensure c->is_full prevents reads
  2243. if (ev == MG_EV_POLL && c->recv.len == MG_MAX_RECV_SIZE) status->polls += 1;
  2244. (void) ev_data;
  2245. }
  2246. // Toggle c->is_full to prevent max_recv_buf_size reached read errors
  2247. static void eh10(struct mg_connection *c, int ev, void *ev_data) {
  2248. if (c->recv.len >= MG_MAX_RECV_SIZE && ev == MG_EV_READ) c->is_full = true;
  2249. eh8(c, ev, ev_data);
  2250. if (c->recv.len < MG_MAX_RECV_SIZE && ev == MG_EV_POLL) c->is_full = false;
  2251. }
  2252. // Send buffer larger than MG_MAX_RECV_SIZE to server
  2253. static void eh11(struct mg_connection *c, int ev, void *ev_data) {
  2254. struct stream_status *status = (struct stream_status *) c->fn_data;
  2255. if (ev == MG_EV_CONNECT) {
  2256. size_t len = MG_MAX_RECV_SIZE * 2;
  2257. struct mg_iobuf buf = {NULL, 0, 0, 0};
  2258. mg_iobuf_init(&buf, len, 0);
  2259. mg_random(buf.buf, buf.size);
  2260. buf.len = buf.size;
  2261. mg_send(c, buf.buf, buf.len);
  2262. status->sent = buf.len;
  2263. status->send_crc = mg_crc32(0, (const char *) buf.buf, buf.len);
  2264. mg_iobuf_free(&buf);
  2265. }
  2266. (void) ev_data;
  2267. }
  2268. static void test_http_stream_buffer(void) {
  2269. struct mg_mgr mgr;
  2270. const char *url = "tcp://127.0.0.1:12344";
  2271. uint32_t i;
  2272. struct stream_status status;
  2273. mg_mgr_init(&mgr);
  2274. mg_listen(&mgr, url, eh10, &status);
  2275. status.polls = 0;
  2276. mg_connect(&mgr, url, eh11, &status);
  2277. for (i = 0; i < (MG_MAX_RECV_SIZE / MG_IO_SIZE) * 50; i++) {
  2278. mg_mgr_poll(&mgr, 1);
  2279. if (status.polls >= 10 && status.sent == status.received) break;
  2280. }
  2281. ASSERT(status.sent == status.received);
  2282. ASSERT(status.send_crc == status.recv_crc);
  2283. mg_mgr_free(&mgr);
  2284. ASSERT(mgr.conns == NULL);
  2285. }
  2286. static void test_multipart(void) {
  2287. struct mg_http_part part;
  2288. size_t ofs;
  2289. const char *s =
  2290. "--xyz\r\n"
  2291. "Content-Disposition: form-data; name=\"val\"\r\n"
  2292. "\r\n"
  2293. "abc\r\ndef\r\n"
  2294. "--xyz\r\n"
  2295. "Content-Disposition: form-data; name=\"foo\"; filename=\"a b.txt\"\r\n"
  2296. "Content-Type: text/plain\r\n"
  2297. "\r\n"
  2298. "hello world\r\n"
  2299. "\r\n"
  2300. "--xyz--\r\n";
  2301. ASSERT(mg_http_next_multipart(mg_str(""), 0, NULL) == 0);
  2302. ASSERT((ofs = mg_http_next_multipart(mg_str(s), 0, &part)) > 0);
  2303. ASSERT(mg_strcmp(part.name, mg_str("val")) == 0);
  2304. // MG_INFO(("--> [%.*s]", (int) part.body.len, part.body.ptr));
  2305. ASSERT(mg_strcmp(part.body, mg_str("abc\r\ndef")) == 0);
  2306. ASSERT(part.filename.len == 0);
  2307. ASSERT((ofs = mg_http_next_multipart(mg_str(s), ofs, &part)) > 0);
  2308. ASSERT(mg_strcmp(part.name, mg_str("foo")) == 0);
  2309. // MG_INFO(("--> [%.*s]", (int) part.filename.len, part.filename.ptr));
  2310. ASSERT(mg_strcmp(part.filename, mg_str("a b.txt")) == 0);
  2311. ASSERT(mg_strcmp(part.body, mg_str("hello world\r\n")) == 0);
  2312. ASSERT(mg_http_next_multipart(mg_str(s), ofs, &part) == 0);
  2313. }
  2314. static void eh7(struct mg_connection *c, int ev, void *ev_data) {
  2315. if (ev == MG_EV_HTTP_MSG) {
  2316. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2317. struct mg_http_serve_opts sopts;
  2318. memset(&sopts, 0, sizeof(sopts));
  2319. sopts.root_dir = "/";
  2320. sopts.fs = &mg_fs_packed;
  2321. mg_http_serve_dir(c, hm, &sopts);
  2322. }
  2323. }
  2324. static void test_packed(void) {
  2325. struct mg_mgr mgr;
  2326. const char *url = "http://127.0.0.1:12351";
  2327. char buf[FETCH_BUF_SIZE],
  2328. *data = mg_file_read(&mg_fs_posix, "Makefile", NULL);
  2329. mg_mgr_init(&mgr);
  2330. mg_http_listen(&mgr, url, eh7, NULL);
  2331. // Load top level file directly
  2332. // fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n");
  2333. // printf("---> %s\n", buf);
  2334. ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200);
  2335. ASSERT(cmpbody(buf, data) == 0);
  2336. free(data);
  2337. // Load file deeper in the FS tree directly
  2338. data = mg_file_read(&mg_fs_posix, "src/ssi.h", NULL);
  2339. ASSERT(fetch(&mgr, buf, url, "GET /src/ssi.h HTTP/1.0\n\n") == 200);
  2340. ASSERT(cmpbody(buf, data) == 0);
  2341. free(data);
  2342. // List root dir
  2343. ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200);
  2344. // printf("--------\n%s\n", buf);
  2345. // List nested dir
  2346. ASSERT(fetch(&mgr, buf, url, "GET /test HTTP/1.0\n\n") == 301);
  2347. ASSERT(fetch(&mgr, buf, url, "GET /test/ HTTP/1.0\n\n") == 200);
  2348. // printf("--------\n%s\n", buf);
  2349. mg_mgr_free(&mgr);
  2350. ASSERT(mgr.conns == NULL);
  2351. }
  2352. #if (MG_ENABLE_SOCKET == 0)
  2353. int send(int sock, const void *buf, size_t len, int flags);
  2354. int send(int sock, const void *buf, size_t len, int flags) {
  2355. (void) sock, (void) buf, (void) len, (void) flags;
  2356. return -1;
  2357. }
  2358. #endif
  2359. static void u1(struct mg_connection *c, int ev, void *ev_data) {
  2360. if (ev == MG_EV_CONNECT) {
  2361. ((int *) c->fn_data)[0] += 1;
  2362. mg_send(c, "hi", 2);
  2363. } else if (ev == MG_EV_WRITE) {
  2364. ((int *) c->fn_data)[0] += 100;
  2365. } else if (ev == MG_EV_READ) {
  2366. ((int *) c->fn_data)[0] += 10;
  2367. mg_iobuf_free(&c->recv);
  2368. }
  2369. (void) ev_data;
  2370. }
  2371. static void test_udp(void) {
  2372. struct mg_mgr mgr;
  2373. const char *url = "udp://127.0.0.1:12353";
  2374. int i, done = 0;
  2375. mg_mgr_init(&mgr);
  2376. mg_listen(&mgr, url, u1, (void *) &done);
  2377. mg_connect(&mgr, url, u1, (void *) &done);
  2378. for (i = 0; i < 5; i++) mg_mgr_poll(&mgr, 1);
  2379. // MG_INFO(("%d", done));
  2380. ASSERT(done == 111);
  2381. mg_mgr_free(&mgr);
  2382. ASSERT(mgr.conns == NULL);
  2383. }
  2384. static void test_check_ip_acl(void) {
  2385. struct mg_addr ip = {{1, 2, 3, 4}, 0, 0, false}; // 1.2.3.4
  2386. ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1);
  2387. ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1);
  2388. ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1);
  2389. ASSERT(mg_check_ip_acl(mg_str("+hi"), &ip) == -2);
  2390. ASSERT(mg_check_ip_acl(mg_str("+//"), &ip) == -2);
  2391. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0"), &ip) == 0);
  2392. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.0.0.0/8"), &ip) == 1);
  2393. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.2.3.4"), &ip) == 1);
  2394. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.0.0.0/16"), &ip) == 0);
  2395. ip.is_ip6 = true;
  2396. ASSERT(mg_check_ip_acl(mg_str("-0.0.0.0/0"), &ip) ==
  2397. -1); // not yet supported
  2398. }
  2399. static void w3(struct mg_connection *c, int ev, void *ev_data) {
  2400. // MG_INFO(("ev %d", ev));
  2401. if (ev == MG_EV_WS_OPEN) {
  2402. char buf[8192];
  2403. memset(buf, 'A', sizeof(buf));
  2404. mg_ws_send(c, "hi there!", 9, WEBSOCKET_OP_TEXT);
  2405. mg_ws_printf(c, WEBSOCKET_OP_TEXT, "%s", "hi there2!");
  2406. mg_printf(c, "%s", "boo");
  2407. mg_ws_wrap(c, 3, WEBSOCKET_OP_TEXT);
  2408. mg_ws_send(c, buf, sizeof(buf), WEBSOCKET_OP_TEXT);
  2409. } else if (ev == MG_EV_WS_MSG) {
  2410. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  2411. ASSERT(mg_strcmp(wm->data, mg_str("lebowski")) == 0);
  2412. ((int *) c->fn_data)[0]++;
  2413. } else if (ev == MG_EV_CLOSE) {
  2414. ((int *) c->fn_data)[0] += 10;
  2415. }
  2416. }
  2417. static void w2(struct mg_connection *c, int ev, void *ev_data) {
  2418. struct mg_str msg = mg_str_n("lebowski", 8);
  2419. if (ev == MG_EV_HTTP_MSG) {
  2420. mg_ws_upgrade(c, (struct mg_http_message *) ev_data, NULL);
  2421. } else if (ev == MG_EV_WS_OPEN) {
  2422. mg_ws_send(c, "x", 1, WEBSOCKET_OP_PONG);
  2423. } else if (ev == MG_EV_POLL && c->is_websocket) {
  2424. size_t ofs, n = (size_t) c->fn_data;
  2425. if (n < msg.len) {
  2426. // Send "msg" char by char using fragmented frames
  2427. // mg_ws_send() sets the FIN flag in the WS header. Clean it
  2428. // to send fragmented packet. Insert PONG messages between frames
  2429. uint8_t op = n == 0 ? WEBSOCKET_OP_TEXT : WEBSOCKET_OP_CONTINUE;
  2430. mg_ws_send(c, ":->", 3, WEBSOCKET_OP_PING);
  2431. ofs = c->send.len;
  2432. mg_ws_send(c, &msg.ptr[n], 1, op);
  2433. if (n < msg.len - 1) c->send.buf[ofs] = op; // Clear FIN flag
  2434. c->fn_data = (void *) (n + 1); // Point to the next char
  2435. } else {
  2436. mg_ws_send(c, "", 0, WEBSOCKET_OP_CLOSE);
  2437. }
  2438. } else if (ev == MG_EV_WS_MSG) {
  2439. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  2440. MG_INFO(("Got WS, %lu", wm->data.len));
  2441. // mg_hexdump(wm->data.ptr, wm->data.len);
  2442. if (wm->data.len == 9) {
  2443. ASSERT(mg_strcmp(wm->data, mg_str("hi there!")) == 0);
  2444. } else if (wm->data.len == 10) {
  2445. ASSERT(mg_strcmp(wm->data, mg_str("hi there2!")) == 0);
  2446. } else if (wm->data.len == 3) {
  2447. ASSERT(mg_strcmp(wm->data, mg_str("boo")) == 0);
  2448. } else {
  2449. MG_INFO(("%lu", wm->data.len));
  2450. ASSERT(wm->data.len == 8192);
  2451. }
  2452. }
  2453. }
  2454. static void test_ws_fragmentation(void) {
  2455. const char *url = "ws://localhost:12357/ws";
  2456. struct mg_mgr mgr;
  2457. int i, done = 0;
  2458. mg_mgr_init(&mgr);
  2459. ASSERT(mg_http_listen(&mgr, url, w2, NULL) != NULL);
  2460. mg_ws_connect(&mgr, url, w3, &done, "%s", "Sec-WebSocket-Protocol: echo\r\n");
  2461. for (i = 0; i < 25; i++) mg_mgr_poll(&mgr, 1);
  2462. // MG_INFO(("--> %d", done));
  2463. ASSERT(done == 11);
  2464. mg_mgr_free(&mgr);
  2465. ASSERT(mgr.conns == NULL);
  2466. }
  2467. static void h7(struct mg_connection *c, int ev, void *ev_data) {
  2468. if (ev == MG_EV_HTTP_MSG) {
  2469. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
  2470. struct mg_http_serve_opts opts;
  2471. memset(&opts, 0, sizeof(opts));
  2472. opts.root_dir = "./test/data,/foo=./src";
  2473. mg_http_serve_dir(c, hm, &opts);
  2474. }
  2475. }
  2476. static void test_rewrites(void) {
  2477. char buf[FETCH_BUF_SIZE];
  2478. const char *url = "http://LOCALHOST:12358";
  2479. const char *expected = "#define MG_VERSION \"" MG_VERSION "\"\n";
  2480. struct mg_mgr mgr;
  2481. mg_mgr_init(&mgr);
  2482. ASSERT(mg_http_listen(&mgr, url, h7, NULL) != NULL);
  2483. ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
  2484. ASSERT(cmpbody(buf, "hello\n") == 0);
  2485. ASSERT(fetch(&mgr, buf, url, "GET /foo/version.h HTTP/1.0\n\n") == 200);
  2486. ASSERT(cmpbody(buf, expected) == 0);
  2487. ASSERT(fetch(&mgr, buf, url, "GET /foo HTTP/1.0\n\n") == 301);
  2488. ASSERT(fetch(&mgr, buf, url, "GET /foo/ HTTP/1.0\n\n") == 200);
  2489. // printf("-->[%s]\n", buf);
  2490. mg_mgr_free(&mgr);
  2491. ASSERT(mgr.conns == NULL);
  2492. }
  2493. static void test_get_header_var(void) {
  2494. struct mg_str empty = mg_str(""), bar = mg_str("bar"), baz = mg_str("baz");
  2495. struct mg_str header = mg_str("Digest foo=\"bar\", blah,boo=baz, x=\"yy\"");
  2496. struct mg_str yy = mg_str("yy");
  2497. // struct mg_str x = mg_http_get_header_var(header, mg_str("x"));
  2498. // MG_INFO(("--> [%d] [%d]", (int) x.len, yy.len));
  2499. ASSERT(mg_strcmp(empty, mg_http_get_header_var(empty, empty)) == 0);
  2500. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, empty)) == 0);
  2501. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("fooo"))) == 0);
  2502. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("fo"))) == 0);
  2503. ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("blah"))) == 0);
  2504. ASSERT(mg_strcmp(bar, mg_http_get_header_var(header, mg_str("foo"))) == 0);
  2505. ASSERT(mg_strcmp(baz, mg_http_get_header_var(header, mg_str("boo"))) == 0);
  2506. ASSERT(mg_strcmp(yy, mg_http_get_header_var(header, mg_str("x"))) == 0);
  2507. }
  2508. static void json_scan(struct mg_str json, int depth) {
  2509. int i, n = 0, o = mg_json_get(json, "$", &n);
  2510. for (i = 0; i < depth; i++) printf(" ");
  2511. printf("%.*s\n", n, json.ptr + o);
  2512. if (json.ptr[o] == '{' || json.ptr[o] == '[') { // Iterate over elems
  2513. struct mg_str key, val, sub = mg_str_n(json.ptr + o, (size_t) n);
  2514. size_t ofs = 0;
  2515. while ((ofs = mg_json_next(sub, ofs, &key, &val)) > 0) {
  2516. for (i = 0; i < depth; i++) printf(" ");
  2517. printf("KEY: %.*s VAL: %.*s\n", (int) key.len, key.ptr, (int) val.len,
  2518. val.ptr);
  2519. if (*val.ptr == '[' || *val.ptr == '{') json_scan(val, depth + 1);
  2520. }
  2521. }
  2522. }
  2523. static void test_json(void) {
  2524. const char *s1 = "{\"a\":{},\"b\":7,\"c\":[[],2]}";
  2525. const char *s2 = "{\"a\":{\"b1\":{}},\"c\":7,\"d\":{\"b2\":{}}}";
  2526. int n;
  2527. struct mg_str json;
  2528. ASSERT(mg_json_get(mg_str_n(" true ", 6), "", &n) == MG_JSON_INVALID);
  2529. ASSERT(mg_json_get(mg_str_n(" true ", 6), "$", &n) == 1 && n == 4);
  2530. ASSERT(mg_json_get(mg_str_n("null ", 5), "$", &n) == 0 && n == 4);
  2531. json = mg_str(" \"hi\\nthere\"");
  2532. ASSERT(mg_json_get(json, "$", &n) == 2 && n == 11);
  2533. ASSERT(mg_json_get(mg_str_n(" { } ", 5), "$", &n) == 1);
  2534. ASSERT(mg_json_get(mg_str_n(" [[]]", 5), "$", &n) == 1);
  2535. ASSERT(mg_json_get(mg_str_n(" [ ] ", 5), "$", &n) == 1);
  2536. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$", &n) == 0 && n == 5);
  2537. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[0]", &n) == 1 && n == 1);
  2538. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[1]", &n) == 3 && n == 1);
  2539. ASSERT(mg_json_get(mg_str_n("[1,2]", 5), "$[3]", &n) == MG_JSON_NOT_FOUND);
  2540. json = mg_str("{\"a\":[]}");
  2541. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2542. json = mg_str("{\"a\":[1,2]}");
  2543. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 5);
  2544. json = mg_str("{\"a\":[1,[1]]}");
  2545. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 7);
  2546. json = mg_str("{\"a\":[[]]}");
  2547. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 4);
  2548. json = mg_str("{\"a\":[[1,2]]}");
  2549. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 7);
  2550. json = mg_str("{\"a\":{}}");
  2551. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2552. json = mg_str("{\"a\":{\"a\":{}}}");
  2553. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 8);
  2554. json = mg_str("{\"a\":{\"a\":[]}}");
  2555. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 8);
  2556. json = mg_str("[[1,[2,3]],4]");
  2557. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 13);
  2558. ASSERT(mg_json_get(json, "$[0]", &n) == 1 && n == 9);
  2559. ASSERT(mg_json_get(json, "$[1]", &n) == 11);
  2560. ASSERT(mg_json_get(json, "$[1]", &n) == 11 && n == 1);
  2561. ASSERT(mg_json_get(json, "$[2]", &n) == MG_JSON_NOT_FOUND);
  2562. ASSERT(mg_json_get(json, "$[0][0]", &n) == 2 && n == 1);
  2563. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 5);
  2564. ASSERT(mg_json_get(json, "$[0][2]", &n) == MG_JSON_NOT_FOUND);
  2565. ASSERT(mg_json_get(json, "$[0][1][0]", &n) == 5 && n == 1);
  2566. ASSERT(mg_json_get(json, "$[0][1][1]", &n) == 7 && n == 1);
  2567. json = mg_str("[[1,2],3]");
  2568. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 9);
  2569. ASSERT(mg_json_get(json, "$[0][0]", &n) == 2 && n == 1);
  2570. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 1);
  2571. ASSERT(mg_json_get(json, "$[0][2]", &n) == MG_JSON_NOT_FOUND);
  2572. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2573. ASSERT(mg_json_get(json, "$[1]", &n) == 7 && n == 1);
  2574. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2575. ASSERT(mg_json_get(json, "$", &n) == 0 && n == 9);
  2576. ASSERT(mg_json_get(json, "$[1][0]", &n) == MG_JSON_NOT_FOUND);
  2577. ASSERT(mg_json_get(json, "$[0][1]", &n) == 4 && n == 1);
  2578. json = mg_str(s1);
  2579. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2580. ASSERT(mg_json_get(json, "$.b", &n) == 12 && n == 1);
  2581. ASSERT(mg_json_get(json, "$.c", &n) == 18 && n == 6);
  2582. ASSERT(mg_json_get(json, "$.c[0]", &n) == 19 && n == 2);
  2583. ASSERT(mg_json_get(json, "$.c[1]", &n) == 22 && n == 1);
  2584. ASSERT(mg_json_get(json, "$.c[3]", &n) == MG_JSON_NOT_FOUND);
  2585. json = mg_str(s2);
  2586. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 9);
  2587. ASSERT(mg_json_get(json, "$.a.b1", &n) == 11 && n == 2);
  2588. ASSERT(mg_json_get(json, "$.a.b2", &n) == MG_JSON_NOT_FOUND);
  2589. ASSERT(mg_json_get(json, "$.a.b", &n) == MG_JSON_NOT_FOUND);
  2590. ASSERT(mg_json_get(json, "$.a1", &n) == MG_JSON_NOT_FOUND);
  2591. ASSERT(mg_json_get(json, "$.c", &n) == 19 && n == 1);
  2592. {
  2593. double d = 0;
  2594. bool b = false;
  2595. int len;
  2596. char *str = NULL;
  2597. json = mg_str("{\"a\":\"b\"}");
  2598. str = mg_json_get_str(json, "$.a");
  2599. ASSERT(str != NULL);
  2600. // printf("---> [%s]\n", str);
  2601. ASSERT(strcmp(str, "b") == 0);
  2602. free(str);
  2603. json = mg_str("{\"a\": \"hi\\nthere\",\"b\": [12345, true]}");
  2604. str = mg_json_get_str(json, "$.a");
  2605. ASSERT(str != NULL);
  2606. ASSERT(strcmp(str, "hi\nthere") == 0);
  2607. free(str);
  2608. ASSERT(mg_json_get_long(json, "$.foo", -42) == -42);
  2609. ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 12345);
  2610. ASSERT(mg_json_get_num(json, "$.a", &d) == false);
  2611. ASSERT(mg_json_get_num(json, "$.c", &d) == false);
  2612. ASSERT(mg_json_get_num(json, "$.b[0]", &d) == true);
  2613. ASSERT(d == 12345);
  2614. ASSERT(mg_json_get_bool(json, "$.b", &b) == false);
  2615. ASSERT(mg_json_get_bool(json, "$.b[0]", &b) == false);
  2616. ASSERT(mg_json_get_bool(json, "$.b[1]", &b) == true);
  2617. ASSERT(b == true);
  2618. ASSERT(mg_json_get(json, "$.b[2]", &len) < 0);
  2619. json = mg_str("[\"YWJj\", \"0100026869\"]");
  2620. ASSERT((str = mg_json_get_b64(json, "$[0]", &len)) != NULL);
  2621. ASSERT(len == 3 && memcmp(str, "abc", (size_t) len) == 0);
  2622. free(str);
  2623. ASSERT((str = mg_json_get_hex(json, "$[1]", &len)) != NULL);
  2624. ASSERT(len == 5 && memcmp(str, "\x01\x00\x02hi", (size_t) len) == 0);
  2625. free(str);
  2626. json = mg_str("{\"a\":[1,2,3], \"ab\": 2}");
  2627. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2628. ASSERT(mg_json_get_long(json, "$.ab", -42) == 2);
  2629. ASSERT(mg_json_get_long(json, "$.ac", -42) == -42);
  2630. json = mg_str("{\"a\":[],\"b\":[1,2]}");
  2631. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == -42);
  2632. ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 1);
  2633. ASSERT(mg_json_get_long(json, "$.b[1]", -42) == 2);
  2634. ASSERT(mg_json_get_long(json, "$.b[2]", -42) == -42);
  2635. json = mg_str("[{\"a\":1,\"b\":2},{\"a\":3, \"b\":4}]");
  2636. ASSERT(mg_json_get_long(json, "$[0].a", -42) == 1);
  2637. ASSERT(mg_json_get_long(json, "$[0].b", -42) == 2);
  2638. ASSERT(mg_json_get_long(json, "$[1].a", -42) == 3);
  2639. ASSERT(mg_json_get_long(json, "$[1].b", -42) == 4);
  2640. ASSERT(mg_json_get_long(json, "$[2].a", -42) == -42);
  2641. json = mg_str("{\"a\":[1],\"b\":[2,3]}");
  2642. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2643. ASSERT(mg_json_get_long(json, "$.a[1]", -42) == -42);
  2644. json = mg_str("{\"a\":[1,[2,3], 4]}");
  2645. ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
  2646. ASSERT(mg_json_get_long(json, "$.a[1][0]", -42) == 2);
  2647. ASSERT(mg_json_get_long(json, "$.a[1][1]", -42) == 3);
  2648. ASSERT(mg_json_get_long(json, "$.a[1][2]", -42) == -42);
  2649. ASSERT(mg_json_get_long(json, "$.a[2]", -42) == 4);
  2650. ASSERT(mg_json_get_long(json, "$.a[3]", -42) == -42);
  2651. }
  2652. json = mg_str("{\"a\":[],\"b\":[1,2]}");
  2653. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2654. ASSERT(mg_json_get(json, "$.a[0]", &n) < 0 && n == 0);
  2655. json = mg_str("{\"a\":{},\"b\":[1,2]}");
  2656. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 2);
  2657. ASSERT(mg_json_get(json, "$.a[0]", &n) < 0 && n == 0);
  2658. json = mg_str("{\"a\":true,\"b\":[1,2]}");
  2659. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 4);
  2660. ASSERT(mg_json_get(json, "$.a[0]", &n) < 0 && n == 0);
  2661. json = mg_str("{\"a\":1,\"b\":[1,2]}");
  2662. ASSERT(mg_json_get(json, "$.a", &n) == 5 && n == 1);
  2663. ASSERT(mg_json_get(json, "$.a[0]", &n) < 0 && n == 0);
  2664. ASSERT(mg_json_get_long(mg_str("[0, 42]"), "$[1]", 0) == 42);
  2665. ASSERT(mg_json_get_long(mg_str("[[], 42]"), "$[1]", 0) == 42);
  2666. ASSERT(mg_json_get_long(mg_str("[{}, 42]"), "$[1]", 0) == 42);
  2667. json = mg_str("[{\"a\":1},{\"a\":2}]");
  2668. ASSERT(mg_json_get_long(json, "$[0]", -1) == -1);
  2669. ASSERT(mg_json_get_long(json, "$[0].a", -1) == 1);
  2670. ASSERT(mg_json_get_long(json, "$[1].a", -1) == 2);
  2671. ASSERT(mg_json_get_long(json, "$[2].a", -1) == -1);
  2672. json = mg_str("[{\"a1\":1},{\"a\":2}]");
  2673. ASSERT(mg_json_get_long(json, "$[0]", -1) == -1);
  2674. ASSERT(mg_json_get_long(json, "$[0].a", -1) == -1);
  2675. ASSERT(mg_json_get_long(json, "$[1].a", -1) == 2);
  2676. ASSERT(mg_json_get_long(json, "$[2].a", -1) == -1);
  2677. // mg_json_next()
  2678. json = mg_str("[1,true,{\"a\":[3],\"b\":42}]");
  2679. json_scan(json, 0);
  2680. {
  2681. struct mg_str k, v, sub = mg_str_n(json.ptr + 8, json.len - 8);
  2682. const char *a = "\"a\"", *b = "\"b\"";
  2683. ASSERT(mg_json_next(sub, 0, &k, &v) == 9);
  2684. ASSERT(mg_vcmp(&k, a) == 0);
  2685. ASSERT(mg_vcmp(&v, "[3]") == 0);
  2686. ASSERT(mg_json_next(sub, 9, &k, &v) == 15);
  2687. ASSERT(mg_vcmp(&k, b) == 0);
  2688. ASSERT(mg_vcmp(&v, "42") == 0);
  2689. ASSERT(mg_json_next(sub, 15, &k, &v) == 0);
  2690. }
  2691. }
  2692. static void resp_rpc(struct mg_rpc_req *r) {
  2693. int len = 0, off = mg_json_get(r->frame, "$.result", &len);
  2694. mg_xprintf(r->pfn, r->pfn_data, "%.*s", len, &r->frame.ptr[off]);
  2695. }
  2696. static void test_rpc(void) {
  2697. struct mg_rpc *head = NULL;
  2698. struct mg_iobuf io = {0, 0, 0, 256};
  2699. struct mg_rpc_req req = {&head, 0, mg_pfn_iobuf, &io, 0, {0, 0}};
  2700. mg_rpc_add(&head, mg_str("rpc.list"), mg_rpc_list, NULL);
  2701. {
  2702. req.frame = mg_str("{\"method\":\"rpc.list\"}");
  2703. mg_rpc_process(&req);
  2704. ASSERT(io.buf == NULL);
  2705. }
  2706. {
  2707. const char *resp = "{\"id\":1,\"result\":[\"rpc.list\"]}";
  2708. req.frame = mg_str("{\"id\": 1,\"method\":\"rpc.list\"}");
  2709. mg_rpc_process(&req);
  2710. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2711. mg_iobuf_free(&io);
  2712. }
  2713. {
  2714. const char *resp =
  2715. "{\"id\":true,\"error\":{\"code\":-32601,\"message\":\"foo not "
  2716. "found\"}}";
  2717. req.frame = mg_str("{\"id\": true,\"method\":\"foo\"}");
  2718. mg_rpc_process(&req);
  2719. // MG_INFO(("-> %s", io.buf));
  2720. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2721. mg_iobuf_free(&io);
  2722. }
  2723. {
  2724. const char *resp =
  2725. "{\"id\":true,\"error\":{\"code\":-32601,\"message\":\"foo not "
  2726. "found\"}}";
  2727. req.frame = mg_str("{\"id\": true,\"method\":\"foo\"}");
  2728. req.head = NULL;
  2729. mg_rpc_process(&req);
  2730. // MG_INFO(("-> %s", io.buf));
  2731. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2732. mg_iobuf_free(&io);
  2733. req.head = &head;
  2734. }
  2735. {
  2736. const char *resp = "{\"error\":{\"code\":-32700,\"message\":\"haha\"}}";
  2737. req.frame = mg_str("haha");
  2738. mg_rpc_process(&req);
  2739. // MG_INFO(("-> %s", io.buf));
  2740. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2741. mg_iobuf_free(&io);
  2742. }
  2743. {
  2744. const char *resp =
  2745. "{\"id\":1,\"error\":{\"code\":-32601,\"message\":\" not found\"}}";
  2746. req.frame = mg_str("{\"id\":1,\"result\":123}");
  2747. mg_rpc_process(&req);
  2748. // MG_INFO(("-> %s", io.buf));
  2749. ASSERT(strcmp((char *) io.buf, resp) == 0);
  2750. mg_iobuf_free(&io);
  2751. }
  2752. {
  2753. req.frame = mg_str("{\"id\":1,\"result\":123}");
  2754. mg_rpc_add(&head, mg_str(""), resp_rpc, NULL);
  2755. mg_rpc_process(&req);
  2756. MG_INFO(("-> %s", io.buf));
  2757. ASSERT(strcmp((char *) io.buf, "123") == 0);
  2758. mg_iobuf_free(&io);
  2759. }
  2760. mg_rpc_del(&head, NULL);
  2761. ASSERT(head == NULL);
  2762. }
  2763. static void ph(struct mg_connection *c, int ev, void *ev_data) {
  2764. if (ev == MG_EV_POLL) ++(*(int *) c->fn_data);
  2765. (void) c, (void) ev_data;
  2766. }
  2767. static void test_poll(void) {
  2768. int count = 0, i;
  2769. struct mg_mgr mgr;
  2770. mg_mgr_init(&mgr);
  2771. mg_http_listen(&mgr, "http://127.0.0.1:42346", ph,
  2772. &count); // To prevent bind errors on Windows
  2773. for (i = 0; i < 10; i++) mg_mgr_poll(&mgr, 0);
  2774. ASSERT(count == 10);
  2775. mg_mgr_free(&mgr);
  2776. }
  2777. #define NMESSAGES 99999
  2778. static uint32_t s_qcrc = 0;
  2779. static int s_out, s_in;
  2780. static void producer(void *param) {
  2781. struct mg_queue *q = (struct mg_queue *) param;
  2782. char tmp[64 * 1024], *buf;
  2783. size_t len, ofs = sizeof(tmp);
  2784. for (s_out = 0; s_out < NMESSAGES; s_out++) {
  2785. if (ofs >= sizeof(tmp)) mg_random(tmp, sizeof(tmp)), ofs = 0;
  2786. len = ((uint8_t *) tmp)[ofs] % 55U + 1U;
  2787. if (ofs + len > sizeof(tmp)) len = sizeof(tmp) - ofs;
  2788. while ((mg_queue_book(q, &buf, len)) < len) (void) 0;
  2789. memcpy(buf, &tmp[ofs], len);
  2790. s_qcrc = mg_crc32(s_qcrc, buf, len);
  2791. ofs += len;
  2792. #if 0
  2793. fprintf(stderr, "-->prod %3d %8x %-3lu %zu/%zu/%lu\n", s_out, s_qcrc, len, q->tail,
  2794. q->head, buf - q->buf);
  2795. #endif
  2796. mg_queue_add(q, len);
  2797. }
  2798. }
  2799. static uint32_t consumer(struct mg_queue *q) {
  2800. uint32_t crc = 0;
  2801. for (s_in = 0; s_in < NMESSAGES; s_in++) {
  2802. char *buf;
  2803. size_t len;
  2804. while ((len = mg_queue_next(q, &buf)) == 0) (void) 0;
  2805. crc = mg_crc32(crc, buf, len);
  2806. #if 0
  2807. fprintf(stderr, "-->cons %3u %8x %-3lu %zu/%zu/%lu\n", s_in, crc, len, q->tail,
  2808. q->head, buf - q->buf);
  2809. #endif
  2810. mg_queue_del(q, len);
  2811. }
  2812. return crc;
  2813. }
  2814. #if MG_ARCH == MG_ARCH_WIN32
  2815. static void start_thread(void (*f)(void *), void *p) {
  2816. _beginthread((void(__cdecl *)(void *)) f, 0, p);
  2817. }
  2818. #elif MG_ARCH == MG_ARCH_UNIX
  2819. #include <pthread.h>
  2820. static void start_thread(void (*f)(void *), void *p) {
  2821. union {
  2822. void (*f1)(void *);
  2823. void *(*f2)(void *);
  2824. } u = {f};
  2825. pthread_t thread_id = (pthread_t) 0;
  2826. pthread_attr_t attr;
  2827. (void) pthread_attr_init(&attr);
  2828. (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  2829. pthread_create(&thread_id, &attr, u.f2, p);
  2830. pthread_attr_destroy(&attr);
  2831. }
  2832. #else
  2833. static void start_thread(void (*f)(void *), void *p) {
  2834. (void) f, (void) p;
  2835. }
  2836. #endif
  2837. static void test_queue(void) {
  2838. char buf[512];
  2839. struct mg_queue queue;
  2840. uint32_t crc;
  2841. memset(buf, 0x55, sizeof(buf));
  2842. mg_queue_init(&queue, buf, sizeof(buf));
  2843. start_thread(producer, &queue); // Start producer in a separate thread
  2844. crc = consumer(&queue); // Consumer eats data in this thread
  2845. MG_INFO(("CRC1 %8x", s_qcrc)); // Show CRCs
  2846. MG_INFO(("CRC2 %8x", crc));
  2847. ASSERT(s_qcrc == crc);
  2848. }
  2849. static void test_md5_str(const char *string,
  2850. const unsigned char *expected_hash) {
  2851. mg_md5_ctx ctx;
  2852. unsigned char digest[16];
  2853. mg_md5_init(&ctx);
  2854. mg_md5_update(&ctx, (unsigned char *) string, strlen(string));
  2855. mg_md5_final(&ctx, digest);
  2856. ASSERT((memcmp(digest, expected_hash, 16) == 0));
  2857. }
  2858. static void test_md5(void) {
  2859. const unsigned char expected_hash_1[] = {0xe5, 0x45, 0x14, 0x96, 0xe1, 0x1d,
  2860. 0x7d, 0xa9, 0x62, 0x9f, 0xe0, 0x64,
  2861. 0xcb, 0x3d, 0x2b, 0x54};
  2862. const unsigned char expected_hash_2[] = {0x99, 0x33, 0xf6, 0x4d, 0x7a, 0xb5,
  2863. 0x0b, 0x0f, 0xf4, 0x35, 0xdc, 0x61,
  2864. 0x1d, 0xef, 0x20, 0xff};
  2865. const unsigned char expected_hash_3[] = {0xf7, 0x94, 0xc3, 0xa4, 0x56, 0x6d,
  2866. 0xc1, 0x10, 0x95, 0xfc, 0x56, 0x87,
  2867. 0xf8, 0xb1, 0x69, 0xf2};
  2868. test_md5_str("#&*%$DHFH(0x12345)^&*(^!@$%^^&&*", expected_hash_1);
  2869. test_md5_str("1298**&^%DHKSHFLS)(*)&^^%$#!!!!", expected_hash_2);
  2870. test_md5_str(")_)+_)!&^*%$#>>>{}}}{{{][[[[]]]", expected_hash_3);
  2871. }
  2872. static void test_sha1_str(const char *string,
  2873. const unsigned char *expected_hash) {
  2874. mg_sha1_ctx ctx;
  2875. unsigned char digest[20];
  2876. mg_sha1_init(&ctx);
  2877. mg_sha1_update(&ctx, (unsigned char *) string, strlen(string));
  2878. mg_sha1_final(digest, &ctx);
  2879. ASSERT((memcmp(digest, expected_hash, 20) == 0));
  2880. }
  2881. static void test_sha1(void) {
  2882. const unsigned char expected_hash_1[] = {
  2883. 0x02, 0xaf, 0x27, 0x00, 0xf7, 0xba, 0xb5, 0xf5, 0xf3, 0x69,
  2884. 0xd8, 0x80, 0x01, 0x0d, 0x6a, 0x28, 0x31, 0x63, 0x1f, 0x92};
  2885. const unsigned char expected_hash_2[] = {
  2886. 0xaa, 0xe4, 0x39, 0xe8, 0xb4, 0x72, 0x47, 0xe5, 0x1a, 0x6d,
  2887. 0x82, 0x25, 0x5e, 0x9f, 0x32, 0xd9, 0x93, 0x0a, 0x5f, 0xfb};
  2888. const unsigned char expected_hash_3[] = {
  2889. 0xa0, 0xdd, 0xd2, 0xa1, 0x52, 0xdf, 0xa9, 0xb8, 0x7e, 0x73,
  2890. 0x32, 0x6a, 0x31, 0x28, 0xe9, 0x6d, 0x3a, 0x90, 0x82, 0x58};
  2891. test_sha1_str("#&*%$DHFH(0x12345)^&*(^!@$%^^&&*", expected_hash_1);
  2892. test_sha1_str("1298**&^%DHKSHFLS)(*)&^^%$#!!!!", expected_hash_2);
  2893. test_sha1_str(")_)+_)!&^*%$#>>>{}}}{{{][[[[]]]", expected_hash_3);
  2894. }
  2895. int main(void) {
  2896. const char *debug_level = getenv("V");
  2897. if (debug_level == NULL) debug_level = "3";
  2898. mg_log_set(atoi(debug_level));
  2899. test_json();
  2900. test_queue();
  2901. test_rpc();
  2902. test_str();
  2903. test_globmatch();
  2904. test_get_header_var();
  2905. test_http_parse();
  2906. test_rewrites();
  2907. test_check_ip_acl();
  2908. test_udp();
  2909. test_packed();
  2910. test_crc32();
  2911. test_multipart();
  2912. test_invalid_listen_addr();
  2913. test_http_chunked();
  2914. test_http_upload();
  2915. test_http_stream_buffer();
  2916. test_util();
  2917. test_dns();
  2918. test_timer();
  2919. test_url();
  2920. test_iobuf();
  2921. test_commalist();
  2922. test_base64();
  2923. test_http_get_var();
  2924. test_http_client();
  2925. test_tls();
  2926. test_ws();
  2927. test_ws_fragmentation();
  2928. test_host_validation();
  2929. test_http_server();
  2930. test_http_404();
  2931. test_http_no_content_length();
  2932. test_http_pipeline();
  2933. test_http_range();
  2934. test_sntp();
  2935. test_mqtt();
  2936. test_poll();
  2937. test_md5();
  2938. test_sha1();
  2939. printf("SUCCESS. Total tests: %d\n", s_num_tests);
  2940. return EXIT_SUCCESS;
  2941. }