From 5bc774db3ab29a6094fd4b01c00e3b319e4cf124 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 18 Feb 2013 13:45:50 +0000 Subject: [PATCH] revising httpd --- qse/cmd/Makefile.am | 2 +- qse/cmd/Makefile.in | 2 +- qse/cmd/{net => http}/Makefile.am | 4 +- qse/cmd/{net => http}/Makefile.in | 10 +- qse/cmd/http/httpd.c | 555 ++++++++++++++++ qse/cmd/http/httpd.conf | 44 ++ qse/cmd/net/httpd.c | 296 --------- qse/cmd/xli/xli.c | 46 +- qse/configure | 10 +- qse/configure.ac | 8 +- qse/include/qse/Makefile.am | 2 +- qse/include/qse/Makefile.in | 2 +- qse/include/qse/cmn/uri.h | 43 +- qse/include/qse/http/Makefile.am | 4 + qse/include/qse/{net => http}/Makefile.in | 10 +- qse/include/qse/{net => http}/htrd.h | 8 +- qse/include/qse/{net => http}/htre.h | 6 +- qse/include/qse/{net => http}/http.h | 4 +- qse/include/qse/{net => http}/httpd.h | 168 ++--- qse/include/qse/{net => http}/upxd.h | 4 +- qse/include/qse/net/Makefile.am | 4 - qse/include/qse/xli/std.h | 137 ++++ qse/include/qse/xli/xli.h | 47 +- qse/lib/Makefile.am | 2 +- qse/lib/Makefile.in | 2 +- qse/lib/awk/err.c | 2 +- qse/lib/awk/parse.c | 4 +- qse/lib/cmn/main.c | 1 + qse/lib/cmn/uri.c | 8 +- qse/lib/{net => http}/Makefile.am | 8 +- qse/lib/{net => http}/Makefile.in | 32 +- qse/lib/{net => http}/htrd.c | 2 +- qse/lib/{net => http}/htre.c | 2 +- qse/lib/{net => http}/http.c | 2 +- qse/lib/{net => http}/httpd-cgi.c | 9 +- qse/lib/{net => http}/httpd-dir.c | 0 qse/lib/{net => http}/httpd-file.c | 0 qse/lib/{net => http}/httpd-proxy.c | 0 qse/lib/{net => http}/httpd-resol.c | 0 qse/lib/{net => http}/httpd-std.c | 741 ++++++++++++---------- qse/lib/{net => http}/httpd-task.c | 0 qse/lib/{net => http}/httpd-text.c | 0 qse/lib/{net => http}/httpd.c | 113 +++- qse/lib/{net => http}/httpd.h | 9 +- qse/lib/{net => http}/upxd.c | 0 qse/lib/{net => http}/upxd.h | 2 +- qse/lib/xli/err.c | 8 +- qse/lib/xli/read.c | 109 ++-- qse/lib/xli/write.c | 4 +- qse/lib/xli/xli.c | 227 ++++++- qse/lib/xli/xli.h | 4 +- qse/samples/{net => http}/Makefile.am | 4 +- qse/samples/{net => http}/Makefile.in | 10 +- qse/samples/{net => http}/httpd01.c | 2 +- qse/samples/{net => http}/httpd02.c | 2 +- qse/samples/{net => http}/upxd01.c | 2 +- 56 files changed, 1774 insertions(+), 953 deletions(-) rename qse/cmd/{net => http}/Makefile.am (65%) rename qse/cmd/{net => http}/Makefile.in (98%) create mode 100644 qse/cmd/http/httpd.c create mode 100644 qse/cmd/http/httpd.conf delete mode 100644 qse/cmd/net/httpd.c create mode 100644 qse/include/qse/http/Makefile.am rename qse/include/qse/{net => http}/Makefile.in (98%) rename qse/include/qse/{net => http}/htrd.h (97%) rename qse/include/qse/{net => http}/htre.h (98%) rename qse/include/qse/{net => http}/http.h (98%) rename qse/include/qse/{net => http}/httpd.h (84%) rename qse/include/qse/{net => http}/upxd.h (98%) delete mode 100644 qse/include/qse/net/Makefile.am create mode 100644 qse/include/qse/xli/std.h rename qse/lib/{net => http}/Makefile.am (59%) rename qse/lib/{net => http}/Makefile.in (95%) rename qse/lib/{net => http}/htrd.c (99%) rename qse/lib/{net => http}/htre.c (99%) rename qse/lib/{net => http}/http.c (99%) rename qse/lib/{net => http}/httpd-cgi.c (99%) rename qse/lib/{net => http}/httpd-dir.c (100%) rename qse/lib/{net => http}/httpd-file.c (100%) rename qse/lib/{net => http}/httpd-proxy.c (100%) rename qse/lib/{net => http}/httpd-resol.c (100%) rename qse/lib/{net => http}/httpd-std.c (81%) rename qse/lib/{net => http}/httpd-task.c (100%) rename qse/lib/{net => http}/httpd-text.c (100%) rename qse/lib/{net => http}/httpd.c (91%) rename qse/lib/{net => http}/httpd.h (96%) rename qse/lib/{net => http}/upxd.c (100%) rename qse/lib/{net => http}/upxd.h (98%) rename qse/samples/{net => http}/Makefile.am (75%) rename qse/samples/{net => http}/Makefile.in (98%) rename qse/samples/{net => http}/httpd01.c (99%) rename qse/samples/{net => http}/httpd02.c (99%) rename qse/samples/{net => http}/upxd01.c (99%) diff --git a/qse/cmd/Makefile.am b/qse/cmd/Makefile.am index 4ab3fa4d..f3bb05fa 100644 --- a/qse/cmd/Makefile.am +++ b/qse/cmd/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = awk sed xli net +SUBDIRS = awk sed xli http DIST_SUBDIRS = $(SUBDIRS) diff --git a/qse/cmd/Makefile.in b/qse/cmd/Makefile.in index 8ab5ee9a..65dcd734 100644 --- a/qse/cmd/Makefile.in +++ b/qse/cmd/Makefile.in @@ -270,7 +270,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = awk sed xli net +SUBDIRS = awk sed xli http DIST_SUBDIRS = $(SUBDIRS) all: all-recursive diff --git a/qse/cmd/net/Makefile.am b/qse/cmd/http/Makefile.am similarity index 65% rename from qse/cmd/net/Makefile.am rename to qse/cmd/http/Makefile.am index 93d45254..a5fe26a3 100644 --- a/qse/cmd/net/Makefile.am +++ b/qse/cmd/http/Makefile.am @@ -8,8 +8,8 @@ AM_CPPFLAGS = \ bin_PROGRAMS = qsehttpd qsehttpd_SOURCES = httpd.c -qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir) -qsehttpd_LDADD = -lqsenet -lqsecmn +qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir) +qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn if WIN32 if WCHAR diff --git a/qse/cmd/net/Makefile.in b/qse/cmd/http/Makefile.in similarity index 98% rename from qse/cmd/net/Makefile.in rename to qse/cmd/http/Makefile.in index 3090634e..6247462a 100644 --- a/qse/cmd/net/Makefile.in +++ b/qse/cmd/http/Makefile.in @@ -36,7 +36,7 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = qsehttpd$(EXEEXT) @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) -subdir = cmd/net +subdir = cmd/http DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \ @@ -276,8 +276,8 @@ AM_CPPFLAGS = \ -I$(includedir) qsehttpd_SOURCES = httpd.c -qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir) -qsehttpd_LDADD = -lqsenet -lqsecmn $(am__append_1) +qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir) +qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn $(am__append_1) all: all-am .SUFFIXES: @@ -291,9 +291,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/net/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/http/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign cmd/net/Makefile + $(AUTOMAKE) --foreign cmd/http/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c new file mode 100644 index 00000000..cf1ce252 --- /dev/null +++ b/qse/cmd/http/httpd.c @@ -0,0 +1,555 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(_WIN32) +# include +# include +# include +# include +#elif defined(__OS2__) +# define INCL_DOSPROCESS +# define INCL_DOSEXCEPTIONS +# define INCL_ERRORS +# include +#elif defined(__DOS__) +# include +#else +# include +# include +#endif + +#if defined(HAVE_SSL) +# include +# include +# include +#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; +} + diff --git a/qse/cmd/http/httpd.conf b/qse/cmd/http/httpd.conf new file mode 100644 index 00000000..9ac4d0a3 --- /dev/null +++ b/qse/cmd/http/httpd.conf @@ -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"; + } + } +} diff --git a/qse/cmd/net/httpd.c b/qse/cmd/net/httpd.c deleted file mode 100644 index 5ed04388..00000000 --- a/qse/cmd/net/httpd.c +++ /dev/null @@ -1,296 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(_WIN32) -# include -# include -# include -# include -#elif defined(__OS2__) -# define INCL_DOSPROCESS -# define INCL_DOSEXCEPTIONS -# define INCL_ERRORS -# include -#elif defined(__DOS__) -# include -#else -# include -# include -#endif - - -#if defined(HAVE_SSL) -# include -# include -# include -#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("")); - - qse_httpd_setserveroptstd ( - httpd, server, QSE_HTTPD_SERVER_ERRCSS, - QSE_MT("")); - - 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 ...\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; -} - diff --git a/qse/cmd/xli/xli.c b/qse/cmd/xli/xli.c index 7465d677..23df68a6 100644 --- a/qse/cmd/xli/xli.c +++ b/qse/cmd/xli/xli.c @@ -52,6 +52,7 @@ static qse_char_t* g_input_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 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]); - 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(" -h/--help show this message\n")); @@ -201,7 +202,7 @@ static int handle_args (int argc, qse_char_t* argv[]) break; case QSE_T('n'): - g_trait |= QSE_XLI_NAMEDKEY; + g_trait |= QSE_XLI_KEYNAME; break; case QSE_T('m'): @@ -251,6 +252,14 @@ static int handle_args (int argc, qse_char_t* argv[]) 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; oops: @@ -287,7 +296,6 @@ static int xli_main (int argc, qse_char_t* argv[]) { qse_mmgr_t* mmgr = QSE_MMGR_GETDFL(); qse_xli_t* xli = QSE_NULL; - qse_fs_t* fs = QSE_NULL; qse_xli_iostd_t in, out; int ret = -1; @@ -361,11 +369,41 @@ static int xli_main (int argc, qse_char_t* argv[]) 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; oops: if (xli) qse_xli_close (xli); - if (fs) qse_fs_close (fs); if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx); #if defined(QSE_BUILD_DEBUG) diff --git a/qse/configure b/qse/configure index 05febbaf..ecee4753 100755 --- a/qse/configure +++ b/qse/configure @@ -20893,7 +20893,7 @@ QSE_PROJECT_AUTHOR="${PACKAGE_BUGREPORT}" 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 # 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/sed/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/sed/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/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cmn/Makefile" ;; "lib/awk/Makefile") CONFIG_FILES="$CONFIG_FILES lib/awk/Makefile" ;; "lib/sed/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sed/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/awk/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/awk/Makefile" ;; "cmd/sed/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/sed/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/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES samples/cmn/Makefile" ;; "samples/awk/Makefile") CONFIG_FILES="$CONFIG_FILES samples/awk/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/awk/Makefile") CONFIG_FILES="$CONFIG_FILES regress/awk/Makefile" ;; "regress/awk/regress.sh") CONFIG_FILES="$CONFIG_FILES regress/awk/regress.sh" ;; diff --git a/qse/configure.ac b/qse/configure.ac index 66f35b08..0daa8f45 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -529,23 +529,23 @@ AC_CONFIG_FILES([ include/qse/awk/Makefile include/qse/sed/Makefile include/qse/xli/Makefile - include/qse/net/Makefile + include/qse/http/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/sed/Makefile lib/xli/Makefile - lib/net/Makefile + lib/http/Makefile cmd/Makefile cmd/awk/Makefile cmd/sed/Makefile cmd/xli/Makefile - cmd/net/Makefile + cmd/http/Makefile samples/Makefile samples/cmn/Makefile samples/awk/Makefile samples/sed/Makefile - samples/net/Makefile + samples/http/Makefile regress/Makefile regress/awk/Makefile regress/awk/regress.sh diff --git a/qse/include/qse/Makefile.am b/qse/include/qse/Makefile.am index 6704f320..40a3c4ab 100644 --- a/qse/include/qse/Makefile.am +++ b/qse/include/qse/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = cmn awk sed net +SUBDIRS = cmn awk sed http pkgincludedir = $(includedir)/qse diff --git a/qse/include/qse/Makefile.in b/qse/include/qse/Makefile.in index b7bdf29e..205f528e 100644 --- a/qse/include/qse/Makefile.in +++ b/qse/include/qse/Makefile.in @@ -306,7 +306,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ 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 \ conf-mac.h conf-inf.h types.h macros.h pack1.h unpack.h \ $(am__append_1) diff --git a/qse/include/qse/cmn/uri.h b/qse/include/qse/cmn/uri.h index 9990b5af..415a7574 100644 --- a/qse/include/qse/cmn/uri.h +++ b/qse/include/qse/cmn/uri.h @@ -24,22 +24,37 @@ #include #include +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_uri_t +struct qse_muri_t { - qse_cptl_t scheme; + qse_mcstr_t scheme; struct { - qse_cptl_t user; - qse_cptl_t pass; + qse_mcstr_t user; + qse_mcstr_t pass; } auth; - qse_cptl_t host; - qse_cptl_t port; - qse_cptl_t path; - qse_cptl_t query; - qse_cptl_t frag; + qse_mcstr_t host; + qse_mcstr_t port; + qse_mcstr_t path; + qse_mcstr_t query; + 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 @@ -60,10 +75,12 @@ enum qse_wcstouri_flag_t # define QSE_STRTOURI_NOAUTH QSE_MBSTOURI_NOAUTH # define QSE_STRTOURI_NOQUERY QSE_MBSTOURI_NOQUERY # define QSE_STRTOURI_NOFRAG QSE_MBSTOURI_NOFRAG + typedef qse_muri_t qse_uri_t; #else # define QSE_STRTOURI_NOAUTH QSE_WCSTOURI_NOAUTH # define QSE_STRTOURI_NOQUERY QSE_WCSTOURI_NOQUERY # define QSE_STRTOURI_NOFRAG QSE_WCSTOURI_NOFRAG + typedef qse_wuri_t qse_uri_t; #endif #ifdef __cplusplus @@ -72,13 +89,13 @@ extern "C" { QSE_EXPORT int qse_mbstouri ( const qse_mchar_t* str, - qse_uri_t* uri, + qse_muri_t* uri, int flags ); QSE_EXPORT int qse_wcstouri ( const qse_wchar_t* str, - qse_uri_t* uri, + qse_wuri_t* uri, int flags ); diff --git a/qse/include/qse/http/Makefile.am b/qse/include/qse/http/Makefile.am new file mode 100644 index 00000000..ca518541 --- /dev/null +++ b/qse/include/qse/http/Makefile.am @@ -0,0 +1,4 @@ +pkgincludedir= $(includedir)/qse/http +pkginclude_HEADERS = http.h htre.h htrd.h httpd.h std.h upxd.h + + diff --git a/qse/include/qse/net/Makefile.in b/qse/include/qse/http/Makefile.in similarity index 98% rename from qse/include/qse/net/Makefile.in rename to qse/include/qse/http/Makefile.in index 654f9539..4d79aeb2 100644 --- a/qse/include/qse/net/Makefile.in +++ b/qse/include/qse/http/Makefile.in @@ -33,7 +33,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = include/qse/net +subdir = include/qse/http DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -89,7 +89,7 @@ HEADERS = $(pkginclude_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -pkgincludedir = $(includedir)/qse/net +pkgincludedir = $(includedir)/qse/http ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ @@ -264,7 +264,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ 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 .SUFFIXES: @@ -277,9 +277,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ 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) && \ - $(AUTOMAKE) --foreign include/qse/net/Makefile + $(AUTOMAKE) --foreign include/qse/http/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/qse/include/qse/net/htrd.h b/qse/include/qse/http/htrd.h similarity index 97% rename from qse/include/qse/net/htrd.h rename to qse/include/qse/http/htrd.h index cb9d7032..173e5cb8 100644 --- a/qse/include/qse/net/htrd.h +++ b/qse/include/qse/http/htrd.h @@ -18,11 +18,11 @@ License along with QSE. If not, see . */ -#ifndef _QSE_NET_HTRD_H_ -#define _QSE_NET_HTRD_H_ +#ifndef _QSE_HTTP_HTRD_H_ +#define _QSE_HTTP_HTRD_H_ -#include -#include +#include +#include typedef struct qse_htrd_t qse_htrd_t; diff --git a/qse/include/qse/net/htre.h b/qse/include/qse/http/htre.h similarity index 98% rename from qse/include/qse/net/htre.h rename to qse/include/qse/http/htre.h index 38062f26..39448a3f 100644 --- a/qse/include/qse/net/htre.h +++ b/qse/include/qse/http/htre.h @@ -18,10 +18,10 @@ License along with QSE. If not, see . */ -#ifndef _QSE_NET_HTRE_H_ -#define _QSE_NET_HTRE_H_ +#ifndef _QSE_HTTP_HTRE_H_ +#define _QSE_HTTP_HTRE_H_ -#include +#include #include #include diff --git a/qse/include/qse/net/http.h b/qse/include/qse/http/http.h similarity index 98% rename from qse/include/qse/net/http.h rename to qse/include/qse/http/http.h index 764904c0..bc9ea095 100644 --- a/qse/include/qse/net/http.h +++ b/qse/include/qse/http/http.h @@ -18,8 +18,8 @@ License along with QSE. If not, see . */ -#ifndef _QSE_NET_HTTP_H_ -#define _QSE_NET_HTTP_H_ +#ifndef _QSE_HTTP_HTTP_H_ +#define _QSE_HTTP_HTTP_H_ /** @file * This file provides basic data types and functions for the http protocol. diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/http/httpd.h similarity index 84% rename from qse/include/qse/net/httpd.h rename to qse/include/qse/http/httpd.h index 927ee2a8..8c6c0134 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -18,17 +18,18 @@ License along with QSE. If not, see . */ -#ifndef _QSE_NET_HTTPD_H_ -#define _QSE_NET_HTTPD_H_ +#ifndef _QSE_HTTP_HTTPD_H_ +#define _QSE_HTTP_HTTPD_H_ #include #include -#include -#include +#include +#include #include #include 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_client_t qse_httpd_client_t; @@ -300,17 +301,28 @@ struct qse_httpd_task_t qse_httpd_task_t* next; }; -enum qse_httpd_sctype_t +enum qse_httpd_mate_type_t { QSE_HTTPD_SERVER, 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 { /* == PRIVATE == */ - qse_httpd_sctype_t type; + QSE_HTTPD_MATE_HDR; /* == PUBLIC == */ qse_ubi_t handle; @@ -352,22 +364,36 @@ typedef void (*qse_httpd_server_predetach_t) ( qse_httpd_server_t* server ); -struct qse_httpd_server_t -{ - qse_httpd_sctype_t type; +typedef void (*qse_httpd_server_reconfig_t) ( + qse_httpd_t* httpd, + qse_httpd_server_t* server +); - /* ---------------------------------------------- */ - int flags; +typedef struct qse_httpd_server_dope_t qse_httpd_server_dope_t; + +struct qse_httpd_server_dope_t +{ + int flags; /* bitwise-ORed of qse_httpd_server_flag_t */ qse_nwad_t nwad; /* binding address */ 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 */ qse_ubi_t handle; /* private */ - qse_httpd_server_predetach_t predetach; - qse_httpd_server_t* next; - qse_httpd_server_t* prev; + qse_httpd_server_t* next; + qse_httpd_server_t* prev; }; /* -------------------------------------------------------------------------- */ @@ -480,54 +506,6 @@ struct qse_httpd_ecb_t 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 extern "C" { #endif @@ -610,13 +588,16 @@ QSE_EXPORT void qse_httpd_stop ( qse_httpd_t* httpd ); +QSE_EXPORT void qse_httpd_reconfig ( + qse_httpd_t* httpd +); + #define qse_httpd_getserverxtn(httpd,server) ((void*)(server+1)) QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserver ( - qse_httpd_t* httpd, - const qse_httpd_server_t* tmpl, - qse_httpd_server_predetach_t predetach, - qse_size_t xtnsize + qse_httpd_t* httpd, + const qse_httpd_server_dope_t* dope, + qse_size_t xtnsize ); QSE_EXPORT void qse_httpd_detachserver ( @@ -804,6 +785,11 @@ QSE_EXPORT void* qse_httpd_allocmem ( 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_httpd_t* httpd, void* ptr, @@ -815,53 +801,17 @@ QSE_EXPORT void qse_httpd_freemem ( void* ptr ); -/* -------------------------------------------- */ - -QSE_EXPORT qse_httpd_t* qse_httpd_openstd ( - qse_size_t xtnsize +QSE_EXPORT qse_mchar_t* qse_httpd_strtombsdup ( + qse_httpd_t* httpd, + const qse_char_t* str ); -QSE_EXPORT qse_httpd_t* qse_httpd_openstdwithmmgr ( - 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_EXPORT qse_mchar_t* qse_httpd_strntombsdup ( qse_httpd_t* httpd, - const qse_ntime_t* tmout + const qse_char_t* str, + qse_size_t len ); - #ifdef __cplusplus } #endif diff --git a/qse/include/qse/net/upxd.h b/qse/include/qse/http/upxd.h similarity index 98% rename from qse/include/qse/net/upxd.h rename to qse/include/qse/http/upxd.h index 63939473..4bc6548e 100644 --- a/qse/include/qse/net/upxd.h +++ b/qse/include/qse/http/upxd.h @@ -18,8 +18,8 @@ License along with QSE. If not, see . */ -#ifndef _QSE_NET_UPXD_H_ -#define _QSE_NET_UPXD_H_ +#ifndef _QSE_HTTP_UPXD_H_ +#define _QSE_HTTP_UPXD_H_ #include #include diff --git a/qse/include/qse/net/Makefile.am b/qse/include/qse/net/Makefile.am deleted file mode 100644 index 48630e4b..00000000 --- a/qse/include/qse/net/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -pkgincludedir= $(includedir)/qse/net -pkginclude_HEADERS = http.h htre.h htrd.h httpd.h upxd.h - - diff --git a/qse/include/qse/xli/std.h b/qse/include/qse/xli/std.h new file mode 100644 index 00000000..314d6052 --- /dev/null +++ b/qse/include/qse/xli/std.h @@ -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 . + */ + +#ifndef _QSE_XLI_STD_H_ +#define _QSE_XLI_STD_H_ + +#include +#include + +/** \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 diff --git a/qse/include/qse/xli/xli.h b/qse/include/qse/xli/xli.h index 9bc18400..ff2e6e9c 100644 --- a/qse/include/qse/xli/xli.h +++ b/qse/include/qse/xli/xli.h @@ -39,10 +39,17 @@ enum qse_xli_errnum_t QSE_XLI_EEXIST, /**< '${0}' already exists */ QSE_XLI_EIOFIL, /**< io error with file '${0}' */ QSE_XLI_EIOUSR, /**< i/o handler error */ + + QSE_XLI_ESYNTAX, /**< syntax error */ QSE_XLI_ESCOLON, /**< semicolon expected in place of '${0}' */ QSE_XLI_ELBREQ, /**< { or = 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; @@ -66,13 +73,14 @@ typedef enum qse_xli_opt_t qse_xli_opt_t; enum qse_xli_trait_t { - QSE_XLI_NAMEDKEY = (1 << 0), - QSE_XLI_NODUPKEY = (1 << 1), + QSE_XLI_KEYNODUP = (1 << 0), + QSE_XLI_KEYNAME = (1 << 1), QSE_XLI_NOTEXT = (1 << 10) }; typedef enum qse_xli_trait_t qse_xli_trait_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_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 { + QSE_XLI_NIL, QSE_XLI_STR, QSE_XLI_LIST, }; @@ -104,6 +113,11 @@ struct qse_xli_val_t QSE_XLI_VAL_HDR; }; +struct qse_xli_nil_t +{ + QSE_XLI_VAL_HDR; +}; + struct qse_xli_list_t { QSE_XLI_VAL_HDR; @@ -114,9 +128,8 @@ struct qse_xli_list_t struct qse_xli_str_t { QSE_XLI_VAL_HDR; - int verbatim; 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 \ @@ -142,7 +155,6 @@ struct qse_xli_text_t { QSE_XLI_ATOM_HDR; const qse_char_t* ptr; - qse_size_t len; }; struct qse_xli_file_t @@ -461,9 +473,18 @@ QSE_EXPORT void qse_xli_freemem ( 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_xli_t* xli, - qse_xli_list_t* parent, + qse_xli_list_t* list, qse_xli_atom_t* peer, const qse_char_t* key, 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_xli_t* xli, - qse_xli_list_t* parent, + qse_xli_list_t* list, qse_xli_atom_t* peer, const qse_char_t* key, const qse_char_t* name, - const qse_char_t* value, - int verbatim + const qse_cstr_t* value +); + + +qse_xli_pair_t* qse_xli_findpairbyname ( + qse_xli_t* xli, + const qse_xli_list_t* list, + const qse_char_t* name ); diff --git a/qse/lib/Makefile.am b/qse/lib/Makefile.am index 5f20c3aa..3ba3d3ec 100644 --- a/qse/lib/Makefile.am +++ b/qse/lib/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = cmn awk sed net +SUBDIRS = cmn awk sed xli http DIST_SUBDIRS = $(SUBDIRS) diff --git a/qse/lib/Makefile.in b/qse/lib/Makefile.in index 03bcdd88..06a1a07f 100644 --- a/qse/lib/Makefile.in +++ b/qse/lib/Makefile.in @@ -270,7 +270,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = cmn awk sed net +SUBDIRS = cmn awk sed xli http DIST_SUBDIRS = $(SUBDIRS) all: all-recursive diff --git a/qse/lib/awk/err.c b/qse/lib/awk/err.c index 8f703432..11d0063c 100644 --- a/qse/lib/awk/err.c +++ b/qse/lib/awk/err.c @@ -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("'@include' not followed by a string"), 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("divide by zero"), diff --git a/qse/lib/awk/parse.c b/qse/lib/awk/parse.c index 5ad7a326..268ac6eb 100644 --- a/qse/lib/awk/parse.c +++ b/qse/lib/awk/parse.c @@ -5512,7 +5512,7 @@ static int get_string ( if (c == QSE_CHAR_EOF) { - SETERR_TOK (awk, QSE_AWK_ESTRNC); + SETERR_LOC (awk, QSE_AWK_ESTRNC, &awk->tok.loc); return -1; } @@ -6072,7 +6072,7 @@ retry: if (c == QSE_CHAR_EOF) { - SETERR_TOK (awk, QSE_AWK_ESTRNC); + SETERR_LOC (awk, QSE_AWK_ESTRNC, &awk->tok.loc); return -1; } diff --git a/qse/lib/cmn/main.c b/qse/lib/cmn/main.c index 98f5001a..b1d54c8d 100644 --- a/qse/lib/cmn/main.c +++ b/qse/lib/cmn/main.c @@ -20,6 +20,7 @@ #include #include + #include "mem.h" int qse_runmain ( diff --git a/qse/lib/cmn/uri.c b/qse/lib/cmn/uri.c index 79175afe..2c0aa2d7 100644 --- a/qse/lib/cmn/uri.c +++ b/qse/lib/cmn/uri.c @@ -21,10 +21,10 @@ #include #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; - qse_uri_t xuri; + qse_muri_t 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; - qse_uri_t xuri; + qse_wuri_t xuri; QSE_MEMSET (&xuri, 0, QSE_SIZEOF(xuri)); diff --git a/qse/lib/net/Makefile.am b/qse/lib/http/Makefile.am similarity index 59% rename from qse/lib/net/Makefile.am rename to qse/lib/http/Makefile.am index 17c1c578..cc8c18b3 100644 --- a/qse/lib/net/Makefile.am +++ b/qse/lib/http/Makefile.am @@ -5,8 +5,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -lib_LTLIBRARIES = libqsenet.la -libqsenet_la_SOURCES = \ +lib_LTLIBRARIES = libqsehttp.la +libqsehttp_la_SOURCES = \ httpd.h \ upxd.h \ http.c \ @@ -23,6 +23,6 @@ libqsenet_la_SOURCES = \ httpd-text.c \ upxd.c -libqsenet_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_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) +libqsehttp_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) diff --git a/qse/lib/net/Makefile.in b/qse/lib/http/Makefile.in similarity index 95% rename from qse/lib/net/Makefile.in rename to qse/lib/http/Makefile.in index c9354939..3a09db21 100644 --- a/qse/lib/net/Makefile.in +++ b/qse/lib/http/Makefile.in @@ -34,7 +34,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = lib/net +subdir = lib/http DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \ @@ -79,19 +79,19 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = -libqsenet_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +libqsehttp_la_DEPENDENCIES = $(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-resol.lo httpd-std.lo httpd-task.lo httpd-text.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_DEFAULT_V@) 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) \ - $(libqsenet_la_LDFLAGS) $(LDFLAGS) -o $@ + $(libqsehttp_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/ac/depcomp 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_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; -SOURCES = $(libqsenet_la_SOURCES) -DIST_SOURCES = $(libqsenet_la_SOURCES) +SOURCES = $(libqsehttp_la_SOURCES) +DIST_SOURCES = $(libqsehttp_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -303,8 +303,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -lib_LTLIBRARIES = libqsenet.la -libqsenet_la_SOURCES = \ +lib_LTLIBRARIES = libqsehttp.la +libqsehttp_la_SOURCES = \ httpd.h \ upxd.h \ http.c \ @@ -321,8 +321,8 @@ libqsenet_la_SOURCES = \ httpd-text.c \ upxd.c -libqsenet_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_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) +libqsehttp_la_LIBADD = -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS) all: all-am .SUFFIXES: @@ -336,9 +336,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/net/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/http/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign lib/net/Makefile + $(AUTOMAKE) --foreign lib/http/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -388,8 +388,8 @@ clean-libLTLIBRARIES: echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done -libqsenet.la: $(libqsenet_la_OBJECTS) $(libqsenet_la_DEPENDENCIES) $(EXTRA_libqsenet_la_DEPENDENCIES) - $(AM_V_CCLD)$(libqsenet_la_LINK) -rpath $(libdir) $(libqsenet_la_OBJECTS) $(libqsenet_la_LIBADD) $(LIBS) +libqsehttp.la: $(libqsehttp_la_OBJECTS) $(libqsehttp_la_DEPENDENCIES) $(EXTRA_libqsehttp_la_DEPENDENCIES) + $(AM_V_CCLD)$(libqsehttp_la_LINK) -rpath $(libdir) $(libqsehttp_la_OBJECTS) $(libqsehttp_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) diff --git a/qse/lib/net/htrd.c b/qse/lib/http/htrd.c similarity index 99% rename from qse/lib/net/htrd.c rename to qse/lib/http/htrd.c index 8daad8c4..e7c7e8b3 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/http/htrd.c @@ -18,7 +18,7 @@ License along with QSE. If not, see . */ -#include +#include #include #include #include "../cmn/mem.h" diff --git a/qse/lib/net/htre.c b/qse/lib/http/htre.c similarity index 99% rename from qse/lib/net/htre.c rename to qse/lib/http/htre.c index b7728e43..be58499c 100644 --- a/qse/lib/net/htre.c +++ b/qse/lib/http/htre.c @@ -18,7 +18,7 @@ License along with QSE. If not, see . */ -#include +#include #include "../cmn/mem.h" static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen) diff --git a/qse/lib/net/http.c b/qse/lib/http/http.c similarity index 99% rename from qse/lib/net/http.c rename to qse/lib/http/http.c index 1f534cd4..06b97358 100644 --- a/qse/lib/net/http.c +++ b/qse/lib/http/http.c @@ -18,7 +18,7 @@ License along with QSE. If not, see . */ -#include +#include #include #include #include diff --git a/qse/lib/net/httpd-cgi.c b/qse/lib/http/httpd-cgi.c similarity index 99% rename from qse/lib/net/httpd-cgi.c rename to qse/lib/http/httpd-cgi.c index 2872d04a..29229ee9 100644 --- a/qse/lib/net/httpd-cgi.c +++ b/qse/lib/http/httpd-cgi.c @@ -446,13 +446,20 @@ static int cgi_add_env ( if (suffix && suffix[0] != QSE_MT('\0')) { const qse_mchar_t* tmp[3]; + qse_mchar_t* tr; tmp[0] = docroot; tmp[1] = suffix; 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_insertmbsa (env, QSE_MT("PATH_TRANSLATED"), tmp); } qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req)); diff --git a/qse/lib/net/httpd-dir.c b/qse/lib/http/httpd-dir.c similarity index 100% rename from qse/lib/net/httpd-dir.c rename to qse/lib/http/httpd-dir.c diff --git a/qse/lib/net/httpd-file.c b/qse/lib/http/httpd-file.c similarity index 100% rename from qse/lib/net/httpd-file.c rename to qse/lib/http/httpd-file.c diff --git a/qse/lib/net/httpd-proxy.c b/qse/lib/http/httpd-proxy.c similarity index 100% rename from qse/lib/net/httpd-proxy.c rename to qse/lib/http/httpd-proxy.c diff --git a/qse/lib/net/httpd-resol.c b/qse/lib/http/httpd-resol.c similarity index 100% rename from qse/lib/net/httpd-resol.c rename to qse/lib/http/httpd-resol.c diff --git a/qse/lib/net/httpd-std.c b/qse/lib/http/httpd-std.c similarity index 81% rename from qse/lib/net/httpd-std.c rename to qse/lib/http/httpd-std.c index c08b296d..34ea0c26 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -18,6 +18,7 @@ License along with QSE. If not, see . */ +#include #include "httpd.h" #include "../cmn/mem.h" #include @@ -90,35 +91,18 @@ #define DEFAULT_PORT 80 #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; 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_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; int addrsize; - addrsize = qse_nwadtoskad (&server->nwad, &addr); + addrsize = qse_nwadtoskad (&server->dope.nwad, &addr); if (addrsize <= -1) { 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)); #endif - if (server->flags & QSE_HTTPD_SERVER_BINDTONWIF) + if (server->dope.flags & QSE_HTTPD_SERVER_BINDTONWIF) { #if defined(SO_BINDTODEVICE) qse_mchar_t tmp[64]; 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) { @@ -815,7 +799,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) { /* TODO: logging */ - client->remote_addr = server->nwad; + client->remote_addr = server->dope.nwad; } 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) { /* TODO: logging */ - client->local_addr = server->nwad; + client->local_addr = server->dope.nwad; } #if defined(SO_ORIGINAL_DST) @@ -1870,7 +1854,7 @@ if (qse_htre_getcontentlen(req) > 0) 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); task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); @@ -1878,8 +1862,8 @@ if (qse_htre_getcontentlen(req) > 0) else { task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req); - if (server_xtn->cfg2.s.cbstd->freersrc) - server_xtn->cfg2.s.cbstd->freersrc (httpd, client, req, &rsrc); + if (server_xtn->freersrc) + server_xtn->freersrc (httpd, client, req, &rsrc); } if (task == QSE_NULL) goto oops; } @@ -1934,8 +1918,8 @@ static int format_err ( server_xtn = qse_httpd_getserverxtn (httpd, client->server); - css = server_xtn->cfg[SERVER_XTN_CFG_ERRCSS]; - if (!css) css = QSE_MT(""); + if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_ERRCSS, &css) <= -1) css = QSE_NULL; + if (css == QSE_NULL) css = QSE_MT(""); msg = qse_httpstatustombs(code); @@ -1972,8 +1956,8 @@ static int format_dir ( const qse_mchar_t* css; int is_root = (qse_mbscmp (qpath, QSE_MT("/")) == 0); - css = server_xtn->cfg[SERVER_XTN_CFG_DIRCSS]; - if (!css) css = QSE_MT(""); + if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_DIRCSS, &css) <= -1) css = QSE_NULL; + if (css == QSE_NULL) css = QSE_MT(""); /* TODO: html escaping of qpath */ n = snprintf (buf, bufsz, @@ -2119,6 +2103,8 @@ static void free_resource ( QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.script); if (target->u.cgi.path != qpath) 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; @@ -2160,85 +2146,141 @@ static qse_mchar_t* merge_paths ( return xpath; } -static int attempt_cgi ( - qse_httpd_t* httpd, const qse_mchar_t* docroot, - qse_mchar_t* xpath, const qse_mchar_t* qpath, const qse_mchar_t* idxfile, - qse_httpd_server_cgistd_t cgistd[], qse_httpd_rsrc_t* target) +static void merge_paths_to_buf ( + qse_httpd_t* httpd, const qse_mchar_t* base, + const qse_mchar_t* path, qse_size_t plen, qse_mchar_t* xpath) { - qse_mchar_t* ext; - qse_mchar_t* script, * suffix; - qse_size_t i; + /* this function merges two path names into a buffer large enough + * to hold the result. it doesn't duplicate the result */ + 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); - if (script == QSE_NULL) return -1; - - 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; + script = merge_paths (httpd, tmp->qpath, tmp->idxfile); + if (script == QSE_NULL) goto oops; } + 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 { - 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 - * /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only. - * 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'))) + slash = qse_mbschr (ptr, QSE_MT('/')); + if (slash) { - if (ext[cgistd[i].len] == QSE_MT('/')) + if (slash > ptr) { - /* it has a path suffix */ - script = qse_mbsxdup (qpath, ext - qpath + cgistd[i].len, httpd->mmgr); - suffix = qse_mbsdup (&ext[cgistd[i].len], httpd->mmgr); - if (script == QSE_NULL || suffix == QSE_NULL) + qse_httpd_stat_t st; + int stx; + + /* 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 (script) QSE_MMGR_FREE (httpd->mmgr, script); - httpd->errnum = QSE_HTTPD_ENOMEM; - return -1; + if (server_xtn->query (httpd, client->server, req, tmp->xpath, QSE_HTTPD_SERVERSTD_CGI, &cgi) >= 0 && cgi.cgi) + { + script = qse_mbsxdup (tmp->qpath, slash - tmp->qpath , httpd->mmgr); + 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 - { - /* it has no path suffix */ - script = qpath; - suffix = QSE_NULL; - } - - 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 = suffix; - target->u.cgi.docroot = docroot; - target->u.cgi.shebang = cgistd[i].shebang; - return 1; + + ptr = slash + 1; + } + else + { + /* no more slash is found. the last segement doesn't have to be checked + * here since it's attempted by the caller. */ + break; } } - } - 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 ( @@ -2246,214 +2288,308 @@ static int make_resource ( qse_htre_t* req, qse_httpd_rsrc_t* target) { server_xtn_t* server_xtn; - const qse_mchar_t* qpath; - const qse_mchar_t* idxfile; - qse_mchar_t* xpath; + struct rsrc_tmp_t tmp; + qse_httpd_stat_t st; - qse_size_t i; 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_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); - if (server_xtn->cfg[SERVER_XTN_CFG_REALM] && - server_xtn->cfg[SERVER_XTN_CFG_AUTH]) + if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1 || + server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 || + 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")); - if (auth) + /* default to the root directory. */ + 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->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM]; + target->u.auth.realm = tmp.realm; return 0; } auth_ok: - idxfile = QSE_NULL; - xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], qpath); - if (xpath == QSE_NULL) return -1; + tmp.xpath = merge_paths (httpd, tmp.docroot, tmp.qpath); + if (tmp.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 (stx <= -1) { /* this OS may fail in stat_file() if the path contains the trailing * separator. it's beause of the way FindFirstFile() or DosQueryPathInfo() - * is ussed in stat_file(). let me work around it here. */ - qse_size_t pl = qse_mbslen(xpath); - if (pl > 1 && xpath[pl - 1] == QSE_MT('/')) + * is used in stat_file(). let me work around it here. */ + qse_size_t pl = qse_mbslen(tmp.xpath); + if (pl > 1 && tmp.xpath[pl - 1] == QSE_MT('/')) { - xpath[pl-1] = QSE_MT('\0'); - stx = stat_file (httpd, xpath, &st, 0); - xpath[pl-1] = QSE_MT('/'); + tmp.xpath[pl-1] = QSE_MT('\0'); + stx = stat_file (httpd, tmp.xpath, &st, 0); + tmp.xpath[pl-1] = QSE_MT('/'); } } #endif - if (stx >= 0 && st.isdir) + + if (stx >= 0) { - /* it is a directory */ - if (server_xtn->cfg2.s.idxstd) - { - /* try to locate an index file */ - for (i = 0; server_xtn->cfg2.s.idxstd[i].name; i++) + /* xpath/qpath is a final match. + * mark that the segments in the query path don't need inspection. */ + tmp.final_match = 1; + + 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); - if (tpath == QSE_NULL) + ptr = tmp.index.files; + for (i = 0; i < tmp.index.count; i++, ptr += qse_mbslen(ptr) + 1) { - QSE_MMGR_FREE (httpd->mmgr, xpath); - return -1; + qse_mchar_t* tpath; + + 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->u.dir.path = xpath; + target->type = QSE_HTTPD_RSRC_DIR; + target->u.dir.path = tmp.xpath; + } + else + { + /* let me treat it as a file. */ + goto attempt_file; + } } else { + /* well, stat failed. i don't know if it is a file. + * i must try each segment in the query path. */ 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 */ - n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], - 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; + QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); + return -1; } + if (n >= 1) return 0; /* fall back to a normal file. */ target->type = QSE_HTTPD_RSRC_FILE; - target->u.file.path = xpath; - target->u.file.mime = QSE_NULL; - if (server_xtn->cfg2.s.mimestd) + target->u.file.path = tmp.xpath; + + if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1) { - for (i = 0; server_xtn->cfg2.s.mimestd[i].ext; i++) - { -/* 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; - } + /* don't care about failure */ + target->u.file.mime = QSE_NULL; } } 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) { server_xtn_t* server_xtn; - qse_size_t i; server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (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]); - server_xtn->cfg[i] = QSE_NULL; + qse_httpd_serverstd_index_t* index = (qse_httpd_serverstd_index_t*)result; + 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_t* httpd, const qse_char_t* uri, - qse_httpd_server_predetach_t predetach, qse_size_t xtnsize) + qse_httpd_t* httpd, qse_httpd_serverstd_t* server, qse_size_t xtnsize) { - qse_httpd_server_t server; + qse_httpd_server_dope_t dope; qse_httpd_server_t* xserver; 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_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)); 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); } - xserver = qse_httpd_attachserver ( - httpd, &server, predetach_server, QSE_SIZEOF(*server_xtn) + xtnsize); - if (xserver == QSE_NULL) return QSE_NULL; - - server_xtn = qse_httpd_getserverxtn (httpd, xserver); - - if (!xuri.path.ptr) + server.predetach = predetach; + server.reconfig = reconfig; +#if 0 + server.docroot = xuri.path; + if (server.docroot.ptr && qse_ismbsdriveabspath((const qse_mchar_t*)server.docroot.ptr + 1)) { - /* the path part is not specified */ -#if defined(QSE_CHAR_IS_MCHAR) - xuri.path.ptr = QSE_MT("/"); -#else - xuri.path.ptr = QSE_WT("/"); + /* if the path name is something like /C:/xxx on support platforms ... */ + server.docroot.ptr++; + server.docroot.len--; + } + server.realm = xuri.frag; + server.user = xuri.auth.user; + server.pass = xuri.auth.pass; #endif - xuri.path.len = 1; - } - - 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; + return qse_httpd_attachserverstd (httpd, &server, xtnsize); invalid: httpd->errnum = QSE_HTTPD_EINVAL; return QSE_NULL; - -nomem_after_attach: - qse_httpd_detachserver (httpd, xserver); - httpd->errnum = QSE_HTTPD_ENOMEM; - return QSE_NULL; } int qse_httpd_getserveroptstd ( @@ -2584,19 +2652,16 @@ int qse_httpd_getserveroptstd ( switch (id) { - case QSE_HTTPD_SERVER_DOCROOT: - case QSE_HTTPD_SERVER_REALM: - 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]; + case QSE_HTTPD_SERVERSTD_QUERY: + *(qse_httpd_serverstd_query_t*)value = server_xtn->query; return 0; - case QSE_HTTPD_SERVER_CBSTD: - case QSE_HTTPD_SERVER_CGISTD: - case QSE_HTTPD_SERVER_MIMESTD: - case QSE_HTTPD_SERVER_IDXSTD: - *(void**)value = (void*)server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD]; + case QSE_HTTPD_SERVERSTD_MAKERSRC: + *(qse_httpd_serverstd_makersrc_t*)value = server_xtn->makersrc; + return 0; + + case QSE_HTTPD_SERVERSTD_FREERSRC: + *(qse_httpd_serverstd_freersrc_t*)value = server_xtn->freersrc; return 0; } @@ -2604,47 +2669,27 @@ int qse_httpd_getserveroptstd ( return -1; } + int qse_httpd_setserveroptstd ( qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_server_optstd_t id, const void* value) { server_xtn_t* server_xtn; - qse_mchar_t* mctmp; server_xtn = qse_httpd_getserverxtn (httpd, server); switch (id) { - case QSE_HTTPD_SERVER_DOCROOT: - case QSE_HTTPD_SERVER_REALM: - 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; + case QSE_HTTPD_SERVERSTD_QUERY: + server_xtn->query = (qse_httpd_serverstd_query_t)value; return 0; - case QSE_HTTPD_SERVER_CBSTD: - case QSE_HTTPD_SERVER_CGISTD: - case QSE_HTTPD_SERVER_MIMESTD: - case QSE_HTTPD_SERVER_IDXSTD: - server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD] = value; + case QSE_HTTPD_SERVERSTD_MAKERSRC: + server_xtn->makersrc = (qse_httpd_serverstd_makersrc_t)value; + return 0; + + case QSE_HTTPD_SERVERSTD_FREERSRC: + server_xtn->freersrc = (qse_httpd_serverstd_freersrc_t)value; return 0; } diff --git a/qse/lib/net/httpd-task.c b/qse/lib/http/httpd-task.c similarity index 100% rename from qse/lib/net/httpd-task.c rename to qse/lib/http/httpd-task.c diff --git a/qse/lib/net/httpd-text.c b/qse/lib/http/httpd-text.c similarity index 100% rename from qse/lib/net/httpd-text.c rename to qse/lib/http/httpd-text.c diff --git a/qse/lib/net/httpd.c b/qse/lib/http/httpd.c similarity index 91% rename from qse/lib/net/httpd.c rename to qse/lib/http/httpd.c index c8b29cbc..0612b414 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/http/httpd.c @@ -89,6 +89,11 @@ void qse_httpd_stop (qse_httpd_t* httpd) 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) { return httpd->errnum; @@ -159,6 +164,14 @@ QSE_INLINE void* qse_httpd_allocmem (qse_httpd_t* httpd, qse_size_t size) 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_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_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 ( @@ -434,15 +475,15 @@ static int accept_client ( { /* TODO: proper logging */ qse_char_t tmp[128]; -qse_nwadtostr (&server->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); -qse_printf (QSE_T("failed to accept from server %s\n"), tmp); +qse_nwadtostr (&server->dope.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); +qse_printf (QSE_T("failed to accept from server [%s] [%d]\n"), tmp, server->handle.i); return -1; } /* 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; 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) { - 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->server.close (httpd, server); - server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; + server->dope.flags &= ~QSE_HTTPD_SERVER_ACTIVE; httpd->server.nactive--; } } @@ -515,13 +556,12 @@ static int activate_servers (qse_httpd_t* httpd) if (httpd->scb->server.open (httpd, server) <= -1) { qse_char_t buf[64]; - qse_nwadtostr (&server->nwad, - buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); + qse_nwadtostr (&server->dope.nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); /* - httpd->rcb->log (httpd, 0, - QSE_T("cannot activate %s"), buf); + httpd->rcb->log (httpd, 0, QSE_T("cannot activate %s"), buf); */ +qse_printf(QSE_T("cannot activate [%s]\n"), buf); continue; } @@ -529,18 +569,17 @@ static int activate_servers (qse_httpd_t* httpd) httpd, httpd->mux, server->handle, QSE_HTTPD_MUX_READ, server) <= -1) { qse_char_t buf[64]; - qse_nwadtostr (&server->nwad, - buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); + qse_nwadtostr (&server->dope.nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); /* - httpd->rcb->log (httpd, 0, - QSE_T("cannot activate %s - "), buf); + httpd->rcb->log (httpd, 0, QSE_T("cannot activate %s - "), buf); */ +qse_printf(QSE_T("cannot add handle [%s]\n"), buf); httpd->scb->server.close (httpd, server); continue; } - server->flags |= QSE_HTTPD_SERVER_ACTIVE; + server->dope.flags |= QSE_HTTPD_SERVER_ACTIVE; 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_t* httpd, const qse_httpd_server_t* tmpl, - qse_httpd_server_predetach_t predetach, qse_size_t xtnsize) + qse_httpd_t* httpd, const qse_httpd_server_dope_t* dope, qse_size_t xtnsize) { 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; - QSE_MEMCPY (server, tmpl, QSE_SIZEOF(*server)); - QSE_MEMSET (server + 1, 0, xtnsize); - server->type = QSE_HTTPD_SERVER; - server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; - server->predetach = predetach; + /* copy the server dope */ + 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 */ 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; 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); 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 ( 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): 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 ( qse_httpd_t* httpd, qse_httpd_scb_t* scb, 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); if (count <= -1) { - xret = -1; - break; + if (httpd->errnum != QSE_HTTPD_EINTR) + { + xret = -1; + break; + } } purge_bad_clients (httpd); purge_idle_clients (httpd); + + if (httpd->reconfigreq) + { + reconfig_servers (httpd); + httpd->reconfigreq = 0; + } } purge_client_list (httpd); diff --git a/qse/lib/net/httpd.h b/qse/lib/http/httpd.h similarity index 96% rename from qse/lib/net/httpd.h rename to qse/lib/http/httpd.h index 972a3393..c1434928 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/http/httpd.h @@ -18,12 +18,12 @@ License along with QSE. If not, see . */ -#ifndef _QSE_LIB_NET_HTTPD_H_ -#define _QSE_LIB_NET_HTTPD_H_ +#ifndef _QSE_LIB_HTTP_HTTPD_H_ +#define _QSE_LIB_HTTP_HTTPD_H_ /* private header file for httpd */ -#include +#include #include /* TODO: remove this.. only for debugging at this moment */ @@ -39,7 +39,8 @@ struct qse_httpd_t { int trait; } opt; - int stopreq; + int stopreq: 1; + int reconfigreq: 1; qse_mchar_t sname[128]; /* server name for the server header */ qse_mchar_t gtbuf[10][64]; /* GMT time buffers */ diff --git a/qse/lib/net/upxd.c b/qse/lib/http/upxd.c similarity index 100% rename from qse/lib/net/upxd.c rename to qse/lib/http/upxd.c diff --git a/qse/lib/net/upxd.h b/qse/lib/http/upxd.h similarity index 98% rename from qse/lib/net/upxd.h rename to qse/lib/http/upxd.h index 294df0f3..f1d6e87b 100644 --- a/qse/lib/net/upxd.h +++ b/qse/lib/http/upxd.h @@ -21,7 +21,7 @@ #ifndef _QSE_LIB_NET_UPXD_H_ #define _QSE_LIB_NET_UPXD_H_ -#include +#include #include "../cmn/mem.h" typedef struct qse_upxd_server_session_t qse_upxd_server_session_t; diff --git a/qse/lib/xli/err.c b/qse/lib/xli/err.c index 6b5d7412..bea0cdd7 100644 --- a/qse/lib/xli/err.c +++ b/qse/lib/xli/err.c @@ -39,10 +39,16 @@ const qse_char_t* qse_xli_dflerrstr ( QSE_T("I/O error with file '${0}'"), QSE_T("error returned by user I/O handler"), + QSE_T("syntax error"), QSE_T("semicolon 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("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))? diff --git a/qse/lib/xli/read.c b/qse/lib/xli/read.c index ddebd97b..fed9f17c 100644 --- a/qse/lib/xli/read.c +++ b/qse/lib/xli/read.c @@ -48,6 +48,7 @@ enum tok_t TOK_LBRACE, TOK_RBRACE, TOK_EQ, + TOK_COMMA, TOK_DQSTR, TOK_SQSTR, 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[] = { { QSE_T("="), 1, TOK_EQ }, + { QSE_T(","), 1, TOK_COMMA }, { QSE_T(";"), 1, TOK_SEMICOLON }, { QSE_T("{"), 1, TOK_LBRACE }, { QSE_T("}"), 1, TOK_RBRACE }, @@ -310,9 +312,7 @@ static int begin_include (qse_xli_t* xli) ); if (pair == QSE_NULL) { -#if 0 - SETERR_LOC (xli, QSE_XLI_ENOMEM, &xli->ptok.loc); -#endif + qse_xli_seterror (xli, QSE_XLI_ENOMEM, QSE_NULL, &xli->tok.loc); goto oops; } @@ -320,13 +320,7 @@ static int begin_include (qse_xli_t* xli) QSE_HTB_VLEN(pair) = QSE_HTB_KLEN(pair);*/ arg = (qse_xli_io_arg_t*) qse_xli_callocmem (xli, QSE_SIZEOF(*arg)); - if (arg == QSE_NULL) - { -#if 0 - ADJERR_LOC (xli, &xli->ptok.loc); -#endif - goto oops; - } + if (arg == QSE_NULL) goto oops; arg->flags = QSE_XLI_IO_INCLUDED; arg->name = QSE_HTB_KPTR(pair); @@ -411,9 +405,7 @@ retry: { /* this directive is empty, * not followed by a valid word */ -#if 0 - SETERR_LOC (xli, QSE_XLI_EXKWEM, &(xli)->tok.loc); -#endif + qse_xli_seterror (xli, QSE_XLI_EXKWEM, QSE_NULL, &xli->tok.loc); return -1; } @@ -429,9 +421,7 @@ retry: if (type == TOK_IDENT) { /* this directive is not recognized */ -#if 0 - SETERR_TOK (xli, QSE_XLI_EXKWNR); -#endif + qse_xli_seterror (xli, QSE_XLI_EXKWNR, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc); return -1; } SET_TOKEN_TYPE (xli, tok, type); @@ -465,9 +455,7 @@ retry: if (c == QSE_CHAR_EOF) { /* the string is not closed */ -#if 0 - SETERR_TOK (xli, QSE_XLI_ESTRNC); -#endif + qse_xli_seterror (xli, QSE_XLI_ESTRNC, QSE_NULL, &xli->tok.loc); return -1; } @@ -490,18 +478,18 @@ retry: /* not handled yet */ if (c == QSE_T('\0')) { -#if 0 - SETERR_ARG_LOC ( - xli, QSE_XLI_ELXCHR, - QSE_T(""), 5, &tok->loc); -#endif + qse_cstr_t ea; + ea.ptr = QSE_T(""); + ea.len = 5; + qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc); } else { -#if 0 qse_char_t cc = (qse_char_t)c; - SETERR_ARG_LOC (xli, QSE_XLI_ELXCHR, &cc, 1, &tok->loc); -#endif + qse_cstr_t ea; + ea.ptr = &cc; + ea.len = 1; + qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc); } return -1; } @@ -518,9 +506,7 @@ retry: if (skip_semicolon_after_include) { /* semiclon has not been skipped yet */ -#if 0 qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_CSTR(tok->name), &tok->loc); -#endif 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_xli_pair_t* pair; - if (xli->opt.trait & QSE_XLI_NODUPKEY) + if (xli->opt.trait & QSE_XLI_KEYNODUP) { 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 (xli->opt.trait & QSE_XLI_NAMEDKEY) + if (xli->opt.trait & QSE_XLI_KEYNAME) { /* 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; @@ -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 (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 ( - xli, list, QSE_NULL, key, name, - QSE_STR_PTR(xli->tok.name), MATCH (xli, TOK_SQSTR)); - if (pair == QSE_NULL) goto oops; + if (qse_str_ncpy (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; + 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 */ 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; } } + 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 { 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 0 - SETERR_LOC (xli, QSE_XLI_EINCLSTR, &xli->ptok.loc); -#endif + qse_xli_seterror (xli, QSE_XLI_EINCLSTR, QSE_NULL, &xli->tok.loc); 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; } - else break; + else + { + break; + } } 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)) { -/* TODO: set erro code */ -qse_printf (QSE_T("NOT ENDING WITH EOF... %s\n"), QSE_STR_PTR(xli->tok.name)); + qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc); goto oops; } diff --git a/qse/lib/xli/write.c b/qse/lib/xli/write.c index 5f8eceae..d6eb5d11 100644 --- a/qse/lib/xli/write.c +++ b/qse/lib/xli/write.c @@ -24,12 +24,12 @@ int qse_xli_write (qse_xli_t* xli, qse_xli_io_impl_t io) { if (io == QSE_NULL) { - xli->errnum = QSE_XLI_EINVAL; + qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); return -1; } /* TODO: write data to io stream */ - xli->errnum = QSE_XLI_ENOIMPL; + qse_xli_seterrnum (xli, QSE_XLI_ENOIMPL, QSE_NULL); return -1; } diff --git a/qse/lib/xli/xli.c b/qse/lib/xli/xli.c index 30d5ca77..61632721 100644 --- a/qse/lib/xli/xli.c +++ b/qse/lib/xli/xli.c @@ -19,6 +19,7 @@ */ #include "xli.h" +#include 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) { + qse_size_t i; + QSE_MEMSET (xli, 0, QSE_SIZEOF(*xli)); xli->mmgr = mmgr; 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); 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) ); + xli->root.type = QSE_XLI_LIST; + xli->xnil.type = QSE_XLI_NIL; return 0; oops: qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); if (xli->sio_names) qse_htb_close (xli->sio_names); 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; } void qse_xli_fini (qse_xli_t* xli) { + qse_size_t i; + qse_xli_clear (xli); qse_htb_close (xli->sio_names); 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) @@ -243,20 +266,20 @@ qse_xli_pair_t* qse_xli_insertpairwithemptylist ( qse_xli_pair_t* qse_xli_insertpairwithstr ( 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_pair_t* tmp; - qse_size_t vlen; - vlen = qse_strlen (value); - val = qse_xli_callocmem (xli, QSE_SIZEOF(*val) + ((vlen + 1) * QSE_SIZEOF(*value))); + val = qse_xli_callocmem (xli, QSE_SIZEOF(*val) + ((value->len + 1) * QSE_SIZEOF(*value->ptr))); if (val == QSE_NULL) return QSE_NULL; 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->len = vlen; - val->verbatim = verbatim; + val->len = value->len; + tmp = qse_xli_insertpair (xli, parent, peer, key, name, (qse_xli_val_t*)val); if (tmp == QSE_NULL) qse_xli_freemem (xli, val); return tmp; @@ -275,7 +298,6 @@ qse_xli_text_t* qse_xli_inserttext ( text->type = QSE_XLI_TEXT; text->ptr = (const qse_char_t*)(text + 1); - text->len = slen; 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; - if (pair->val->type == QSE_XLI_LIST) - free_list (xli, (qse_xli_list_t*)pair->val); + if (pair->val != &xli->xnil) + { + 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); @@ -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) { - /* TODO: free data under 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; +} + diff --git a/qse/lib/xli/xli.h b/qse/lib/xli/xli.h index 276d6b7c..1fb5fd08 100644 --- a/qse/lib/xli/xli.h +++ b/qse/lib/xli/xli.h @@ -52,12 +52,14 @@ struct qse_xli_t qse_xli_ecb_t* ecb; qse_xli_list_t root; + qse_xli_nil_t xnil; + qse_str_t* tmp[1]; qse_xli_tok_t tok; struct { 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* inp; /* current */ } sio; diff --git a/qse/samples/net/Makefile.am b/qse/samples/http/Makefile.am similarity index 75% rename from qse/samples/net/Makefile.am rename to qse/samples/http/Makefile.am index 2b1c86b9..0d9574fe 100644 --- a/qse/samples/net/Makefile.am +++ b/qse/samples/http/Makefile.am @@ -7,8 +7,8 @@ AM_CPPFLAGS = \ bin_PROGRAMS = httpd01 httpd02 upxd01 -LDFLAGS += -L../../lib/cmn -L../../lib/net -LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) +LDFLAGS += -L../../lib/cmn -L../../lib/http +LDADD = -lqsehttp -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) if WIN32 if WCHAR diff --git a/qse/samples/net/Makefile.in b/qse/samples/http/Makefile.in similarity index 98% rename from qse/samples/net/Makefile.in rename to qse/samples/http/Makefile.in index e086f345..f84a1a33 100644 --- a/qse/samples/net/Makefile.in +++ b/qse/samples/http/Makefile.in @@ -36,7 +36,7 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = httpd01$(EXEEXT) httpd02$(EXEEXT) upxd01$(EXEEXT) @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) -subdir = samples/net +subdir = samples/http DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \ @@ -144,7 +144,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ -LDFLAGS = @LDFLAGS@ -L../../lib/cmn -L../../lib/net +LDFLAGS = @LDFLAGS@ -L../../lib/cmn -L../../lib/http LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ @@ -282,7 +282,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \ +LDADD = -lqsehttp -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \ $(SENDFILE_LIBS) $(am__append_1) httpd01_SOURCES = httpd01.c httpd02_SOURCES = httpd02.c @@ -302,9 +302,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/net/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/http/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign samples/net/Makefile + $(AUTOMAKE) --foreign samples/http/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/qse/samples/net/httpd01.c b/qse/samples/http/httpd01.c similarity index 99% rename from qse/samples/net/httpd01.c rename to qse/samples/http/httpd01.c index 7e0a2e1a..e4bb8ad7 100644 --- a/qse/samples/net/httpd01.c +++ b/qse/samples/http/httpd01.c @@ -1,5 +1,5 @@ -#include +#include #include #include #include diff --git a/qse/samples/net/httpd02.c b/qse/samples/http/httpd02.c similarity index 99% rename from qse/samples/net/httpd02.c rename to qse/samples/http/httpd02.c index ab943172..5ee9fbae 100644 --- a/qse/samples/net/httpd02.c +++ b/qse/samples/http/httpd02.c @@ -1,5 +1,5 @@ -#include +#include #include #include #include diff --git a/qse/samples/net/upxd01.c b/qse/samples/http/upxd01.c similarity index 99% rename from qse/samples/net/upxd01.c rename to qse/samples/http/upxd01.c index 8e6b834b..21cb3339 100644 --- a/qse/samples/net/upxd01.c +++ b/qse/samples/http/upxd01.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include