example.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * This file is an example of how to embed web-server functionality
  3. * into existing application.
  4. * Compilation line (from Mongoose sources root directory):
  5. * cc mongoose.c examples/example.c -I. -lpthread -o example
  6. */
  7. #ifdef _WIN32
  8. #include <winsock.h>
  9. #define snprintf _snprintf
  10. #ifndef _WIN32_WCE
  11. #ifdef _MSC_VER /* pragmas not valid on MinGW */
  12. #endif /* _MSC_VER */
  13. #define ALIAS_URI "/my_c"
  14. #define ALIAS_DIR "c:\\"
  15. #else /* _WIN32_WCE */
  16. /* Windows CE-specific definitions */
  17. #pragma comment(lib,"ws2")
  18. //#include "compat_wince.h"
  19. #define ALIAS_URI "/my_root"
  20. #define ALIAS_DIR "\\"
  21. #endif /* _WIN32_WCE */
  22. #else
  23. #include <sys/types.h>
  24. #include <sys/select.h>
  25. #include <sys/wait.h>
  26. #define ALIAS_URI "/my_etc"
  27. #define ALIAS_DIR "/etc/"
  28. #endif
  29. #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
  30. #include <time.h>
  31. #include <errno.h>
  32. #include <signal.h>
  33. #endif
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <assert.h>
  37. #include <string.h>
  38. #include "mongoose.h"
  39. /*
  40. * This callback function is attached to the "/" and "/abc.html" URIs,
  41. * thus is acting as "index.html" file. It shows a bunch of links
  42. * to other URIs, and allows to change the value of program's
  43. * internal variable. The pointer to that variable is passed to the
  44. * callback function as arg->user_data.
  45. */
  46. static void
  47. show_index(struct mg_connection *conn,
  48. const struct mg_request_info *request_info,
  49. void *user_data)
  50. {
  51. char *value;
  52. const char *host;
  53. /* Change the value of integer variable */
  54. value = mg_get_var(conn, "name1");
  55. if (value != NULL) {
  56. * (int *) user_data = atoi(value);
  57. mg_free(value);
  58. /*
  59. * Suggested by Luke Dunstan. When POST is used,
  60. * send 303 code to force the browser to re-request the
  61. * page using GET method. This prevents the possibility of
  62. * the user accidentally resubmitting the form when using
  63. * Refresh or Back commands in the browser.
  64. */
  65. if (!strcmp(request_info->request_method, "POST")) {
  66. (void) mg_printf(conn, "HTTP/1.1 303 See Other\r\n"
  67. "Location: %s\r\n\r\n", request_info->uri);
  68. return;
  69. }
  70. }
  71. mg_printf(conn, "%s",
  72. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
  73. "<html><body><h1>Welcome to embedded example of Mongoose");
  74. mg_printf(conn, " v. %s </h1><ul>", mg_version());
  75. mg_printf(conn, "<li><code>REQUEST_METHOD: %s "
  76. "REQUEST_URI: \"%s\" QUERY_STRING: \"%s\""
  77. " REMOTE_ADDR: %lx REMOTE_USER: \"(null)\"</code><hr>",
  78. request_info->request_method, request_info->uri,
  79. request_info->query_string ? request_info->query_string : "(null)",
  80. request_info->remote_ip);
  81. mg_printf(conn, "<li>Internal int variable value: <b>%d</b>",
  82. * (int *) user_data);
  83. mg_printf(conn, "%s",
  84. "<form method=\"GET\">Enter new value: "
  85. "<input type=\"text\" name=\"name1\"/>"
  86. "<input type=\"submit\" "
  87. "value=\"set new value using GET method\"></form>");
  88. mg_printf(conn, "%s",
  89. "<form method=\"POST\">Enter new value: "
  90. "<input type=\"text\" name=\"name1\"/>"
  91. "<input type=\"submit\" "
  92. "value=\"set new value using POST method\"></form>");
  93. mg_printf(conn, "%s",
  94. "<hr><li><a href=\"/secret\">"
  95. "Protected page</a> (guest:guest)<hr>"
  96. "<li><a href=\"/huge\">Output lots of data</a><hr>"
  97. "<li><a href=\"" ALIAS_URI "/\">Aliased "
  98. ALIAS_DIR " directory</a><hr>");
  99. mg_printf(conn, "%s",
  100. "<li><a href=\"/Makefile\">Regular file (Makefile)</a><hr>"
  101. "<li><a href=\"/ssi_test.shtml\">SSI file "
  102. "(ssi_test.shtml)</a><hr>"
  103. "<li><a href=\"/users/joe/\">Wildcard URI example</a><hr>"
  104. "<li><a href=\"/not-existent/\">Custom 404 handler</a><hr>");
  105. host = mg_get_header(conn, "Host");
  106. mg_printf(conn, "<li>'Host' header value: [%s]<hr>",
  107. host ? host : "NOT SET");
  108. mg_printf(conn, "<li>Upload file example. "
  109. "<form method=\"post\" enctype=\"multipart/form-data\" "
  110. "action=\"/post\"><input type=\"file\" name=\"file\">"
  111. "<input type=\"submit\"></form>");
  112. mg_printf(conn, "%s", "</body></html>");
  113. }
  114. /*
  115. * This callback is attached to the URI "/post"
  116. * It uploads file from a client to the server. This is the demostration
  117. * of how to use POST method to send lots of data from the client.
  118. * The uploaded file is saved into "uploaded.txt".
  119. * This function is called many times during single request. To keep the
  120. * state (how many bytes we have received, opened file etc), we allocate
  121. * a "struct state" structure for every new connection.
  122. */
  123. static void
  124. show_post(struct mg_connection *conn,
  125. const struct mg_request_info *request_info,
  126. void *user_data)
  127. {
  128. const char *path = "uploaded.txt";
  129. FILE *fp;
  130. mg_printf(conn, "HTTP/1.0 200 OK\nContent-Type: text/plain\n\n");
  131. /*
  132. * Open a file and write POST data into it. We do not do any URL
  133. * decoding here. File will contain form-urlencoded stuff.
  134. */
  135. if ((fp = fopen(path, "wb+")) == NULL) {
  136. (void) fprintf(stderr, "Error opening %s: %s\n",
  137. path, strerror(errno));
  138. } else if (fwrite(request_info->post_data,
  139. request_info->post_data_len, 1, fp) != 1) {
  140. (void) fprintf(stderr, "Error writing to %s: %s\n",
  141. path, strerror(errno));
  142. } else {
  143. /* Write was successful */
  144. (void) fclose(fp);
  145. }
  146. }
  147. /*
  148. * This callback function is attached to the "/secret" URI.
  149. * It shows simple text message, but in order to be shown, user must
  150. * authorized himself against the passwords file "passfile".
  151. */
  152. static void
  153. show_secret(struct mg_connection *conn,
  154. const struct mg_request_info *request_info,
  155. void *user_data)
  156. {
  157. mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n");
  158. mg_printf(conn, "%s", "Content-Type: text/html\r\n\r\n");
  159. mg_printf(conn, "%s", "<html><body>");
  160. mg_printf(conn, "%s", "<p>This is a protected page</body></html>");
  161. }
  162. /*
  163. * This callback function is attached to the "/huge" URI.
  164. * It outputs binary data to the client.
  165. * The number of bytes already sent is stored directly in the arg->state.
  166. */
  167. static void
  168. show_huge(struct mg_connection *conn,
  169. const struct mg_request_info *request_info,
  170. void *user_data)
  171. {
  172. int i;
  173. const char *line = "Hello, this is a line of text";
  174. mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n");
  175. mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
  176. for (i = 0; i < 1024 * 1024; i++)
  177. mg_printf(conn, "%s\n", line);
  178. }
  179. /*
  180. * This callback function is used to show how to handle 404 error
  181. */
  182. static void
  183. show_404(struct mg_connection *conn,
  184. const struct mg_request_info *request_info,
  185. void *user_data)
  186. {
  187. mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n");
  188. mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
  189. mg_printf(conn, "%s", "Oops. File not found! ");
  190. mg_printf(conn, "%s", "This is a custom error handler.");
  191. }
  192. /*
  193. * This callback function is attached to the wildcard URI "/users/.*"
  194. * It shows a greeting message and an actual URI requested by the user.
  195. */
  196. static void
  197. show_users(struct mg_connection *conn,
  198. const struct mg_request_info *request_info,
  199. void *user_data)
  200. {
  201. mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n");
  202. mg_printf(conn, "%s", "Content-Type: text/html\r\n\r\n");
  203. mg_printf(conn, "%s", "<html><body>");
  204. mg_printf(conn, "%s", "<h1>Hi. This is a wildcard uri handler"
  205. "for the URI /users/*/ </h1>");
  206. mg_printf(conn, "<h2>URI: %s</h2></body></html>", request_info->uri);
  207. }
  208. /*
  209. * Make sure we have ho zombies from CGIs
  210. */
  211. static void
  212. signal_handler(int sig_num)
  213. {
  214. switch (sig_num) {
  215. #ifndef _WIN32
  216. case SIGCHLD:
  217. while (waitpid(-1, &sig_num, WNOHANG) > 0) ;
  218. break;
  219. #endif /* !_WIN32 */
  220. default:
  221. break;
  222. }
  223. }
  224. int main(int argc, char *argv[])
  225. {
  226. int data = 1234567;
  227. struct mg_context *ctx;
  228. /* Get rid of warnings */
  229. argc = argc;
  230. argv = argv;
  231. #ifndef _WIN32
  232. signal(SIGPIPE, SIG_IGN);
  233. signal(SIGCHLD, &signal_handler);
  234. #endif /* !_WIN32 */
  235. /*
  236. * Initialize SHTTPD context.
  237. * Attach folder c:\ to the URL /my_c (for windows), and
  238. * /etc/ to URL /my_etc (for UNIX). These are Apache-like aliases.
  239. * Set WWW root to current directory.
  240. * Start listening on ports 8080 and 8081
  241. */
  242. ctx = mg_start();
  243. mg_set_option(ctx, "ssl_cert", "ssl_cert.pem");
  244. mg_set_option(ctx, "aliases", ALIAS_URI "=" ALIAS_DIR);
  245. mg_set_option(ctx, "ports", "8080,8081s");
  246. /* Register an index page under two URIs */
  247. mg_set_uri_callback(ctx, "/", &show_index, (void *) &data);
  248. mg_set_uri_callback(ctx, "/abc.html", &show_index, (void *) &data);
  249. /* Register a callback on wildcard URI */
  250. mg_set_uri_callback(ctx, "/users/*/", &show_users, NULL);
  251. /* Show how to use password protection */
  252. mg_set_uri_callback(ctx, "/secret", &show_secret, NULL);
  253. mg_set_option(ctx, "protect", "/secret=passfile");
  254. /* Show how to use stateful big data transfer */
  255. mg_set_uri_callback(ctx, "/huge", &show_huge, NULL);
  256. /* Register URI for file upload */
  257. mg_set_uri_callback(ctx, "/post", &show_post, NULL);
  258. mg_set_error_callback(ctx, 404, show_404, NULL);
  259. /* Wait until user presses 'enter' on console */
  260. (void) getchar();
  261. mg_stop(ctx);
  262. return (EXIT_SUCCESS);
  263. }