embedded_cpp.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /* Copyright (c) 2013-2018 the Civetweb developers
  2. * Copyright (c) 2013 No Face Press, LLC
  3. * License http://opensource.org/licenses/mit-license.php MIT License
  4. */
  5. // Simple example program on how to use Embedded C++ interface.
  6. #include "CivetServer.h"
  7. #include <cstring>
  8. #ifdef _WIN32
  9. #include <windows.h>
  10. #else
  11. #include <unistd.h>
  12. #endif
  13. #define DOCUMENT_ROOT "."
  14. #define PORT "8081"
  15. #define EXAMPLE_URI "/example"
  16. #define EXIT_URI "/exit"
  17. /* Exit flag for main loop */
  18. volatile bool exitNow = false;
  19. class ExampleHandler : public CivetHandler
  20. {
  21. public:
  22. bool
  23. handleGet(CivetServer *server, struct mg_connection *conn)
  24. {
  25. mg_printf(conn,
  26. "HTTP/1.1 200 OK\r\nContent-Type: "
  27. "text/html\r\nConnection: close\r\n\r\n");
  28. mg_printf(conn, "<html><body>\r\n");
  29. mg_printf(conn,
  30. "<h2>This is an example text from a C++ handler</h2>\r\n");
  31. mg_printf(conn,
  32. "<p>To see a page from the A handler <a "
  33. "href=\"a\">click here</a></p>\r\n");
  34. mg_printf(conn,
  35. "<form action=\"a\" method=\"get\">"
  36. "To see a page from the A handler with a parameter "
  37. "<input type=\"submit\" value=\"click here\" "
  38. "name=\"param\" \\> (GET)</form>\r\n");
  39. mg_printf(conn,
  40. "<form action=\"a\" method=\"post\">"
  41. "To see a page from the A handler with a parameter "
  42. "<input type=\"submit\" value=\"click here\" "
  43. "name=\"param\" \\> (POST)</form>\r\n");
  44. mg_printf(conn,
  45. "<p>To see a page from the A/B handler <a "
  46. "href=\"a/b\">click here</a></p>\r\n");
  47. mg_printf(conn,
  48. "<p>To see a page from the *.foo handler <a "
  49. "href=\"xy.foo\">click here</a></p>\r\n");
  50. mg_printf(conn,
  51. "<p>To see a page from the WebSocket handler <a "
  52. "href=\"ws\">click here</a></p>\r\n");
  53. mg_printf(conn,
  54. "<p>To exit <a href=\"%s\">click here</a></p>\r\n",
  55. EXIT_URI);
  56. mg_printf(conn, "</body></html>\r\n");
  57. return true;
  58. }
  59. };
  60. class ExitHandler : public CivetHandler
  61. {
  62. public:
  63. bool
  64. handleGet(CivetServer *server, struct mg_connection *conn)
  65. {
  66. mg_printf(conn,
  67. "HTTP/1.1 200 OK\r\nContent-Type: "
  68. "text/plain\r\nConnection: close\r\n\r\n");
  69. mg_printf(conn, "Bye!\n");
  70. exitNow = true;
  71. return true;
  72. }
  73. };
  74. class AHandler : public CivetHandler
  75. {
  76. private:
  77. bool
  78. handleAll(const char *method,
  79. CivetServer *server,
  80. struct mg_connection *conn)
  81. {
  82. std::string s = "";
  83. mg_printf(conn,
  84. "HTTP/1.1 200 OK\r\nContent-Type: "
  85. "text/html\r\nConnection: close\r\n\r\n");
  86. mg_printf(conn, "<html><body>");
  87. mg_printf(conn, "<h2>This is the A handler for \"%s\" !</h2>", method);
  88. if (CivetServer::getParam(conn, "param", s)) {
  89. mg_printf(conn, "<p>param set to %s</p>", s.c_str());
  90. } else {
  91. mg_printf(conn, "<p>param not set</p>");
  92. }
  93. mg_printf(conn, "</body></html>\n");
  94. return true;
  95. }
  96. public:
  97. bool
  98. handleGet(CivetServer *server, struct mg_connection *conn)
  99. {
  100. return handleAll("GET", server, conn);
  101. }
  102. bool
  103. handlePost(CivetServer *server, struct mg_connection *conn)
  104. {
  105. return handleAll("POST", server, conn);
  106. }
  107. };
  108. class ABHandler : public CivetHandler
  109. {
  110. public:
  111. bool
  112. handleGet(CivetServer *server, struct mg_connection *conn)
  113. {
  114. mg_printf(conn,
  115. "HTTP/1.1 200 OK\r\nContent-Type: "
  116. "text/html\r\nConnection: close\r\n\r\n");
  117. mg_printf(conn, "<html><body>");
  118. mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
  119. mg_printf(conn, "</body></html>\n");
  120. return true;
  121. }
  122. };
  123. class FooHandler : public CivetHandler
  124. {
  125. public:
  126. bool
  127. handleGet(CivetServer *server, struct mg_connection *conn)
  128. {
  129. /* Handler may access the request info using mg_get_request_info */
  130. const struct mg_request_info *req_info = mg_get_request_info(conn);
  131. mg_printf(conn,
  132. "HTTP/1.1 200 OK\r\nContent-Type: "
  133. "text/html\r\nConnection: close\r\n\r\n");
  134. mg_printf(conn, "<html><body>\n");
  135. mg_printf(conn, "<h2>This is the Foo GET handler!!!</h2>\n");
  136. mg_printf(conn,
  137. "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
  138. req_info->request_method,
  139. req_info->request_uri,
  140. req_info->http_version);
  141. mg_printf(conn, "</body></html>\n");
  142. return true;
  143. }
  144. bool
  145. handlePost(CivetServer *server, struct mg_connection *conn)
  146. {
  147. /* Handler may access the request info using mg_get_request_info */
  148. const struct mg_request_info *req_info = mg_get_request_info(conn);
  149. long long rlen, wlen;
  150. long long nlen = 0;
  151. long long tlen = req_info->content_length;
  152. char buf[1024];
  153. mg_printf(conn,
  154. "HTTP/1.1 200 OK\r\nContent-Type: "
  155. "text/html\r\nConnection: close\r\n\r\n");
  156. mg_printf(conn, "<html><body>\n");
  157. mg_printf(conn, "<h2>This is the Foo POST handler!!!</h2>\n");
  158. mg_printf(conn,
  159. "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
  160. req_info->request_method,
  161. req_info->request_uri,
  162. req_info->http_version);
  163. mg_printf(conn, "<p>Content Length: %li</p>\n", (long)tlen);
  164. mg_printf(conn, "<pre>\n");
  165. while (nlen < tlen) {
  166. rlen = tlen - nlen;
  167. if (rlen > sizeof(buf)) {
  168. rlen = sizeof(buf);
  169. }
  170. rlen = mg_read(conn, buf, (size_t)rlen);
  171. if (rlen <= 0) {
  172. break;
  173. }
  174. wlen = mg_write(conn, buf, (size_t)rlen);
  175. if (wlen != rlen) {
  176. break;
  177. }
  178. nlen += wlen;
  179. }
  180. mg_printf(conn, "\n</pre>\n");
  181. mg_printf(conn, "</body></html>\n");
  182. return true;
  183. }
  184. #define fopen_recursive fopen
  185. bool
  186. handlePut(CivetServer *server, struct mg_connection *conn)
  187. {
  188. /* Handler may access the request info using mg_get_request_info */
  189. const struct mg_request_info *req_info = mg_get_request_info(conn);
  190. long long rlen, wlen;
  191. long long nlen = 0;
  192. long long tlen = req_info->content_length;
  193. FILE * f;
  194. char buf[1024];
  195. int fail = 0;
  196. #ifdef _WIN32
  197. _snprintf(buf, sizeof(buf), "D:\\somewhere\\%s\\%s", req_info->remote_user, req_info->local_uri);
  198. buf[sizeof(buf)-1] = 0;
  199. if (strlen(buf)>255) {
  200. /* Windows will not work with path > 260 (MAX_PATH), unless we use
  201. * the unicode API. However, this is just an example code: A real
  202. * code will probably never store anything to D:\\somewhere and
  203. * must be adapted to the specific needs anyhow. */
  204. fail = 1;
  205. f = NULL;
  206. } else {
  207. f = fopen_recursive(buf, "wb");
  208. }
  209. #else
  210. snprintf(buf, sizeof(buf), "~/somewhere/%s/%s", req_info->remote_user, req_info->local_uri);
  211. buf[sizeof(buf)-1] = 0;
  212. if (strlen(buf)>1020) {
  213. /* The string is too long and probably truncated. Make sure an
  214. * UTF-8 string is never truncated between the UTF-8 code bytes.
  215. * This example code must be adapted to the specific needs. */
  216. fail = 1;
  217. f = NULL;
  218. } else {
  219. f = fopen_recursive(buf, "w");
  220. }
  221. #endif
  222. if (!f) {
  223. fail = 1;
  224. } else {
  225. while (nlen < tlen) {
  226. rlen = tlen - nlen;
  227. if (rlen > sizeof(buf)) {
  228. rlen = sizeof(buf);
  229. }
  230. rlen = mg_read(conn, buf, (size_t)rlen);
  231. if (rlen <= 0) {
  232. fail = 1;
  233. break;
  234. }
  235. wlen = fwrite(buf, 1, (size_t)rlen, f);
  236. if (wlen != rlen) {
  237. fail = 1;
  238. break;
  239. }
  240. nlen += wlen;
  241. }
  242. fclose(f);
  243. }
  244. if (fail) {
  245. mg_printf(conn,
  246. "HTTP/1.1 409 Conflict\r\n"
  247. "Content-Type: text/plain\r\n"
  248. "Connection: close\r\n\r\n");
  249. } else {
  250. mg_printf(conn,
  251. "HTTP/1.1 201 Created\r\n"
  252. "Content-Type: text/plain\r\n"
  253. "Connection: close\r\n\r\n");
  254. }
  255. return true;
  256. }
  257. };
  258. class WsStartHandler : public CivetHandler
  259. {
  260. public:
  261. bool
  262. handleGet(CivetServer *server, struct mg_connection *conn)
  263. {
  264. mg_printf(conn,
  265. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
  266. "close\r\n\r\n");
  267. mg_printf(conn, "<!DOCTYPE html>\n");
  268. mg_printf(conn, "<html>\n<head>\n");
  269. mg_printf(conn, "<meta charset=\"UTF-8\">\n");
  270. mg_printf(conn, "<title>Embedded websocket example</title>\n");
  271. #ifdef USE_WEBSOCKET
  272. /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
  273. * xhtml style */
  274. mg_printf(conn, "<script>\n");
  275. mg_printf(
  276. conn,
  277. "var i=0\n"
  278. "function load() {\n"
  279. " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
  280. " connection = new WebSocket(wsproto + '//' + window.location.host + "
  281. "'/websocket');\n"
  282. " websock_text_field = "
  283. "document.getElementById('websock_text_field');\n"
  284. " connection.onmessage = function (e) {\n"
  285. " websock_text_field.innerHTML=e.data;\n"
  286. " i=i+1;"
  287. " connection.send(i);\n"
  288. " }\n"
  289. " connection.onerror = function (error) {\n"
  290. " alert('WebSocket error');\n"
  291. " connection.close();\n"
  292. " }\n"
  293. "}\n");
  294. /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
  295. mg_printf(conn, "</script>\n");
  296. mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
  297. mg_printf(
  298. conn,
  299. "<div id='websock_text_field'>No websocket connection yet</div>\n");
  300. #else
  301. mg_printf(conn, "</head>\n<body>\n");
  302. mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
  303. #endif
  304. mg_printf(conn, "</body>\n</html>\n");
  305. return 1;
  306. }
  307. };
  308. #ifdef USE_WEBSOCKET
  309. class WebSocketHandler : public CivetWebSocketHandler {
  310. virtual bool handleConnection(CivetServer *server,
  311. const struct mg_connection *conn) {
  312. printf("WS connected\n");
  313. return true;
  314. }
  315. virtual void handleReadyState(CivetServer *server,
  316. struct mg_connection *conn) {
  317. printf("WS ready\n");
  318. const char *text = "Hello from the websocket ready handler";
  319. mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, text, strlen(text));
  320. }
  321. virtual bool handleData(CivetServer *server,
  322. struct mg_connection *conn,
  323. int bits,
  324. char *data,
  325. size_t data_len) {
  326. printf("WS got %lu bytes: ", (long unsigned)data_len);
  327. fwrite(data, 1, data_len, stdout);
  328. printf("\n");
  329. mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, data, data_len);
  330. return (data_len<4);
  331. }
  332. virtual void handleClose(CivetServer *server,
  333. const struct mg_connection *conn) {
  334. printf("WS closed\n");
  335. }
  336. };
  337. #endif
  338. int
  339. main(int argc, char *argv[])
  340. {
  341. mg_init_library(0);
  342. const char *options[] = {
  343. "document_root", DOCUMENT_ROOT, "listening_ports", PORT, 0};
  344. std::vector<std::string> cpp_options;
  345. for (int i=0; i<(sizeof(options)/sizeof(options[0])-1); i++) {
  346. cpp_options.push_back(options[i]);
  347. }
  348. // CivetServer server(options); // <-- C style start
  349. CivetServer server(cpp_options); // <-- C++ style start
  350. ExampleHandler h_ex;
  351. server.addHandler(EXAMPLE_URI, h_ex);
  352. ExitHandler h_exit;
  353. server.addHandler(EXIT_URI, h_exit);
  354. AHandler h_a;
  355. server.addHandler("/a", h_a);
  356. ABHandler h_ab;
  357. server.addHandler("/a/b", h_ab);
  358. WsStartHandler h_ws;
  359. server.addHandler("/ws", h_ws);
  360. #ifdef NO_FILES
  361. /* This handler will handle "everything else", including
  362. * requests to files. If this handler is installed,
  363. * NO_FILES should be set. */
  364. FooHandler h_foo;
  365. server.addHandler("", h_foo);
  366. printf("See a page from the \"all\" handler at http://localhost:%s/\n", PORT);
  367. #else
  368. FooHandler h_foo;
  369. server.addHandler("**.foo", h_foo);
  370. printf("Browse files at http://localhost:%s/\n", PORT);
  371. #endif
  372. #ifdef USE_WEBSOCKET
  373. WebSocketHandler h_websocket;
  374. server.addWebSocketHandler("/websocket", h_websocket);
  375. printf("Run websocket example at http://localhost:%s/ws\n", PORT);
  376. #endif
  377. printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
  378. printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);
  379. while (!exitNow) {
  380. #ifdef _WIN32
  381. Sleep(1000);
  382. #else
  383. sleep(1);
  384. #endif
  385. }
  386. printf("Bye!\n");
  387. mg_exit_library();
  388. return 0;
  389. }