embedded_cpp.cpp 12 KB

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