revising httpd
This commit is contained in:
		| @ -1,2 +1,2 @@ | |||||||
| SUBDIRS = awk sed xli net  | SUBDIRS = awk sed xli http  | ||||||
| DIST_SUBDIRS = $(SUBDIRS)  | DIST_SUBDIRS = $(SUBDIRS)  | ||||||
|  | |||||||
| @ -270,7 +270,7 @@ target_alias = @target_alias@ | |||||||
| top_build_prefix = @top_build_prefix@ | top_build_prefix = @top_build_prefix@ | ||||||
| top_builddir = @top_builddir@ | top_builddir = @top_builddir@ | ||||||
| top_srcdir = @top_srcdir@ | top_srcdir = @top_srcdir@ | ||||||
| SUBDIRS = awk sed xli net  | SUBDIRS = awk sed xli http  | ||||||
| DIST_SUBDIRS = $(SUBDIRS)  | DIST_SUBDIRS = $(SUBDIRS)  | ||||||
| all: all-recursive | all: all-recursive | ||||||
|  |  | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ AM_CPPFLAGS = \ | |||||||
| bin_PROGRAMS = qsehttpd | bin_PROGRAMS = qsehttpd | ||||||
| 
 | 
 | ||||||
| qsehttpd_SOURCES = httpd.c | qsehttpd_SOURCES = httpd.c | ||||||
| qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir) | qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir) | ||||||
| qsehttpd_LDADD = -lqsenet -lqsecmn | qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn | ||||||
| 
 | 
 | ||||||
| if WIN32  | if WIN32  | ||||||
| if WCHAR | if WCHAR | ||||||
| @ -36,7 +36,7 @@ build_triplet = @build@ | |||||||
| host_triplet = @host@ | host_triplet = @host@ | ||||||
| bin_PROGRAMS = qsehttpd$(EXEEXT) | bin_PROGRAMS = qsehttpd$(EXEEXT) | ||||||
| @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) | @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) | ||||||
| subdir = cmd/net | subdir = cmd/http | ||||||
| DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | ||||||
| ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||||||
| am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | ||||||
| @ -276,8 +276,8 @@ AM_CPPFLAGS = \ | |||||||
| 	-I$(includedir) | 	-I$(includedir) | ||||||
| 
 | 
 | ||||||
| qsehttpd_SOURCES = httpd.c | qsehttpd_SOURCES = httpd.c | ||||||
| qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir) | qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir) | ||||||
| qsehttpd_LDADD = -lqsenet -lqsecmn $(am__append_1) | qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn $(am__append_1) | ||||||
| all: all-am | all: all-am | ||||||
| 
 | 
 | ||||||
| .SUFFIXES: | .SUFFIXES: | ||||||
| @ -291,9 +291,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps) | |||||||
| 	      exit 1;; \
 | 	      exit 1;; \
 | ||||||
| 	  esac; \
 | 	  esac; \
 | ||||||
| 	done; \
 | 	done; \
 | ||||||
| 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/net/Makefile'; \
 | 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/http/Makefile'; \
 | ||||||
| 	$(am__cd) $(top_srcdir) && \
 | 	$(am__cd) $(top_srcdir) && \
 | ||||||
| 	  $(AUTOMAKE) --foreign cmd/net/Makefile | 	  $(AUTOMAKE) --foreign cmd/http/Makefile | ||||||
| .PRECIOUS: Makefile | .PRECIOUS: Makefile | ||||||
| Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||||||
| 	@case '$?' in \
 | 	@case '$?' in \
 | ||||||
							
								
								
									
										555
									
								
								qse/cmd/http/httpd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								qse/cmd/http/httpd.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,555 @@ | |||||||
