rest.c 6.4 KB

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