rest.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright (c) 2018 the CivetWeb developers
  3. * MIT License
  4. */
  5. /* Simple demo of a REST callback. */
  6. #ifdef _WIN32
  7. # include <windows.h>
  8. #else
  9. # include <unistd.h>
  10. #endif
  11. #include "cJSON.h"
  12. #include "civetweb.h"
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #ifdef NO_SSL
  17. # define PORT "8089"
  18. # define HOST_INFO "http://localhost:8089"
  19. #else
  20. # define PORT "8089r,8843s"
  21. # define HOST_INFO "https://localhost:8843"
  22. #endif
  23. #define EXAMPLE_URI "/example"
  24. #define EXIT_URI "/exit"
  25. int exitNow = 0;
  26. static int
  27. SendJSON(struct mg_connection *conn, cJSON *json_obj)
  28. {
  29. char *json_str = cJSON_PrintUnformatted(json_obj);
  30. size_t json_str_len = strlen(json_str);
  31. /* Send HTTP message header */
  32. mg_send_http_ok(conn, "application/json; charset=utf-8", json_str_len);
  33. /* Send HTTP message content */
  34. mg_write(conn, json_str, json_str_len);
  35. /* Free string allocated by cJSON_Print* */
  36. cJSON_free(json_str);
  37. return (int)json_str_len;
  38. }
  39. static unsigned request = 0; /* demo data: request counter */
  40. static int
  41. ExampleGET(struct mg_connection *conn)
  42. {
  43. cJSON *obj = cJSON_CreateObject();
  44. if (!obj) {
  45. /* insufficient memory? */
  46. mg_send_http_error(conn, 500, "Server error");
  47. return 500;
  48. }
  49. cJSON_AddStringToObject(obj, "version", CIVETWEB_VERSION);
  50. cJSON_AddNumberToObject(obj, "request", ++request);
  51. SendJSON(conn, obj);
  52. cJSON_Delete(obj);
  53. return 200;
  54. }
  55. static int
  56. ExampleDELETE(struct mg_connection *conn)
  57. {
  58. request = 0;
  59. mg_send_http_error(conn,
  60. 204,
  61. "%s",
  62. ""); /* Return "deleted" = "204 No Content" */
  63. return 204;
  64. }
  65. static int
  66. ExamplePUT(struct mg_connection *conn)
  67. {
  68. char buffer[1024];
  69. int dlen = mg_read(conn, buffer, sizeof(buffer) - 1);
  70. cJSON *obj, *elem;
  71. unsigned newvalue;
  72. if ((dlen < 1) || (dlen >= sizeof(buffer))) {
  73. mg_send_http_error(conn, 400, "%s", "No request body data");
  74. return 400;
  75. }
  76. buffer[dlen] = 0;
  77. obj = cJSON_Parse(buffer);
  78. if (obj == NULL) {
  79. mg_send_http_error(conn, 400, "%s", "Invalid request body data");
  80. return 400;
  81. }
  82. elem = cJSON_GetObjectItemCaseSensitive(obj, "request");
  83. if (!cJSON_IsNumber(elem)) {
  84. cJSON_Delete(obj);
  85. mg_send_http_error(conn,
  86. 400,
  87. "%s",
  88. "No \"request\" number in body data");
  89. return 400;
  90. }
  91. newvalue = (unsigned)elem->valuedouble;
  92. if ((double)newvalue != elem->valuedouble) {
  93. cJSON_Delete(obj);
  94. mg_send_http_error(conn,
  95. 400,
  96. "%s",
  97. "Invalid \"request\" number in body data");
  98. return 400;
  99. }
  100. request = newvalue;
  101. cJSON_Delete(obj);
  102. mg_send_http_error(conn, 201, "%s", ""); /* Return "201 Created" */
  103. return 201;
  104. }
  105. static int
  106. ExamplePOST(struct mg_connection *conn)
  107. {
  108. /* In this example, do the same for PUT and POST */
  109. return ExamplePUT(conn);
  110. }
  111. static int
  112. ExamplePATCH(struct mg_connection *conn)
  113. {
  114. /* In this example, do the same for PUT and PATCH */
  115. return ExamplePUT(conn);
  116. }
  117. static int
  118. ExampleHandler(struct mg_connection *conn, void *cbdata)
  119. {
  120. const struct mg_request_info *ri = mg_get_request_info(conn);
  121. (void)cbdata; /* currently unused */
  122. if (0 == strcmp(ri->request_method, "GET")) {
  123. return ExampleGET(conn);
  124. }
  125. if (0 == strcmp(ri->request_method, "PUT")) {
  126. return ExamplePUT(conn);
  127. }
  128. if (0 == strcmp(ri->request_method, "POST")) {
  129. return ExamplePOST(conn);
  130. }
  131. if (0 == strcmp(ri->request_method, "DELETE")) {
  132. return ExampleDELETE(conn);
  133. }
  134. if (0 == strcmp(ri->request_method, "PATCH")) {
  135. return ExamplePATCH(conn);
  136. }
  137. /* this is not a GET request */
  138. mg_send_http_error(
  139. conn, 405, "Only GET, PUT, POST, DELETE and PATCH method supported");
  140. return 405;
  141. }
  142. int
  143. ExitHandler(struct mg_connection *conn, void *cbdata)
  144. {
  145. mg_printf(conn,
  146. "HTTP/1.1 200 OK\r\nContent-Type: "
  147. "text/plain\r\nConnection: close\r\n\r\n");
  148. mg_printf(conn, "Server will shut down.\n");
  149. mg_printf(conn, "Bye!\n");
  150. exitNow = 1;
  151. return 1;
  152. }
  153. int
  154. log_message(const struct mg_connection *conn, const char *message)
  155. {
  156. puts(message);
  157. return 1;
  158. }
  159. int
  160. main(int argc, char *argv[])
  161. {
  162. const char *options[] = {"listening_ports",
  163. PORT,
  164. "request_timeout_ms",
  165. "10000",
  166. "error_log_file",
  167. "error.log",
  168. #ifndef NO_SSL
  169. "ssl_certificate",
  170. "../../resources/cert/server.pem",
  171. "ssl_protocol_version",
  172. "3",
  173. "ssl_cipher_list",
  174. "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
  175. #endif
  176. "enable_auth_domain_check",
  177. "no",
  178. 0};
  179. struct mg_callbacks callbacks;
  180. struct mg_context *ctx;
  181. int err = 0;
  182. /* Check if libcivetweb has been built with all required features. */
  183. #ifndef NO_SSL
  184. if (!mg_check_feature(2)) {
  185. fprintf(stderr,
  186. "Error: Embedded example built with SSL support, "
  187. "but civetweb library build without.\n");
  188. err = 1;
  189. }
  190. mg_init_library(MG_FEATURES_SSL);
  191. #else
  192. mg_init_library(0);
  193. #endif
  194. if (err) {
  195. fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");
  196. return EXIT_FAILURE;
  197. }
  198. /* Callback will print error messages to console */
  199. memset(&callbacks, 0, sizeof(callbacks));
  200. callbacks.log_message = log_message;
  201. /* Start CivetWeb web server */
  202. ctx = mg_start(&callbacks, 0, options);
  203. /* Check return value: */
  204. if (ctx == NULL) {
  205. fprintf(stderr, "Cannot start CivetWeb - mg_start failed.\n");
  206. return EXIT_FAILURE;
  207. }
  208. /* Add handler EXAMPLE_URI, to explain the example */
  209. mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
  210. mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
  211. /* Show sone info */
  212. printf("Start example: %s%s\n", HOST_INFO, EXAMPLE_URI);
  213. printf("Exit example: %s%s\n", HOST_INFO, EXIT_URI);
  214. /* Wait until the server should be closed */
  215. while (!exitNow) {
  216. #ifdef _WIN32
  217. Sleep(1000);
  218. #else
  219. sleep(1);
  220. #endif
  221. }
  222. /* Stop the server */
  223. mg_stop(ctx);
  224. printf("Server stopped.\n");
  225. printf("Bye!\n");
  226. return EXIT_SUCCESS;
  227. }