public_server.c 40 KB

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