public.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. /* Copyright (c) 2015 the Civetweb developers
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. #ifdef _MSC_VER
  22. #define _CRT_SECURE_NO_WARNINGS
  23. #endif
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <time.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include "public.h"
  30. #include <civetweb.h>
  31. #if defined(_WIN32)
  32. #include <Windows.h>
  33. #define mg_Sleep(x) (Sleep(x * 1000))
  34. #else
  35. #include <unistd.h>
  36. #define mg_Sleep(x) (sleep(x))
  37. #endif
  38. /* This unit test file uses the excellent Check unit testing library.
  39. * The API documentation is available here:
  40. * http://check.sourceforge.net/doc/check_html/index.html
  41. */
  42. START_TEST(test_mg_version)
  43. {
  44. const char *ver = mg_version();
  45. unsigned major = 0, minor = 0;
  46. int ret;
  47. ck_assert(ver != NULL);
  48. ck_assert_str_eq(ver, CIVETWEB_VERSION);
  49. /* check structure of version string */
  50. ret = sscanf(ver, "%u.%u", &major, &minor);
  51. ck_assert_int_eq(ret, 2);
  52. ck_assert_uint_ge(major, 1);
  53. }
  54. END_TEST
  55. START_TEST(test_mg_get_valid_options)
  56. {
  57. int i;
  58. const struct mg_option *default_options = mg_get_valid_options();
  59. ck_assert(default_options != NULL);
  60. for (i = 0; default_options[i].name != NULL; i++) {
  61. ck_assert(default_options[i].name != NULL);
  62. ck_assert(strlen(default_options[i].name) > 0);
  63. ck_assert(((int)default_options[i].type) > 0);
  64. }
  65. ck_assert(i > 0);
  66. }
  67. END_TEST
  68. START_TEST(test_mg_get_builtin_mime_type)
  69. {
  70. ck_assert_str_eq(mg_get_builtin_mime_type("x.txt"), "text/plain");
  71. ck_assert_str_eq(mg_get_builtin_mime_type("x.html"), "text/html");
  72. ck_assert_str_eq(mg_get_builtin_mime_type("x.HTML"), "text/html");
  73. ck_assert_str_eq(mg_get_builtin_mime_type("x.hTmL"), "text/html");
  74. ck_assert_str_eq(mg_get_builtin_mime_type("/abc/def/ghi.htm"), "text/html");
  75. ck_assert_str_eq(mg_get_builtin_mime_type("x.unknown_extention_xyz"),
  76. "text/plain");
  77. }
  78. END_TEST
  79. START_TEST(test_mg_strncasecmp)
  80. {
  81. ck_assert(mg_strncasecmp("abc", "abc", 3) == 0);
  82. ck_assert(mg_strncasecmp("abc", "abcd", 3) == 0);
  83. ck_assert(mg_strncasecmp("abc", "abcd", 4) != 0);
  84. ck_assert(mg_strncasecmp("a", "A", 1) == 0);
  85. ck_assert(mg_strncasecmp("A", "B", 1) < 0);
  86. ck_assert(mg_strncasecmp("A", "b", 1) < 0);
  87. ck_assert(mg_strncasecmp("a", "B", 1) < 0);
  88. ck_assert(mg_strncasecmp("a", "b", 1) < 0);
  89. ck_assert(mg_strncasecmp("b", "A", 1) > 0);
  90. ck_assert(mg_strncasecmp("B", "A", 1) > 0);
  91. ck_assert(mg_strncasecmp("b", "a", 1) > 0);
  92. ck_assert(mg_strncasecmp("B", "a", 1) > 0);
  93. ck_assert(mg_strncasecmp("xAx", "xBx", 3) < 0);
  94. ck_assert(mg_strncasecmp("xAx", "xbx", 3) < 0);
  95. ck_assert(mg_strncasecmp("xax", "xBx", 3) < 0);
  96. ck_assert(mg_strncasecmp("xax", "xbx", 3) < 0);
  97. ck_assert(mg_strncasecmp("xbx", "xAx", 3) > 0);
  98. ck_assert(mg_strncasecmp("xBx", "xAx", 3) > 0);
  99. ck_assert(mg_strncasecmp("xbx", "xax", 3) > 0);
  100. ck_assert(mg_strncasecmp("xBx", "xax", 3) > 0);
  101. }
  102. END_TEST
  103. START_TEST(test_mg_get_cookie)
  104. {
  105. char buf[32];
  106. int ret;
  107. const char *longcookie = "key1=1; key2=2; key3; key4=4; key5=; key6; "
  108. "key7=this+is+it; key8=8; key9";
  109. /* invalid result buffer */
  110. ret = mg_get_cookie("", "notfound", NULL, 999);
  111. ck_assert_int_eq(ret, -2);
  112. /* zero size result buffer */
  113. ret = mg_get_cookie("", "notfound", buf, 0);
  114. ck_assert_int_eq(ret, -2);
  115. /* too small result buffer */
  116. ret = mg_get_cookie("key=toooooooooolong", "key", buf, 4);
  117. ck_assert_int_eq(ret, -3);
  118. /* key not found in string */
  119. ret = mg_get_cookie("", "notfound", buf, sizeof(buf));
  120. ck_assert_int_eq(ret, -1);
  121. ret = mg_get_cookie(longcookie, "notfound", buf, sizeof(buf));
  122. ck_assert_int_eq(ret, -1);
  123. /* key not found in string */
  124. ret = mg_get_cookie("key1=1; key2=2; key3=3", "notfound", buf, sizeof(buf));
  125. ck_assert_int_eq(ret, -1);
  126. /* keys are found as first, middle and last key */
  127. memset(buf, 77, sizeof(buf));
  128. ret = mg_get_cookie("key1=1; key2=2; key3=3", "key1", buf, sizeof(buf));
  129. ck_assert_int_eq(ret, 1);
  130. ck_assert_str_eq("1", buf);
  131. memset(buf, 77, sizeof(buf));
  132. ret = mg_get_cookie("key1=1; key2=2; key3=3", "key2", buf, sizeof(buf));
  133. ck_assert_int_eq(ret, 1);
  134. ck_assert_str_eq("2", buf);
  135. memset(buf, 77, sizeof(buf));
  136. ret = mg_get_cookie("key1=1; key2=2; key3=3", "key3", buf, sizeof(buf));
  137. ck_assert_int_eq(ret, 1);
  138. ck_assert_str_eq("3", buf);
  139. /* longer value in the middle of a longer string */
  140. memset(buf, 77, sizeof(buf));
  141. ret = mg_get_cookie(longcookie, "key7", buf, sizeof(buf));
  142. ck_assert_int_eq(ret, 10);
  143. ck_assert_str_eq("this+is+it", buf);
  144. /* key with = but without value in the middle of a longer string */
  145. memset(buf, 77, sizeof(buf));
  146. ret = mg_get_cookie(longcookie, "key5", buf, sizeof(buf));
  147. ck_assert_int_eq(ret, 0);
  148. ck_assert_str_eq("", buf);
  149. /* key without = and without value in the middle of a longer string */
  150. memset(buf, 77, sizeof(buf));
  151. ret = mg_get_cookie(longcookie, "key6", buf, sizeof(buf));
  152. ck_assert_int_eq(ret, -1);
  153. /* TODO: mg_get_cookie and mg_get_var(2) should have the same behavior */
  154. }
  155. END_TEST
  156. START_TEST(test_mg_get_var)
  157. {
  158. char buf[32];
  159. int ret;
  160. const char *shortquery = "key1=1&key2=2&key3=3";
  161. const char *longquery = "key1=1&key2=2&key3&key4=4&key5=&key6&"
  162. "key7=this+is+it&key8=8&key9&&key10=&&"
  163. "key7=that+is+it&key12=12";
  164. /* invalid result buffer */
  165. ret = mg_get_var2("", 0, "notfound", NULL, 999, 0);
  166. ck_assert_int_eq(ret, -2);
  167. /* zero size result buffer */
  168. ret = mg_get_var2("", 0, "notfound", buf, 0, 0);
  169. ck_assert_int_eq(ret, -2);
  170. /* too small result buffer */
  171. ret = mg_get_var2("key=toooooooooolong", 19, "key", buf, 4, 0);
  172. /* ck_assert_int_eq(ret, -3);
  173. --> TODO: mg_get_cookie returns -3, mg_get_var -2. This should be
  174. unified. */
  175. ck_assert(ret < 0);
  176. /* key not found in string */
  177. ret = mg_get_var2("", 0, "notfound", buf, sizeof(buf), 0);
  178. ck_assert_int_eq(ret, -1);
  179. ret = mg_get_var2(
  180. longquery, strlen(longquery), "notfound", buf, sizeof(buf), 0);
  181. ck_assert_int_eq(ret, -1);
  182. /* key not found in string */
  183. ret = mg_get_var2(
  184. shortquery, strlen(shortquery), "notfound", buf, sizeof(buf), 0);
  185. ck_assert_int_eq(ret, -1);
  186. /* key not found in string */
  187. ret = mg_get_var2("key1=1&key2=2&key3=3&notfound=here",
  188. strlen(shortquery),
  189. "notfound",
  190. buf,
  191. sizeof(buf),
  192. 0);
  193. ck_assert_int_eq(ret, -1);
  194. /* key not found in string */
  195. ret = mg_get_var2(
  196. shortquery, strlen(shortquery), "key1", buf, sizeof(buf), 1);
  197. ck_assert_int_eq(ret, -1);
  198. /* keys are found as first, middle and last key */
  199. memset(buf, 77, sizeof(buf));
  200. ret = mg_get_var2(
  201. shortquery, strlen(shortquery), "key1", buf, sizeof(buf), 0);
  202. ck_assert_int_eq(ret, 1);
  203. ck_assert_str_eq("1", buf);
  204. memset(buf, 77, sizeof(buf));
  205. ret = mg_get_var2(
  206. shortquery, strlen(shortquery), "key2", buf, sizeof(buf), 0);
  207. ck_assert_int_eq(ret, 1);
  208. ck_assert_str_eq("2", buf);
  209. memset(buf, 77, sizeof(buf));
  210. ret = mg_get_var2(
  211. shortquery, strlen(shortquery), "key3", buf, sizeof(buf), 0);
  212. ck_assert_int_eq(ret, 1);
  213. ck_assert_str_eq("3", buf);
  214. /* longer value in the middle of a longer string */
  215. memset(buf, 77, sizeof(buf));
  216. ret =
  217. mg_get_var2(longquery, strlen(longquery), "key7", buf, sizeof(buf), 0);
  218. ck_assert_int_eq(ret, 10);
  219. ck_assert_str_eq("this is it", buf);
  220. /* longer value in the middle of a longer string - seccond occurance of key
  221. */
  222. memset(buf, 77, sizeof(buf));
  223. ret =
  224. mg_get_var2(longquery, strlen(longquery), "key7", buf, sizeof(buf), 1);
  225. ck_assert_int_eq(ret, 10);
  226. ck_assert_str_eq("that is it", buf);
  227. /* key with = but without value in the middle of a longer string */
  228. memset(buf, 77, sizeof(buf));
  229. ret =
  230. mg_get_var2(longquery, strlen(longquery), "key5", buf, sizeof(buf), 0);
  231. ck_assert_int_eq(ret, 0);
  232. ck_assert_str_eq(buf, "");
  233. /* key without = and without value in the middle of a longer string */
  234. memset(buf, 77, sizeof(buf));
  235. ret =
  236. mg_get_var2(longquery, strlen(longquery), "key6", buf, sizeof(buf), 0);
  237. ck_assert_int_eq(ret, -1);
  238. ck_assert_str_eq(buf, "");
  239. /* TODO: this is the same situation as with mg_get_value */
  240. }
  241. END_TEST
  242. START_TEST(test_mg_md5)
  243. {
  244. char buf[33];
  245. char *ret;
  246. const char *long_str =
  247. "_123456789A123456789B123456789C123456789D123456789E123456789F123456789"
  248. "G123456789H123456789I123456789J123456789K123456789L123456789M123456789"
  249. "N123456789O123456789P123456789Q123456789R123456789S123456789T123456789"
  250. "U123456789V123456789W123456789X123456789Y123456789Z";
  251. memset(buf, 77, sizeof(buf));
  252. ret = mg_md5(buf, NULL);
  253. ck_assert_str_eq(buf, "d41d8cd98f00b204e9800998ecf8427e");
  254. ck_assert_str_eq(ret, "d41d8cd98f00b204e9800998ecf8427e");
  255. ck_assert_ptr_eq(ret, buf);
  256. memset(buf, 77, sizeof(buf));
  257. ret = mg_md5(buf, "The quick brown fox jumps over the lazy dog.", NULL);
  258. ck_assert_str_eq(buf, "e4d909c290d0fb1ca068ffaddf22cbd0");
  259. ck_assert_str_eq(ret, "e4d909c290d0fb1ca068ffaddf22cbd0");
  260. ck_assert_ptr_eq(ret, buf);
  261. memset(buf, 77, sizeof(buf));
  262. ret = mg_md5(buf,
  263. "",
  264. "The qu",
  265. "ick bro",
  266. "",
  267. "wn fox ju",
  268. "m",
  269. "ps over the la",
  270. "",
  271. "",
  272. "zy dog.",
  273. "",
  274. NULL);
  275. ck_assert_str_eq(buf, "e4d909c290d0fb1ca068ffaddf22cbd0");
  276. ck_assert_str_eq(ret, "e4d909c290d0fb1ca068ffaddf22cbd0");
  277. ck_assert_ptr_eq(ret, buf);
  278. memset(buf, 77, sizeof(buf));
  279. ret = mg_md5(buf, long_str, NULL);
  280. ck_assert_str_eq(buf, "1cb13cf9f16427807f081b2138241f08");
  281. ck_assert_str_eq(ret, "1cb13cf9f16427807f081b2138241f08");
  282. ck_assert_ptr_eq(ret, buf);
  283. memset(buf, 77, sizeof(buf));
  284. ret = mg_md5(buf, long_str + 1, NULL);
  285. ck_assert_str_eq(buf, "cf62d3264334154f5779d3694cc5093f");
  286. ck_assert_str_eq(ret, "cf62d3264334154f5779d3694cc5093f");
  287. ck_assert_ptr_eq(ret, buf);
  288. }
  289. END_TEST
  290. START_TEST(test_mg_url_encode)
  291. {
  292. char buf[20];
  293. int ret;
  294. memset(buf, 77, sizeof(buf));
  295. ret = mg_url_encode("abc", buf, sizeof(buf));
  296. ck_assert_int_eq(3, ret);
  297. ck_assert_str_eq("abc", buf);
  298. memset(buf, 77, sizeof(buf));
  299. ret = mg_url_encode("a%b/c&d.e", buf, sizeof(buf));
  300. ck_assert_int_eq(15, ret);
  301. ck_assert_str_eq("a%25b%2fc%26d.e", buf);
  302. memset(buf, 77, sizeof(buf));
  303. ret = mg_url_encode("%%%", buf, 4);
  304. ck_assert_int_eq(-1, ret);
  305. ck_assert_str_eq("%25", buf);
  306. }
  307. END_TEST
  308. START_TEST(test_mg_url_decode)
  309. {
  310. char buf[20];
  311. int ret;
  312. ret = mg_url_decode("abc", 3, buf, sizeof(buf), 0);
  313. ck_assert_int_eq(ret, 3);
  314. ck_assert_str_eq(buf, "abc");
  315. ret = mg_url_decode("abcdef", 3, buf, sizeof(buf), 0);
  316. ck_assert_int_eq(ret, 3);
  317. ck_assert_str_eq(buf, "abc");
  318. ret = mg_url_decode("x+y", 3, buf, sizeof(buf), 0);
  319. ck_assert_int_eq(ret, 3);
  320. ck_assert_str_eq(buf, "x+y");
  321. ret = mg_url_decode("x+y", 3, buf, sizeof(buf), 1);
  322. ck_assert_int_eq(ret, 3);
  323. ck_assert_str_eq(buf, "x y");
  324. ret = mg_url_decode("%25", 3, buf, sizeof(buf), 1);
  325. ck_assert_int_eq(ret, 1);
  326. ck_assert_str_eq(buf, "%");
  327. }
  328. END_TEST
  329. START_TEST(test_the_test_environment)
  330. {
  331. char wd[300];
  332. char buf[500];
  333. FILE *f;
  334. struct stat st;
  335. int ret;
  336. memset(wd, 0, sizeof(wd));
  337. memset(buf, 0, sizeof(buf));
  338. /* Get the current working directory */
  339. #ifdef _WIN32
  340. (void)GetCurrentDirectoryA(sizeof(wd), wd);
  341. wd[sizeof(wd) - 1] = 0;
  342. #else
  343. (void)getcwd(wd, sizeof(wd));
  344. wd[sizeof(wd) - 1] = 0;
  345. #endif
  346. /* Check the pem file */
  347. #ifdef _WIN32
  348. strcpy(buf, wd);
  349. strcat(buf, "\\resources\\ssl_cert.pem");
  350. f = fopen(buf, "rb");
  351. #else
  352. strcpy(buf, wd);
  353. strcat(buf, "/resources/ssl_cert.pem");
  354. f = fopen(buf, "r");
  355. #endif
  356. if (f) {
  357. fclose(f);
  358. } else {
  359. ck_abort_msg("%s not found", buf);
  360. }
  361. /* Check the test dir */
  362. #ifdef _WIN32
  363. strcpy(buf, wd);
  364. strcat(buf, "\\test");
  365. #else
  366. strcpy(buf, wd);
  367. strcat(buf, "/test");
  368. #endif
  369. memset(&st, 0, sizeof(st));
  370. ret = stat(buf, &st);
  371. if (!ret) {
  372. fclose(f);
  373. } else {
  374. ck_abort_msg("%s not found", buf);
  375. }
  376. }
  377. END_TEST
  378. static int log_msg_func(const struct mg_connection *conn, const char *message)
  379. {
  380. struct mg_context *ctx;
  381. char *ud;
  382. ck_assert(conn != NULL);
  383. ctx = mg_get_context(conn);
  384. ck_assert(ctx != NULL);
  385. ud = (char *)mg_get_user_data(ctx);
  386. strncpy(ud, message, 255);
  387. ud[255] = 0;
  388. return 1;
  389. }
  390. START_TEST(test_mg_start_stop_http_server)
  391. {
  392. struct mg_context *ctx;
  393. const char *OPTIONS[] = {
  394. "document_root", ".", "listening_ports", "8080", NULL,
  395. };
  396. size_t ports_cnt;
  397. int ports[16];
  398. int ssl[16];
  399. struct mg_callbacks callbacks;
  400. char errmsg[256];
  401. memset(ports, 0, sizeof(ports));
  402. memset(ssl, 0, sizeof(ssl));
  403. memset(&callbacks, 0, sizeof(callbacks));
  404. memset(errmsg, 0, sizeof(errmsg));
  405. callbacks.log_message = log_msg_func;
  406. ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS);
  407. mg_Sleep(1);
  408. ck_assert_str_eq(errmsg, "");
  409. ck_assert(ctx != NULL);
  410. ports_cnt = mg_get_ports(ctx, 16, ports, ssl);
  411. ck_assert_uint_eq(ports_cnt, 1);
  412. ck_assert_int_eq(ports[0], 8080);
  413. ck_assert_int_eq(ssl[0], 0);
  414. ck_assert_int_eq(ports[1], 0);
  415. ck_assert_int_eq(ssl[1], 0);
  416. mg_Sleep(1);
  417. mg_stop(ctx);
  418. }
  419. END_TEST
  420. START_TEST(test_mg_start_stop_https_server)
  421. {
  422. struct mg_context *ctx;
  423. const char *OPTIONS[] = {
  424. "document_root",
  425. ".",
  426. "listening_ports",
  427. "8080,8443s",
  428. "ssl_certificate",
  429. "resources/ssl_cert.pem", // TODO: check working path of CI test
  430. // system
  431. NULL,
  432. };
  433. size_t ports_cnt;
  434. int ports[16];
  435. int ssl[16];
  436. struct mg_callbacks callbacks;
  437. char errmsg[256];
  438. memset(ports, 0, sizeof(ports));
  439. memset(ssl, 0, sizeof(ssl));
  440. memset(&callbacks, 0, sizeof(callbacks));
  441. memset(errmsg, 0, sizeof(errmsg));
  442. callbacks.log_message = log_msg_func;
  443. ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS);
  444. mg_Sleep(1);
  445. ck_assert_str_eq(errmsg, "");
  446. ck_assert(ctx != NULL);
  447. ports_cnt = mg_get_ports(ctx, 16, ports, ssl);
  448. ck_assert_uint_eq(ports_cnt, 2);
  449. ck_assert_int_eq(ports[0], 8080);
  450. ck_assert_int_eq(ssl[0], 0);
  451. ck_assert_int_eq(ports[1], 8443);
  452. ck_assert_int_eq(ssl[1], 1);
  453. ck_assert_int_eq(ports[2], 0);
  454. ck_assert_int_eq(ssl[2], 0);
  455. mg_Sleep(1);
  456. mg_stop(ctx);
  457. }
  458. END_TEST
  459. static struct mg_context *g_ctx;
  460. static int request_test_handler(struct mg_connection *conn, void *cbdata)
  461. {
  462. int i;
  463. char chunk_data[32];
  464. const struct mg_request_info *ri;
  465. struct mg_context *ctx;
  466. void *ud, *cud;
  467. ctx = mg_get_context(conn);
  468. ud = mg_get_user_data(ctx);
  469. ri = mg_get_request_info(conn);
  470. ck_assert(ri != NULL);
  471. ck_assert(ctx == g_ctx);
  472. ck_assert(ud == &g_ctx);
  473. mg_set_user_connection_data(conn, (void *)6543);
  474. cud = mg_get_user_connection_data(conn);
  475. ck_assert(cud == (void *)6543);
  476. ck_assert(cbdata == (void *)7);
  477. strcpy(chunk_data, "123456789A123456789B123456789C");
  478. mg_printf(conn,
  479. "HTTP/1.1 200 OK\r\n"
  480. "Transfer-Encoding: chunked\r\n"
  481. "Content-Type: text/plain\r\n\r\n");
  482. for (i = 1; i <= 10; i++) {
  483. mg_printf(conn, "%x\r\n", i);
  484. mg_write(conn, chunk_data, (unsigned)i);
  485. mg_printf(conn, "\r\n");
  486. }
  487. mg_printf(conn, "0\r\n\r\n");
  488. return 1;
  489. }
  490. START_TEST(test_request_handlers)
  491. {
  492. char ebuf[100];
  493. struct mg_context *ctx;
  494. struct mg_connection *conn;
  495. const struct mg_request_info *ri;
  496. char uri[64];
  497. char buf[1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 8];
  498. const char *expected =
  499. "112123123412345123456123456712345678123456789123456789A";
  500. int i;
  501. const char *request = "GET /U7 HTTP/1.0\r\n\r\n";
  502. #if defined(USE_IPV6) && defined(NO_SSL)
  503. const char *HTTP_PORT = "8084,[::]:8086";
  504. short ipv4_port = 8084;
  505. short ipv6_port = 8086;
  506. #elif !defined(USE_IPV6) && defined(NO_SSL)
  507. const char *HTTP_PORT = "8084";
  508. short ipv4_port = 8084;
  509. #elif defined(USE_IPV6) && !defined(NO_SSL)
  510. const char *HTTP_PORT = "8084,[::]:8086,8194r,[::]:8196r,8094s,[::]:8096s";
  511. short ipv4_port = 8084;
  512. short ipv4s_port = 8094;
  513. short ipv4r_port = 8194;
  514. short ipv6_port = 8086;
  515. short ipv6s_port = 8096;
  516. short ipv6r_port = 8196;
  517. #elif !defined(USE_IPV6) && !defined(NO_SSL)
  518. const char *HTTP_PORT = "8084,8194r,8094s";
  519. short ipv4_port = 8084;
  520. short ipv4s_port = 8094;
  521. short ipv4r_port = 8194;
  522. #endif
  523. const char *OPTIONS[8]; /* initializer list here is rejected by CI test */
  524. const char *opt;
  525. FILE *f;
  526. memset((void *)OPTIONS, 0, sizeof(OPTIONS));
  527. OPTIONS[0] = "listening_ports";
  528. OPTIONS[1] = HTTP_PORT;
  529. OPTIONS[2] = "document_root";
  530. OPTIONS[3] = ".";
  531. #ifndef NO_SSL
  532. OPTIONS[4] = "ssl_certificate";
  533. OPTIONS[5] = "resources/ssl_cert.pem";
  534. #endif
  535. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL);
  536. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL);
  537. ctx = mg_start(NULL, &g_ctx, OPTIONS);
  538. ck_assert(ctx != NULL);
  539. g_ctx = ctx;
  540. opt = mg_get_option(ctx, "listening_ports");
  541. ck_assert_str_eq(opt, HTTP_PORT);
  542. opt = mg_get_option(ctx, "cgi_environment");
  543. ck_assert_str_eq(opt, "");
  544. opt = mg_get_option(ctx, "unknown_option_name");
  545. ck_assert(opt == NULL);
  546. for (i = 0; i < 1000; i++) {
  547. sprintf(uri, "/U%u", i);
  548. mg_set_request_handler(ctx, uri, request_test_handler, NULL);
  549. }
  550. for (i = 500; i < 800; i++) {
  551. sprintf(uri, "/U%u", i);
  552. mg_set_request_handler(ctx, uri, NULL, (void *)1);
  553. }
  554. for (i = 600; i >= 0; i--) {
  555. sprintf(uri, "/U%u", i);
  556. mg_set_request_handler(ctx, uri, NULL, (void *)2);
  557. }
  558. for (i = 750; i <= 1000; i++) {
  559. sprintf(uri, "/U%u", i);
  560. mg_set_request_handler(ctx, uri, NULL, (void *)3);
  561. }
  562. for (i = 5; i < 9; i++) {
  563. sprintf(uri, "/U%u", i);
  564. mg_set_request_handler(
  565. ctx, uri, request_test_handler, (void *)(ptrdiff_t)i);
  566. }
  567. /* Try to load non existing file */
  568. conn = mg_download("localhost",
  569. ipv4_port,
  570. 0,
  571. ebuf,
  572. sizeof(ebuf),
  573. "%s",
  574. "GET /file/not/found HTTP/1.0\r\n\r\n");
  575. ck_assert(conn != NULL);
  576. ri = mg_get_request_info(conn);
  577. ck_assert(ri != NULL);
  578. ck_assert_str_eq(ri->uri, "404");
  579. mg_close_connection(conn);
  580. /* Get data from callback */
  581. conn = mg_download(
  582. "localhost", ipv4_port, 0, ebuf, sizeof(ebuf), "%s", request);
  583. ck_assert(conn != NULL);
  584. ri = mg_get_request_info(conn);
  585. ck_assert(ri != NULL);
  586. ck_assert_str_eq(ri->uri, "200");
  587. i = mg_read(conn, buf, sizeof(buf));
  588. ck_assert_int_eq(i, (int)strlen(expected));
  589. buf[i] = 0;
  590. ck_assert_str_eq(buf, expected);
  591. mg_close_connection(conn);
  592. /* Get data from callback using http://127.0.0.1 */
  593. conn = mg_download(
  594. "127.0.0.1", ipv4_port, 0, ebuf, sizeof(ebuf), "%s", request);
  595. ck_assert(conn != NULL);
  596. ri = mg_get_request_info(conn);
  597. ck_assert(ri != NULL);
  598. ck_assert_str_eq(ri->uri, "200");
  599. i = mg_read(conn, buf, sizeof(buf));
  600. ck_assert_int_eq(i, (int)strlen(expected));
  601. buf[i] = 0;
  602. ck_assert_str_eq(buf, expected);
  603. mg_close_connection(conn);
  604. #if defined(USE_IPV6)
  605. /* Get data from callback using http://[::1] */
  606. conn =
  607. mg_download("[::1]", ipv6_port, 0, ebuf, sizeof(ebuf), "%s", request);
  608. ck_assert(conn != NULL);
  609. ri = mg_get_request_info(conn);
  610. ck_assert(ri != NULL);
  611. ck_assert_str_eq(ri->uri, "200");
  612. i = mg_read(conn, buf, sizeof(buf));
  613. ck_assert_int_eq(i, (int)strlen(expected));
  614. buf[i] = 0;
  615. ck_assert_str_eq(buf, expected);
  616. mg_close_connection(conn);
  617. #endif
  618. #if !defined(NO_SSL)
  619. /* Get data from callback using https://127.0.0.1 */
  620. conn = mg_download(
  621. "127.0.0.1", ipv4s_port, 1, ebuf, sizeof(ebuf), "%s", request);
  622. ck_assert(conn != NULL);
  623. ri = mg_get_request_info(conn);
  624. ck_assert(ri != NULL);
  625. ck_assert_str_eq(ri->uri, "200");
  626. i = mg_read(conn, buf, sizeof(buf));
  627. ck_assert_int_eq(i, (int)strlen(expected));
  628. buf[i] = 0;
  629. ck_assert_str_eq(buf, expected);
  630. mg_close_connection(conn);
  631. /* Get redirect from callback using http://127.0.0.1 */
  632. conn = mg_download(
  633. "127.0.0.1", ipv4r_port, 0, ebuf, sizeof(ebuf), "%s", request);
  634. ck_assert(conn != NULL);
  635. ri = mg_get_request_info(conn);
  636. ck_assert(ri != NULL);
  637. ck_assert_str_eq(ri->uri, "302");
  638. i = mg_read(conn, buf, sizeof(buf));
  639. ck_assert_int_eq(i, -1);
  640. mg_close_connection(conn);
  641. #endif
  642. #if defined(USE_IPV6) && !defined(NO_SSL)
  643. /* Get data from callback using https://[::1] */
  644. conn =
  645. mg_download("[::1]", ipv6s_port, 1, ebuf, sizeof(ebuf), "%s", request);
  646. ck_assert(conn != NULL);
  647. ri = mg_get_request_info(conn);
  648. ck_assert(ri != NULL);
  649. ck_assert_str_eq(ri->uri, "200");
  650. i = mg_read(conn, buf, sizeof(buf));
  651. ck_assert_int_eq(i, (int)strlen(expected));
  652. buf[i] = 0;
  653. ck_assert_str_eq(buf, expected);
  654. mg_close_connection(conn);
  655. /* Get redirect from callback using http://127.0.0.1 */
  656. conn =
  657. mg_download("[::1]", ipv6r_port, 0, ebuf, sizeof(ebuf), "%s", request);
  658. ck_assert(conn != NULL);
  659. ri = mg_get_request_info(conn);
  660. ck_assert(ri != NULL);
  661. ck_assert_str_eq(ri->uri, "302");
  662. i = mg_read(conn, buf, sizeof(buf));
  663. ck_assert_int_eq(i, -1);
  664. mg_close_connection(conn);
  665. #endif
  666. /* It seems to be impossible to find out what the actual working
  667. * directory of the CI test environment is. Before breaking another
  668. * dozen of builds by trying blindly with different paths, just
  669. * create the file here */
  670. #ifdef _WIN32
  671. f = fopen("test.txt", "wb");
  672. #else
  673. f = fopen("test.txt", "w");
  674. #endif
  675. fwrite("simple text file\n", 17, 1, f);
  676. fclose(f);
  677. /* Get static data */
  678. conn = mg_download("localhost",
  679. ipv4_port,
  680. 0,
  681. ebuf,
  682. sizeof(ebuf),
  683. "%s",
  684. "GET /test.txt HTTP/1.0\r\n\r\n");
  685. ck_assert(conn != NULL);
  686. ri = mg_get_request_info(conn);
  687. ck_assert(ri != NULL);
  688. ck_assert_str_eq(ri->uri, "200");
  689. i = mg_read(conn, buf, sizeof(buf));
  690. ck_assert_int_eq(i, 17);
  691. if ((i >= 0) && (i < (int)sizeof(buf))) {
  692. buf[i] = 0;
  693. }
  694. ck_assert_str_eq(buf, "simple text file\n");
  695. mg_close_connection(conn);
  696. /* Get directory listing */
  697. conn = mg_download("localhost",
  698. ipv4_port,
  699. 0,
  700. ebuf,
  701. sizeof(ebuf),
  702. "%s",
  703. "GET / HTTP/1.0\r\n\r\n");
  704. ck_assert(conn != NULL);
  705. ri = mg_get_request_info(conn);
  706. ck_assert(ri != NULL);
  707. ck_assert_str_eq(ri->uri, "200");
  708. i = mg_read(conn, buf, sizeof(buf));
  709. ck_assert(i > 6);
  710. buf[6] = 0;
  711. ck_assert_str_eq(buf, "<html>");
  712. mg_close_connection(conn);
  713. /* POST to static file (will not work) */
  714. conn = mg_download("localhost",
  715. ipv4_port,
  716. 0,
  717. ebuf,
  718. sizeof(ebuf),
  719. "%s",
  720. "POST /test.txt HTTP/1.0\r\n\r\n");
  721. ck_assert(conn != NULL);
  722. ri = mg_get_request_info(conn);
  723. ck_assert(ri != NULL);
  724. ck_assert_str_eq(ri->uri, "405");
  725. i = mg_read(conn, buf, sizeof(buf));
  726. ck_assert(i >= 29);
  727. buf[29] = 0;
  728. ck_assert_str_eq(buf, "Error 405: Method Not Allowed");
  729. mg_close_connection(conn);
  730. /* PUT to static file (will not work) */
  731. conn = mg_download("localhost",
  732. ipv4_port,
  733. 0,
  734. ebuf,
  735. sizeof(ebuf),
  736. "%s",
  737. "PUT /test.txt HTTP/1.0\r\n\r\n");
  738. ck_assert(conn != NULL);
  739. ri = mg_get_request_info(conn);
  740. ck_assert(ri != NULL);
  741. ck_assert_str_eq(ri->uri, "401"); /* not authorized */
  742. mg_close_connection(conn);
  743. /* TODO: Test websockets */
  744. /* Close the server */
  745. g_ctx = NULL;
  746. mg_stop(ctx);
  747. mg_Sleep(1);
  748. }
  749. END_TEST
  750. Suite *make_public_suite(void)
  751. {
  752. Suite *const suite = suite_create("Public");
  753. TCase *const version = tcase_create("Version");
  754. TCase *const get_valid_options = tcase_create("Options");
  755. TCase *const get_builtin_mime_type = tcase_create("MIME types");
  756. TCase *const tstrncasecmp = tcase_create("strcasecmp");
  757. TCase *const urlencodingdecoding = tcase_create("URL encoding decoding");
  758. TCase *const cookies = tcase_create("Cookies and variables");
  759. TCase *const md5 = tcase_create("MD5");
  760. TCase *const checktestenv = tcase_create("Check test environment");
  761. TCase *const startstophttp = tcase_create("Start Stop HTTP Server");
  762. TCase *const startstophttps = tcase_create("Start Stop HTTPS Server");
  763. TCase *const serverrequests = tcase_create("Server Requests");
  764. tcase_add_test(version, test_mg_version);
  765. suite_add_tcase(suite, version);
  766. tcase_add_test(get_valid_options, test_mg_get_valid_options);
  767. suite_add_tcase(suite, get_valid_options);
  768. tcase_add_test(get_builtin_mime_type, test_mg_get_builtin_mime_type);
  769. suite_add_tcase(suite, get_builtin_mime_type);
  770. tcase_add_test(tstrncasecmp, test_mg_strncasecmp);
  771. suite_add_tcase(suite, tstrncasecmp);
  772. tcase_add_test(urlencodingdecoding, test_mg_url_encode);
  773. tcase_add_test(urlencodingdecoding, test_mg_url_decode);
  774. suite_add_tcase(suite, urlencodingdecoding);
  775. tcase_add_test(cookies, test_mg_get_cookie);
  776. tcase_add_test(cookies, test_mg_get_var);
  777. suite_add_tcase(suite, cookies);
  778. tcase_add_test(md5, test_mg_md5);
  779. suite_add_tcase(suite, md5);
  780. tcase_add_test(checktestenv, test_the_test_environment);
  781. suite_add_tcase(suite, checktestenv);
  782. tcase_add_test(startstophttp, test_mg_start_stop_http_server);
  783. suite_add_tcase(suite, startstophttp);
  784. tcase_add_test(startstophttps, test_mg_start_stop_https_server);
  785. suite_add_tcase(suite, startstophttps);
  786. tcase_add_test(serverrequests, test_request_handlers);
  787. suite_add_tcase(suite, serverrequests);
  788. return suite;
  789. }
  790. #ifdef REPLACE_CHECK_FOR_LOCAL_DEBUGGING
  791. /* Used to debug test cases without using the check framework */
  792. static int chk_ok = 0;
  793. static int chk_failed = 0;
  794. void main(void)
  795. {
  796. test_the_test_environment(0);
  797. test_mg_start_stop_http_server(0);
  798. test_mg_start_stop_https_server(0);
  799. test_request_handlers(0);
  800. printf("\nok: %i\nfailed: %i\n\n", chk_ok, chk_failed);
  801. }
  802. void _ck_assert_failed(const char *file, int line, const char *expr, ...)
  803. {
  804. va_list va;
  805. va_start(va, expr);
  806. fprintf(stderr, "Error: %s, line %i\n", file, line); /* breakpoint here ! */
  807. vfprintf(stderr, expr, va);
  808. va_end(va);
  809. chk_failed++;
  810. }
  811. void _mark_point(const char *file, int line) { chk_ok++; }
  812. void tcase_fn_start(const char *fname, const char *file, int line) {}
  813. void suite_add_tcase(Suite *s, TCase *tc){};
  814. void _tcase_add_test(TCase *tc,
  815. TFun tf,
  816. const char *fname,
  817. int _signal,
  818. int allowed_exit_value,
  819. int start,
  820. int end){};
  821. TCase *tcase_create(const char *name) { return NULL; };
  822. Suite *suite_create(const char *name) { return NULL; };
  823. #endif