embedded_c.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. /*
  2. * Copyright (c) 2013-2016 the CivetWeb developers
  3. * Copyright (c) 2013 No Face Press, LLC
  4. * License http://opensource.org/licenses/mit-license.php MIT License
  5. */
  6. /* Simple example program on how to use CivetWeb embedded into a C program. */
  7. #ifdef _WIN32
  8. #include <Windows.h>
  9. #else
  10. #include <unistd.h>
  11. #endif
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #include "civetweb.h"
  16. #define DOCUMENT_ROOT "."
  17. #ifdef NO_SSL
  18. #ifdef USE_IPV6
  19. #define PORT "[::]:8888"
  20. #else
  21. #define PORT "8888"
  22. #endif
  23. #else
  24. #ifdef USE_IPV6
  25. #define PORT "[::]:8888r,[::]:8843s,8884"
  26. #else
  27. #define PORT "8888r,8843s"
  28. #endif
  29. #endif
  30. #define EXAMPLE_URI "/example"
  31. #define EXIT_URI "/exit"
  32. int exitNow = 0;
  33. int
  34. ExampleHandler(struct mg_connection *conn, void *cbdata)
  35. {
  36. mg_printf(conn,
  37. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  38. "close\r\n\r\n");
  39. mg_printf(conn, "<html><body>");
  40. mg_printf(conn, "<h2>This is an example text from a C handler</h2>");
  41. mg_printf(
  42. conn,
  43. "<p>To see a page from the A handler <a href=\"A\">click A</a></p>");
  44. mg_printf(conn,
  45. "<p>To see a page from the A handler <a href=\"A/A\">click "
  46. "A/A</a></p>");
  47. mg_printf(conn,
  48. "<p>To see a page from the A/B handler <a "
  49. "href=\"A/B\">click A/B</a></p>");
  50. mg_printf(conn,
  51. "<p>To see a page from the B handler (0) <a "
  52. "href=\"B\">click B</a></p>");
  53. mg_printf(conn,
  54. "<p>To see a page from the B handler (1) <a "
  55. "href=\"B/A\">click B/A</a></p>");
  56. mg_printf(conn,
  57. "<p>To see a page from the B handler (2) <a "
  58. "href=\"B/B\">click B/B</a></p>");
  59. mg_printf(conn,
  60. "<p>To see a page from the *.foo handler <a "
  61. "href=\"xy.foo\">click xy.foo</a></p>");
  62. mg_printf(conn,
  63. "<p>To see a page from the close handler <a "
  64. "href=\"close\">click close</a></p>");
  65. mg_printf(conn,
  66. "<p>To see a page from the FileHandler handler <a "
  67. "href=\"form\">click form</a> (the starting point of the "
  68. "<b>form</b> test)</p>");
  69. mg_printf(conn,
  70. "<p>To see a page from the CookieHandler handler <a "
  71. "href=\"cookie\">click cookie</a></p>");
  72. mg_printf(conn,
  73. "<p>To see an example for parsing files on the fly <a "
  74. "href=\"on_the_fly_form\">click form</a> (form for "
  75. "uploading files)</p>");
  76. #ifdef USE_WEBSOCKET
  77. mg_printf(conn,
  78. "<p>To test websocket handler <a href=\"/websocket\">click "
  79. "websocket</a></p>");
  80. #endif
  81. mg_printf(conn, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI);
  82. mg_printf(conn, "</body></html>\n");
  83. return 1;
  84. }
  85. int
  86. ExitHandler(struct mg_connection *conn, void *cbdata)
  87. {
  88. mg_printf(conn,
  89. "HTTP/1.1 200 OK\r\nContent-Type: "
  90. "text/plain\r\nConnection: close\r\n\r\n");
  91. mg_printf(conn, "Server will shut down.\n");
  92. mg_printf(conn, "Bye!\n");
  93. exitNow = 1;
  94. return 1;
  95. }
  96. int
  97. AHandler(struct mg_connection *conn, void *cbdata)
  98. {
  99. mg_printf(conn,
  100. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  101. "close\r\n\r\n");
  102. mg_printf(conn, "<html><body>");
  103. mg_printf(conn, "<h2>This is the A handler!!!</h2>");
  104. mg_printf(conn, "</body></html>\n");
  105. return 1;
  106. }
  107. int
  108. ABHandler(struct mg_connection *conn, void *cbdata)
  109. {
  110. mg_printf(conn,
  111. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  112. "close\r\n\r\n");
  113. mg_printf(conn, "<html><body>");
  114. mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
  115. mg_printf(conn, "</body></html>\n");
  116. return 1;
  117. }
  118. int
  119. BXHandler(struct mg_connection *conn, void *cbdata)
  120. {
  121. /* Handler may access the request info using mg_get_request_info */
  122. const struct mg_request_info *req_info = mg_get_request_info(conn);
  123. mg_printf(conn,
  124. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  125. "close\r\n\r\n");
  126. mg_printf(conn, "<html><body>");
  127. mg_printf(conn, "<h2>This is the BX handler %p!!!</h2>", cbdata);
  128. mg_printf(conn, "<p>The actual uri is %s</p>", req_info->uri);
  129. mg_printf(conn, "</body></html>\n");
  130. return 1;
  131. }
  132. int
  133. FooHandler(struct mg_connection *conn, void *cbdata)
  134. {
  135. /* Handler may access the request info using mg_get_request_info */
  136. const struct mg_request_info *req_info = mg_get_request_info(conn);
  137. mg_printf(conn,
  138. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  139. "close\r\n\r\n");
  140. mg_printf(conn, "<html><body>");
  141. mg_printf(conn, "<h2>This is the Foo handler!!!</h2>");
  142. mg_printf(conn,
  143. "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",
  144. req_info->request_method,
  145. req_info->uri,
  146. req_info->http_version);
  147. mg_printf(conn, "</body></html>\n");
  148. return 1;
  149. }
  150. int
  151. CloseHandler(struct mg_connection *conn, void *cbdata)
  152. {
  153. /* Handler may access the request info using mg_get_request_info */
  154. const struct mg_request_info *req_info = mg_get_request_info(conn);
  155. mg_printf(conn,
  156. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  157. "close\r\n\r\n");
  158. mg_printf(conn, "<html><body>");
  159. mg_printf(conn,
  160. "<h2>This handler will close the connection in a second</h2>");
  161. #ifdef _WIN32
  162. Sleep(1000);
  163. #else
  164. sleep(1);
  165. #endif
  166. mg_printf(conn, "bye");
  167. printf("CloseHandler: close connection\n");
  168. mg_close_connection(conn);
  169. printf("CloseHandler: wait 10 sec\n");
  170. #ifdef _WIN32
  171. Sleep(10000);
  172. #else
  173. sleep(10);
  174. #endif
  175. printf("CloseHandler: return from function\n");
  176. return 1;
  177. }
  178. int
  179. FileHandler(struct mg_connection *conn, void *cbdata)
  180. {
  181. /* In this handler, we ignore the req_info and send the file "fileName". */
  182. const char *fileName = (const char *)cbdata;
  183. mg_send_file(conn, fileName);
  184. return 1;
  185. }
  186. int
  187. field_found(const char *key,
  188. const char *filename,
  189. char *path,
  190. size_t pathlen,
  191. void *user_data)
  192. {
  193. struct mg_connection *conn = (struct mg_connection *)user_data;
  194. mg_printf(conn, "\r\n\r\n%s:\r\n", key);
  195. if (filename && *filename) {
  196. #ifdef _WIN32
  197. _snprintf(path, pathlen, "D:\\tmp\\%s", filename);
  198. #else
  199. snprintf(path, pathlen, "/tmp/%s", filename);
  200. #endif
  201. return FORM_FIELD_STORAGE_STORE;
  202. }
  203. return FORM_FIELD_STORAGE_GET;
  204. }
  205. int
  206. field_get(const char *key, const char *value, size_t valuelen, void *user_data)
  207. {
  208. struct mg_connection *conn = (struct mg_connection *)user_data;
  209. if (key[0]) {
  210. mg_printf(conn, "%s = ", key);
  211. }
  212. mg_write(conn, value, valuelen);
  213. return 0;
  214. }
  215. int
  216. field_stored(const char *path, long long file_size, void *user_data)
  217. {
  218. struct mg_connection *conn = (struct mg_connection *)user_data;
  219. mg_printf(conn,
  220. "stored as %s (%lu bytes)\r\n\r\n",
  221. path,
  222. (unsigned long)file_size);
  223. return 0;
  224. }
  225. int
  226. FormHandler(struct mg_connection *conn, void *cbdata)
  227. {
  228. /* Handler may access the request info using mg_get_request_info */
  229. const struct mg_request_info *req_info = mg_get_request_info(conn);
  230. int ret;
  231. struct mg_form_data_handler fdh = {field_found, field_get, field_stored, 0};
  232. /* It would be possible to check the request info here before calling
  233. * mg_handle_form_request. */
  234. (void)req_info;
  235. mg_printf(conn,
  236. "HTTP/1.1 200 OK\r\nContent-Type: "
  237. "text/plain\r\nConnection: close\r\n\r\n");
  238. fdh.user_data = (void *)conn;
  239. /* Call the form handler */
  240. mg_printf(conn, "Form data:");
  241. ret = mg_handle_form_request(conn, &fdh);
  242. mg_printf(conn, "\r\n%i fields found", ret);
  243. return 1;
  244. }
  245. int
  246. FileUploadForm(struct mg_connection *conn, void *cbdata)
  247. {
  248. mg_printf(conn,
  249. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  250. "close\r\n\r\n");
  251. mg_printf(conn, "<!DOCTYPE html>\n");
  252. mg_printf(conn, "<html>\n<head>\n");
  253. mg_printf(conn, "<meta charset=\"UTF-8\">\n");
  254. mg_printf(conn, "<title>File upload</title>\n");
  255. mg_printf(conn, "</head>\n<body>\n");
  256. mg_printf(conn,
  257. "<form action=\"%s\" method=\"POST\" "
  258. "enctype=\"multipart/form-data\">\n",
  259. (const char *)cbdata);
  260. mg_printf(conn, "<input type=\"file\" name=\"filesin\" multiple>\n");
  261. mg_printf(conn, "<input type=\"submit\" value=\"Submit\">\n");
  262. mg_printf(conn, "</form>\n</body>\n</html>\n");
  263. return 1;
  264. }
  265. #define MD5_STATIC static
  266. #include "../src/md5.inl"
  267. struct tfile_checksum {
  268. char name[128];
  269. unsigned long long length;
  270. md5_state_t chksum;
  271. };
  272. #define MAX_FILES (10)
  273. struct tfiles_checksums {
  274. int index;
  275. struct tfile_checksum file[MAX_FILES];
  276. };
  277. int
  278. field_disp_read_on_the_fly(const char *key,
  279. const char *filename,
  280. char *path,
  281. size_t pathlen,
  282. void *user_data)
  283. {
  284. struct tfiles_checksums *context = (struct tfiles_checksums *)user_data;
  285. (void)key;
  286. (void)path;
  287. (void)pathlen;
  288. if (context->index < MAX_FILES) {
  289. context->index++;
  290. strncpy(context->file[context->index - 1].name, filename, 128);
  291. context->file[context->index - 1].name[127] = 0;
  292. context->file[context->index - 1].length = 0;
  293. md5_init(&(context->file[context->index - 1].chksum));
  294. return FORM_FIELD_STORAGE_GET;
  295. }
  296. return FORM_FIELD_STORAGE_ABORT;
  297. }
  298. int
  299. field_get_checksum(const char *key,
  300. const char *value,
  301. size_t valuelen,
  302. void *user_data)
  303. {
  304. struct tfiles_checksums *context = (struct tfiles_checksums *)user_data;
  305. (void)key;
  306. context->file[context->index - 1].length += valuelen;
  307. md5_append(&(context->file[context->index - 1].chksum),
  308. (const md5_byte_t *)value,
  309. valuelen);
  310. return 0;
  311. }
  312. int
  313. CheckSumHandler(struct mg_connection *conn, void *cbdata)
  314. {
  315. /* Handler may access the request info using mg_get_request_info */
  316. const struct mg_request_info *req_info = mg_get_request_info(conn);
  317. int i, j, ret;
  318. struct tfiles_checksums chksums;
  319. md5_byte_t digest[16];
  320. struct mg_form_data_handler fdh = {field_disp_read_on_the_fly,
  321. field_get_checksum,
  322. 0,
  323. (void *)&chksums};
  324. /* It would be possible to check the request info here before calling
  325. * mg_handle_form_request. */
  326. (void)req_info;
  327. memset(&chksums, 0, sizeof(chksums));
  328. mg_printf(conn,
  329. "HTTP/1.1 200 OK\r\n"
  330. "Content-Type: text/plain\r\n"
  331. "Connection: close\r\n\r\n");
  332. /* Call the form handler */
  333. mg_printf(conn, "File checksums:");
  334. ret = mg_handle_form_request(conn, &fdh);
  335. for (i = 0; i < chksums.index; i++) {
  336. md5_finish(&(chksums.file[i].chksum), digest);
  337. /* Visual Studio 2010+ support llu */
  338. mg_printf(conn,
  339. "\r\n%s %llu ",
  340. chksums.file[i].name,
  341. chksums.file[i].length);
  342. for (j = 0; j < 16; j++) {
  343. mg_printf(conn, "%02x", (unsigned int)digest[j]);
  344. }
  345. }
  346. mg_printf(conn, "\r\n%i files\r\n", ret);
  347. return 1;
  348. }
  349. int
  350. CookieHandler(struct mg_connection *conn, void *cbdata)
  351. {
  352. /* Handler may access the request info using mg_get_request_info */
  353. const struct mg_request_info *req_info = mg_get_request_info(conn);
  354. const char *cookie = mg_get_header(conn, "Cookie");
  355. char first_str[64], count_str[64];
  356. int count;
  357. (void)mg_get_cookie(cookie, "first", first_str, sizeof(first_str));
  358. (void)mg_get_cookie(cookie, "count", count_str, sizeof(count_str));
  359. mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close\r\n");
  360. if (first_str[0] == 0) {
  361. time_t t = time(0);
  362. struct tm *ptm = localtime(&t);
  363. mg_printf(conn,
  364. "Set-Cookie: first=%04i-%02i-%02iT%02i:%02i:%02i\r\n",
  365. ptm->tm_year + 1900,
  366. ptm->tm_mon + 1,
  367. ptm->tm_mday,
  368. ptm->tm_hour,
  369. ptm->tm_min,
  370. ptm->tm_sec);
  371. }
  372. count = (count_str[0] == 0) ? 0 : atoi(count_str);
  373. mg_printf(conn, "Set-Cookie: count=%i\r\n", count + 1);
  374. mg_printf(conn, "Content-Type: text/html\r\n\r\n");
  375. mg_printf(conn, "<html><body>");
  376. mg_printf(conn, "<h2>This is the CookieHandler.</h2>", cbdata);
  377. mg_printf(conn, "<p>The actual uri is %s</p>", req_info->uri);
  378. if (first_str[0] == 0) {
  379. mg_printf(conn, "<p>This is the first time, you opened this page</p>");
  380. } else {
  381. mg_printf(conn, "<p>You opened this page %i times before.</p>", count);
  382. mg_printf(conn, "<p>You first opened this page on %s.</p>", first_str);
  383. }
  384. mg_printf(conn, "</body></html>\n");
  385. return 1;
  386. }
  387. int
  388. WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
  389. {
  390. mg_printf(conn,
  391. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  392. "close\r\n\r\n");
  393. mg_printf(conn, "<!DOCTYPE html>\n");
  394. mg_printf(conn, "<html>\n<head>\n");
  395. mg_printf(conn, "<meta charset=\"UTF-8\">\n");
  396. mg_printf(conn, "<title>Embedded websocket example</title>\n");
  397. #ifdef USE_WEBSOCKET
  398. /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
  399. * xhtml style */
  400. mg_printf(conn, "<script>\n");
  401. mg_printf(
  402. conn,
  403. "function load() {\n"
  404. " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
  405. " connection = new WebSocket(wsproto + '//' + window.location.host + "
  406. "'/websocket');\n"
  407. " websock_text_field = "
  408. "document.getElementById('websock_text_field');\n"
  409. " connection.onmessage = function (e) {\n"
  410. " websock_text_field.innerHTML=e.data;\n"
  411. " }\n"
  412. " connection.onerror = function (error) {\n"
  413. " alert('WebSocket error');\n"
  414. " connection.close();\n"
  415. " }\n"
  416. "}\n");
  417. /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
  418. mg_printf(conn, "</script>\n");
  419. mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
  420. mg_printf(
  421. conn,
  422. "<div id='websock_text_field'>No websocket connection yet</div>\n");
  423. #else
  424. mg_printf(conn, "</head>\n<body>\n");
  425. mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
  426. #endif
  427. mg_printf(conn, "</body>\n</html>\n");
  428. return 1;
  429. }
  430. #ifdef USE_WEBSOCKET
  431. /* MAX_WS_CLIENTS defines how many clients can connect to a websocket at the
  432. * same time. The value 5 is very small and used here only for demonstration;
  433. * it can be easily tested to connect more than MAX_WS_CLIENTS clients.
  434. * A real server should use a much higher number, or better use a dynamic list
  435. * of currently connected websocket clients. */
  436. #define MAX_WS_CLIENTS (5)
  437. struct t_ws_client {
  438. struct mg_connection *conn;
  439. int state;
  440. } static ws_clients[MAX_WS_CLIENTS];
  441. #define ASSERT(x) \
  442. { \
  443. if (!(x)) { \
  444. fprintf(stderr, \
  445. "Assertion failed in line %u\n", \
  446. (unsigned)__LINE__); \
  447. } \
  448. }
  449. int
  450. WebSocketConnectHandler(const struct mg_connection *conn, void *cbdata)
  451. {
  452. struct mg_context *ctx = mg_get_context(conn);
  453. int reject = 1;
  454. int i;
  455. mg_lock_context(ctx);
  456. for (i = 0; i < MAX_WS_CLIENTS; i++) {
  457. if (ws_clients[i].conn == NULL) {
  458. ws_clients[i].conn = (struct mg_connection *)conn;
  459. ws_clients[i].state = 1;
  460. mg_set_user_connection_data(ws_clients[i].conn,
  461. (void *)(ws_clients + i));
  462. reject = 0;
  463. break;
  464. }
  465. }
  466. mg_unlock_context(ctx);
  467. fprintf(stdout,
  468. "Websocket client %s\r\n\r\n",
  469. (reject ? "rejected" : "accepted"));
  470. return reject;
  471. }
  472. void
  473. WebSocketReadyHandler(struct mg_connection *conn, void *cbdata)
  474. {
  475. const char *text = "Hello from the websocket ready handler";
  476. struct t_ws_client *client = mg_get_user_connection_data(conn);
  477. mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));
  478. fprintf(stdout, "Greeting message sent to websocket client\r\n\r\n");
  479. ASSERT(client->conn == conn);
  480. ASSERT(client->state == 1);
  481. client->state = 2;
  482. }
  483. int
  484. WebsocketDataHandler(struct mg_connection *conn,
  485. int bits,
  486. char *data,
  487. size_t len,
  488. void *cbdata)
  489. {
  490. struct t_ws_client *client = mg_get_user_connection_data(conn);
  491. ASSERT(client->conn == conn);
  492. ASSERT(client->state >= 1);
  493. fprintf(stdout, "Websocket got data:\r\n");
  494. fwrite(data, len, 1, stdout);
  495. fprintf(stdout, "\r\n\r\n");
  496. return 1;
  497. }
  498. void
  499. WebSocketCloseHandler(const struct mg_connection *conn, void *cbdata)
  500. {
  501. struct mg_context *ctx = mg_get_context(conn);
  502. struct t_ws_client *client = mg_get_user_connection_data(conn);
  503. ASSERT(client->conn == conn);
  504. ASSERT(client->state >= 1);
  505. mg_lock_context(ctx);
  506. client->state = 0;
  507. client->conn = NULL;
  508. mg_unlock_context(ctx);
  509. fprintf(stdout,
  510. "Client droped from the set of webserver connections\r\n\r\n");
  511. }
  512. void
  513. InformWebsockets(struct mg_context *ctx)
  514. {
  515. static unsigned long cnt = 0;
  516. char text[32];
  517. int i;
  518. sprintf(text, "%lu", ++cnt);
  519. mg_lock_context(ctx);
  520. for (i = 0; i < MAX_WS_CLIENTS; i++) {
  521. if (ws_clients[i].state == 2) {
  522. mg_websocket_write(ws_clients[i].conn,
  523. WEBSOCKET_OPCODE_TEXT,
  524. text,
  525. strlen(text));
  526. }
  527. }
  528. mg_unlock_context(ctx);
  529. }
  530. #endif
  531. #ifndef NO_SSL
  532. int
  533. init_ssl(void *ssl_context, void *user_data)
  534. {
  535. /* Add application specific SSL initialization */
  536. return 0;
  537. }
  538. #endif
  539. int
  540. main(int argc, char *argv[])
  541. {
  542. const char *options[] = {"document_root",
  543. DOCUMENT_ROOT,
  544. "listening_ports",
  545. PORT,
  546. "request_timeout_ms",
  547. "10000",
  548. "error_log_file",
  549. "error.log",
  550. #ifdef USE_WEBSOCKET
  551. "websocket_timeout_ms",
  552. "3600000",
  553. #endif
  554. #ifndef NO_SSL
  555. "ssl_certificate",
  556. "../../resources/cert/server.pem",
  557. "ssl_protocol_version",
  558. "3",
  559. "ssl_cipher_list",
  560. "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256"
  561. #endif
  562. 0};
  563. struct mg_callbacks callbacks;
  564. struct mg_context *ctx;
  565. struct mg_server_ports ports[32];
  566. int port_cnt, n;
  567. int err = 0;
  568. /* Check if libcivetweb has been built with all required features. */
  569. #ifdef USE_IPV6
  570. if (!mg_check_feature(8)) {
  571. fprintf(stderr,
  572. "Error: Embedded example built with IPv6 support, "
  573. "but civetweb library build without.\n");
  574. err = 1;
  575. }
  576. #endif
  577. #ifdef USE_WEBSOCKET
  578. if (!mg_check_feature(16)) {
  579. fprintf(stderr,
  580. "Error: Embedded example built with websocket support, "
  581. "but civetweb library build without.\n");
  582. err = 1;
  583. }
  584. #endif
  585. #ifndef NO_SSL
  586. if (!mg_check_feature(2)) {
  587. fprintf(stderr,
  588. "Error: Embedded example built with SSL support, "
  589. "but civetweb library build without.\n");
  590. err = 1;
  591. }
  592. #endif
  593. if (err) {
  594. fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");
  595. return EXIT_FAILURE;
  596. }
  597. /* Start CivetWeb web server */
  598. memset(&callbacks, 0, sizeof(callbacks));
  599. #ifndef NO_SSL
  600. callbacks.init_ssl = init_ssl;
  601. #endif
  602. ctx = mg_start(&callbacks, 0, options);
  603. /* Add handler EXAMPLE_URI, to explain the example */
  604. mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
  605. mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
  606. /* Add handler for /A* and special handler for /A/B */
  607. mg_set_request_handler(ctx, "/A", AHandler, 0);
  608. mg_set_request_handler(ctx, "/A/B", ABHandler, 0);
  609. /* Add handler for /B, /B/A, /B/B but not for /B* */
  610. mg_set_request_handler(ctx, "/B$", BXHandler, (void *)0);
  611. mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)1);
  612. mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)2);
  613. /* Add handler for all files with .foo extention */
  614. mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
  615. /* Add handler for /close extention */
  616. mg_set_request_handler(ctx, "/close", CloseHandler, 0);
  617. /* Add handler for /form (serve a file outside the document root) */
  618. mg_set_request_handler(ctx,
  619. "/form",
  620. FileHandler,
  621. (void *)"../../test/form.html");
  622. /* Add handler for form data */
  623. mg_set_request_handler(ctx,
  624. "/handle_form.embedded_c.example.callback",
  625. FormHandler,
  626. (void *)0);
  627. /* Add a file upload handler for parsing files on the fly */
  628. mg_set_request_handler(ctx,
  629. "/on_the_fly_form",
  630. FileUploadForm,
  631. (void *)"/on_the_fly_form.md5.callback");
  632. mg_set_request_handler(ctx,
  633. "/on_the_fly_form.md5.callback",
  634. CheckSumHandler,
  635. (void *)0);
  636. /* Add handler for /cookie example */
  637. mg_set_request_handler(ctx, "/cookie", CookieHandler, 0);
  638. /* Add HTTP site to open a websocket connection */
  639. mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
  640. #ifdef USE_WEBSOCKET
  641. /* WS site for the websocket connection */
  642. mg_set_websocket_handler(ctx,
  643. "/websocket",
  644. WebSocketConnectHandler,
  645. WebSocketReadyHandler,
  646. WebsocketDataHandler,
  647. WebSocketCloseHandler,
  648. 0);
  649. #endif
  650. /* List all listening ports */
  651. memset(ports, 0, sizeof(ports));
  652. port_cnt = mg_get_server_ports(ctx, 32, ports);
  653. printf("\n%i listening ports:\n\n", port_cnt);
  654. for (n = 0; n < port_cnt && n < 32; n++) {
  655. const char *proto = ports[n].is_ssl ? "https" : "http";
  656. const char *host;
  657. if ((ports[n].protocol & 1) == 1) {
  658. /* IPv4 */
  659. host = "127.0.0.1";
  660. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  661. printf("Run example at %s://%s:%i%s\n",
  662. proto,
  663. host,
  664. ports[n].port,
  665. EXAMPLE_URI);
  666. printf(
  667. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  668. printf("\n");
  669. }
  670. if ((ports[n].protocol & 2) == 2) {
  671. /* IPv6 */
  672. host = "[::1]";
  673. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  674. printf("Run example at %s://%s:%i%s\n",
  675. proto,
  676. host,
  677. ports[n].port,
  678. EXAMPLE_URI);
  679. printf(
  680. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  681. printf("\n");
  682. }
  683. }
  684. /* Wait until the server should be closed */
  685. while (!exitNow) {
  686. #ifdef _WIN32
  687. Sleep(1000);
  688. #else
  689. sleep(1);
  690. #endif
  691. #ifdef USE_WEBSOCKET
  692. InformWebsockets(ctx);
  693. #endif
  694. }
  695. /* Stop the server */
  696. mg_stop(ctx);
  697. printf("Server stopped.\n");
  698. printf("Bye!\n");
  699. return EXIT_SUCCESS;
  700. }