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