| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 | /** Copyright (c) 2013-2016 the CivetWeb developers* Copyright (c) 2013 No Face Press, LLC* License http://opensource.org/licenses/mit-license.php MIT License*//* Simple example program on how to use CivetWeb embedded into a C program. */#ifdef _WIN32#include <Windows.h>#else#include <unistd.h>#endif#include <stdlib.h>#include <string.h>#include "civetweb.h"#define DOCUMENT_ROOT "."#ifdef NO_SSL#ifdef USE_IPV6#define PORT "[::]:8888"#else#define PORT "8888"#endif#else#ifdef USE_IPV6#define PORT "[::]:8888r,[::]:8843s,8884"#else#define PORT "8888r,8843s"#endif#endif#define EXAMPLE_URI "/example"#define EXIT_URI "/exit"int exitNow = 0;intExampleHandler(struct mg_connection *conn, void *cbdata){	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<html><body>");	mg_printf(conn, "<h2>This is an example text from a C handler</h2>");	mg_printf(	    conn,	    "<p>To see a page from the A handler <a href=\"A\">click A</a></p>");	mg_printf(conn,	          "<p>To see a page from the A handler <a href=\"A/A\">click "	          "A/A</a></p>");	mg_printf(conn,	          "<p>To see a page from the A/B handler <a "	          "href=\"A/B\">click A/B</a></p>");	mg_printf(conn,	          "<p>To see a page from the B handler (0) <a "	          "href=\"B\">click B</a></p>");	mg_printf(conn,	          "<p>To see a page from the B handler (1) <a "	          "href=\"B/A\">click B/A</a></p>");	mg_printf(conn,	          "<p>To see a page from the B handler (2) <a "	          "href=\"B/B\">click B/B</a></p>");	mg_printf(conn,	          "<p>To see a page from the *.foo handler <a "	          "href=\"xy.foo\">click xy.foo</a></p>");	mg_printf(conn,	          "<p>To see a page from the FileHandler handler <a "	          "href=\"form\">click form</a> (this is the form test page)</p>");#ifdef USE_WEBSOCKET	mg_printf(conn,	          "<p>To test websocket handler <a href=\"/websocket\">click "	          "websocket</a></p>");#endif	mg_printf(conn, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI);	mg_printf(conn, "</body></html>\n");	return 1;}intExitHandler(struct mg_connection *conn, void *cbdata){	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n");	mg_printf(conn, "Server will shut down.\n");	mg_printf(conn, "Bye!\n");	exitNow = 1;	return 1;}intAHandler(struct mg_connection *conn, void *cbdata){	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<html><body>");	mg_printf(conn, "<h2>This is the A handler!!!</h2>");	mg_printf(conn, "</body></html>\n");	return 1;}intABHandler(struct mg_connection *conn, void *cbdata){	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<html><body>");	mg_printf(conn, "<h2>This is the AB handler!!!</h2>");	mg_printf(conn, "</body></html>\n");	return 1;}intBXHandler(struct mg_connection *conn, void *cbdata){	/* Handler may access the request info using mg_get_request_info */	const struct mg_request_info *req_info = mg_get_request_info(conn);	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<html><body>");	mg_printf(conn, "<h2>This is the BX handler %p!!!</h2>", cbdata);	mg_printf(conn, "<p>The actual uri is %s</p>", req_info->uri);	mg_printf(conn, "</body></html>\n");	return 1;}intFooHandler(struct mg_connection *conn, void *cbdata){	/* Handler may access the request info using mg_get_request_info */	const struct mg_request_info *req_info = mg_get_request_info(conn);	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<html><body>");	mg_printf(conn, "<h2>This is the Foo handler!!!</h2>");	mg_printf(conn,	          "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",	          req_info->request_method,	          req_info->uri,	          req_info->http_version);	mg_printf(conn, "</body></html>\n");	return 1;}intFileHandler(struct mg_connection *conn, void *cbdata){	/* In this handler, we ignore the req_info and send the file "fileName". */	const char *fileName = (const char *)cbdata;	mg_send_file(conn, fileName);	return 1;}intfield_found(const char *key,            const char *filename,            char *path,            size_t pathlen,            void *user_data){	struct mg_connection *conn = (struct mg_connection *)user_data;	mg_printf(conn, "%s:\r\n", key);	if (filename && *filename) {#ifdef _WIN32		_snprintf(path, pathlen, "D:\\tmp\\%s", filename);#else		snprintf(path, pathlen, "/tmp/%s", filename);#endif		return FORM_FIELD_STORAGE_STORE;	}	return FORM_FIELD_STORAGE_GET;}intfield_get(const char *key, const char *value, size_t valuelen, void *user_data){	struct mg_connection *conn = (struct mg_connection *)user_data;	mg_printf(conn, "%s = ", key);	mg_write(conn, value, valuelen);	mg_printf(conn, "\r\n\r\n");	return 0;}intfield_stored(const char *path, size_t file_size, void *user_data){	struct mg_connection *conn = (struct mg_connection *)user_data;	mg_printf(conn,	          "stored as %s (%lu bytes)\r\n\r\n",	          path,	          (unsigned long)file_size);	return 0;}intFormHandler(struct mg_connection *conn, void *cbdata){	/* Handler may access the request info using mg_get_request_info */	const struct mg_request_info *req_info = mg_get_request_info(conn);	int ret;	struct mg_form_data_handler fdh = {field_found, field_get, field_stored, 0};	/* TODO: Checks before calling mg_handle_form_request ? */	(void)req_info;	mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n");	fdh.user_data = (void *)conn;	/* TODO: Handle the return value */	ret = mg_handle_form_request(conn, &fdh);	return 1;}intWebSocketStartHandler(struct mg_connection *conn, void *cbdata){	mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");	mg_printf(conn, "<!DOCTYPE html>\n");	mg_printf(conn, "<html>\n<head>\n");	mg_printf(conn, "<meta charset=\"UTF-8\">\n");	mg_printf(conn, "<title>Embedded websocket example</title>\n");#ifdef USE_WEBSOCKET	/* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...	 * xhtml style */	mg_printf(conn, "<script>\n");	mg_printf(	    conn,	    "function load() {\n"	    "  var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"	    "  connection = new WebSocket(wsproto + '//' + window.location.host + "	    "'/websocket');\n"	    "  websock_text_field = "	    "document.getElementById('websock_text_field');\n"	    "  connection.onmessage = function (e) {\n"	    "    websock_text_field.innerHTML=e.data;\n"	    "  }\n"	    "  connection.onerror = function (error) {\n"	    "    alert('WebSocket error');\n"	    "    connection.close();\n"	    "  }\n"	    "}\n");	/* mg_printf(conn, "]]></script>\n"); ... xhtml style */	mg_printf(conn, "</script>\n");	mg_printf(conn, "</head>\n<body onload=\"load()\">\n");	mg_printf(	    conn,	    "<div id='websock_text_field'>No websocket connection yet</div>\n");#else	mg_printf(conn, "</head>\n<body>\n");	mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");#endif	mg_printf(conn, "</body>\n</html>\n");	return 1;}#ifdef USE_WEBSOCKET/* MAX_WS_CLIENTS defines how many clients can connect to a websocket at the * same time. The value 5 is very small and used here only for demonstration; * it can be easily tested to connect more than MAX_WS_CLIENTS clients. * A real server should use a much higher number, or better use a dynamic list * of currently connected websocket clients. */#define MAX_WS_CLIENTS (5)struct t_ws_client {	struct mg_connection *conn;	int state;} static ws_clients[MAX_WS_CLIENTS];#define ASSERT(x)                                                              \	{                                                                          \		if (!(x)) {                                                            \			fprintf(stderr,                                                    \			        "Assertion failed in line %u\n",                           \			        (unsigned)__LINE__);                                       \		}                                                                      \	}intWebSocketConnectHandler(const struct mg_connection *conn, void *cbdata){	struct mg_context *ctx = mg_get_context(conn);	int reject = 1;	int i;	mg_lock_context(ctx);	for (i = 0; i < MAX_WS_CLIENTS; i++) {		if (ws_clients[i].conn == NULL) {			ws_clients[i].conn = (struct mg_connection *)conn;			ws_clients[i].state = 1;			mg_set_user_connection_data(conn, (void *)(ws_clients + i));			reject = 0;			break;		}	}	mg_unlock_context(ctx);	fprintf(stdout,	        "Websocket client %s\r\n\r\n",	        (reject ? "rejected" : "accepted"));	return reject;}voidWebSocketReadyHandler(struct mg_connection *conn, void *cbdata){	const char *text = "Hello from the websocket ready handler";	struct t_ws_client *client = mg_get_user_connection_data(conn);	mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));	fprintf(stdout, "Greeting message sent to websocket client\r\n\r\n");	ASSERT(client->conn == conn);	ASSERT(client->state == 1);	client->state = 2;}intWebsocketDataHandler(struct mg_connection *conn,                     int bits,                     char *data,                     size_t len,                     void *cbdata){	struct t_ws_client *client = mg_get_user_connection_data(conn);	ASSERT(client->conn == conn);	ASSERT(client->state >= 1);	fprintf(stdout, "Websocket got data:\r\n");	fwrite(data, len, 1, stdout);	fprintf(stdout, "\r\n\r\n");	return 1;}voidWebSocketCloseHandler(const struct mg_connection *conn, void *cbdata){	struct mg_context *ctx = mg_get_context(conn);	struct t_ws_client *client = mg_get_user_connection_data(conn);	ASSERT(client->conn == conn);	ASSERT(client->state >= 1);	mg_lock_context(ctx);	client->state = 0;	client->conn = NULL;	mg_unlock_context(ctx);	fprintf(stdout,	        "Client droped from the set of webserver connections\r\n\r\n");}voidInformWebsockets(struct mg_context *ctx){	static unsigned long cnt = 0;	char text[32];	int i;	sprintf(text, "%lu", ++cnt);	mg_lock_context(ctx);	for (i = 0; i < MAX_WS_CLIENTS; i++) {		if (ws_clients[i].state == 2) {			mg_websocket_write(ws_clients[i].conn,			                   WEBSOCKET_OPCODE_TEXT,			                   text,			                   strlen(text));		}	}	mg_unlock_context(ctx);}#endifintmain(int argc, char *argv[]){	const char *options[] = {"document_root",	                         DOCUMENT_ROOT,	                         "listening_ports",	                         PORT,	                         "request_timeout_ms",	                         "10000",	                         "error_log_file",	                         "error.log",#ifdef USE_WEBSOCKET	                         "websocket_timeout_ms",	                         "3600000",#endif#ifndef NO_SSL	                         "ssl_certificate",	                         "../../resources/cert/server.pem",#endif	                         0};	struct mg_callbacks callbacks;	struct mg_context *ctx;	struct mg_server_ports ports[32];	int port_cnt, n;	int err = 0;/* Check if libcivetweb has been built with all required features. */#ifdef USE_IPV6	if (!mg_check_feature(8)) {		fprintf(stderr,		        "Error: Embedded example built with IPv6 support, "		        "but civetweb library build without.\n");		err = 1;	}#endif#ifdef USE_WEBSOCKET	if (!mg_check_feature(16)) {		fprintf(stderr,		        "Error: Embedded example built with websocket support, "		        "but civetweb library build without.\n");		err = 1;	}#endif#ifndef NO_SSL	if (!mg_check_feature(2)) {		fprintf(stderr,		        "Error: Embedded example built with SSL support, "		        "but civetweb library build without.\n");		err = 1;	}#endif	if (err) {		fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");		return EXIT_FAILURE;	}	/* Start CivetWeb web server */	memset(&callbacks, 0, sizeof(callbacks));	ctx = mg_start(&callbacks, 0, options);	/* Add handler EXAMPLE_URI, to explain the example */	mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);	mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);	/* Add handler for /A* and special handler for /A/B */	mg_set_request_handler(ctx, "/A", AHandler, 0);	mg_set_request_handler(ctx, "/A/B", ABHandler, 0);	/* Add handler for /B, /B/A, /B/B but not for /B* */	mg_set_request_handler(ctx, "/B$", BXHandler, (void *)0);	mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)1);	mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)2);	/* Add handler for all files with .foo extention */	mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);	/* Add handler for /form  (serve a file outside the document root) */	mg_set_request_handler(ctx,	                       "/form",	                       FileHandler,	                       (void *)"../../test/form.html");	/* Add handler for form data */	mg_set_request_handler(ctx,	                       "/handle_form.embedded_c.example.callback",	                       FormHandler,	                       (void *)0);	/* Add HTTP site to open a websocket connection */	mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);#ifdef USE_WEBSOCKET	/* WS site for the websocket connection */	mg_set_websocket_handler(ctx,	                         "/websocket",	                         WebSocketConnectHandler,	                         WebSocketReadyHandler,	                         WebsocketDataHandler,	                         WebSocketCloseHandler,	                         0);#endif	/* List all listening ports */	memset(ports, 0, sizeof(ports));	port_cnt = mg_get_server_ports(ctx, 32, ports);	printf("\n%i listening ports:\n\n", port_cnt);	for (n = 0; n < port_cnt && n < 32; n++) {		const char *proto = ports[n].is_ssl ? "https" : "http";		const char *host;		if ((ports[n].protocol & 1) == 1) {			/* IPv4 */			host = "127.0.0.1";			printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);			printf("Run example at %s://%s:%i%s\n",			       proto,			       host,			       ports[n].port,			       EXAMPLE_URI);			printf(			    "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);			printf("\n");		}		if ((ports[n].protocol & 2) == 2) {			/* IPv6 */			host = "[::1]";			printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);			printf("Run example at %s://%s:%i%s\n",			       proto,			       host,			       ports[n].port,			       EXAMPLE_URI);			printf(			    "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);			printf("\n");		}	}	/* Wait until the server should be closed */	while (!exitNow) {#ifdef _WIN32		Sleep(1000);#else		sleep(1);#endif#ifdef USE_WEBSOCKET		InformWebsockets(ctx);#endif	}	/* Stop the server */	mg_stop(ctx);	printf("Server stopped.\n");	printf("Bye!\n");	return EXIT_SUCCESS;}
 |