1 /*
2  * Copyright (c) 2013-2017 the CivetWeb developers
3  * Copyright (c) 2013 No Face Press, LLC
4  * License http://opensource.org/licenses/mit-license.php MIT License
5  */
6 
7 #ifdef NO_SSL
8 #define TEST_WITHOUT_SSL
9 #endif
10 
11 /* Simple example program on how to use CivetWeb embedded into a C program. */
12 #ifdef _WIN32
13 #include <windows.h>
14 #else
15 #include <unistd.h>
16 #endif
17 
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 
22 #include "civetweb.h"
23 
24 
25 #define DOCUMENT_ROOT "."
26 #ifdef TEST_WITHOUT_SSL
27 
28 #ifdef USE_IPV6
29 #define PORT "[::]:8888,8884"
30 #else
31 #define PORT "8888,8884"
32 #endif
33 
34 #else
35 
36 #ifdef USE_IPV6
37 #define PORT "[::]:8888r,[::]:8843s,8884"
38 #else
39 #define PORT "8888r,8843s,8884"
40 #endif
41 
42 #endif
43 
44 
45 #define EXAMPLE_URI "/example"
46 #define EXIT_URI "/exit"
47 int exitNow = 0;
48 
49 
50 int
ExampleHandler(struct mg_connection * conn,void * cbdata)51 ExampleHandler(struct mg_connection *conn, void *cbdata)
52 {
53 	mg_printf(conn,
54 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
55 	          "close\r\n\r\n");
56 	mg_printf(conn, "<html><body>");
57 	mg_printf(conn, "<h2>This is an example text from a C handler</h2>");
58 	mg_printf(
59 	    conn,
60 	    "<p>To see a page from the A handler <a href=\"A\">click A</a></p>");
61 	mg_printf(conn,
62 	          "<p>To see a page from the A handler <a href=\"A/A\">click "
63 	          "A/A</a></p>");
64 	mg_printf(conn,
65 	          "<p>To see a page from the A/B handler <a "
66 	          "href=\"A/B\">click A/B</a></p>");
67 	mg_printf(conn,
68 	          "<p>To see a page from the B handler (0) <a "
69 	          "href=\"B\">click B</a></p>");
70 	mg_printf(conn,
71 	          "<p>To see a page from the B handler (1) <a "
72 	          "href=\"B/A\">click B/A</a></p>");
73 	mg_printf(conn,
74 	          "<p>To see a page from the B handler (2) <a "
75 	          "href=\"B/B\">click B/B</a></p>");
76 	mg_printf(conn,
77 	          "<p>To see a page from the *.foo handler <a "
78 	          "href=\"xy.foo\">click xy.foo</a></p>");
79 	mg_printf(conn,
80 	          "<p>To see a page from the close handler <a "
81 	          "href=\"close\">click close</a></p>");
82 	mg_printf(conn,
83 	          "<p>To see a page from the FileHandler handler <a "
84 	          "href=\"form\">click form</a> (the starting point of the "
85 	          "<b>form</b> test)</p>");
86 	mg_printf(conn,
87 	          "<p>To see a page from the CookieHandler handler <a "
88 	          "href=\"cookie\">click cookie</a></p>");
89 	mg_printf(conn,
90 	          "<p>To see a page from the PostResponser handler <a "
91 	          "href=\"postresponse\">click post response</a></p>");
92 	mg_printf(conn,
93 	          "<p>To see an example for parsing files on the fly <a "
94 	          "href=\"on_the_fly_form\">click form</a> (form for "
95 	          "uploading files)</p>");
96 
97 #ifdef USE_WEBSOCKET
98 	mg_printf(conn,
99 	          "<p>To test the websocket handler <a href=\"/websocket\">click "
100 	          "websocket</a></p>");
101 #endif
102 
103 	mg_printf(conn,
104 	          "<p>To test the authentication handler <a href=\"/auth\">click "
105 	          "auth</a></p>");
106 
107 	mg_printf(conn, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI);
108 	mg_printf(conn, "</body></html>\n");
109 	return 1;
110 }
111 
112 
113 int
ExitHandler(struct mg_connection * conn,void * cbdata)114 ExitHandler(struct mg_connection *conn, void *cbdata)
115 {
116 	mg_printf(conn,
117 	          "HTTP/1.1 200 OK\r\nContent-Type: "
118 	          "text/plain\r\nConnection: close\r\n\r\n");
119 	mg_printf(conn, "Server will shut down.\n");
120 	mg_printf(conn, "Bye!\n");
121 	exitNow = 1;
122 	return 1;
123 }
124 
125 
126 int
AHandler(struct mg_connection * conn,void * cbdata)127 AHandler(struct mg_connection *conn, void *cbdata)
128 {
129 	mg_printf(conn,
130 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
131 	          "close\r\n\r\n");
132 	mg_printf(conn, "<html><body>");
133 	mg_printf(conn, "<h2>This is the A handler!!!</h2>");
134 	mg_printf(conn, "</body></html>\n");
135 	return 1;
136 }
137 
138 
139 int
ABHandler(struct mg_connection * conn,void * cbdata)140 ABHandler(struct mg_connection *conn, void *cbdata)
141 {
142 	mg_printf(conn,
143 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
144 	          "close\r\n\r\n");
145 	mg_printf(conn, "<html><body>");
146 	mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
147 	mg_printf(conn, "</body></html>\n");
148 	return 1;
149 }
150 
151 
152 int
BXHandler(struct mg_connection * conn,void * cbdata)153 BXHandler(struct mg_connection *conn, void *cbdata)
154 {
155 	/* Handler may access the request info using mg_get_request_info */
156 	const struct mg_request_info *req_info = mg_get_request_info(conn);
157 
158 	mg_printf(conn,
159 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
160 	          "close\r\n\r\n");
161 	mg_printf(conn, "<html><body>");
162 	mg_printf(conn,
163 	          "<h2>This is the BX handler with argument %s.</h2>",
164 	          cbdata);
165 	mg_printf(conn, "<p>The actual uri is %s</p>", req_info->local_uri);
166 	mg_printf(conn, "</body></html>\n");
167 	return 1;
168 }
169 
170 
171 int
FooHandler(struct mg_connection * conn,void * cbdata)172 FooHandler(struct mg_connection *conn, void *cbdata)
173 {
174 	/* Handler may access the request info using mg_get_request_info */
175 	const struct mg_request_info *req_info = mg_get_request_info(conn);
176 
177 	mg_printf(conn,
178 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
179 	          "close\r\n\r\n");
180 	mg_printf(conn, "<html><body>");
181 	mg_printf(conn, "<h2>This is the Foo handler!!!</h2>");
182 	mg_printf(conn,
183 	          "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",
184 	          req_info->request_method,
185 	          req_info->local_uri,
186 	          req_info->http_version);
187 	mg_printf(conn, "</body></html>\n");
188 	return 1;
189 }
190 
191 
192 int
CloseHandler(struct mg_connection * conn,void * cbdata)193 CloseHandler(struct mg_connection *conn, void *cbdata)
194 {
195 	/* Handler may access the request info using mg_get_request_info */
196 	const struct mg_request_info *req_info = mg_get_request_info(conn);
197 
198 	mg_printf(conn,
199 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
200 	          "close\r\n\r\n");
201 	mg_printf(conn, "<html><body>");
202 	mg_printf(conn,
203 	          "<h2>This handler will close the connection in a second</h2>");
204 #ifdef _WIN32
205 	Sleep(1000);
206 #else
207 	sleep(1);
208 #endif
209 	mg_printf(conn, "bye");
210 	printf("CloseHandler: close connection\n");
211 	mg_close_connection(conn);
212 	printf("CloseHandler: wait 10 sec\n");
213 #ifdef _WIN32
214 	Sleep(10000);
215 #else
216 	sleep(10);
217 #endif
218 	printf("CloseHandler: return from function\n");
219 	return 1;
220 }
221 
222 
223 #if !defined(NO_FILESYSTEMS)
224 int
FileHandler(struct mg_connection * conn,void * cbdata)225 FileHandler(struct mg_connection *conn, void *cbdata)
226 {
227 	/* In this handler, we ignore the req_info and send the file "fileName". */
228 	const char *fileName = (const char *)cbdata;
229 
230 	mg_send_file(conn, fileName);
231 	return 1;
232 }
233 #endif /* NO_FILESYSTEMS */
234 
235 
236 #define MD5_STATIC static
237 #include "../src/md5.inl"
238 
239 /* Stringify binary data. Output buffer must be twice as big as input,
240  * because each byte takes 2 bytes in string representation */
241 static void
bin2str(char * to,const unsigned char * p,size_t len)242 bin2str(char *to, const unsigned char *p, size_t len)
243 {
244 	static const char *hex = "0123456789abcdef";
245 
246 	for (; len--; p++) {
247 		*to++ = hex[p[0] >> 4];
248 		*to++ = hex[p[0] & 0x0f];
249 	}
250 	*to = '\0';
251 }
252 
253 
254 int
field_found(const char * key,const char * filename,char * path,size_t pathlen,void * user_data)255 field_found(const char *key,
256             const char *filename,
257             char *path,
258             size_t pathlen,
259             void *user_data)
260 {
261 	struct mg_connection *conn = (struct mg_connection *)user_data;
262 
263 	mg_printf(conn, "\r\n\r\n%s:\r\n", key);
264 
265 	if (filename && *filename) {
266 #ifdef _WIN32
267 		_snprintf(path, pathlen, "D:\\tmp\\%s", filename);
268 #else
269 		snprintf(path, pathlen, "/tmp/%s", filename);
270 #endif
271 		return MG_FORM_FIELD_STORAGE_GET;
272 	}
273 	return MG_FORM_FIELD_STORAGE_GET;
274 }
275 
276 
277 int
field_get(const char * key,const char * value,size_t valuelen,void * user_data)278 field_get(const char *key, const char *value, size_t valuelen, void *user_data)
279 {
280 	struct mg_connection *conn = (struct mg_connection *)user_data;
281 
282 	if ((key != NULL) && (key[0] == '\0')) {
283 		/* Incorrect form data detected */
284 		return MG_FORM_FIELD_HANDLE_ABORT;
285 	}
286 	if ((valuelen > 0) && (value == NULL)) {
287 		/* Unreachable, since this call will not be generated by civetweb. */
288 		return MG_FORM_FIELD_HANDLE_ABORT;
289 	}
290 
291 	if (key) {
292 		mg_printf(conn, "key = %s\n", key);
293 	}
294 	mg_printf(conn, "valuelen = %u\n", valuelen);
295 
296 	if (valuelen > 0) {
297 		/* mg_write(conn, value, valuelen); */
298 
299 		md5_byte_t hash[16];
300 		md5_state_t ctx;
301 		char outputbuf[33];
302 
303 		md5_init(&ctx);
304 		md5_append(&ctx, (const md5_byte_t *)value, valuelen);
305 		md5_finish(&ctx, hash);
306 		bin2str(outputbuf, hash, sizeof(hash));
307 		mg_printf(conn, "value md5 hash = %s\n", outputbuf);
308 	}
309 
310 #if 0 /* for debugging */
311 	if (!strcmp(key, "File")) {
312 		FILE *f = fopen("test.txt", "wb");
313 		if (f) {
314 			fwrite(value, 1, valuelen, f);
315 			fclose(f);
316 		}
317 	}
318 #endif
319 
320 	return 0;
321 }
322 
323 
324 int
field_stored(const char * path,long long file_size,void * user_data)325 field_stored(const char *path, long long file_size, void *user_data)
326 {
327 	struct mg_connection *conn = (struct mg_connection *)user_data;
328 
329 	mg_printf(conn,
330 	          "stored as %s (%lu bytes)\r\n\r\n",
331 	          path,
332 	          (unsigned long)file_size);
333 
334 	return 0;
335 }
336 
337 
338 int
FormHandler(struct mg_connection * conn,void * cbdata)339 FormHandler(struct mg_connection *conn, void *cbdata)
340 {
341 	/* Handler may access the request info using mg_get_request_info */
342 	const struct mg_request_info *req_info = mg_get_request_info(conn);
343 	int ret;
344 	struct mg_form_data_handler fdh = {field_found, field_get, field_stored, 0};
345 
346 	/* It would be possible to check the request info here before calling
347 	 * mg_handle_form_request. */
348 	(void)req_info;
349 
350 	mg_printf(conn,
351 	          "HTTP/1.1 200 OK\r\nContent-Type: "
352 	          "text/plain\r\nConnection: close\r\n\r\n");
353 	fdh.user_data = (void *)conn;
354 
355 	/* Call the form handler */
356 	mg_printf(conn, "Form data:");
357 	ret = mg_handle_form_request(conn, &fdh);
358 	mg_printf(conn, "\r\n%i fields found", ret);
359 
360 	return 1;
361 }
362 
363 
364 int
FileUploadForm(struct mg_connection * conn,void * cbdata)365 FileUploadForm(struct mg_connection *conn, void *cbdata)
366 {
367 	mg_printf(conn,
368 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
369 	          "close\r\n\r\n");
370 
371 	mg_printf(conn, "<!DOCTYPE html>\n");
372 	mg_printf(conn, "<html>\n<head>\n");
373 	mg_printf(conn, "<meta charset=\"UTF-8\">\n");
374 	mg_printf(conn, "<title>File upload</title>\n");
375 	mg_printf(conn, "</head>\n<body>\n");
376 	mg_printf(conn,
377 	          "<form action=\"%s\" method=\"POST\" "
378 	          "enctype=\"multipart/form-data\">\n",
379 	          (const char *)cbdata);
380 	mg_printf(conn, "<input type=\"file\" name=\"filesin\" multiple>\n");
381 	mg_printf(conn, "<input type=\"submit\" value=\"Submit\">\n");
382 	mg_printf(conn, "</form>\n</body>\n</html>\n");
383 	return 1;
384 }
385 
386 
387 struct tfile_checksum {
388 	char name[128];
389 	unsigned long long length;
390 	md5_state_t chksum;
391 };
392 
393 #define MAX_FILES (10)
394 
395 struct tfiles_checksums {
396 	int index;
397 	struct tfile_checksum file[MAX_FILES];
398 };
399 
400 
401 int
field_disp_read_on_the_fly(const char * key,const char * filename,char * path,size_t pathlen,void * user_data)402 field_disp_read_on_the_fly(const char *key,
403                            const char *filename,
404                            char *path,
405                            size_t pathlen,
406                            void *user_data)
407 {
408 	struct tfiles_checksums *context = (struct tfiles_checksums *)user_data;
409 
410 	(void)key;
411 	(void)path;
412 	(void)pathlen;
413 
414 	if (context->index < MAX_FILES) {
415 		context->index++;
416 		strncpy(context->file[context->index - 1].name, filename, 128);
417 		context->file[context->index - 1].name[127] = 0;
418 		context->file[context->index - 1].length = 0;
419 		md5_init(&(context->file[context->index - 1].chksum));
420 		return MG_FORM_FIELD_STORAGE_GET;
421 	}
422 	return MG_FORM_FIELD_STORAGE_ABORT;
423 }
424 
425 
426 int
field_get_checksum(const char * key,const char * value,size_t valuelen,void * user_data)427 field_get_checksum(const char *key,
428                    const char *value,
429                    size_t valuelen,
430                    void *user_data)
431 {
432 	struct tfiles_checksums *context = (struct tfiles_checksums *)user_data;
433 	(void)key;
434 
435 	context->file[context->index - 1].length += valuelen;
436 	md5_append(&(context->file[context->index - 1].chksum),
437 	           (const md5_byte_t *)value,
438 	           valuelen);
439 
440 	return 0;
441 }
442 
443 
444 int
CheckSumHandler(struct mg_connection * conn,void * cbdata)445 CheckSumHandler(struct mg_connection *conn, void *cbdata)
446 {
447 	/* Handler may access the request info using mg_get_request_info */
448 	const struct mg_request_info *req_info = mg_get_request_info(conn);
449 	int i, j, ret;
450 	struct tfiles_checksums chksums;
451 	md5_byte_t digest[16];
452 	struct mg_form_data_handler fdh = {field_disp_read_on_the_fly,
453 	                                   field_get_checksum,
454 	                                   0,
455 	                                   (void *)&chksums};
456 
457 	/* It would be possible to check the request info here before calling
458 	 * mg_handle_form_request. */
459 	(void)req_info;
460 
461 	memset(&chksums, 0, sizeof(chksums));
462 
463 	mg_printf(conn,
464 	          "HTTP/1.1 200 OK\r\n"
465 	          "Content-Type: text/plain\r\n"
466 	          "Connection: close\r\n\r\n");
467 
468 	/* Call the form handler */
469 	mg_printf(conn, "File checksums:");
470 	ret = mg_handle_form_request(conn, &fdh);
471 	for (i = 0; i < chksums.index; i++) {
472 		md5_finish(&(chksums.file[i].chksum), digest);
473 		/* Visual Studio 2010+ support llu */
474 		mg_printf(conn,
475 		          "\r\n%s %llu ",
476 		          chksums.file[i].name,
477 		          chksums.file[i].length);
478 		for (j = 0; j < 16; j++) {
479 			mg_printf(conn, "%02x", (unsigned int)digest[j]);
480 		}
481 	}
482 	mg_printf(conn, "\r\n%i files\r\n", ret);
483 
484 	return 1;
485 }
486 
487 
488 int
CookieHandler(struct mg_connection * conn,void * cbdata)489 CookieHandler(struct mg_connection *conn, void *cbdata)
490 {
491 	/* Handler may access the request info using mg_get_request_info */
492 	const struct mg_request_info *req_info = mg_get_request_info(conn);
493 	const char *cookie = mg_get_header(conn, "Cookie");
494 	char first_str[64], count_str[64];
495 	int count;
496 
497 	(void)mg_get_cookie(cookie, "first", first_str, sizeof(first_str));
498 	(void)mg_get_cookie(cookie, "count", count_str, sizeof(count_str));
499 
500 	mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close\r\n");
501 	if (first_str[0] == 0) {
502 		time_t t = time(0);
503 		struct tm *ptm = localtime(&t);
504 		mg_printf(conn,
505 		          "Set-Cookie: first=%04i-%02i-%02iT%02i:%02i:%02i\r\n",
506 		          ptm->tm_year + 1900,
507 		          ptm->tm_mon + 1,
508 		          ptm->tm_mday,
509 		          ptm->tm_hour,
510 		          ptm->tm_min,
511 		          ptm->tm_sec);
512 	}
513 	count = (count_str[0] == 0) ? 0 : atoi(count_str);
514 	mg_printf(conn, "Set-Cookie: count=%i\r\n", count + 1);
515 	mg_printf(conn, "Content-Type: text/html\r\n\r\n");
516 
517 	mg_printf(conn, "<html><body>");
518 	mg_printf(conn, "<h2>This is the CookieHandler.</h2>");
519 	mg_printf(conn, "<p>The actual uri is %s</p>", req_info->local_uri);
520 
521 	if (first_str[0] == 0) {
522 		mg_printf(conn, "<p>This is the first time, you opened this page</p>");
523 	} else {
524 		mg_printf(conn, "<p>You opened this page %i times before.</p>", count);
525 		mg_printf(conn, "<p>You first opened this page on %s.</p>", first_str);
526 	}
527 
528 	mg_printf(conn, "</body></html>\n");
529 	return 1;
530 }
531 
532 
533 int
PostResponser(struct mg_connection * conn,void * cbdata)534 PostResponser(struct mg_connection *conn, void *cbdata)
535 {
536 	long long r_total = 0;
537 	int r, s;
538 
539 	char buf[2048];
540 
541 	const struct mg_request_info *ri = mg_get_request_info(conn);
542 
543 	if (0 != strcmp(ri->request_method, "POST")) {
544 		/* Not a POST request */
545 		char buf[1024];
546 		int ret = mg_get_request_link(conn, buf, sizeof(buf));
547 
548 		mg_printf(conn,
549 		          "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
550 		mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
551 		mg_printf(conn,
552 		          "%s method not allowed in the POST handler\n",
553 		          ri->request_method);
554 		if (ret >= 0) {
555 			mg_printf(conn,
556 			          "use a web tool to send a POST request to %s\n",
557 			          buf);
558 		}
559 		return 1;
560 	}
561 
562 	if (ri->content_length >= 0) {
563 		/* We know the content length in advance */
564 	} else {
565 		/* We must read until we find the end (chunked encoding
566 		 * or connection close), indicated my mg_read returning 0 */
567 	}
568 
569 	mg_printf(conn,
570 	          "HTTP/1.1 200 OK\r\nConnection: "
571 	          "close\r\nTransfer-Encoding: chunked\r\n");
572 	mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
573 
574 	r = mg_read(conn, buf, sizeof(buf));
575 	while (r > 0) {
576 		r_total += r;
577 		s = mg_send_chunk(conn, buf, r);
578 		if (r != s) {
579 			/* Send error */
580 			break;
581 		}
582 		r = mg_read(conn, buf, sizeof(buf));
583 	}
584 	mg_printf(conn, "0\r\n");
585 
586 	return 1;
587 }
588 
589 
590 #if !defined(NO_FILESYSTEMS)
591 int
AuthStartHandler(struct mg_connection * conn,void * cbdata)592 AuthStartHandler(struct mg_connection *conn, void *cbdata)
593 {
594 	static unsigned long long firstload = 0;
595 	const char *passfile = "password_example_file.txt";
596 	const char *realm = "password_example";
597 	const char *user = "user";
598 	char passwd[64];
599 
600 	if (firstload == 0) {
601 
602 		/* Set a random password (4 digit number - bad idea from a security
603 		 * point of view, but this is an API demo, not a security tutorial),
604 		 * and store it in some directory within the document root (extremely
605 		 * bad idea, but this is still not a security tutorial).
606 		 * The reason we create a new password every time the server starts
607 		 * is just for demonstration - we don't want the browser to store the
608 		 * password, so when we repeat the test we start with a new password.
609 		 */
610 		firstload = (unsigned long long)time(NULL);
611 		sprintf(passwd, "%04u", (unsigned int)(firstload % 10000));
612 		mg_modify_passwords_file(passfile, realm, user, passwd);
613 
614 		/* Just tell the user the new password generated for this test. */
615 		mg_printf(conn,
616 		          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
617 		          "close\r\n\r\n");
618 
619 		mg_printf(conn, "<!DOCTYPE html>\n");
620 		mg_printf(conn, "<html>\n<head>\n");
621 		mg_printf(conn, "<meta charset=\"UTF-8\">\n");
622 		mg_printf(conn, "<title>Auth handlerexample</title>\n");
623 		mg_printf(conn, "</head>\n");
624 
625 		mg_printf(conn, "<body>\n");
626 		mg_printf(conn,
627 		          "<p>The first time you visit this page, it's free!</p>\n");
628 		mg_printf(conn,
629 		          "<p>Next time, use username \"%s\" and password \"%s\"</p>\n",
630 		          user,
631 		          passwd);
632 		mg_printf(conn, "</body>\n</html>\n");
633 
634 		return 1;
635 	}
636 
637 	if (mg_check_digest_access_authentication(conn, realm, passfile) <= 0) {
638 		/* No valid authorization */
639 		mg_send_digest_access_authentication_request(conn, realm);
640 		return 1;
641 	}
642 
643 	mg_printf(conn,
644 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
645 	          "close\r\n\r\n");
646 
647 	mg_printf(conn, "<!DOCTYPE html>\n");
648 	mg_printf(conn, "<html>\n<head>\n");
649 	mg_printf(conn, "<meta charset=\"UTF-8\">\n");
650 	mg_printf(conn, "<title>Auth handlerexample</title>\n");
651 	mg_printf(conn, "</head>\n");
652 
653 	mg_printf(conn, "<body>\n");
654 	mg_printf(conn, "<p>This is the password protected contents</p>\n");
655 	mg_printf(conn, "</body>\n</html>\n");
656 
657 	return 1;
658 }
659 #endif /* NO_FILESYSTEMS */
660 
661 
662 int
WebSocketStartHandler(struct mg_connection * conn,void * cbdata)663 WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
664 {
665 	mg_printf(conn,
666 	          "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
667 	          "close\r\n\r\n");
668 
669 	mg_printf(conn, "<!DOCTYPE html>\n");
670 	mg_printf(conn, "<html>\n<head>\n");
671 	mg_printf(conn, "<meta charset=\"UTF-8\">\n");
672 	mg_printf(conn, "<title>Embedded websocket example</title>\n");
673 
674 #ifdef USE_WEBSOCKET
675 	/* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
676 	 * xhtml style */
677 	mg_printf(conn, "<script>\n");
678 	mg_printf(
679 	    conn,
680 	    "function load() {\n"
681 	    "  var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
682 	    "  connection = new WebSocket(wsproto + '//' + window.location.host + "
683 	    "'/websocket');\n"
684 	    "  websock_text_field = "
685 	    "document.getElementById('websock_text_field');\n"
686 	    "  connection.onmessage = function (e) {\n"
687 	    "    websock_text_field.innerHTML=e.data;\n"
688 	    "  }\n"
689 	    "  connection.onerror = function (error) {\n"
690 	    "    alert('WebSocket error');\n"
691 	    "    connection.close();\n"
692 	    "  }\n"
693 	    "}\n");
694 	/* mg_printf(conn, "]]></script>\n"); ... xhtml style */
695 	mg_printf(conn, "</script>\n");
696 	mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
697 	mg_printf(
698 	    conn,
699 	    "<div id='websock_text_field'>No websocket connection yet</div>\n");
700 #else
701 	mg_printf(conn, "</head>\n<body>\n");
702 	mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
703 #endif
704 	mg_printf(conn, "</body>\n</html>\n");
705 
706 	return 1;
707 }
708 
709 
710 #ifdef USE_WEBSOCKET
711 
712 /* MAX_WS_CLIENTS defines how many clients can connect to a websocket at the
713  * same time. The value 5 is very small and used here only for demonstration;
714  * it can be easily tested to connect more than MAX_WS_CLIENTS clients.
715  * A real server should use a much higher number, or better use a dynamic list
716  * of currently connected websocket clients. */
717 #define MAX_WS_CLIENTS (5)
718 
719 struct t_ws_client {
720 	struct mg_connection *conn;
721 	int state;
722 } static ws_clients[MAX_WS_CLIENTS];
723 
724 
725 #define ASSERT(x)                                                              \
726 	{                                                                          \
727 		if (!(x)) {                                                            \
728 			fprintf(stderr,                                                    \
729 			        "Assertion failed in line %u\n",                           \
730 			        (unsigned)__LINE__);                                       \
731 		}                                                                      \
732 	}
733 
734 
735 int
WebSocketConnectHandler(const struct mg_connection * conn,void * cbdata)736 WebSocketConnectHandler(const struct mg_connection *conn, void *cbdata)
737 {
738 	struct mg_context *ctx = mg_get_context(conn);
739 	int reject = 1;
740 	int i;
741 
742 	mg_lock_context(ctx);
743 	for (i = 0; i < MAX_WS_CLIENTS; i++) {
744 		if (ws_clients[i].conn == NULL) {
745 			ws_clients[i].conn = (struct mg_connection *)conn;
746 			ws_clients[i].state = 1;
747 			mg_set_user_connection_data(ws_clients[i].conn,
748 			                            (void *)(ws_clients + i));
749 			reject = 0;
750 			break;
751 		}
752 	}
753 	mg_unlock_context(ctx);
754 
755 	fprintf(stdout,
756 	        "Websocket client %s\r\n\r\n",
757 	        (reject ? "rejected" : "accepted"));
758 	return reject;
759 }
760 
761 
762 void
WebSocketReadyHandler(struct mg_connection * conn,void * cbdata)763 WebSocketReadyHandler(struct mg_connection *conn, void *cbdata)
764 {
765 	const char *text = "Hello from the websocket ready handler";
766 	struct t_ws_client *client = mg_get_user_connection_data(conn);
767 
768 	mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, text, strlen(text));
769 	fprintf(stdout, "Greeting message sent to websocket client\r\n\r\n");
770 	ASSERT(client->conn == conn);
771 	ASSERT(client->state == 1);
772 
773 	client->state = 2;
774 }
775 
776 
777 int
WebsocketDataHandler(struct mg_connection * conn,int bits,char * data,size_t len,void * cbdata)778 WebsocketDataHandler(struct mg_connection *conn,
779                      int bits,
780                      char *data,
781                      size_t len,
782                      void *cbdata)
783 {
784 	struct t_ws_client *client = mg_get_user_connection_data(conn);
785 	ASSERT(client->conn == conn);
786 	ASSERT(client->state >= 1);
787 
788 	fprintf(stdout, "Websocket got %lu bytes of ", (unsigned long)len);
789 	switch (((unsigned char)bits) & 0x0F) {
790 	case MG_WEBSOCKET_OPCODE_CONTINUATION:
791 		fprintf(stdout, "continuation");
792 		break;
793 	case MG_WEBSOCKET_OPCODE_TEXT:
794 		fprintf(stdout, "text");
795 		break;
796 	case MG_WEBSOCKET_OPCODE_BINARY:
797 		fprintf(stdout, "binary");
798 		break;
799 	case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
800 		fprintf(stdout, "close");
801 		break;
802 	case MG_WEBSOCKET_OPCODE_PING:
803 		fprintf(stdout, "ping");
804 		break;
805 	case MG_WEBSOCKET_OPCODE_PONG:
806 		fprintf(stdout, "pong");
807 		break;
808 	default:
809 		fprintf(stdout, "unknown(%1xh)", ((unsigned char)bits) & 0x0F);
810 		break;
811 	}
812 	fprintf(stdout, " data:\r\n");
813 	fwrite(data, len, 1, stdout);
814 	fprintf(stdout, "\r\n\r\n");
815 
816 	return 1;
817 }
818 
819 
820 void
WebSocketCloseHandler(const struct mg_connection * conn,void * cbdata)821 WebSocketCloseHandler(const struct mg_connection *conn, void *cbdata)
822 {
823 	struct mg_context *ctx = mg_get_context(conn);
824 	struct t_ws_client *client = mg_get_user_connection_data(conn);
825 	ASSERT(client->conn == conn);
826 	ASSERT(client->state >= 1);
827 
828 	mg_lock_context(ctx);
829 	client->state = 0;
830 	client->conn = NULL;
831 	mg_unlock_context(ctx);
832 
833 	fprintf(stdout,
834 	        "Client dropped from the set of webserver connections\r\n\r\n");
835 }
836 
837 
838 void
InformWebsockets(struct mg_context * ctx)839 InformWebsockets(struct mg_context *ctx)
840 {
841 	static unsigned long cnt = 0;
842 	char text[32];
843 	size_t textlen;
844 	int i;
845 
846 	sprintf(text, "%lu", ++cnt);
847 	textlen = strlen(text);
848 
849 	mg_lock_context(ctx);
850 	for (i = 0; i < MAX_WS_CLIENTS; i++) {
851 		if (ws_clients[i].state == 2) {
852 			mg_websocket_write(ws_clients[i].conn,
853 			                   MG_WEBSOCKET_OPCODE_TEXT,
854 			                   text,
855 			                   textlen);
856 		}
857 	}
858 	mg_unlock_context(ctx);
859 }
860 #endif
861 
862 
863 #ifdef USE_SSL_DH
864 #include "openssl/dh.h"
865 #include "openssl/ec.h"
866 #include "openssl/ecdsa.h"
867 #include "openssl/evp.h"
868 #include "openssl/ssl.h"
869 
870 DH *
get_dh2236()871 get_dh2236()
872 {
873 	static unsigned char dh2236_p[] = {
874 	    0x0E, 0x97, 0x6E, 0x6A, 0x88, 0x84, 0xD2, 0xD7, 0x55, 0x6A, 0x17, 0xB7,
875 	    0x81, 0x9A, 0x98, 0xBC, 0x7E, 0xD1, 0x6A, 0x44, 0xB1, 0x18, 0xE6, 0x25,
876 	    0x3A, 0x62, 0x35, 0xF0, 0x41, 0x91, 0xE2, 0x16, 0x43, 0x9D, 0x8F, 0x7D,
877 	    0x5D, 0xDA, 0x85, 0x47, 0x25, 0xC4, 0xBA, 0x68, 0x0A, 0x87, 0xDC, 0x2C,
878 	    0x33, 0xF9, 0x75, 0x65, 0x17, 0xCB, 0x8B, 0x80, 0xFE, 0xE0, 0xA8, 0xAF,
879 	    0xC7, 0x9E, 0x82, 0xBE, 0x6F, 0x1F, 0x00, 0x04, 0xBD, 0x69, 0x50, 0x8D,
880 	    0x9C, 0x3C, 0x41, 0x69, 0x21, 0x4E, 0x86, 0xC8, 0x2B, 0xCC, 0x07, 0x4D,
881 	    0xCF, 0xE4, 0xA2, 0x90, 0x8F, 0x66, 0xA9, 0xEF, 0xF7, 0xFC, 0x6F, 0x5F,
882 	    0x06, 0x22, 0x00, 0xCB, 0xCB, 0xC3, 0x98, 0x3F, 0x06, 0xB9, 0xEC, 0x48,
883 	    0x3B, 0x70, 0x6E, 0x94, 0xE9, 0x16, 0xE1, 0xB7, 0x63, 0x2E, 0xAB, 0xB2,
884 	    0xF3, 0x84, 0xB5, 0x3D, 0xD7, 0x74, 0xF1, 0x6A, 0xD1, 0xEF, 0xE8, 0x04,
885 	    0x18, 0x76, 0xD2, 0xD6, 0xB0, 0xB7, 0x71, 0xB6, 0x12, 0x8F, 0xD1, 0x33,
886 	    0xAB, 0x49, 0xAB, 0x09, 0x97, 0x35, 0x9D, 0x4B, 0xBB, 0x54, 0x22, 0x6E,
887 	    0x1A, 0x33, 0x18, 0x02, 0x8A, 0xF4, 0x7C, 0x0A, 0xCE, 0x89, 0x75, 0x2D,
888 	    0x10, 0x68, 0x25, 0xA9, 0x6E, 0xCD, 0x97, 0x49, 0xED, 0xAE, 0xE6, 0xA7,
889 	    0xB0, 0x07, 0x26, 0x25, 0x60, 0x15, 0x2B, 0x65, 0x88, 0x17, 0xF2, 0x5D,
890 	    0x2C, 0xF6, 0x2A, 0x7A, 0x8C, 0xAD, 0xB6, 0x0A, 0xA2, 0x57, 0xB0, 0xC1,
891 	    0x0E, 0x5C, 0xA8, 0xA1, 0x96, 0x58, 0x9A, 0x2B, 0xD4, 0xC0, 0x8A, 0xCF,
892 	    0x91, 0x25, 0x94, 0xB4, 0x14, 0xA7, 0xE4, 0xE2, 0x1B, 0x64, 0x5F, 0xD2,
893 	    0xCA, 0x70, 0x46, 0xD0, 0x2C, 0x95, 0x6B, 0x9A, 0xFB, 0x83, 0xF9, 0x76,
894 	    0xE6, 0xD4, 0xA4, 0xA1, 0x2B, 0x2F, 0xF5, 0x1D, 0xE4, 0x06, 0xAF, 0x7D,
895 	    0x22, 0xF3, 0x04, 0x30, 0x2E, 0x4C, 0x64, 0x12, 0x5B, 0xB0, 0x55, 0x3E,
896 	    0xC0, 0x5E, 0x56, 0xCB, 0x99, 0xBC, 0xA8, 0xD9, 0x23, 0xF5, 0x57, 0x40,
897 	    0xF0, 0x52, 0x85, 0x9B,
898 	};
899 	static unsigned char dh2236_g[] = {
900 	    0x02,
901 	};
902 	DH *dh;
903 
904 	if ((dh = DH_new()) == NULL)
905 		return (NULL);
906 	dh->p = BN_bin2bn(dh2236_p, sizeof(dh2236_p), NULL);
907 	dh->g = BN_bin2bn(dh2236_g, sizeof(dh2236_g), NULL);
908 	if ((dh->p == NULL) || (dh->g == NULL)) {
909 		DH_free(dh);
910 		return (NULL);
911 	}
912 	return (dh);
913 }
914 #endif
915 
916 
917 #ifndef TEST_WITHOUT_SSL
918 int
init_ssl(void * ssl_context,void * user_data)919 init_ssl(void *ssl_context, void *user_data)
920 {
921 	/* Add application specific SSL initialization */
922 	struct ssl_ctx_st *ctx = (struct ssl_ctx_st *)ssl_context;
923 
924 #ifdef USE_SSL_DH
925 	/* example from https://github.com/civetweb/civetweb/issues/347 */
926 	DH *dh = get_dh2236();
927 	if (!dh)
928 		return -1;
929 	if (1 != SSL_CTX_set_tmp_dh(ctx, dh))
930 		return -1;
931 	DH_free(dh);
932 
933 	EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
934 	if (!ecdh)
935 		return -1;
936 	if (1 != SSL_CTX_set_tmp_ecdh(ctx, ecdh))
937 		return -1;
938 	EC_KEY_free(ecdh);
939 
940 	printf("ECDH ciphers initialized\n");
941 #endif
942 	return 0;
943 }
944 #endif
945 
946 
947 int
log_message(const struct mg_connection * conn,const char * message)948 log_message(const struct mg_connection *conn, const char *message)
949 {
950 	puts(message);
951 	return 1;
952 }
953 
954 
955 int
main(int argc,char * argv[])956 main(int argc, char *argv[])
957 {
958 	const char *options[] = {
959 #if !defined(NO_FILES)
960 		"document_root",
961 		DOCUMENT_ROOT,
962 #endif
963 		"listening_ports",
964 		PORT,
965 		"request_timeout_ms",
966 		"10000",
967 		"error_log_file",
968 		"error.log",
969 #ifdef USE_WEBSOCKET
970 		"websocket_timeout_ms",
971 		"3600000",
972 #endif
973 #ifndef TEST_WITHOUT_SSL
974 		"ssl_certificate",
975 		"../../resources/cert/server.pem",
976 		"ssl_protocol_version",
977 		"3",
978 		"ssl_cipher_list",
979 #ifdef USE_SSL_DH
980 		"ECDHE-RSA-AES256-GCM-SHA384:DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
981 #else
982 		"DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
983 #endif
984 #endif
985 		"enable_auth_domain_check",
986 		"no",
987 		0
988 	};
989 	struct mg_callbacks callbacks;
990 	struct mg_context *ctx;
991 	struct mg_server_port ports[32];
992 	int port_cnt, n;
993 	int err = 0;
994 
995 	/* Check if libcivetweb has been built with all required features. */
996 #ifdef USE_IPV6
997 	if (!mg_check_feature(8)) {
998 		fprintf(stderr,
999 		        "Error: Embedded example built with IPv6 support, "
1000 		        "but civetweb library build without.\n");
1001 		err = 1;
1002 	}
1003 #endif
1004 #ifdef USE_WEBSOCKET
1005 	if (!mg_check_feature(16)) {
1006 		fprintf(stderr,
1007 		        "Error: Embedded example built with websocket support, "
1008 		        "but civetweb library build without.\n");
1009 		err = 1;
1010 	}
1011 #endif
1012 #ifndef TEST_WITHOUT_SSL
1013 	if (!mg_check_feature(2)) {
1014 		fprintf(stderr,
1015 		        "Error: Embedded example built with SSL support, "
1016 		        "but civetweb library build without.\n");
1017 		err = 1;
1018 	}
1019 #endif
1020 	if (err) {
1021 		fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");
1022 		return EXIT_FAILURE;
1023 	}
1024 
1025 	/* Start CivetWeb web server */
1026 	memset(&callbacks, 0, sizeof(callbacks));
1027 #ifndef TEST_WITHOUT_SSL
1028 	callbacks.init_ssl = init_ssl;
1029 #endif
1030 	callbacks.log_message = log_message;
1031 	ctx = mg_start(&callbacks, 0, options);
1032 
1033 	/* Check return value: */
1034 	if (ctx == NULL) {
1035 		fprintf(stderr, "Cannot start CivetWeb - mg_start failed.\n");
1036 		return EXIT_FAILURE;
1037 	}
1038 
1039 	/* Add handler EXAMPLE_URI, to explain the example */
1040 	mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
1041 	mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
1042 
1043 	/* Add handler for /A* and special handler for /A/B */
1044 	mg_set_request_handler(ctx, "/A", AHandler, 0);
1045 	mg_set_request_handler(ctx, "/A/B", ABHandler, 0);
1046 
1047 	/* Add handler for /B, /B/A, /B/B but not for /B* */
1048 	mg_set_request_handler(ctx, "/B$", BXHandler, (void *)"alpha");
1049 	mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)"beta");
1050 	mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)"gamma");
1051 
1052 	/* Add handler for all files with .foo extension */
1053 	mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
1054 
1055 	/* Add handler for /close extension */
1056 	mg_set_request_handler(ctx, "/close", CloseHandler, 0);
1057 
1058 #if !defined(NO_FILESYSTEMS)
1059 	/* Add handler for /form  (serve a file outside the document root) */
1060 	mg_set_request_handler(ctx,
1061 	                       "/form",
1062 	                       FileHandler,
1063 	                       (void *)"../../test/form.html");
1064 #endif /* NO_FILESYSTEMS */
1065 
1066 	/* Add handler for form data */
1067 	mg_set_request_handler(ctx,
1068 	                       "/handle_form.embedded_c.example.callback",
1069 	                       FormHandler,
1070 	                       (void *)0);
1071 
1072 	/* Add a file upload handler for parsing files on the fly */
1073 	mg_set_request_handler(ctx,
1074 	                       "/on_the_fly_form",
1075 	                       FileUploadForm,
1076 	                       (void *)"/on_the_fly_form.md5.callback");
1077 	mg_set_request_handler(ctx,
1078 	                       "/on_the_fly_form.md5.callback",
1079 	                       CheckSumHandler,
1080 	                       (void *)0);
1081 
1082 	/* Add handler for /cookie example */
1083 	mg_set_request_handler(ctx, "/cookie", CookieHandler, 0);
1084 
1085 	/* Add handler for /postresponse example */
1086 	mg_set_request_handler(ctx, "/postresponse", PostResponser, 0);
1087 
1088 	/* Add HTTP site to open a websocket connection */
1089 	mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
1090 
1091 #if !defined(NO_FILESYSTEMS)
1092 	/* Add HTTP site with auth */
1093 	mg_set_request_handler(ctx, "/auth", AuthStartHandler, 0);
1094 #endif /* NO_FILESYSTEMS */
1095 
1096 
1097 #ifdef USE_WEBSOCKET
1098 	/* WS site for the websocket connection */
1099 	mg_set_websocket_handler(ctx,
1100 	                         "/websocket",
1101 	                         WebSocketConnectHandler,
1102 	                         WebSocketReadyHandler,
1103 	                         WebsocketDataHandler,
1104 	                         WebSocketCloseHandler,
1105 	                         0);
1106 #endif
1107 
1108 	/* List all listening ports */
1109 	memset(ports, 0, sizeof(ports));
1110 	port_cnt = mg_get_server_ports(ctx, 32, ports);
1111 	printf("\n%i listening ports:\n\n", port_cnt);
1112 
1113 	for (n = 0; n < port_cnt && n < 32; n++) {
1114 		const char *proto = ports[n].is_ssl ? "https" : "http";
1115 		const char *host;
1116 
1117 		if ((ports[n].protocol & 1) == 1) {
1118 			/* IPv4 */
1119 			host = "127.0.0.1";
1120 			printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
1121 			printf("Run example at %s://%s:%i%s\n",
1122 			       proto,
1123 			       host,
1124 			       ports[n].port,
1125 			       EXAMPLE_URI);
1126 			printf(
1127 			    "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
1128 			printf("\n");
1129 		}
1130 
1131 		if ((ports[n].protocol & 2) == 2) {
1132 			/* IPv6 */
1133 			host = "[::1]";
1134 			printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
1135 			printf("Run example at %s://%s:%i%s\n",
1136 			       proto,
1137 			       host,
1138 			       ports[n].port,
1139 			       EXAMPLE_URI);
1140 			printf(
1141 			    "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
1142 			printf("\n");
1143 		}
1144 	}
1145 
1146 	/* Wait until the server should be closed */
1147 	while (!exitNow) {
1148 #ifdef _WIN32
1149 		Sleep(1000);
1150 #else
1151 		sleep(1);
1152 #endif
1153 #ifdef USE_WEBSOCKET
1154 		InformWebsockets(ctx);
1155 #endif
1156 	}
1157 
1158 	/* Stop the server */
1159 	mg_stop(ctx);
1160 	printf("Server stopped.\n");
1161 	printf("Bye!\n");
1162 
1163 	return EXIT_SUCCESS;
1164 }
1165