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
7 /* Simple example program on how to use CivetWeb embedded into a C program. */
21 #define DOCUMENT_ROOT "."
24 #define PORT "[::]:8888,8884"
26 #define PORT "8888,8884"
30 #define PORT "[::]:8888r,[::]:8843s,8884"
32 #define PORT "8888r,8843s,8884"
35 #define EXAMPLE_URI "/example"
36 #define EXIT_URI "/exit"
41 ExampleHandler(struct mg_connection
*conn
, void *cbdata
)
44 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
46 mg_printf(conn
, "<html><body>");
47 mg_printf(conn
, "<h2>This is an example text from a C handler</h2>");
50 "<p>To see a page from the A handler <a href=\"A\">click A</a></p>");
52 "<p>To see a page from the A handler <a href=\"A/A\">click "
55 "<p>To see a page from the A/B handler <a "
56 "href=\"A/B\">click A/B</a></p>");
58 "<p>To see a page from the B handler (0) <a "
59 "href=\"B\">click B</a></p>");
61 "<p>To see a page from the B handler (1) <a "
62 "href=\"B/A\">click B/A</a></p>");
64 "<p>To see a page from the B handler (2) <a "
65 "href=\"B/B\">click B/B</a></p>");
67 "<p>To see a page from the *.foo handler <a "
68 "href=\"xy.foo\">click xy.foo</a></p>");
70 "<p>To see a page from the close handler <a "
71 "href=\"close\">click close</a></p>");
73 "<p>To see a page from the FileHandler handler <a "
74 "href=\"form\">click form</a> (the starting point of the "
75 "<b>form</b> test)</p>");
77 "<p>To see a page from the CookieHandler handler <a "
78 "href=\"cookie\">click cookie</a></p>");
80 "<p>To see a page from the PostResponser handler <a "
81 "href=\"postresponse\">click post response</a></p>");
83 "<p>To see an example for parsing files on the fly <a "
84 "href=\"on_the_fly_form\">click form</a> (form for "
85 "uploading files)</p>");
89 "<p>To test the websocket handler <a href=\"/websocket\">click "
94 "<p>To test the authentication handler <a href=\"/auth\">click "
97 mg_printf(conn
, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI
);
98 mg_printf(conn
, "</body></html>\n");
104 ExitHandler(struct mg_connection
*conn
, void *cbdata
)
107 "HTTP/1.1 200 OK\r\nContent-Type: "
108 "text/plain\r\nConnection: close\r\n\r\n");
109 mg_printf(conn
, "Server will shut down.\n");
110 mg_printf(conn
, "Bye!\n");
117 AHandler(struct mg_connection
*conn
, void *cbdata
)
120 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
122 mg_printf(conn
, "<html><body>");
123 mg_printf(conn
, "<h2>This is the A handler!!!</h2>");
124 mg_printf(conn
, "</body></html>\n");
130 ABHandler(struct mg_connection
*conn
, void *cbdata
)
133 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
135 mg_printf(conn
, "<html><body>");
136 mg_printf(conn
, "<h2>This is the AB handler!!!</h2>");
137 mg_printf(conn
, "</body></html>\n");
143 BXHandler(struct mg_connection
*conn
, void *cbdata
)
145 /* Handler may access the request info using mg_get_request_info */
146 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
149 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
151 mg_printf(conn
, "<html><body>");
152 mg_printf(conn
, "<h2>This is the BX handler %p!!!</h2>", cbdata
);
153 mg_printf(conn
, "<p>The actual uri is %s</p>", req_info
->local_uri
);
154 mg_printf(conn
, "</body></html>\n");
160 FooHandler(struct mg_connection
*conn
, void *cbdata
)
162 /* Handler may access the request info using mg_get_request_info */
163 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
166 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
168 mg_printf(conn
, "<html><body>");
169 mg_printf(conn
, "<h2>This is the Foo handler!!!</h2>");
171 "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",
172 req_info
->request_method
,
174 req_info
->http_version
);
175 mg_printf(conn
, "</body></html>\n");
181 CloseHandler(struct mg_connection
*conn
, void *cbdata
)
183 /* Handler may access the request info using mg_get_request_info */
184 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
187 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
189 mg_printf(conn
, "<html><body>");
191 "<h2>This handler will close the connection in a second</h2>");
197 mg_printf(conn
, "bye");
198 printf("CloseHandler: close connection\n");
199 mg_close_connection(conn
);
200 printf("CloseHandler: wait 10 sec\n");
206 printf("CloseHandler: return from function\n");
212 FileHandler(struct mg_connection
*conn
, void *cbdata
)
214 /* In this handler, we ignore the req_info and send the file "fileName". */
215 const char *fileName
= (const char *)cbdata
;
217 mg_send_file(conn
, fileName
);
223 field_found(const char *key
,
224 const char *filename
,
229 struct mg_connection
*conn
= (struct mg_connection
*)user_data
;
231 mg_printf(conn
, "\r\n\r\n%s:\r\n", key
);
233 if (filename
&& *filename
) {
235 _snprintf(path
, pathlen
, "D:\\tmp\\%s", filename
);
237 snprintf(path
, pathlen
, "/tmp/%s", filename
);
239 return FORM_FIELD_STORAGE_STORE
;
241 return FORM_FIELD_STORAGE_GET
;
246 field_get(const char *key
, const char *value
, size_t valuelen
, void *user_data
)
248 struct mg_connection
*conn
= (struct mg_connection
*)user_data
;
251 mg_printf(conn
, "%s = ", key
);
253 mg_write(conn
, value
, valuelen
);
260 field_stored(const char *path
, long long file_size
, void *user_data
)
262 struct mg_connection
*conn
= (struct mg_connection
*)user_data
;
265 "stored as %s (%lu bytes)\r\n\r\n",
267 (unsigned long)file_size
);
274 FormHandler(struct mg_connection
*conn
, void *cbdata
)
276 /* Handler may access the request info using mg_get_request_info */
277 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
279 struct mg_form_data_handler fdh
= {field_found
, field_get
, field_stored
, 0};
281 /* It would be possible to check the request info here before calling
282 * mg_handle_form_request. */
286 "HTTP/1.1 200 OK\r\nContent-Type: "
287 "text/plain\r\nConnection: close\r\n\r\n");
288 fdh
.user_data
= (void *)conn
;
290 /* Call the form handler */
291 mg_printf(conn
, "Form data:");
292 ret
= mg_handle_form_request(conn
, &fdh
);
293 mg_printf(conn
, "\r\n%i fields found", ret
);
300 FileUploadForm(struct mg_connection
*conn
, void *cbdata
)
303 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
306 mg_printf(conn
, "<!DOCTYPE html>\n");
307 mg_printf(conn
, "<html>\n<head>\n");
308 mg_printf(conn
, "<meta charset=\"UTF-8\">\n");
309 mg_printf(conn
, "<title>File upload</title>\n");
310 mg_printf(conn
, "</head>\n<body>\n");
312 "<form action=\"%s\" method=\"POST\" "
313 "enctype=\"multipart/form-data\">\n",
314 (const char *)cbdata
);
315 mg_printf(conn
, "<input type=\"file\" name=\"filesin\" multiple>\n");
316 mg_printf(conn
, "<input type=\"submit\" value=\"Submit\">\n");
317 mg_printf(conn
, "</form>\n</body>\n</html>\n");
321 #define MD5_STATIC static
322 #include "../src/md5.inl"
324 struct tfile_checksum
{
326 unsigned long long length
;
330 #define MAX_FILES (10)
332 struct tfiles_checksums
{
334 struct tfile_checksum file
[MAX_FILES
];
339 field_disp_read_on_the_fly(const char *key
,
340 const char *filename
,
345 struct tfiles_checksums
*context
= (struct tfiles_checksums
*)user_data
;
351 if (context
->index
< MAX_FILES
) {
353 strncpy(context
->file
[context
->index
- 1].name
, filename
, 128);
354 context
->file
[context
->index
- 1].name
[127] = 0;
355 context
->file
[context
->index
- 1].length
= 0;
356 md5_init(&(context
->file
[context
->index
- 1].chksum
));
357 return FORM_FIELD_STORAGE_GET
;
359 return FORM_FIELD_STORAGE_ABORT
;
364 field_get_checksum(const char *key
,
369 struct tfiles_checksums
*context
= (struct tfiles_checksums
*)user_data
;
372 context
->file
[context
->index
- 1].length
+= valuelen
;
373 md5_append(&(context
->file
[context
->index
- 1].chksum
),
374 (const md5_byte_t
*)value
,
382 CheckSumHandler(struct mg_connection
*conn
, void *cbdata
)
384 /* Handler may access the request info using mg_get_request_info */
385 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
387 struct tfiles_checksums chksums
;
388 md5_byte_t digest
[16];
389 struct mg_form_data_handler fdh
= {field_disp_read_on_the_fly
,
394 /* It would be possible to check the request info here before calling
395 * mg_handle_form_request. */
398 memset(&chksums
, 0, sizeof(chksums
));
401 "HTTP/1.1 200 OK\r\n"
402 "Content-Type: text/plain\r\n"
403 "Connection: close\r\n\r\n");
405 /* Call the form handler */
406 mg_printf(conn
, "File checksums:");
407 ret
= mg_handle_form_request(conn
, &fdh
);
408 for (i
= 0; i
< chksums
.index
; i
++) {
409 md5_finish(&(chksums
.file
[i
].chksum
), digest
);
410 /* Visual Studio 2010+ support llu */
413 chksums
.file
[i
].name
,
414 chksums
.file
[i
].length
);
415 for (j
= 0; j
< 16; j
++) {
416 mg_printf(conn
, "%02x", (unsigned int)digest
[j
]);
419 mg_printf(conn
, "\r\n%i files\r\n", ret
);
426 CookieHandler(struct mg_connection
*conn
, void *cbdata
)
428 /* Handler may access the request info using mg_get_request_info */
429 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
430 const char *cookie
= mg_get_header(conn
, "Cookie");
431 char first_str
[64], count_str
[64];
434 (void)mg_get_cookie(cookie
, "first", first_str
, sizeof(first_str
));
435 (void)mg_get_cookie(cookie
, "count", count_str
, sizeof(count_str
));
437 mg_printf(conn
, "HTTP/1.1 200 OK\r\nConnection: close\r\n");
438 if (first_str
[0] == 0) {
440 struct tm
*ptm
= localtime(&t
);
442 "Set-Cookie: first=%04i-%02i-%02iT%02i:%02i:%02i\r\n",
450 count
= (count_str
[0] == 0) ? 0 : atoi(count_str
);
451 mg_printf(conn
, "Set-Cookie: count=%i\r\n", count
+ 1);
452 mg_printf(conn
, "Content-Type: text/html\r\n\r\n");
454 mg_printf(conn
, "<html><body>");
455 mg_printf(conn
, "<h2>This is the CookieHandler.</h2>");
456 mg_printf(conn
, "<p>The actual uri is %s</p>", req_info
->local_uri
);
458 if (first_str
[0] == 0) {
459 mg_printf(conn
, "<p>This is the first time, you opened this page</p>");
461 mg_printf(conn
, "<p>You opened this page %i times before.</p>", count
);
462 mg_printf(conn
, "<p>You first opened this page on %s.</p>", first_str
);
465 mg_printf(conn
, "</body></html>\n");
471 PostResponser(struct mg_connection
*conn
, void *cbdata
)
473 long long r_total
= 0;
478 const struct mg_request_info
*ri
= mg_get_request_info(conn
);
480 if (strcmp(ri
->request_method
, "POST")) {
482 int ret
= mg_get_request_link(conn
, buf
, sizeof(buf
));
485 "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
486 mg_printf(conn
, "Content-Type: text/plain\r\n\r\n");
488 "%s method not allowed in the POST handler\n",
492 "use a web tool to send a POST request to %s\n",
498 if (ri
->content_length
>= 0) {
499 /* We know the content length in advance */
501 /* We must read until we find the end (chunked encoding
502 * or connection close), indicated my mg_read returning 0 */
506 "HTTP/1.1 200 OK\r\nConnection: "
507 "close\r\nTransfer-Encoding: chunked\r\n");
508 mg_printf(conn
, "Content-Type: text/plain\r\n\r\n");
510 r
= mg_read(conn
, buf
, sizeof(buf
));
513 s
= mg_send_chunk(conn
, buf
, r
);
518 r
= mg_read(conn
, buf
, sizeof(buf
));
520 mg_printf(conn
, "0\r\n");
527 AuthStartHandler(struct mg_connection
*conn
, void *cbdata
)
529 static unsigned long long firstload
= 0;
530 const char *passfile
= "password_example_file.txt";
531 const char *realm
= "password_example";
532 const char *user
= "user";
535 if (firstload
== 0) {
537 /* Set a random password (4 digit number - bad idea from a security
538 * point of view, but this is an API demo, not a security tutorial),
539 * and store it in some directory within the document root (extremely
540 * bad idea, but this is still not a security tutorial).
541 * The reason we create a new password every time the server starts
542 * is just for demonstration - we don't want the browser to store the
543 * password, so when we repeat the test we start with a new password.
545 firstload
= (unsigned long long)time(NULL
);
546 sprintf(passwd
, "%04u", (unsigned int)(firstload
% 10000));
547 mg_modify_passwords_file(passfile
, realm
, user
, passwd
);
549 /* Just tell the user the new password generated for this test. */
551 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
554 mg_printf(conn
, "<!DOCTYPE html>\n");
555 mg_printf(conn
, "<html>\n<head>\n");
556 mg_printf(conn
, "<meta charset=\"UTF-8\">\n");
557 mg_printf(conn
, "<title>Auth handlerexample</title>\n");
558 mg_printf(conn
, "</head>\n");
560 mg_printf(conn
, "<body>\n");
562 "<p>The first time you visit this page, it's free!</p>\n");
564 "<p>Next time, use username \"%s\" and password \"%s\"</p>\n",
567 mg_printf(conn
, "</body>\n</html>\n");
572 if (mg_check_digest_access_authentication(conn
, realm
, passfile
) <= 0) {
573 /* No valid authorization */
574 mg_send_digest_access_authentication_request(conn
, realm
);
579 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
582 mg_printf(conn
, "<!DOCTYPE html>\n");
583 mg_printf(conn
, "<html>\n<head>\n");
584 mg_printf(conn
, "<meta charset=\"UTF-8\">\n");
585 mg_printf(conn
, "<title>Auth handlerexample</title>\n");
586 mg_printf(conn
, "</head>\n");
588 mg_printf(conn
, "<body>\n");
589 mg_printf(conn
, "<p>This is the password protected contents</p>\n");
590 mg_printf(conn
, "</body>\n</html>\n");
597 WebSocketStartHandler(struct mg_connection
*conn
, void *cbdata
)
600 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
603 mg_printf(conn
, "<!DOCTYPE html>\n");
604 mg_printf(conn
, "<html>\n<head>\n");
605 mg_printf(conn
, "<meta charset=\"UTF-8\">\n");
606 mg_printf(conn
, "<title>Embedded websocket example</title>\n");
609 /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
611 mg_printf(conn
, "<script>\n");
614 "function load() {\n"
615 " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
616 " connection = new WebSocket(wsproto + '//' + window.location.host + "
618 " websock_text_field = "
619 "document.getElementById('websock_text_field');\n"
620 " connection.onmessage = function (e) {\n"
621 " websock_text_field.innerHTML=e.data;\n"
623 " connection.onerror = function (error) {\n"
624 " alert('WebSocket error');\n"
625 " connection.close();\n"
628 /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
629 mg_printf(conn
, "</script>\n");
630 mg_printf(conn
, "</head>\n<body onload=\"load()\">\n");
633 "<div id='websock_text_field'>No websocket connection yet</div>\n");
635 mg_printf(conn
, "</head>\n<body>\n");
636 mg_printf(conn
, "Example not compiled with USE_WEBSOCKET\n");
638 mg_printf(conn
, "</body>\n</html>\n");
646 /* MAX_WS_CLIENTS defines how many clients can connect to a websocket at the
647 * same time. The value 5 is very small and used here only for demonstration;
648 * it can be easily tested to connect more than MAX_WS_CLIENTS clients.
649 * A real server should use a much higher number, or better use a dynamic list
650 * of currently connected websocket clients. */
651 #define MAX_WS_CLIENTS (5)
654 struct mg_connection
*conn
;
656 } static ws_clients
[MAX_WS_CLIENTS
];
663 "Assertion failed in line %u\n", \
664 (unsigned)__LINE__); \
670 WebSocketConnectHandler(const struct mg_connection
*conn
, void *cbdata
)
672 struct mg_context
*ctx
= mg_get_context(conn
);
676 mg_lock_context(ctx
);
677 for (i
= 0; i
< MAX_WS_CLIENTS
; i
++) {
678 if (ws_clients
[i
].conn
== NULL
) {
679 ws_clients
[i
].conn
= (struct mg_connection
*)conn
;
680 ws_clients
[i
].state
= 1;
681 mg_set_user_connection_data(ws_clients
[i
].conn
,
682 (void *)(ws_clients
+ i
));
687 mg_unlock_context(ctx
);
690 "Websocket client %s\r\n\r\n",
691 (reject
? "rejected" : "accepted"));
697 WebSocketReadyHandler(struct mg_connection
*conn
, void *cbdata
)
699 const char *text
= "Hello from the websocket ready handler";
700 struct t_ws_client
*client
= mg_get_user_connection_data(conn
);
702 mg_websocket_write(conn
, WEBSOCKET_OPCODE_TEXT
, text
, strlen(text
));
703 fprintf(stdout
, "Greeting message sent to websocket client\r\n\r\n");
704 ASSERT(client
->conn
== conn
);
705 ASSERT(client
->state
== 1);
712 WebsocketDataHandler(struct mg_connection
*conn
,
718 struct t_ws_client
*client
= mg_get_user_connection_data(conn
);
719 ASSERT(client
->conn
== conn
);
720 ASSERT(client
->state
>= 1);
722 fprintf(stdout
, "Websocket got %lu bytes of ", (unsigned long)len
);
723 switch (((unsigned char)bits
) & 0x0F) {
724 case WEBSOCKET_OPCODE_CONTINUATION
:
725 fprintf(stdout
, "continuation");
727 case WEBSOCKET_OPCODE_TEXT
:
728 fprintf(stdout
, "text");
730 case WEBSOCKET_OPCODE_BINARY
:
731 fprintf(stdout
, "binary");
733 case WEBSOCKET_OPCODE_CONNECTION_CLOSE
:
734 fprintf(stdout
, "close");
736 case WEBSOCKET_OPCODE_PING
:
737 fprintf(stdout
, "ping");
739 case WEBSOCKET_OPCODE_PONG
:
740 fprintf(stdout
, "pong");
743 fprintf(stdout
, "unknown(%1xh)", ((unsigned char)bits
) & 0x0F);
746 fprintf(stdout
, " data:\r\n");
747 fwrite(data
, len
, 1, stdout
);
748 fprintf(stdout
, "\r\n\r\n");
755 WebSocketCloseHandler(const struct mg_connection
*conn
, void *cbdata
)
757 struct mg_context
*ctx
= mg_get_context(conn
);
758 struct t_ws_client
*client
= mg_get_user_connection_data(conn
);
759 ASSERT(client
->conn
== conn
);
760 ASSERT(client
->state
>= 1);
762 mg_lock_context(ctx
);
765 mg_unlock_context(ctx
);
768 "Client droped from the set of webserver connections\r\n\r\n");
773 InformWebsockets(struct mg_context
*ctx
)
775 static unsigned long cnt
= 0;
779 sprintf(text
, "%lu", ++cnt
);
781 mg_lock_context(ctx
);
782 for (i
= 0; i
< MAX_WS_CLIENTS
; i
++) {
783 if (ws_clients
[i
].state
== 2) {
784 mg_websocket_write(ws_clients
[i
].conn
,
785 WEBSOCKET_OPCODE_TEXT
,
790 mg_unlock_context(ctx
);
796 #include "openssl/ssl.h"
797 #include "openssl/dh.h"
798 #include "openssl/ec.h"
799 #include "openssl/evp.h"
800 #include "openssl/ecdsa.h"
805 static unsigned char dh2236_p
[] = {
806 0x0E, 0x97, 0x6E, 0x6A, 0x88, 0x84, 0xD2, 0xD7, 0x55, 0x6A, 0x17, 0xB7,
807 0x81, 0x9A, 0x98, 0xBC, 0x7E, 0xD1, 0x6A, 0x44, 0xB1, 0x18, 0xE6, 0x25,
808 0x3A, 0x62, 0x35, 0xF0, 0x41, 0x91, 0xE2, 0x16, 0x43, 0x9D, 0x8F, 0x7D,
809 0x5D, 0xDA, 0x85, 0x47, 0x25, 0xC4, 0xBA, 0x68, 0x0A, 0x87, 0xDC, 0x2C,
810 0x33, 0xF9, 0x75, 0x65, 0x17, 0xCB, 0x8B, 0x80, 0xFE, 0xE0, 0xA8, 0xAF,
811 0xC7, 0x9E, 0x82, 0xBE, 0x6F, 0x1F, 0x00, 0x04, 0xBD, 0x69, 0x50, 0x8D,
812 0x9C, 0x3C, 0x41, 0x69, 0x21, 0x4E, 0x86, 0xC8, 0x2B, 0xCC, 0x07, 0x4D,
813 0xCF, 0xE4, 0xA2, 0x90, 0x8F, 0x66, 0xA9, 0xEF, 0xF7, 0xFC, 0x6F, 0x5F,
814 0x06, 0x22, 0x00, 0xCB, 0xCB, 0xC3, 0x98, 0x3F, 0x06, 0xB9, 0xEC, 0x48,
815 0x3B, 0x70, 0x6E, 0x94, 0xE9, 0x16, 0xE1, 0xB7, 0x63, 0x2E, 0xAB, 0xB2,
816 0xF3, 0x84, 0xB5, 0x3D, 0xD7, 0x74, 0xF1, 0x6A, 0xD1, 0xEF, 0xE8, 0x04,
817 0x18, 0x76, 0xD2, 0xD6, 0xB0, 0xB7, 0x71, 0xB6, 0x12, 0x8F, 0xD1, 0x33,
818 0xAB, 0x49, 0xAB, 0x09, 0x97, 0x35, 0x9D, 0x4B, 0xBB, 0x54, 0x22, 0x6E,
819 0x1A, 0x33, 0x18, 0x02, 0x8A, 0xF4, 0x7C, 0x0A, 0xCE, 0x89, 0x75, 0x2D,
820 0x10, 0x68, 0x25, 0xA9, 0x6E, 0xCD, 0x97, 0x49, 0xED, 0xAE, 0xE6, 0xA7,
821 0xB0, 0x07, 0x26, 0x25, 0x60, 0x15, 0x2B, 0x65, 0x88, 0x17, 0xF2, 0x5D,
822 0x2C, 0xF6, 0x2A, 0x7A, 0x8C, 0xAD, 0xB6, 0x0A, 0xA2, 0x57, 0xB0, 0xC1,
823 0x0E, 0x5C, 0xA8, 0xA1, 0x96, 0x58, 0x9A, 0x2B, 0xD4, 0xC0, 0x8A, 0xCF,
824 0x91, 0x25, 0x94, 0xB4, 0x14, 0xA7, 0xE4, 0xE2, 0x1B, 0x64, 0x5F, 0xD2,
825 0xCA, 0x70, 0x46, 0xD0, 0x2C, 0x95, 0x6B, 0x9A, 0xFB, 0x83, 0xF9, 0x76,
826 0xE6, 0xD4, 0xA4, 0xA1, 0x2B, 0x2F, 0xF5, 0x1D, 0xE4, 0x06, 0xAF, 0x7D,
827 0x22, 0xF3, 0x04, 0x30, 0x2E, 0x4C, 0x64, 0x12, 0x5B, 0xB0, 0x55, 0x3E,
828 0xC0, 0x5E, 0x56, 0xCB, 0x99, 0xBC, 0xA8, 0xD9, 0x23, 0xF5, 0x57, 0x40,
829 0xF0, 0x52, 0x85, 0x9B,
831 static unsigned char dh2236_g
[] = {
836 if ((dh
= DH_new()) == NULL
)
838 dh
->p
= BN_bin2bn(dh2236_p
, sizeof(dh2236_p
), NULL
);
839 dh
->g
= BN_bin2bn(dh2236_g
, sizeof(dh2236_g
), NULL
);
840 if ((dh
->p
== NULL
) || (dh
->g
== NULL
)) {
851 init_ssl(void *ssl_context
, void *user_data
)
853 /* Add application specific SSL initialization */
854 struct ssl_ctx_st
*ctx
= (struct ssl_ctx_st
*)ssl_context
;
857 /* example from https://github.com/civetweb/civetweb/issues/347 */
858 DH
*dh
= get_dh2236();
861 if (1 != SSL_CTX_set_tmp_dh(ctx
, dh
))
865 EC_KEY
*ecdh
= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1
);
868 if (1 != SSL_CTX_set_tmp_ecdh(ctx
, ecdh
))
872 printf("ECDH ciphers initialized\n");
880 log_message(const struct mg_connection
*conn
, const char *message
)
888 main(int argc
, char *argv
[])
890 const char *options
[] = {
895 "request_timeout_ms",
900 "websocket_timeout_ms",
905 "../../resources/cert/server.pem",
906 "ssl_protocol_version",
910 "ECDHE-RSA-AES256-GCM-SHA384:DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
912 "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
915 "enable_auth_domain_check",
918 struct mg_callbacks callbacks
;
919 struct mg_context
*ctx
;
920 struct mg_server_ports ports
[32];
924 /* Check if libcivetweb has been built with all required features. */
926 if (!mg_check_feature(8)) {
928 "Error: Embedded example built with IPv6 support, "
929 "but civetweb library build without.\n");
934 if (!mg_check_feature(16)) {
936 "Error: Embedded example built with websocket support, "
937 "but civetweb library build without.\n");
942 if (!mg_check_feature(2)) {
944 "Error: Embedded example built with SSL support, "
945 "but civetweb library build without.\n");
950 fprintf(stderr
, "Cannot start CivetWeb - inconsistent build.\n");
954 /* Start CivetWeb web server */
955 memset(&callbacks
, 0, sizeof(callbacks
));
957 callbacks
.init_ssl
= init_ssl
;
959 callbacks
.log_message
= log_message
;
960 ctx
= mg_start(&callbacks
, 0, options
);
962 /* Check return value: */
964 fprintf(stderr
, "Cannot start CivetWeb - mg_start failed.\n");
968 /* Add handler EXAMPLE_URI, to explain the example */
969 mg_set_request_handler(ctx
, EXAMPLE_URI
, ExampleHandler
, 0);
970 mg_set_request_handler(ctx
, EXIT_URI
, ExitHandler
, 0);
972 /* Add handler for /A* and special handler for /A/B */
973 mg_set_request_handler(ctx
, "/A", AHandler
, 0);
974 mg_set_request_handler(ctx
, "/A/B", ABHandler
, 0);
976 /* Add handler for /B, /B/A, /B/B but not for /B* */
977 mg_set_request_handler(ctx
, "/B$", BXHandler
, (void *)0);
978 mg_set_request_handler(ctx
, "/B/A$", BXHandler
, (void *)1);
979 mg_set_request_handler(ctx
, "/B/B$", BXHandler
, (void *)2);
981 /* Add handler for all files with .foo extention */
982 mg_set_request_handler(ctx
, "**.foo$", FooHandler
, 0);
984 /* Add handler for /close extention */
985 mg_set_request_handler(ctx
, "/close", CloseHandler
, 0);
987 /* Add handler for /form (serve a file outside the document root) */
988 mg_set_request_handler(ctx
,
991 (void *)"../../test/form.html");
993 /* Add handler for form data */
994 mg_set_request_handler(ctx
,
995 "/handle_form.embedded_c.example.callback",
999 /* Add a file upload handler for parsing files on the fly */
1000 mg_set_request_handler(ctx
,
1003 (void *)"/on_the_fly_form.md5.callback");
1004 mg_set_request_handler(ctx
,
1005 "/on_the_fly_form.md5.callback",
1009 /* Add handler for /cookie example */
1010 mg_set_request_handler(ctx
, "/cookie", CookieHandler
, 0);
1012 /* Add handler for /postresponse example */
1013 mg_set_request_handler(ctx
, "/postresponse", PostResponser
, 0);
1015 /* Add HTTP site to open a websocket connection */
1016 mg_set_request_handler(ctx
, "/websocket", WebSocketStartHandler
, 0);
1018 /* Add HTTP site with auth */
1019 mg_set_request_handler(ctx
, "/auth", AuthStartHandler
, 0);
1022 #ifdef USE_WEBSOCKET
1023 /* WS site for the websocket connection */
1024 mg_set_websocket_handler(ctx
,
1026 WebSocketConnectHandler
,
1027 WebSocketReadyHandler
,
1028 WebsocketDataHandler
,
1029 WebSocketCloseHandler
,
1033 /* List all listening ports */
1034 memset(ports
, 0, sizeof(ports
));
1035 port_cnt
= mg_get_server_ports(ctx
, 32, ports
);
1036 printf("\n%i listening ports:\n\n", port_cnt
);
1038 for (n
= 0; n
< port_cnt
&& n
< 32; n
++) {
1039 const char *proto
= ports
[n
].is_ssl
? "https" : "http";
1042 if ((ports
[n
].protocol
& 1) == 1) {
1045 printf("Browse files at %s://%s:%i/\n", proto
, host
, ports
[n
].port
);
1046 printf("Run example at %s://%s:%i%s\n",
1052 "Exit at %s://%s:%i%s\n", proto
, host
, ports
[n
].port
, EXIT_URI
);
1056 if ((ports
[n
].protocol
& 2) == 2) {
1059 printf("Browse files at %s://%s:%i/\n", proto
, host
, ports
[n
].port
);
1060 printf("Run example at %s://%s:%i%s\n",
1066 "Exit at %s://%s:%i%s\n", proto
, host
, ports
[n
].port
, EXIT_URI
);
1071 /* Wait until the server should be closed */
1078 #ifdef USE_WEBSOCKET
1079 InformWebsockets(ctx
);
1083 /* Stop the server */
1085 printf("Server stopped.\n");
1088 return EXIT_SUCCESS
;