revising httpd
This commit is contained in:
@ -1,2 +1,2 @@
|
||||
SUBDIRS = cmn awk sed net
|
||||
SUBDIRS = cmn awk sed xli http
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
int qse_runmain (
|
||||
|
@ -21,10 +21,10 @@
|
||||
#include <qse/cmn/uri.h>
|
||||
#include "mem.h"
|
||||
|
||||
int qse_mbstouri (const qse_mchar_t* str, qse_uri_t* uri, int flags)
|
||||
int qse_mbstouri (const qse_mchar_t* str, qse_muri_t* uri, int flags)
|
||||
{
|
||||
const qse_mchar_t* ptr, * colon;
|
||||
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));
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
@ -18,7 +18,7 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <qse/net/htrd.h>
|
||||
#include <qse/http/htrd.h>
|
||||
#include <qse/cmn/chr.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include "../cmn/mem.h"
|
@ -18,7 +18,7 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <qse/net/htre.h>
|
||||
#include <qse/http/htre.h>
|
||||
#include "../cmn/mem.h"
|
||||
|
||||
static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen)
|
@ -18,7 +18,7 @@
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <qse/net/http.h>
|
||||
#include <qse/http/http.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/chr.h>
|
||||
#include <qse/cmn/htb.h>
|
@ -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));
|
@ -18,6 +18,7 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <qse/http/std.h>
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem.h"
|
||||
#include <qse/cmn/hton.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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);
|
@ -18,12 +18,12 @@
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <qse/net/httpd.h>
|
||||
#include <qse/http/httpd.h>
|
||||
|
||||
#include <qse/cmn/stdio.h> /* 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 */
|
@ -21,7 +21,7 @@
|
||||
#ifndef _QSE_LIB_NET_UPXD_H_
|
||||
#define _QSE_LIB_NET_UPXD_H_
|
||||
|
||||
#include <qse/net/upxd.h>
|
||||
#include <qse/http/upxd.h>
|
||||
#include "../cmn/mem.h"
|
||||
|
||||
typedef struct qse_upxd_server_session_t qse_upxd_server_session_t;
|
@ -39,10 +39,16 @@ const qse_char_t* qse_xli_dflerrstr (
|
||||
QSE_T("I/O error with file '${0}'"),
|
||||
QSE_T("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))?
|
||||
|
@ -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("<NUL>"), 5, &tok->loc);
|
||||
#endif
|
||||
qse_cstr_t ea;
|
||||
ea.ptr = QSE_T("<NUL>");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "xli.h"
|
||||
#include <qse/cmn/chr.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user