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/time.h> | ||||
| #include <qse/cmn/path.h> | ||||
| #include <qse/cmn/opt.h> | ||||
|  | ||||
| #include <signal.h> | ||||
| #include <locale.h> | ||||
| @ -27,6 +28,7 @@ | ||||
| #else | ||||
| #	include <unistd.h> | ||||
| #	include <errno.h> | ||||
| #	include <fcntl.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(HAVE_SSL) | ||||
| @ -38,17 +40,34 @@ | ||||
| /* --------------------------------------------------------------------- */ | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
| static void sighup (int sig) | ||||
| static void sig_reconf (int sig) | ||||
| { | ||||
| 	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); | ||||
| 	} | ||||
| } | ||||
| @ -59,15 +78,25 @@ static void setup_signal_handlers () | ||||
|  | ||||
| #if defined(SIGINT) | ||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||
| 	act.sa_handler = sigint; | ||||
| 	act.sa_handler = sig_stop; | ||||
| 	sigaction (SIGINT, &act, QSE_NULL); | ||||
| #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) | ||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||
| 	act.sa_handler = sighup; | ||||
| 	act.sa_handler = sig_reconf; | ||||
| 	sigaction (SIGHUP, &act, QSE_NULL); | ||||
| #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) | ||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||
| @ -85,12 +114,22 @@ static void restore_signal_handlers () | ||||
| 	act.sa_handler = SIG_DFL; | ||||
| 	sigaction (SIGINT, &act, QSE_NULL); | ||||
| #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) | ||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||
| 	act.sa_handler = SIG_DFL; | ||||
| 	sigaction (SIGHUP, &act, QSE_NULL); | ||||
| #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) | ||||
| 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||
| @ -99,6 +138,43 @@ static void restore_signal_handlers () | ||||
| #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 | ||||
| @ -117,8 +193,7 @@ struct cgi_t | ||||
| { | ||||
| 	enum { | ||||
| 		CGI_SUFFIX, | ||||
| 		CGI_FILE, | ||||
|  | ||||
| 		CGI_NAME, | ||||
| 		CGI_MAX | ||||
| 	} type; | ||||
|  | ||||
| @ -133,8 +208,8 @@ struct mime_t | ||||
| { | ||||
| 	enum { | ||||
| 		MIME_SUFFIX, | ||||
| 		MIME_FILE, | ||||
|  | ||||
| 		MIME_NAME, | ||||
| 		MIME_OTHER, | ||||
| 		MIME_MAX | ||||
| 	} type; | ||||
|  | ||||
| @ -144,6 +219,23 @@ struct mime_t | ||||
| 	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; | ||||
| struct server_xtn_t | ||||
| { | ||||
| @ -176,15 +268,14 @@ struct server_xtn_t | ||||
| 		struct mime_t* head; | ||||
| 		struct mime_t* tail; | ||||
| 	} 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 ( | ||||
| 	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) | ||||
| { | ||||
| 	server_xtn_t* server_xtn; | ||||
| 	qse_size_t i; | ||||
| 	qse_size_t i, j; | ||||
|  | ||||
| 	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].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) | ||||
| @ -369,8 +479,8 @@ static int query_server ( | ||||
| 				struct cgi_t* cgi; | ||||
| 				for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next) | ||||
| 				{ | ||||
| 					if ((cgi->type == MIME_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) || | ||||
| 					    (cgi->type == MIME_FILE && qse_mbscmp (xpath_base, cgi->spec) == 0)) | ||||
| 					if ((cgi->type == CGI_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) || | ||||
| 					    (cgi->type == CGI_NAME && qse_mbscmp (xpath_base, cgi->spec) == 0)) | ||||
| 					{ | ||||
| 						scgi->cgi = 1; | ||||
| 						scgi->nph = cgi->nph;		 | ||||
| @ -386,7 +496,7 @@ static int query_server ( | ||||
| 		case QSE_HTTPD_SERVERSTD_MIME: | ||||
| 		{ | ||||
| 			qse_size_t i; | ||||
| 			qse_mchar_t* xpath_base; | ||||
| 			const qse_mchar_t* xpath_base; | ||||
|  | ||||
| 			xpath_base = qse_mbsbasename (xpath); | ||||
|  | ||||
| @ -397,7 +507,8 @@ static int query_server ( | ||||
| 				for (mime = server_xtn->mime[i].head; mime; mime = mime->next) | ||||
| 				{ | ||||
| 					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; | ||||
| 						return 0; | ||||
| @ -406,6 +517,35 @@ static int query_server ( | ||||
| 			} | ||||
| 			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); | ||||
| @ -498,9 +638,9 @@ static int load_server_config ( | ||||
| 				{ | ||||
| 					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; | ||||
|  | ||||
| @ -570,13 +710,14 @@ static int load_server_config ( | ||||
| 			if (atom->type != QSE_XLI_PAIR) continue; | ||||
|  | ||||
| 			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; | ||||
| 				int type; | ||||
|  | ||||
| 				if (qse_strcmp (pair->key, QSE_T("suffix")) == 0) type = MIME_SUFFIX; | ||||
| 				else if (qse_strcmp (pair->key, QSE_T("file")) == 0) type = MIME_FILE; | ||||
| 				if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = MIME_SUFFIX; | ||||
| 				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; | ||||
|  | ||||
| 				mime = qse_httpd_callocmem (httpd, QSE_SIZEOF(*mime)); | ||||
| @ -594,8 +735,7 @@ static int load_server_config ( | ||||
| 					qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); | ||||
| 					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) | ||||
| 				{ | ||||
| @ -605,9 +745,6 @@ static int load_server_config ( | ||||
| 					return -1; | ||||
| 				} | ||||
|  | ||||
| 					/* TODO: more sanity check */ | ||||
|  | ||||
| 				} | ||||
| 				if (server_xtn->mime[type].tail) | ||||
| 					server_xtn->mime[type].tail->next = mime; | ||||
| 				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 */ | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	qse_char_t tmp[256]; | ||||
| 	qse_char_t tmp[128], tmp2[128], tmp3[128]; | ||||
|  | ||||
| 	httpd_xtn = qse_httpd_getxtnstd (httpd); | ||||
|  | ||||
| 	switch (act->code) | ||||
| 	{ | ||||
| 		case QSE_HTTPD_ACCEPT_CLIENT: | ||||
| 		case QSE_HTTPD_CATCH_MERRMSG: | ||||
| 			qse_printf (QSE_T("ERROR: %hs\n"), act->u.merrmsg); | ||||
| 			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: | ||||
| 			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;		 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* --------------------------------------------------------------------- */ | ||||
| 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[]) | ||||
| { | ||||
| 	qse_httpd_t* httpd = QSE_NULL; | ||||
| 	httpd_xtn_t* httpd_xtn; | ||||
| 	qse_ntime_t tmout; | ||||
| 	int trait, ret = -1; | ||||
| 	int trait, ret; | ||||
| 	qse_httpd_rcb_t rcb; | ||||
|  | ||||
| 	if (argc != 2) | ||||
| 	{ | ||||
| 		/* TODO: proper check... */ | ||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]); | ||||
| 		goto oops; | ||||
| 	} | ||||
| 	ret = handle_args (argc, argv); | ||||
| 	if (ret <= -1) return -1; | ||||
| 	if (ret == 0) return 0; | ||||
|  | ||||
| 	httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t)); | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	httpd_xtn = qse_httpd_getxtnstd (httpd); | ||||
| 	httpd_xtn->cfgfile = argv[1]; | ||||
| 	httpd_xtn->cfgfile = g_cfgfile; | ||||
|  | ||||
| 	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; | ||||
| 	setup_signal_handlers (); | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 	tmout.sec = 10; | ||||
| @ -921,7 +1241,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) | ||||
|  | ||||
| oops: | ||||
| 	if (httpd) qse_httpd_close (httpd); | ||||
| 	return ret; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int qse_main (int argc, qse_achar_t* argv[]) | ||||
|  | ||||
| @ -2,43 +2,119 @@ | ||||
| # this is a sample configuration file for qsehttpd. | ||||
| # | ||||
|  | ||||
| server { | ||||
| 	bind = "0.0.0.0:80"; | ||||
| default { | ||||
| 	# the default name is used in http headers and in pages  | ||||
| 	# generated by httpd. | ||||
| 	name = "QSEHTTPD v1"; | ||||
|  | ||||
| 	ssl { | ||||
| 		certificate { | ||||
| 			private = "xxxx"; | ||||
| 			public = "xxxx"; | ||||
| 		}		 | ||||
| 	} | ||||
| 	docroot = "/"; | ||||
|  | ||||
| 	root = "/home/www/default"; | ||||
| 	option = "xxxx,xxx,xxxx"; | ||||
|  | ||||
| 	realm { | ||||
| 		name = "xxxxxx"; | ||||
| 		password = "zzzzzzzzzzzzzzzz"; | ||||
| 	} | ||||
| 	realm = "default realm"; | ||||
| 	auth = "username:password";	 | ||||
| 	index = "index.ant", | ||||
| 	        "index.html", | ||||
| 	        "index.cgi"; | ||||
|  | ||||
| 	cgi { | ||||
| 		suffix ".ant" = "xxxxx"; | ||||
| 		name "t3.nph" = "nph"; | ||||
| 		suffix ".cgi"; | ||||
| 		suffix ".nph"; | ||||
| 		suffix ".ant" = "nph", ""; | ||||
| 		suffix ".awk" = "cgi", "/usr/bin/qseawk -f"; | ||||
|  | ||||
| 		# glob is not supported yet | ||||
| 		# glob "x*.xxx"; | ||||
| 	} | ||||
|  | ||||
| 	mime { | ||||
| 		suffix ".jpg" = "image/picture"; | ||||
| 		suffix ".txt" = "text/plain"; | ||||
| 		@include "httpd-mime.conf"; | ||||
| 	} | ||||
|  | ||||
| 	# virtual host | ||||
| 	host "www.google.com" { | ||||
| 		root = "/home/www/google";	 | ||||
| 		option = "xxx, xxx, xxxx"; | ||||
| 	# control access to directories | ||||
| 	dir-access { | ||||
| 		# suffix ".xxxx" = ok; | ||||
| 		# 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_CGINOCLOEXEC = (1 << 2), | ||||
| 	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; | ||||
|  | ||||
| @ -115,7 +115,7 @@ typedef struct qse_httpd_dirent_t qse_httpd_dirent_t; | ||||
|  | ||||
| struct qse_httpd_dirent_t | ||||
| { | ||||
| 	qse_mchar_t*     name; | ||||
| 	const qse_mchar_t* name; | ||||
| 	qse_httpd_stat_t   stat; | ||||
| }; | ||||
|  | ||||
| @ -266,8 +266,11 @@ typedef void (*qse_httpd_impede_t) ( | ||||
|  | ||||
| enum qse_httpd_act_code_t  | ||||
| { | ||||
| 	QSE_HTTPD_CATCH_MERRMSG, | ||||
| 	QSE_HTTPD_CATCH_MDBGMSG, | ||||
| 	QSE_HTTPD_ACCEPT_CLIENT, | ||||
| 	QSE_HTTPD_PURGE_CLIENT, | ||||
| 	QSE_HTTPD_READERR_CLIENT | ||||
| }; | ||||
| typedef enum qse_httpd_act_code_t qse_httpd_act_code_t; | ||||
|  | ||||
| @ -277,6 +280,8 @@ struct qse_httpd_act_t | ||||
| 	union | ||||
| 	{ | ||||
| 		qse_httpd_client_t* client; | ||||
| 		qse_mchar_t merrmsg[128]; | ||||
| 		qse_mchar_t mdbgmsg[128]; | ||||
| 	} u; | ||||
| }; | ||||
| typedef struct qse_httpd_act_t qse_httpd_act_t; | ||||
|  | ||||
| @ -385,8 +385,13 @@ static int get_highest_fd (void) | ||||
| 		#endif | ||||
| 		} | ||||
| 		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--;  | ||||
| 	} | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
| #include <qse/cmn/str.h> | ||||
| #include <qse/cmn/pio.h> | ||||
| #include <qse/cmn/fmt.h> | ||||
| #include <qse/cmn/path.h> | ||||
|  | ||||
| #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; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	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) && | ||||
| 	    cgi->script_output_received > cgi->script_output_length) | ||||
| 	{ | ||||
| /* TODO: cgi returning too much data... something is wrong in CGI */ | ||||
| qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n")); | ||||
| 		/* cgi returning too much data... something is wrong in CGI */ | ||||
| 		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 */ | ||||
| 		return -1; | ||||
| 	} | ||||
| @ -501,8 +514,10 @@ static int cgi_snatch_client_input ( | ||||
| 	task = (qse_httpd_task_t*)ctx; | ||||
| 	cgi = (task_cgi_t*)task->ctx; | ||||
|  | ||||
| #if 0 | ||||
| if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr); | ||||
| else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); | ||||
| #endif | ||||
|  | ||||
| 	QSE_ASSERT (cgi->req); | ||||
| 	QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); | ||||
| @ -587,7 +602,9 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); | ||||
|  | ||||
| 		/* output pipe to child */ | ||||
| 		task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||
| #if 0 | ||||
| qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr); | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| @ -608,7 +625,9 @@ static void cgi_forward_client_input_to_script ( | ||||
| 		{ | ||||
| 			/* a forwarding error has occurred previously. | ||||
| 			 * clear the forwarding buffer */ | ||||
| #if 0 | ||||
| qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); | ||||
| #endif | ||||
| 			qse_mbs_clear (cgi->reqfwdbuf); | ||||
| 		} | ||||
| 		else | ||||
| @ -624,9 +643,11 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); | ||||
| 			{ | ||||
| 			forward: | ||||
| 				/* writable */ | ||||
| #if 0 | ||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), | ||||
| 	(int)QSE_MBS_LEN(cgi->reqfwdbuf), | ||||
| 	QSE_MBS_PTR(cgi->reqfwdbuf)); | ||||
| #endif | ||||
| 				n = qse_pio_write ( | ||||
| 					&cgi->pio, QSE_PIO_IN, | ||||
| 					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) | ||||
| 			{ | ||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n")); | ||||
| /* TODO: logging ... */ | ||||
| 				if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||
| 					log_cgi_script_error (cgi, QSE_MT("cgi pio write error - ")); | ||||
|  | ||||
| 				cgi->reqflags |= CGI_REQ_FWDERR; | ||||
| 				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. | ||||
| 		 * clear the relay and write triggers for the time being. | ||||
| 		 */ | ||||
| #if 0 | ||||
| qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n")); | ||||
| #endif | ||||
| 		QSE_ASSERT (cgi->req == QSE_NULL); | ||||
|  | ||||
| 		/* 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_htre_unsetconcb (cgi->req); | ||||
| 	} | ||||
| 		 | ||||
| qse_printf (QSE_T("task_fini_cgi\n")); | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	); | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| @ -942,13 +968,16 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client ( | ||||
| { | ||||
| 	qse_ssize_t n; | ||||
|  | ||||
| 	httpd->errnum = QSE_HTTPD_ENOERR; | ||||
| 	n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); | ||||
| 	if (n > 0) | ||||
| 	{ | ||||
| 		QSE_MEMCPY (&cgi->buf[0], &cgi->buf[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; | ||||
| } | ||||
|  | ||||
| @ -971,13 +1000,11 @@ static int task_main_cgi_5 ( | ||||
| 	if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || | ||||
| 	    (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_write_script_output_to_client (httpd, client, cgi) <= -1) | ||||
| 			{ | ||||
| 				/* can't return internal server error any more... */ | ||||
| /* TODO: logging ... */ | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| @ -1024,11 +1051,7 @@ static int task_main_cgi_4_nph ( | ||||
| 		} | ||||
|  | ||||
| 		QSE_ASSERT (cgi->buflen > 0); | ||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | ||||
| 		{ | ||||
| /* TODO: logging ... */ | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| @ -1043,8 +1066,10 @@ static int task_main_cgi_4 ( | ||||
| 	QSE_ASSERT (!cgi->nph); | ||||
| 	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"),  | ||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||
| #endif | ||||
|  | ||||
| 	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) | ||||
| 	{ | ||||
| qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | ||||
| 		if (cgi->resflags & CGI_RES_CLIENT_CHUNK) | ||||
| 		{ | ||||
| 			qse_size_t count, extra; | ||||
| @ -1068,7 +1092,6 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | ||||
| 	 | ||||
| #define CHLEN_RESERVE 6  | ||||
|  | ||||
| 	qse_printf (QSE_T("READING CHUNKED MODE...\n")); | ||||
| 			extra = CHLEN_RESERVE + 2; | ||||
| 			count = QSE_SIZEOF(cgi->buf) - cgi->buflen; | ||||
| 			if (count > extra) | ||||
| @ -1080,7 +1103,8 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | ||||
| 				); | ||||
| 				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; | ||||
| 				} | ||||
| 				if (n == 0)  | ||||
| @ -1121,15 +1145,15 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); | ||||
| 				if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && | ||||
| 				    cgi->script_output_received > cgi->script_output_length) | ||||
| 				{ | ||||
| 	/* TODO: cgi returning too much data... something is wrong in CGI */ | ||||
| 	qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); | ||||
| 					/* cgi returning too much data... something is wrong in CGI */ | ||||
| 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||
| 						log_cgi_script_error (cgi, QSE_MT("cgi redundant output - ")); | ||||
| 					return -1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 	qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n")); | ||||
| 			if (cgi->buflen < QSE_SIZEOF(cgi->buf)) | ||||
| 			{ | ||||
| 				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) && | ||||
| 				    cgi->script_output_received > cgi->script_output_length) | ||||
| 				{ | ||||
| 					/* TODO: logging */ | ||||
| 	/* TODO: cgi returning too much data... something is wrong in CGI */ | ||||
| 	qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); | ||||
| 					/* cgi returning too much data... something is wrong in CGI */ | ||||
| 					if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||
| 						log_cgi_script_error (cgi, QSE_MT("cgi redundant output - ")); | ||||
| 					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 | ||||
| 		 * this task function is called. */ | ||||
| 		QSE_ASSERT (cgi->buflen > 0); | ||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) | ||||
| 		{ | ||||
| 			/* TODO: logging ... */ | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| @ -1181,8 +1201,10 @@ static int task_main_cgi_3 ( | ||||
|  | ||||
| 	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"),  | ||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||
| #endif | ||||
| 	if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) | ||||
| 	{ | ||||
| 		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; | ||||
| 		if (count >= cgi->res_left) count = cgi->res_left; | ||||
|  | ||||
| qse_printf (QSE_T("[cgi_3 sending %d bytes]\n"), (int)count); | ||||
| 		if (count > 0) | ||||
| 		{ | ||||
| 			httpd->errnum = QSE_HTTPD_ENOERR; | ||||
| 			n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); | ||||
|  | ||||
| 			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; | ||||
| 			} | ||||
|  | ||||
| @ -1223,7 +1243,6 @@ qse_printf (QSE_T("[cgi-3 send failure....\n")); | ||||
| 			if ((cgi->resflags & CGI_RES_SCRIPT_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 | ||||
| 				 * and it has emitted as much as the length, | ||||
| 				 * i don't wait for the script to finish. | ||||
| @ -1236,7 +1255,6 @@ qse_printf (QSE_T("[switching to cgi-5....\n")); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| qse_printf (QSE_T("[switching to cgi-4....\n")); | ||||
| 				task->main = task_main_cgi_4; | ||||
| 				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->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"),  | ||||
| 	task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); | ||||
| #endif | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
| 	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) | ||||
| 	{ | ||||
| qse_printf (QSE_T("[cgi_2 read]\n")); | ||||
| 		n = qse_pio_read ( | ||||
| 			&cgi->pio, QSE_PIO_OUT, | ||||
| 			&cgi->buf[cgi->buflen],  | ||||
| @ -1286,25 +1304,24 @@ qse_printf (QSE_T("[cgi_2 read]\n")); | ||||
| 		if (n <= -1) | ||||
| 		{ | ||||
| 			/* 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; | ||||
| 		} | ||||
| 		if (n == 0)  | ||||
| 		{ | ||||
| 			/* end of output from cgi before it has seen a header. | ||||
| 			 * the cgi script must be crooked. */ | ||||
| /* TODO: logging */ | ||||
| qse_printf (QSE_T("#####PREMATURE EOF FROM CHILD\n")); | ||||
| 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||
| 				log_cgi_script_error (cgi, QSE_MT("cgi premature eof - ")); | ||||
| 			goto oops; | ||||
| 		} | ||||
| 			 | ||||
| 		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) | ||||
| 		{ | ||||
| /* TODO: logging */ | ||||
| qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->buflen, cgi->buf); | ||||
| 			if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)  | ||||
| 				log_cgi_script_error (cgi, QSE_MT("cgi feed error - ")); | ||||
| 			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_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)); | ||||
| #endif | ||||
| 			task->main = task_main_cgi_3; | ||||
| 			task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; | ||||
| 			return 1; | ||||
| @ -1447,7 +1466,6 @@ static int task_main_cgi ( | ||||
| 			 * this is possible because the main loop can still read  | ||||
| 			 * between the initializer function (task_init_cgi()) and  | ||||
| 			 * 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); | ||||
|  | ||||
| 			/* if the initial forwarding clears the forwarding  | ||||
|  | ||||
| @ -29,8 +29,8 @@ | ||||
| typedef struct task_proxy_arg_t task_proxy_arg_t; | ||||
| struct task_proxy_arg_t  | ||||
| { | ||||
| 	qse_nwad_t* peer_nwad; | ||||
| 	qse_nwad_t* peer_local; | ||||
| 	const qse_nwad_t* peer_nwad; | ||||
| 	const qse_nwad_t* peer_local; | ||||
| 	qse_htre_t* req; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -531,12 +531,15 @@ struct httpd_xtn_t | ||||
|  | ||||
| #if defined(HAVE_SSL) | ||||
| static int init_xtn_ssl ( | ||||
| 	httpd_xtn_t* xtn, | ||||
| 	qse_httpd_t* httpd, | ||||
| 	const qse_mchar_t* pemfile, | ||||
| 	const qse_mchar_t* keyfile/*, | ||||
| 	const qse_mchar_t* chainfile*/) | ||||
| { | ||||
| 	SSL_CTX* ctx; | ||||
| 	httpd_xtn_t* xtn; | ||||
|  | ||||
| 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | ||||
|  | ||||
| 	ctx = SSL_CTX_new (SSLv23_server_method()); | ||||
| 	if (ctx == QSE_NULL) return -1; | ||||
| @ -548,10 +551,14 @@ static int init_xtn_ssl ( | ||||
| 	    SSL_CTX_check_private_key (ctx) == 0 /*|| | ||||
| 	    SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/) | ||||
| 	{ | ||||
| 		qse_mchar_t buf[128]; | ||||
| 		ERR_error_string_n(ERR_get_error(), buf, QSE_COUNTOF(buf)); | ||||
| /* TODO: logging */ | ||||
| qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf); | ||||
| 		if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||
| 		{ | ||||
| 			qse_httpd_act_t msg; | ||||
| 			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); | ||||
| 		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); | ||||
|  | ||||
| #if defined(HAVE_SSL) | ||||
| 	/*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/ | ||||
| 	/*init_xtn_ssl (httpd, "http01.pem", "http01.key");*/ | ||||
| #endif | ||||
|  | ||||
| 	set_httpd_callbacks (httpd); | ||||
| @ -1409,7 +1416,16 @@ static int file_ropen ( | ||||
| 	} | ||||
|  | ||||
| 	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; | ||||
|  | ||||
| } | ||||
| @ -1438,13 +1454,22 @@ static int file_wopen ( | ||||
| 	} | ||||
|  | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| 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_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; | ||||
| 	} | ||||
| 		 | ||||
| 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; | ||||
| 	return 0; | ||||
| } | ||||
| @ -1693,7 +1727,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||
| 		{ | ||||
| 			/* delayed initialization of ssl */ | ||||
| /* 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; | ||||
| 			} | ||||
| @ -1711,9 +1745,6 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||
| 			if (ssl == QSE_NULL) return -1; | ||||
|  | ||||
| 			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) | ||||
| 			{ | ||||
| 				/* don't free ssl here since client_closed() | ||||
| @ -1727,18 +1758,25 @@ qse_fflush (QSE_STDOUT); | ||||
| 		ret = SSL_accept (ssl); | ||||
| 		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. */ | ||||
| 				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); */ | ||||
| 			return -1; | ||||
| 		} | ||||
| qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i); | ||||
| qse_fflush (QSE_STDOUT); | ||||
|  | ||||
| 	#else | ||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||
| 		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) | ||||
| { | ||||
| 	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; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static int process_request ( | ||||
| 	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 */ | ||||
| 	if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req)); | ||||
|  | ||||
| #if 0 | ||||
| qse_printf (QSE_T("================================\n")); | ||||
| qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), | ||||
| 	(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)); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| 	if (peek) | ||||
| 	{ | ||||
| @ -2044,11 +2086,12 @@ static void impede_httpd (qse_httpd_t* httpd) | ||||
| 	/* 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 */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static qse_httpd_scb_t httpd_system_callbacks = | ||||
| { | ||||
| 	/* server */ | ||||
| @ -2341,11 +2384,11 @@ static int make_resource ( | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 	if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -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_DOCROOT, &tmp.docroot) <= -1) return -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_INDEX, &tmp.index) <= -1) | ||||
| 	{ | ||||
| @ -2455,9 +2498,20 @@ auth_ok: | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			/* it is a directory - should i allow it? */ | ||||
| 			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 | ||||
| 		{ | ||||
| 			/* let me treat it as a file. */ | ||||
| @ -2478,6 +2532,16 @@ auth_ok: | ||||
| 		} | ||||
| 		if (n >= 1) return 0; | ||||
|  | ||||
| 		/* check file's access permission */ | ||||
| 		if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_FILEACC, &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 | ||||
| 		{ | ||||
| 			/* fall back to a normal file. */ | ||||
| 			target->type = QSE_HTTPD_RSRC_FILE; | ||||
| 			target->u.file.path = tmp.xpath; | ||||
| @ -2488,6 +2552,7 @@ auth_ok: | ||||
| 				target->u.file.mime = QSE_NULL; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @ -2581,6 +2646,12 @@ static int query_server ( | ||||
|  | ||||
| 			*(const qse_mchar_t**)result = QSE_NULL; | ||||
| 			return 0; | ||||
|  | ||||
| 		case QSE_HTTPD_SERVERSTD_DIRACC: | ||||
| 		case QSE_HTTPD_SERVERSTD_FILEACC: | ||||
| 			*(int*)result = 200; | ||||
| 			return 0; | ||||
| 			 | ||||
| 	} | ||||
|  | ||||
| 	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; | ||||
| 	next = client->next; | ||||
|  | ||||
| 	if (httpd->opt.trait & QSE_HTTPD_ENABLELOG) | ||||
| 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||
| 	{ | ||||
| 		qse_httpd_act_t msg; | ||||
| 		msg.code = QSE_HTTPD_PURGE_CLIENT; | ||||
| @ -562,13 +562,12 @@ qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i); | ||||
| 			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_nwadtostr (&client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | ||||
| qse_nwadtostr (&client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); | ||||
| qse_nwadtostr (&client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL); | ||||
| qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, tmp, tmp2, tmp3); | ||||
| 			qse_httpd_act_t msg; | ||||
| 			msg.code = QSE_HTTPD_ACCEPT_CLIENT; | ||||
| 			msg.u.client = client; | ||||
| 			httpd->opt.rcb.logact (httpd, &msg); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| @ -733,7 +732,6 @@ reread: | ||||
| 		if (httpd->errnum == QSE_HTTPD_EAGAIN) | ||||
| 		{ | ||||
| 			/* nothing to read yet. */ | ||||
| qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i); | ||||
| 			return 0; /* return ok */ | ||||
| 		} | ||||
| 		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 | ||||
| 		{ | ||||
| 			/* 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) | ||||
| 			{ | ||||
| 				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; | ||||
| 		} | ||||
| 	} | ||||
| 	else if (m == 0) | ||||
| 	{ | ||||
| #if 0 | ||||
| qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i); | ||||
| #endif | ||||
| 		/* reading from the client returned 0. this typically | ||||
| 		 * happens when the client closes the connection or | ||||
| 		 * 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  | ||||
| 			 * http reader is not waiting for any more feeds.  */ | ||||
| 			client->status |= CLIENT_MUTE; | ||||
| #if 0 | ||||
| qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i); | ||||
| #endif | ||||
| 			return 0; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| #if 0 | ||||
| qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i); | ||||
| #endif | ||||
| 			httpd->errnum = QSE_HTTPD_EDISCON; | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| #if 0 | ||||
| qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i); | ||||
| #if !defined(__WATCOMC__) | ||||
| { | ||||
| @ -783,6 +794,7 @@ for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); | ||||
| } | ||||
| #endif | ||||
| qse_printf (QSE_T("]\n")); | ||||
| #endif | ||||
|  | ||||
| 	/* qse_htrd_feed() may call the request callback  | ||||
| 	 * 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 */ | ||||
| 		} | ||||
| 	 | ||||
| #if 0 | ||||
| qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i); | ||||
| { | ||||
| int i; | ||||
| for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); | ||||
| } | ||||
| qse_printf (QSE_T("]\n")); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
| #if 0 | ||||
| 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)  | ||||
| 	{ | ||||
| @ -840,7 +856,6 @@ static int invoke_client_task ( | ||||
| 	int n, trigger_fired, client_handle_writable; | ||||
|  | ||||
| /* 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 (!(client->status & CLIENT_MUTE) &&  | ||||
| @ -850,7 +865,6 @@ qse_printf (QSE_T("INVOKE CLIENT TASK..........\n")); | ||||
| 			 * purge the client in perform_client_task(). | ||||
| 			 * thus the following line isn't necessary. | ||||
| 			 *if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/ | ||||
| qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i); | ||||
| 			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) | ||||
| 		{ | ||||
| 			/* 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; | ||||
| 		} | ||||
|  | ||||
| @ -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); | ||||
| qse_printf (QSE_T("task returend %d\n"), n); | ||||
| 	if (n <= -1) return -1; | ||||
| 	else if (n == 0) | ||||
| 	{ | ||||
| @ -1118,17 +1130,12 @@ static int perform_client_task ( | ||||
| 		qse_gettime (&client->last_active); /* TODO: error check??? */ | ||||
| 		move_client_to_tail (httpd, client); | ||||
|  | ||||
| 		if (invoke_client_task (httpd, client, handle, mask) <= -1)  | ||||
| 		{ | ||||
| qse_printf (QSE_T("OOPS AFTER CLIENT TASK BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i); | ||||
| 			goto oops; | ||||
| 		} | ||||
| 		if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| oops: | ||||
| qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i); | ||||
| 	/*purge_client (httpd, client);*/ | ||||
| 	client->status |= 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])); | ||||
| 	return httpd->gtbuf[idx]; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* --------------------------------------------------- */ | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -235,13 +235,16 @@ qse_xli_pair_t* qse_xli_insertpair ( | ||||
| 	if (pair == QSE_NULL) return QSE_NULL; | ||||
|  | ||||
| 	kptr = (qse_char_t*)(pair + 1); | ||||
| 	nptr = kptr + klen + 1; | ||||
| 	qse_strcpy (kptr, key); | ||||
| 	if (name) qse_strcpy (nptr, name); | ||||
|  | ||||
| 	pair->type = QSE_XLI_PAIR; | ||||
| 	pair->key = kptr; | ||||
| 	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  */ | ||||
|  | ||||
| 	insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user