|  |  | ||||||
|  | #include <qse/http/std.h> | ||||||
|  | #include <qse/xli/std.h> | ||||||
|  | #include <qse/cmn/stdio.h> | ||||||
|  | #include <qse/cmn/main.h> | ||||||
|  | #include <qse/cmn/str.h> | ||||||
|  | #include <qse/cmn/mem.h> | ||||||
|  | #include <qse/cmn/mbwc.h> | ||||||
|  | #include <qse/cmn/time.h> | ||||||
|  |  | ||||||
|  | #include <signal.h> | ||||||
|  | #include <locale.h> | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | #	include <winsock2.h> | ||||||
|  | #	include <windows.h> | ||||||
|  | #	include <tchar.h> | ||||||
|  | #	include <process.h> | ||||||
|  | #elif defined(__OS2__) | ||||||
|  | #	define INCL_DOSPROCESS | ||||||
|  | #	define INCL_DOSEXCEPTIONS | ||||||
|  | #	define INCL_ERRORS | ||||||
|  | #	include <os2.h> | ||||||
|  | #elif defined(__DOS__) | ||||||
|  | #	include <dos.h> | ||||||
|  | #else | ||||||
|  | #	include <unistd.h> | ||||||
|  | #	include <errno.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(HAVE_SSL) | ||||||
|  | #	include <openssl/ssl.h> | ||||||
|  | #	include <openssl/err.h> | ||||||
|  | #	include <openssl/engine.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | static qse_httpd_t* g_httpd = QSE_NULL; | ||||||
|  |  | ||||||
|  | static void sigint (int sig) | ||||||
|  | { | ||||||
|  | 	if (g_httpd) qse_httpd_stop (g_httpd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void sighup (int sig) | ||||||
|  | { | ||||||
|  | 	if (g_httpd) qse_httpd_reconfig (g_httpd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void setup_signal_handlers () | ||||||
|  | { | ||||||
|  | 	struct sigaction act; | ||||||
|  |  | ||||||
|  | #if defined(SIGINT) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = sigint; | ||||||
|  | 	sigaction (SIGINT, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(SIGHUP) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = sighup; | ||||||
|  | 	sigaction (SIGHUP, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(SIGPIPE) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = SIG_IGN; | ||||||
|  | 	sigaction (SIGPIPE, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void restore_signal_handlers () | ||||||
|  | { | ||||||
|  | 	struct sigaction act; | ||||||
|  |  | ||||||
|  | #if defined(SIGINT) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = SIG_DFL; | ||||||
|  | 	sigaction (SIGINT, &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(SIGPIPE) | ||||||
|  | 	qse_memset (&act, 0, QSE_SIZEOF(act)); | ||||||
|  | 	act.sa_handler = SIG_DFL; | ||||||
|  | 	sigaction (SIGPIPE, &act, QSE_NULL); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | typedef struct server_xtn_t server_xtn_t; | ||||||
|  | struct server_xtn_t | ||||||
|  | { | ||||||
|  | 	int tproxy; | ||||||
|  | 	int nodir; /* no directory listing */ | ||||||
|  |  | ||||||
|  | 	qse_httpd_serverstd_makersrc_t orgmakersrc; | ||||||
|  | 	qse_httpd_serverstd_freersrc_t orgfreersrc; | ||||||
|  | 	qse_httpd_serverstd_query_t orgquery; | ||||||
|  |  | ||||||
|  | 	qse_mchar_t* docroot; | ||||||
|  | 	qse_mchar_t* realm; | ||||||
|  | 	qse_mchar_t* auth; | ||||||
|  | 	qse_mchar_t* dircss; | ||||||
|  | 	qse_mchar_t* errcss; | ||||||
|  | 	 | ||||||
|  | 	qse_httpd_serverstd_index_t index; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int make_resource ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client, | ||||||
|  | 	qse_htre_t* req, qse_httpd_rsrc_t* rsrc) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  |  | ||||||
|  | 	server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); | ||||||
|  |  | ||||||
|  | 	if (server_xtn->tproxy) | ||||||
|  | 	{ | ||||||
|  | 		if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */ | ||||||
|  | 		{ | ||||||
|  | 			/* TODO: implement a better check that the | ||||||
|  | 			 *       destination is not one of the local addresses */ | ||||||
|  |  | ||||||
|  | 			rsrc->type = QSE_HTTPD_RSRC_ERR; | ||||||
|  | 			rsrc->u.err.code = 500; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			rsrc->type = QSE_HTTPD_RSRC_PROXY; | ||||||
|  | 			rsrc->u.proxy.dst = client->orgdst_addr; | ||||||
|  | 			rsrc->u.proxy.src = client->remote_addr; | ||||||
|  | 	 | ||||||
|  | 			if (rsrc->u.proxy.src.type == QSE_NWAD_IN4) | ||||||
|  | 				rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */ | ||||||
|  | 			else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6) | ||||||
|  | 				rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */ | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (server_xtn->orgmakersrc (httpd, client, req, rsrc) <= -1) return -1; | ||||||
|  | 		if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR) | ||||||
|  | 		{ | ||||||
|  | 			/* prohibit no directory listing */ | ||||||
|  | 			if (server_xtn->orgfreersrc) | ||||||
|  | 				server_xtn->orgfreersrc (httpd, client, req, rsrc); | ||||||
|  | 			rsrc->type = QSE_HTTPD_RSRC_ERR; | ||||||
|  | 			rsrc->u.err.code = 403; | ||||||
|  | 		} | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void free_resource ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client,  | ||||||
|  | 	qse_htre_t* req, qse_httpd_rsrc_t* rsrc) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  |  | ||||||
|  | 	server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); | ||||||
|  |  | ||||||
|  | 	if (server_xtn->tproxy) | ||||||
|  | 	{ | ||||||
|  | 		/* nothing to do */ | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (server_xtn->orgfreersrc)  | ||||||
|  | 			server_xtn->orgfreersrc (httpd, client, req, rsrc); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  | static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  |  | ||||||
|  | 	server_xtn = qse_httpd_getserverxtnstd (httpd, server); | ||||||
|  |  | ||||||
|  | 	if (server_xtn->docroot) qse_httpd_freemem (httpd, server_xtn->docroot); | ||||||
|  | 	if (server_xtn->realm) qse_httpd_freemem (httpd, server_xtn->realm); | ||||||
|  | 	if (server_xtn->auth) qse_httpd_freemem (httpd, server_xtn->auth); | ||||||
|  | 	if (server_xtn->dircss) qse_httpd_freemem (httpd, server_xtn->dircss); | ||||||
|  | 	if (server_xtn->errcss) qse_httpd_freemem (httpd, server_xtn->errcss); | ||||||
|  | 	if (server_xtn->index.files) qse_httpd_freemem (httpd, server_xtn->index.files); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void reconfig_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
|  | { | ||||||
|  | 	qse_printf (QSE_T("reconfiguring server.....\n")); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int query_server ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_server_t* server,  | ||||||
|  | 	qse_htre_t* req, const qse_mchar_t* xpath, | ||||||
|  | 	qse_httpd_serverstd_query_code_t code, void* result) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  |  | ||||||
|  | 	server_xtn = qse_httpd_getserverxtnstd (httpd, server); | ||||||
|  |  | ||||||
|  | 	switch (code) | ||||||
|  | 	{ | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_DOCROOT: | ||||||
|  | 			*(const qse_mchar_t**)result = server_xtn->docroot; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_REALM: | ||||||
|  | 			*(const qse_mchar_t**)result = server_xtn->realm; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_AUTH: | ||||||
|  | 			*(const qse_mchar_t**)result = server_xtn->auth; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_DIRCSS: | ||||||
|  | 			*(const qse_mchar_t**)result = server_xtn->dircss; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_ERRCSS: | ||||||
|  | 			*(const qse_mchar_t**)result = server_xtn->errcss; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_INDEX: | ||||||
|  | 			*(qse_httpd_serverstd_index_t*)result = server_xtn->index; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_CGI: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_MIME: | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return server_xtn->orgquery (httpd, server, req, xpath, code, result); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | static int load_server (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list) | ||||||
|  | { | ||||||
|  | 	qse_httpd_serverstd_t server;  | ||||||
|  | 	qse_httpd_server_t* xserver; | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  | 	qse_xli_pair_t* pair; | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("bind")); | ||||||
|  | 	if (pair == QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		/* TOOD: logging */ | ||||||
|  | 		qse_printf (QSE_T("WARNING: no bind specified for  ....\n")); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (pair->val->type != QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/*  TOOD: logging */ | ||||||
|  | 		qse_printf (QSE_T("WARNING: non-string value for bind\n")); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	qse_memset (&server, 0, QSE_SIZEOF(server)); | ||||||
|  | 	if (qse_strtonwad (((qse_xli_str_t*)pair->val)->ptr, &server.nwad) <= -1) | ||||||
|  | 	{ | ||||||
|  | 		/*  TOOD: logging */ | ||||||
|  | 		qse_printf (QSE_T("WARNING: invalid value for bind - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	server.predetach = predetach_server; | ||||||
|  | 	xserver = qse_httpd_attachserverstd (httpd, &server, QSE_SIZEOF(server_xtn_t)); | ||||||
|  | 	if (xserver == QSE_NULL)  | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: logging */ | ||||||
|  | 		qse_printf (QSE_T("WARNING: failed to attach server\n")); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	server_xtn = qse_httpd_getserverxtnstd (httpd, xserver); | ||||||
|  |  | ||||||
|  | 	qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, &server_xtn->orgquery); | ||||||
|  | 	qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, query_server); | ||||||
|  |  | ||||||
|  | 	qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, &server_xtn->orgmakersrc); | ||||||
|  | 	qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, make_resource); | ||||||
|  |  | ||||||
|  | 	qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, &server_xtn->orgfreersrc); | ||||||
|  | 	qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, free_resource); | ||||||
|  |  | ||||||
|  | 	/* --------------------------------------------------------------------- */ | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].docroot")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.docroot")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: use a table */ | ||||||
|  |  | ||||||
|  | 		server_xtn->docroot = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		if (server_xtn->docroot == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy docroot - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].realm")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.realm")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: use a table */ | ||||||
|  |  | ||||||
|  | 		server_xtn->realm = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		if (server_xtn->realm == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy realm - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].auth")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.auth")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: use a table */ | ||||||
|  | 		server_xtn->auth = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		if (server_xtn->auth == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy auth - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (qse_mbschr (server_xtn->auth, QSE_MT(':')) == QSE_NULL) | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: no colon in the auth string - [%hs]\n"), server_xtn->auth); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.dir")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.dir")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: use a table */ | ||||||
|  | 		server_xtn->dircss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		if (server_xtn->dircss == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.error")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.error")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: use a table */ | ||||||
|  |  | ||||||
|  | 		server_xtn->errcss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 		if (server_xtn->errcss == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].index")); | ||||||
|  | 	if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.index")); | ||||||
|  | 	if (pair && pair->val->type == QSE_XLI_STR) | ||||||
|  | 	{ | ||||||
|  | 		const qse_char_t* tmpptr, * tmpend; | ||||||
|  | 		qse_size_t count; | ||||||
|  |  | ||||||
|  | 		tmpptr = ((qse_xli_str_t*)pair->val)->ptr; | ||||||
|  | 		tmpend = tmpptr + ((qse_xli_str_t*)pair->val)->len; | ||||||
|  | 	 | ||||||
|  | 		for (count = 0; tmpptr < tmpend; count++) tmpptr += qse_strlen (tmpptr) + 1; | ||||||
|  |  | ||||||
|  | 		server_xtn->index.count = count; | ||||||
|  | 		server_xtn->index.files = qse_httpd_strntombsdup ( | ||||||
|  | 			httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len); | ||||||
|  | 		if (server_xtn->index.files == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_printf (QSE_T("WARNING: fail to copy index\n")); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int load_config (qse_httpd_t* httpd, qse_xli_t* xli, const qse_char_t* file) | ||||||
|  | { | ||||||
|  | 	qse_xli_iostd_t xli_in; | ||||||
|  | 	qse_xli_pair_t* pair; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	xli_in.type = QSE_XLI_IOSTD_FILE; | ||||||
|  | 	xli_in.u.file.path = file; | ||||||
|  | 	xli_in.u.file.cmgr = QSE_NULL; | ||||||
|  |  | ||||||
|  | 	if (qse_xli_readstd (xli, &xli_in) <= -1) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("Cannot load %s - %s\n"), xli_in.u.file.path, qse_xli_geterrmsg(xli)); | ||||||
|  | 		return - 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for (i = 0; ; i++) | ||||||
|  | 	{ | ||||||
|  | 		qse_char_t buf[32]; | ||||||
|  | 		qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("server[%d]"), i); | ||||||
|  | 		pair = qse_xli_findpairbyname (xli, QSE_NULL, buf); | ||||||
|  | 		if (pair == QSE_NULL) break; | ||||||
|  |  | ||||||
|  | 		if (pair->val->type != QSE_XLI_LIST) | ||||||
|  | 		{ | ||||||
|  | 			qse_fprintf (QSE_STDERR, QSE_T("WARNING: non-list value for server\n")); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			load_server (httpd, xli, (qse_xli_list_t*)pair->val); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (i == 0) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("No valid server specified in %s\n"), xli_in.u.file.path); | ||||||
|  | 		return - 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* --------------------------------------------------------------------- */ | ||||||
|  | static int httpd_main (int argc, qse_char_t* argv[]) | ||||||
|  | { | ||||||
|  | 	qse_httpd_t* httpd = QSE_NULL; | ||||||
|  | 	qse_xli_t* xli = QSE_NULL; | ||||||
|  | 	qse_ntime_t tmout; | ||||||
|  | 	int ret = -1, i; | ||||||
|  | 	int trait; | ||||||
|  |  | ||||||
|  | 	if (argc != 2) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO: proper check... */ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t)); | ||||||
|  | 	if (httpd == QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n")); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	xli = qse_xli_openstd (0); | ||||||
|  | 	if (xli == QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("Cannot open xli\n")); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	qse_xli_getopt (xli, QSE_XLI_TRAIT, &trait); | ||||||
|  | 	trait |= QSE_XLI_KEYNAME; | ||||||
|  | 	qse_xli_setopt (xli, QSE_XLI_TRAIT, &trait); | ||||||
|  | 	if (load_config (httpd, xli, argv[1]) <= -1) goto oops; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	g_httpd = httpd; | ||||||
|  | 	setup_signal_handlers (); | ||||||
|  |  | ||||||
|  | 	qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0")); | ||||||
|  |  | ||||||
|  | 	qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait); | ||||||
|  | 	trait |= QSE_HTTPD_CGIERRTONUL; | ||||||
|  | 	qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait); | ||||||
|  |  | ||||||
|  | 	tmout.sec = 10; | ||||||
|  | 	tmout.nsec = 0; | ||||||
|  | 	ret = qse_httpd_loopstd (httpd, &tmout); | ||||||
|  |  | ||||||
|  | 	restore_signal_handlers (); | ||||||
|  | 	g_httpd = QSE_NULL; | ||||||
|  |  | ||||||
|  | 	if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error - %d\n"), qse_httpd_geterrnum (httpd)); | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (xli) qse_xli_close (xli); | ||||||
|  | 	if (httpd) qse_httpd_close (httpd); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int qse_main (int argc, qse_achar_t* argv[]) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	char locale[100]; | ||||||
|  | 	UINT codepage; | ||||||
|  | 	WSADATA wsadata; | ||||||
|  |  | ||||||
|  | 	codepage = GetConsoleOutputCP(); | ||||||
|  | 	if (codepage == CP_UTF8) | ||||||
|  | 	{ | ||||||
|  | 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||||
|  | 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		sprintf (locale, ".%u", (unsigned int)codepage); | ||||||
|  | 		setlocale (LC_ALL, locale); | ||||||
|  | 		qse_setdflcmgrbyid (QSE_CMGR_SLMB); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n")); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | 	setlocale (LC_ALL, ""); | ||||||
|  | 	qse_setdflcmgrbyid (QSE_CMGR_SLMB); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(HAVE_SSL)     | ||||||
|  | 	SSL_load_error_strings (); | ||||||
|  | 	SSL_library_init (); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	ret = qse_runmain (argc, argv, httpd_main); | ||||||
|  |  | ||||||
|  | #if defined(HAVE_SSL) | ||||||
|  | 	/*ERR_remove_state ();*/ | ||||||
|  | 	ENGINE_cleanup (); | ||||||
|  | 	ERR_free_strings (); | ||||||
|  | 	EVP_cleanup (); | ||||||
|  | 	CRYPTO_cleanup_all_ex_data (); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	WSACleanup ();	 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										44
									
								
								qse/cmd/http/httpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								qse/cmd/http/httpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | # | ||||||
|  | # this is a sample configuration file for qsehttpd. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | server { | ||||||
|  | 	bind = "0.0.0.0:80"; | ||||||
|  |  | ||||||
|  | 	ssl { | ||||||
|  | 		certificate { | ||||||
|  | 			private = "xxxx"; | ||||||
|  | 			public = "xxxx"; | ||||||
|  | 		}		 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	root = "/home/www/default"; | ||||||
|  | 	option = "xxxx,xxx,xxxx"; | ||||||
|  |  | ||||||
|  | 	realm { | ||||||
|  | 		name = "xxxxxx"; | ||||||
|  | 		password = "zzzzzzzzzzzzzzzz"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cgi { | ||||||
|  | 		suffix ".ant" = "xxxxx"; | ||||||
|  | 		suffix ".cgi"; | ||||||
|  | 		suffix ".nph"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mime { | ||||||
|  | 		suffix ".jpg" = "image/picture"; | ||||||
|  | 		suffix ".txt" = "text/plain"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	# virtual host | ||||||
|  | 	host "www.google.com" { | ||||||
|  | 		root = "/home/www/google";	 | ||||||
|  | 		option = "xxx, xxx, xxxx"; | ||||||
|  |  | ||||||
|  | 		realm { | ||||||
|  | 			name = "www.google.com"; | ||||||
|  | 			password = "zzzzzzzzzzzzzzzz"; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -1,296 +0,0 @@ | |||||||
|  |  | ||||||
| #include <qse/net/httpd.h> |  | ||||||
| #include <qse/cmn/stdio.h> |  | ||||||
| #include <qse/cmn/main.h> |  | ||||||
| #include <qse/cmn/str.h> |  | ||||||
| #include <qse/cmn/mem.h> |  | ||||||
| #include <qse/cmn/mbwc.h> |  | ||||||
| #include <qse/cmn/time.h> |  | ||||||
|  |  | ||||||
| #include <signal.h> |  | ||||||
| #include <locale.h> |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) |  | ||||||
| #	include <winsock2.h> |  | ||||||
| #	include <windows.h> |  | ||||||
| #	include <tchar.h> |  | ||||||
| #	include <process.h> |  | ||||||
| #elif defined(__OS2__) |  | ||||||
| #	define INCL_DOSPROCESS |  | ||||||
| #	define INCL_DOSEXCEPTIONS |  | ||||||
| #	define INCL_ERRORS |  | ||||||
| #	include <os2.h> |  | ||||||
| #elif defined(__DOS__) |  | ||||||
| #	include <dos.h> |  | ||||||
| #else |  | ||||||
| #	include <unistd.h> |  | ||||||
| #	include <errno.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL) |  | ||||||
| #	include <openssl/ssl.h> |  | ||||||
| #	include <openssl/err.h> |  | ||||||
| #	include <openssl/engine.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| static qse_httpd_t* g_httpd = QSE_NULL; |  | ||||||
|  |  | ||||||
| static void sigint (int sig) |  | ||||||
| { |  | ||||||
| 	if (g_httpd) qse_httpd_stop (g_httpd); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| typedef struct server_xtn_t server_xtn_t; |  | ||||||
| struct server_xtn_t |  | ||||||
| { |  | ||||||
| 	int tproxy; |  | ||||||
| 	int nodir; /* no directory listing */ |  | ||||||
| 	qse_httpd_server_cbstd_t* orgcbstd; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static int makersrc ( |  | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, |  | ||||||
| 	qse_htre_t* req, qse_httpd_rsrc_t* rsrc) |  | ||||||
| { |  | ||||||
| 	server_xtn_t* server_xtn; |  | ||||||
|  |  | ||||||
| 	server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); |  | ||||||
|  |  | ||||||
| 	if (server_xtn->tproxy) |  | ||||||
| 	{ |  | ||||||
| 		if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */ |  | ||||||
| 		{ |  | ||||||
| 			/* TODO: implement a better check that the |  | ||||||
| 			 *       destination is not one of the local addresses */ |  | ||||||
|  |  | ||||||
| 			rsrc->type = QSE_HTTPD_RSRC_ERR; |  | ||||||
| 			rsrc->u.err.code = 500; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			rsrc->type = QSE_HTTPD_RSRC_PROXY; |  | ||||||
| 			rsrc->u.proxy.dst = client->orgdst_addr; |  | ||||||
| 			rsrc->u.proxy.src = client->remote_addr; |  | ||||||
| 	 |  | ||||||
| 			if (rsrc->u.proxy.src.type == QSE_NWAD_IN4) |  | ||||||
| 				rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */ |  | ||||||
| 			else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6) |  | ||||||
| 				rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */ |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		if (server_xtn->orgcbstd->makersrc (httpd, client, req, rsrc) <= -1) return -1; |  | ||||||
| 		if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR) |  | ||||||
| 		{ |  | ||||||
| 			/* prohibit no directory listing */ |  | ||||||
| 			if (server_xtn->orgcbstd->freersrc) |  | ||||||
| 				server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc); |  | ||||||
| 			rsrc->type = QSE_HTTPD_RSRC_ERR; |  | ||||||
| 			rsrc->u.err.code = 403; |  | ||||||
| 		} |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void freersrc ( |  | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client,  |  | ||||||
| 	qse_htre_t* req, qse_httpd_rsrc_t* rsrc) |  | ||||||
| { |  | ||||||
| 	server_xtn_t* server_xtn; |  | ||||||
|  |  | ||||||
| 	server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); |  | ||||||
|  |  | ||||||
| 	if (server_xtn->tproxy) |  | ||||||
| 	{ |  | ||||||
| 		/* nothing to do */ |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		if (server_xtn->orgcbstd->freersrc)  |  | ||||||
| 			server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| static qse_httpd_server_t* attach_server ( |  | ||||||
| 	qse_httpd_t* httpd, qse_char_t* uri, qse_httpd_server_cbstd_t* cbstd) |  | ||||||
| { |  | ||||||
| 	qse_httpd_server_t* server; |  | ||||||
| 	server_xtn_t* server_xtn; |  | ||||||
| 	int tproxy = 0; |  | ||||||
|  |  | ||||||
| 	static qse_httpd_server_idxstd_t idxstd[] = |  | ||||||
| 	{ |  | ||||||
| 		{ QSE_MT("index.cgi")  }, |  | ||||||
| 		{ QSE_MT("index.html") }, |  | ||||||
| 		{ QSE_NULL             } |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	if (qse_strzcasecmp (uri, QSE_T("http-tproxy://"), 14) == 0) |  | ||||||
| 	{ |  | ||||||
| 		tproxy = 1; |  | ||||||
| 		qse_strcpy (&uri[4], &uri[11]);  |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	server = qse_httpd_attachserverstd ( |  | ||||||
| 		httpd, uri, QSE_NULL, QSE_SIZEOF(server_xtn_t)); |  | ||||||
| 	if (server == QSE_NULL) return QSE_NULL; |  | ||||||
|  |  | ||||||
| 	/* qse_httpd_getserverxtnstd() returns the pointer to  |  | ||||||
| 	 * the extension space requested above, of the size |  | ||||||
| 	 * QSE_SIZEOF(server_xtn_t) */ |  | ||||||
| 	server_xtn = qse_httpd_getserverxtnstd (httpd, server); |  | ||||||
| 	server_xtn->tproxy = tproxy; |  | ||||||
|  |  | ||||||
| 	/* qse_httpd_getserverxtn() returns the pointer to the |  | ||||||
| 	 * extension space created by qse_httpd_attachserverstd() |  | ||||||
| 	 * internally. |  | ||||||
| 	 */ |  | ||||||
| 	/* remember the callback set in qse_httpd_attachserverstd() */ |  | ||||||
| 	qse_httpd_getserveroptstd ( |  | ||||||
| 		httpd, server,  |  | ||||||
| 		QSE_HTTPD_SERVER_CBSTD, (void**)&server_xtn->orgcbstd); |  | ||||||
| 	/* override it with a new callback for chaining */ |  | ||||||
| 	qse_httpd_setserveroptstd ( |  | ||||||
| 		httpd, server, |  | ||||||
| 		QSE_HTTPD_SERVER_CBSTD, cbstd); |  | ||||||
|  |  | ||||||
| 	/* totally override idxstd without remembering the old idxstd */ |  | ||||||
| 	qse_httpd_setserveroptstd ( |  | ||||||
| 		httpd, server, |  | ||||||
| 		QSE_HTTPD_SERVER_IDXSTD, idxstd); |  | ||||||
|  |  | ||||||
| 	qse_httpd_setserveroptstd ( |  | ||||||
| 		httpd, server, QSE_HTTPD_SERVER_DIRCSS,  |  | ||||||
| 		QSE_MT("<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>")); |  | ||||||
|  |  | ||||||
| 	qse_httpd_setserveroptstd ( |  | ||||||
| 		httpd, server, QSE_HTTPD_SERVER_ERRCSS,  |  | ||||||
| 		QSE_MT("<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>")); |  | ||||||
| 	 |  | ||||||
| 	return server; |  | ||||||
| } |  | ||||||
| /* --------------------------------------------------------------------- */ |  | ||||||
| static int httpd_main (int argc, qse_char_t* argv[]) |  | ||||||
| { |  | ||||||
| 	qse_httpd_t* httpd = QSE_NULL; |  | ||||||
| 	qse_ntime_t tmout; |  | ||||||
| 	int ret = -1, i; |  | ||||||
| 	int trait; |  | ||||||
| 	static qse_httpd_server_cbstd_t cbstd = { makersrc, freersrc }; |  | ||||||
|  |  | ||||||
| 	if (argc <= 1) |  | ||||||
| 	{ |  | ||||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri> ...\n"), argv[0]); |  | ||||||
| 		goto oops; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t)); |  | ||||||
| 	if (httpd == QSE_NULL) |  | ||||||
| 	{ |  | ||||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n")); |  | ||||||
| 		goto oops; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for (i = 1; i < argc; i++) |  | ||||||
| 	{ |  | ||||||
| 		if (attach_server (httpd, argv[i], &cbstd) == QSE_NULL) |  | ||||||
| 		{ |  | ||||||
| 			qse_fprintf (QSE_STDERR, |  | ||||||
| 				QSE_T("Failed to add httpd listener - %s\n"), argv[i]); |  | ||||||
| 			goto oops; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	g_httpd = httpd; |  | ||||||
| 	signal (SIGINT, sigint); |  | ||||||
| #if defined(SIGPIPE) |  | ||||||
| 	signal (SIGPIPE, SIG_IGN); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0")); |  | ||||||
|  |  | ||||||
| 	trait = QSE_HTTPD_CGIERRTONUL; |  | ||||||
| 	qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait); |  | ||||||
|  |  | ||||||
| 	tmout.sec = 10; |  | ||||||
| 	tmout.nsec = 0; |  | ||||||
| 	ret = qse_httpd_loopstd (httpd, &tmout); |  | ||||||
|  |  | ||||||
| 	signal (SIGINT, SIG_DFL); |  | ||||||
| #if defined(SIGPIPE) |  | ||||||
| 	signal (SIGPIPE, SIG_DFL); |  | ||||||
| #endif |  | ||||||
| 	g_httpd = QSE_NULL; |  | ||||||
|  |  | ||||||
| 	if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error\n")); |  | ||||||
|  |  | ||||||
| oops: |  | ||||||
| 	if (httpd) qse_httpd_close (httpd); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int qse_main (int argc, qse_achar_t* argv[]) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) |  | ||||||
| 	char locale[100]; |  | ||||||
| 	UINT codepage; |  | ||||||
| 	WSADATA wsadata; |  | ||||||
|  |  | ||||||
| 	codepage = GetConsoleOutputCP(); |  | ||||||
| 	if (codepage == CP_UTF8) |  | ||||||
| 	{ |  | ||||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ |  | ||||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		sprintf (locale, ".%u", (unsigned int)codepage); |  | ||||||
| 		setlocale (LC_ALL, locale); |  | ||||||
| 		qse_setdflcmgrbyid (QSE_CMGR_SLMB); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0) |  | ||||||
| 	{ |  | ||||||
| 		qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n")); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| 	setlocale (LC_ALL, ""); |  | ||||||
| 	qse_setdflcmgrbyid (QSE_CMGR_SLMB); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL)     |  | ||||||
| 	SSL_load_error_strings (); |  | ||||||
| 	SSL_library_init (); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	ret = qse_runmain (argc, argv, httpd_main); |  | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL) |  | ||||||
| 	/*ERR_remove_state ();*/ |  | ||||||
| 	ENGINE_cleanup (); |  | ||||||
| 	ERR_free_strings (); |  | ||||||
| 	EVP_cleanup (); |  | ||||||
| 	CRYPTO_cleanup_all_ex_data (); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) |  | ||||||
| 	WSACleanup ();	 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @ -52,6 +52,7 @@ | |||||||
|  |  | ||||||
| static qse_char_t* g_input_file = QSE_NULL; | static qse_char_t* g_input_file = QSE_NULL; | ||||||
| static qse_char_t* g_output_file = QSE_NULL; | static qse_char_t* g_output_file = QSE_NULL; | ||||||
|  | static qse_char_t* g_lookup_key = QSE_NULL; | ||||||
| static qse_ulong_t g_memlimit = 0; | static qse_ulong_t g_memlimit = 0; | ||||||
| static int g_trait = 0; | static int g_trait = 0; | ||||||
|  |  | ||||||
| @ -122,7 +123,7 @@ static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[]) | |||||||
| { | { | ||||||
| 	const qse_char_t* b = qse_basename (argv[0]); | 	const qse_char_t* b = qse_basename (argv[0]); | ||||||
|  |  | ||||||
| 	qse_fprintf (out, QSE_T("USAGE: %s [options] -f input-file\n"), b); | 	qse_fprintf (out, QSE_T("USAGE: %s [options] -f input-file [key]\n"), b); | ||||||
|  |  | ||||||
| 	qse_fprintf (out, QSE_T("options as follows:\n")); | 	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(" -h/--help                 show this message\n")); | ||||||
| @ -201,7 +202,7 @@ static int handle_args (int argc, qse_char_t* argv[]) | |||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case QSE_T('n'): | 			case QSE_T('n'): | ||||||
| 				g_trait |= QSE_XLI_NAMEDKEY; | 				g_trait |= QSE_XLI_KEYNAME; | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case QSE_T('m'): | 			case QSE_T('m'): | ||||||
| @ -251,6 +252,14 @@ static int handle_args (int argc, qse_char_t* argv[]) | |||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (opt.ind < argc) g_lookup_key = argv[opt.ind++]; | ||||||
|  |  | ||||||
|  | 	if (opt.ind < argc) | ||||||
|  | 	{ | ||||||
|  | 		print_usage (QSE_STDERR, argc, argv); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| @ -287,7 +296,6 @@ static int xli_main (int argc, qse_char_t* argv[]) | |||||||
| { | { | ||||||
| 	qse_mmgr_t* mmgr = QSE_MMGR_GETDFL(); | 	qse_mmgr_t* mmgr = QSE_MMGR_GETDFL(); | ||||||
| 	qse_xli_t* xli = QSE_NULL; | 	qse_xli_t* xli = QSE_NULL; | ||||||
| 	qse_fs_t* fs = QSE_NULL; |  | ||||||
| 	qse_xli_iostd_t in, out; | 	qse_xli_iostd_t in, out; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
|  |  | ||||||
| @ -361,11 +369,41 @@ static int xli_main (int argc, qse_char_t* argv[]) | |||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (g_lookup_key) | ||||||
|  | 	{ | ||||||
|  | 		qse_xli_pair_t* pair; | ||||||
|  | 		pair = qse_xli_findpairbyname (xli, QSE_NULL, g_lookup_key); | ||||||
|  | 		if (pair == QSE_NULL) | ||||||
|  | 		{ | ||||||
|  | 			qse_fprintf (QSE_STDERR,  | ||||||
|  | 				QSE_T("ERROR: cannot find %s - %s \n"), | ||||||
|  | 				g_lookup_key, | ||||||
|  | 				qse_xli_geterrmsg(xli) | ||||||
|  | 			); | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (pair->val->type == QSE_XLI_STR) | ||||||
|  | 			{ | ||||||
|  | 				qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | ||||||
|  | 				qse_printf (QSE_T("[%.*s]\n"), (int)str->len, str->ptr); | ||||||
|  | 			} | ||||||
|  | 			else if (pair->val->type == QSE_XLI_NIL) | ||||||
|  | 			{ | ||||||
|  | 				qse_printf (QSE_T("#NIL\n")); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				qse_printf (QSE_T("#LIST\n")); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	ret = 0; | 	ret = 0; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	if (xli) qse_xli_close (xli); | 	if (xli) qse_xli_close (xli); | ||||||
| 	if (fs) qse_fs_close (fs); |  | ||||||
| 	if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx); | 	if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx); | ||||||
|  |  | ||||||
| #if defined(QSE_BUILD_DEBUG) | #if defined(QSE_BUILD_DEBUG) | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								qse/configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								qse/configure
									
									
									
									
										vendored
									
									
								
							| @ -20893,7 +20893,7 @@ QSE_PROJECT_AUTHOR="${PACKAGE_BUGREPORT}" | |||||||
| QSE_PROJECT_URL="${PACKAGE_URL}" | QSE_PROJECT_URL="${PACKAGE_URL}" | ||||||
|  |  | ||||||
|  |  | ||||||
| ac_config_files="$ac_config_files Makefile README include/Makefile include/qse/Makefile include/qse/cmn/Makefile include/qse/awk/Makefile include/qse/sed/Makefile include/qse/xli/Makefile include/qse/net/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/sed/Makefile lib/xli/Makefile lib/net/Makefile cmd/Makefile cmd/awk/Makefile cmd/sed/Makefile cmd/xli/Makefile cmd/net/Makefile samples/Makefile samples/cmn/Makefile samples/awk/Makefile samples/sed/Makefile samples/net/Makefile regress/Makefile regress/awk/Makefile regress/awk/regress.sh regress/sed/Makefile regress/sed/regress.sh doc/Makefile doc/Doxyfile tools/Makefile" | ac_config_files="$ac_config_files Makefile README include/Makefile include/qse/Makefile include/qse/cmn/Makefile include/qse/awk/Makefile include/qse/sed/Makefile include/qse/xli/Makefile include/qse/http/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/sed/Makefile lib/xli/Makefile lib/http/Makefile cmd/Makefile cmd/awk/Makefile cmd/sed/Makefile cmd/xli/Makefile cmd/http/Makefile samples/Makefile samples/cmn/Makefile samples/awk/Makefile samples/sed/Makefile samples/http/Makefile regress/Makefile regress/awk/Makefile regress/awk/regress.sh regress/sed/Makefile regress/sed/regress.sh doc/Makefile doc/Doxyfile tools/Makefile" | ||||||
|  |  | ||||||
| cat >confcache <<\_ACEOF | cat >confcache <<\_ACEOF | ||||||
| # This file is a shell script that caches the results of configure | # This file is a shell script that caches the results of configure | ||||||
| @ -22073,23 +22073,23 @@ do | |||||||
|     "include/qse/awk/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/awk/Makefile" ;; |     "include/qse/awk/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/awk/Makefile" ;; | ||||||
|     "include/qse/sed/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/sed/Makefile" ;; |     "include/qse/sed/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/sed/Makefile" ;; | ||||||
|     "include/qse/xli/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/xli/Makefile" ;; |     "include/qse/xli/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/xli/Makefile" ;; | ||||||
|     "include/qse/net/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/net/Makefile" ;; |     "include/qse/http/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/http/Makefile" ;; | ||||||
|     "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; |     "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; | ||||||
|     "lib/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cmn/Makefile" ;; |     "lib/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cmn/Makefile" ;; | ||||||
|     "lib/awk/Makefile") CONFIG_FILES="$CONFIG_FILES lib/awk/Makefile" ;; |     "lib/awk/Makefile") CONFIG_FILES="$CONFIG_FILES lib/awk/Makefile" ;; | ||||||
|     "lib/sed/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sed/Makefile" ;; |     "lib/sed/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sed/Makefile" ;; | ||||||
|     "lib/xli/Makefile") CONFIG_FILES="$CONFIG_FILES lib/xli/Makefile" ;; |     "lib/xli/Makefile") CONFIG_FILES="$CONFIG_FILES lib/xli/Makefile" ;; | ||||||
|     "lib/net/Makefile") CONFIG_FILES="$CONFIG_FILES lib/net/Makefile" ;; |     "lib/http/Makefile") CONFIG_FILES="$CONFIG_FILES lib/http/Makefile" ;; | ||||||
|     "cmd/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/Makefile" ;; |     "cmd/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/Makefile" ;; | ||||||
|     "cmd/awk/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/awk/Makefile" ;; |     "cmd/awk/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/awk/Makefile" ;; | ||||||
|     "cmd/sed/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/sed/Makefile" ;; |     "cmd/sed/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/sed/Makefile" ;; | ||||||
|     "cmd/xli/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/xli/Makefile" ;; |     "cmd/xli/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/xli/Makefile" ;; | ||||||
|     "cmd/net/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/net/Makefile" ;; |     "cmd/http/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/http/Makefile" ;; | ||||||
|     "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;; |     "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;; | ||||||
|     "samples/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES samples/cmn/Makefile" ;; |     "samples/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES samples/cmn/Makefile" ;; | ||||||
|     "samples/awk/Makefile") CONFIG_FILES="$CONFIG_FILES samples/awk/Makefile" ;; |     "samples/awk/Makefile") CONFIG_FILES="$CONFIG_FILES samples/awk/Makefile" ;; | ||||||
|     "samples/sed/Makefile") CONFIG_FILES="$CONFIG_FILES samples/sed/Makefile" ;; |     "samples/sed/Makefile") CONFIG_FILES="$CONFIG_FILES samples/sed/Makefile" ;; | ||||||
|     "samples/net/Makefile") CONFIG_FILES="$CONFIG_FILES samples/net/Makefile" ;; |     "samples/http/Makefile") CONFIG_FILES="$CONFIG_FILES samples/http/Makefile" ;; | ||||||
|     "regress/Makefile") CONFIG_FILES="$CONFIG_FILES regress/Makefile" ;; |     "regress/Makefile") CONFIG_FILES="$CONFIG_FILES regress/Makefile" ;; | ||||||
|     "regress/awk/Makefile") CONFIG_FILES="$CONFIG_FILES regress/awk/Makefile" ;; |     "regress/awk/Makefile") CONFIG_FILES="$CONFIG_FILES regress/awk/Makefile" ;; | ||||||
|     "regress/awk/regress.sh") CONFIG_FILES="$CONFIG_FILES regress/awk/regress.sh" ;; |     "regress/awk/regress.sh") CONFIG_FILES="$CONFIG_FILES regress/awk/regress.sh" ;; | ||||||
|  | |||||||
| @ -529,23 +529,23 @@ AC_CONFIG_FILES([ | |||||||
| 	include/qse/awk/Makefile | 	include/qse/awk/Makefile | ||||||
| 	include/qse/sed/Makefile | 	include/qse/sed/Makefile | ||||||
| 	include/qse/xli/Makefile | 	include/qse/xli/Makefile | ||||||
| 	include/qse/net/Makefile | 	include/qse/http/Makefile | ||||||
| 	lib/Makefile  | 	lib/Makefile  | ||||||
| 	lib/cmn/Makefile  | 	lib/cmn/Makefile  | ||||||
| 	lib/awk/Makefile  | 	lib/awk/Makefile  | ||||||
| 	lib/sed/Makefile  | 	lib/sed/Makefile  | ||||||
| 	lib/xli/Makefile  | 	lib/xli/Makefile  | ||||||
| 	lib/net/Makefile  | 	lib/http/Makefile  | ||||||
| 	cmd/Makefile  | 	cmd/Makefile  | ||||||
| 	cmd/awk/Makefile  | 	cmd/awk/Makefile  | ||||||
| 	cmd/sed/Makefile  | 	cmd/sed/Makefile  | ||||||
| 	cmd/xli/Makefile  | 	cmd/xli/Makefile  | ||||||
| 	cmd/net/Makefile  | 	cmd/http/Makefile  | ||||||
| 	samples/Makefile  | 	samples/Makefile  | ||||||
| 	samples/cmn/Makefile  | 	samples/cmn/Makefile  | ||||||
| 	samples/awk/Makefile  | 	samples/awk/Makefile  | ||||||
| 	samples/sed/Makefile  | 	samples/sed/Makefile  | ||||||
| 	samples/net/Makefile | 	samples/http/Makefile | ||||||
| 	regress/Makefile | 	regress/Makefile | ||||||
| 	regress/awk/Makefile | 	regress/awk/Makefile | ||||||
| 	regress/awk/regress.sh | 	regress/awk/regress.sh | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| SUBDIRS = cmn awk sed net | SUBDIRS = cmn awk sed http | ||||||
|  |  | ||||||
| pkgincludedir = $(includedir)/qse | pkgincludedir = $(includedir)/qse | ||||||
|  |  | ||||||
|  | |||||||
| @ -306,7 +306,7 @@ target_alias = @target_alias@ | |||||||
| top_build_prefix = @top_build_prefix@ | top_build_prefix = @top_build_prefix@ | ||||||
| top_builddir = @top_builddir@ | top_builddir = @top_builddir@ | ||||||
| top_srcdir = @top_srcdir@ | top_srcdir = @top_srcdir@ | ||||||
| SUBDIRS = cmn awk sed net | SUBDIRS = cmn awk sed http | ||||||
| pkginclude_HEADERS = conf-msw.h conf-os2.h conf-dos.h conf-vms.h \ | pkginclude_HEADERS = conf-msw.h conf-os2.h conf-dos.h conf-vms.h \ | ||||||
| 	conf-mac.h conf-inf.h types.h macros.h pack1.h unpack.h \ | 	conf-mac.h conf-inf.h types.h macros.h pack1.h unpack.h \ | ||||||
| 	$(am__append_1) | 	$(am__append_1) | ||||||
|  | |||||||
| @ -24,22 +24,37 @@ | |||||||
| #include <qse/types.h> | #include <qse/types.h> | ||||||
| #include <qse/macros.h> | #include <qse/macros.h> | ||||||
|  |  | ||||||
|  | typedef struct qse_muri_t qse_muri_t; | ||||||
|  | typedef struct qse_wuri_t qse_wuri_t; | ||||||
|  |  | ||||||
| typedef struct qse_uri_t qse_uri_t; | struct qse_muri_t | ||||||
|  |  | ||||||
| struct qse_uri_t |  | ||||||
| { | { | ||||||
| 	qse_cptl_t scheme; | 	qse_mcstr_t scheme; | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		qse_cptl_t user; | 		qse_mcstr_t user; | ||||||
| 		qse_cptl_t pass; | 		qse_mcstr_t pass; | ||||||
| 	} auth; | 	} auth; | ||||||
| 	qse_cptl_t host; | 	qse_mcstr_t host; | ||||||
| 	qse_cptl_t port; | 	qse_mcstr_t port; | ||||||
| 	qse_cptl_t path; | 	qse_mcstr_t path; | ||||||
| 	qse_cptl_t query; | 	qse_mcstr_t query; | ||||||
| 	qse_cptl_t frag; | 	qse_mcstr_t frag; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct qse_wuri_t | ||||||
|  | { | ||||||
|  | 	qse_wcstr_t scheme; | ||||||
|  | 	struct | ||||||
|  | 	{ | ||||||
|  | 		qse_wcstr_t user; | ||||||
|  | 		qse_wcstr_t pass; | ||||||
|  | 	} auth; | ||||||
|  | 	qse_wcstr_t host; | ||||||
|  | 	qse_wcstr_t port; | ||||||
|  | 	qse_wcstr_t path; | ||||||
|  | 	qse_wcstr_t query; | ||||||
|  | 	qse_wcstr_t frag; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum qse_mbstouri_flag_t | enum qse_mbstouri_flag_t | ||||||
| @ -60,10 +75,12 @@ enum qse_wcstouri_flag_t | |||||||
| #	define QSE_STRTOURI_NOAUTH  QSE_MBSTOURI_NOAUTH | #	define QSE_STRTOURI_NOAUTH  QSE_MBSTOURI_NOAUTH | ||||||
| #	define QSE_STRTOURI_NOQUERY QSE_MBSTOURI_NOQUERY | #	define QSE_STRTOURI_NOQUERY QSE_MBSTOURI_NOQUERY | ||||||
| #	define QSE_STRTOURI_NOFRAG  QSE_MBSTOURI_NOFRAG | #	define QSE_STRTOURI_NOFRAG  QSE_MBSTOURI_NOFRAG | ||||||
|  | 	typedef qse_muri_t qse_uri_t; | ||||||
| #else | #else | ||||||
| #	define QSE_STRTOURI_NOAUTH  QSE_WCSTOURI_NOAUTH | #	define QSE_STRTOURI_NOAUTH  QSE_WCSTOURI_NOAUTH | ||||||
| #	define QSE_STRTOURI_NOQUERY QSE_WCSTOURI_NOQUERY | #	define QSE_STRTOURI_NOQUERY QSE_WCSTOURI_NOQUERY | ||||||
| #	define QSE_STRTOURI_NOFRAG  QSE_WCSTOURI_NOFRAG | #	define QSE_STRTOURI_NOFRAG  QSE_WCSTOURI_NOFRAG | ||||||
|  | 	typedef qse_wuri_t qse_uri_t; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| @ -72,13 +89,13 @@ extern "C" { | |||||||
|  |  | ||||||
| QSE_EXPORT int qse_mbstouri ( | QSE_EXPORT int qse_mbstouri ( | ||||||
| 	const qse_mchar_t* str, | 	const qse_mchar_t* str, | ||||||
| 	qse_uri_t*         uri, | 	qse_muri_t*        uri, | ||||||
| 	int                flags | 	int                flags | ||||||
| ); | ); | ||||||
|  |  | ||||||
| QSE_EXPORT int qse_wcstouri ( | QSE_EXPORT int qse_wcstouri ( | ||||||
| 	const qse_wchar_t* str, | 	const qse_wchar_t* str, | ||||||
| 	qse_uri_t*         uri, | 	qse_wuri_t*        uri, | ||||||
| 	int                flags | 	int                flags | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								qse/include/qse/http/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								qse/include/qse/http/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | pkgincludedir= $(includedir)/qse/http | ||||||
|  | pkginclude_HEADERS = http.h htre.h htrd.h httpd.h std.h upxd.h | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -33,7 +33,7 @@ PRE_UNINSTALL = : | |||||||
| POST_UNINSTALL = : | POST_UNINSTALL = : | ||||||
| build_triplet = @build@ | build_triplet = @build@ | ||||||
| host_triplet = @host@ | host_triplet = @host@ | ||||||
| subdir = include/qse/net | subdir = include/qse/http | ||||||
| DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \
 | DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \
 | ||||||
| 	$(srcdir)/Makefile.in | 	$(srcdir)/Makefile.in | ||||||
| ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||||||
| @ -89,7 +89,7 @@ HEADERS = $(pkginclude_HEADERS) | |||||||
| ETAGS = etags | ETAGS = etags | ||||||
| CTAGS = ctags | CTAGS = ctags | ||||||
| DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | ||||||
| pkgincludedir = $(includedir)/qse/net | pkgincludedir = $(includedir)/qse/http | ||||||
| ACLOCAL = @ACLOCAL@ | ACLOCAL = @ACLOCAL@ | ||||||
| AMTAR = @AMTAR@ | AMTAR = @AMTAR@ | ||||||
| AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ | ||||||
| @ -264,7 +264,7 @@ target_alias = @target_alias@ | |||||||
| top_build_prefix = @top_build_prefix@ | top_build_prefix = @top_build_prefix@ | ||||||
| top_builddir = @top_builddir@ | top_builddir = @top_builddir@ | ||||||
| top_srcdir = @top_srcdir@ | top_srcdir = @top_srcdir@ | ||||||
| pkginclude_HEADERS = http.h htre.h htrd.h httpd.h upxd.h | pkginclude_HEADERS = http.h htre.h htrd.h httpd.h std.h upxd.h | ||||||
| all: all-am | all: all-am | ||||||
| 
 | 
 | ||||||
| .SUFFIXES: | .SUFFIXES: | ||||||
| @ -277,9 +277,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps) | |||||||
| 	      exit 1;; \
 | 	      exit 1;; \
 | ||||||
| 	  esac; \
 | 	  esac; \
 | ||||||
| 	done; \
 | 	done; \
 | ||||||
| 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/qse/net/Makefile'; \
 | 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/qse/http/Makefile'; \
 | ||||||
| 	$(am__cd) $(top_srcdir) && \
 | 	$(am__cd) $(top_srcdir) && \
 | ||||||
| 	  $(AUTOMAKE) --foreign include/qse/net/Makefile | 	  $(AUTOMAKE) --foreign include/qse/http/Makefile | ||||||
| .PRECIOUS: Makefile | .PRECIOUS: Makefile | ||||||
| Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||||||
| 	@case '$?' in \
 | 	@case '$?' in \
 | ||||||
| @ -18,11 +18,11 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_NET_HTRD_H_ | #ifndef _QSE_HTTP_HTRD_H_ | ||||||
| #define _QSE_NET_HTRD_H_ | #define _QSE_HTTP_HTRD_H_ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/http.h> | #include <qse/http/http.h> | ||||||
| #include <qse/net/htre.h> | #include <qse/http/htre.h> | ||||||
| 
 | 
 | ||||||
| typedef struct qse_htrd_t qse_htrd_t; | typedef struct qse_htrd_t qse_htrd_t; | ||||||
| 
 | 
 | ||||||
| @ -18,10 +18,10 @@ | |||||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_NET_HTRE_H_ | #ifndef _QSE_HTTP_HTRE_H_ | ||||||
| #define _QSE_NET_HTRE_H_ | #define _QSE_HTTP_HTRE_H_ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/http.h> | #include <qse/http/http.h> | ||||||
| #include <qse/cmn/htb.h> | #include <qse/cmn/htb.h> | ||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
| 
 | 
 | ||||||
| @ -18,8 +18,8 @@ | |||||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_NET_HTTP_H_ | #ifndef _QSE_HTTP_HTTP_H_ | ||||||
| #define _QSE_NET_HTTP_H_ | #define _QSE_HTTP_HTTP_H_ | ||||||
| 
 | 
 | ||||||
| /** @file
 | /** @file
 | ||||||
|  * This file provides basic data types and functions for the http protocol. |  * This file provides basic data types and functions for the http protocol. | ||||||
| @ -18,17 +18,18 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_NET_HTTPD_H_ | #ifndef _QSE_HTTP_HTTPD_H_ | ||||||
| #define _QSE_NET_HTTPD_H_ | #define _QSE_HTTP_HTTPD_H_ | ||||||
| 
 | 
 | ||||||
| #include <qse/types.h> | #include <qse/types.h> | ||||||
| #include <qse/macros.h> | #include <qse/macros.h> | ||||||
| #include <qse/net/htre.h> | #include <qse/http/htre.h> | ||||||
| #include <qse/net/htrd.h> | #include <qse/http/htrd.h> | ||||||
| #include <qse/cmn/nwad.h> | #include <qse/cmn/nwad.h> | ||||||
| #include <qse/cmn/time.h> | #include <qse/cmn/time.h> | ||||||
| 
 | 
 | ||||||
| typedef struct qse_httpd_t        qse_httpd_t; | typedef struct qse_httpd_t        qse_httpd_t; | ||||||
|  | typedef struct qse_httpd_mate_t   qse_httpd_mate_t; | ||||||
| typedef struct qse_httpd_server_t qse_httpd_server_t; | typedef struct qse_httpd_server_t qse_httpd_server_t; | ||||||
| typedef struct qse_httpd_client_t qse_httpd_client_t; | typedef struct qse_httpd_client_t qse_httpd_client_t; | ||||||
| 
 | 
 | ||||||
| @ -300,17 +301,28 @@ struct qse_httpd_task_t | |||||||
| 	qse_httpd_task_t*     next; | 	qse_httpd_task_t*     next; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum qse_httpd_sctype_t  | enum qse_httpd_mate_type_t  | ||||||
| { | { | ||||||
| 	QSE_HTTPD_SERVER, | 	QSE_HTTPD_SERVER, | ||||||
| 	QSE_HTTPD_CLIENT | 	QSE_HTTPD_CLIENT | ||||||
| }; | }; | ||||||
| typedef enum qse_httpd_sctype_t  qse_httpd_sctype_t; | typedef enum qse_httpd_mate_type_t  qse_httpd_mate_type_t; | ||||||
|  | 
 | ||||||
|  | /* it contains header fields common between 
 | ||||||
|  |  * qse_httpd_cleint_t and qse_httpd_server_t. */ | ||||||
|  | #define QSE_HTTPD_MATE_HDR \ | ||||||
|  | 	qse_httpd_mate_type_t type | ||||||
|  | 
 | ||||||
|  | struct qse_httpd_mate_t | ||||||
|  | { | ||||||
|  | 	/* == PRIVATE == */ | ||||||
|  | 	QSE_HTTPD_MATE_HDR; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| struct qse_httpd_client_t | struct qse_httpd_client_t | ||||||
| { | { | ||||||
| 	/* == PRIVATE == */ | 	/* == PRIVATE == */ | ||||||
| 	qse_httpd_sctype_t       type; | 	QSE_HTTPD_MATE_HDR; | ||||||
| 
 | 
 | ||||||
| 	/* == PUBLIC  == */ | 	/* == PUBLIC  == */ | ||||||
| 	qse_ubi_t                handle; | 	qse_ubi_t                handle; | ||||||
| @ -352,22 +364,36 @@ typedef void (*qse_httpd_server_predetach_t) ( | |||||||
| 	qse_httpd_server_t* server | 	qse_httpd_server_t* server | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| struct qse_httpd_server_t | typedef void (*qse_httpd_server_reconfig_t) ( | ||||||
| { | 	qse_httpd_t*        httpd, | ||||||
| 	qse_httpd_sctype_t       type; | 	qse_httpd_server_t* server | ||||||
|  | ); | ||||||
| 
 | 
 | ||||||
| 	/* ---------------------------------------------- */ | typedef struct qse_httpd_server_dope_t qse_httpd_server_dope_t; | ||||||
| 	int          flags; | 
 | ||||||
|  | struct qse_httpd_server_dope_t | ||||||
|  | { | ||||||
|  | 	int          flags; /* bitwise-ORed of qse_httpd_server_flag_t */ | ||||||
| 	qse_nwad_t   nwad; /* binding address */ | 	qse_nwad_t   nwad; /* binding address */ | ||||||
| 	unsigned int nwif; /* interface number to bind to */ | 	unsigned int nwif; /* interface number to bind to */ | ||||||
|  | 	qse_httpd_server_predetach_t predetach; /* executed when the server is detached */ | ||||||
|  | 	qse_httpd_server_reconfig_t reconfig; /* executed when reconfiguration is requested */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct qse_httpd_server_t | ||||||
|  | { | ||||||
|  | 	/* == PRIVATE == */ | ||||||
|  | 	QSE_HTTPD_MATE_HDR; | ||||||
|  | 
 | ||||||
|  | 	/* provided by a user for attaching */ | ||||||
|  | 	qse_httpd_server_dope_t dope; | ||||||
| 
 | 
 | ||||||
| 	/* set by server.open callback */ | 	/* set by server.open callback */ | ||||||
| 	qse_ubi_t  handle; | 	qse_ubi_t  handle; | ||||||
| 
 | 
 | ||||||
| 	/* private  */ | 	/* private  */ | ||||||
| 	qse_httpd_server_predetach_t predetach; | 	qse_httpd_server_t*   next; | ||||||
| 	qse_httpd_server_t*          next; | 	qse_httpd_server_t*   prev; | ||||||
| 	qse_httpd_server_t*          prev; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* -------------------------------------------------------------------------- */ | /* -------------------------------------------------------------------------- */ | ||||||
| @ -480,54 +506,6 @@ struct qse_httpd_ecb_t | |||||||
| 	qse_httpd_ecb_t* next; | 	qse_httpd_ecb_t* next; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct qse_httpd_server_cbstd_t qse_httpd_server_cbstd_t; |  | ||||||
| struct qse_httpd_server_cbstd_t |  | ||||||
| { |  | ||||||
| 	int (*makersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* required */ |  | ||||||
| 	void (*freersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* optional */ |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct qse_httpd_server_cgistd_t qse_httpd_server_cgistd_t; |  | ||||||
| struct qse_httpd_server_cgistd_t |  | ||||||
| { |  | ||||||
| 	const qse_mchar_t*  ext; |  | ||||||
| 	qse_size_t          len; |  | ||||||
| 	int                 nph; |  | ||||||
| 	const qse_mchar_t*  shebang; /* optional, can be #QSE_NULL */ |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct qse_httpd_server_mimestd_t qse_httpd_server_mimestd_t; |  | ||||||
| struct qse_httpd_server_mimestd_t |  | ||||||
| { |  | ||||||
| 	const qse_mchar_t* ext; |  | ||||||
| 	const qse_mchar_t* type; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * The qse_httpd_server_idxstd_t type defines a structure to hold |  | ||||||
|  * an index file name. |  | ||||||
|  */ |  | ||||||
| typedef struct qse_httpd_server_idxstd_t qse_httpd_server_idxstd_t; |  | ||||||
| struct qse_httpd_server_idxstd_t |  | ||||||
| { |  | ||||||
| 	const qse_mchar_t* name; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum qse_httpd_server_optstd_t |  | ||||||
| { |  | ||||||
| 	QSE_HTTPD_SERVER_DOCROOT = 0, /* const qse_mchar_t* */ |  | ||||||
| 	QSE_HTTPD_SERVER_REALM,       /* const qse_mchar_t* */ |  | ||||||
| 	QSE_HTTPD_SERVER_AUTH,        /* const qse_mchar_t* */ |  | ||||||
| 	QSE_HTTPD_SERVER_DIRCSS,      /* const qse_mchar_t* */ |  | ||||||
| 	QSE_HTTPD_SERVER_ERRCSS,      /* const qse_mchar_t* */ |  | ||||||
| 
 |  | ||||||
| 	QSE_HTTPD_SERVER_CBSTD,       /* qse_httpd_server_cbstd_t* */ |  | ||||||
| 	QSE_HTTPD_SERVER_CGISTD,      /* qse_httpd_server_cgistd_t[] */ |  | ||||||
| 	QSE_HTTPD_SERVER_MIMESTD,     /* qse_httpd_server_mimestd_t[] */ |  | ||||||
| 	QSE_HTTPD_SERVER_IDXSTD       /* qse_httpd_server_idxstd_t[] */ |  | ||||||
| }; |  | ||||||
| typedef enum qse_httpd_server_optstd_t qse_httpd_server_optstd_t; |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| @ -610,13 +588,16 @@ QSE_EXPORT void qse_httpd_stop ( | |||||||
| 	qse_httpd_t* httpd | 	qse_httpd_t* httpd | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | QSE_EXPORT void qse_httpd_reconfig ( | ||||||
|  | 	qse_httpd_t* httpd | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| #define qse_httpd_getserverxtn(httpd,server) ((void*)(server+1)) | #define qse_httpd_getserverxtn(httpd,server) ((void*)(server+1)) | ||||||
| 
 | 
 | ||||||
| QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserver ( | QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserver ( | ||||||
| 	qse_httpd_t*                 httpd, | 	qse_httpd_t*                   httpd, | ||||||
| 	const qse_httpd_server_t*    tmpl, | 	const qse_httpd_server_dope_t* dope, | ||||||
| 	qse_httpd_server_predetach_t predetach,	 | 	qse_size_t                     xtnsize | ||||||
| 	qse_size_t                   xtnsize |  | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| QSE_EXPORT void qse_httpd_detachserver ( | QSE_EXPORT void qse_httpd_detachserver ( | ||||||
| @ -804,6 +785,11 @@ QSE_EXPORT void* qse_httpd_allocmem ( | |||||||
| 	qse_size_t   size | 	qse_size_t   size | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | QSE_EXPORT void* qse_httpd_callocmem ( | ||||||
|  | 	qse_httpd_t* httpd,  | ||||||
|  | 	qse_size_t   size | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| QSE_EXPORT void* qse_httpd_reallocmem ( | QSE_EXPORT void* qse_httpd_reallocmem ( | ||||||
| 	qse_httpd_t* httpd, | 	qse_httpd_t* httpd, | ||||||
| 	void*        ptr, | 	void*        ptr, | ||||||
| @ -815,53 +801,17 @@ QSE_EXPORT void qse_httpd_freemem ( | |||||||
| 	void*        ptr | 	void*        ptr | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| /* -------------------------------------------- */ | QSE_EXPORT qse_mchar_t* qse_httpd_strtombsdup ( | ||||||
| 
 | 	qse_httpd_t* httpd,  | ||||||
| QSE_EXPORT qse_httpd_t* qse_httpd_openstd ( | 	const qse_char_t*  str | ||||||
| 	qse_size_t xtnsize |  | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| QSE_EXPORT qse_httpd_t* qse_httpd_openstdwithmmgr ( | QSE_EXPORT qse_mchar_t* qse_httpd_strntombsdup ( | ||||||
| 	qse_mmgr_t* mmgr, |  | ||||||
| 	qse_size_t  xtnsize |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT void* qse_httpd_getxtnstd ( |  | ||||||
| 	qse_httpd_t* httpd |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserverstd ( |  | ||||||
| 	qse_httpd_t*                 httpd, |  | ||||||
| 	const qse_char_t*            uri, |  | ||||||
| 	qse_httpd_server_predetach_t predetach,	 |  | ||||||
| 	qse_size_t                   xtnsize |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT int qse_httpd_getserveroptstd ( |  | ||||||
| 	qse_httpd_t*              httpd, |  | ||||||
| 	qse_httpd_server_t*       server, |  | ||||||
| 	qse_httpd_server_optstd_t id, |  | ||||||
| 	void*                     value |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT int qse_httpd_setserveroptstd ( |  | ||||||
| 	qse_httpd_t*              httpd, |  | ||||||
| 	qse_httpd_server_t*       server, |  | ||||||
| 	qse_httpd_server_optstd_t id, |  | ||||||
| 	const void*               value |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT void* qse_httpd_getserverxtnstd ( |  | ||||||
| 	qse_httpd_t*         httpd, |  | ||||||
| 	qse_httpd_server_t*  server |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| QSE_EXPORT int qse_httpd_loopstd ( |  | ||||||
| 	qse_httpd_t*       httpd,  | 	qse_httpd_t*       httpd,  | ||||||
| 	const qse_ntime_t* tmout | 	const qse_char_t*  str, | ||||||
|  | 	qse_size_t         len | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @ -18,8 +18,8 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_NET_UPXD_H_ | #ifndef _QSE_HTTP_UPXD_H_ | ||||||
| #define _QSE_NET_UPXD_H_ | #define _QSE_HTTP_UPXD_H_ | ||||||
| 
 | 
 | ||||||
| #include <qse/types.h> | #include <qse/types.h> | ||||||
| #include <qse/macros.h> | #include <qse/macros.h> | ||||||
| @ -1,4 +0,0 @@ | |||||||
| pkgincludedir= $(includedir)/qse/net |  | ||||||
| pkginclude_HEADERS = http.h htre.h htrd.h httpd.h upxd.h |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										137
									
								
								qse/include/qse/xli/std.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								qse/include/qse/xli/std.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,137 @@ | |||||||
|  | /* | ||||||
|  |  * $Id$ | ||||||
|  |  * | ||||||
|  |     Copyright 2006-2012 Chung, Hyung-Hwan. | ||||||
|  |     This file is part of QSE. | ||||||
|  |  | ||||||
|  |     QSE is free software: you can redistribute it and/or modify | ||||||
|  |     it under the terms of the GNU Lesser General Public License as  | ||||||
|  |     published by the Free Software Foundation, either version 3 of  | ||||||
|  |     the License, or (at your option) any later version. | ||||||
|  |  | ||||||
|  |     QSE is distributed in the hope that it will be useful, | ||||||
|  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |     GNU Lesser General Public License for more details. | ||||||
|  |  | ||||||
|  |     You should have received a copy of the GNU Lesser General Public  | ||||||
|  |     License along with QSE. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef _QSE_XLI_STD_H_ | ||||||
|  | #define _QSE_XLI_STD_H_ | ||||||
|  |  | ||||||
|  | #include <qse/xli/xli.h> | ||||||
|  | #include <qse/cmn/sio.h> | ||||||
|  |  | ||||||
|  | /** \file | ||||||
|  |  * This file defines functions and data types that help you create | ||||||
|  |  * an xli interpreter with less effort. It is designed to be as close | ||||||
|  |  * to conventional xli implementations as possible. | ||||||
|  |  *  | ||||||
|  |  * The source script handler does not evaluate a file name of the "var=val" | ||||||
|  |  * form as an assignment expression. Instead, it just treats it as a | ||||||
|  |  * normal file name. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_xli_iostd_type_t type defines standard source I/O types. | ||||||
|  |  */ | ||||||
|  | enum qse_xli_iostd_type_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_IOSTD_NULL  = 0, /**< pseudo-value to indicate no script */ | ||||||
|  | 	QSE_XLI_IOSTD_FILE  = 1, /**< file */ | ||||||
|  | 	QSE_XLI_IOSTD_STR   = 2  /**< length-bounded string */ | ||||||
|  | }; | ||||||
|  | typedef enum qse_xli_iostd_type_t qse_xli_iostd_type_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_xli_iostd_t type defines a source I/O. | ||||||
|  |  */ | ||||||
|  | struct qse_xli_iostd_t | ||||||
|  | { | ||||||
|  | 	qse_xli_iostd_type_t type; | ||||||
|  |  | ||||||
|  | 	union | ||||||
|  | 	{ | ||||||
|  | 		struct | ||||||
|  | 		{ | ||||||
|  | 			/** file path to open. #QSE_NULL or '-' for stdin/stdout. */ | ||||||
|  | 			const qse_char_t*  path;  | ||||||
|  |  | ||||||
|  | 			/** a stream created with the file path is set with this | ||||||
|  | 			 * cmgr if it is not #QSE_NULL. */ | ||||||
|  | 			qse_cmgr_t*  cmgr;  | ||||||
|  | 		} file; | ||||||
|  |  | ||||||
|  | 		/**  | ||||||
|  | 		 * input string or dynamically allocated output string | ||||||
|  | 		 * | ||||||
|  | 		 * For input, the ptr and the len field of str indicates the  | ||||||
|  | 		 * pointer and the length of a string to read. You must set | ||||||
|  | 		 * these fields before calling qse_xli_readstd(). | ||||||
|  | 		 * | ||||||
|  | 		 * For output, the ptr and the len field of str indicates the | ||||||
|  | 		 * pointer and the length of a dereadd source string. The output | ||||||
|  | 		 * string is dynamically allocated. You don't need to set these | ||||||
|  | 		 * fields before calling qse_xli_readstd() because they are set | ||||||
|  | 		 * by qse_xli_readstd() and valid while the relevant xli object | ||||||
|  | 		 * is alive. You must free the memory chunk pointed to by the | ||||||
|  | 		 * ptr field with qse_xli_freemem() once you're done with it to  | ||||||
|  | 		 * avoid memory leaks.  | ||||||
|  | 		 */ | ||||||
|  | 		qse_xstr_t str; | ||||||
|  | 	} u; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct qse_xli_iostd_t qse_xli_iostd_t; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_xli_openstd() function creates an xli object using the default  | ||||||
|  |  * memory manager and primitive functions. Besides, it adds a set of | ||||||
|  |  * standard intrinsic functions like atan, system, etc. Use this function | ||||||
|  |  * over qse_xli_open() if you don't need finer-grained customization. | ||||||
|  |  */ | ||||||
|  | QSE_EXPORT qse_xli_t* qse_xli_openstd ( | ||||||
|  | 	qse_size_t xtnsize  /**< extension size in bytes */ | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_xli_openstdwithmmgr() function creates an xli object with a  | ||||||
|  |  * user-defined memory manager. It is equivalent to qse_xli_openstd(),  | ||||||
|  |  * except that you can specify your own memory manager. | ||||||
|  |  */ | ||||||
|  | QSE_EXPORT qse_xli_t* qse_xli_openstdwithmmgr ( | ||||||
|  | 	qse_mmgr_t* mmgr,    /**< memory manager */ | ||||||
|  | 	qse_size_t  xtnsize  /**< extension size in bytes */ | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The qse_xli_getxtnstd() gets the pointer to extension area created with  | ||||||
|  |  * qse_xli_openstd() or qse_xli_openstdwithmmgr(). You must not call  | ||||||
|  |  * qse_xli_getxtn() for sunch an object. | ||||||
|  |  */ | ||||||
|  | QSE_EXPORT void* qse_xli_getxtnstd ( | ||||||
|  | 	qse_xli_t* xli | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT int qse_xli_readstd ( | ||||||
|  | 	qse_xli_t*       xli, | ||||||
|  | 	qse_xli_iostd_t* in | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT int qse_xli_writestd ( | ||||||
|  | 	qse_xli_t*       xli, | ||||||
|  | 	qse_xli_iostd_t* out | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @ -39,10 +39,17 @@ enum qse_xli_errnum_t | |||||||
| 	QSE_XLI_EEXIST,  /**< '${0}' already exists */ | 	QSE_XLI_EEXIST,  /**< '${0}' already exists */ | ||||||
| 	QSE_XLI_EIOFIL,  /**< io error with file '${0}' */ | 	QSE_XLI_EIOFIL,  /**< io error with file '${0}' */ | ||||||
| 	QSE_XLI_EIOUSR,  /**< i/o handler error */ | 	QSE_XLI_EIOUSR,  /**< i/o handler error */ | ||||||
|  |  | ||||||
|  | 	QSE_XLI_ESYNTAX, /**< syntax error */ | ||||||
| 	QSE_XLI_ESCOLON, /**< semicolon expected in place of '${0}' */ | 	QSE_XLI_ESCOLON, /**< semicolon expected in place of '${0}' */ | ||||||
| 	QSE_XLI_ELBREQ,  /**< { or = expected in place of '${0}' */ | 	QSE_XLI_ELBREQ,  /**< { or = expected in place of '${0}' */ | ||||||
| 	QSE_XLI_ERBRCE,  /**< } expected in place of '${0}' */ | 	QSE_XLI_ERBRCE,  /**< } expected in place of '${0}' */ | ||||||
| 	QSE_XLI_EPAVAL   /**< pair value expected in place of '${0}' */ | 	QSE_XLI_EPAVAL,  /**< pair value expected in place of '${0}' */ | ||||||
|  | 	QSE_XLI_ESTRNC,  /**< string not closed */ | ||||||
|  | 	QSE_XLI_EINCLSTR,/**< '@include' not followed by a string */ | ||||||
|  | 	QSE_XLI_ELXCHR,  /**< invalid character '${0} */ | ||||||
|  | 	QSE_XLI_EXKWNR,  /**< @word '${0}' not recognized */ | ||||||
|  | 	QSE_XLI_EXKWEM   /**< @ not followed by a valid word  */ | ||||||
| }; | }; | ||||||
| typedef enum qse_xli_errnum_t qse_xli_errnum_t; | typedef enum qse_xli_errnum_t qse_xli_errnum_t; | ||||||
|  |  | ||||||
| @ -66,13 +73,14 @@ typedef enum qse_xli_opt_t qse_xli_opt_t; | |||||||
|  |  | ||||||
| enum qse_xli_trait_t | enum qse_xli_trait_t | ||||||
| { | { | ||||||
| 	QSE_XLI_NAMEDKEY = (1 << 0), | 	QSE_XLI_KEYNODUP = (1 << 0), | ||||||
| 	QSE_XLI_NODUPKEY = (1 << 1), | 	QSE_XLI_KEYNAME  = (1 << 1), | ||||||
| 	QSE_XLI_NOTEXT   = (1 << 10) | 	QSE_XLI_NOTEXT   = (1 << 10) | ||||||
| }; | }; | ||||||
| typedef enum qse_xli_trait_t qse_xli_trait_t; | typedef enum qse_xli_trait_t qse_xli_trait_t; | ||||||
|  |  | ||||||
| typedef struct qse_xli_val_t qse_xli_val_t; | typedef struct qse_xli_val_t qse_xli_val_t; | ||||||
|  | typedef struct qse_xli_nil_t qse_xli_nil_t; | ||||||
| typedef struct qse_xli_str_t qse_xli_str_t; | typedef struct qse_xli_str_t qse_xli_str_t; | ||||||
| typedef struct qse_xli_list_t qse_xli_list_t; | typedef struct qse_xli_list_t qse_xli_list_t; | ||||||
|  |  | ||||||
| @ -83,6 +91,7 @@ typedef struct qse_xli_file_t qse_xli_file_t; | |||||||
|  |  | ||||||
| enum qse_xli_val_type_t | enum qse_xli_val_type_t | ||||||
| { | { | ||||||
|  | 	QSE_XLI_NIL, | ||||||
| 	QSE_XLI_STR, | 	QSE_XLI_STR, | ||||||
| 	QSE_XLI_LIST, | 	QSE_XLI_LIST, | ||||||
| }; | }; | ||||||
| @ -104,6 +113,11 @@ struct qse_xli_val_t | |||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct qse_xli_nil_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_VAL_HDR; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct qse_xli_list_t | struct qse_xli_list_t | ||||||
| { | { | ||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
| @ -114,9 +128,8 @@ struct qse_xli_list_t | |||||||
| struct qse_xli_str_t | struct qse_xli_str_t | ||||||
| { | { | ||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
| 	int verbatim; |  | ||||||
| 	const qse_char_t* ptr; | 	const qse_char_t* ptr; | ||||||
| 	qse_size_t        len; | 	qse_size_t        len; /* take note that qse_strlen(ptr) != len */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define QSE_XLI_ATOM_HDR \ | #define QSE_XLI_ATOM_HDR \ | ||||||
| @ -142,7 +155,6 @@ struct qse_xli_text_t | |||||||
| { | { | ||||||
| 	QSE_XLI_ATOM_HDR; | 	QSE_XLI_ATOM_HDR; | ||||||
| 	const qse_char_t* ptr; | 	const qse_char_t* ptr; | ||||||
| 	qse_size_t len; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct qse_xli_file_t | struct qse_xli_file_t | ||||||
| @ -461,9 +473,18 @@ QSE_EXPORT void qse_xli_freemem ( | |||||||
| 	void*      ptr | 	void*      ptr | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT qse_xli_pair_t* qse_xli_insertpair ( | ||||||
|  | 	qse_xli_t*        xli, | ||||||
|  | 	qse_xli_list_t*   list, | ||||||
|  | 	qse_xli_atom_t*   peer, | ||||||
|  | 	const qse_char_t* key, | ||||||
|  | 	const qse_char_t* name, | ||||||
|  | 	qse_xli_val_t*    val | ||||||
|  | ); | ||||||
|  |  | ||||||
| QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | ||||||
| 	qse_xli_t*        xli, | 	qse_xli_t*        xli, | ||||||
| 	qse_xli_list_t*   parent, | 	qse_xli_list_t*   list, | ||||||
| 	qse_xli_atom_t*   peer, | 	qse_xli_atom_t*   peer, | ||||||
| 	const qse_char_t* key, | 	const qse_char_t* key, | ||||||
| 	const qse_char_t* name | 	const qse_char_t* name | ||||||
| @ -471,12 +492,18 @@ QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | |||||||
|  |  | ||||||
| QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithstr ( | QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithstr ( | ||||||
| 	qse_xli_t*        xli,  | 	qse_xli_t*        xli,  | ||||||
| 	qse_xli_list_t*   parent, | 	qse_xli_list_t*   list, | ||||||
| 	qse_xli_atom_t*   peer, | 	qse_xli_atom_t*   peer, | ||||||
| 	const qse_char_t* key, | 	const qse_char_t* key, | ||||||
| 	const qse_char_t* name, | 	const qse_char_t* name, | ||||||
| 	const qse_char_t* value, | 	const qse_cstr_t* value | ||||||
| 	int               verbatim | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | qse_xli_pair_t* qse_xli_findpairbyname ( | ||||||
|  |      qse_xli_t*            xli, | ||||||
|  | 	const qse_xli_list_t* list, | ||||||
|  | 	const qse_char_t*     name | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| SUBDIRS = cmn awk sed net  | SUBDIRS = cmn awk sed xli http  | ||||||
| DIST_SUBDIRS = $(SUBDIRS)  | DIST_SUBDIRS = $(SUBDIRS)  | ||||||
|  | |||||||
| @ -270,7 +270,7 @@ target_alias = @target_alias@ | |||||||
| top_build_prefix = @top_build_prefix@ | top_build_prefix = @top_build_prefix@ | ||||||
| top_builddir = @top_builddir@ | top_builddir = @top_builddir@ | ||||||
| top_srcdir = @top_srcdir@ | top_srcdir = @top_srcdir@ | ||||||
| SUBDIRS = cmn awk sed net  | SUBDIRS = cmn awk sed xli http  | ||||||
| DIST_SUBDIRS = $(SUBDIRS)  | DIST_SUBDIRS = $(SUBDIRS)  | ||||||
| all: all-recursive | all: all-recursive | ||||||
|  |  | ||||||
|  | |||||||
| @ -103,7 +103,7 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn | |||||||
| 		QSE_T("illegal operand for increment/decrement operator"), | 		QSE_T("illegal operand for increment/decrement operator"), | ||||||
| 		QSE_T("'@include' not followed by a string"), | 		QSE_T("'@include' not followed by a string"), | ||||||
| 		QSE_T("include level too deep"), | 		QSE_T("include level too deep"), | ||||||
| 		QSE_T("@word '${0}' not recognized"), | 		QSE_T("'${0}' not recognized"), | ||||||
| 		QSE_T("@ not followed by a valid word"), | 		QSE_T("@ not followed by a valid word"), | ||||||
|  |  | ||||||
| 		QSE_T("divide by zero"), | 		QSE_T("divide by zero"), | ||||||
|  | |||||||
| @ -5512,7 +5512,7 @@ static int get_string ( | |||||||
|  |  | ||||||
| 		if (c == QSE_CHAR_EOF) | 		if (c == QSE_CHAR_EOF) | ||||||
| 		{ | 		{ | ||||||
| 			SETERR_TOK (awk, QSE_AWK_ESTRNC); | 			SETERR_LOC (awk, QSE_AWK_ESTRNC, &awk->tok.loc); | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -6072,7 +6072,7 @@ retry: | |||||||
|  |  | ||||||
| 			if (c == QSE_CHAR_EOF) | 			if (c == QSE_CHAR_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				SETERR_TOK (awk, QSE_AWK_ESTRNC); | 				SETERR_LOC (awk, QSE_AWK_ESTRNC, &awk->tok.loc); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ | |||||||
|  |  | ||||||
| #include <qse/cmn/main.h> | #include <qse/cmn/main.h> | ||||||
| #include <qse/cmn/mbwc.h> | #include <qse/cmn/mbwc.h> | ||||||
|  |  | ||||||
| #include "mem.h" | #include "mem.h" | ||||||
|  |  | ||||||
| int qse_runmain ( | int qse_runmain ( | ||||||
|  | |||||||
| @ -21,10 +21,10 @@ | |||||||
| #include <qse/cmn/uri.h> | #include <qse/cmn/uri.h> | ||||||
| #include "mem.h" | #include "mem.h" | ||||||
|  |  | ||||||
| int qse_mbstouri (const qse_mchar_t* str, qse_uri_t* uri, int flags) | int qse_mbstouri (const qse_mchar_t* str, qse_muri_t* uri, int flags) | ||||||
| { | { | ||||||
| 	const qse_mchar_t* ptr, * colon; | 	const qse_mchar_t* ptr, * colon; | ||||||
| 	qse_uri_t xuri; | 	qse_muri_t xuri; | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&xuri, 0, QSE_SIZEOF(xuri)); | 	QSE_MEMSET (&xuri, 0, QSE_SIZEOF(xuri)); | ||||||
|  |  | ||||||
| @ -145,10 +145,10 @@ int qse_mbstouri (const qse_mchar_t* str, qse_uri_t* uri, int flags) | |||||||
|  |  | ||||||
| /* -------------------------------------------------------- */ | /* -------------------------------------------------------- */ | ||||||
|  |  | ||||||
| int qse_wcstouri (const qse_wchar_t* str, qse_uri_t* uri, int flags) | int qse_wcstouri (const qse_wchar_t* str, qse_wuri_t* uri, int flags) | ||||||
| { | { | ||||||
| 	const qse_wchar_t* ptr, * colon; | 	const qse_wchar_t* ptr, * colon; | ||||||
| 	qse_uri_t xuri; | 	qse_wuri_t xuri; | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&xuri, 0, QSE_SIZEOF(xuri)); | 	QSE_MEMSET (&xuri, 0, QSE_SIZEOF(xuri)); | ||||||
|  |  | ||||||
|  | |||||||
| @ -5,8 +5,8 @@ AM_CPPFLAGS = \ | |||||||
| 	-I$(top_srcdir)/include \
 | 	-I$(top_srcdir)/include \
 | ||||||
| 	-I$(includedir) | 	-I$(includedir) | ||||||
| 
 | 
 | ||||||
| lib_LTLIBRARIES = libqsenet.la | lib_LTLIBRARIES = libqsehttp.la | ||||||
| libqsenet_la_SOURCES = \
 | libqsehttp_la_SOURCES = \
 | ||||||
| 	httpd.h \
 | 	httpd.h \
 | ||||||
| 	upxd.h \
 | 	upxd.h \
 | ||||||
| 	http.c \
 | 	http.c \
 | ||||||
| @ -23,6 +23,6 @@ libqsenet_la_SOURCES = \ | |||||||
| 	httpd-text.c \
 | 	httpd-text.c \
 | ||||||
| 	upxd.c | 	upxd.c | ||||||
| 
 | 
 | ||||||
| libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) | libqsehttp_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) | ||||||
| libqsenet_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) | libqsehttp_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) | ||||||
| 
 | 
 | ||||||
| @ -34,7 +34,7 @@ PRE_UNINSTALL = : | |||||||
| POST_UNINSTALL = : | POST_UNINSTALL = : | ||||||
| build_triplet = @build@ | build_triplet = @build@ | ||||||
| host_triplet = @host@ | host_triplet = @host@ | ||||||
| subdir = lib/net | subdir = lib/http | ||||||
| DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | ||||||
| ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||||||
| am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | ||||||
| @ -79,19 +79,19 @@ am__uninstall_files_from_dir = { \ | |||||||
| am__installdirs = "$(DESTDIR)$(libdir)" | am__installdirs = "$(DESTDIR)$(libdir)" | ||||||
| LTLIBRARIES = $(lib_LTLIBRARIES) | LTLIBRARIES = $(lib_LTLIBRARIES) | ||||||
| am__DEPENDENCIES_1 = | am__DEPENDENCIES_1 = | ||||||
| libqsenet_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 | libqsehttp_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 | ||||||
| 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) | 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) | ||||||
| am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
 | am_libqsehttp_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
 | ||||||
| 	httpd-cgi.lo httpd-dir.lo httpd-file.lo httpd-proxy.lo \
 | 	httpd-cgi.lo httpd-dir.lo httpd-file.lo httpd-proxy.lo \
 | ||||||
| 	httpd-resol.lo httpd-std.lo httpd-task.lo httpd-text.lo \
 | 	httpd-resol.lo httpd-std.lo httpd-task.lo httpd-text.lo \
 | ||||||
| 	upxd.lo | 	upxd.lo | ||||||
| libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS) | libqsehttp_la_OBJECTS = $(am_libqsehttp_la_OBJECTS) | ||||||
| AM_V_lt = $(am__v_lt_@AM_V@) | AM_V_lt = $(am__v_lt_@AM_V@) | ||||||
| am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | ||||||
| am__v_lt_0 = --silent | am__v_lt_0 = --silent | ||||||
| libqsenet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 | libqsehttp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 | ||||||
| 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 | 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 | ||||||
| 	$(libqsenet_la_LDFLAGS) $(LDFLAGS) -o $@ | 	$(libqsehttp_la_LDFLAGS) $(LDFLAGS) -o $@ | ||||||
| DEFAULT_INCLUDES =  | DEFAULT_INCLUDES =  | ||||||
| depcomp = $(SHELL) $(top_srcdir)/ac/depcomp | depcomp = $(SHELL) $(top_srcdir)/ac/depcomp | ||||||
| am__depfiles_maybe = depfiles | am__depfiles_maybe = depfiles | ||||||
| @ -118,8 +118,8 @@ am__v_CCLD_0 = @echo "  CCLD  " $@; | |||||||
| AM_V_GEN = $(am__v_GEN_@AM_V@) | AM_V_GEN = $(am__v_GEN_@AM_V@) | ||||||
| am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) | ||||||
| am__v_GEN_0 = @echo "  GEN   " $@; | am__v_GEN_0 = @echo "  GEN   " $@; | ||||||
| SOURCES = $(libqsenet_la_SOURCES) | SOURCES = $(libqsehttp_la_SOURCES) | ||||||
| DIST_SOURCES = $(libqsenet_la_SOURCES) | DIST_SOURCES = $(libqsehttp_la_SOURCES) | ||||||
| ETAGS = etags | ETAGS = etags | ||||||
| CTAGS = ctags | CTAGS = ctags | ||||||
| DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | ||||||
| @ -303,8 +303,8 @@ AM_CPPFLAGS = \ | |||||||
| 	-I$(top_srcdir)/include \
 | 	-I$(top_srcdir)/include \
 | ||||||
| 	-I$(includedir) | 	-I$(includedir) | ||||||
| 
 | 
 | ||||||
| lib_LTLIBRARIES = libqsenet.la | lib_LTLIBRARIES = libqsehttp.la | ||||||
| libqsenet_la_SOURCES = \
 | libqsehttp_la_SOURCES = \
 | ||||||
| 	httpd.h \
 | 	httpd.h \
 | ||||||
| 	upxd.h \
 | 	upxd.h \
 | ||||||
| 	http.c \
 | 	http.c \
 | ||||||
| @ -321,8 +321,8 @@ libqsenet_la_SOURCES = \ | |||||||
| 	httpd-text.c \
 | 	httpd-text.c \
 | ||||||
| 	upxd.c | 	upxd.c | ||||||
| 
 | 
 | ||||||
| libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) | libqsehttp_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) | ||||||
| libqsenet_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) | libqsehttp_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) | ||||||
| all: all-am | all: all-am | ||||||
| 
 | 
 | ||||||
| .SUFFIXES: | .SUFFIXES: | ||||||
| @ -336,9 +336,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps) | |||||||
| 	      exit 1;; \
 | 	      exit 1;; \
 | ||||||
| 	  esac; \
 | 	  esac; \
 | ||||||
| 	done; \
 | 	done; \
 | ||||||
| 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/net/Makefile'; \
 | 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/http/Makefile'; \
 | ||||||
| 	$(am__cd) $(top_srcdir) && \
 | 	$(am__cd) $(top_srcdir) && \
 | ||||||
| 	  $(AUTOMAKE) --foreign lib/net/Makefile | 	  $(AUTOMAKE) --foreign lib/http/Makefile | ||||||
| .PRECIOUS: Makefile | .PRECIOUS: Makefile | ||||||
| Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||||||
| 	@case '$?' in \
 | 	@case '$?' in \
 | ||||||
| @ -388,8 +388,8 @@ clean-libLTLIBRARIES: | |||||||
| 	  echo "rm -f \"$${dir}/so_locations\""; \
 | 	  echo "rm -f \"$${dir}/so_locations\""; \
 | ||||||
| 	  rm -f "$${dir}/so_locations"; \
 | 	  rm -f "$${dir}/so_locations"; \
 | ||||||
| 	done | 	done | ||||||
| libqsenet.la: $(libqsenet_la_OBJECTS) $(libqsenet_la_DEPENDENCIES) $(EXTRA_libqsenet_la_DEPENDENCIES)  | libqsehttp.la: $(libqsehttp_la_OBJECTS) $(libqsehttp_la_DEPENDENCIES) $(EXTRA_libqsehttp_la_DEPENDENCIES)  | ||||||
| 	$(AM_V_CCLD)$(libqsenet_la_LINK) -rpath $(libdir) $(libqsenet_la_OBJECTS) $(libqsenet_la_LIBADD) $(LIBS) | 	$(AM_V_CCLD)$(libqsehttp_la_LINK) -rpath $(libdir) $(libqsehttp_la_OBJECTS) $(libqsehttp_la_LIBADD) $(LIBS) | ||||||
| 
 | 
 | ||||||
| mostlyclean-compile: | mostlyclean-compile: | ||||||
| 	-rm -f *.$(OBJEXT) | 	-rm -f *.$(OBJEXT) | ||||||
| @ -18,7 +18,7 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/htrd.h> | #include <qse/http/htrd.h> | ||||||
| #include <qse/cmn/chr.h> | #include <qse/cmn/chr.h> | ||||||
| #include <qse/cmn/path.h> | #include <qse/cmn/path.h> | ||||||
| #include "../cmn/mem.h" | #include "../cmn/mem.h" | ||||||
| @ -18,7 +18,7 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/htre.h> | #include <qse/http/htre.h> | ||||||
| #include "../cmn/mem.h" | #include "../cmn/mem.h" | ||||||
| 
 | 
 | ||||||
| static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen) | static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen) | ||||||
| @ -18,7 +18,7 @@ | |||||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/http.h> | #include <qse/http/http.h> | ||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
| #include <qse/cmn/chr.h> | #include <qse/cmn/chr.h> | ||||||
| #include <qse/cmn/htb.h> | #include <qse/cmn/htb.h> | ||||||
| @ -446,13 +446,20 @@ static int cgi_add_env ( | |||||||
| 	if (suffix && suffix[0] != QSE_MT('\0'))  | 	if (suffix && suffix[0] != QSE_MT('\0'))  | ||||||
| 	{ | 	{ | ||||||
| 		const qse_mchar_t* tmp[3]; | 		const qse_mchar_t* tmp[3]; | ||||||
|  | 		qse_mchar_t* tr; | ||||||
| 
 | 
 | ||||||
| 		tmp[0] = docroot;  | 		tmp[0] = docroot;  | ||||||
| 		tmp[1] = suffix;  | 		tmp[1] = suffix;  | ||||||
| 		tmp[2] = QSE_NULL; | 		tmp[2] = QSE_NULL; | ||||||
| 
 | 
 | ||||||
|  | 		tr = qse_mbsadup  (tmp, QSE_NULL, httpd->mmgr); | ||||||
|  | 		if (tr)  | ||||||
|  | 		{ | ||||||
|  | 			qse_canonmbspath (tr, tr, 0); | ||||||
|  | 			qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), tr); | ||||||
|  | 			QSE_MMGR_FREE (httpd->mmgr, tr); | ||||||
|  | 		} | ||||||
| 		qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix); | 		qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix); | ||||||
| 		qse_env_insertmbsa (env, QSE_MT("PATH_TRANSLATED"), tmp); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req)); | 	qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req)); | ||||||
| @ -18,6 +18,7 @@ | |||||||
|     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <qse/http/std.h> | ||||||
| #include "httpd.h" | #include "httpd.h" | ||||||
| #include "../cmn/mem.h" | #include "../cmn/mem.h" | ||||||
| #include <qse/cmn/hton.h> | #include <qse/cmn/hton.h> | ||||||
| @ -90,35 +91,18 @@ | |||||||
| #define DEFAULT_PORT        80 | #define DEFAULT_PORT        80 | ||||||
| #define DEFAULT_SECURE_PORT 443 | #define DEFAULT_SECURE_PORT 443 | ||||||
| 
 | 
 | ||||||
| enum server_xtn_cfg_id_t |  | ||||||
| { |  | ||||||
| 	SERVER_XTN_CFG_DOCROOT = 0, |  | ||||||
| 	SERVER_XTN_CFG_REALM, |  | ||||||
| 	SERVER_XTN_CFG_AUTH, /* basic auth */ |  | ||||||
| 	SERVER_XTN_CFG_DIRCSS, /* can't be too long due to internal buffer size  */ |  | ||||||
| 	SERVER_XTN_CFG_ERRCSS, |  | ||||||
| 	SERVER_XTN_CFG_MAX |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct server_xtn_t server_xtn_t; | typedef struct server_xtn_t server_xtn_t; | ||||||
| struct server_xtn_t | struct server_xtn_t | ||||||
| { | { | ||||||
| 	qse_mchar_t* cfg[SERVER_XTN_CFG_MAX]; |  | ||||||
| 
 |  | ||||||
| 	union |  | ||||||
| 	{ |  | ||||||
| 		void* a[4]; |  | ||||||
| 		struct |  | ||||||
| 		{ |  | ||||||
| 			qse_httpd_server_cbstd_t*    cbstd; |  | ||||||
| 			qse_httpd_server_cgistd_t*   cgistd; |  | ||||||
| 			qse_httpd_server_mimestd_t*  mimestd; |  | ||||||
| 			qse_httpd_server_idxstd_t*   idxstd; |  | ||||||
| 		} s; |  | ||||||
| 	} cfg2; |  | ||||||
| 
 |  | ||||||
| 	/* private */ |  | ||||||
| 	qse_httpd_server_predetach_t predetach; | 	qse_httpd_server_predetach_t predetach; | ||||||
|  | 	qse_httpd_server_reconfig_t reconfig; | ||||||
|  | 
 | ||||||
|  | 	qse_httpd_serverstd_query_t query; | ||||||
|  | 	qse_httpd_serverstd_makersrc_t makersrc; | ||||||
|  | 	qse_httpd_serverstd_freersrc_t freersrc; | ||||||
|  | 
 | ||||||
|  | 	/* temporary buffer to handle authorization */ | ||||||
|  | 	qse_mxstr_t auth; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
| @ -640,7 +624,7 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 	qse_skad_t addr; | 	qse_skad_t addr; | ||||||
| 	int addrsize; | 	int addrsize; | ||||||
| 
 | 
 | ||||||
| 	addrsize = qse_nwadtoskad (&server->nwad, &addr); | 	addrsize = qse_nwadtoskad (&server->dope.nwad, &addr); | ||||||
| 	if (addrsize <= -1) | 	if (addrsize <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
| @ -694,13 +678,13 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 	setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); | 	setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); | ||||||
| 	#endif | 	#endif | ||||||
| 
 | 
 | ||||||
| 	if (server->flags & QSE_HTTPD_SERVER_BINDTONWIF) | 	if (server->dope.flags & QSE_HTTPD_SERVER_BINDTONWIF) | ||||||
| 	{ | 	{ | ||||||
| 	#if defined(SO_BINDTODEVICE) | 	#if defined(SO_BINDTODEVICE) | ||||||
| 		qse_mchar_t tmp[64]; | 		qse_mchar_t tmp[64]; | ||||||
| 		qse_size_t len; | 		qse_size_t len; | ||||||
| 
 | 
 | ||||||
| 		len = qse_nwifindextombs (server->nwif, tmp, QSE_COUNTOF(tmp)); | 		len = qse_nwifindextombs (server->dope.nwif, tmp, QSE_COUNTOF(tmp)); | ||||||
| 
 | 
 | ||||||
| 		if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) | 		if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) | ||||||
| 		{ | 		{ | ||||||
| @ -815,7 +799,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | |||||||
| 	if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) | 	if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) | ||||||
| 	{ | 	{ | ||||||
| /* TODO: logging */ | /* TODO: logging */ | ||||||
| 		client->remote_addr = server->nwad; | 		client->remote_addr = server->dope.nwad; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	addrlen = QSE_SIZEOF(addr); | 	addrlen = QSE_SIZEOF(addr); | ||||||
| @ -823,7 +807,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); | |||||||
| 	    qse_skadtonwad (&addr, &client->local_addr) <= -1) | 	    qse_skadtonwad (&addr, &client->local_addr) <= -1) | ||||||
| 	{ | 	{ | ||||||
| /* TODO: logging */ | /* TODO: logging */ | ||||||
| 		client->local_addr = server->nwad; | 		client->local_addr = server->dope.nwad; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	#if defined(SO_ORIGINAL_DST) | 	#if defined(SO_ORIGINAL_DST) | ||||||
| @ -1870,7 +1854,7 @@ if (qse_htre_getcontentlen(req) > 0) | |||||||
| 					task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); | 					task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else if (server_xtn->cfg2.s.cbstd->makersrc (httpd, client, req, &rsrc) <= -1) | 			else if (server_xtn->makersrc (httpd, client, req, &rsrc) <= -1) | ||||||
| 			{ | 			{ | ||||||
| 				qse_httpd_discardcontent (httpd, req); | 				qse_httpd_discardcontent (httpd, req); | ||||||
| 				task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); | 				task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); | ||||||
| @ -1878,8 +1862,8 @@ if (qse_htre_getcontentlen(req) > 0) | |||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req); | 				task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req); | ||||||
| 				if (server_xtn->cfg2.s.cbstd->freersrc)  | 				if (server_xtn->freersrc)  | ||||||
| 					server_xtn->cfg2.s.cbstd->freersrc (httpd, client, req, &rsrc); | 					server_xtn->freersrc (httpd, client, req, &rsrc); | ||||||
| 			} | 			} | ||||||
| 			if (task == QSE_NULL) goto oops; | 			if (task == QSE_NULL) goto oops; | ||||||
| 		} | 		} | ||||||
| @ -1934,8 +1918,8 @@ static int format_err ( | |||||||
| 
 | 
 | ||||||
| 	server_xtn = qse_httpd_getserverxtn (httpd, client->server); | 	server_xtn = qse_httpd_getserverxtn (httpd, client->server); | ||||||
| 
 | 
 | ||||||
| 	css = server_xtn->cfg[SERVER_XTN_CFG_ERRCSS]; | 	if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_ERRCSS, &css) <= -1) css = QSE_NULL; | ||||||
| 	if (!css) css = QSE_MT(""); | 	if (css == QSE_NULL) css = QSE_MT(""); | ||||||
| 
 | 
 | ||||||
| 	msg = qse_httpstatustombs(code); | 	msg = qse_httpstatustombs(code); | ||||||
| 
 | 
 | ||||||
| @ -1972,8 +1956,8 @@ static int format_dir ( | |||||||
| 			const qse_mchar_t* css; | 			const qse_mchar_t* css; | ||||||
| 			int is_root = (qse_mbscmp (qpath, QSE_MT("/")) == 0); | 			int is_root = (qse_mbscmp (qpath, QSE_MT("/")) == 0); | ||||||
| 
 | 
 | ||||||
| 			css = server_xtn->cfg[SERVER_XTN_CFG_DIRCSS]; | 			if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_DIRCSS, &css) <= -1) css = QSE_NULL; | ||||||
| 			if (!css) css = QSE_MT(""); | 			if (css == QSE_NULL) css = QSE_MT(""); | ||||||
| 
 | 
 | ||||||
| /* TODO: html escaping of qpath */ | /* TODO: html escaping of qpath */ | ||||||
| 			n = snprintf (buf, bufsz, | 			n = snprintf (buf, bufsz, | ||||||
| @ -2119,6 +2103,8 @@ static void free_resource ( | |||||||
| 				QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.script); | 				QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.script); | ||||||
| 			if (target->u.cgi.path != qpath) | 			if (target->u.cgi.path != qpath) | ||||||
| 				QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.path); | 				QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.path); | ||||||
|  | 			if (target->u.cgi.shebang) | ||||||
|  | 				QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.shebang); | ||||||
| 
 | 
 | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| @ -2160,85 +2146,141 @@ static qse_mchar_t* merge_paths ( | |||||||
| 	return xpath; | 	return xpath; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int attempt_cgi ( | static void merge_paths_to_buf ( | ||||||
| 	qse_httpd_t* httpd, const qse_mchar_t* docroot,  | 	qse_httpd_t* httpd, const qse_mchar_t* base,  | ||||||
| 	qse_mchar_t* xpath, const qse_mchar_t* qpath, const qse_mchar_t* idxfile, | 	const qse_mchar_t* path, qse_size_t plen, qse_mchar_t* xpath) | ||||||
| 	qse_httpd_server_cgistd_t cgistd[], qse_httpd_rsrc_t* target) |  | ||||||
| { | { | ||||||
| 	qse_mchar_t* ext; | 	/* this function merges two path names into a buffer large enough
 | ||||||
| 	qse_mchar_t* script, * suffix; | 	 * to hold the result. it doesn't duplicate the result */ | ||||||
| 	qse_size_t i; | 	qse_size_t len = 0; | ||||||
|  | 	len += qse_mbscpy (&xpath[len], base); | ||||||
|  | 	len += qse_mbscpy (&xpath[len], QSE_MT("/")); | ||||||
|  | 	len += qse_mbsncpy (&xpath[len], path, plen); | ||||||
|  | 	qse_canonmbspath (xpath, xpath, 0); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	if (idxfile) | struct rsrc_tmp_t | ||||||
|  | { | ||||||
|  | 	const qse_mchar_t* qpath; | ||||||
|  | 	const qse_mchar_t* idxfile; | ||||||
|  | 	qse_mchar_t* xpath; | ||||||
|  | 
 | ||||||
|  | 	const qse_mchar_t* docroot; | ||||||
|  | 	const qse_mchar_t* realm; | ||||||
|  | 	const qse_mchar_t* auth; | ||||||
|  | 	qse_httpd_serverstd_index_t index; | ||||||
|  | 
 | ||||||
|  | 	int final_match; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int attempt_cgi ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req,  | ||||||
|  | 	struct rsrc_tmp_t* tmp, qse_httpd_rsrc_t* target) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  | 	qse_mchar_t* shebang = QSE_NULL; | ||||||
|  | 	qse_mchar_t* suffix = QSE_NULL; | ||||||
|  | 	qse_mchar_t* script = QSE_NULL; | ||||||
|  | 	qse_httpd_serverstd_cgi_t cgi; | ||||||
|  | 
 | ||||||
|  | 	server_xtn = qse_httpd_getserverxtn (httpd, client->server); | ||||||
|  | 
 | ||||||
|  | 	if (tmp->final_match) | ||||||
| 	{ | 	{ | ||||||
| 		for (i = 0; cgistd[i].ext; i++) | 		/* it is a final match. tmp->xpath is tmp->docroot + tmp->qpath  */ | ||||||
|  | 		if (server_xtn->query (httpd, client->server, req, tmp->xpath, QSE_HTTPD_SERVERSTD_CGI, &cgi) >= 0 && cgi.cgi) | ||||||
| 		{ | 		{ | ||||||
| 			if (qse_mbsend (idxfile, cgistd[i].ext)) | 			if (tmp->idxfile) | ||||||
| 			{ | 			{ | ||||||
| 				script = merge_paths (httpd, qpath, idxfile); | 				script = merge_paths (httpd, tmp->qpath, tmp->idxfile); | ||||||
| 				if (script == QSE_NULL) return -1; | 				if (script == QSE_NULL) goto oops; | ||||||
| 
 |  | ||||||
| 				target->type = QSE_HTTPD_RSRC_CGI; |  | ||||||
| 				target->u.cgi.nph = cgistd[i].nph; |  | ||||||
| 				target->u.cgi.path = xpath; |  | ||||||
| 				target->u.cgi.script = script; |  | ||||||
| 				target->u.cgi.suffix = QSE_NULL; |  | ||||||
| 				target->u.cgi.docroot = docroot; |  | ||||||
| 				target->u.cgi.shebang = cgistd[i].shebang; |  | ||||||
| 				return 1; |  | ||||||
| 			} | 			} | ||||||
|  | 			else script = (qse_mchar_t*)tmp->qpath; | ||||||
|  | 
 | ||||||
|  | 			if (cgi.shebang) | ||||||
|  | 			{ | ||||||
|  | 				shebang = qse_mbsdup (cgi.shebang, httpd->mmgr); | ||||||
|  | 				if (shebang == QSE_NULL) goto oops; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			goto bingo; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		for (i = 0; cgistd[i].ext; i++) | 		/* inspect each segment from the head. */ | ||||||
|  | 		const qse_mchar_t* ptr; | ||||||
|  | 		const qse_mchar_t* slash; | ||||||
|  | 
 | ||||||
|  | 		QSE_ASSERT (tmp->qpath[0] == QSE_T('/')); | ||||||
|  | 
 | ||||||
|  | 		ptr = tmp->qpath + 1; | ||||||
|  | 		while (*ptr != QSE_MT('\0')) | ||||||
| 		{ | 		{ | ||||||
| 	/* TODO: attempt other segments if qpath is like
 | 			slash = qse_mbschr (ptr, QSE_MT('/')); | ||||||
| 	 *       /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only. | 			if (slash) | ||||||
| 	 *       x.cgi could be a directory name . |  | ||||||
| 	 */ |  | ||||||
| 			ext = qse_mbsstr (qpath, cgistd[i].ext); |  | ||||||
| 	 |  | ||||||
| 			if (ext && (ext[cgistd[i].len] == QSE_MT('/') ||  |  | ||||||
| 			            ext[cgistd[i].len] == QSE_MT('\0')))  |  | ||||||
| 			{ | 			{ | ||||||
| 				if (ext[cgistd[i].len] == QSE_MT('/'))  | 				if (slash > ptr) | ||||||
| 				{ | 				{ | ||||||
| 					/* it has a path suffix */ | 					qse_httpd_stat_t st; | ||||||
| 					script = qse_mbsxdup (qpath, ext - qpath + cgistd[i].len, httpd->mmgr); | 					int stx; | ||||||
| 					suffix = qse_mbsdup (&ext[cgistd[i].len], httpd->mmgr); | 
 | ||||||
| 					if (script == QSE_NULL || suffix == QSE_NULL) | 					/* a slash is found and the segment is not empty.
 | ||||||
|  | 					 * | ||||||
|  | 					 * tmp->xpath should be large enough to hold the merge path made of | ||||||
|  | 					 * the subsegments of the original query path and docroot. */ | ||||||
|  | 					merge_paths_to_buf (httpd, tmp->docroot, tmp->qpath, slash - tmp->qpath, tmp->xpath); | ||||||
|  | 	 | ||||||
|  | 					/* attempt this */ | ||||||
|  | 					stx = stat_file (httpd, tmp->xpath, &st, 0); | ||||||
|  | 					if (stx >= 0 && !st.isdir) | ||||||
| 					{ | 					{ | ||||||
| 						if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix); | 						if (server_xtn->query (httpd, client->server, req, tmp->xpath, QSE_HTTPD_SERVERSTD_CGI, &cgi) >= 0 && cgi.cgi) | ||||||
| 						if (script) QSE_MMGR_FREE (httpd->mmgr, script); | 						{ | ||||||
| 						httpd->errnum = QSE_HTTPD_ENOMEM; | 							script = qse_mbsxdup (tmp->qpath, slash - tmp->qpath , httpd->mmgr); | ||||||
| 						return -1; | 							suffix = qse_mbsdup (slash, httpd->mmgr); | ||||||
|  | 							if (!script || !suffix) goto oops; | ||||||
|  | 
 | ||||||
|  | 							if (cgi.shebang) | ||||||
|  | 							{ | ||||||
|  | 								shebang = qse_mbsdup (cgi.shebang, httpd->mmgr); | ||||||
|  | 								if (shebang == QSE_NULL) goto oops; | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 							goto bingo; | ||||||
|  | 						} | ||||||
| 					} | 					} | ||||||
| 	 |  | ||||||
| 					/* drop the suffix part */ |  | ||||||
| 					xpath[qse_mbslen(xpath) - qse_mbslen(suffix)] = QSE_MT('\0'); |  | ||||||
| 				} | 				} | ||||||
| 				else | 
 | ||||||
| 				{ | 				ptr = slash + 1; | ||||||
| 					/* it has no path suffix  */ | 			} | ||||||
| 					script = qpath; | 			else  | ||||||
| 					suffix = QSE_NULL; | 			{ | ||||||
| 				} | 				/* no more slash is found. the last segement doesn't have to be checked 
 | ||||||
| 	 | 				 * here since it's attempted by the caller. */ | ||||||
| 				target->type = QSE_HTTPD_RSRC_CGI; | 				break; | ||||||
| 				target->u.cgi.nph = cgistd[i].nph; |  | ||||||
| 				target->u.cgi.path = xpath; |  | ||||||
| 				target->u.cgi.script = script; |  | ||||||
| 				target->u.cgi.suffix = suffix; |  | ||||||
| 				target->u.cgi.docroot = docroot; |  | ||||||
| 				target->u.cgi.shebang = cgistd[i].shebang; |  | ||||||
| 				return 1; |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; /* not a cgi */ | ||||||
|  | 
 | ||||||
|  | bingo: | ||||||
|  | 	target->type = QSE_HTTPD_RSRC_CGI; | ||||||
|  | 	target->u.cgi.nph = cgi.nph; | ||||||
|  | 	target->u.cgi.path = tmp->xpath; | ||||||
|  | 	target->u.cgi.script = script; | ||||||
|  | 	target->u.cgi.suffix = suffix; | ||||||
|  | 	target->u.cgi.docroot = tmp->docroot; | ||||||
|  | 	target->u.cgi.shebang = shebang; | ||||||
|  | 	return 1; | ||||||
|  | 
 | ||||||
|  | oops: | ||||||
|  | 	httpd->errnum = QSE_HTTPD_ENOMEM; | ||||||
|  | 	if (shebang) QSE_MMGR_FREE (httpd->mmgr, shebang); | ||||||
|  | 	if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix); | ||||||
|  | 	if (script && script != tmp->qpath) QSE_MMGR_FREE (httpd->mmgr, script); | ||||||
|  | 	return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int make_resource ( | static int make_resource ( | ||||||
| @ -2246,214 +2288,308 @@ static int make_resource ( | |||||||
| 	qse_htre_t* req, qse_httpd_rsrc_t* target) | 	qse_htre_t* req, qse_httpd_rsrc_t* target) | ||||||
| { | { | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	const qse_mchar_t* qpath; | 	struct rsrc_tmp_t tmp; | ||||||
| 	const qse_mchar_t* idxfile; | 
 | ||||||
| 	qse_mchar_t* xpath;  |  | ||||||
| 	qse_httpd_stat_t st; | 	qse_httpd_stat_t st; | ||||||
| 	qse_size_t i; |  | ||||||
| 	int n, stx; | 	int n, stx; | ||||||
| 
 | 
 | ||||||
| 	qpath = qse_htre_getqpath(req); | 	QSE_MEMSET (&tmp, 0, QSE_SIZEOF(tmp)); | ||||||
|  | 	tmp.qpath = qse_htre_getqpath(req); | ||||||
| 
 | 
 | ||||||
| 	QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); | 	QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); | ||||||
| 
 | 
 | ||||||
| qse_printf (QSE_T(">>> MAKING RESOURCE [%hs]\n"), qpath); | 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->cfg[SERVER_XTN_CFG_REALM] && | 	if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1 || | ||||||
| 	    server_xtn->cfg[SERVER_XTN_CFG_AUTH]) | 	    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) | ||||||
| 	{ | 	{ | ||||||
| 		const qse_htre_hdrval_t* auth; | 		return -1; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 		auth = qse_htre_getheaderval (req, QSE_MT("Authorization")); | 	/* default to the root directory. */ | ||||||
| 		if (auth) | 	if (!tmp.docroot) tmp.docroot = QSE_MT("/");  | ||||||
|  | 
 | ||||||
|  | 	if (tmp.realm && tmp.auth) | ||||||
|  | 	{ | ||||||
|  | 		const qse_htre_hdrval_t* authv; | ||||||
|  | 
 | ||||||
|  | 		authv = qse_htre_getheaderval (req, QSE_MT("Authorization")); | ||||||
|  | 		if (authv) | ||||||
| 		{ | 		{ | ||||||
| 			while (auth->next) auth = auth->next; | 			while (authv->next) authv = authv->next; | ||||||
| 
 | 
 | ||||||
| 			if (qse_mbszcasecmp(auth->ptr, QSE_MT("Basic "), 6) == 0)  | 			if (qse_mbszcasecmp(authv->ptr, QSE_MT("Basic "), 6) == 0)  | ||||||
| 			{ | 			{ | ||||||
| 				if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_AUTH]) == 0) goto auth_ok; | 				qse_size_t authl, authl2; | ||||||
|  | 
 | ||||||
|  | 				/* basic authorization is a base64-encoded string of username:password. */ | ||||||
|  | 
 | ||||||
|  | 				authl = qse_mbslen(&authv->ptr[6]);	 | ||||||
|  | 				if (authl > server_xtn->auth.len) | ||||||
|  | 				{ | ||||||
|  | 					qse_mchar_t* tmp; | ||||||
|  | 					tmp = qse_httpd_reallocmem (httpd, server_xtn->auth.ptr, authl * QSE_SIZEOF(qse_mchar_t)); | ||||||
|  | 					if (!tmp) return -1; | ||||||
|  | 
 | ||||||
|  | 					server_xtn->auth.ptr = tmp; | ||||||
|  | 					/* the maximum capacity that can hold the largest authorization value */ | ||||||
|  | 					server_xtn->auth.len = authl;	  | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				/* decoding a base64-encoded string result in a shorter value than the input.
 | ||||||
|  | 				 * so passing the length of the input(authl) as the output buffer size is ok */ | ||||||
|  | 				authl2 = qse_debase64 (&authv->ptr[6], authl, server_xtn->auth.ptr, authl, QSE_NULL); | ||||||
|  | 				if (qse_mbsxcmp (server_xtn->auth.ptr, authl2, tmp.auth) == 0) goto auth_ok; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		target->type = QSE_HTTPD_RSRC_AUTH; | 		target->type = QSE_HTTPD_RSRC_AUTH; | ||||||
| 		target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM]; | 		target->u.auth.realm = tmp.realm;  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| auth_ok: | auth_ok: | ||||||
| 	idxfile = QSE_NULL; | 	tmp.xpath = merge_paths (httpd, tmp.docroot, tmp.qpath); | ||||||
| 	xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], qpath); | 	if (tmp.xpath == QSE_NULL) return -1; | ||||||
| 	if (xpath == QSE_NULL) return -1; |  | ||||||
| 
 | 
 | ||||||
| 	stx = stat_file (httpd, xpath, &st, 0); | 	stx = stat_file (httpd, tmp.xpath, &st, 0); | ||||||
| #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | ||||||
| 	if (stx <= -1) | 	if (stx <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		/* this OS may fail in stat_file() if the path contains the trailing 
 | 		/* this OS may fail in stat_file() if the path contains the trailing 
 | ||||||
| 		 * separator. it's beause of the way FindFirstFile() or DosQueryPathInfo() | 		 * separator. it's beause of the way FindFirstFile() or DosQueryPathInfo() | ||||||
| 		 * is ussed in stat_file(). let me work around it here. */ | 		 * is used in stat_file(). let me work around it here. */ | ||||||
| 		qse_size_t pl = qse_mbslen(xpath); | 		qse_size_t pl = qse_mbslen(tmp.xpath); | ||||||
| 		if (pl > 1 && xpath[pl - 1] == QSE_MT('/'))  | 		if (pl > 1 && tmp.xpath[pl - 1] == QSE_MT('/'))  | ||||||
| 		{ | 		{ | ||||||
| 			xpath[pl-1] = QSE_MT('\0'); | 			tmp.xpath[pl-1] = QSE_MT('\0'); | ||||||
| 			stx = stat_file (httpd, xpath, &st, 0); | 			stx = stat_file (httpd, tmp.xpath, &st, 0); | ||||||
| 			xpath[pl-1] = QSE_MT('/'); | 			tmp.xpath[pl-1] = QSE_MT('/'); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
| 	if (stx >= 0 && st.isdir) | 
 | ||||||
|  | 	if (stx >= 0) | ||||||
| 	{ | 	{ | ||||||
| 		/* it is a directory */ | 		/* xpath/qpath is a final match.
 | ||||||
| 		if (server_xtn->cfg2.s.idxstd) | 		 * mark that the segments in the query path don't need inspection. */ | ||||||
| 		{ | 		tmp.final_match = 1; | ||||||
| 			/* try to locate an index file */ | 
 | ||||||
| 			for (i = 0; server_xtn->cfg2.s.idxstd[i].name; i++) | 		if (st.isdir) | ||||||
|  | 		{	 | ||||||
|  | 			/* it is a directory */ | ||||||
|  | 			if (tmp.index.count > 0) | ||||||
| 			{ | 			{ | ||||||
| 				qse_mchar_t* tpath; | 				/* try to locate an index file */ | ||||||
|  | 				qse_size_t i; | ||||||
|  | 				const qse_mchar_t* ptr; | ||||||
| 
 | 
 | ||||||
| 				tpath = merge_paths (httpd, xpath, server_xtn->cfg2.s.idxstd[i].name); | 				ptr = tmp.index.files; | ||||||
| 				if (tpath == QSE_NULL)  | 				for (i = 0; i < tmp.index.count; i++, ptr += qse_mbslen(ptr) + 1) | ||||||
| 				{ | 				{ | ||||||
| 					QSE_MMGR_FREE (httpd->mmgr, xpath); | 					qse_mchar_t* tpath; | ||||||
| 					return -1; | 
 | ||||||
|  | 					tpath = merge_paths (httpd, tmp.xpath, ptr); | ||||||
|  | 					if (tpath == QSE_NULL)  | ||||||
|  | 					{ | ||||||
|  | 						QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); | ||||||
|  | 						return -1; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (httpd->scb->file.stat (httpd, tpath, &st) >= 0 && !st.isdir) | ||||||
|  | 					{ | ||||||
|  | 						/* the index file is found */ | ||||||
|  | 						QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); | ||||||
|  | 						tmp.xpath = tpath; | ||||||
|  | 						tmp.idxfile = ptr; | ||||||
|  | 						goto attempt_file; | ||||||
|  | 					}	 | ||||||
|  | 
 | ||||||
|  | 					QSE_MMGR_FREE (httpd->mmgr, tpath); | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 				if (httpd->scb->file.stat (httpd, tpath, &st) >= 0 && !st.isdir) |  | ||||||
| 				{ |  | ||||||
| 					/* the index file is found */ |  | ||||||
| 					QSE_MMGR_FREE (httpd->mmgr, xpath); |  | ||||||
| 					xpath = tpath; |  | ||||||
| 					idxfile = server_xtn->cfg2.s.idxstd[i].name; |  | ||||||
| 					goto attempt_file; |  | ||||||
| 				}	 |  | ||||||
| 
 |  | ||||||
| 				QSE_MMGR_FREE (httpd->mmgr, tpath); |  | ||||||
| 			} | 			} | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		target->type = QSE_HTTPD_RSRC_DIR; | 			target->type = QSE_HTTPD_RSRC_DIR; | ||||||
| 		target->u.dir.path = xpath; | 			target->u.dir.path = tmp.xpath; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* let me treat it as a file. */ | ||||||
|  | 			goto attempt_file; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
|  | 		/* well, stat failed. i don't know if it is a file.
 | ||||||
|  | 		 * i must try each segment in the query path. */ | ||||||
| 	attempt_file: | 	attempt_file: | ||||||
| 		if (server_xtn->cfg2.s.cgistd) | 		/* check if the request can resolve to a cgi script */ | ||||||
|  | 		n = attempt_cgi (httpd, client, req, &tmp, target); | ||||||
|  | 		if (n <= -1)  | ||||||
| 		{ | 		{ | ||||||
| 			/* check if the request can resolve to a cgi script */ | 			QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); | ||||||
| 			n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT],  | 			return -1; | ||||||
| 			                 xpath, qpath, idxfile, server_xtn->cfg2.s.cgistd, target); |  | ||||||
| 			if (n <= -1)  |  | ||||||
| 			{ |  | ||||||
| 				QSE_MMGR_FREE (httpd->mmgr, xpath); |  | ||||||
| 				return -1; |  | ||||||
| 			} |  | ||||||
| 			if (n >= 1) return 0; |  | ||||||
| 		} | 		} | ||||||
|  | 		if (n >= 1) return 0; | ||||||
| 
 | 
 | ||||||
| 		/* fall back to a normal file. */ | 		/* fall back to a normal file. */ | ||||||
| 		target->type = QSE_HTTPD_RSRC_FILE; | 		target->type = QSE_HTTPD_RSRC_FILE; | ||||||
| 		target->u.file.path = xpath; | 		target->u.file.path = tmp.xpath; | ||||||
| 		target->u.file.mime = QSE_NULL; | 
 | ||||||
| 		if (server_xtn->cfg2.s.mimestd) | 		if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			for (i = 0; server_xtn->cfg2.s.mimestd[i].ext; i++) | 			/* don't care about failure */ | ||||||
| 			{ | 			target->u.file.mime = QSE_NULL; | ||||||
| /* TODO: require the table sorted and so the binary search */ |  | ||||||
| 				if (qse_mbsend (qpath, server_xtn->cfg2.s.mimestd[i].ext)) |  | ||||||
| 					target->u.file.mime = server_xtn->cfg2.s.mimestd[i].type;  |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static qse_httpd_server_cbstd_t server_cbstd = |  | ||||||
| { |  | ||||||
| 	make_resource, |  | ||||||
| 	free_resource	 |  | ||||||
| }; |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
| 
 | 
 | ||||||
| static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| { | { | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	qse_size_t i; |  | ||||||
| 
 | 
 | ||||||
| 	server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server); | 	server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server); | ||||||
| 	 |  | ||||||
| 	if (server_xtn->predetach) server_xtn->predetach (httpd, server); | 	if (server_xtn->predetach) server_xtn->predetach (httpd, server); | ||||||
|  | 	if (server_xtn->auth.ptr) QSE_MMGR_FREE (httpd->mmgr, server_xtn->auth.ptr); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	for (i = QSE_COUNTOF(server_xtn->cfg); i > 0; ) | static void reconfig_server (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
|  | { | ||||||
|  | 	server_xtn_t* server_xtn; | ||||||
|  | 	server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server); | ||||||
|  | 	 | ||||||
|  | 	if (server_xtn->reconfig) server_xtn->reconfig (httpd, server); | ||||||
|  | 
 | ||||||
|  | 	/* nothing more to do here ...  */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct mime_tab_t | ||||||
|  | { | ||||||
|  | 	const qse_mchar_t* suffix; | ||||||
|  | 	const qse_mchar_t* type; | ||||||
|  | }; | ||||||
|  | static struct mime_tab_t mimetab[] = | ||||||
|  | { | ||||||
|  | 	{ QSE_MT(".htm"),  QSE_MT("text/html") }, | ||||||
|  | 	{ QSE_MT(".html"), QSE_MT("text/html") }, | ||||||
|  | 	{ QSE_MT(".txt"),  QSE_MT("text/plain") } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct cgi_tab_t | ||||||
|  | { | ||||||
|  | 	const qse_mchar_t* suffix; | ||||||
|  | 	qse_httpd_serverstd_cgi_t cgi; | ||||||
|  | }; | ||||||
|  | static struct cgi_tab_t cgitab[] = | ||||||
|  | { | ||||||
|  | 	{ QSE_MT(".cgi"), { 1, 0, QSE_NULL } }, | ||||||
|  | 	{ QSE_MT(".nph"), { 1, 1, QSE_NULL } }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int query_server ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_server_t* server,  | ||||||
|  | 	qse_htre_t* req, const qse_mchar_t* xpath, | ||||||
|  | 	qse_httpd_serverstd_query_code_t code, void* result) | ||||||
|  | { | ||||||
|  | 	qse_size_t i; | ||||||
|  | 
 | ||||||
|  | 	switch (code) | ||||||
| 	{ | 	{ | ||||||
| 		if (server_xtn->cfg[--i]) | 		case QSE_HTTPD_SERVERSTD_DOCROOT: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_REALM: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_AUTH: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_ERRCSS: | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_DIRCSS: | ||||||
|  | 			*(const qse_mchar_t**)result = QSE_NULL; | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_INDEX: | ||||||
| 		{ | 		{ | ||||||
| 			QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i]); | 			qse_httpd_serverstd_index_t* index = (qse_httpd_serverstd_index_t*)result; | ||||||
| 			server_xtn->cfg[i] = QSE_NULL; | 			index->count = 2; | ||||||
|  | 			index->files = QSE_MT("index.html\0index.cgi\0"); | ||||||
|  | 			return 0; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_CGI: | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_serverstd_cgi_t* cgi = (qse_httpd_serverstd_cgi_t*)result; | ||||||
|  | 			for (i = 0; i < QSE_COUNTOF(cgitab); i++) | ||||||
|  | 			{ | ||||||
|  | 				if (qse_mbsend (xpath, cgitab[i].suffix)) | ||||||
|  | 				{ | ||||||
|  | 					QSE_MEMCPY (cgi, &cgitab[i].cgi, QSE_SIZEOF(*cgi)); | ||||||
|  | 					return 0; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			QSE_MEMSET (cgi,0, QSE_SIZEOF(*cgi)); | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		case QSE_HTTPD_SERVERSTD_MIME: | ||||||
|  | 			/* TODO: binary search if the table is large */ | ||||||
|  | 			for (i = 0; i < QSE_COUNTOF(mimetab); i++) | ||||||
|  | 			{ | ||||||
|  | 				if (qse_mbsend (xpath, mimetab[i].suffix)) | ||||||
|  | 				{ | ||||||
|  | 					*(const qse_mchar_t**)result = mimetab[i].type; | ||||||
|  | 					return 0; | ||||||
|  | 				} | ||||||
|  | 			}			 | ||||||
|  | 
 | ||||||
|  | 			*(const qse_mchar_t**)result = QSE_NULL; | ||||||
|  | 			return 0; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | ||||||
|  | 	return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| qse_httpd_server_t* qse_httpd_attachserverstd ( | qse_httpd_server_t* qse_httpd_attachserverstd ( | ||||||
| 	qse_httpd_t* httpd, const qse_char_t* uri,  | 	qse_httpd_t* httpd, qse_httpd_serverstd_t* server, qse_size_t xtnsize) | ||||||
| 	qse_httpd_server_predetach_t predetach, qse_size_t xtnsize) |  | ||||||
| { | { | ||||||
| 	qse_httpd_server_t server; | 	qse_httpd_server_dope_t dope; | ||||||
| 	qse_httpd_server_t* xserver; | 	qse_httpd_server_t* xserver; | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	qse_mxstr_t ba; |  | ||||||
| 	qse_size_t balen2; |  | ||||||
| 
 | 
 | ||||||
|  | 	/* memcpy here assumes that the top of the dope structure
 | ||||||
|  | 	 * is common with the server structure */ | ||||||
|  | 	QSE_MEMCPY (&dope, server, QSE_SIZEOF(dope)); | ||||||
|  | 	dope.predetach = predetach_server; /* set my own detaching function */ | ||||||
|  | 	dope.reconfig = reconfig_server; /* set my own detaching function */ | ||||||
|  | 
 | ||||||
|  | 	xserver = qse_httpd_attachserver (httpd, &dope, QSE_SIZEOF(*server_xtn) + xtnsize); | ||||||
|  | 	if (xserver == QSE_NULL) return QSE_NULL; | ||||||
|  | 
 | ||||||
|  | 	server_xtn = qse_httpd_getserverxtn (httpd, xserver); | ||||||
|  | 	server_xtn->predetach = server->predetach; | ||||||
|  | 	server_xtn->reconfig = server->reconfig; | ||||||
|  | 	server_xtn->query = query_server; | ||||||
|  | 	server_xtn->makersrc = make_resource; | ||||||
|  | 	server_xtn->freersrc = free_resource; | ||||||
|  | 
 | ||||||
|  | 	return xserver; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | qse_httpd_server_t* qse_httpd_attachserverstdwithuri ( | ||||||
|  | 	qse_httpd_t* httpd, const qse_char_t* uri,  | ||||||
|  | 	qse_httpd_server_predetach_t predetach,  | ||||||
|  | 	qse_httpd_server_reconfig_t reconfig,  | ||||||
|  | 	qse_httpd_serverstd_query_t query,  | ||||||
|  | 	qse_size_t xtnsize) | ||||||
|  | { | ||||||
|  | 	qse_httpd_serverstd_t server; | ||||||
| 	qse_uint16_t default_port; | 	qse_uint16_t default_port; | ||||||
| 	qse_uri_t xuri; | 	qse_uri_t xuri; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	static qse_httpd_server_cgistd_t server_cgistd[] =  |  | ||||||
| 	{ |  | ||||||
| 		{ QSE_MT(".cgi"), 4, 0, QSE_NULL }, |  | ||||||
| 		{ QSE_MT(".nph"), 4, 1, QSE_NULL }, |  | ||||||
| 		{ QSE_NULL,       0, 0, QSE_NULL } |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	static qse_httpd_server_mimestd_t server_mimestd[] = |  | ||||||
| 	{ |  | ||||||
| 		{ QSE_MT(".html"), QSE_MT("text/html") }, |  | ||||||
| 		{ QSE_MT(".htm"),  QSE_MT("text/htm") }, |  | ||||||
| 		{ QSE_MT(".txt"),  QSE_MT("text/plain") }, |  | ||||||
| 		{ QSE_MT(".log"),  QSE_MT("text/plain") }, |  | ||||||
| 		{ QSE_MT(".css"),  QSE_MT("text/css") }, |  | ||||||
| 		{ QSE_MT(".xml"),  QSE_MT("text/xml") }, |  | ||||||
| 		{ QSE_MT(".js"),   QSE_MT("application/javascript") }, |  | ||||||
| 		{ QSE_MT(".jpg"),  QSE_MT("image/jpeg") }, |  | ||||||
| 		{ QSE_MT(".png"),  QSE_MT("image/png") }, |  | ||||||
| 		{ QSE_MT(".mp4"),  QSE_MT("video/mp4") }, |  | ||||||
| 		{ QSE_MT(".mp3"),  QSE_MT("audio/mpeg") },  |  | ||||||
| 		{ QSE_MT(".c"),    QSE_MT("text/plain") },  |  | ||||||
| 		{ QSE_MT(".h"),    QSE_MT("text/plain") }, |  | ||||||
| 		{ QSE_MT(".cpp"),  QSE_MT("text/plain") },  |  | ||||||
| 		{ QSE_MT(".hpp"),  QSE_MT("text/plain") }, |  | ||||||
| 		{ QSE_NULL,        QSE_NULL } |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	qse_mcstr_t tmp[4] =  |  | ||||||
| 	{  |  | ||||||
| 		{ QSE_MT(""),  0 }, |  | ||||||
| 		{ QSE_MT(":"), 1 }, |  | ||||||
| 		{ QSE_MT(""),  0 }, |  | ||||||
| 		{ QSE_NULL,    0 }  |  | ||||||
| 	}; |  | ||||||
| #else |  | ||||||
| 	qse_wcstr_t tmp[4] =  |  | ||||||
| 	{  |  | ||||||
| 		{ QSE_WT(""),  0 }, |  | ||||||
| 		{ QSE_WT(":"), 1 }, |  | ||||||
| 		{ QSE_WT(""),  0 }, |  | ||||||
| 		{ QSE_NULL,    0 }  |  | ||||||
| 	}; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	QSE_MEMSET (&server, 0, QSE_SIZEOF(server)); | 	QSE_MEMSET (&server, 0, QSE_SIZEOF(server)); | ||||||
| 
 | 
 | ||||||
| 	if (qse_strtouri (uri, &xuri, QSE_STRTOURI_NOQUERY) <= -1)  goto invalid; | 	if (qse_strtouri (uri, &xuri, QSE_STRTOURI_NOQUERY) <= -1)  goto invalid; | ||||||
| @ -2485,93 +2621,25 @@ qse_httpd_server_t* qse_httpd_attachserverstd ( | |||||||
| 			server.nwad.u.in6.port = qse_hton16(default_port); | 			server.nwad.u.in6.port = qse_hton16(default_port); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	xserver = qse_httpd_attachserver ( | 	server.predetach = predetach; | ||||||
| 		httpd, &server, predetach_server, QSE_SIZEOF(*server_xtn) + xtnsize); | 	server.reconfig = reconfig; | ||||||
| 	if (xserver == QSE_NULL) return QSE_NULL; | #if 0 | ||||||
| 
 | 	server.docroot = xuri.path; | ||||||
| 	server_xtn = qse_httpd_getserverxtn (httpd, xserver); | 	if (server.docroot.ptr && qse_ismbsdriveabspath((const qse_mchar_t*)server.docroot.ptr + 1)) | ||||||
| 
 |  | ||||||
| 	if (!xuri.path.ptr) |  | ||||||
| 	{ | 	{ | ||||||
| 		/* the path part is not specified */ | 		/* if the path name is something like /C:/xxx on support platforms ... */ | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) | 		server.docroot.ptr++;	 | ||||||
| 		xuri.path.ptr = QSE_MT("/"); | 		server.docroot.len--; | ||||||
| #else | 	} | ||||||
| 		xuri.path.ptr = QSE_WT("/"); | 	server.realm = xuri.frag; | ||||||
|  | 	server.user = xuri.auth.user; | ||||||
|  | 	server.pass = xuri.auth.pass; | ||||||
| #endif | #endif | ||||||
| 		xuri.path.len = 1; | 	return qse_httpd_attachserverstd (httpd, &server, xtnsize); | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (xuri.auth.user.ptr) |  | ||||||
| 	{ |  | ||||||
| 		tmp[0].ptr = xuri.auth.user.ptr; |  | ||||||
| 		tmp[0].len = xuri.auth.user.len; |  | ||||||
| 	} |  | ||||||
| 	if (xuri.auth.pass.ptr) |  | ||||||
| 	{ |  | ||||||
| 		tmp[2].ptr = xuri.auth.pass.ptr; |  | ||||||
| 		tmp[2].len = xuri.auth.pass.len; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	if (qse_ismbsdriveabspath((const qse_mchar_t*)xuri.path.ptr + 1)) |  | ||||||
| 		server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup ((const qse_mchar_t*)xuri.path.ptr + 1, xuri.path.len - 1, httpd->mmgr); |  | ||||||
| 	else |  | ||||||
| 		server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); |  | ||||||
| 	if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = qse_mbsxdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr); |  | ||||||
| 	ba.ptr = qse_mcstradup (tmp, &ba.len, httpd->mmgr); |  | ||||||
| 	 |  | ||||||
| #else |  | ||||||
| 	if (qse_iswcsdriveabspath((const qse_wchar_t*)xuri.path.ptr + 1)) |  | ||||||
| 		server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_wcsntombsdup ((const qse_wchar_t*)xuri.path.ptr + 1, xuri.path.len - 1, QSE_NULL, httpd->mmgr); |  | ||||||
| 	else |  | ||||||
| 		server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, QSE_NULL, httpd->mmgr); |  | ||||||
| 	if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = qse_wcsntombsdup (xuri.frag.ptr, xuri.frag.len, QSE_NULL, httpd->mmgr); |  | ||||||
| 	ba.ptr = qse_wcsnatombsdup (tmp, &ba.len, httpd->mmgr); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	if ((!server_xtn->cfg[SERVER_XTN_CFG_DOCROOT]) || |  | ||||||
| 	    (xuri.frag.ptr && !server_xtn->cfg[SERVER_XTN_CFG_REALM]) || |  | ||||||
| 	    !ba.ptr)  |  | ||||||
| 	{ |  | ||||||
| 		if (ba.ptr) QSE_MMGR_FREE (httpd->mmgr, ba.ptr); |  | ||||||
| 		goto nomem_after_attach; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	balen2 = ((ba.len / 3) + 1) * 4; |  | ||||||
| 	server_xtn->cfg[SERVER_XTN_CFG_AUTH] = QSE_MMGR_ALLOC ( |  | ||||||
| 		httpd->mmgr, (balen2 + 1) * QSE_SIZEOF(qse_mchar_t)); |  | ||||||
| 	if (!server_xtn->cfg[SERVER_XTN_CFG_AUTH])  |  | ||||||
| 	{ |  | ||||||
| 		QSE_MMGR_FREE (httpd->mmgr, ba.ptr); |  | ||||||
| 		goto nomem_after_attach; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	qse_enbase64 ( |  | ||||||
| 		ba.ptr, ba.len, |  | ||||||
| 		server_xtn->cfg[SERVER_XTN_CFG_AUTH], |  | ||||||
| 		balen2, |  | ||||||
| 		&balen2 |  | ||||||
| 	); |  | ||||||
| 	QSE_MMGR_FREE (httpd->mmgr, ba.ptr); |  | ||||||
| 	(server_xtn->cfg[SERVER_XTN_CFG_AUTH])[balen2] = QSE_MT('\0'); |  | ||||||
| 
 |  | ||||||
| 	server_xtn->predetach = predetach; |  | ||||||
| 	server_xtn->cfg2.s.cbstd = &server_cbstd; |  | ||||||
| 	server_xtn->cfg2.s.cgistd = server_cgistd; |  | ||||||
| 	server_xtn->cfg2.s.mimestd = server_mimestd; |  | ||||||
| 	server_xtn->cfg2.s.idxstd = QSE_NULL; |  | ||||||
| 
 |  | ||||||
| 	return xserver; |  | ||||||
| 
 | 
 | ||||||
| invalid: | invalid: | ||||||
| 	httpd->errnum = QSE_HTTPD_EINVAL; | 	httpd->errnum = QSE_HTTPD_EINVAL; | ||||||
| 	return QSE_NULL; | 	return QSE_NULL; | ||||||
| 
 |  | ||||||
| nomem_after_attach: |  | ||||||
| 	qse_httpd_detachserver (httpd, xserver);	 |  | ||||||
| 	httpd->errnum = QSE_HTTPD_ENOMEM; |  | ||||||
| 	return QSE_NULL; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int qse_httpd_getserveroptstd ( | int qse_httpd_getserveroptstd ( | ||||||
| @ -2584,19 +2652,16 @@ int qse_httpd_getserveroptstd ( | |||||||
| 
 | 
 | ||||||
| 	switch (id) | 	switch (id) | ||||||
| 	{ | 	{ | ||||||
| 		case QSE_HTTPD_SERVER_DOCROOT: | 		case QSE_HTTPD_SERVERSTD_QUERY: | ||||||
| 		case QSE_HTTPD_SERVER_REALM: | 			*(qse_httpd_serverstd_query_t*)value = server_xtn->query; | ||||||
| 		case QSE_HTTPD_SERVER_AUTH: |  | ||||||
| 		case QSE_HTTPD_SERVER_ERRCSS: |  | ||||||
| 		case QSE_HTTPD_SERVER_DIRCSS: |  | ||||||
| 			*(qse_mchar_t**)value = server_xtn->cfg[id - QSE_HTTPD_SERVER_DOCROOT]; |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 
 | 
 | ||||||
| 		case QSE_HTTPD_SERVER_CBSTD: | 		case QSE_HTTPD_SERVERSTD_MAKERSRC: | ||||||
| 		case QSE_HTTPD_SERVER_CGISTD: | 			*(qse_httpd_serverstd_makersrc_t*)value = server_xtn->makersrc; | ||||||
| 		case QSE_HTTPD_SERVER_MIMESTD: | 			return 0; | ||||||
| 		case QSE_HTTPD_SERVER_IDXSTD: | 
 | ||||||
| 			*(void**)value = (void*)server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD]; | 		case QSE_HTTPD_SERVERSTD_FREERSRC: | ||||||
|  | 			*(qse_httpd_serverstd_freersrc_t*)value = server_xtn->freersrc; | ||||||
| 			return 0; | 			return 0; | ||||||
| 	}	 | 	}	 | ||||||
| 
 | 
 | ||||||
| @ -2604,47 +2669,27 @@ int qse_httpd_getserveroptstd ( | |||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| int qse_httpd_setserveroptstd ( | int qse_httpd_setserveroptstd ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_server_t* server, | 	qse_httpd_t* httpd, qse_httpd_server_t* server, | ||||||
| 	qse_httpd_server_optstd_t id, const void* value) | 	qse_httpd_server_optstd_t id, const void* value) | ||||||
| { | { | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	qse_mchar_t* mctmp; |  | ||||||
| 
 | 
 | ||||||
| 	server_xtn = qse_httpd_getserverxtn (httpd, server); | 	server_xtn = qse_httpd_getserverxtn (httpd, server); | ||||||
| 
 | 
 | ||||||
| 	switch (id) | 	switch (id) | ||||||
| 	{ | 	{ | ||||||
| 		case QSE_HTTPD_SERVER_DOCROOT: | 		case QSE_HTTPD_SERVERSTD_QUERY: | ||||||
| 		case QSE_HTTPD_SERVER_REALM: | 			server_xtn->query = (qse_httpd_serverstd_query_t)value; | ||||||
| 		case QSE_HTTPD_SERVER_AUTH: |  | ||||||
| 		case QSE_HTTPD_SERVER_ERRCSS: |  | ||||||
| 		case QSE_HTTPD_SERVER_DIRCSS: |  | ||||||
| 			mctmp = (qse_mchar_t*)value; |  | ||||||
| 			if(mctmp) |  | ||||||
| 			{	 |  | ||||||
| 				mctmp = qse_mbsdup ((qse_mchar_t*)mctmp, httpd->mmgr); |  | ||||||
| 				if (mctmp == QSE_NULL) |  | ||||||
| 				{ |  | ||||||
| 					httpd->errnum = QSE_HTTPD_ENOMEM; |  | ||||||
| 					return -1; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (server_xtn->cfg[id - QSE_HTTPD_SERVER_DOCROOT]) |  | ||||||
| 			{ |  | ||||||
| 				QSE_MMGR_FREE (httpd->mmgr,  |  | ||||||
| 					server_xtn->cfg[id - QSE_HTTPD_SERVER_DOCROOT]); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			server_xtn->cfg[id - QSE_HTTPD_SERVER_DOCROOT] = mctmp; |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 
 | 
 | ||||||
| 		case QSE_HTTPD_SERVER_CBSTD: | 		case QSE_HTTPD_SERVERSTD_MAKERSRC: | ||||||
| 		case QSE_HTTPD_SERVER_CGISTD: | 			server_xtn->makersrc = (qse_httpd_serverstd_makersrc_t)value; | ||||||
| 		case QSE_HTTPD_SERVER_MIMESTD: | 			return 0; | ||||||
| 		case QSE_HTTPD_SERVER_IDXSTD: | 
 | ||||||
| 			server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD] = value; | 		case QSE_HTTPD_SERVERSTD_FREERSRC: | ||||||
|  | 			server_xtn->freersrc = (qse_httpd_serverstd_freersrc_t)value; | ||||||
| 			return 0; | 			return 0; | ||||||
| 	}	 | 	}	 | ||||||
| 
 | 
 | ||||||
| @ -89,6 +89,11 @@ void qse_httpd_stop (qse_httpd_t* httpd) | |||||||
| 	httpd->stopreq = 1; | 	httpd->stopreq = 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void qse_httpd_reconfig (qse_httpd_t* httpd) | ||||||
|  | { | ||||||
|  | 	httpd->reconfigreq = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| qse_httpd_errnum_t qse_httpd_geterrnum (qse_httpd_t* httpd) | qse_httpd_errnum_t qse_httpd_geterrnum (qse_httpd_t* httpd) | ||||||
| { | { | ||||||
| 	return httpd->errnum; | 	return httpd->errnum; | ||||||
| @ -159,6 +164,14 @@ QSE_INLINE void* qse_httpd_allocmem (qse_httpd_t* httpd, qse_size_t size) | |||||||
| 	return ptr; | 	return ptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | QSE_INLINE void* qse_httpd_callocmem (qse_httpd_t* httpd, qse_size_t size) | ||||||
|  | { | ||||||
|  | 	void* ptr = QSE_MMGR_ALLOC (httpd->mmgr, size); | ||||||
|  | 	if (ptr == QSE_NULL) httpd->errnum = QSE_HTTPD_ENOMEM; | ||||||
|  | 	else QSE_MEMSET (ptr, 0, size); | ||||||
|  | 	return ptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| QSE_INLINE void* qse_httpd_reallocmem ( | QSE_INLINE void* qse_httpd_reallocmem ( | ||||||
| 	qse_httpd_t* httpd, void* ptr, qse_size_t size) | 	qse_httpd_t* httpd, void* ptr, qse_size_t size) | ||||||
| { | { | ||||||
| @ -172,6 +185,34 @@ QSE_INLINE void qse_httpd_freemem (qse_httpd_t* httpd, void* ptr) | |||||||
| 	QSE_MMGR_FREE (httpd->mmgr, ptr); | 	QSE_MMGR_FREE (httpd->mmgr, ptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | qse_mchar_t* qse_httpd_strtombsdup (qse_httpd_t* httpd, const qse_char_t* str) | ||||||
|  | { | ||||||
|  | 	qse_mchar_t* mptr; | ||||||
|  | 
 | ||||||
|  | #if defined(QSE_CHAR_IS_MCHAR) | ||||||
|  | 	mptr = qse_mbsdup (str, httpd->mmgr); | ||||||
|  | #else | ||||||
|  | 	mptr = qse_wcstombsdup (str, QSE_NULL, httpd->mmgr); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	if (mptr == QSE_NULL) httpd->errnum = QSE_HTTPD_ENOMEM; | ||||||
|  | 	return mptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | qse_mchar_t* qse_httpd_strntombsdup (qse_httpd_t* httpd, const qse_char_t* str, qse_size_t len) | ||||||
|  | { | ||||||
|  | 	qse_mchar_t* mptr; | ||||||
|  | 
 | ||||||
|  | #if defined(QSE_CHAR_IS_MCHAR) | ||||||
|  | 	mptr = qse_mbsxdup (str, len, httpd->mmgr); | ||||||
|  | #else | ||||||
|  | 	mptr = qse_wcsntombsdup (str, len, QSE_NULL, httpd->mmgr); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	if (mptr == QSE_NULL) httpd->errnum = QSE_HTTPD_ENOMEM; | ||||||
|  | 	return mptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* --------------------------------------------------- */ | /* --------------------------------------------------- */ | ||||||
| 
 | 
 | ||||||
| static qse_httpd_task_t* enqueue_task ( | static qse_httpd_task_t* enqueue_task ( | ||||||
| @ -434,15 +475,15 @@ static int accept_client ( | |||||||
| 		{ | 		{ | ||||||
| /* TODO: proper logging */ | /* TODO: proper logging */ | ||||||
| qse_char_t tmp[128]; | qse_char_t tmp[128]; | ||||||
| qse_nwadtostr (&server->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | qse_nwadtostr (&server->dope.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); | ||||||
| qse_printf (QSE_T("failed to accept from server %s\n"), tmp); | qse_printf (QSE_T("failed to accept from server [%s] [%d]\n"), tmp, server->handle.i); | ||||||
| 
 | 
 | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| /* TODO: check maximum number of client. if exceed call client.close */ | /* TODO: check maximum number of client. if exceed call client.close */ | ||||||
| 
 | 
 | ||||||
| 		if (server->flags & QSE_HTTPD_SERVER_SECURE) clibuf.status |= CLIENT_SECURE; | 		if (server->dope.flags & QSE_HTTPD_SERVER_SECURE) clibuf.status |= CLIENT_SECURE; | ||||||
| 		clibuf.server = server; | 		clibuf.server = server; | ||||||
| 
 | 
 | ||||||
| 		client = new_client (httpd, &clibuf); | 		client = new_client (httpd, &clibuf); | ||||||
| @ -496,11 +537,11 @@ static void deactivate_servers (qse_httpd_t* httpd) | |||||||
| 
 | 
 | ||||||
| 	for (server = httpd->server.list.head; server; server = server->next) | 	for (server = httpd->server.list.head; server; server = server->next) | ||||||
| 	{ | 	{ | ||||||
| 		if (server->flags & QSE_HTTPD_SERVER_ACTIVE) | 		if (server->dope.flags & QSE_HTTPD_SERVER_ACTIVE) | ||||||
| 		{ | 		{ | ||||||
| 			httpd->scb->mux.delhnd (httpd, httpd->mux, server->handle); | 			httpd->scb->mux.delhnd (httpd, httpd->mux, server->handle); | ||||||
| 			httpd->scb->server.close (httpd, server); | 			httpd->scb->server.close (httpd, server); | ||||||
| 			server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; | 			server->dope.flags &= ~QSE_HTTPD_SERVER_ACTIVE; | ||||||
| 			httpd->server.nactive--; | 			httpd->server.nactive--; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -515,13 +556,12 @@ static int activate_servers (qse_httpd_t* httpd) | |||||||
| 		if (httpd->scb->server.open (httpd, server) <= -1) | 		if (httpd->scb->server.open (httpd, server) <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			qse_char_t buf[64]; | 			qse_char_t buf[64]; | ||||||
| 			qse_nwadtostr (&server->nwad,  | 			qse_nwadtostr (&server->dope.nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); | ||||||
| 				buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| 			httpd->rcb->log (httpd, 0,  | 			httpd->rcb->log (httpd, 0, QSE_T("cannot activate %s"), buf); | ||||||
| 				QSE_T("cannot activate %s"), buf); |  | ||||||
| */ | */ | ||||||
|  | qse_printf(QSE_T("cannot activate [%s]\n"), buf); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| @ -529,18 +569,17 @@ static int activate_servers (qse_httpd_t* httpd) | |||||||
| 			httpd, httpd->mux, server->handle, QSE_HTTPD_MUX_READ, server) <= -1) | 			httpd, httpd->mux, server->handle, QSE_HTTPD_MUX_READ, server) <= -1) | ||||||
| 		{ | 		{ | ||||||
| 			qse_char_t buf[64]; | 			qse_char_t buf[64]; | ||||||
| 			qse_nwadtostr (&server->nwad,  | 			qse_nwadtostr (&server->dope.nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); | ||||||
| 				buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); |  | ||||||
| /*
 | /*
 | ||||||
| 			httpd->rcb->log (httpd, 0,  | 			httpd->rcb->log (httpd, 0, QSE_T("cannot activate %s - "), buf); | ||||||
| 				QSE_T("cannot activate %s - "), buf); |  | ||||||
| */ | */ | ||||||
|  | qse_printf(QSE_T("cannot add handle [%s]\n"), buf); | ||||||
| 
 | 
 | ||||||
| 			httpd->scb->server.close (httpd, server); | 			httpd->scb->server.close (httpd, server); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		server->flags |= QSE_HTTPD_SERVER_ACTIVE; | 		server->dope.flags |= QSE_HTTPD_SERVER_ACTIVE; | ||||||
| 		httpd->server.nactive++; | 		httpd->server.nactive++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -566,20 +605,18 @@ static void free_server_list (qse_httpd_t* httpd) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| qse_httpd_server_t* qse_httpd_attachserver ( | qse_httpd_server_t* qse_httpd_attachserver ( | ||||||
| 	qse_httpd_t* httpd, const qse_httpd_server_t* tmpl,  | 	qse_httpd_t* httpd, const qse_httpd_server_dope_t* dope, qse_size_t xtnsize) | ||||||
| 	qse_httpd_server_predetach_t predetach, qse_size_t xtnsize) |  | ||||||
| { | { | ||||||
| 	qse_httpd_server_t* server; | 	qse_httpd_server_t* server; | ||||||
| 
 | 
 | ||||||
| 	server = qse_httpd_allocmem (httpd, QSE_SIZEOF(*server) + xtnsize); | 	server = qse_httpd_callocmem (httpd, QSE_SIZEOF(*server) + xtnsize); | ||||||
| 	if (server == QSE_NULL) return QSE_NULL; | 	if (server == QSE_NULL) return QSE_NULL; | ||||||
| 
 | 
 | ||||||
| 	QSE_MEMCPY (server, tmpl, QSE_SIZEOF(*server));  |  | ||||||
| 	QSE_MEMSET (server + 1, 0, xtnsize); |  | ||||||
| 
 |  | ||||||
| 	server->type = QSE_HTTPD_SERVER; | 	server->type = QSE_HTTPD_SERVER; | ||||||
| 	server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; | 	/* copy the server dope */ | ||||||
| 	server->predetach = predetach; | 	server->dope = *dope; | ||||||
|  | 	/* and correct some fields in case the dope contains invalid stuffs */ | ||||||
|  | 	server->dope.flags &= ~QSE_HTTPD_SERVER_ACTIVE; | ||||||
| 
 | 
 | ||||||
| 	/* chain the server to the tail of the list */ | 	/* chain the server to the tail of the list */ | ||||||
| 	server->prev = httpd->server.list.tail; | 	server->prev = httpd->server.list.tail; | ||||||
| @ -601,9 +638,9 @@ void qse_httpd_detachserver (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 	prev = server->prev; | 	prev = server->prev; | ||||||
| 	next = server->next; | 	next = server->next; | ||||||
| 
 | 
 | ||||||
| 	QSE_ASSERT (!(server->flags & QSE_HTTPD_SERVER_ACTIVE)); | 	QSE_ASSERT (!(server->dope.flags & QSE_HTTPD_SERVER_ACTIVE)); | ||||||
| 
 | 
 | ||||||
| 	if (server->predetach) server->predetach (httpd, server); | 	if (server->dope.predetach) server->dope.predetach (httpd, server); | ||||||
| 
 | 
 | ||||||
| 	qse_httpd_freemem (httpd, server); | 	qse_httpd_freemem (httpd, server); | ||||||
| 	httpd->server.navail--; | 	httpd->server.navail--; | ||||||
| @ -1112,11 +1149,24 @@ qse_printf (QSE_T("MUX ADDHND CLIENT RW(ENTASK) %d\n"), client->handle.i); | |||||||
| static int dispatch_mux ( | static int dispatch_mux ( | ||||||
| 	qse_httpd_t* httpd, void* mux, qse_ubi_t handle, int mask, void* cbarg) | 	qse_httpd_t* httpd, void* mux, qse_ubi_t handle, int mask, void* cbarg) | ||||||
| { | { | ||||||
| 	return ((qse_httpd_server_t*)cbarg)->type == QSE_HTTPD_SERVER? | 	return ((qse_httpd_mate_t*)cbarg)->type == QSE_HTTPD_SERVER? | ||||||
| 		accept_client (httpd, mux, handle, mask, cbarg): | 		accept_client (httpd, mux, handle, mask, cbarg): | ||||||
| 		perform_client_task (httpd, mux, handle, mask, cbarg); | 		perform_client_task (httpd, mux, handle, mask, cbarg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void reconfig_servers (qse_httpd_t* httpd) | ||||||
|  | { | ||||||
|  | 	qse_httpd_server_t* server; | ||||||
|  | 
 | ||||||
|  | 	for (server = httpd->server.list.head; server; server = server->next) | ||||||
|  | 	{ | ||||||
|  | 		if (server->dope.flags & QSE_HTTPD_SERVER_ACTIVE) | ||||||
|  | 		{ | ||||||
|  | 			if (server->dope.reconfig) server->dope.reconfig (httpd, server); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int qse_httpd_loop ( | int qse_httpd_loop ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_scb_t* scb, | 	qse_httpd_t* httpd, qse_httpd_scb_t* scb, | ||||||
| 	qse_httpd_rcb_t* rcb, const qse_ntime_t* tmout) | 	qse_httpd_rcb_t* rcb, const qse_ntime_t* tmout) | ||||||
| @ -1166,12 +1216,21 @@ int qse_httpd_loop ( | |||||||
| 		count = httpd->scb->mux.poll (httpd, httpd->mux, tmout); | 		count = httpd->scb->mux.poll (httpd, httpd->mux, tmout); | ||||||
| 		if (count <= -1)  | 		if (count <= -1)  | ||||||
| 		{ | 		{ | ||||||
| 			xret = -1;  | 			if (httpd->errnum != QSE_HTTPD_EINTR) | ||||||
| 			break; | 			{ | ||||||
|  | 				xret = -1;  | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		purge_bad_clients (httpd); | 		purge_bad_clients (httpd); | ||||||
| 		purge_idle_clients (httpd); | 		purge_idle_clients (httpd); | ||||||
|  | 
 | ||||||
|  | 		if (httpd->reconfigreq) | ||||||
|  | 		{ | ||||||
|  | 			reconfig_servers (httpd);	 | ||||||
|  | 			httpd->reconfigreq = 0; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	purge_client_list (httpd); | 	purge_client_list (httpd); | ||||||
| @ -18,12 +18,12 @@ | |||||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 |     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _QSE_LIB_NET_HTTPD_H_ | #ifndef _QSE_LIB_HTTP_HTTPD_H_ | ||||||
| #define _QSE_LIB_NET_HTTPD_H_ | #define _QSE_LIB_HTTP_HTTPD_H_ | ||||||
| 
 | 
 | ||||||
| /* private header file for httpd */ | /* private header file for httpd */ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/httpd.h> | #include <qse/http/httpd.h> | ||||||
| 
 | 
 | ||||||
| #include <qse/cmn/stdio.h> /* TODO: remove this.. only for debugging at this moment */ | #include <qse/cmn/stdio.h> /* TODO: remove this.. only for debugging at this moment */ | ||||||
| 
 | 
 | ||||||
| @ -39,7 +39,8 @@ struct qse_httpd_t | |||||||
| 	{ | 	{ | ||||||
| 		int trait; | 		int trait; | ||||||
| 	} opt; | 	} opt; | ||||||
| 	int stopreq; | 	int stopreq: 1; | ||||||
|  | 	int reconfigreq: 1; | ||||||
| 
 | 
 | ||||||
| 	qse_mchar_t sname[128]; /* server name for the server header */ | 	qse_mchar_t sname[128]; /* server name for the server header */ | ||||||
| 	qse_mchar_t gtbuf[10][64]; /* GMT time buffers */ | 	qse_mchar_t gtbuf[10][64]; /* GMT time buffers */ | ||||||
| @ -21,7 +21,7 @@ | |||||||
| #ifndef _QSE_LIB_NET_UPXD_H_ | #ifndef _QSE_LIB_NET_UPXD_H_ | ||||||
| #define _QSE_LIB_NET_UPXD_H_ | #define _QSE_LIB_NET_UPXD_H_ | ||||||
| 
 | 
 | ||||||
| #include <qse/net/upxd.h> | #include <qse/http/upxd.h> | ||||||
| #include "../cmn/mem.h" | #include "../cmn/mem.h" | ||||||
| 
 | 
 | ||||||
| typedef struct qse_upxd_server_session_t qse_upxd_server_session_t; | typedef struct qse_upxd_server_session_t qse_upxd_server_session_t; | ||||||
| @ -39,10 +39,16 @@ const qse_char_t* qse_xli_dflerrstr ( | |||||||
| 		QSE_T("I/O error with file '${0}'"), | 		QSE_T("I/O error with file '${0}'"), | ||||||
| 		QSE_T("error returned by user I/O handler"), | 		QSE_T("error returned by user I/O handler"), | ||||||
|  |  | ||||||
|  | 		QSE_T("syntax error"), | ||||||
| 		QSE_T("semicolon expected in place of '${0}'"), | 		QSE_T("semicolon expected in place of '${0}'"), | ||||||
| 		QSE_T("left-brace or equal-sign expected in place of '${0}'"), | 		QSE_T("left-brace or equal-sign expected in place of '${0}'"), | ||||||
| 		QSE_T("right-brace expected in place of '${0}'"), | 		QSE_T("right-brace expected in place of '${0}'"), | ||||||
| 		QSE_T("pair value expected in place of '${0}'") | 		QSE_T("pair value expected in place of '${0}'"), | ||||||
|  | 		QSE_T("string not closed"), | ||||||
|  | 		QSE_T("'@include' not followed by a string"), | ||||||
|  | 		QSE_T("invalid character '${0}'"), | ||||||
|  | 		QSE_T("'${0}' not recognized"), | ||||||
|  | 		QSE_T("@ not followed by a valid word") | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))? | 	return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))? | ||||||
|  | |||||||
| @ -48,6 +48,7 @@ enum tok_t | |||||||
| 	TOK_LBRACE, | 	TOK_LBRACE, | ||||||
| 	TOK_RBRACE, | 	TOK_RBRACE, | ||||||
| 	TOK_EQ, | 	TOK_EQ, | ||||||
|  | 	TOK_COMMA, | ||||||
| 	TOK_DQSTR, | 	TOK_DQSTR, | ||||||
| 	TOK_SQSTR, | 	TOK_SQSTR, | ||||||
| 	TOK_IDENT, | 	TOK_IDENT, | ||||||
| @ -221,6 +222,7 @@ static int get_symbols (qse_xli_t* xli, qse_cint_t c, qse_xli_tok_t* tok) | |||||||
| 	static struct ops_t ops[] =  | 	static struct ops_t ops[] =  | ||||||
| 	{ | 	{ | ||||||
| 		{ QSE_T("="),   1, TOK_EQ          }, | 		{ QSE_T("="),   1, TOK_EQ          }, | ||||||
|  | 		{ QSE_T(","),   1, TOK_COMMA       }, | ||||||
| 		{ QSE_T(";"),   1, TOK_SEMICOLON   }, | 		{ QSE_T(";"),   1, TOK_SEMICOLON   }, | ||||||
| 		{ QSE_T("{"),   1, TOK_LBRACE      }, | 		{ QSE_T("{"),   1, TOK_LBRACE      }, | ||||||
| 		{ QSE_T("}"),   1, TOK_RBRACE      }, | 		{ QSE_T("}"),   1, TOK_RBRACE      }, | ||||||
| @ -310,9 +312,7 @@ static int begin_include (qse_xli_t* xli) | |||||||
| 	); | 	); | ||||||
| 	if (pair == QSE_NULL) | 	if (pair == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| #if 0 | 		qse_xli_seterror (xli, QSE_XLI_ENOMEM, QSE_NULL, &xli->tok.loc); | ||||||
| 		SETERR_LOC (xli, QSE_XLI_ENOMEM, &xli->ptok.loc); |  | ||||||
| #endif |  | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -320,13 +320,7 @@ static int begin_include (qse_xli_t* xli) | |||||||
| 	QSE_HTB_VLEN(pair) = QSE_HTB_KLEN(pair);*/ | 	QSE_HTB_VLEN(pair) = QSE_HTB_KLEN(pair);*/ | ||||||
|  |  | ||||||
| 	arg = (qse_xli_io_arg_t*) qse_xli_callocmem (xli, QSE_SIZEOF(*arg)); | 	arg = (qse_xli_io_arg_t*) qse_xli_callocmem (xli, QSE_SIZEOF(*arg)); | ||||||
| 	if (arg == QSE_NULL) | 	if (arg == QSE_NULL) goto oops; | ||||||
| 	{ |  | ||||||
| #if 0 |  | ||||||
| 		ADJERR_LOC (xli, &xli->ptok.loc); |  | ||||||
| #endif |  | ||||||
| 		goto oops; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	arg->flags = QSE_XLI_IO_INCLUDED; | 	arg->flags = QSE_XLI_IO_INCLUDED; | ||||||
| 	arg->name = QSE_HTB_KPTR(pair); | 	arg->name = QSE_HTB_KPTR(pair); | ||||||
| @ -411,9 +405,7 @@ retry: | |||||||
| 		{ | 		{ | ||||||
| 			/* this directive is empty,  | 			/* this directive is empty,  | ||||||
| 			 * not followed by a valid word */ | 			 * not followed by a valid word */ | ||||||
| #if  0 | 			qse_xli_seterror (xli, QSE_XLI_EXKWEM, QSE_NULL, &xli->tok.loc); | ||||||
| 			SETERR_LOC (xli, QSE_XLI_EXKWEM, &(xli)->tok.loc); |  | ||||||
| #endif |  | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -429,9 +421,7 @@ retry: | |||||||
| 		if (type == TOK_IDENT) | 		if (type == TOK_IDENT) | ||||||
| 		{ | 		{ | ||||||
| 			/* this directive is not recognized */ | 			/* this directive is not recognized */ | ||||||
| #if 0 | 			qse_xli_seterror (xli, QSE_XLI_EXKWNR, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc); | ||||||
| 			SETERR_TOK (xli, QSE_XLI_EXKWNR); |  | ||||||
| #endif |  | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 		SET_TOKEN_TYPE (xli, tok, type); | 		SET_TOKEN_TYPE (xli, tok, type); | ||||||
| @ -465,9 +455,7 @@ retry: | |||||||
| 			if (c == QSE_CHAR_EOF) | 			if (c == QSE_CHAR_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				/* the string is not closed */ | 				/* the string is not closed */ | ||||||
| #if 0 | 				qse_xli_seterror (xli, QSE_XLI_ESTRNC, QSE_NULL, &xli->tok.loc); | ||||||
| 				SETERR_TOK (xli, QSE_XLI_ESTRNC); |  | ||||||
| #endif |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -490,18 +478,18 @@ retry: | |||||||
| 			/* not handled yet */ | 			/* not handled yet */ | ||||||
| 			if (c == QSE_T('\0')) | 			if (c == QSE_T('\0')) | ||||||
| 			{ | 			{ | ||||||
| #if 0 | 				qse_cstr_t ea; | ||||||
| 				SETERR_ARG_LOC ( | 				ea.ptr = QSE_T("<NUL>"); | ||||||
| 					xli, QSE_XLI_ELXCHR, | 				ea.len = 5; | ||||||
| 					QSE_T("<NUL>"), 5, &tok->loc); | 				qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc); | ||||||
| #endif |  | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| #if 0 |  | ||||||
| 				qse_char_t cc = (qse_char_t)c; | 				qse_char_t cc = (qse_char_t)c; | ||||||
| 				SETERR_ARG_LOC (xli, QSE_XLI_ELXCHR, &cc, 1, &tok->loc); | 				qse_cstr_t ea; | ||||||
| #endif | 				ea.ptr = &cc; | ||||||
|  | 				ea.len = 1; | ||||||
|  | 				qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc); | ||||||
| 			} | 			} | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| @ -518,9 +506,7 @@ retry: | |||||||
| 	if (skip_semicolon_after_include) | 	if (skip_semicolon_after_include) | ||||||
| 	{ | 	{ | ||||||
| 		/* semiclon has not been skipped yet */ | 		/* semiclon has not been skipped yet */ | ||||||
| #if 0 |  | ||||||
| 		qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_CSTR(tok->name), &tok->loc); | 		qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_CSTR(tok->name), &tok->loc); | ||||||
| #endif |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -538,7 +524,7 @@ static int read_pair (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
| 	qse_char_t* name = QSE_NULL; | 	qse_char_t* name = QSE_NULL; | ||||||
| 	qse_xli_pair_t* pair; | 	qse_xli_pair_t* pair; | ||||||
|  |  | ||||||
| 	if (xli->opt.trait & QSE_XLI_NODUPKEY) | 	if (xli->opt.trait & QSE_XLI_KEYNODUP) | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_atom_t* atom; | 		qse_xli_atom_t* atom; | ||||||
|  |  | ||||||
| @ -566,10 +552,10 @@ static int read_pair (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
|  |  | ||||||
| 	if (get_token (xli) <= -1) goto oops; | 	if (get_token (xli) <= -1) goto oops; | ||||||
|  |  | ||||||
| 	if  (xli->opt.trait & QSE_XLI_NAMEDKEY) | 	if  (xli->opt.trait & QSE_XLI_KEYNAME) | ||||||
| 	{ | 	{ | ||||||
| 		/* the name part must be unique for the same key(s) */ | 		/* the name part must be unique for the same key(s) */ | ||||||
| 		if (MATCH (xli, TOK_SQSTR) || MATCH(xli, TOK_DQSTR)) | 		if (MATCH (xli, TOK_IDENT) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_SQSTR)) | ||||||
| 		{ | 		{ | ||||||
| 			qse_xli_atom_t* atom; | 			qse_xli_atom_t* atom; | ||||||
|  |  | ||||||
| @ -602,14 +588,42 @@ static int read_pair (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
| 	{ | 	{ | ||||||
| 		if (get_token (xli) <= -1) goto oops; | 		if (get_token (xli) <= -1) goto oops; | ||||||
|  |  | ||||||
| 		if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR)) | 		if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_IDENT)) | ||||||
| 		{ | 		{ | ||||||
| 			pair = qse_xli_insertpairwithstr ( | 			if (qse_str_ncpy (xli->tmp[0], QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name) + 1) == (qse_size_t)-1) | ||||||
| 				xli, list, QSE_NULL, key, name,  | 			{ | ||||||
| 				QSE_STR_PTR(xli->tok.name), MATCH (xli, TOK_SQSTR)); | 				qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | ||||||
| 			if (pair == QSE_NULL) goto oops; | 				goto oops; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			if (get_token (xli) <= -1) goto oops; | 			if (get_token (xli) <= -1) goto oops; | ||||||
|  | 			if (MATCH(xli, TOK_COMMA)) | ||||||
|  | 			{ | ||||||
|  | 				/* multi-segmented string */ | ||||||
|  | 				do | ||||||
|  | 				{ | ||||||
|  | 					if (get_token (xli) <= -1) goto oops; /* skip the comma */ | ||||||
|  |  | ||||||
|  | 					if (!MATCH (xli, TOK_SQSTR) && !MATCH (xli, TOK_DQSTR) && !MATCH (xli, TOK_IDENT)) | ||||||
|  | 					{ | ||||||
|  | 						qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc); | ||||||
|  | 						goto oops; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (qse_str_ncat (xli->tmp[0], QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name) + 1) == (qse_size_t)-1) | ||||||
|  | 					{ | ||||||
|  | 						qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | ||||||
|  | 						goto oops; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (get_token (xli) <= -1) goto oops; /* skip the value */ | ||||||
|  | 				} | ||||||
|  | 				while (MATCH (xli, TOK_COMMA)); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			pair = qse_xli_insertpairwithstr ( | ||||||
|  | 				xli, list, QSE_NULL, key, name, QSE_STR_CSTR(xli->tmp[0])); | ||||||
|  | 			if (pair == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
| 			/* semicolon is mandatory for a string */ | 			/* semicolon is mandatory for a string */ | ||||||
| 			if (!MATCH (xli, TOK_SEMICOLON)) | 			if (!MATCH (xli, TOK_SEMICOLON)) | ||||||
| @ -651,6 +665,15 @@ static int read_pair (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
| 			if (get_token (xli) <= -1) goto oops; | 			if (get_token (xli) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	else if (MATCH (xli, TOK_SEMICOLON)) | ||||||
|  | 	{ | ||||||
|  | 		/* no value has been specified for the pair */ | ||||||
|  | 		pair = qse_xli_insertpair (xli, list, QSE_NULL, key, name, &xli->xnil); | ||||||
|  | 		if (pair == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
|  | 		/* skip the semicolon */ | ||||||
|  | 		if (get_token (xli) <= -1) goto oops; | ||||||
|  | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_seterror (xli, QSE_XLI_ELBREQ, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc); | 		qse_xli_seterror (xli, QSE_XLI_ELBREQ, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc); | ||||||
| @ -677,9 +700,7 @@ static int read_list (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
|  |  | ||||||
| 			if (!MATCH(xli,TOK_SQSTR) && !MATCH(xli,TOK_DQSTR)) | 			if (!MATCH(xli,TOK_SQSTR) && !MATCH(xli,TOK_DQSTR)) | ||||||
| 			{ | 			{ | ||||||
| #if 0 | 				qse_xli_seterror (xli, QSE_XLI_EINCLSTR, QSE_NULL, &xli->tok.loc); | ||||||
| 				SETERR_LOC (xli, QSE_XLI_EINCLSTR, &xli->ptok.loc); |  | ||||||
| #endif |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -693,7 +714,10 @@ static int read_list (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
| 		{ | 		{ | ||||||
| 			if (get_token(xli) <= -1) goto oops; | 			if (get_token(xli) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
| 		else break; | 		else  | ||||||
|  | 		{ | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -733,8 +757,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io) | |||||||
|  |  | ||||||
| 	if (!MATCH (xli, TOK_EOF)) | 	if (!MATCH (xli, TOK_EOF)) | ||||||
| 	{ | 	{ | ||||||
| /* TODO: set erro code */ | 		qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc); | ||||||
| qse_printf (QSE_T("NOT ENDING WITH EOF... %s\n"), QSE_STR_PTR(xli->tok.name)); |  | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -24,12 +24,12 @@ int qse_xli_write (qse_xli_t* xli, qse_xli_io_impl_t io) | |||||||
| { | { | ||||||
| 	if (io == QSE_NULL) | 	if (io == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| 		xli->errnum = QSE_XLI_EINVAL; | 		qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* TODO: write data to io stream */ | 	/* TODO: write data to io stream */ | ||||||
| 	xli->errnum = QSE_XLI_ENOIMPL; | 	qse_xli_seterrnum (xli, QSE_XLI_ENOIMPL, QSE_NULL); | ||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "xli.h" | #include "xli.h" | ||||||
|  | #include <qse/cmn/chr.h> | ||||||
|  |  | ||||||
| qse_xli_t* qse_xli_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) | qse_xli_t* qse_xli_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) | ||||||
| { | { | ||||||
| @ -51,10 +52,18 @@ void qse_xli_close (qse_xli_t* xli) | |||||||
|  |  | ||||||
| int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr) | int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr) | ||||||
| { | { | ||||||
|  | 	qse_size_t i; | ||||||
|  |  | ||||||
| 	QSE_MEMSET (xli, 0, QSE_SIZEOF(*xli)); | 	QSE_MEMSET (xli, 0, QSE_SIZEOF(*xli)); | ||||||
| 	xli->mmgr = mmgr; | 	xli->mmgr = mmgr; | ||||||
| 	xli->errstr = qse_xli_dflerrstr; | 	xli->errstr = qse_xli_dflerrstr; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < QSE_COUNTOF(xli->tmp); i++) | ||||||
|  | 	{ | ||||||
|  | 		xli->tmp[i] = qse_str_open (mmgr, 0, 128); | ||||||
|  | 		if (xli->tmp[i] == QSE_NULL) goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	xli->tok.name = qse_str_open (mmgr, 0, 128); | 	xli->tok.name = qse_str_open (mmgr, 0, 128); | ||||||
| 	if (xli->tok.name == QSE_NULL) goto oops; | 	if (xli->tok.name == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
| @ -67,20 +76,34 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr) | |||||||
| 		qse_gethtbmancbs(QSE_HTB_MANCBS_INLINE_KEY_COPIER) | 		qse_gethtbmancbs(QSE_HTB_MANCBS_INLINE_KEY_COPIER) | ||||||
| 	); | 	); | ||||||
| 	 | 	 | ||||||
|  | 	xli->root.type = QSE_XLI_LIST; | ||||||
|  | 	xli->xnil.type = QSE_XLI_NIL; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | 	qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); | ||||||
| 	if (xli->sio_names) qse_htb_close (xli->sio_names); | 	if (xli->sio_names) qse_htb_close (xli->sio_names); | ||||||
| 	if (xli->tok.name) qse_str_close (xli->tok.name); | 	if (xli->tok.name) qse_str_close (xli->tok.name); | ||||||
|  | 	 | ||||||
|  | 	for (i = QSE_COUNTOF(xli->tmp); i > 0; ) | ||||||
|  | 	{ | ||||||
|  | 		if (xli->tmp[--i]) qse_str_close (xli->tmp[i]); | ||||||
|  | 	} | ||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| void qse_xli_fini (qse_xli_t* xli) | void qse_xli_fini (qse_xli_t* xli) | ||||||
| { | { | ||||||
|  | 	qse_size_t i; | ||||||
|  |  | ||||||
| 	qse_xli_clear (xli); | 	qse_xli_clear (xli); | ||||||
| 	qse_htb_close (xli->sio_names); | 	qse_htb_close (xli->sio_names); | ||||||
| 	qse_str_close (xli->tok.name); | 	qse_str_close (xli->tok.name); | ||||||
|  |  | ||||||
|  | 	for (i = QSE_COUNTOF(xli->tmp); i > 0; ) | ||||||
|  | 	{ | ||||||
|  | 		if (xli->tmp[--i]) qse_str_close (xli->tmp[i]); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| qse_mmgr_t* qse_xli_getmmgr (qse_xli_t* xli) | qse_mmgr_t* qse_xli_getmmgr (qse_xli_t* xli) | ||||||
| @ -243,20 +266,20 @@ qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | |||||||
|  |  | ||||||
| qse_xli_pair_t* qse_xli_insertpairwithstr ( | qse_xli_pair_t* qse_xli_insertpairwithstr ( | ||||||
| 	qse_xli_t* xli, qse_xli_list_t* parent, qse_xli_atom_t* peer, | 	qse_xli_t* xli, qse_xli_list_t* parent, qse_xli_atom_t* peer, | ||||||
| 	const qse_char_t* key, const qse_char_t* name, const qse_char_t* value, int verbatim) | 	const qse_char_t* key, const qse_char_t* name, const qse_cstr_t* value) | ||||||
| { | { | ||||||
| 	qse_xli_str_t* val; | 	qse_xli_str_t* val; | ||||||
| 	qse_xli_pair_t* tmp; | 	qse_xli_pair_t* tmp; | ||||||
| 	qse_size_t vlen; |  | ||||||
|  |  | ||||||
| 	vlen = qse_strlen (value); | 	val = qse_xli_callocmem (xli, QSE_SIZEOF(*val) + ((value->len  + 1) * QSE_SIZEOF(*value->ptr))); | ||||||
| 	val = qse_xli_callocmem (xli, QSE_SIZEOF(*val) + ((vlen  + 1) * QSE_SIZEOF(*value))); |  | ||||||
| 	if (val == QSE_NULL) return QSE_NULL; | 	if (val == QSE_NULL) return QSE_NULL; | ||||||
|  |  | ||||||
| 	val->type = QSE_XLI_STR; | 	val->type = QSE_XLI_STR; | ||||||
|  |  | ||||||
|  | 	qse_strncpy ((qse_char_t*)(val + 1), value->ptr, value->len); | ||||||
| 	val->ptr = (const qse_char_t*)(val + 1); | 	val->ptr = (const qse_char_t*)(val + 1); | ||||||
| 	val->len = vlen; | 	val->len = value->len; | ||||||
| 	val->verbatim = verbatim; |  | ||||||
| 	tmp = qse_xli_insertpair (xli, parent, peer, key, name, (qse_xli_val_t*)val);	 | 	tmp = qse_xli_insertpair (xli, parent, peer, key, name, (qse_xli_val_t*)val);	 | ||||||
| 	if (tmp == QSE_NULL) qse_xli_freemem (xli, val); | 	if (tmp == QSE_NULL) qse_xli_freemem (xli, val); | ||||||
| 	return tmp; | 	return tmp; | ||||||
| @ -275,7 +298,6 @@ qse_xli_text_t* qse_xli_inserttext ( | |||||||
|  |  | ||||||
| 	text->type = QSE_XLI_TEXT; | 	text->type = QSE_XLI_TEXT; | ||||||
| 	text->ptr = (const qse_char_t*)(text + 1); | 	text->ptr = (const qse_char_t*)(text + 1); | ||||||
| 	text->len = slen; |  | ||||||
|  |  | ||||||
| 	insert_atom (xli, parent, peer, (qse_xli_atom_t*)text); | 	insert_atom (xli, parent, peer, (qse_xli_atom_t*)text); | ||||||
|  |  | ||||||
| @ -292,10 +314,13 @@ static void free_atom (qse_xli_t* xli, qse_xli_atom_t* atom) | |||||||
| 	{ | 	{ | ||||||
| 		qse_xli_pair_t* pair = (qse_xli_pair_t*)atom; | 		qse_xli_pair_t* pair = (qse_xli_pair_t*)atom; | ||||||
|  |  | ||||||
| 		if (pair->val->type == QSE_XLI_LIST) | 		if (pair->val != &xli->xnil) | ||||||
| 			free_list (xli, (qse_xli_list_t*)pair->val); | 		{ | ||||||
|  | 			if (pair->val->type == QSE_XLI_LIST) | ||||||
|  | 				free_list (xli, (qse_xli_list_t*)pair->val); | ||||||
|  |  | ||||||
| 		QSE_MMGR_FREE (xli->mmgr, pair->val); | 			QSE_MMGR_FREE (xli->mmgr, pair->val); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	QSE_MMGR_FREE (xli->mmgr, atom); | 	QSE_MMGR_FREE (xli->mmgr, atom); | ||||||
| @ -319,6 +344,186 @@ static void free_list (qse_xli_t* xli, qse_xli_list_t* list) | |||||||
|  |  | ||||||
| void qse_xli_clear (qse_xli_t* xli) | void qse_xli_clear (qse_xli_t* xli) | ||||||
| { | { | ||||||
| 	/* TODO: free data under xli->root */ |  | ||||||
| 	free_list (xli, &xli->root); | 	free_list (xli, &xli->root); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static qse_xli_pair_t* find_pair_byname ( | ||||||
|  | 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||||
|  | 	const qse_cstr_t* key, const qse_cstr_t* name) | ||||||
|  | { | ||||||
|  | 	qse_xli_atom_t* p; | ||||||
|  |  | ||||||
|  | 	/* TODO: speed up. no linear search */ | ||||||
|  | 	p = list->head; | ||||||
|  | 	while (p) | ||||||
|  | 	{ | ||||||
|  | 		if (p->type == QSE_XLI_PAIR) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_pair_t* pair = (qse_xli_pair_t*)p; | ||||||
|  | 			if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)  | ||||||
|  | 			{ | ||||||
|  | 				if (name == QSE_NULL ||  | ||||||
|  | 				    qse_strxcmp (name->ptr, name->len, pair->name) == 0) return pair; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		p = p->next; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return QSE_NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static qse_xli_pair_t* find_pair_byindex ( | ||||||
|  | 	qse_xli_t* xli, const qse_xli_list_t* list,  | ||||||
|  | 	const qse_cstr_t* key, qse_size_t index) | ||||||
|  | { | ||||||
|  | 	qse_xli_atom_t* p; | ||||||
|  | 	qse_size_t count = 0; | ||||||
|  |  | ||||||
|  | 	/* TODO: speed up. no linear search */ | ||||||
|  | 	p = list->head; | ||||||
|  | 	while (p) | ||||||
|  | 	{ | ||||||
|  | 		if (p->type == QSE_XLI_PAIR) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_pair_t* pair = (qse_xli_pair_t*)p; | ||||||
|  | 			if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)  | ||||||
|  | 			{ | ||||||
|  | 				if (index == count) return pair; | ||||||
|  | 				count++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		p = p->next; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return QSE_NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | qse_xli_pair_t* qse_xli_findpairbyname ( | ||||||
|  | 	qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name) | ||||||
|  | { | ||||||
|  | 	const qse_char_t* ptr; | ||||||
|  | 	qse_cstr_t seg; | ||||||
|  | 	qse_xli_list_t* curlist; | ||||||
|  | 	qse_xli_pair_t* pair; | ||||||
|  |  | ||||||
|  | 	curlist = list? list: &xli->root; | ||||||
|  |  | ||||||
|  | 	ptr = name; | ||||||
|  | 	while (1) | ||||||
|  | 	{ | ||||||
|  | 		seg.ptr = ptr; | ||||||
|  | 		while (*ptr != QSE_T('\0') &&  | ||||||
|  | 		       *ptr != QSE_T('.') &&  | ||||||
|  | 		       *ptr != QSE_T('[')) ptr++; | ||||||
|  | 		if (ptr == seg.ptr) goto inval; | ||||||
|  | 		seg.len = ptr - seg.ptr; | ||||||
|  |  | ||||||
|  | 		if (curlist->type != QSE_XLI_LIST)  | ||||||
|  | 		{ | ||||||
|  | 			/* check the type of curlist. this check is needed | ||||||
|  | 			 * because of the unconditional switching at the bottom of the  | ||||||
|  | 			 * this loop. this implementation strategy has been chosen | ||||||
|  | 			 * to provide the segment name easily. */ | ||||||
|  | 			goto noent; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (*ptr == QSE_T('[')) | ||||||
|  | 		{ | ||||||
|  | 			/*  index is specified */ | ||||||
|  | 			ptr++; | ||||||
|  |  | ||||||
|  | 			if (QSE_ISDIGIT(*ptr)) | ||||||
|  | 			{ | ||||||
|  | 				/* numeric index */ | ||||||
|  | 				qse_size_t index = 0, count = 0; | ||||||
|  | 				do  | ||||||
|  | 				{ | ||||||
|  | 					index = index * 10 + (*ptr++ - QSE_T('0'));  | ||||||
|  | 					count++; | ||||||
|  | 				} | ||||||
|  | 				while (QSE_ISDIGIT(*ptr)); | ||||||
|  |  | ||||||
|  | 				if (*ptr != QSE_T(']')) goto inval; | ||||||
|  |  | ||||||
|  | 				pair = find_pair_byindex (xli, curlist, &seg, index); | ||||||
|  | 				if (pair == QSE_NULL)  | ||||||
|  | 				{ | ||||||
|  | 					seg.len += count + 2; /* adjustment for error message */ | ||||||
|  | 					goto noent; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else if (QSE_ISALPHA(*ptr)) | ||||||
|  | 			{ | ||||||
|  | 				/* word index */ | ||||||
|  | 				qse_cstr_t idx; | ||||||
|  |  | ||||||
|  | 				idx.ptr = ptr; | ||||||
|  | 				do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-')); | ||||||
|  | 				idx.len = ptr - idx.ptr; | ||||||
|  | 	 | ||||||
|  | 				if (*ptr != QSE_T(']')) goto inval; | ||||||
|  |  | ||||||
|  | 				pair = find_pair_byname (xli, curlist, &seg, &idx); | ||||||
|  | 				if (pair == QSE_NULL)  | ||||||
|  | 				{ | ||||||
|  | 					seg.len += idx.len + 2; /* adjustment for error message */ | ||||||
|  | 					goto noent; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"')) | ||||||
|  | 			{ | ||||||
|  | 				qse_cstr_t idx; | ||||||
|  | 				qse_char_t cc = *ptr++; | ||||||
|  |  | ||||||
|  | 				idx.ptr = ptr; | ||||||
|  | 				do ptr++; while (*ptr != cc && *ptr != QSE_T('\0')); | ||||||
|  | 				idx.len = ptr - idx.ptr; | ||||||
|  | 		 | ||||||
|  | 				if (*ptr != cc) goto inval; | ||||||
|  | 				if (*++ptr != QSE_T(']')) goto inval; | ||||||
|  |  | ||||||
|  | 				pair = find_pair_byname (xli, curlist, &seg, &idx); | ||||||
|  | 				if (pair == QSE_NULL)  | ||||||
|  | 				{ | ||||||
|  | 					seg.len += idx.len + 4; /* adjustment for error message */ | ||||||
|  | 					goto noent; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else goto inval; | ||||||
|  |  | ||||||
|  | 			ptr++;  /* skip ] */ | ||||||
|  |  | ||||||
|  | 			if (*ptr == QSE_T('\0')) break; /* no more segments */ | ||||||
|  | 			else if (*ptr != QSE_T('.')) goto inval; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			pair = find_pair_byname (xli, curlist, &seg, QSE_NULL); | ||||||
|  | 			if (pair == QSE_NULL) goto noent; | ||||||
|  |  | ||||||
|  | 			if (*ptr == QSE_T('\0')) break; /* no more segments */ | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		/* more segments to handle */ | ||||||
|  | 		QSE_ASSERT (*ptr == QSE_T('.')); | ||||||
|  | 		ptr++; | ||||||
|  |  | ||||||
|  | 		/* switch to the value regardless of its type. | ||||||
|  | 		 * check if it is a list in the beginning of the loop | ||||||
|  | 		 * just after having gotten the next segment name */ | ||||||
|  | 		curlist = (qse_xli_list_t*)pair->val; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return pair; | ||||||
|  |  | ||||||
|  | inval: | ||||||
|  | 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||||
|  | 	return QSE_NULL; | ||||||
|  |  | ||||||
|  | noent: | ||||||
|  | 	qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &seg); | ||||||
|  | 	return QSE_NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -52,12 +52,14 @@ struct qse_xli_t | |||||||
| 	qse_xli_ecb_t* ecb; | 	qse_xli_ecb_t* ecb; | ||||||
|  |  | ||||||
| 	qse_xli_list_t root; | 	qse_xli_list_t root; | ||||||
|  | 	qse_xli_nil_t xnil; | ||||||
|  |  | ||||||
|  | 	qse_str_t* tmp[1]; | ||||||
| 	qse_xli_tok_t tok; | 	qse_xli_tok_t tok; | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_io_impl_t inf; /* input handler */ | 		qse_xli_io_impl_t inf; /* input handler */ | ||||||
| 		qse_xli_io_lxc_t last;	 | 		qse_xli_io_lxc_t  last;	 | ||||||
| 		qse_xli_io_arg_t  arg; /* for top level */ | 		qse_xli_io_arg_t  arg; /* for top level */ | ||||||
| 		qse_xli_io_arg_t* inp; /* current */ | 		qse_xli_io_arg_t* inp; /* current */ | ||||||
| 	} sio; | 	} sio; | ||||||
|  | |||||||
| @ -7,8 +7,8 @@ AM_CPPFLAGS = \ | |||||||
| 	 | 	 | ||||||
| bin_PROGRAMS = httpd01 httpd02 upxd01 | bin_PROGRAMS = httpd01 httpd02 upxd01 | ||||||
| 
 | 
 | ||||||
| LDFLAGS += -L../../lib/cmn -L../../lib/net  | LDFLAGS += -L../../lib/cmn -L../../lib/http  | ||||||
| LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) | LDADD = -lqsehttp -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) | ||||||
| 
 | 
 | ||||||
| if WIN32  | if WIN32  | ||||||
| if WCHAR | if WCHAR | ||||||
| @ -36,7 +36,7 @@ build_triplet = @build@ | |||||||
| host_triplet = @host@ | host_triplet = @host@ | ||||||
| bin_PROGRAMS = httpd01$(EXEEXT) httpd02$(EXEEXT) upxd01$(EXEEXT) | bin_PROGRAMS = httpd01$(EXEEXT) httpd02$(EXEEXT) upxd01$(EXEEXT) | ||||||
| @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) | @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) | ||||||
| subdir = samples/net | subdir = samples/http | ||||||
| DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | ||||||
| ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||||||
| am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
 | ||||||
| @ -144,7 +144,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |||||||
| INSTALL_SCRIPT = @INSTALL_SCRIPT@ | INSTALL_SCRIPT = @INSTALL_SCRIPT@ | ||||||
| INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | ||||||
| LD = @LD@ | LD = @LD@ | ||||||
| LDFLAGS = @LDFLAGS@ -L../../lib/cmn -L../../lib/net | LDFLAGS = @LDFLAGS@ -L../../lib/cmn -L../../lib/http | ||||||
| LIBADD_DL = @LIBADD_DL@ | LIBADD_DL = @LIBADD_DL@ | ||||||
| LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ | LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ | ||||||
| LIBADD_DLOPEN = @LIBADD_DLOPEN@ | LIBADD_DLOPEN = @LIBADD_DLOPEN@ | ||||||
| @ -282,7 +282,7 @@ AM_CPPFLAGS = \ | |||||||
| 	-I$(top_srcdir)/include \
 | 	-I$(top_srcdir)/include \
 | ||||||
| 	-I$(includedir)  | 	-I$(includedir)  | ||||||
| 
 | 
 | ||||||
| LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
 | LDADD = -lqsehttp -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
 | ||||||
| 	$(SENDFILE_LIBS) $(am__append_1) | 	$(SENDFILE_LIBS) $(am__append_1) | ||||||
| httpd01_SOURCES = httpd01.c | httpd01_SOURCES = httpd01.c | ||||||
| httpd02_SOURCES = httpd02.c | httpd02_SOURCES = httpd02.c | ||||||
| @ -302,9 +302,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps) | |||||||
| 	      exit 1;; \
 | 	      exit 1;; \
 | ||||||
| 	  esac; \
 | 	  esac; \
 | ||||||
| 	done; \
 | 	done; \
 | ||||||
| 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/net/Makefile'; \
 | 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/http/Makefile'; \
 | ||||||
| 	$(am__cd) $(top_srcdir) && \
 | 	$(am__cd) $(top_srcdir) && \
 | ||||||
| 	  $(AUTOMAKE) --foreign samples/net/Makefile | 	  $(AUTOMAKE) --foreign samples/http/Makefile | ||||||
| .PRECIOUS: Makefile | .PRECIOUS: Makefile | ||||||
| Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||||||
| 	@case '$?' in \
 | 	@case '$?' in \
 | ||||||
| @ -1,5 +1,5 @@ | |||||||
| 
 | 
 | ||||||
| #include <qse/net/httpd.h> | #include <qse/http/httpd.h> | ||||||
| #include <qse/cmn/stdio.h> | #include <qse/cmn/stdio.h> | ||||||
| #include <qse/cmn/main.h> | #include <qse/cmn/main.h> | ||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| 
 | 
 | ||||||
| #include <qse/net/httpd.h> | #include <qse/http/httpd.h> | ||||||
| #include <qse/cmn/stdio.h> | #include <qse/cmn/stdio.h> | ||||||
| #include <qse/cmn/main.h> | #include <qse/cmn/main.h> | ||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
| @ -1,4 +1,4 @@ | |||||||
| #include <qse/net/upxd.h> | #include <qse/http/upxd.h> | ||||||
| #include <qse/cmn/stdio.h> | #include <qse/cmn/stdio.h> | ||||||
| #include <qse/cmn/main.h> | #include <qse/cmn/main.h> | ||||||
| #include <qse/cmn/str.h> | #include <qse/cmn/str.h> | ||||||
		Reference in New Issue
	
	Block a user