added file-access and dir-access to cmd/http/httpd.c
This commit is contained in:
		
							
								
								
									
										23
									
								
								qse/cmd/http/httpd-mime.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								qse/cmd/http/httpd-mime.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | ############################################### | ||||||
|  | # this file defines various mime types that | ||||||
|  | # can be @included in a mime block. | ||||||
|  | # | ||||||
|  | # file entries are inspected first. | ||||||
|  | # then suffix entries are inspected. | ||||||
|  | # 'other' comes the last. | ||||||
|  | ############################################### | ||||||
|  |  | ||||||
|  | suffix ".htm" = "text/html"; | ||||||
|  | suffix ".html" = "text/html"; | ||||||
|  | suffix ".txt" = "text/plain"; | ||||||
|  | suffix ".css" = "text/css"; | ||||||
|  | suffix ".xml" = "text/xml"; | ||||||
|  | suffix ".js" = "application/javascript"; | ||||||
|  | suffix ".jpg" = "image/jpeg"; | ||||||
|  | suffix ".png" = "image/png"; | ||||||
|  |  | ||||||
|  | # use file to set the type for a particular file | ||||||
|  | #file "x.jpg" = "specific mime type"; | ||||||
|  |  | ||||||
|  | # other can override the built-in default. | ||||||
|  | #other = "default mime type"; | ||||||
| @ -8,6 +8,7 @@ | |||||||
| #include <qse/cmn/mbwc.h> | #include <qse/cmn/mbwc.h> | ||||||
| #include <qse/cmn/time.h> | #include <qse/cmn/time.h> | ||||||
| #include <qse/cmn/path.h> | #include <qse/cmn/path.h> | ||||||
|  | #include <qse/cmn/opt.h> | ||||||
|  |  | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <locale.h> | #include <locale.h> | ||||||
| @ -27,6 +28,7 @@ | |||||||
| #else | #else | ||||||
| #	include <unistd.h> | #	include <unistd.h> | ||||||
| #	include <errno.h> | #	include <errno.h> | ||||||
|  | #	include <fcntl.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| @ -38,17 +40,34 @@ | |||||||
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
| static qse_httpd_t* g_httpd = QSE_NULL; | static qse_httpd_t* g_httpd = QSE_NULL; | ||||||
|  | static const qse_char_t* g_cfgfile = QSE_NULL; | ||||||
|  | static int g_daemon = 0; | ||||||
|  |  | ||||||
| static void sigint (int sig) | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | typedef struct httpd_xtn_t httpd_xtn_t; | ||||||
|  | struct httpd_xtn_t | ||||||
|  | { | ||||||
|  | 	const  qse_char_t* cfgfile; | ||||||
|  | 	qse_xli_t* xli; | ||||||
|  | 	qse_httpd_impede_t orgimpede; | ||||||
|  | 	int impede_code; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | static void sig_stop (int sig) | ||||||
| { | { | ||||||
| 	if (g_httpd) qse_httpd_stop (g_httpd); | 	if (g_httpd) qse_httpd_stop (g_httpd); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void sighup (int sig) | static void sig_reconf (int sig) | ||||||
| { | { | ||||||
| 	if (g_httpd)  | 	if (g_httpd)  | ||||||
| 	{ | 	{ | ||||||
| 		/* arrange to intefere with httpd to perform reconfiguration */ | 		httpd_xtn_t* httpd_xtn; | ||||||
|  | 		httpd_xtn = qse_httpd_getxtnstd (g_httpd); | ||||||
|  | 		httpd_xtn->impede_code = sig; | ||||||
| 		qse_httpd_impede (g_httpd); | 		qse_httpd_impede (g_httpd); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -59,15 +78,25 @@ static void setup_signal_handlers () | |||||||
|  |  | ||||||
| #if defined(SIGINT) | #if defined(SIGINT) | ||||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
| 	act.sa_handler = sigint; | 	act.sa_handler = sig_stop; | ||||||
| 	sigaction (SIGINT, &act, QSE_NULL); | 	sigaction (SIGINT, &act, QSE_NULL); | ||||||
| #endif | #endif | ||||||
|  | #if defined(SIGTERM) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = sig_stop; | ||||||
|  | 	sigaction (SIGTERM, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(SIGHUP) | #if defined(SIGHUP) | ||||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
| 	act.sa_handler = sighup; | 	act.sa_handler = sig_reconf; | ||||||
| 	sigaction (SIGHUP, &act, QSE_NULL); | 	sigaction (SIGHUP, &act, QSE_NULL); | ||||||
| #endif | #endif | ||||||
|  | #if defined(SIGUSR1) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = sig_reconf; | ||||||
|  | 	sigaction (SIGUSR1, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(SIGPIPE) | #if defined(SIGPIPE) | ||||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
| @ -85,12 +114,22 @@ static void restore_signal_handlers () | |||||||
| 	act.sa_handler = SIG_DFL; | 	act.sa_handler = SIG_DFL; | ||||||
| 	sigaction (SIGINT, &act, QSE_NULL); | 	sigaction (SIGINT, &act, QSE_NULL); | ||||||
| #endif | #endif | ||||||
|  | #if defined(SIGTERM) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = SIG_DFL; | ||||||
|  | 	sigaction (SIGTERM, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(SIGHUP) | #if defined(SIGHUP) | ||||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
| 	act.sa_handler = SIG_DFL; | 	act.sa_handler = SIG_DFL; | ||||||
| 	sigaction (SIGHUP, &act, QSE_NULL); | 	sigaction (SIGHUP, &act, QSE_NULL); | ||||||
| #endif | #endif | ||||||
|  | #if defined(SIGUSR1) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = SIG_DFL; | ||||||
|  | 	sigaction (SIGUSR1, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(SIGPIPE) | #if defined(SIGPIPE) | ||||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
| @ -99,6 +138,43 @@ static void restore_signal_handlers () | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int daemonize (int devnull) | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #if defined(HAVE_FORK) | ||||||
|  | 	switch (fork()) | ||||||
|  | 	{ | ||||||
|  | 		case -1: return -1; | ||||||
|  | 		case 0: break; /* child */ | ||||||
|  | 		default: _exit (0); /* parent */ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (setsid () <= -1) return -1; | ||||||
|  |  | ||||||
|  | 	/*umask (0);*/ | ||||||
|  | 	chdir ("/"); | ||||||
|  |  | ||||||
|  | 	if (devnull) | ||||||
|  | 	{ | ||||||
|  | 		/* redirect stdin/out/err to /dev/null */ | ||||||
|  | 		int fd = open ("/dev/null", O_RDWR);	 | ||||||
|  | 		if (fd >= 0) | ||||||
|  | 		{ | ||||||
|  | 			dup2 (fd, 0); | ||||||
|  | 			dup2 (fd, 1); | ||||||
|  | 			dup2 (fd, 2); | ||||||
|  | 			close (fd); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | 	return -1; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
| enum | enum | ||||||
| @ -117,8 +193,7 @@ struct cgi_t | |||||||
| { | { | ||||||
| 	enum { | 	enum { | ||||||
| 		CGI_SUFFIX, | 		CGI_SUFFIX, | ||||||
| 		CGI_FILE, | 		CGI_NAME, | ||||||
|  |  | ||||||
| 		CGI_MAX | 		CGI_MAX | ||||||
| 	} type; | 	} type; | ||||||
|  |  | ||||||
| @ -133,8 +208,8 @@ struct mime_t | |||||||
| { | { | ||||||
| 	enum { | 	enum { | ||||||
| 		MIME_SUFFIX, | 		MIME_SUFFIX, | ||||||
| 		MIME_FILE, | 		MIME_NAME, | ||||||
|  | 		MIME_OTHER, | ||||||
| 		MIME_MAX | 		MIME_MAX | ||||||
| 	} type; | 	} type; | ||||||
|  |  | ||||||
| @ -144,6 +219,23 @@ struct mime_t | |||||||
| 	struct mime_t* next; | 	struct mime_t* next; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct access_t | ||||||
|  | { | ||||||
|  | 	/* TODO: support more types like ACCESS_GLOB  | ||||||
|  | 	         not-only the base name, find a way to use query path or xpath */ | ||||||
|  | 	enum { | ||||||
|  | 		ACCESS_SUFFIX, | ||||||
|  | 		ACCESS_NAME, | ||||||
|  | 		ACCESS_OTHER, | ||||||
|  | 		ACCESS_MAX | ||||||
|  | 	} type; | ||||||
|  |  | ||||||
|  | 	qse_mchar_t* spec; | ||||||
|  | 	int value; | ||||||
|  |  | ||||||
|  | 	struct access_t* next; | ||||||
|  | }; | ||||||
|  |  | ||||||
| typedef struct server_xtn_t server_xtn_t; | typedef struct server_xtn_t server_xtn_t; | ||||||
| struct server_xtn_t | struct server_xtn_t | ||||||
| { | { | ||||||
| @ -176,15 +268,14 @@ struct server_xtn_t | |||||||
| 		struct mime_t* head; | 		struct mime_t* head; | ||||||
| 		struct mime_t* tail; | 		struct mime_t* tail; | ||||||
| 	} mime[MIME_MAX]; | 	} mime[MIME_MAX]; | ||||||
|  |  | ||||||
|  | 	struct | ||||||
|  | 	{ | ||||||
|  | 		struct access_t* head; | ||||||
|  | 		struct access_t* tail; | ||||||
|  | 	} access[2][ACCESS_MAX]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef struct httpd_xtn_t httpd_xtn_t; |  | ||||||
| struct httpd_xtn_t |  | ||||||
| { |  | ||||||
| 	const  qse_char_t* cfgfile; |  | ||||||
| 	qse_xli_t* xli; |  | ||||||
| 	qse_httpd_impede_t orgimpede; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static int make_resource ( | static int make_resource ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, | 	qse_httpd_t* httpd, qse_httpd_client_t* client, | ||||||
| @ -253,7 +344,7 @@ static void free_resource ( | |||||||
| static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server) | static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| { | { | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	qse_size_t i; | 	qse_size_t i, j; | ||||||
|  |  | ||||||
| 	server_xtn = qse_httpd_getserverstdxtn (httpd, server); | 	server_xtn = qse_httpd_getserverstdxtn (httpd, server); | ||||||
|  |  | ||||||
| @ -306,6 +397,25 @@ static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 		server_xtn->mime[i].head = QSE_NULL; | 		server_xtn->mime[i].head = QSE_NULL; | ||||||
| 		server_xtn->mime[i].tail = QSE_NULL; | 		server_xtn->mime[i].tail = QSE_NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	for (j = 0; j < QSE_COUNTOF(server_xtn->access); j++) | ||||||
|  | 	{ | ||||||
|  | 		for (i = 0; i < QSE_COUNTOF(server_xtn->access[j]); i++) | ||||||
|  | 		{ | ||||||
|  | 			struct access_t* access = server_xtn->access[j][i].head; | ||||||
|  | 			while (access) | ||||||
|  | 			{ | ||||||
|  | 				struct access_t* x = access; | ||||||
|  | 				access = x->next; | ||||||
|  |  | ||||||
|  | 				if (x->spec) qse_httpd_freemem (httpd, x->spec); | ||||||
|  | 				if (x) qse_httpd_freemem (httpd, x); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			server_xtn->access[j][i].head = QSE_NULL; | ||||||
|  | 			server_xtn->access[j][i].tail = QSE_NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static void detach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | static void detach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| @ -369,8 +479,8 @@ static int query_server ( | |||||||
| 				struct cgi_t* cgi; | 				struct cgi_t* cgi; | ||||||
| 				for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next) | 				for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next) | ||||||
| 				{ | 				{ | ||||||
| 					if ((cgi->type == MIME_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) || | 					if ((cgi->type == CGI_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) || | ||||||
| 					    (cgi->type == MIME_FILE && qse_mbscmp (xpath_base, cgi->spec) == 0)) | 					    (cgi->type == CGI_NAME && qse_mbscmp (xpath_base, cgi->spec) == 0)) | ||||||
| 					{ | 					{ | ||||||
| 						scgi->cgi = 1; | 						scgi->cgi = 1; | ||||||
| 						scgi->nph = cgi->nph;		 | 						scgi->nph = cgi->nph;		 | ||||||
| @ -386,7 +496,7 @@ static int query_server ( | |||||||
| 		case QSE_HTTPD_SERVERSTD_MIME: | 		case QSE_HTTPD_SERVERSTD_MIME: | ||||||
| 		{ | 		{ | ||||||
| 			qse_size_t i; | 			qse_size_t i; | ||||||
| 			qse_mchar_t* xpath_base; | 			const qse_mchar_t* xpath_base; | ||||||
|  |  | ||||||
| 			xpath_base = qse_mbsbasename (xpath); | 			xpath_base = qse_mbsbasename (xpath); | ||||||
|  |  | ||||||
| @ -397,7 +507,8 @@ static int query_server ( | |||||||
| 				for (mime = server_xtn->mime[i].head; mime; mime = mime->next) | 				for (mime = server_xtn->mime[i].head; mime; mime = mime->next) | ||||||
| 				{ | 				{ | ||||||
| 					if ((mime->type == MIME_SUFFIX && qse_mbsend (xpath_base, mime->spec)) || | 					if ((mime->type == MIME_SUFFIX && qse_mbsend (xpath_base, mime->spec)) || | ||||||
| 					    (mime->type == MIME_FILE && qse_mbscmp (xpath_base, mime->spec) == 0)) | 					    (mime->type == MIME_NAME && qse_mbscmp (xpath_base, mime->spec) == 0) || | ||||||
|  | 					    mime->type == MIME_OTHER) | ||||||
| 					{ | 					{ | ||||||
| 						*(const qse_mchar_t**)result = mime->value; | 						*(const qse_mchar_t**)result = mime->value; | ||||||
| 						return 0; | 						return 0; | ||||||
| @ -406,6 +517,35 @@ static int query_server ( | |||||||
| 			} | 			} | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_DIRACC: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_FILEACC: | ||||||
|  | 		{ | ||||||
|  | 			qse_size_t i; | ||||||
|  | 			const qse_mchar_t* xpath_base; | ||||||
|  | 			int id; | ||||||
|  |  | ||||||
|  | 			id = (code == QSE_HTTPD_SERVERSTD_DIRACC)? 0: 1; | ||||||
|  |  | ||||||
|  | 			xpath_base = qse_mbsbasename (xpath); | ||||||
|  |  | ||||||
|  | 			*(int*)result = 200; | ||||||
|  | 			for (i = 0; i < QSE_COUNTOF(server_xtn->access[id]); i++) | ||||||
|  | 			{ | ||||||
|  | 				struct access_t* access; | ||||||
|  | 				for (access = server_xtn->access[id][i].head; access; access = access->next) | ||||||
|  | 				{ | ||||||
|  | 					if ((access->type == ACCESS_SUFFIX && qse_mbsend (xpath_base, access->spec)) || | ||||||
|  | 					    (access->type == ACCESS_NAME && qse_mbscmp (xpath_base, access->spec) == 0) || | ||||||
|  | 					    access->type == ACCESS_OTHER) | ||||||
|  | 					{ | ||||||
|  | 						*(int*)result = access->value; | ||||||
|  | 						return 0; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return server_xtn->orgquery (httpd, server, req, xpath, code, result); | 	return server_xtn->orgquery (httpd, server, req, xpath, code, result); | ||||||
| @ -498,9 +638,9 @@ static int load_server_config ( | |||||||
| 				{ | 				{ | ||||||
| 					type = CGI_SUFFIX; | 					type = CGI_SUFFIX; | ||||||
| 				} | 				} | ||||||
| 				else if (qse_strcmp (pair->key, QSE_T("file")) == 0) | 				else if (qse_strcmp (pair->key, QSE_T("name")) == 0) | ||||||
| 				{ | 				{ | ||||||
| 					type = CGI_FILE; | 					type = CGI_NAME; | ||||||
| 				} | 				} | ||||||
| 				else continue; | 				else continue; | ||||||
|  |  | ||||||
| @ -570,13 +710,14 @@ static int load_server_config ( | |||||||
| 			if (atom->type != QSE_XLI_PAIR) continue; | 			if (atom->type != QSE_XLI_PAIR) continue; | ||||||
|  |  | ||||||
| 			pair = (qse_xli_pair_t*)atom; | 			pair = (qse_xli_pair_t*)atom; | ||||||
| 			if (pair->key && pair->name && pair->val->type == QSE_XLI_STR) | 			if (pair->key && pair->val->type == QSE_XLI_STR) | ||||||
| 			{ | 			{ | ||||||
| 				struct mime_t* mime; | 				struct mime_t* mime; | ||||||
| 				int type; | 				int type; | ||||||
|  |  | ||||||
| 				if (qse_strcmp (pair->key, QSE_T("suffix")) == 0) type = MIME_SUFFIX; | 				if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = MIME_SUFFIX; | ||||||
| 				else if (qse_strcmp (pair->key, QSE_T("file")) == 0) type = MIME_FILE; | 				else if (qse_strcmp (pair->key, QSE_T("name")) == 0 && pair->name) type = MIME_NAME; | ||||||
|  | 				else if (qse_strcmp (pair->key, QSE_T("other")) == 0 && !pair->name) type = MIME_OTHER; | ||||||
| 				else continue; | 				else continue; | ||||||
|  |  | ||||||
| 				mime = qse_httpd_callocmem (httpd, QSE_SIZEOF(*mime)); | 				mime = qse_httpd_callocmem (httpd, QSE_SIZEOF(*mime)); | ||||||
| @ -594,20 +735,16 @@ static int load_server_config ( | |||||||
| 					qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); | 					qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 				if (pair->val->type == QSE_XLI_STR)  |  | ||||||
|  | 				mime->value = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 				if (!mime->value) | ||||||
| 				{ | 				{ | ||||||
| 					mime->value = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | 					qse_httpd_freemem (httpd, mime->spec); | ||||||
| 					if (!mime->value) | 					qse_httpd_freemem (httpd, mime); | ||||||
| 					{ | 					qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); | ||||||
| 						qse_httpd_freemem (httpd, mime->spec); | 					return -1; | ||||||
| 						qse_httpd_freemem (httpd, mime); |  | ||||||
| 						qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); |  | ||||||
| 						return -1; |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					/* TODO: more sanity check */ |  | ||||||
|  |  | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (server_xtn->mime[type].tail) | 				if (server_xtn->mime[type].tail) | ||||||
| 					server_xtn->mime[type].tail->next = mime; | 					server_xtn->mime[type].tail->next = mime; | ||||||
| 				else | 				else | ||||||
| @ -617,6 +754,76 @@ static int load_server_config ( | |||||||
| 		}	 | 		}	 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < 2;  i++) | ||||||
|  | 	{ | ||||||
|  | 		static struct  | ||||||
|  | 		{ | ||||||
|  | 			const qse_char_t* x; | ||||||
|  | 			const qse_char_t* y; | ||||||
|  | 		} acc_items[] = | ||||||
|  | 		{ | ||||||
|  | 			{ QSE_T("host['*'].location['/'].dir-access"), QSE_T("default.dir-access") }, | ||||||
|  | 			{ QSE_T("host['*'].location['/'].file-access"), QSE_T("default.file-access") }, | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		pair = qse_xli_findpairbyname (httpd_xtn->xli, list, acc_items[i].x); | ||||||
|  | 		if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, acc_items[i].y); | ||||||
|  | 		if (pair && pair->val->type == QSE_XLI_LIST) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_list_t* acclist = (qse_xli_list_t*)pair->val; | ||||||
|  | 			for (atom = acclist->head; atom; atom = atom->next) | ||||||
|  | 			{ | ||||||
|  | 				if (atom->type != QSE_XLI_PAIR) continue; | ||||||
|  | 	 | ||||||
|  | 				pair = (qse_xli_pair_t*)atom; | ||||||
|  | 				if (pair->key && pair->val->type == QSE_XLI_STR) | ||||||
|  | 				{ | ||||||
|  | 					struct access_t* acc; | ||||||
|  | 					const qse_char_t* tmp; | ||||||
|  | 					int type, value; | ||||||
|  | 	 | ||||||
|  | 					if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = ACCESS_SUFFIX; | ||||||
|  | 					else if (qse_strcmp (pair->key, QSE_T("name")) == 0 && pair->name) type = ACCESS_NAME; | ||||||
|  | 					else if (qse_strcmp (pair->key, QSE_T("other")) == 0 && !pair->name) type = ACCESS_OTHER; | ||||||
|  | 					else continue; | ||||||
|  | 	 | ||||||
|  | 					tmp = ((qse_xli_str_t*)pair->val)->ptr; | ||||||
|  | 					if (qse_strcmp (tmp, QSE_T("noent")) == 0) value = 404; | ||||||
|  | 					else if (qse_strcmp (tmp, QSE_T("forbid")) == 0) value = 403; | ||||||
|  | 					else if (qse_strcmp (tmp, QSE_T("ok")) == 0) value = 200; | ||||||
|  | 					else continue; | ||||||
|  | 					/* TODO: more sanity check */ | ||||||
|  | 	 | ||||||
|  | 					acc = qse_httpd_callocmem (httpd, QSE_SIZEOF(*acc)); | ||||||
|  | 					if (acc == QSE_NULL) | ||||||
|  | 					{ | ||||||
|  | 						qse_printf (QSE_T("ERROR: memory failure in copying acc\n")); | ||||||
|  | 						return -1; | ||||||
|  | 					} | ||||||
|  | 	 | ||||||
|  | 					acc->type = type; | ||||||
|  | 					if (pair->name) | ||||||
|  | 					{ | ||||||
|  | 						acc->spec = qse_httpd_strtombsdup (httpd, pair->name); | ||||||
|  | 						if (!acc->spec) | ||||||
|  | 						{ | ||||||
|  | 							qse_httpd_freemem (httpd, acc); | ||||||
|  | 							qse_printf (QSE_T("ERROR: memory failure in copying access\n")); | ||||||
|  | 							return -1; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					acc->value = value; | ||||||
|  | 	 | ||||||
|  | 					if (server_xtn->access[i][type].tail) | ||||||
|  | 						server_xtn->access[i][type].tail->next = acc; | ||||||
|  | 					else | ||||||
|  | 						server_xtn->access[i][type].head = acc; | ||||||
|  | 					server_xtn->access[i][type].tail = acc; | ||||||
|  | 				} | ||||||
|  | 			}	 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/* perform more sanity check */ | 	/* perform more sanity check */ | ||||||
| 	if (qse_mbschr (server_xtn->scfg[SCFG_AUTH], QSE_MT(':')) == QSE_NULL) | 	if (qse_mbschr (server_xtn->scfg[SCFG_AUTH], QSE_MT(':')) == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| @ -844,58 +1051,171 @@ static void impede_httpd (qse_httpd_t* httpd) | |||||||
| 	if (httpd_xtn->orgimpede) httpd_xtn->orgimpede (httpd); | 	if (httpd_xtn->orgimpede) httpd_xtn->orgimpede (httpd); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void logact_httpd (qse_httpd_t* httpd, qse_httpd_act_t* act) | static void logact_httpd (qse_httpd_t* httpd, const qse_httpd_act_t* act) | ||||||
| { | { | ||||||
| 	httpd_xtn_t* httpd_xtn; | 	httpd_xtn_t* httpd_xtn; | ||||||
| 	qse_char_t tmp[256]; | 	qse_char_t tmp[128], tmp2[128], tmp3[128]; | ||||||
|  |  | ||||||
| 	httpd_xtn = qse_httpd_getxtnstd (httpd); | 	httpd_xtn = qse_httpd_getxtnstd (httpd); | ||||||
|  |  | ||||||
| 	switch (act->code) | 	switch (act->code) | ||||||
| 	{ | 	{ | ||||||
| 		case QSE_HTTPD_ACCEPT_CLIENT: | 		case QSE_HTTPD_CATCH_MERRMSG: | ||||||
|  | 			qse_printf (QSE_T("ERROR: %hs\n"), act->u.merrmsg); | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_CATCH_MDBGMSG: | ||||||
|  | 			qse_printf (QSE_T("DEBUG: %hs\n"), act->u.mdbgmsg); | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_ACCEPT_CLIENT: | ||||||
|  | 			qse_nwadtostr (&act->u.client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | ||||||
|  | 			qse_nwadtostr (&act->u.client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); | ||||||
|  | 			qse_nwadtostr (&act->u.client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL); | ||||||
|  | 			qse_printf (QSE_T("accepted client %s(%s) from %s\n"), tmp, tmp2, tmp3); | ||||||
|  |  | ||||||
| 		case QSE_HTTPD_PURGE_CLIENT: | 		case QSE_HTTPD_PURGE_CLIENT: | ||||||
| 			qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | 			qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | ||||||
| 			qse_printf (QSE_T("purged client from %s\n"), tmp); | 			qse_printf (QSE_T("purged client - %s\n"), tmp); | ||||||
|  | 			break;		 | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_READERR_CLIENT: | ||||||
|  | 			qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | ||||||
|  | 			qse_printf (QSE_T("failed to read client - %s\n"), tmp); | ||||||
| 			break;		 | 			break;		 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ | ||||||
|  | static void print_version (void) | ||||||
|  | { | ||||||
|  | 	qse_printf (QSE_T("QSEHTTPD version %hs\n"), QSE_PACKAGE_VERSION); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[]) | ||||||
|  | { | ||||||
|  | 	const qse_char_t* b = qse_basename (argv[0]); | ||||||
|  |  | ||||||
|  | 	qse_fprintf (out, QSE_T("USAGE: %s [options] -c file\n"), b); | ||||||
|  | 	qse_fprintf (out, QSE_T("       %s [options] --config-file file\n"), b); | ||||||
|  |  | ||||||
|  | 	qse_fprintf (out, QSE_T("options as follows:\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" -h/--help                 show this message\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" --version                 show version\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" -c/--config-file file     specify a configuration file\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" -d/--daemon               run in the background\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int handle_args (int argc, qse_char_t* argv[]) | ||||||
|  | { | ||||||
|  | 	static qse_opt_lng_t lng[] =  | ||||||
|  | 	{ | ||||||
|  | 		{ QSE_T(":config-file"),     QSE_T('c') }, | ||||||
|  | 		{ QSE_T("daemon"),           QSE_T('d') }, | ||||||
|  | 		{ QSE_T("help"),             QSE_T('h') }, | ||||||
|  | 		{ QSE_T("version"),          QSE_T('\0') }, | ||||||
|  | 		{ QSE_NULL,                  QSE_T('\0') }                   | ||||||
|  | 	}; | ||||||
|  | 	static qse_opt_t opt =  | ||||||
|  | 	{ | ||||||
|  | 		QSE_T("c:dh"), | ||||||
|  | 		lng | ||||||
|  | 	}; | ||||||
|  | 	qse_cint_t c; | ||||||
|  |  | ||||||
|  | 	while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF) | ||||||
|  | 	{ | ||||||
|  | 		switch (c) | ||||||
|  | 		{ | ||||||
|  | 			default: | ||||||
|  | 				goto wrongusage; | ||||||
|  |  | ||||||
|  | 			case QSE_T('?'): | ||||||
|  | 				qse_fprintf (QSE_STDERR,  | ||||||
|  | 					QSE_T("ERROR: bad option - %c\n"), | ||||||
|  | 					opt.opt | ||||||
|  | 				); | ||||||
|  | 				goto wrongusage; | ||||||
|  |  | ||||||
|  | 			case QSE_T(':'): | ||||||
|  | 				qse_fprintf (QSE_STDERR,  | ||||||
|  | 					QSE_T("ERROR: bad parameter for %c\n"), | ||||||
|  | 					opt.opt | ||||||
|  | 				); | ||||||
|  | 				goto wrongusage; | ||||||
|  |  | ||||||
|  | 			case QSE_T('c'): | ||||||
|  | 				g_cfgfile = opt.arg; | ||||||
|  | 				break; | ||||||
|  |  | ||||||
|  | 			case QSE_T('d'): | ||||||
|  | 				g_daemon = 1; | ||||||
|  | 				break; | ||||||
|  |  | ||||||
|  | 			case QSE_T('h'): | ||||||
|  | 				print_usage (QSE_STDOUT, argc, argv); | ||||||
|  | 				return 0; | ||||||
|  |  | ||||||
|  | 			case QSE_T('\0'): | ||||||
|  | 			{ | ||||||
|  | 				if (qse_strcmp(opt.lngopt, QSE_T("version")) == 0) | ||||||
|  | 				{ | ||||||
|  | 					print_version (); | ||||||
|  | 					return 0; | ||||||
|  |                     } | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (opt.ind < argc || g_cfgfile == QSE_NULL) goto wrongusage; | ||||||
|  |  | ||||||
|  | 	return 1; | ||||||
|  |  | ||||||
|  | wrongusage: | ||||||
|  | 	print_usage (QSE_STDERR, argc, argv); | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int httpd_main (int argc, qse_char_t* argv[]) | static int httpd_main (int argc, qse_char_t* argv[]) | ||||||
| { | { | ||||||
| 	qse_httpd_t* httpd = QSE_NULL; | 	qse_httpd_t* httpd = QSE_NULL; | ||||||
| 	httpd_xtn_t* httpd_xtn; | 	httpd_xtn_t* httpd_xtn; | ||||||
| 	qse_ntime_t tmout; | 	qse_ntime_t tmout; | ||||||
| 	int trait, ret = -1; | 	int trait, ret; | ||||||
| 	qse_httpd_rcb_t rcb; | 	qse_httpd_rcb_t rcb; | ||||||
|  |  | ||||||
| 	if (argc != 2) | 	ret = handle_args (argc, argv); | ||||||
| 	{ | 	if (ret <= -1) return -1; | ||||||
| 		/* TODO: proper check... */ | 	if (ret == 0) return 0; | ||||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]); |  | ||||||
| 		goto oops; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t)); | 	httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t)); | ||||||
| 	if (httpd == QSE_NULL) | 	if (httpd == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n")); | 		qse_fprintf (QSE_STDERR, QSE_T("ERROR: Cannot open httpd\n")); | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	httpd_xtn = qse_httpd_getxtnstd (httpd); | 	httpd_xtn = qse_httpd_getxtnstd (httpd); | ||||||
| 	httpd_xtn->cfgfile = argv[1]; | 	httpd_xtn->cfgfile = g_cfgfile; | ||||||
|  |  | ||||||
| 	if (load_config (httpd) <= -1) goto oops; | 	if (load_config (httpd) <= -1) goto oops; | ||||||
|  |  | ||||||
|  | 	if (g_daemon) | ||||||
|  | 	{ | ||||||
|  | 		if (daemonize (1) <= -1) | ||||||
|  | 		{ | ||||||
|  | 			qse_fprintf (QSE_STDERR, QSE_T("ERROR: Cannot daemonize\n")); | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	g_httpd = httpd; | 	g_httpd = httpd; | ||||||
| 	setup_signal_handlers (); | 	setup_signal_handlers (); | ||||||
|  |  | ||||||
| 	qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait); | 	qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait); | ||||||
| 	trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_ENABLELOG; | 	trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_LOGACT; | ||||||
| 	qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait); | 	qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait); | ||||||
|  |  | ||||||
| 	tmout.sec = 10; | 	tmout.sec = 10; | ||||||
| @ -921,7 +1241,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) | |||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	if (httpd) qse_httpd_close (httpd); | 	if (httpd) qse_httpd_close (httpd); | ||||||
| 	return ret; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| int qse_main (int argc, qse_achar_t* argv[]) | int qse_main (int argc, qse_achar_t* argv[]) | ||||||
|  | |||||||
| @ -2,43 +2,119 @@ | |||||||
| # this is a sample configuration file for qsehttpd. | # this is a sample configuration file for qsehttpd. | ||||||
| # | # | ||||||
|  |  | ||||||
| server { | default { | ||||||
| 	bind = "0.0.0.0:80"; | 	# the default name is used in http headers and in pages  | ||||||
|  | 	# generated by httpd. | ||||||
|  | 	name = "QSEHTTPD v1"; | ||||||
|  |  | ||||||
| 	ssl { | 	docroot = "/"; | ||||||
| 		certificate { |  | ||||||
| 			private = "xxxx"; |  | ||||||
| 			public = "xxxx"; |  | ||||||
| 		}		 |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	root = "/home/www/default"; | 	realm = "default realm"; | ||||||
| 	option = "xxxx,xxx,xxxx"; | 	auth = "username:password";	 | ||||||
|  | 	index = "index.ant", | ||||||
| 	realm { | 	        "index.html", | ||||||
| 		name = "xxxxxx"; | 	        "index.cgi"; | ||||||
| 		password = "zzzzzzzzzzzzzzzz"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cgi { | 	cgi { | ||||||
| 		suffix ".ant" = "xxxxx"; | 		name "t3.nph" = "nph"; | ||||||
| 		suffix ".cgi"; | 		suffix ".cgi"; | ||||||
| 		suffix ".nph"; | 		suffix ".ant" = "nph", ""; | ||||||
|  | 		suffix ".awk" = "cgi", "/usr/bin/qseawk -f"; | ||||||
|  |  | ||||||
|  | 		# glob is not supported yet | ||||||
|  | 		# glob "x*.xxx"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	mime { | 	mime { | ||||||
| 		suffix ".jpg" = "image/picture"; | 		@include "httpd-mime.conf"; | ||||||
| 		suffix ".txt" = "text/plain"; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	# virtual host | 	# control access to directories | ||||||
| 	host "www.google.com" { | 	dir-access { | ||||||
| 		root = "/home/www/google";	 | 		# suffix ".xxxx" = ok; | ||||||
| 		option = "xxx, xxx, xxxx"; | 		# name "xxxxx" = ok; | ||||||
|  | 		other = noent; | ||||||
| 		realm { |  | ||||||
| 			name = "www.google.com"; |  | ||||||
| 			password = "zzzzzzzzzzzzzzzz"; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	# control access to normal files. | ||||||
|  | 	# cgi scripts are not control by these. | ||||||
|  | 	file-access { | ||||||
|  | 		suffix ".html" = ok; | ||||||
|  | 		suffix ".css" = ok; | ||||||
|  | 		suffix ".js" = ok; | ||||||
|  | 		suffix ".png" = ok; | ||||||
|  | 		suffix ".jpg" = ok; | ||||||
|  | 		other = noent; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	dir-css = "<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; } table { font-size: 0.9em; } td { white-space: nowrap; } td.size { text-align: right; }</style>"; | ||||||
|  | 	error-css = "<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; }</style>"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | server { | ||||||
|  | 	bind = "0.0.0.0:1999"; | ||||||
|  |  | ||||||
|  | 	# ssl is not supported yet. | ||||||
|  | 	#ssl { | ||||||
|  | 	#	certificate { | ||||||
|  | 	#		private = "xxxx"; | ||||||
|  | 	#		public = "xxxx"; | ||||||
|  | 	#	}		 | ||||||
|  | 	#} | ||||||
|  | 	 | ||||||
|  | 	host "*" { | ||||||
|  | 		location "/" { | ||||||
|  | 			# the location-specific name is used in pages | ||||||
|  | 			# generated by httpd, not in http headers. | ||||||
|  | 			# you can't override the default name for use in  | ||||||
|  | 			# http headers. | ||||||
|  | 			#name = "QSEHTTPD v1"; | ||||||
|  |  | ||||||
|  | 			# uncomment the followng block to override the default. | ||||||
|  | 			#docroot = "/var/www"; | ||||||
|  |  | ||||||
|  | 			# uncomment the followng block to override the default. | ||||||
|  | 			# if you want to disable authentication while the default | ||||||
|  | 			# enables it, don't put a value like 'realm;' | ||||||
|  | 			#realm = "default realm"; | ||||||
|  | 			#auth = "username:password"; | ||||||
|  |  | ||||||
|  | 			# uncomment the following block to override the default | ||||||
|  | 			#index = "index.cgi", "index.html"; | ||||||
|  |  | ||||||
|  | 			# uncomment the following block to override the default | ||||||
|  | 			#cgi { | ||||||
|  | 			#	suffix ".cgi"; | ||||||
|  | 			#	suffix ".awk" = "/usr/bin/qseawk -f"; | ||||||
|  | 			#} | ||||||
|  |  | ||||||
|  | 			# uncomment the following block to override the default. | ||||||
|  | 			#mime { | ||||||
|  | 			#	suffix ".htm" = "text/html"; | ||||||
|  | 			#	suffix ".html" = "text/html"; | ||||||
|  | 			#	suffix ".txt" = "text/html"; | ||||||
|  | 			#	suffix ".css" = "text/css"; | ||||||
|  | 			#	suffix ".xml" = "text/xml"; | ||||||
|  | 			#	suffix ".js" = "application/javascript"; | ||||||
|  | 			#	suffix ".jpg" = "image/jpeg"; | ||||||
|  | 			#	suffix ".png" = "image/png"; | ||||||
|  | 			#} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		# other locations than / are not supported yet. | ||||||
|  | 		#location "/help"  { | ||||||
|  | 		#} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	# virtual hosts are not supported yet. | ||||||
|  | 	#host "www.google.com" { | ||||||
|  | 	#	location "/" { | ||||||
|  | 	#		docroot = "/home/www/google";	 | ||||||
|  | 	#		auth { | ||||||
|  | 	#			realm = "jjjjjjjj"; | ||||||
|  | 	#			name = "www.google.com"; | ||||||
|  | 	#			password = "zzzzzzzzzzzzzzzz"; | ||||||
|  | 	#		} | ||||||
|  | 	#	} | ||||||
|  | 	#} | ||||||
| } | } | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ enum qse_httpd_trait_t | |||||||
| 	QSE_HTTPD_CGIERRTONUL  = (1 << 1), | 	QSE_HTTPD_CGIERRTONUL  = (1 << 1), | ||||||
| 	QSE_HTTPD_CGINOCLOEXEC = (1 << 2), | 	QSE_HTTPD_CGINOCLOEXEC = (1 << 2), | ||||||
| 	QSE_HTTPD_CGINOCHUNKED = (1 << 3), | 	QSE_HTTPD_CGINOCHUNKED = (1 << 3), | ||||||
| 	QSE_HTTPD_ENABLELOG    = (1 << 4)       | 	QSE_HTTPD_LOGACT       = (1 << 4) | ||||||
| }; | }; | ||||||
| typedef enum qse_httpd_trait_t qse_httpd_trait_t; | typedef enum qse_httpd_trait_t qse_httpd_trait_t; | ||||||
|  |  | ||||||
| @ -115,8 +115,8 @@ typedef struct qse_httpd_dirent_t qse_httpd_dirent_t; | |||||||
|  |  | ||||||
| struct qse_httpd_dirent_t | struct qse_httpd_dirent_t | ||||||
| { | { | ||||||
| 	qse_mchar_t*     name; | 	const qse_mchar_t* name; | ||||||
| 	qse_httpd_stat_t stat; | 	qse_httpd_stat_t   stat; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef struct qse_httpd_scb_t qse_httpd_scb_t; | typedef struct qse_httpd_scb_t qse_httpd_scb_t; | ||||||
| @ -266,8 +266,11 @@ typedef void (*qse_httpd_impede_t) ( | |||||||
|  |  | ||||||
| enum qse_httpd_act_code_t  | enum qse_httpd_act_code_t  | ||||||
| { | { | ||||||
|  | 	QSE_HTTPD_CATCH_MERRMSG, | ||||||
|  | 	QSE_HTTPD_CATCH_MDBGMSG, | ||||||
| 	QSE_HTTPD_ACCEPT_CLIENT, | 	QSE_HTTPD_ACCEPT_CLIENT, | ||||||
| 	QSE_HTTPD_PURGE_CLIENT, | 	QSE_HTTPD_PURGE_CLIENT, | ||||||
|  | 	QSE_HTTPD_READERR_CLIENT | ||||||
| }; | }; | ||||||
| typedef enum qse_httpd_act_code_t qse_httpd_act_code_t; | typedef enum qse_httpd_act_code_t qse_httpd_act_code_t; | ||||||
|  |  | ||||||
| @ -277,6 +280,8 @@ struct qse_httpd_act_t | |||||||
| 	union | 	union | ||||||
| 	{ | 	{ | ||||||
| 		qse_httpd_client_t* client; | 		qse_httpd_client_t* client; | ||||||
|  | 		qse_mchar_t merrmsg[128]; | ||||||
|  | 		qse_mchar_t mdbgmsg[128]; | ||||||
| 	} u; | 	} u; | ||||||
| }; | }; | ||||||
| typedef struct qse_httpd_act_t qse_httpd_act_t; | typedef struct qse_httpd_act_t qse_httpd_act_t; | ||||||
|  | |||||||
| @ -385,8 +385,13 @@ static int get_highest_fd (void) | |||||||
| 		#endif | 		#endif | ||||||
| 		} | 		} | ||||||
| 		else fd = rlim.rlim_max; | 		else fd = rlim.rlim_max; | ||||||
|  | 		if (fd == -1) fd = 1024; /* fallback */ | ||||||
|  |  | ||||||
|  | 		/* F_MAXFD is the highest fd. but RLIMIT_NOFILE and  | ||||||
|  | 		 * _SC_OPEN_MAX returnes the maximum number of file  | ||||||
|  | 		 * descriptors. make adjustment */ | ||||||
|  | 		if (fd > 0) fd--;  | ||||||
| 	} | 	} | ||||||
| 	if (fd == -1) fd = 1024; /* fallback */ |  | ||||||
| 	return fd; | 	return fd; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ | |||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
| #include <qse/cmn/pio.h> | #include <qse/cmn/pio.h> | ||||||
| #include <qse/cmn/fmt.h> | #include <qse/cmn/fmt.h> | ||||||
|  | #include <qse/cmn/path.h> | ||||||
|  |  | ||||||
| #include <stdio.h> /* TODO: remove this */ | #include <stdio.h> /* TODO: remove this */ | ||||||
|  |  | ||||||
| @ -196,6 +197,17 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void log_cgi_script_error (task_cgi_t* cgi, const qse_mchar_t* shortmsg) | ||||||
|  | { | ||||||
|  | 	qse_httpd_act_t msg; | ||||||
|  | 	qse_size_t pos = 0; | ||||||
|  |  | ||||||
|  | 	msg.code = QSE_HTTPD_CATCH_MERRMSG; | ||||||
|  | 	pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, shortmsg); | ||||||
|  | 	pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, cgi->script); | ||||||
|  | 	cgi->httpd->opt.rcb.logact (cgi->httpd, &msg); | ||||||
|  | } | ||||||
|  |  | ||||||
| static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) | static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) | ||||||
| { | { | ||||||
| 	cgi_script_htrd_xtn_t* xtn; | 	cgi_script_htrd_xtn_t* xtn; | ||||||
| @ -355,8 +367,9 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) | |||||||
| 	if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | 	if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||||
| 	    cgi->script_output_received > cgi->script_output_length) | 	    cgi->script_output_received > cgi->script_output_length) | ||||||
| 	{ | 	{ | ||||||
| /* TODO: cgi returning too much data... something is wrong in CGI */ | 		/* cgi returning too much data... something is wrong in CGI */ | ||||||
| qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n")); | 		if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 			log_cgi_script_error (cgi, QSE_MT("cgi redundant output - ")); | ||||||
| 		cgi->httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ | 		cgi->httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| @ -501,8 +514,10 @@ static int cgi_snatch_client_input ( | |||||||
| 	task = (qse_httpd_task_t*)ctx; | 	task = (qse_httpd_task_t*)ctx; | ||||||
| 	cgi = (task_cgi_t*)task->ctx; | 	cgi = (task_cgi_t*)task->ctx; | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr); | if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr); | ||||||
| else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); | else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	QSE_ASSERT (cgi->req); | 	QSE_ASSERT (cgi->req); | ||||||
| 	QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); | 	QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); | ||||||
| @ -587,7 +602,9 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); | |||||||
|  |  | ||||||
| 		/* output pipe to child */ | 		/* output pipe to child */ | ||||||
| 		task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE; | 		task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr); | qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr); | ||||||
|  | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -608,7 +625,9 @@ static void cgi_forward_client_input_to_script ( | |||||||
| 		{ | 		{ | ||||||
| 			/* a forwarding error has occurred previously. | 			/* a forwarding error has occurred previously. | ||||||
| 			 * clear the forwarding buffer */ | 			 * clear the forwarding buffer */ | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); | qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); | ||||||
|  | #endif | ||||||
| 			qse_mbs_clear (cgi->reqfwdbuf); | 			qse_mbs_clear (cgi->reqfwdbuf); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| @ -624,9 +643,11 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); | |||||||
| 			{ | 			{ | ||||||
| 			forward: | 			forward: | ||||||
| 				/* writable */ | 				/* writable */ | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), | qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), | ||||||
| 	(int)QSE_MBS_LEN(cgi->reqfwdbuf), | 	(int)QSE_MBS_LEN(cgi->reqfwdbuf), | ||||||
| 	QSE_MBS_PTR(cgi->reqfwdbuf)); | 	QSE_MBS_PTR(cgi->reqfwdbuf)); | ||||||
|  | #endif | ||||||
| 				n = qse_pio_write ( | 				n = qse_pio_write ( | ||||||
| 					&cgi->pio, QSE_PIO_IN, | 					&cgi->pio, QSE_PIO_IN, | ||||||
| 					QSE_MBS_PTR(cgi->reqfwdbuf), | 					QSE_MBS_PTR(cgi->reqfwdbuf), | ||||||
| @ -647,8 +668,9 @@ to the head all the time..  grow the buffer to a certain limit. */ | |||||||
|  |  | ||||||
| 			if (n <= -1) | 			if (n <= -1) | ||||||
| 			{ | 			{ | ||||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n")); | 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| /* TODO: logging ... */ | 					log_cgi_script_error (cgi, QSE_MT("cgi pio write error - ")); | ||||||
|  |  | ||||||
| 				cgi->reqflags |= CGI_REQ_FWDERR; | 				cgi->reqflags |= CGI_REQ_FWDERR; | ||||||
| 				qse_mbs_clear (cgi->reqfwdbuf);  | 				qse_mbs_clear (cgi->reqfwdbuf);  | ||||||
|  |  | ||||||
| @ -679,7 +701,9 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n")); | |||||||
| 		 * there is nothing more to forward in the forwarding buffer. | 		 * there is nothing more to forward in the forwarding buffer. | ||||||
| 		 * clear the relay and write triggers for the time being. | 		 * clear the relay and write triggers for the time being. | ||||||
| 		 */ | 		 */ | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n")); | qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n")); | ||||||
|  | #endif | ||||||
| 		QSE_ASSERT (cgi->req == QSE_NULL); | 		QSE_ASSERT (cgi->req == QSE_NULL); | ||||||
|  |  | ||||||
| 		/* mark the end of input to the child explicitly. */ | 		/* mark the end of input to the child explicitly. */ | ||||||
| @ -919,8 +943,6 @@ static void task_fini_cgi ( | |||||||
| 		QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); | 		QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); | ||||||
| 		qse_htre_unsetconcb (cgi->req); | 		qse_htre_unsetconcb (cgi->req); | ||||||
| 	} | 	} | ||||||
| 		 |  | ||||||
| qse_printf (QSE_T("task_fini_cgi\n")); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer ( | static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer ( | ||||||
| @ -934,6 +956,10 @@ static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer ( | |||||||
| 		QSE_SIZEOF(cgi->buf) - cgi->buflen | 		QSE_SIZEOF(cgi->buf) - cgi->buflen | ||||||
| 	); | 	); | ||||||
| 	if (n > 0) cgi->buflen += n; | 	if (n > 0) cgi->buflen += n; | ||||||
|  |  | ||||||
|  | 	if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 		log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
|  |  | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -942,13 +968,16 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client ( | |||||||
| { | { | ||||||
| 	qse_ssize_t n; | 	qse_ssize_t n; | ||||||
|  |  | ||||||
| 	httpd->errnum = QSE_HTTPD_ENOERR; |  | ||||||
| 	n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); | 	n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); | ||||||
| 	if (n > 0) | 	if (n > 0) | ||||||
| 	{ | 	{ | ||||||
| 		QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); | 		QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); | ||||||
| 		cgi->buflen -= n; | 		cgi->buflen -= n; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 		log_cgi_script_error (cgi, QSE_MT("cgi write error to client - ")); | ||||||
|  |  | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -971,13 +1000,11 @@ static int task_main_cgi_5 ( | |||||||
| 	if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || | 	if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || | ||||||
| 	    (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) | 	    (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) | ||||||
| 	{ | 	{ | ||||||
| qse_printf (QSE_T("task_main_cgi_5 about to write %d bytes\n"), (int)cgi->buflen); |  | ||||||
| 		if (cgi->buflen > 0) | 		if (cgi->buflen > 0) | ||||||
| 		{ | 		{ | ||||||
| 			if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | 			if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | ||||||
| 			{ | 			{ | ||||||
| 		/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| /* TODO: logging ... */ |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1024,11 +1051,7 @@ static int task_main_cgi_4_nph ( | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		QSE_ASSERT (cgi->buflen > 0); | 		QSE_ASSERT (cgi->buflen > 0); | ||||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||||
| 		{ |  | ||||||
| /* TODO: logging ... */ |  | ||||||
| 			return -1; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| @ -1043,8 +1066,10 @@ static int task_main_cgi_4 ( | |||||||
| 	QSE_ASSERT (!cgi->nph); | 	QSE_ASSERT (!cgi->nph); | ||||||
| 	QSE_ASSERT (cgi->pio_inited); | 	QSE_ASSERT (cgi->pio_inited); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | ||||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| @ -1057,7 +1082,6 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger | |||||||
|  |  | ||||||
| 	if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); |  | ||||||
| 		if (cgi->resflags & CGI_RES_CLIENT_CHUNK) | 		if (cgi->resflags & CGI_RES_CLIENT_CHUNK) | ||||||
| 		{ | 		{ | ||||||
| 			qse_size_t count, extra; | 			qse_size_t count, extra; | ||||||
| @ -1068,7 +1092,6 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | |||||||
| 	 | 	 | ||||||
| #define CHLEN_RESERVE 6  | #define CHLEN_RESERVE 6  | ||||||
|  |  | ||||||
| 	qse_printf (QSE_T("READING CHUNKED MODE...\n")); |  | ||||||
| 			extra = CHLEN_RESERVE + 2; | 			extra = CHLEN_RESERVE + 2; | ||||||
| 			count = QSE_SIZEOF(cgi->buf) - cgi->buflen; | 			count = QSE_SIZEOF(cgi->buf) - cgi->buflen; | ||||||
| 			if (count > extra) | 			if (count > extra) | ||||||
| @ -1080,7 +1103,8 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | |||||||
| 				); | 				); | ||||||
| 				if (n <= -1) | 				if (n <= -1) | ||||||
| 				{ | 				{ | ||||||
| 	/* TODO: logging ... */ | 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 						log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 				if (n == 0)  | 				if (n == 0)  | ||||||
| @ -1121,15 +1145,15 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | |||||||
| 				if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | 				if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||||
| 				    cgi->script_output_received > cgi->script_output_length) | 				    cgi->script_output_received > cgi->script_output_length) | ||||||
| 				{ | 				{ | ||||||
| 	/* TODO: cgi returning too much data... something is wrong in CGI */ | 					/* cgi returning too much data... something is wrong in CGI */ | ||||||
| 	qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); | 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 						log_cgi_script_error (cgi, QSE_MT("cgi redundant output - ")); | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 	qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n")); |  | ||||||
| 			if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | 			if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | ||||||
| 			{ | 			{ | ||||||
| 				n = cgi_read_script_output_to_buffer (httpd, client, cgi); | 				n = cgi_read_script_output_to_buffer (httpd, client, cgi); | ||||||
| @ -1147,9 +1171,9 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | |||||||
| 				if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | 				if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||||
| 				    cgi->script_output_received > cgi->script_output_length) | 				    cgi->script_output_received > cgi->script_output_length) | ||||||
| 				{ | 				{ | ||||||
| 					/* TODO: logging */ | 					/* cgi returning too much data... something is wrong in CGI */ | ||||||
| 	/* TODO: cgi returning too much data... something is wrong in CGI */ | 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| 	qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); | 						log_cgi_script_error (cgi, QSE_MT("cgi redundant output - ")); | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @ -1159,11 +1183,7 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | |||||||
| 		 * side is writable. it should be safe to write whenever | 		 * side is writable. it should be safe to write whenever | ||||||
| 		 * this task function is called. */ | 		 * this task function is called. */ | ||||||
| 		QSE_ASSERT (cgi->buflen > 0); | 		QSE_ASSERT (cgi->buflen > 0); | ||||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||||
| 		{ |  | ||||||
| 			/* TODO: logging ... */ |  | ||||||
| 			return -1; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| @ -1181,8 +1201,10 @@ static int task_main_cgi_3 ( | |||||||
|  |  | ||||||
| 	QSE_ASSERT (!cgi->nph); | 	QSE_ASSERT (!cgi->nph); | ||||||
|  |  | ||||||
|  | #if  0 | ||||||
| qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | ||||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||||
|  | #endif | ||||||
| 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| 		cgi_forward_client_input_to_script (httpd, task, 0); | 		cgi_forward_client_input_to_script (httpd, task, 0); | ||||||
| @ -1200,15 +1222,13 @@ qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger | |||||||
| 		count = MAX_SEND_SIZE; | 		count = MAX_SEND_SIZE; | ||||||
| 		if (count >= cgi->res_left) count = cgi->res_left; | 		if (count >= cgi->res_left) count = cgi->res_left; | ||||||
|  |  | ||||||
| qse_printf (QSE_T("[cgi_3 sending %d bytes]\n"), (int)count); |  | ||||||
| 		if (count > 0) | 		if (count > 0) | ||||||
| 		{ | 		{ | ||||||
| 			httpd->errnum = QSE_HTTPD_ENOERR; |  | ||||||
| 			n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); | 			n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); | ||||||
|  |  | ||||||
| 			if (n <= -1)  | 			if (n <= -1)  | ||||||
| 			{ | 			{ | ||||||
| qse_printf (QSE_T("[cgi-3 send failure....\n")); | 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 					log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - ")); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -1223,7 +1243,6 @@ qse_printf (QSE_T("[cgi-3 send failure....\n")); | |||||||
| 			if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | 			if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||||
| 			    cgi->script_output_received >= cgi->script_output_length) | 			    cgi->script_output_received >= cgi->script_output_length) | ||||||
| 			{	 | 			{	 | ||||||
| qse_printf (QSE_T("[switching to cgi-5....\n")); |  | ||||||
| 				/* if a cgi script specified the content length | 				/* if a cgi script specified the content length | ||||||
| 				 * and it has emitted as much as the length, | 				 * and it has emitted as much as the length, | ||||||
| 				 * i don't wait for the script to finish. | 				 * i don't wait for the script to finish. | ||||||
| @ -1236,7 +1255,6 @@ qse_printf (QSE_T("[switching to cgi-5....\n")); | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| qse_printf (QSE_T("[switching to cgi-4....\n")); |  | ||||||
| 				task->main = task_main_cgi_4; | 				task->main = task_main_cgi_4; | ||||||
| 				task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; | 				task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
| 			} | 			} | ||||||
| @ -1262,12 +1280,13 @@ static int task_main_cgi_2 ( | |||||||
| 	QSE_ASSERT (!cgi->nph); | 	QSE_ASSERT (!cgi->nph); | ||||||
| 	QSE_ASSERT (cgi->pio_inited); | 	QSE_ASSERT (cgi->pio_inited); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),  | ||||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| qse_printf (QSE_T("[cgi_2 write]\n")); |  | ||||||
| 		cgi_forward_client_input_to_script (httpd, task, 0); | 		cgi_forward_client_input_to_script (httpd, task, 0); | ||||||
| 	} | 	} | ||||||
| 	else if (task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) | 	else if (task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) | ||||||
| @ -1277,7 +1296,6 @@ qse_printf (QSE_T("[cgi_2 write]\n")); | |||||||
|  |  | ||||||
| 	if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | 	if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||||
| 	{ | 	{ | ||||||
| qse_printf (QSE_T("[cgi_2 read]\n")); |  | ||||||
| 		n = qse_pio_read ( | 		n = qse_pio_read ( | ||||||
| 			&cgi->pio, QSE_PIO_OUT, | 			&cgi->pio, QSE_PIO_OUT, | ||||||
| 			&cgi->buf[cgi->buflen],  | 			&cgi->buf[cgi->buflen],  | ||||||
| @ -1286,25 +1304,24 @@ qse_printf (QSE_T("[cgi_2 read]\n")); | |||||||
| 		if (n <= -1) | 		if (n <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			/* can't return internal server error any more... */ | 			/* can't return internal server error any more... */ | ||||||
| /* TODO: logging ... */ | 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
|  | 				log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
| 		if (n == 0)  | 		if (n == 0)  | ||||||
| 		{ | 		{ | ||||||
| 			/* end of output from cgi before it has seen a header. | 			/* end of output from cgi before it has seen a header. | ||||||
| 			 * the cgi script must be crooked. */ | 			 * the cgi script must be crooked. */ | ||||||
| /* TODO: logging */ | 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| qse_printf (QSE_T("#####PREMATURE EOF FROM CHILD\n")); | 				log_cgi_script_error (cgi, QSE_MT("cgi premature eof - ")); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
| 			 |  | ||||||
| 		cgi->buflen += n; | 		cgi->buflen += n; | ||||||
|  |  | ||||||
| qse_printf (QSE_T("#####CGI FEED [%.*hs]\n"), (int)cgi->buflen, cgi->buf); |  | ||||||
| 		if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) | 		if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) | ||||||
| 		{ | 		{ | ||||||
| /* TODO: logging */ | 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||||
| qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->buflen, cgi->buf); | 				log_cgi_script_error (cgi, QSE_MT("cgi feed error - ")); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -1324,7 +1341,9 @@ qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->bu | |||||||
| 			cgi->res_ptr = QSE_MBS_PTR(cgi->res); | 			cgi->res_ptr = QSE_MBS_PTR(cgi->res); | ||||||
| 			cgi->res_left = QSE_MBS_LEN(cgi->res); | 			cgi->res_left = QSE_MBS_LEN(cgi->res); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res)); | qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res)); | ||||||
|  | #endif | ||||||
| 			task->main = task_main_cgi_3; | 			task->main = task_main_cgi_3; | ||||||
| 			task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | 			task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||||
| 			return 1; | 			return 1; | ||||||
| @ -1447,7 +1466,6 @@ static int task_main_cgi ( | |||||||
| 			 * this is possible because the main loop can still read  | 			 * this is possible because the main loop can still read  | ||||||
| 			 * between the initializer function (task_init_cgi()) and  | 			 * between the initializer function (task_init_cgi()) and  | ||||||
| 			 * this function. so let's forward it initially. */ | 			 * this function. so let's forward it initially. */ | ||||||
| qse_printf (QSE_T("FORWARDING INITIAL PART OF CONTENT...\n")); |  | ||||||
| 			cgi_forward_client_input_to_script (httpd, task, 0); | 			cgi_forward_client_input_to_script (httpd, task, 0); | ||||||
|  |  | ||||||
| 			/* if the initial forwarding clears the forwarding  | 			/* if the initial forwarding clears the forwarding  | ||||||
|  | |||||||
| @ -29,8 +29,8 @@ | |||||||
| typedef struct task_proxy_arg_t task_proxy_arg_t; | typedef struct task_proxy_arg_t task_proxy_arg_t; | ||||||
| struct task_proxy_arg_t  | struct task_proxy_arg_t  | ||||||
| { | { | ||||||
| 	qse_nwad_t* peer_nwad; | 	const qse_nwad_t* peer_nwad; | ||||||
| 	qse_nwad_t* peer_local; | 	const qse_nwad_t* peer_local; | ||||||
| 	qse_htre_t* req; | 	qse_htre_t* req; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -531,12 +531,15 @@ struct httpd_xtn_t | |||||||
|  |  | ||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| static int init_xtn_ssl ( | static int init_xtn_ssl ( | ||||||
| 	httpd_xtn_t* xtn, | 	qse_httpd_t* httpd, | ||||||
| 	const qse_mchar_t* pemfile, | 	const qse_mchar_t* pemfile, | ||||||
| 	const qse_mchar_t* keyfile/*, | 	const qse_mchar_t* keyfile/*, | ||||||
| 	const qse_mchar_t* chainfile*/) | 	const qse_mchar_t* chainfile*/) | ||||||
| { | { | ||||||
| 	SSL_CTX* ctx; | 	SSL_CTX* ctx; | ||||||
|  | 	httpd_xtn_t* xtn; | ||||||
|  |  | ||||||
|  | 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | ||||||
|  |  | ||||||
| 	ctx = SSL_CTX_new (SSLv23_server_method()); | 	ctx = SSL_CTX_new (SSLv23_server_method()); | ||||||
| 	if (ctx == QSE_NULL) return -1; | 	if (ctx == QSE_NULL) return -1; | ||||||
| @ -548,10 +551,14 @@ static int init_xtn_ssl ( | |||||||
| 	    SSL_CTX_check_private_key (ctx) == 0 /*|| | 	    SSL_CTX_check_private_key (ctx) == 0 /*|| | ||||||
| 	    SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/) | 	    SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/) | ||||||
| 	{ | 	{ | ||||||
| 		qse_mchar_t buf[128]; | 		if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| 		ERR_error_string_n(ERR_get_error(), buf, QSE_COUNTOF(buf)); | 		{ | ||||||
| /* TODO: logging */ | 			qse_httpd_act_t msg; | ||||||
| qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf); | 			msg.code = QSE_HTTPD_CATCH_MERRMSG; | ||||||
|  | 			ERR_error_string_n (ERR_get_error(), msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); | ||||||
|  | 			httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		SSL_CTX_free (ctx); | 		SSL_CTX_free (ctx); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| @ -600,7 +607,7 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) | |||||||
| 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| 	/*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/ | 	/*init_xtn_ssl (httpd, "http01.pem", "http01.key");*/ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	set_httpd_callbacks (httpd); | 	set_httpd_callbacks (httpd); | ||||||
| @ -1409,7 +1416,16 @@ static int file_ropen ( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	handle->ptr = fio; | 	handle->ptr = fio; | ||||||
| qse_printf (QSE_T("opened rfile [%hs][%p][%p]\n"), path, handle->ptr, fio->handle); |  | ||||||
|  | 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_act_t msg; | ||||||
|  | 		qse_size_t pos; | ||||||
|  | 		msg.code = QSE_HTTPD_CATCH_MDBGMSG; | ||||||
|  | 		pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("ropened file ")); | ||||||
|  | 		qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path); | ||||||
|  | 		httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -1438,13 +1454,22 @@ static int file_wopen ( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	handle->ptr = fio; | 	handle->ptr = fio; | ||||||
| qse_printf (QSE_T("opened wfile [%hs][%p][%p]\n"), path, handle->ptr, fio->handle); |  | ||||||
|  | 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_act_t msg; | ||||||
|  | 		qse_size_t pos; | ||||||
|  | 		msg.code = QSE_HTTPD_CATCH_MDBGMSG; | ||||||
|  | 		pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("wopened file ")); | ||||||
|  | 		qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path); | ||||||
|  | 		httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void file_close (qse_httpd_t* httpd, qse_ubi_t handle) | static void file_close (qse_httpd_t* httpd, qse_ubi_t handle) | ||||||
| { | { | ||||||
| qse_printf (QSE_T("closed file....%p\n"), handle.ptr); |  | ||||||
| 	qse_fio_fini (handle.ptr); | 	qse_fio_fini (handle.ptr); | ||||||
| 	QSE_MMGR_FREE (httpd->mmgr, handle.ptr); | 	QSE_MMGR_FREE (httpd->mmgr, handle.ptr); | ||||||
| } | } | ||||||
| @ -1512,7 +1537,16 @@ static int dir_open (qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* han | |||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 		 | 		 | ||||||
| qse_printf (QSE_T("OPENED DIRECTORY [%hs]\n"), path); | 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_act_t msg; | ||||||
|  | 		qse_size_t pos; | ||||||
|  | 		msg.code = QSE_HTTPD_CATCH_MDBGMSG; | ||||||
|  | 		pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("opened dir ")); | ||||||
|  | 		qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path); | ||||||
|  | 		httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	handle->ptr = d; | 	handle->ptr = d; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -1693,7 +1727,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 		{ | 		{ | ||||||
| 			/* delayed initialization of ssl */ | 			/* delayed initialization of ssl */ | ||||||
| /* TODO: certificate from options */ | /* TODO: certificate from options */ | ||||||
| 			if (init_xtn_ssl (xtn, "http01.pem", "http01.key") <= -1)  | 			if (init_xtn_ssl (httpd, "http01.pem", "http01.key") <= -1)  | ||||||
| 			{ | 			{ | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| @ -1711,9 +1745,6 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 			if (ssl == QSE_NULL) return -1; | 			if (ssl == QSE_NULL) return -1; | ||||||
|  |  | ||||||
| 			client->handle2.ptr = ssl; | 			client->handle2.ptr = ssl; | ||||||
|  |  | ||||||
| qse_printf (QSE_T("SSL ACCEPTING %d\n"), client->handle.i); |  | ||||||
| qse_fflush (QSE_STDOUT); |  | ||||||
| 			if (SSL_set_fd (ssl, client->handle.i) == 0) | 			if (SSL_set_fd (ssl, client->handle.i) == 0) | ||||||
| 			{ | 			{ | ||||||
| 				/* don't free ssl here since client_closed() | 				/* don't free ssl here since client_closed() | ||||||
| @ -1727,18 +1758,25 @@ qse_fflush (QSE_STDOUT); | |||||||
| 		ret = SSL_accept (ssl); | 		ret = SSL_accept (ssl); | ||||||
| 		if (ret <= 0) | 		if (ret <= 0) | ||||||
| 		{ | 		{ | ||||||
| 			if (SSL_get_error(ssl,ret) == SSL_ERROR_WANT_READ) | 			int err; | ||||||
|  | 			if ((err = SSL_get_error(ssl,ret)) == SSL_ERROR_WANT_READ) | ||||||
| 			{ | 			{ | ||||||
| 				/* handshaking isn't complete. */ | 				/* handshaking isn't complete. */ | ||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			qse_fprintf (QSE_STDERR, QSE_T("Error: SSL ACCEPT ERROR\n")); | 			if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
|  | 			{ | ||||||
|  | 				qse_httpd_act_t msg; | ||||||
|  | 				msg.code = QSE_HTTPD_CATCH_MERRMSG; | ||||||
|  | 				ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); | ||||||
|  | 				httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			/* SSL_free (ssl); */ | 			/* SSL_free (ssl); */ | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i); |  | ||||||
| qse_fflush (QSE_STDOUT); |  | ||||||
| 	#else | 	#else | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
| 		return -1; | 		return -1; | ||||||
| @ -1763,6 +1801,7 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
|  | #if 0 | ||||||
| static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) | static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) | ||||||
| { | { | ||||||
| 	qse_htre_hdrval_t* val; | 	qse_htre_hdrval_t* val; | ||||||
| @ -1775,6 +1814,7 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"),  (int)QSE_HTB_KLEN(pair), QSE_ | |||||||
| 	} | 	} | ||||||
| 	return QSE_HTB_WALK_FORWARD; | 	return QSE_HTB_WALK_FORWARD; | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| static int process_request ( | static int process_request ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) | 	qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) | ||||||
| @ -1796,6 +1836,7 @@ static int process_request ( | |||||||
| 	 * non-peek mode as well */ | 	 * non-peek mode as well */ | ||||||
| 	if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req)); | 	if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req)); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("================================\n")); | qse_printf (QSE_T("================================\n")); | ||||||
| qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), | qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), | ||||||
| 	(unsigned long)time(NULL), | 	(unsigned long)time(NULL), | ||||||
| @ -1814,6 +1855,7 @@ if (qse_htre_getcontentlen(req) > 0) | |||||||
| { | { | ||||||
| 	qse_printf (QSE_T("CONTENT [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); | 	qse_printf (QSE_T("CONTENT [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (peek) | 	if (peek) | ||||||
| 	{ | 	{ | ||||||
| @ -2044,11 +2086,12 @@ static void impede_httpd (qse_httpd_t* httpd) | |||||||
| 	/* do nothing */ | 	/* do nothing */ | ||||||
| } | } | ||||||
|  |  | ||||||
| static void logact_httpd (qse_httpd_t* httpd, qse_httpd_act_t* act) | static void logact_httpd (qse_httpd_t* httpd, const qse_httpd_act_t* act) | ||||||
| { | { | ||||||
| 	/* do nothing */ | 	/* do nothing */ | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static qse_httpd_scb_t httpd_system_callbacks = | static qse_httpd_scb_t httpd_system_callbacks = | ||||||
| { | { | ||||||
| 	/* server */ | 	/* server */ | ||||||
| @ -2341,11 +2384,11 @@ static int make_resource ( | |||||||
|  |  | ||||||
| 	QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); | 	QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); | ||||||
|  |  | ||||||
| qse_printf (QSE_T(">>> MAKING RESOURCE [%hs]\n"), tmp.qpath); |  | ||||||
| 	server_xtn = qse_httpd_getserverxtn (httpd, client->server); | 	server_xtn = qse_httpd_getserverxtn (httpd, client->server); | ||||||
|  |  | ||||||
| 	if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1 || | 	if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1) return -1; | ||||||
| 	    server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 || |  | ||||||
|  | 	if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 || | ||||||
| 	    server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_AUTH, &tmp.auth) <= -1 || | 	    server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_AUTH, &tmp.auth) <= -1 || | ||||||
| 	    server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1) | 	    server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1) | ||||||
| 	{ | 	{ | ||||||
| @ -2455,8 +2498,19 @@ auth_ok: | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			target->type = QSE_HTTPD_RSRC_DIR; | 			/* it is a directory - should i allow it? */ | ||||||
| 			target->u.dir.path = tmp.xpath; | 			if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRACC, &target->u.err.code) <= -1) target->u.err.code = 500; | ||||||
|  | 			if (target->u.err.code != 200) | ||||||
|  | 			{ | ||||||
|  | 				target->type = QSE_HTTPD_RSRC_ERR; | ||||||
|  | 				/* free xpath since it won't be used */ | ||||||
|  | 				QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				target->type = QSE_HTTPD_RSRC_DIR; | ||||||
|  | 				target->u.dir.path = tmp.xpath; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| @ -2478,14 +2532,25 @@ auth_ok: | |||||||
| 		} | 		} | ||||||
| 		if (n >= 1) return 0; | 		if (n >= 1) return 0; | ||||||
|  |  | ||||||
| 		/* fall back to a normal file. */ | 		/* check file's access permission */ | ||||||
| 		target->type = QSE_HTTPD_RSRC_FILE; | 		if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_FILEACC, &target->u.err.code) <= -1) target->u.err.code = 500; | ||||||
| 		target->u.file.path = tmp.xpath; | 		if (target->u.err.code != 200) | ||||||
|  |  | ||||||
| 		if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1) |  | ||||||
| 		{ | 		{ | ||||||
| 			/* don't care about failure */ | 			target->type = QSE_HTTPD_RSRC_ERR; | ||||||
| 			target->u.file.mime = QSE_NULL; | 			/* free xpath since it won't be used */ | ||||||
|  | 			QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* fall back to a normal file. */ | ||||||
|  | 			target->type = QSE_HTTPD_RSRC_FILE; | ||||||
|  | 			target->u.file.path = tmp.xpath; | ||||||
|  |  | ||||||
|  | 			if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1) | ||||||
|  | 			{ | ||||||
|  | 				/* don't care about failure */ | ||||||
|  | 				target->u.file.mime = QSE_NULL; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -2581,6 +2646,12 @@ static int query_server ( | |||||||
|  |  | ||||||
| 			*(const qse_mchar_t**)result = QSE_NULL; | 			*(const qse_mchar_t**)result = QSE_NULL; | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_DIRACC: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_FILEACC: | ||||||
|  | 			*(int*)result = 200; | ||||||
|  | 			return 0; | ||||||
|  | 			 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | ||||||
|  | |||||||
| @ -457,7 +457,7 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 	prev = client->prev; | 	prev = client->prev; | ||||||
| 	next = client->next; | 	next = client->next; | ||||||
|  |  | ||||||
| 	if (httpd->opt.trait & QSE_HTTPD_ENABLELOG) | 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| 	{ | 	{ | ||||||
| 		qse_httpd_act_t msg; | 		qse_httpd_act_t msg; | ||||||
| 		msg.code = QSE_HTTPD_PURGE_CLIENT; | 		msg.code = QSE_HTTPD_PURGE_CLIENT; | ||||||
| @ -562,14 +562,13 @@ qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i); | |||||||
| 			httpd->client.list.tail = client; | 			httpd->client.list.tail = client; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| { | 		if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| /* TODO: proper logging */ | 		{ | ||||||
| qse_char_t tmp[128], tmp2[128], tmp3[128]; | 			qse_httpd_act_t msg; | ||||||
| qse_nwadtostr (&client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | 			msg.code = QSE_HTTPD_ACCEPT_CLIENT; | ||||||
| qse_nwadtostr (&client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); | 			msg.u.client = client; | ||||||
| qse_nwadtostr (&client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL); | 			httpd->opt.rcb.logact (httpd, &msg); | ||||||
| qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, tmp, tmp2, tmp3); | 		} | ||||||
| } |  | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -733,7 +732,6 @@ reread: | |||||||
| 		if (httpd->errnum == QSE_HTTPD_EAGAIN) | 		if (httpd->errnum == QSE_HTTPD_EAGAIN) | ||||||
| 		{ | 		{ | ||||||
| 			/* nothing to read yet. */ | 			/* nothing to read yet. */ | ||||||
| qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i); |  | ||||||
| 			return 0; /* return ok */ | 			return 0; /* return ok */ | ||||||
| 		} | 		} | ||||||
| 		else if (httpd->errnum == QSE_HTTPD_EINTR) | 		else if (httpd->errnum == QSE_HTTPD_EINTR) | ||||||
| @ -743,14 +741,22 @@ qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle | |||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			/* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */ | 			/* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */ | ||||||
| qse_printf (QSE_T("Error: failed to read from a client %d\n"), client->handle.i); | 			if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| 	/* TODO: find a way to disconnect */ | 			{ | ||||||
|  | 				qse_httpd_act_t msg; | ||||||
|  | 				msg.code = QSE_HTTPD_READERR_CLIENT; | ||||||
|  | 				msg.u.client = client; | ||||||
|  | 				httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 			} | ||||||
|  | 			/* TODO: find a way to disconnect */ | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else if (m == 0) | 	else if (m == 0) | ||||||
| 	{ | 	{ | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i); | qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i); | ||||||
|  | #endif | ||||||
| 		/* reading from the client returned 0. this typically | 		/* reading from the client returned 0. this typically | ||||||
| 		 * happens when the client closes the connection or | 		 * happens when the client closes the connection or | ||||||
| 		 * shutdown the writing half of the socket. it's | 		 * shutdown the writing half of the socket. it's | ||||||
| @ -764,17 +770,22 @@ qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i); | |||||||
| 			/* there is still more tasks to finish and  | 			/* there is still more tasks to finish and  | ||||||
| 			 * http reader is not waiting for any more feeds.  */ | 			 * http reader is not waiting for any more feeds.  */ | ||||||
| 			client->status |= CLIENT_MUTE; | 			client->status |= CLIENT_MUTE; | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i); | qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i); | ||||||
|  | #endif | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i); | qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i); | ||||||
|  | #endif | ||||||
| 			httpd->errnum = QSE_HTTPD_EDISCON; | 			httpd->errnum = QSE_HTTPD_EDISCON; | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i); | qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i); | ||||||
| #if !defined(__WATCOMC__) | #if !defined(__WATCOMC__) | ||||||
| { | { | ||||||
| @ -783,6 +794,7 @@ for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
| qse_printf (QSE_T("]\n")); | qse_printf (QSE_T("]\n")); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	/* qse_htrd_feed() may call the request callback  | 	/* qse_htrd_feed() may call the request callback  | ||||||
| 	 * multiple times. that's because we don't know  | 	 * multiple times. that's because we don't know  | ||||||
| @ -798,17 +810,21 @@ qse_printf (QSE_T("]\n")); | |||||||
| 			else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */ | 			else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */ | ||||||
| 		} | 		} | ||||||
| 	 | 	 | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i); | qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i); | ||||||
| { | { | ||||||
| int i; | int i; | ||||||
| for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); | for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); | ||||||
| } | } | ||||||
| qse_printf (QSE_T("]\n")); | qse_printf (QSE_T("]\n")); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  | #if 0 | ||||||
| qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i); | qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (client->status & CLIENT_PENDING)  | 	if (client->status & CLIENT_PENDING)  | ||||||
| 	{ | 	{ | ||||||
| @ -840,7 +856,6 @@ static int invoke_client_task ( | |||||||
| 	int n, trigger_fired, client_handle_writable; | 	int n, trigger_fired, client_handle_writable; | ||||||
|  |  | ||||||
| /* TODO: handle comparison callback ... */ | /* TODO: handle comparison callback ... */ | ||||||
| qse_printf (QSE_T("INVOKE CLIENT TASK..........\n")); |  | ||||||
| 	if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */ | 	if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */ | ||||||
| 	{ | 	{ | ||||||
| 		if (!(client->status & CLIENT_MUTE) &&  | 		if (!(client->status & CLIENT_MUTE) &&  | ||||||
| @ -850,7 +865,6 @@ qse_printf (QSE_T("INVOKE CLIENT TASK..........\n")); | |||||||
| 			 * purge the client in perform_client_task(). | 			 * purge the client in perform_client_task(). | ||||||
| 			 * thus the following line isn't necessary. | 			 * thus the following line isn't necessary. | ||||||
| 			 *if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/ | 			 *if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/ | ||||||
| qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i); |  | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -862,7 +876,6 @@ qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i); | |||||||
| 		if (client->status & CLIENT_MUTE) | 		if (client->status & CLIENT_MUTE) | ||||||
| 		{ | 		{ | ||||||
| 			/* handle this delayed client disconnection */ | 			/* handle this delayed client disconnection */ | ||||||
| qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int)client->handle.i); |  | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -908,7 +921,6 @@ qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	n = task->main (httpd, client, task); | 	n = task->main (httpd, client, task); | ||||||
| qse_printf (QSE_T("task returend %d\n"), n); |  | ||||||
| 	if (n <= -1) return -1; | 	if (n <= -1) return -1; | ||||||
| 	else if (n == 0) | 	else if (n == 0) | ||||||
| 	{ | 	{ | ||||||
| @ -1118,17 +1130,12 @@ static int perform_client_task ( | |||||||
| 		qse_gettime (&client->last_active); /* TODO: error check??? */ | 		qse_gettime (&client->last_active); /* TODO: error check??? */ | ||||||
| 		move_client_to_tail (httpd, client); | 		move_client_to_tail (httpd, client); | ||||||
|  |  | ||||||
| 		if (invoke_client_task (httpd, client, handle, mask) <= -1)  | 		if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops; | ||||||
| 		{ |  | ||||||
| qse_printf (QSE_T("OOPS AFTER CLIENT TASK BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i); |  | ||||||
| 			goto oops; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i); |  | ||||||
| 	/*purge_client (httpd, client);*/ | 	/*purge_client (httpd, client);*/ | ||||||
| 	client->status |= CLIENT_BAD; | 	client->status |= CLIENT_BAD; | ||||||
| 	client->bad_next = httpd->client.bad; | 	client->bad_next = httpd->client.bad; | ||||||
| @ -1336,3 +1343,8 @@ const qse_mchar_t* qse_httpd_fmtgmtimetobb ( | |||||||
| 	qse_fmthttptime (nt, httpd->gtbuf[idx], QSE_COUNTOF(httpd->gtbuf[idx])); | 	qse_fmthttptime (nt, httpd->gtbuf[idx], QSE_COUNTOF(httpd->gtbuf[idx])); | ||||||
| 	return httpd->gtbuf[idx]; | 	return httpd->gtbuf[idx]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------- */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -235,13 +235,16 @@ qse_xli_pair_t* qse_xli_insertpair ( | |||||||
| 	if (pair == QSE_NULL) return QSE_NULL; | 	if (pair == QSE_NULL) return QSE_NULL; | ||||||
|  |  | ||||||
| 	kptr = (qse_char_t*)(pair + 1); | 	kptr = (qse_char_t*)(pair + 1); | ||||||
| 	nptr = kptr + klen + 1; |  | ||||||
| 	qse_strcpy (kptr, key); | 	qse_strcpy (kptr, key); | ||||||
| 	if (name) qse_strcpy (nptr, name); |  | ||||||
|  |  | ||||||
| 	pair->type = QSE_XLI_PAIR; | 	pair->type = QSE_XLI_PAIR; | ||||||
| 	pair->key = kptr; | 	pair->key = kptr; | ||||||
| 	pair->name = nptr; | 	if (name)  | ||||||
|  | 	{ | ||||||
|  | 		nptr = kptr + klen + 1; | ||||||
|  | 		qse_strcpy (nptr, name); | ||||||
|  | 		pair->name = nptr; | ||||||
|  | 	} | ||||||
| 	pair->val = value;  /* this assumes it points to a dynamically allocated atom  */ | 	pair->val = value;  /* this assumes it points to a dynamically allocated atom  */ | ||||||
|  |  | ||||||
| 	insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair); | 	insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user