rest.c 5.4 KB

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