1 /* Copyright (c) 2013-2018 the Civetweb developers
2 * Copyright (c) 2013 No Face Press, LLC
3 * License http://opensource.org/licenses/mit-license.php MIT License
4 */
5
6 // Simple example program on how to use Embedded C++ interface.
7
8 #include "CivetServer.h"
9 #include <cstring>
10
11 #ifdef _WIN32
12 #include <windows.h>
13 #else
14 #include <unistd.h>
15 #endif
16
17 #define DOCUMENT_ROOT "."
18 #define PORT "8081"
19 #define EXAMPLE_URI "/example"
20 #define EXIT_URI "/exit"
21
22
23 /* Exit flag for main loop */
24 volatile bool exitNow = false;
25
26
27 class ExampleHandler : public CivetHandler
28 {
29 public:
30 bool
handleGet(CivetServer * server,struct mg_connection * conn)31 handleGet(CivetServer *server, struct mg_connection *conn)
32 {
33 mg_printf(conn,
34 "HTTP/1.1 200 OK\r\nContent-Type: "
35 "text/html\r\nConnection: close\r\n\r\n");
36 mg_printf(conn, "<html><body>\r\n");
37 mg_printf(conn,
38 "<h2>This is an example text from a C++ handler</h2>\r\n");
39 mg_printf(conn,
40 "<p>To see a page from the A handler <a "
41 "href=\"a\">click here</a></p>\r\n");
42 mg_printf(conn,
43 "<form action=\"a\" method=\"get\">"
44 "To see a page from the A handler with a parameter "
45 "<input type=\"submit\" value=\"click here\" "
46 "name=\"param\" \\> (GET)</form>\r\n");
47 mg_printf(conn,
48 "<form action=\"a\" method=\"post\">"
49 "To see a page from the A handler with a parameter "
50 "<input type=\"submit\" value=\"click here\" "
51 "name=\"param\" \\> (POST)</form>\r\n");
52 mg_printf(conn,
53 "<p>To see a page from the A/B handler <a "
54 "href=\"a/b\">click here</a></p>\r\n");
55 mg_printf(conn,
56 "<p>To see a page from the *.foo handler <a "
57 "href=\"xy.foo\">click here</a></p>\r\n");
58 mg_printf(conn,
59 "<p>To see a page from the WebSocket handler <a "
60 "href=\"ws\">click here</a></p>\r\n");
61 mg_printf(conn,
62 "<p>To exit <a href=\"%s\">click here</a></p>\r\n",
63 EXIT_URI);
64 mg_printf(conn, "</body></html>\r\n");
65 return true;
66 }
67 };
68
69 class ExitHandler : public CivetHandler
70 {
71 public:
72 bool
handleGet(CivetServer * server,struct mg_connection * conn)73 handleGet(CivetServer *server, struct mg_connection *conn)
74 {
75 mg_printf(conn,
76 "HTTP/1.1 200 OK\r\nContent-Type: "
77 "text/plain\r\nConnection: close\r\n\r\n");
78 mg_printf(conn, "Bye!\n");
79 exitNow = true;
80 return true;
81 }
82 };
83
84 class AHandler : public CivetHandler
85 {
86 private:
87 bool
handleAll(const char * method,CivetServer * server,struct mg_connection * conn)88 handleAll(const char *method,
89 CivetServer *server,
90 struct mg_connection *conn)
91 {
92 std::string s = "";
93 mg_printf(conn,
94 "HTTP/1.1 200 OK\r\nContent-Type: "
95 "text/html\r\nConnection: close\r\n\r\n");
96 mg_printf(conn, "<html><body>");
97 mg_printf(conn, "<h2>This is the A handler for \"%s\" !</h2>", method);
98 if (CivetServer::getParam(conn, "param", s)) {
99 mg_printf(conn, "<p>param set to %s</p>", s.c_str());
100 } else {
101 mg_printf(conn, "<p>param not set</p>");
102 }
103 mg_printf(conn, "</body></html>\n");
104 return true;
105 }
106
107 public:
108 bool
handleGet(CivetServer * server,struct mg_connection * conn)109 handleGet(CivetServer *server, struct mg_connection *conn)
110 {
111 return handleAll("GET", server, conn);
112 }
113 bool
handlePost(CivetServer * server,struct mg_connection * conn)114 handlePost(CivetServer *server, struct mg_connection *conn)
115 {
116 return handleAll("POST", server, conn);
117 }
118 };
119
120 class ABHandler : public CivetHandler
121 {
122 public:
123 bool
handleGet(CivetServer * server,struct mg_connection * conn)124 handleGet(CivetServer *server, struct mg_connection *conn)
125 {
126 mg_printf(conn,
127 "HTTP/1.1 200 OK\r\nContent-Type: "
128 "text/html\r\nConnection: close\r\n\r\n");
129 mg_printf(conn, "<html><body>");
130 mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
131 mg_printf(conn, "</body></html>\n");
132 return true;
133 }
134 };
135
136 class FooHandler : public CivetHandler
137 {
138 public:
139 bool
handleGet(CivetServer * server,struct mg_connection * conn)140 handleGet(CivetServer *server, struct mg_connection *conn)
141 {
142 /* Handler may access the request info using mg_get_request_info */
143 const struct mg_request_info *req_info = mg_get_request_info(conn);
144
145 mg_printf(conn,
146 "HTTP/1.1 200 OK\r\nContent-Type: "
147 "text/html\r\nConnection: close\r\n\r\n");
148
149 mg_printf(conn, "<html><body>\n");
150 mg_printf(conn, "<h2>This is the Foo GET handler!!!</h2>\n");
151 mg_printf(conn,
152 "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
153 req_info->request_method,
154 req_info->request_uri,
155 req_info->http_version);
156 mg_printf(conn, "</body></html>\n");
157
158 return true;
159 }
160 bool
handlePost(CivetServer * server,struct mg_connection * conn)161 handlePost(CivetServer *server, struct mg_connection *conn)
162 {
163 /* Handler may access the request info using mg_get_request_info */
164 const struct mg_request_info *req_info = mg_get_request_info(conn);
165 long long rlen, wlen;
166 long long nlen = 0;
167 long long tlen = req_info->content_length;
168 char buf[1024];
169
170 mg_printf(conn,
171 "HTTP/1.1 200 OK\r\nContent-Type: "
172 "text/html\r\nConnection: close\r\n\r\n");
173
174 mg_printf(conn, "<html><body>\n");
175 mg_printf(conn, "<h2>This is the Foo POST handler!!!</h2>\n");
176 mg_printf(conn,
177 "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
178 req_info->request_method,
179 req_info->request_uri,
180 req_info->http_version);
181 mg_printf(conn, "<p>Content Length: %li</p>\n", (long)tlen);
182 mg_printf(conn, "<pre>\n");
183
184 while (nlen < tlen) {
185 rlen = tlen - nlen;
186 if (rlen > sizeof(buf)) {
187 rlen = sizeof(buf);
188 }
189 rlen = mg_read(conn, buf, (size_t)rlen);
190 if (rlen <= 0) {
191 break;
192 }
193 wlen = mg_write(conn, buf, (size_t)rlen);
194 if (wlen != rlen) {
195 break;
196 }
197 nlen += wlen;
198 }
199
200 mg_printf(conn, "\n</pre>\n");
201 mg_printf(conn, "</body></html>\n");
202
203 return true;
204 }
205
206 #define fopen_recursive fopen
207
208 bool
handlePut(CivetServer * server,struct mg_connection * conn)209 handlePut(CivetServer *server, struct mg_connection *conn)
210 {
211 /* Handler may access the request info using mg_get_request_info */
212 const struct mg_request_info *req_info = mg_get_request_info(conn);
213 long long rlen, wlen;
214 long long nlen = 0;
215 long long tlen = req_info->content_length;
216 FILE * f;
217 char buf[1024];
218 int fail = 0;
219
220 #ifdef _WIN32
221 _snprintf(buf, sizeof(buf), "D:\\somewhere\\%s\\%s", req_info->remote_user, req_info->local_uri);
222 buf[sizeof(buf)-1] = 0;
223 if (strlen(buf)>255) {
224 /* Windows will not work with path > 260 (MAX_PATH), unless we use
225 * the unicode API. However, this is just an example code: A real
226 * code will probably never store anything to D:\\somewhere and
227 * must be adapted to the specific needs anyhow. */
228 fail = 1;
229 f = NULL;
230 } else {
231 f = fopen_recursive(buf, "wb");
232 }
233 #else
234 snprintf(buf, sizeof(buf), "~/somewhere/%s/%s", req_info->remote_user, req_info->local_uri);
235 buf[sizeof(buf)-1] = 0;
236 if (strlen(buf)>1020) {
237 /* The string is too long and probably truncated. Make sure an
238 * UTF-8 string is never truncated between the UTF-8 code bytes.
239 * This example code must be adapted to the specific needs. */
240 fail = 1;
241 f = NULL;
242 } else {
243 f = fopen_recursive(buf, "w");
244 }
245 #endif
246
247 if (!f) {
248 fail = 1;
249 } else {
250 while (nlen < tlen) {
251 rlen = tlen - nlen;
252 if (rlen > sizeof(buf)) {
253 rlen = sizeof(buf);
254 }
255 rlen = mg_read(conn, buf, (size_t)rlen);
256 if (rlen <= 0) {
257 fail = 1;
258 break;
259 }
260 wlen = fwrite(buf, 1, (size_t)rlen, f);
261 if (wlen != rlen) {
262 fail = 1;
263 break;
264 }
265 nlen += wlen;
266 }
267 fclose(f);
268 }
269
270 if (fail) {
271 mg_printf(conn,
272 "HTTP/1.1 409 Conflict\r\n"
273 "Content-Type: text/plain\r\n"
274 "Connection: close\r\n\r\n");
275 } else {
276 mg_printf(conn,
277 "HTTP/1.1 201 Created\r\n"
278 "Content-Type: text/plain\r\n"
279 "Connection: close\r\n\r\n");
280 }
281
282 return true;
283 }
284 };
285
286 class WsStartHandler : public CivetHandler
287 {
288 public:
289 bool
handleGet(CivetServer * server,struct mg_connection * conn)290 handleGet(CivetServer *server, struct mg_connection *conn)
291 {
292
293 mg_printf(conn,
294 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
295 "close\r\n\r\n");
296
297 mg_printf(conn, "<!DOCTYPE html>\n");
298 mg_printf(conn, "<html>\n<head>\n");
299 mg_printf(conn, "<meta charset=\"UTF-8\">\n");
300 mg_printf(conn, "<title>Embedded websocket example</title>\n");
301
302 #ifdef USE_WEBSOCKET
303 /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
304 * xhtml style */
305 mg_printf(conn, "<script>\n");
306 mg_printf(
307 conn,
308 "var i=0\n"
309 "function load() {\n"
310 " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
311 " connection = new WebSocket(wsproto + '//' + window.location.host + "
312 "'/websocket');\n"
313 " websock_text_field = "
314 "document.getElementById('websock_text_field');\n"
315 " connection.onmessage = function (e) {\n"
316 " websock_text_field.innerHTML=e.data;\n"
317 " i=i+1;"
318 " connection.send(i);\n"
319 " }\n"
320 " connection.onerror = function (error) {\n"
321 " alert('WebSocket error');\n"
322 " connection.close();\n"
323 " }\n"
324 "}\n");
325 /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
326 mg_printf(conn, "</script>\n");
327 mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
328 mg_printf(
329 conn,
330 "<div id='websock_text_field'>No websocket connection yet</div>\n");
331 #else
332 mg_printf(conn, "</head>\n<body>\n");
333 mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
334 #endif
335 mg_printf(conn, "</body>\n</html>\n");
336
337 return 1;
338 }
339 };
340
341
342 #ifdef USE_WEBSOCKET
343 class WebSocketHandler : public CivetWebSocketHandler {
344
handleConnection(CivetServer * server,const struct mg_connection * conn)345 virtual bool handleConnection(CivetServer *server,
346 const struct mg_connection *conn) {
347 printf("WS connected\n");
348 return true;
349 }
350
handleReadyState(CivetServer * server,struct mg_connection * conn)351 virtual void handleReadyState(CivetServer *server,
352 struct mg_connection *conn) {
353 printf("WS ready\n");
354
355 const char *text = "Hello from the websocket ready handler";
356 mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, text, strlen(text));
357 }
358
handleData(CivetServer * server,struct mg_connection * conn,int bits,char * data,size_t data_len)359 virtual bool handleData(CivetServer *server,
360 struct mg_connection *conn,
361 int bits,
362 char *data,
363 size_t data_len) {
364 printf("WS got %lu bytes: ", (long unsigned)data_len);
365 fwrite(data, 1, data_len, stdout);
366 printf("\n");
367
368 mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, data, data_len);
369 return (data_len<4);
370 }
371
handleClose(CivetServer * server,const struct mg_connection * conn)372 virtual void handleClose(CivetServer *server,
373 const struct mg_connection *conn) {
374 printf("WS closed\n");
375 }
376 };
377 #endif
378
379
380 int
main(int argc,char * argv[])381 main(int argc, char *argv[])
382 {
383 const char *options[] = {
384 "document_root", DOCUMENT_ROOT, "listening_ports", PORT, 0};
385
386 std::vector<std::string> cpp_options;
387 for (int i=0; i<(sizeof(options)/sizeof(options[0])-1); i++) {
388 cpp_options.push_back(options[i]);
389 }
390
391 // CivetServer server(options); // <-- C style start
392 CivetServer server(cpp_options); // <-- C++ style start
393
394 ExampleHandler h_ex;
395 server.addHandler(EXAMPLE_URI, h_ex);
396
397 ExitHandler h_exit;
398 server.addHandler(EXIT_URI, h_exit);
399
400 AHandler h_a;
401 server.addHandler("/a", h_a);
402
403 ABHandler h_ab;
404 server.addHandler("/a/b", h_ab);
405
406 WsStartHandler h_ws;
407 server.addHandler("/ws", h_ws);
408
409 #ifdef NO_FILES
410 /* This handler will handle "everything else", including
411 * requests to files. If this handler is installed,
412 * NO_FILES should be set. */
413 FooHandler h_foo;
414 server.addHandler("", h_foo);
415
416 printf("See a page from the \"all\" handler at http://localhost:%s/\n", PORT);
417 #else
418 FooHandler h_foo;
419 server.addHandler("**.foo", h_foo);
420 printf("Browse files at http://localhost:%s/\n", PORT);
421 #endif
422
423 #ifdef USE_WEBSOCKET
424 WebSocketHandler h_websocket;
425 server.addWebSocketHandler("/websocket", h_websocket);
426 printf("Run websocket example at http://localhost:%s/ws\n", PORT);
427 #endif
428
429 printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
430 printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);
431
432 while (!exitNow) {
433 #ifdef _WIN32
434 Sleep(1000);
435 #else
436 sleep(1);
437 #endif
438 }
439
440 printf("Bye!\n");
441
442 return 0;
443 }
444