embedded_c.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /*
  2. * Copyright (c) 2013-2017 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->local_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->local_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>");
  377. mg_printf(conn, "<p>The actual uri is %s</p>", req_info->local_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. #ifdef USE_SSL_DH
  532. #include "openssl/ssl.h"
  533. #include "openssl/dh.h"
  534. #include "openssl/ec.h"
  535. #include "openssl/evp.h"
  536. #include "openssl/ecdsa.h"
  537. DH *
  538. get_dh2236()
  539. {
  540. static unsigned char dh2236_p[] = {
  541. 0x0E, 0x97, 0x6E, 0x6A, 0x88, 0x84, 0xD2, 0xD7, 0x55, 0x6A, 0x17, 0xB7,
  542. 0x81, 0x9A, 0x98, 0xBC, 0x7E, 0xD1, 0x6A, 0x44, 0xB1, 0x18, 0xE6, 0x25,
  543. 0x3A, 0x62, 0x35, 0xF0, 0x41, 0x91, 0xE2, 0x16, 0x43, 0x9D, 0x8F, 0x7D,
  544. 0x5D, 0xDA, 0x85, 0x47, 0x25, 0xC4, 0xBA, 0x68, 0x0A, 0x87, 0xDC, 0x2C,
  545. 0x33, 0xF9, 0x75, 0x65, 0x17, 0xCB, 0x8B, 0x80, 0xFE, 0xE0, 0xA8, 0xAF,
  546. 0xC7, 0x9E, 0x82, 0xBE, 0x6F, 0x1F, 0x00, 0x04, 0xBD, 0x69, 0x50, 0x8D,
  547. 0x9C, 0x3C, 0x41, 0x69, 0x21, 0x4E, 0x86, 0xC8, 0x2B, 0xCC, 0x07, 0x4D,
  548. 0xCF, 0xE4, 0xA2, 0x90, 0x8F, 0x66, 0xA9, 0xEF, 0xF7, 0xFC, 0x6F, 0x5F,
  549. 0x06, 0x22, 0x00, 0xCB, 0xCB, 0xC3, 0x98, 0x3F, 0x06, 0xB9, 0xEC, 0x48,
  550. 0x3B, 0x70, 0x6E, 0x94, 0xE9, 0x16, 0xE1, 0xB7, 0x63, 0x2E, 0xAB, 0xB2,
  551. 0xF3, 0x84, 0xB5, 0x3D, 0xD7, 0x74, 0xF1, 0x6A, 0xD1, 0xEF, 0xE8, 0x04,
  552. 0x18, 0x76, 0xD2, 0xD6, 0xB0, 0xB7, 0x71, 0xB6, 0x12, 0x8F, 0xD1, 0x33,
  553. 0xAB, 0x49, 0xAB, 0x09, 0x97, 0x35, 0x9D, 0x4B, 0xBB, 0x54, 0x22, 0x6E,
  554. 0x1A, 0x33, 0x18, 0x02, 0x8A, 0xF4, 0x7C, 0x0A, 0xCE, 0x89, 0x75, 0x2D,
  555. 0x10, 0x68, 0x25, 0xA9, 0x6E, 0xCD, 0x97, 0x49, 0xED, 0xAE, 0xE6, 0xA7,
  556. 0xB0, 0x07, 0x26, 0x25, 0x60, 0x15, 0x2B, 0x65, 0x88, 0x17, 0xF2, 0x5D,
  557. 0x2C, 0xF6, 0x2A, 0x7A, 0x8C, 0xAD, 0xB6, 0x0A, 0xA2, 0x57, 0xB0, 0xC1,
  558. 0x0E, 0x5C, 0xA8, 0xA1, 0x96, 0x58, 0x9A, 0x2B, 0xD4, 0xC0, 0x8A, 0xCF,
  559. 0x91, 0x25, 0x94, 0xB4, 0x14, 0xA7, 0xE4, 0xE2, 0x1B, 0x64, 0x5F, 0xD2,
  560. 0xCA, 0x70, 0x46, 0xD0, 0x2C, 0x95, 0x6B, 0x9A, 0xFB, 0x83, 0xF9, 0x76,
  561. 0xE6, 0xD4, 0xA4, 0xA1, 0x2B, 0x2F, 0xF5, 0x1D, 0xE4, 0x06, 0xAF, 0x7D,
  562. 0x22, 0xF3, 0x04, 0x30, 0x2E, 0x4C, 0x64, 0x12, 0x5B, 0xB0, 0x55, 0x3E,
  563. 0xC0, 0x5E, 0x56, 0xCB, 0x99, 0xBC, 0xA8, 0xD9, 0x23, 0xF5, 0x57, 0x40,
  564. 0xF0, 0x52, 0x85, 0x9B,
  565. };
  566. static unsigned char dh2236_g[] = {
  567. 0x02,
  568. };
  569. DH *dh;
  570. if ((dh = DH_new()) == NULL)
  571. return (NULL);
  572. dh->p = BN_bin2bn(dh2236_p, sizeof(dh2236_p), NULL);
  573. dh->g = BN_bin2bn(dh2236_g, sizeof(dh2236_g), NULL);
  574. if ((dh->p == NULL) || (dh->g == NULL)) {
  575. DH_free(dh);
  576. return (NULL);
  577. }
  578. return (dh);
  579. }
  580. #endif
  581. #ifndef NO_SSL
  582. int
  583. init_ssl(void *ssl_context, void *user_data)
  584. {
  585. /* Add application specific SSL initialization */
  586. struct ssl_ctx_st *ctx = (struct ssl_ctx_st *)ssl_context;
  587. #ifdef USE_SSL_DH
  588. /* example from https://github.com/civetweb/civetweb/issues/347 */
  589. DH *dh = get_dh2236();
  590. if (!dh)
  591. return -1;
  592. if (1 != SSL_CTX_set_tmp_dh(ctx, dh))
  593. return -1;
  594. DH_free(dh);
  595. EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
  596. if (!ecdh)
  597. return -1;
  598. if (1 != SSL_CTX_set_tmp_ecdh(ctx, ecdh))
  599. return -1;
  600. EC_KEY_free(ecdh);
  601. printf("ECDH ciphers initialized\n");
  602. #endif
  603. return 0;
  604. }
  605. #endif
  606. int
  607. log_message(const struct mg_connection *conn, const char *message)
  608. {
  609. puts(message);
  610. return 1;
  611. }
  612. int
  613. main(int argc, char *argv[])
  614. {
  615. const char *options[] = {
  616. "document_root",
  617. DOCUMENT_ROOT,
  618. "listening_ports",
  619. PORT,
  620. "request_timeout_ms",
  621. "10000",
  622. "error_log_file",
  623. "error.log",
  624. #ifdef USE_WEBSOCKET
  625. "websocket_timeout_ms",
  626. "3600000",
  627. #endif
  628. #ifndef NO_SSL
  629. "ssl_certificate",
  630. "../../resources/cert/server.pem",
  631. "ssl_protocol_version",
  632. "3",
  633. "ssl_cipher_list",
  634. #ifdef USE_SSL_DH
  635. "ECDHE-RSA-AES256-GCM-SHA384:DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
  636. #else
  637. "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
  638. #endif
  639. #endif
  640. 0};
  641. struct mg_callbacks callbacks;
  642. struct mg_context *ctx;
  643. struct mg_server_ports ports[32];
  644. int port_cnt, n;
  645. int err = 0;
  646. /* Check if libcivetweb has been built with all required features. */
  647. #ifdef USE_IPV6
  648. if (!mg_check_feature(8)) {
  649. fprintf(stderr,
  650. "Error: Embedded example built with IPv6 support, "
  651. "but civetweb library build without.\n");
  652. err = 1;
  653. }
  654. #endif
  655. #ifdef USE_WEBSOCKET
  656. if (!mg_check_feature(16)) {
  657. fprintf(stderr,
  658. "Error: Embedded example built with websocket support, "
  659. "but civetweb library build without.\n");
  660. err = 1;
  661. }
  662. #endif
  663. #ifndef NO_SSL
  664. if (!mg_check_feature(2)) {
  665. fprintf(stderr,
  666. "Error: Embedded example built with SSL support, "
  667. "but civetweb library build without.\n");
  668. err = 1;
  669. }
  670. #endif
  671. if (err) {
  672. fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");
  673. return EXIT_FAILURE;
  674. }
  675. /* Start CivetWeb web server */
  676. memset(&callbacks, 0, sizeof(callbacks));
  677. #ifndef NO_SSL
  678. callbacks.init_ssl = init_ssl;
  679. #endif
  680. callbacks.log_message = log_message;
  681. ctx = mg_start(&callbacks, 0, options);
  682. /* Check return value: */
  683. if (ctx == NULL) {
  684. fprintf(stderr, "Cannot start CivetWeb - mg_start failed.\n");
  685. return EXIT_FAILURE;
  686. }
  687. /* Add handler EXAMPLE_URI, to explain the example */
  688. mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
  689. mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
  690. /* Add handler for /A* and special handler for /A/B */
  691. mg_set_request_handler(ctx, "/A", AHandler, 0);
  692. mg_set_request_handler(ctx, "/A/B", ABHandler, 0);
  693. /* Add handler for /B, /B/A, /B/B but not for /B* */
  694. mg_set_request_handler(ctx, "/B$", BXHandler, (void *)0);
  695. mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)1);
  696. mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)2);
  697. /* Add handler for all files with .foo extention */
  698. mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
  699. /* Add handler for /close extention */
  700. mg_set_request_handler(ctx, "/close", CloseHandler, 0);
  701. /* Add handler for /form (serve a file outside the document root) */
  702. mg_set_request_handler(ctx,
  703. "/form",
  704. FileHandler,
  705. (void *)"../../test/form.html");
  706. /* Add handler for form data */
  707. mg_set_request_handler(ctx,
  708. "/handle_form.embedded_c.example.callback",
  709. FormHandler,
  710. (void *)0);
  711. /* Add a file upload handler for parsing files on the fly */
  712. mg_set_request_handler(ctx,
  713. "/on_the_fly_form",
  714. FileUploadForm,
  715. (void *)"/on_the_fly_form.md5.callback");
  716. mg_set_request_handler(ctx,
  717. "/on_the_fly_form.md5.callback",
  718. CheckSumHandler,
  719. (void *)0);
  720. /* Add handler for /cookie example */
  721. mg_set_request_handler(ctx, "/cookie", CookieHandler, 0);
  722. /* Add HTTP site to open a websocket connection */
  723. mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
  724. #ifdef USE_WEBSOCKET
  725. /* WS site for the websocket connection */
  726. mg_set_websocket_handler(ctx,
  727. "/websocket",
  728. WebSocketConnectHandler,
  729. WebSocketReadyHandler,
  730. WebsocketDataHandler,
  731. WebSocketCloseHandler,
  732. 0);
  733. #endif
  734. /* List all listening ports */
  735. memset(ports, 0, sizeof(ports));
  736. port_cnt = mg_get_server_ports(ctx, 32, ports);
  737. printf("\n%i listening ports:\n\n", port_cnt);
  738. for (n = 0; n < port_cnt && n < 32; n++) {
  739. const char *proto = ports[n].is_ssl ? "https" : "http";
  740. const char *host;
  741. if ((ports[n].protocol & 1) == 1) {
  742. /* IPv4 */
  743. host = "127.0.0.1";
  744. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  745. printf("Run example at %s://%s:%i%s\n",
  746. proto,
  747. host,
  748. ports[n].port,
  749. EXAMPLE_URI);
  750. printf(
  751. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  752. printf("\n");
  753. }
  754. if ((ports[n].protocol & 2) == 2) {
  755. /* IPv6 */
  756. host = "[::1]";
  757. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  758. printf("Run example at %s://%s:%i%s\n",
  759. proto,
  760. host,
  761. ports[n].port,
  762. EXAMPLE_URI);
  763. printf(
  764. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  765. printf("\n");
  766. }
  767. }
  768. /* Wait until the server should be closed */
  769. while (!exitNow) {
  770. #ifdef _WIN32
  771. Sleep(1000);
  772. #else
  773. sleep(1);
  774. #endif
  775. #ifdef USE_WEBSOCKET
  776. InformWebsockets(ctx);
  777. #endif
  778. }
  779. /* Stop the server */
  780. mg_stop(ctx);
  781. printf("Server stopped.\n");
  782. printf("Bye!\n");
  783. return EXIT_SUCCESS;
  784. }