public_server.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. /* Copyright (c) 2015-2016 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. #ifndef _CRT_SECURE_NO_WARNINGS
  23. #define _CRT_SECURE_NO_WARNINGS
  24. #endif
  25. #endif
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <stdarg.h>
  29. #include <time.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include "public_server.h"
  33. #include <civetweb.h>
  34. #if defined(_WIN32)
  35. #include <Windows.h>
  36. #define test_sleep(x) (Sleep((x)*1000))
  37. #else
  38. #include <unistd.h>
  39. #define test_sleep(x) (sleep(x))
  40. #endif
  41. /* This unit test file uses the excellent Check unit testing library.
  42. * The API documentation is available here:
  43. * http://check.sourceforge.net/doc/check_html/index.html
  44. */
  45. static const char *
  46. locate_path(const char *a_path)
  47. {
  48. static char r_path[256];
  49. #ifdef _WIN32
  50. #ifdef LOCAL_TEST
  51. sprintf(r_path, "%s\\", a_path);
  52. #else
  53. /* Appveyor */
  54. sprintf(r_path, "..\\..\\..\\%s\\", a_path);
  55. /* TODO: the different paths
  56. * used in the different test
  57. * system is an unsolved
  58. * problem. */
  59. #endif
  60. #else
  61. #ifdef LOCAL_TEST
  62. sprintf(r_path, "%s/", a_path);
  63. #else
  64. /* Travis */
  65. sprintf(r_path,
  66. "../../%s/",
  67. a_path); // TODO: fix path in CI test environment
  68. #endif
  69. #endif
  70. return r_path;
  71. }
  72. #define locate_resources() locate_path("resources")
  73. #define locate_test_exes() locate_path("output")
  74. static const char *
  75. locate_ssl_cert(void)
  76. {
  77. static char cert_path[256];
  78. const char *res = locate_resources();
  79. size_t l;
  80. ck_assert(res != NULL);
  81. l = strlen(res);
  82. ck_assert_uint_gt(l, 0);
  83. ck_assert_uint_lt(l, 100); /* assume there is enough space left in our
  84. typical 255 character string buffers */
  85. strcpy(cert_path, res);
  86. strcat(cert_path, "ssl_cert.pem");
  87. return cert_path;
  88. }
  89. static int
  90. wait_not_null(void *volatile *data)
  91. {
  92. int i;
  93. for (i = 0; i < 100; i++) {
  94. test_sleep(1);
  95. if (*data != NULL) {
  96. return 1;
  97. }
  98. }
  99. #if defined(__MINGW32__) || defined(__GNUC__)
  100. #pragma GCC diagnostic push
  101. #pragma GCC diagnostic ignored "-Wunreachable-code"
  102. #endif
  103. #ifdef __clang__
  104. #pragma clang diagnostic push
  105. #pragma clang diagnostic ignored "-Wunreachable-code"
  106. #endif
  107. ck_abort_msg("wait_not_null failed");
  108. return 0;
  109. #ifdef __clang__
  110. #pragma clang diagnostic pop
  111. #endif
  112. #if defined(__MINGW32__) || defined(__GNUC__)
  113. #pragma GCC diagnostic pop
  114. #endif
  115. }
  116. START_TEST(test_the_test_environment)
  117. {
  118. char wd[300];
  119. char buf[500];
  120. FILE *f;
  121. struct stat st;
  122. int ret;
  123. const char *ssl_cert = locate_ssl_cert();
  124. memset(wd, 0, sizeof(wd));
  125. memset(buf, 0, sizeof(buf));
  126. /* Get the current working directory */
  127. #ifdef _WIN32
  128. (void)GetCurrentDirectoryA(sizeof(wd), wd);
  129. wd[sizeof(wd) - 1] = 0;
  130. #else
  131. (void)getcwd(wd, sizeof(wd));
  132. wd[sizeof(wd) - 1] = 0;
  133. #endif
  134. /* Check the pem file */
  135. #ifdef _WIN32
  136. strcpy(buf, wd);
  137. strcat(buf, "\\");
  138. strcat(buf, ssl_cert);
  139. f = fopen(buf, "rb");
  140. #else
  141. strcpy(buf, wd);
  142. strcat(buf, "/");
  143. strcat(buf, ssl_cert);
  144. f = fopen(buf, "r");
  145. #endif
  146. if (f) {
  147. fclose(f);
  148. } else {
  149. fprintf(stderr, "%s not found", buf);
  150. }
  151. /* Check the test dir */
  152. #ifdef _WIN32
  153. strcpy(buf, wd);
  154. strcat(buf, "\\test");
  155. #else
  156. strcpy(buf, wd);
  157. strcat(buf, "/test");
  158. #endif
  159. memset(&st, 0, sizeof(st));
  160. ret = stat(buf, &st);
  161. if (ret) {
  162. fprintf(stderr, "%s not found", buf);
  163. }
  164. }
  165. END_TEST
  166. static void *threading_data;
  167. static void *
  168. test_thread_func_t(void *param)
  169. {
  170. ck_assert_ptr_eq(param, &threading_data);
  171. ck_assert_ptr_eq(threading_data, NULL);
  172. threading_data = &threading_data;
  173. return NULL;
  174. }
  175. START_TEST(test_threading)
  176. {
  177. int ok;
  178. threading_data = NULL;
  179. ok = mg_start_thread(test_thread_func_t, &threading_data);
  180. ck_assert_int_eq(ok, 0);
  181. wait_not_null(&threading_data);
  182. ck_assert_ptr_eq(threading_data, &threading_data);
  183. }
  184. END_TEST
  185. static int
  186. log_msg_func(const struct mg_connection *conn, const char *message)
  187. {
  188. struct mg_context *ctx;
  189. char *ud;
  190. ck_assert(conn != NULL);
  191. ctx = mg_get_context(conn);
  192. ck_assert(ctx != NULL);
  193. ud = (char *)mg_get_user_data(ctx);
  194. strncpy(ud, message, 255);
  195. ud[255] = 0;
  196. return 1;
  197. }
  198. START_TEST(test_mg_start_stop_http_server)
  199. {
  200. struct mg_context *ctx;
  201. const char *OPTIONS[] = {
  202. #if !defined(NO_FILES)
  203. "document_root",
  204. ".",
  205. #endif
  206. "listening_ports",
  207. "8080",
  208. NULL,
  209. };
  210. size_t ports_cnt;
  211. int ports[16];
  212. int ssl[16];
  213. struct mg_callbacks callbacks;
  214. char errmsg[256];
  215. struct mg_connection *client_conn;
  216. char client_err[256];
  217. const struct mg_request_info *client_ri;
  218. int client_res;
  219. memset(ports, 0, sizeof(ports));
  220. memset(ssl, 0, sizeof(ssl));
  221. memset(&callbacks, 0, sizeof(callbacks));
  222. memset(errmsg, 0, sizeof(errmsg));
  223. callbacks.log_message = log_msg_func;
  224. ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS);
  225. mark_point();
  226. test_sleep(1);
  227. ck_assert_str_eq(errmsg, "");
  228. ck_assert(ctx != NULL);
  229. ports_cnt = mg_get_ports(ctx, 16, ports, ssl);
  230. ck_assert_uint_eq(ports_cnt, 1);
  231. ck_assert_int_eq(ports[0], 8080);
  232. ck_assert_int_eq(ssl[0], 0);
  233. ck_assert_int_eq(ports[1], 0);
  234. ck_assert_int_eq(ssl[1], 0);
  235. test_sleep(1);
  236. mark_point();
  237. memset(client_err, 0, sizeof(client_err));
  238. client_conn =
  239. mg_connect_client("127.0.0.1", 8080, 0, client_err, sizeof(client_err));
  240. ck_assert(client_conn != NULL);
  241. ck_assert_str_eq(client_err, "");
  242. mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n");
  243. client_res =
  244. mg_get_response(client_conn, client_err, sizeof(client_err), 10000);
  245. ck_assert_int_ge(client_res, 0);
  246. ck_assert_str_eq(client_err, "");
  247. client_ri = mg_get_request_info(client_conn);
  248. ck_assert(client_ri != NULL);
  249. #if defined(NO_FILES)
  250. ck_assert_str_eq(client_ri->uri, "404");
  251. #else
  252. ck_assert_str_eq(client_ri->uri, "200");
  253. /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */
  254. client_res = (int)mg_read(client_conn, client_err, sizeof(client_err));
  255. ck_assert_int_gt(client_res, 0);
  256. ck_assert_int_le(client_res, sizeof(client_err));
  257. #endif
  258. mg_close_connection(client_conn);
  259. mark_point();
  260. test_sleep(1);
  261. mark_point();
  262. mg_stop(ctx);
  263. }
  264. END_TEST
  265. START_TEST(test_mg_start_stop_https_server)
  266. {
  267. #ifndef NO_SSL
  268. struct mg_context *ctx;
  269. size_t ports_cnt;
  270. int ports[16];
  271. int ssl[16];
  272. struct mg_callbacks callbacks;
  273. char errmsg[256];
  274. const char *OPTIONS[8]; /* initializer list here is rejected by CI test */
  275. int opt_idx = 0;
  276. const char *ssl_cert = locate_ssl_cert();
  277. struct mg_connection *client_conn;
  278. char client_err[256];
  279. const struct mg_request_info *client_ri;
  280. int client_res;
  281. ck_assert(ssl_cert != NULL);
  282. memset((void *)OPTIONS, 0, sizeof(OPTIONS));
  283. #if !defined(NO_FILES)
  284. OPTIONS[opt_idx++] = "document_root";
  285. OPTIONS[opt_idx++] = ".";
  286. #endif
  287. OPTIONS[opt_idx++] = "listening_ports";
  288. OPTIONS[opt_idx++] = "8080r,8443s";
  289. OPTIONS[opt_idx++] = "ssl_certificate";
  290. OPTIONS[opt_idx++] = ssl_cert;
  291. ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0])));
  292. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL);
  293. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL);
  294. memset(ports, 0, sizeof(ports));
  295. memset(ssl, 0, sizeof(ssl));
  296. memset(&callbacks, 0, sizeof(callbacks));
  297. memset(errmsg, 0, sizeof(errmsg));
  298. callbacks.log_message = log_msg_func;
  299. ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS);
  300. mark_point();
  301. test_sleep(1);
  302. ck_assert_str_eq(errmsg, "");
  303. ck_assert(ctx != NULL);
  304. ports_cnt = mg_get_ports(ctx, 16, ports, ssl);
  305. ck_assert_uint_eq(ports_cnt, 2);
  306. ck_assert_int_eq(ports[0], 8080);
  307. ck_assert_int_eq(ssl[0], 0);
  308. ck_assert_int_eq(ports[1], 8443);
  309. ck_assert_int_eq(ssl[1], 1);
  310. ck_assert_int_eq(ports[2], 0);
  311. ck_assert_int_eq(ssl[2], 0);
  312. test_sleep(1);
  313. mark_point();
  314. memset(client_err, 0, sizeof(client_err));
  315. client_conn =
  316. mg_connect_client("127.0.0.1", 8443, 1, client_err, sizeof(client_err));
  317. ck_assert(client_conn != NULL);
  318. ck_assert_str_eq(client_err, "");
  319. mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n");
  320. client_res =
  321. mg_get_response(client_conn, client_err, sizeof(client_err), 10000);
  322. ck_assert_int_ge(client_res, 0);
  323. ck_assert_str_eq(client_err, "");
  324. client_ri = mg_get_request_info(client_conn);
  325. ck_assert(client_ri != NULL);
  326. #if defined(NO_FILES)
  327. ck_assert_str_eq(client_ri->uri, "404");
  328. #else
  329. ck_assert_str_eq(client_ri->uri, "200");
  330. /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */
  331. client_res = (int)mg_read(client_conn, client_err, sizeof(client_err));
  332. ck_assert_int_gt(client_res, 0);
  333. ck_assert_int_le(client_res, sizeof(client_err));
  334. #endif
  335. mg_close_connection(client_conn);
  336. mark_point();
  337. test_sleep(1);
  338. mark_point();
  339. mg_stop(ctx);
  340. #endif
  341. }
  342. END_TEST
  343. START_TEST(test_mg_server_and_client_tls)
  344. {
  345. #ifndef NO_SSL
  346. struct mg_context *ctx;
  347. int ports_cnt;
  348. struct mg_server_ports ports[16];
  349. struct mg_callbacks callbacks;
  350. char errmsg[256];
  351. struct mg_connection *client_conn;
  352. char client_err[256];
  353. const struct mg_request_info *client_ri;
  354. int client_res;
  355. struct mg_client_options client_options;
  356. const char *OPTIONS[32]; /* initializer list here is rejected by CI test */
  357. int opt_idx = 0;
  358. char server_cert[256];
  359. char client_cert[256];
  360. const char *res_dir = locate_resources();
  361. ck_assert(res_dir != NULL);
  362. strcpy(server_cert, res_dir);
  363. strcpy(client_cert, res_dir);
  364. #ifdef _WIN32
  365. strcat(server_cert, "cert\\server.pem");
  366. strcat(client_cert, "cert\\client.pem");
  367. #else
  368. strcat(server_cert, "cert/server.pem");
  369. strcat(client_cert, "cert/client.pem");
  370. #endif
  371. memset((void *)OPTIONS, 0, sizeof(OPTIONS));
  372. #if !defined(NO_FILES)
  373. OPTIONS[opt_idx++] = "document_root";
  374. OPTIONS[opt_idx++] = ".";
  375. #endif
  376. OPTIONS[opt_idx++] = "listening_ports";
  377. OPTIONS[opt_idx++] = "8080r,8443s";
  378. OPTIONS[opt_idx++] = "ssl_certificate";
  379. OPTIONS[opt_idx++] = server_cert;
  380. OPTIONS[opt_idx++] = "ssl_verify_peer";
  381. OPTIONS[opt_idx++] = "yes";
  382. OPTIONS[opt_idx++] = "ssl_ca_file";
  383. OPTIONS[opt_idx++] = client_cert;
  384. ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0])));
  385. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL);
  386. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL);
  387. memset(ports, 0, sizeof(ports));
  388. memset(&callbacks, 0, sizeof(callbacks));
  389. memset(errmsg, 0, sizeof(errmsg));
  390. callbacks.log_message = log_msg_func;
  391. ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS);
  392. mark_point();
  393. test_sleep(1);
  394. ck_assert_str_eq(errmsg, "");
  395. ck_assert(ctx != NULL);
  396. ports_cnt = mg_get_server_ports(ctx, 16, ports);
  397. ck_assert_int_eq(ports_cnt, 2);
  398. ck_assert_int_eq(ports[0].protocol, 1);
  399. ck_assert_int_eq(ports[0].port, 8080);
  400. ck_assert_int_eq(ports[0].is_ssl, 0);
  401. ck_assert_int_eq(ports[0].is_redirect, 1);
  402. ck_assert_int_eq(ports[1].protocol, 1);
  403. ck_assert_int_eq(ports[1].port, 8443);
  404. ck_assert_int_eq(ports[1].is_ssl, 1);
  405. ck_assert_int_eq(ports[1].is_redirect, 0);
  406. ck_assert_int_eq(ports[2].protocol, 0);
  407. ck_assert_int_eq(ports[2].port, 0);
  408. ck_assert_int_eq(ports[2].is_ssl, 0);
  409. ck_assert_int_eq(ports[2].is_redirect, 0);
  410. test_sleep(1);
  411. mark_point();
  412. memset(client_err, 0, sizeof(client_err));
  413. client_conn =
  414. mg_connect_client("127.0.0.1", 8443, 1, client_err, sizeof(client_err));
  415. ck_assert(client_conn == NULL);
  416. ck_assert_str_ne(client_err, "");
  417. memset(client_err, 0, sizeof(client_err));
  418. memset(&client_options, 0, sizeof(client_options));
  419. client_options.host = "127.0.0.1";
  420. client_options.port = 8443;
  421. client_options.client_cert = client_cert;
  422. client_options.server_cert = server_cert;
  423. client_conn = mg_connect_client_secure(&client_options,
  424. client_err,
  425. sizeof(client_err));
  426. ck_assert(client_conn != NULL);
  427. ck_assert_str_eq(client_err, "");
  428. mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n");
  429. client_res =
  430. mg_get_response(client_conn, client_err, sizeof(client_err), 10000);
  431. ck_assert_int_ge(client_res, 0);
  432. ck_assert_str_eq(client_err, "");
  433. client_ri = mg_get_request_info(client_conn);
  434. ck_assert(client_ri != NULL);
  435. #if defined(NO_FILES)
  436. ck_assert_str_eq(client_ri->uri, "404");
  437. #else
  438. ck_assert_str_eq(client_ri->uri, "200");
  439. /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */
  440. client_res = (int)mg_read(client_conn, client_err, sizeof(client_err));
  441. ck_assert_int_gt(client_res, 0);
  442. ck_assert_int_le(client_res, sizeof(client_err));
  443. #endif
  444. mg_close_connection(client_conn);
  445. /* TODO: A client API using a client certificate is missing */
  446. mark_point();
  447. test_sleep(1);
  448. mark_point();
  449. mg_stop(ctx);
  450. #endif
  451. }
  452. END_TEST
  453. static struct mg_context *g_ctx;
  454. static int
  455. request_test_handler(struct mg_connection *conn, void *cbdata)
  456. {
  457. int i;
  458. char chunk_data[32];
  459. const struct mg_request_info *ri;
  460. struct mg_context *ctx;
  461. void *ud, *cud;
  462. ctx = mg_get_context(conn);
  463. ud = mg_get_user_data(ctx);
  464. ri = mg_get_request_info(conn);
  465. ck_assert(ri != NULL);
  466. ck_assert(ctx == g_ctx);
  467. ck_assert(ud == &g_ctx);
  468. mg_set_user_connection_data(conn, (void *)6543);
  469. cud = mg_get_user_connection_data(conn);
  470. ck_assert_ptr_eq((void *)cud, (void *)6543);
  471. ck_assert_ptr_eq((void *)cbdata, (void *)7);
  472. strcpy(chunk_data, "123456789A123456789B123456789C");
  473. mg_printf(conn,
  474. "HTTP/1.1 200 OK\r\n"
  475. "Transfer-Encoding: chunked\r\n"
  476. "Content-Type: text/plain\r\n\r\n");
  477. for (i = 1; i <= 10; i++) {
  478. mg_printf(conn, "%x\r\n", i);
  479. mg_write(conn, chunk_data, (unsigned)i);
  480. mg_printf(conn, "\r\n");
  481. }
  482. mg_printf(conn, "0\r\n\r\n");
  483. return 1;
  484. }
  485. #ifdef USE_WEBSOCKET
  486. /****************************************************************************/
  487. /* WEBSOCKET SERVER */
  488. /****************************************************************************/
  489. static const char *websocket_welcome_msg = "websocket welcome\n";
  490. static const size_t websocket_welcome_msg_len =
  491. 18 /* strlen(websocket_welcome_msg) */;
  492. static const char *websocket_goodbye_msg = "websocket bye\n";
  493. static const size_t websocket_goodbye_msg_len =
  494. 14 /* strlen(websocket_goodbye_msg) */;
  495. static int
  496. websock_server_connect(const struct mg_connection *conn, void *udata)
  497. {
  498. (void)conn;
  499. ck_assert_ptr_eq((void *)udata, (void *)7531);
  500. printf("Server: Websocket connected\n");
  501. return 0; /* return 0 to accept every connection */
  502. }
  503. static void
  504. websock_server_ready(struct mg_connection *conn, void *udata)
  505. {
  506. ck_assert_ptr_eq((void *)udata, (void *)7531);
  507. printf("Server: Websocket ready\n");
  508. /* Send websocket welcome message */
  509. mg_lock_connection(conn);
  510. mg_websocket_write(conn,
  511. WEBSOCKET_OPCODE_TEXT,
  512. websocket_welcome_msg,
  513. websocket_welcome_msg_len);
  514. mg_unlock_connection(conn);
  515. printf("Server: Websocket ready X\n");
  516. }
  517. static int
  518. websock_server_data(struct mg_connection *conn,
  519. int bits,
  520. char *data,
  521. size_t data_len,
  522. void *udata)
  523. {
  524. (void)bits;
  525. ck_assert_ptr_eq((void *)udata, (void *)7531);
  526. printf("Server: Got %u bytes from the client\n", (unsigned)data_len);
  527. if (data_len == 3 && !memcmp(data, "bye", 3)) {
  528. /* Send websocket goodbye message */
  529. mg_lock_connection(conn);
  530. mg_websocket_write(conn,
  531. WEBSOCKET_OPCODE_TEXT,
  532. websocket_goodbye_msg,
  533. websocket_goodbye_msg_len);
  534. mg_unlock_connection(conn);
  535. } else if (data_len == 5 && !memcmp(data, "data1", 5)) {
  536. mg_lock_connection(conn);
  537. mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok1", 3);
  538. mg_unlock_connection(conn);
  539. } else if (data_len == 5 && !memcmp(data, "data2", 5)) {
  540. mg_lock_connection(conn);
  541. mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok 2", 4);
  542. mg_unlock_connection(conn);
  543. } else if (data_len == 5 && !memcmp(data, "data3", 5)) {
  544. mg_lock_connection(conn);
  545. mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok - 3", 6);
  546. mg_unlock_connection(conn);
  547. } else {
  548. #if defined(__MINGW32__) || defined(__GNUC__)
  549. #pragma GCC diagnostic push
  550. #pragma GCC diagnostic ignored "-Wunreachable-code"
  551. #endif
  552. #ifdef __clang__
  553. #pragma clang diagnostic push
  554. #pragma clang diagnostic ignored "-Wunreachable-code"
  555. #endif
  556. ck_abort_msg("Got unexpected message from websocket client");
  557. return 0;
  558. #ifdef __clang__
  559. #pragma clang diagnostic pop
  560. #endif
  561. #if defined(__MINGW32__) || defined(__GNUC__)
  562. #pragma GCC diagnostic pop
  563. #endif
  564. }
  565. return 1; /* return 1 to keep the connetion open */
  566. }
  567. static void
  568. websock_server_close(const struct mg_connection *conn, void *udata)
  569. {
  570. (void)conn;
  571. ck_assert_ptr_eq((void *)udata, (void *)7531);
  572. printf("Server: Close connection\n");
  573. /* Can not send a websocket goodbye message here - the connection is already
  574. * closed */
  575. }
  576. /****************************************************************************/
  577. /* WEBSOCKET CLIENT */
  578. /****************************************************************************/
  579. struct tclient_data {
  580. void *data;
  581. size_t len;
  582. int closed;
  583. };
  584. static int
  585. websocket_client_data_handler(struct mg_connection *conn,
  586. int flags,
  587. char *data,
  588. size_t data_len,
  589. void *user_data)
  590. {
  591. struct mg_context *ctx = mg_get_context(conn);
  592. struct tclient_data *pclient_data =
  593. (struct tclient_data *)mg_get_user_data(ctx);
  594. (void)user_data; /* TODO: check this */
  595. ck_assert(pclient_data != NULL);
  596. ck_assert_int_eq(flags, (int)(128 | 1));
  597. printf("Client received data from server: ");
  598. fwrite(data, 1, data_len, stdout);
  599. printf("\n");
  600. pclient_data->data = malloc(data_len);
  601. ck_assert(pclient_data->data != NULL);
  602. memcpy(pclient_data->data, data, data_len);
  603. pclient_data->len = data_len;
  604. return 1;
  605. }
  606. static void
  607. websocket_client_close_handler(const struct mg_connection *conn,
  608. void *user_data)
  609. {
  610. struct mg_context *ctx = mg_get_context(conn);
  611. struct tclient_data *pclient_data =
  612. (struct tclient_data *)mg_get_user_data(ctx);
  613. (void)user_data; /* TODO: check this */
  614. ck_assert(pclient_data != NULL);
  615. printf("Client: Close handler\n");
  616. pclient_data->closed++;
  617. }
  618. #endif
  619. START_TEST(test_request_handlers)
  620. {
  621. char ebuf[100];
  622. struct mg_context *ctx;
  623. struct mg_connection *client_conn;
  624. const struct mg_request_info *ri;
  625. char uri[64];
  626. char buf[1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 8];
  627. const char *expected =
  628. "112123123412345123456123456712345678123456789123456789A";
  629. int i;
  630. const char *request = "GET /U7 HTTP/1.0\r\n\r\n";
  631. #if defined(USE_IPV6) && defined(NO_SSL)
  632. const char *HTTP_PORT = "8084,[::]:8086";
  633. short ipv4_port = 8084;
  634. short ipv6_port = 8086;
  635. #elif !defined(USE_IPV6) && defined(NO_SSL)
  636. const char *HTTP_PORT = "8084";
  637. short ipv4_port = 8084;
  638. #elif defined(USE_IPV6) && !defined(NO_SSL)
  639. const char *HTTP_PORT = "8084,[::]:8086,8194r,[::]:8196r,8094s,[::]:8096s";
  640. short ipv4_port = 8084;
  641. short ipv4s_port = 8094;
  642. short ipv4r_port = 8194;
  643. short ipv6_port = 8086;
  644. short ipv6s_port = 8096;
  645. short ipv6r_port = 8196;
  646. #elif !defined(USE_IPV6) && !defined(NO_SSL)
  647. const char *HTTP_PORT = "8084,8194r,8094s";
  648. short ipv4_port = 8084;
  649. short ipv4s_port = 8094;
  650. short ipv4r_port = 8194;
  651. #endif
  652. const char *OPTIONS[8]; /* initializer list here is rejected by CI test */
  653. const char *opt;
  654. FILE *f;
  655. const char *plain_file_content;
  656. const char *encoded_file_content;
  657. const char *cgi_script_content;
  658. const char *expected_cgi_result;
  659. int opt_idx = 0;
  660. #if !defined(NO_SSL)
  661. const char *ssl_cert = locate_ssl_cert();
  662. #endif
  663. #if defined(USE_WEBSOCKET)
  664. struct tclient_data ws_client1_data = {NULL, 0, 0};
  665. struct tclient_data ws_client2_data = {NULL, 0, 0};
  666. struct tclient_data ws_client3_data = {NULL, 0, 0};
  667. struct mg_connection *ws_client1_conn = NULL;
  668. struct mg_connection *ws_client2_conn = NULL;
  669. struct mg_connection *ws_client3_conn = NULL;
  670. #endif
  671. char cmd_buf[256];
  672. memset((void *)OPTIONS, 0, sizeof(OPTIONS));
  673. OPTIONS[opt_idx++] = "listening_ports";
  674. OPTIONS[opt_idx++] = HTTP_PORT;
  675. #if !defined(NO_FILES)
  676. OPTIONS[opt_idx++] = "document_root";
  677. OPTIONS[opt_idx++] = ".";
  678. #endif
  679. #ifndef NO_SSL
  680. ck_assert(ssl_cert != NULL);
  681. OPTIONS[opt_idx++] = "ssl_certificate";
  682. OPTIONS[opt_idx++] = ssl_cert;
  683. #endif
  684. ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0])));
  685. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL);
  686. ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL);
  687. ctx = mg_start(NULL, &g_ctx, OPTIONS);
  688. ck_assert(ctx != NULL);
  689. g_ctx = ctx;
  690. opt = mg_get_option(ctx, "listening_ports");
  691. ck_assert_str_eq(opt, HTTP_PORT);
  692. opt = mg_get_option(ctx, "cgi_environment");
  693. ck_assert_str_eq(opt, "");
  694. opt = mg_get_option(ctx, "unknown_option_name");
  695. ck_assert(opt == NULL);
  696. for (i = 0; i < 1000; i++) {
  697. sprintf(uri, "/U%u", i);
  698. mg_set_request_handler(ctx, uri, request_test_handler, NULL);
  699. }
  700. for (i = 500; i < 800; i++) {
  701. sprintf(uri, "/U%u", i);
  702. mg_set_request_handler(ctx, uri, NULL, (void *)1);
  703. }
  704. for (i = 600; i >= 0; i--) {
  705. sprintf(uri, "/U%u", i);
  706. mg_set_request_handler(ctx, uri, NULL, (void *)2);
  707. }
  708. for (i = 750; i <= 1000; i++) {
  709. sprintf(uri, "/U%u", i);
  710. mg_set_request_handler(ctx, uri, NULL, (void *)3);
  711. }
  712. for (i = 5; i < 9; i++) {
  713. sprintf(uri, "/U%u", i);
  714. mg_set_request_handler(ctx,
  715. uri,
  716. request_test_handler,
  717. (void *)(ptrdiff_t)i);
  718. }
  719. #ifdef USE_WEBSOCKET
  720. mg_set_websocket_handler(ctx,
  721. "/websocket",
  722. websock_server_connect,
  723. websock_server_ready,
  724. websock_server_data,
  725. websock_server_close,
  726. (void *)7531);
  727. #endif
  728. /* Try to load non existing file */
  729. client_conn = mg_download("localhost",
  730. ipv4_port,
  731. 0,
  732. ebuf,
  733. sizeof(ebuf),
  734. "%s",
  735. "GET /file/not/found HTTP/1.0\r\n\r\n");
  736. ck_assert(client_conn != NULL);
  737. ri = mg_get_request_info(client_conn);
  738. ck_assert(ri != NULL);
  739. ck_assert_str_eq(ri->uri, "404");
  740. mg_close_connection(client_conn);
  741. /* Get data from callback */
  742. client_conn = mg_download(
  743. "localhost", ipv4_port, 0, ebuf, sizeof(ebuf), "%s", request);
  744. ck_assert(client_conn != NULL);
  745. ri = mg_get_request_info(client_conn);
  746. ck_assert(ri != NULL);
  747. ck_assert_str_eq(ri->uri, "200");
  748. i = mg_read(client_conn, buf, sizeof(buf));
  749. ck_assert_int_eq(i, (int)strlen(expected));
  750. buf[i] = 0;
  751. ck_assert_str_eq(buf, expected);
  752. mg_close_connection(client_conn);
  753. /* Get data from callback using http://127.0.0.1 */
  754. client_conn = mg_download(
  755. "127.0.0.1", ipv4_port, 0, ebuf, sizeof(ebuf), "%s", request);
  756. ck_assert(client_conn != NULL);
  757. ri = mg_get_request_info(client_conn);
  758. ck_assert(ri != NULL);
  759. ck_assert_str_eq(ri->uri, "200");
  760. i = mg_read(client_conn, buf, sizeof(buf));
  761. if ((i >= 0) && ((size_t)i < sizeof(buf))) {
  762. buf[i] = 0;
  763. } else {
  764. ck_abort_msg(
  765. "ERROR: test_request_handlers: read returned %i (>=0, <%i)",
  766. (int)i,
  767. (int)sizeof(buf));
  768. }
  769. ck_assert((int)i < (int)sizeof(buf));
  770. ck_assert(i > 0);
  771. ck_assert_int_eq(i, (int)strlen(expected));
  772. buf[i] = 0;
  773. ck_assert_str_eq(buf, expected);
  774. mg_close_connection(client_conn);
  775. #if defined(USE_IPV6)
  776. /* Get data from callback using http://[::1] */
  777. client_conn =
  778. mg_download("[::1]", ipv6_port, 0, ebuf, sizeof(ebuf), "%s", request);
  779. ck_assert(client_conn != NULL);
  780. ri = mg_get_request_info(client_conn);
  781. ck_assert(ri != NULL);
  782. ck_assert_str_eq(ri->uri, "200");
  783. i = mg_read(client_conn, buf, sizeof(buf));
  784. ck_assert_int_eq(i, (int)strlen(expected));
  785. buf[i] = 0;
  786. ck_assert_str_eq(buf, expected);
  787. mg_close_connection(client_conn);
  788. #endif
  789. #if !defined(NO_SSL)
  790. /* Get data from callback using https://127.0.0.1 */
  791. client_conn = mg_download(
  792. "127.0.0.1", ipv4s_port, 1, ebuf, sizeof(ebuf), "%s", request);
  793. ck_assert(client_conn != NULL);
  794. ri = mg_get_request_info(client_conn);
  795. ck_assert(ri != NULL);
  796. ck_assert_str_eq(ri->uri, "200");
  797. i = mg_read(client_conn, buf, sizeof(buf));
  798. ck_assert_int_eq(i, (int)strlen(expected));
  799. buf[i] = 0;
  800. ck_assert_str_eq(buf, expected);
  801. mg_close_connection(client_conn);
  802. /* Get redirect from callback using http://127.0.0.1 */
  803. client_conn = mg_download(
  804. "127.0.0.1", ipv4r_port, 0, ebuf, sizeof(ebuf), "%s", request);
  805. ck_assert(client_conn != NULL);
  806. ri = mg_get_request_info(client_conn);
  807. ck_assert(ri != NULL);
  808. ck_assert_str_eq(ri->uri, "302");
  809. i = mg_read(client_conn, buf, sizeof(buf));
  810. ck_assert_int_eq(i, -1);
  811. mg_close_connection(client_conn);
  812. #endif
  813. #if defined(USE_IPV6) && !defined(NO_SSL)
  814. /* Get data from callback using https://[::1] */
  815. client_conn =
  816. mg_download("[::1]", ipv6s_port, 1, ebuf, sizeof(ebuf), "%s", request);
  817. ck_assert(client_conn != NULL);
  818. ri = mg_get_request_info(client_conn);
  819. ck_assert(ri != NULL);
  820. ck_assert_str_eq(ri->uri, "200");
  821. i = mg_read(client_conn, buf, sizeof(buf));
  822. ck_assert_int_eq(i, (int)strlen(expected));
  823. buf[i] = 0;
  824. ck_assert_str_eq(buf, expected);
  825. mg_close_connection(client_conn);
  826. /* Get redirect from callback using http://127.0.0.1 */
  827. client_conn =
  828. mg_download("[::1]", ipv6r_port, 0, ebuf, sizeof(ebuf), "%s", request);
  829. ck_assert(client_conn != NULL);
  830. ri = mg_get_request_info(client_conn);
  831. ck_assert(ri != NULL);
  832. ck_assert_str_eq(ri->uri, "302");
  833. i = mg_read(client_conn, buf, sizeof(buf));
  834. ck_assert_int_eq(i, -1);
  835. mg_close_connection(client_conn);
  836. #endif
  837. /* It seems to be impossible to find out what the actual working
  838. * directory of the CI test environment is. Before breaking another
  839. * dozen of builds by trying blindly with different paths, just
  840. * create the file here */
  841. #ifdef _WIN32
  842. f = fopen("test.txt", "wb");
  843. #else
  844. f = fopen("test.txt", "w");
  845. #endif
  846. plain_file_content = "simple text file\n";
  847. fwrite(plain_file_content, 17, 1, f);
  848. fclose(f);
  849. #ifdef _WIN32
  850. f = fopen("test_gz.txt.gz", "wb");
  851. #else
  852. f = fopen("test_gz.txt.gz", "w");
  853. #endif
  854. encoded_file_content = "\x1f\x8b\x08\x08\xf8\x9d\xcb\x55\x00\x00"
  855. "test_gz.txt"
  856. "\x00\x01\x11\x00\xee\xff"
  857. "zipped text file"
  858. "\x0a\x34\x5f\xcc\x49\x11\x00\x00\x00";
  859. fwrite(encoded_file_content, 1, 52, f);
  860. fclose(f);
  861. #ifdef _WIN32
  862. f = fopen("test.cgi", "wb");
  863. cgi_script_content = "#!test.cgi.cmd\r\n";
  864. fwrite(cgi_script_content, strlen(cgi_script_content), 1, f);
  865. fclose(f);
  866. f = fopen("test.cgi.cmd", "w");
  867. cgi_script_content = "@echo off\r\n"
  868. "echo Connection: close\r\n"
  869. "echo Content-Type: text/plain\r\n"
  870. "echo.\r\n"
  871. "echo CGI test\r\n"
  872. "\r\n";
  873. fwrite(cgi_script_content, strlen(cgi_script_content), 1, f);
  874. fclose(f);
  875. #else
  876. f = fopen("test.cgi", "w");
  877. cgi_script_content = "#!/bin/sh\n\n"
  878. "printf \"Connection: close\\r\\n\"\n"
  879. "printf \"Content-Type: text/plain\\r\\n\"\n"
  880. "printf \"\\r\\n\"\n"
  881. "printf \"CGI test\\r\\n\"\n"
  882. "\n";
  883. fwrite(cgi_script_content, strlen(cgi_script_content), 1, f);
  884. fclose(f);
  885. system("chmod a+x test.cgi");
  886. #endif
  887. expected_cgi_result = "CGI test";
  888. /* Get static data */
  889. client_conn = mg_download("localhost",
  890. ipv4_port,
  891. 0,
  892. ebuf,
  893. sizeof(ebuf),
  894. "%s",
  895. "GET /test.txt HTTP/1.0\r\n\r\n");
  896. ck_assert(client_conn != NULL);
  897. ri = mg_get_request_info(client_conn);
  898. ck_assert(ri != NULL);
  899. #if defined(NO_FILES)
  900. ck_assert_str_eq(ri->uri, "404");
  901. #else
  902. ck_assert_str_eq(ri->uri, "200");
  903. i = mg_read(client_conn, buf, sizeof(buf));
  904. ck_assert_int_eq(i, 17);
  905. if ((i >= 0) && (i < (int)sizeof(buf))) {
  906. buf[i] = 0;
  907. }
  908. ck_assert_str_eq(buf, plain_file_content);
  909. #endif
  910. mg_close_connection(client_conn);
  911. /* Test with CGI test executable */
  912. #if defined(_WIN32)
  913. sprintf(cmd_buf, "copy %s\\cgi_test.cgi cgi_test.exe", locate_test_exes());
  914. #else
  915. sprintf(cmd_buf, "cp %s/cgi_test.cgi cgi_test.cgi", locate_test_exes());
  916. #endif
  917. system(cmd_buf);
  918. #if !defined(NO_CGI) && !defined(NO_FILES) && !defined(_WIN32)
  919. /* TODO: add test for windows, check with POST */
  920. client_conn = mg_download(
  921. "localhost",
  922. ipv4_port,
  923. 0,
  924. ebuf,
  925. sizeof(ebuf),
  926. "%s",
  927. "POST /cgi_test.cgi HTTP/1.0\r\nContent-Length: 3\r\n\r\nABC");
  928. ck_assert(client_conn != NULL);
  929. ri = mg_get_request_info(client_conn);
  930. ck_assert(ri != NULL);
  931. ck_assert_str_eq(ri->uri, "200");
  932. mg_close_connection(client_conn);
  933. #endif
  934. /* Get zipped static data - will not work if Accept-Encoding is not set */
  935. client_conn = mg_download("localhost",
  936. ipv4_port,
  937. 0,
  938. ebuf,
  939. sizeof(ebuf),
  940. "%s",
  941. "GET /test_gz.txt HTTP/1.0\r\n\r\n");
  942. ck_assert(client_conn != NULL);
  943. ri = mg_get_request_info(client_conn);
  944. ck_assert(ri != NULL);
  945. ck_assert_str_eq(ri->uri, "404");
  946. mg_close_connection(client_conn);
  947. /* Get zipped static data - with Accept-Encoding */
  948. client_conn = mg_download(
  949. "localhost",
  950. ipv4_port,
  951. 0,
  952. ebuf,
  953. sizeof(ebuf),
  954. "%s",
  955. "GET /test_gz.txt HTTP/1.0\r\nAccept-Encoding: gzip\r\n\r\n");
  956. ck_assert(client_conn != NULL);
  957. ri = mg_get_request_info(client_conn);
  958. ck_assert(ri != NULL);
  959. #if defined(NO_FILES)
  960. ck_assert_str_eq(ri->uri, "404");
  961. #else
  962. ck_assert_str_eq(ri->uri, "200");
  963. i = mg_read(client_conn, buf, sizeof(buf));
  964. ck_assert_int_eq(i, 52);
  965. if ((i >= 0) && (i < (int)sizeof(buf))) {
  966. buf[i] = 0;
  967. }
  968. ck_assert_int_eq(ri->content_length, 52);
  969. ck_assert_str_eq(buf, encoded_file_content);
  970. #endif
  971. mg_close_connection(client_conn);
  972. /* Get CGI generated data */
  973. #if !defined(NO_CGI)
  974. client_conn = mg_download("localhost",
  975. ipv4_port,
  976. 0,
  977. ebuf,
  978. sizeof(ebuf),
  979. "%s",
  980. "GET /test.cgi HTTP/1.0\r\n\r\n");
  981. ck_assert(client_conn != NULL);
  982. ri = mg_get_request_info(client_conn);
  983. ck_assert(ri != NULL);
  984. #if defined(NO_FILES)
  985. ck_assert_str_eq(ri->uri, "404");
  986. (void)expected_cgi_result;
  987. (void)cgi_script_content;
  988. #else
  989. i = mg_read(client_conn, buf, sizeof(buf));
  990. if ((i >= 0) && (i < (int)sizeof(buf))) {
  991. while ((i > 0) && ((buf[i - 1] == '\r') || (buf[i - 1] == '\n'))) {
  992. i--;
  993. }
  994. buf[i] = 0;
  995. }
  996. /* ck_assert_int_eq(i, (int)strlen(expected_cgi_result)); */
  997. ck_assert_str_eq(buf, expected_cgi_result);
  998. ck_assert_str_eq(ri->uri, "200");
  999. mg_close_connection(client_conn);
  1000. #endif
  1001. #else
  1002. (void)expected_cgi_result;
  1003. (void)cgi_script_content;
  1004. #endif
  1005. /* Get directory listing */
  1006. client_conn = mg_download("localhost",
  1007. ipv4_port,
  1008. 0,
  1009. ebuf,
  1010. sizeof(ebuf),
  1011. "%s",
  1012. "GET / HTTP/1.0\r\n\r\n");
  1013. ck_assert(client_conn != NULL);
  1014. ri = mg_get_request_info(client_conn);
  1015. ck_assert(ri != NULL);
  1016. #if defined(NO_FILES)
  1017. ck_assert_str_eq(ri->uri, "404");
  1018. #else
  1019. ck_assert_str_eq(ri->uri, "200");
  1020. i = mg_read(client_conn, buf, sizeof(buf));
  1021. ck_assert(i > 6);
  1022. buf[6] = 0;
  1023. ck_assert_str_eq(buf, "<html>");
  1024. #endif
  1025. mg_close_connection(client_conn);
  1026. /* POST to static file (will not work) */
  1027. client_conn = mg_download("localhost",
  1028. ipv4_port,
  1029. 0,
  1030. ebuf,
  1031. sizeof(ebuf),
  1032. "%s",
  1033. "POST /test.txt HTTP/1.0\r\n\r\n");
  1034. ck_assert(client_conn != NULL);
  1035. ri = mg_get_request_info(client_conn);
  1036. ck_assert(ri != NULL);
  1037. #if defined(NO_FILES)
  1038. ck_assert_str_eq(ri->uri, "404");
  1039. #else
  1040. ck_assert_str_eq(ri->uri, "405");
  1041. i = mg_read(client_conn, buf, sizeof(buf));
  1042. ck_assert(i >= 29);
  1043. buf[29] = 0;
  1044. ck_assert_str_eq(buf, "Error 405: Method Not Allowed");
  1045. #endif
  1046. mg_close_connection(client_conn);
  1047. /* PUT to static file (will not work) */
  1048. client_conn = mg_download("localhost",
  1049. ipv4_port,
  1050. 0,
  1051. ebuf,
  1052. sizeof(ebuf),
  1053. "%s",
  1054. "PUT /test.txt HTTP/1.0\r\n\r\n");
  1055. ck_assert(client_conn != NULL);
  1056. ri = mg_get_request_info(client_conn);
  1057. ck_assert(ri != NULL);
  1058. #if defined(NO_FILES)
  1059. ck_assert_str_eq(ri->uri, "405"); /* method not allowed */
  1060. #else
  1061. ck_assert_str_eq(ri->uri, "401"); /* not authorized */
  1062. #endif
  1063. mg_close_connection(client_conn);
  1064. /* Websocket test */
  1065. #ifdef USE_WEBSOCKET
  1066. /* Then connect a first client */
  1067. ws_client1_conn =
  1068. mg_connect_websocket_client("localhost",
  1069. ipv4_port,
  1070. 0,
  1071. ebuf,
  1072. sizeof(ebuf),
  1073. "/websocket",
  1074. NULL,
  1075. websocket_client_data_handler,
  1076. websocket_client_close_handler,
  1077. &ws_client1_data);
  1078. ck_assert(ws_client1_conn != NULL);
  1079. wait_not_null(
  1080. &(ws_client1_data.data)); /* Wait for the websocket welcome message */
  1081. ck_assert_int_eq(ws_client1_data.closed, 0);
  1082. ck_assert_int_eq(ws_client2_data.closed, 0);
  1083. ck_assert_int_eq(ws_client3_data.closed, 0);
  1084. ck_assert(ws_client2_data.data == NULL);
  1085. ck_assert_uint_eq(ws_client2_data.len, 0);
  1086. ck_assert(ws_client1_data.data != NULL);
  1087. ck_assert_uint_eq(ws_client1_data.len, websocket_welcome_msg_len);
  1088. ck_assert(!memcmp(ws_client1_data.data,
  1089. websocket_welcome_msg,
  1090. websocket_welcome_msg_len));
  1091. free(ws_client1_data.data);
  1092. ws_client1_data.data = NULL;
  1093. ws_client1_data.len = 0;
  1094. mg_websocket_client_write(ws_client1_conn,
  1095. WEBSOCKET_OPCODE_TEXT,
  1096. "data1",
  1097. 5);
  1098. mark_point();
  1099. wait_not_null(
  1100. &(ws_client1_data
  1101. .data)); /* Wait for the websocket acknowledge message */
  1102. ck_assert_int_eq(ws_client1_data.closed, 0);
  1103. ck_assert_int_eq(ws_client2_data.closed, 0);
  1104. ck_assert(ws_client2_data.data == NULL);
  1105. ck_assert_uint_eq(ws_client2_data.len, 0);
  1106. ck_assert(ws_client1_data.data != NULL);
  1107. ck_assert_uint_eq(ws_client1_data.len, 3);
  1108. ck_assert(!memcmp(ws_client1_data.data, "ok1", 3));
  1109. free(ws_client1_data.data);
  1110. ws_client1_data.data = NULL;
  1111. ws_client1_data.len = 0;
  1112. /* Now connect a second client */
  1113. #ifdef USE_IPV6
  1114. ws_client2_conn =
  1115. mg_connect_websocket_client("[::1]",
  1116. ipv6_port,
  1117. 0,
  1118. ebuf,
  1119. sizeof(ebuf),
  1120. "/websocket",
  1121. NULL,
  1122. websocket_client_data_handler,
  1123. websocket_client_close_handler,
  1124. &ws_client2_data);
  1125. #else
  1126. ws_client2_conn =
  1127. mg_connect_websocket_client("127.0.0.1",
  1128. ipv4_port,
  1129. 0,
  1130. ebuf,
  1131. sizeof(ebuf),
  1132. "/websocket",
  1133. NULL,
  1134. websocket_client_data_handler,
  1135. websocket_client_close_handler,
  1136. &ws_client2_data);
  1137. #endif
  1138. ck_assert(ws_client2_conn != NULL);
  1139. wait_not_null(
  1140. &(ws_client2_data.data)); /* Wait for the websocket welcome message */
  1141. ck_assert(ws_client1_data.closed == 0);
  1142. ck_assert(ws_client2_data.closed == 0);
  1143. ck_assert(ws_client1_data.data == NULL);
  1144. ck_assert(ws_client1_data.len == 0);
  1145. ck_assert(ws_client2_data.data != NULL);
  1146. ck_assert(ws_client2_data.len == websocket_welcome_msg_len);
  1147. ck_assert(!memcmp(ws_client2_data.data,
  1148. websocket_welcome_msg,
  1149. websocket_welcome_msg_len));
  1150. free(ws_client2_data.data);
  1151. ws_client2_data.data = NULL;
  1152. ws_client2_data.len = 0;
  1153. mg_websocket_client_write(ws_client1_conn,
  1154. WEBSOCKET_OPCODE_TEXT,
  1155. "data2",
  1156. 5);
  1157. mark_point();
  1158. wait_not_null(
  1159. &(ws_client1_data
  1160. .data)); /* Wait for the websocket acknowledge message */
  1161. ck_assert(ws_client1_data.closed == 0);
  1162. ck_assert(ws_client2_data.closed == 0);
  1163. ck_assert(ws_client2_data.data == NULL);
  1164. ck_assert(ws_client2_data.len == 0);
  1165. ck_assert(ws_client1_data.data != NULL);
  1166. ck_assert(ws_client1_data.len == 4);
  1167. ck_assert(!memcmp(ws_client1_data.data, "ok 2", 4));
  1168. free(ws_client1_data.data);
  1169. ws_client1_data.data = NULL;
  1170. ws_client1_data.len = 0;
  1171. mg_websocket_client_write(ws_client1_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
  1172. mark_point();
  1173. wait_not_null(
  1174. &(ws_client1_data.data)); /* Wait for the websocket goodbye message */
  1175. ck_assert(ws_client1_data.closed == 0);
  1176. ck_assert(ws_client2_data.closed == 0);
  1177. ck_assert(ws_client2_data.data == NULL);
  1178. ck_assert(ws_client2_data.len == 0);
  1179. ck_assert(ws_client1_data.data != NULL);
  1180. ck_assert(ws_client1_data.len == websocket_goodbye_msg_len);
  1181. ck_assert(!memcmp(ws_client1_data.data,
  1182. websocket_goodbye_msg,
  1183. websocket_goodbye_msg_len));
  1184. free(ws_client1_data.data);
  1185. ws_client1_data.data = NULL;
  1186. ws_client1_data.len = 0;
  1187. mg_close_connection(ws_client1_conn);
  1188. mark_point();
  1189. test_sleep(3); /* Won't get any message */
  1190. ck_assert(ws_client1_data.closed == 1);
  1191. ck_assert(ws_client2_data.closed == 0);
  1192. ck_assert(ws_client1_data.data == NULL);
  1193. ck_assert(ws_client1_data.len == 0);
  1194. ck_assert(ws_client2_data.data == NULL);
  1195. ck_assert(ws_client2_data.len == 0);
  1196. mg_websocket_client_write(ws_client2_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
  1197. mark_point();
  1198. wait_not_null(
  1199. &(ws_client2_data.data)); /* Wait for the websocket goodbye message */
  1200. ck_assert(ws_client1_data.closed == 1);
  1201. ck_assert(ws_client2_data.closed == 0);
  1202. ck_assert(ws_client1_data.data == NULL);
  1203. ck_assert(ws_client1_data.len == 0);
  1204. ck_assert(ws_client2_data.data != NULL);
  1205. ck_assert(ws_client2_data.len == websocket_goodbye_msg_len);
  1206. ck_assert(!memcmp(ws_client2_data.data,
  1207. websocket_goodbye_msg,
  1208. websocket_goodbye_msg_len));
  1209. free(ws_client2_data.data);
  1210. ws_client2_data.data = NULL;
  1211. ws_client2_data.len = 0;
  1212. mg_close_connection(ws_client2_conn);
  1213. mark_point();
  1214. test_sleep(3); /* Won't get any message */
  1215. ck_assert(ws_client1_data.closed == 1);
  1216. ck_assert(ws_client2_data.closed == 1);
  1217. ck_assert(ws_client1_data.data == NULL);
  1218. ck_assert(ws_client1_data.len == 0);
  1219. ck_assert(ws_client2_data.data == NULL);
  1220. ck_assert(ws_client2_data.len == 0);
  1221. /* Connect client 3 */
  1222. ws_client3_conn =
  1223. mg_connect_websocket_client("localhost",
  1224. #if defined(NO_SSL)
  1225. ipv4_port,
  1226. 0,
  1227. #else
  1228. ipv4s_port,
  1229. 1,
  1230. #endif
  1231. ebuf,
  1232. sizeof(ebuf),
  1233. "/websocket",
  1234. NULL,
  1235. websocket_client_data_handler,
  1236. websocket_client_close_handler,
  1237. &ws_client3_data);
  1238. ck_assert(ws_client3_conn != NULL);
  1239. wait_not_null(
  1240. &(ws_client3_data.data)); /* Wait for the websocket welcome message */
  1241. ck_assert(ws_client1_data.closed == 1);
  1242. ck_assert(ws_client2_data.closed == 1);
  1243. ck_assert(ws_client3_data.closed == 0);
  1244. ck_assert(ws_client1_data.data == NULL);
  1245. ck_assert(ws_client1_data.len == 0);
  1246. ck_assert(ws_client2_data.data == NULL);
  1247. ck_assert(ws_client2_data.len == 0);
  1248. ck_assert(ws_client3_data.data != NULL);
  1249. ck_assert(ws_client3_data.len == websocket_welcome_msg_len);
  1250. ck_assert(!memcmp(ws_client3_data.data,
  1251. websocket_welcome_msg,
  1252. websocket_welcome_msg_len));
  1253. free(ws_client3_data.data);
  1254. ws_client3_data.data = NULL;
  1255. ws_client3_data.len = 0;
  1256. #endif
  1257. /* Close the server */
  1258. g_ctx = NULL;
  1259. mg_stop(ctx);
  1260. mark_point();
  1261. #ifdef USE_WEBSOCKET
  1262. for (i = 0; i < 100; i++) {
  1263. test_sleep(1);
  1264. if (ws_client3_data.closed != 0) {
  1265. mark_point();
  1266. break;
  1267. }
  1268. }
  1269. ck_assert_int_eq(ws_client3_data.closed, 1);
  1270. #endif
  1271. }
  1272. END_TEST
  1273. Suite *
  1274. make_public_server_suite(void)
  1275. {
  1276. Suite *const suite = suite_create("PublicServer");
  1277. TCase *const tcase_checktestenv = tcase_create("Check test environment");
  1278. TCase *const tcase_startthreads = tcase_create("Start threads");
  1279. TCase *const tcase_startstophttp = tcase_create("Start Stop HTTP Server");
  1280. TCase *const tcase_startstophttps = tcase_create("Start Stop HTTPS Server");
  1281. TCase *const tcase_serverandclienttls = tcase_create("TLS Server Client");
  1282. TCase *const tcase_serverrequests = tcase_create("Server Requests");
  1283. tcase_add_test(tcase_checktestenv, test_the_test_environment);
  1284. tcase_set_timeout(tcase_checktestenv, civetweb_min_test_timeout);
  1285. suite_add_tcase(suite, tcase_checktestenv);
  1286. tcase_add_test(tcase_startthreads, test_threading);
  1287. tcase_set_timeout(tcase_startthreads, civetweb_min_test_timeout);
  1288. suite_add_tcase(suite, tcase_startthreads);
  1289. tcase_add_test(tcase_startstophttp, test_mg_start_stop_http_server);
  1290. tcase_set_timeout(tcase_startstophttp, civetweb_min_test_timeout);
  1291. suite_add_tcase(suite, tcase_startstophttp);
  1292. tcase_add_test(tcase_startstophttps, test_mg_start_stop_https_server);
  1293. tcase_set_timeout(tcase_startstophttps, civetweb_min_test_timeout);
  1294. suite_add_tcase(suite, tcase_startstophttps);
  1295. tcase_add_test(tcase_serverandclienttls, test_mg_server_and_client_tls);
  1296. tcase_set_timeout(tcase_serverandclienttls, civetweb_min_test_timeout);
  1297. suite_add_tcase(suite, tcase_serverandclienttls);
  1298. tcase_add_test(tcase_serverrequests, test_request_handlers);
  1299. tcase_set_timeout(tcase_serverrequests, 120);
  1300. suite_add_tcase(suite, tcase_serverrequests);
  1301. return suite;
  1302. }
  1303. #ifdef REPLACE_CHECK_FOR_LOCAL_DEBUGGING
  1304. /* Used to debug test cases without using the check framework */
  1305. static int chk_ok = 0;
  1306. static int chk_failed = 0;
  1307. void
  1308. xmain(void)
  1309. {
  1310. test_the_test_environment(0);
  1311. test_threading(0);
  1312. test_mg_start_stop_http_server(0);
  1313. test_mg_start_stop_https_server(0);
  1314. test_request_handlers(0);
  1315. test_mg_server_and_client_tls(0);
  1316. printf("\nok: %i\nfailed: %i\n\n", chk_ok, chk_failed);
  1317. }
  1318. void
  1319. _ck_assert_failed(const char *file, int line, const char *expr, ...)
  1320. {
  1321. va_list va;
  1322. va_start(va, expr);
  1323. fprintf(stderr, "Error: %s, line %i\n", file, line); /* breakpoint here ! */
  1324. vfprintf(stderr, expr, va);
  1325. fprintf(stderr, "\n\n");
  1326. va_end(va);
  1327. chk_failed++;
  1328. }
  1329. void
  1330. _ck_assert_msg(int cond, const char *file, int line, const char *expr, ...)
  1331. {
  1332. va_list va;
  1333. if (cond) {
  1334. chk_ok++;
  1335. return;
  1336. }
  1337. va_start(va, expr);
  1338. fprintf(stderr, "Error: %s, line %i\n", file, line); /* breakpoint here ! */
  1339. vfprintf(stderr, expr, va);
  1340. fprintf(stderr, "\n\n");
  1341. va_end(va);
  1342. chk_failed++;
  1343. }
  1344. void
  1345. _mark_point(const char *file, int line)
  1346. {
  1347. chk_ok++;
  1348. }
  1349. void
  1350. tcase_fn_start(const char *fname, const char *file, int line)
  1351. {
  1352. }
  1353. void suite_add_tcase(Suite *s, TCase *tc){};
  1354. void _tcase_add_test(TCase *tc,
  1355. TFun tf,
  1356. const char *fname,
  1357. int _signal,
  1358. int allowed_exit_value,
  1359. int start,
  1360. int end){};
  1361. TCase *
  1362. tcase_create(const char *name)
  1363. {
  1364. return NULL;
  1365. };
  1366. Suite *
  1367. suite_create(const char *name)
  1368. {
  1369. return NULL;
  1370. };
  1371. void tcase_set_timeout(TCase *tc, double timeout){};
  1372. #endif