revising httpd
This commit is contained in:
parent
bbdf168ee8
commit
5bc774db3a
@ -1,2 +1,2 @@
|
||||
SUBDIRS = awk sed xli net
|
||||
SUBDIRS = 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 = awk sed xli net
|
||||
SUBDIRS = awk sed xli http
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
all: all-recursive
|
||||
|
||||
|
@ -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
|
@ -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 \
|
555
qse/cmd/http/httpd.c
Normal file
555
qse/cmd/http/httpd.c
Normal file
@ -0,0 +1,555 @@
|
||||
|
||||
#include <qse/http/std.h>
|
||||
#include <qse/xli/std.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <process.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSEXCEPTIONS
|
||||
# define INCL_ERRORS
|
||||
# include <os2.h>
|
||||
#elif defined(__DOS__)
|
||||
# include <dos.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
static void sighup (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_reconfig (g_httpd);
|
||||
}
|
||||
|
||||
static void setup_signal_handlers ()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
#if defined(SIGINT)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sigint;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGHUP)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sighup;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGPIPE)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction (SIGPIPE, &act, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void restore_signal_handlers ()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
#if defined(SIGINT)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGHUP)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGPIPE)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGPIPE, &act, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct server_xtn_t server_xtn_t;
|
||||
struct server_xtn_t
|
||||
{
|
||||
int tproxy;
|
||||
int nodir; /* no directory listing */
|
||||
|
||||
qse_httpd_serverstd_makersrc_t orgmakersrc;
|
||||
qse_httpd_serverstd_freersrc_t orgfreersrc;
|
||||
qse_httpd_serverstd_query_t orgquery;
|
||||
|
||||
qse_mchar_t* docroot;
|
||||
qse_mchar_t* realm;
|
||||
qse_mchar_t* auth;
|
||||
qse_mchar_t* dircss;
|
||||
qse_mchar_t* errcss;
|
||||
|
||||
qse_httpd_serverstd_index_t index;
|
||||
};
|
||||
|
||||
static int make_resource (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */
|
||||
{
|
||||
/* TODO: implement a better check that the
|
||||
* destination is not one of the local addresses */
|
||||
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsrc->type = QSE_HTTPD_RSRC_PROXY;
|
||||
rsrc->u.proxy.dst = client->orgdst_addr;
|
||||
rsrc->u.proxy.src = client->remote_addr;
|
||||
|
||||
if (rsrc->u.proxy.src.type == QSE_NWAD_IN4)
|
||||
rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */
|
||||
else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6)
|
||||
rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgmakersrc (httpd, client, req, rsrc) <= -1) return -1;
|
||||
if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR)
|
||||
{
|
||||
/* prohibit no directory listing */
|
||||
if (server_xtn->orgfreersrc)
|
||||
server_xtn->orgfreersrc (httpd, client, req, rsrc);
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 403;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_resource (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgfreersrc)
|
||||
server_xtn->orgfreersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
|
||||
if (server_xtn->docroot) qse_httpd_freemem (httpd, server_xtn->docroot);
|
||||
if (server_xtn->realm) qse_httpd_freemem (httpd, server_xtn->realm);
|
||||
if (server_xtn->auth) qse_httpd_freemem (httpd, server_xtn->auth);
|
||||
if (server_xtn->dircss) qse_httpd_freemem (httpd, server_xtn->dircss);
|
||||
if (server_xtn->errcss) qse_httpd_freemem (httpd, server_xtn->errcss);
|
||||
if (server_xtn->index.files) qse_httpd_freemem (httpd, server_xtn->index.files);
|
||||
}
|
||||
|
||||
static void reconfig_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
qse_printf (QSE_T("reconfiguring server.....\n"));
|
||||
}
|
||||
|
||||
static int query_server (
|
||||
qse_httpd_t* httpd, qse_httpd_server_t* server,
|
||||
qse_htre_t* req, const qse_mchar_t* xpath,
|
||||
qse_httpd_serverstd_query_code_t code, void* result)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case QSE_HTTPD_SERVERSTD_DOCROOT:
|
||||
*(const qse_mchar_t**)result = server_xtn->docroot;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_REALM:
|
||||
*(const qse_mchar_t**)result = server_xtn->realm;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_AUTH:
|
||||
*(const qse_mchar_t**)result = server_xtn->auth;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_DIRCSS:
|
||||
*(const qse_mchar_t**)result = server_xtn->dircss;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_ERRCSS:
|
||||
*(const qse_mchar_t**)result = server_xtn->errcss;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_INDEX:
|
||||
*(qse_httpd_serverstd_index_t*)result = server_xtn->index;
|
||||
return 0;
|
||||
|
||||
|
||||
#if 0
|
||||
case QSE_HTTPD_SERVERSTD_CGI:
|
||||
case QSE_HTTPD_SERVERSTD_MIME:
|
||||
#endif
|
||||
}
|
||||
|
||||
return server_xtn->orgquery (httpd, server, req, xpath, code, result);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int load_server (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list)
|
||||
{
|
||||
qse_httpd_serverstd_t server;
|
||||
qse_httpd_server_t* xserver;
|
||||
server_xtn_t* server_xtn;
|
||||
qse_xli_pair_t* pair;
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("bind"));
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: no bind specified for ....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pair->val->type != QSE_XLI_STR)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: non-string value for bind\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_memset (&server, 0, QSE_SIZEOF(server));
|
||||
if (qse_strtonwad (((qse_xli_str_t*)pair->val)->ptr, &server.nwad) <= -1)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: invalid value for bind - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
server.predetach = predetach_server;
|
||||
xserver = qse_httpd_attachserverstd (httpd, &server, QSE_SIZEOF(server_xtn_t));
|
||||
if (xserver == QSE_NULL)
|
||||
{
|
||||
/* TODO: logging */
|
||||
qse_printf (QSE_T("WARNING: failed to attach server\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, xserver);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, &server_xtn->orgquery);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, query_server);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, &server_xtn->orgmakersrc);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, make_resource);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, &server_xtn->orgfreersrc);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, free_resource);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].docroot"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.docroot"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->docroot = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->docroot == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy docroot - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].realm"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.realm"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->realm = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->realm == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy realm - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].auth"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.auth"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
server_xtn->auth = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->auth == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy auth - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qse_mbschr (server_xtn->auth, QSE_MT(':')) == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: no colon in the auth string - [%hs]\n"), server_xtn->auth);
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.dir"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.dir"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
server_xtn->dircss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->dircss == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.error"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.error"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->errcss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->errcss == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].index"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.index"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
const qse_char_t* tmpptr, * tmpend;
|
||||
qse_size_t count;
|
||||
|
||||
tmpptr = ((qse_xli_str_t*)pair->val)->ptr;
|
||||
tmpend = tmpptr + ((qse_xli_str_t*)pair->val)->len;
|
||||
|
||||
for (count = 0; tmpptr < tmpend; count++) tmpptr += qse_strlen (tmpptr) + 1;
|
||||
|
||||
server_xtn->index.count = count;
|
||||
server_xtn->index.files = qse_httpd_strntombsdup (
|
||||
httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len);
|
||||
if (server_xtn->index.files == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy index\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_config (qse_httpd_t* httpd, qse_xli_t* xli, const qse_char_t* file)
|
||||
{
|
||||
qse_xli_iostd_t xli_in;
|
||||
qse_xli_pair_t* pair;
|
||||
int i;
|
||||
|
||||
xli_in.type = QSE_XLI_IOSTD_FILE;
|
||||
xli_in.u.file.path = file;
|
||||
xli_in.u.file.cmgr = QSE_NULL;
|
||||
|
||||
if (qse_xli_readstd (xli, &xli_in) <= -1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot load %s - %s\n"), xli_in.u.file.path, qse_xli_geterrmsg(xli));
|
||||
return - 1;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
qse_char_t buf[32];
|
||||
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("server[%d]"), i);
|
||||
pair = qse_xli_findpairbyname (xli, QSE_NULL, buf);
|
||||
if (pair == QSE_NULL) break;
|
||||
|
||||
if (pair->val->type != QSE_XLI_LIST)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("WARNING: non-list value for server\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
load_server (httpd, xli, (qse_xli_list_t*)pair->val);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("No valid server specified in %s\n"), xli_in.u.file.path);
|
||||
return - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
qse_xli_t* xli = QSE_NULL;
|
||||
qse_ntime_t tmout;
|
||||
int ret = -1, i;
|
||||
int trait;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
/* TODO: proper check... */
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
xli = qse_xli_openstd (0);
|
||||
if (xli == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open xli\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
qse_xli_getopt (xli, QSE_XLI_TRAIT, &trait);
|
||||
trait |= QSE_XLI_KEYNAME;
|
||||
qse_xli_setopt (xli, QSE_XLI_TRAIT, &trait);
|
||||
if (load_config (httpd, xli, argv[1]) <= -1) goto oops;
|
||||
|
||||
|
||||
g_httpd = httpd;
|
||||
setup_signal_handlers ();
|
||||
|
||||
qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0"));
|
||||
|
||||
qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
trait |= QSE_HTTPD_CGIERRTONUL;
|
||||
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
|
||||
tmout.sec = 10;
|
||||
tmout.nsec = 0;
|
||||
ret = qse_httpd_loopstd (httpd, &tmout);
|
||||
|
||||
restore_signal_handlers ();
|
||||
g_httpd = QSE_NULL;
|
||||
|
||||
if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error - %d\n"), qse_httpd_geterrnum (httpd));
|
||||
|
||||
oops:
|
||||
if (xli) qse_xli_close (xli);
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(_WIN32)
|
||||
char locale[100];
|
||||
UINT codepage;
|
||||
WSADATA wsadata;
|
||||
|
||||
codepage = GetConsoleOutputCP();
|
||||
if (codepage == CP_UTF8)
|
||||
{
|
||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||
setlocale (LC_ALL, locale);
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
}
|
||||
|
||||
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
setlocale (LC_ALL, "");
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
SSL_load_error_strings ();
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
|
||||
ret = qse_runmain (argc, argv, httpd_main);
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
/*ERR_remove_state ();*/
|
||||
ENGINE_cleanup ();
|
||||
ERR_free_strings ();
|
||||
EVP_cleanup ();
|
||||
CRYPTO_cleanup_all_ex_data ();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
WSACleanup ();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
44
qse/cmd/http/httpd.conf
Normal file
44
qse/cmd/http/httpd.conf
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# this is a sample configuration file for qsehttpd.
|
||||
#
|
||||
|
||||
server {
|
||||
bind = "0.0.0.0:80";
|
||||
|
||||
ssl {
|
||||
certificate {
|
||||
private = "xxxx";
|
||||
public = "xxxx";
|
||||
}
|
||||
}
|
||||
|
||||
root = "/home/www/default";
|
||||
option = "xxxx,xxx,xxxx";
|
||||
|
||||
realm {
|
||||
name = "xxxxxx";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
|
||||
cgi {
|
||||
suffix ".ant" = "xxxxx";
|
||||
suffix ".cgi";
|
||||
suffix ".nph";
|
||||
}
|
||||
|
||||
mime {
|
||||
suffix ".jpg" = "image/picture";
|
||||
suffix ".txt" = "text/plain";
|
||||
}
|
||||
|
||||
# virtual host
|
||||
host "www.google.com" {
|
||||
root = "/home/www/google";
|
||||
option = "xxx, xxx, xxxx";
|
||||
|
||||
realm {
|
||||
name = "www.google.com";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,296 +0,0 @@
|
||||
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <process.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSEXCEPTIONS
|
||||
# define INCL_ERRORS
|
||||
# include <os2.h>
|
||||
#elif defined(__DOS__)
|
||||
# include <dos.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct server_xtn_t server_xtn_t;
|
||||
struct server_xtn_t
|
||||
{
|
||||
int tproxy;
|
||||
int nodir; /* no directory listing */
|
||||
qse_httpd_server_cbstd_t* orgcbstd;
|
||||
};
|
||||
|
||||
static int makersrc (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */
|
||||
{
|
||||
/* TODO: implement a better check that the
|
||||
* destination is not one of the local addresses */
|
||||
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsrc->type = QSE_HTTPD_RSRC_PROXY;
|
||||
rsrc->u.proxy.dst = client->orgdst_addr;
|
||||
rsrc->u.proxy.src = client->remote_addr;
|
||||
|
||||
if (rsrc->u.proxy.src.type == QSE_NWAD_IN4)
|
||||
rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */
|
||||
else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6)
|
||||
rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgcbstd->makersrc (httpd, client, req, rsrc) <= -1) return -1;
|
||||
if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR)
|
||||
{
|
||||
/* prohibit no directory listing */
|
||||
if (server_xtn->orgcbstd->freersrc)
|
||||
server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc);
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 403;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void freersrc (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgcbstd->freersrc)
|
||||
server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_server_t* attach_server (
|
||||
qse_httpd_t* httpd, qse_char_t* uri, qse_httpd_server_cbstd_t* cbstd)
|
||||
{
|
||||
qse_httpd_server_t* server;
|
||||
server_xtn_t* server_xtn;
|
||||
int tproxy = 0;
|
||||
|
||||
static qse_httpd_server_idxstd_t idxstd[] =
|
||||
{
|
||||
{ QSE_MT("index.cgi") },
|
||||
{ QSE_MT("index.html") },
|
||||
{ QSE_NULL }
|
||||
};
|
||||
|
||||
if (qse_strzcasecmp (uri, QSE_T("http-tproxy://"), 14) == 0)
|
||||
{
|
||||
tproxy = 1;
|
||||
qse_strcpy (&uri[4], &uri[11]);
|
||||
}
|
||||
|
||||
server = qse_httpd_attachserverstd (
|
||||
httpd, uri, QSE_NULL, QSE_SIZEOF(server_xtn_t));
|
||||
if (server == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* qse_httpd_getserverxtnstd() returns the pointer to
|
||||
* the extension space requested above, of the size
|
||||
* QSE_SIZEOF(server_xtn_t) */
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
server_xtn->tproxy = tproxy;
|
||||
|
||||
/* qse_httpd_getserverxtn() returns the pointer to the
|
||||
* extension space created by qse_httpd_attachserverstd()
|
||||
* internally.
|
||||
*/
|
||||
/* remember the callback set in qse_httpd_attachserverstd() */
|
||||
qse_httpd_getserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_CBSTD, (void**)&server_xtn->orgcbstd);
|
||||
/* override it with a new callback for chaining */
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_CBSTD, cbstd);
|
||||
|
||||
/* totally override idxstd without remembering the old idxstd */
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_IDXSTD, idxstd);
|
||||
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server, QSE_HTTPD_SERVER_DIRCSS,
|
||||
QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; } table { font-size: 0.9em; } td { white-space: nowrap; } td.size { text-align: right; }</style>"));
|
||||
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server, QSE_HTTPD_SERVER_ERRCSS,
|
||||
QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; }</style>"));
|
||||
|
||||
return server;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
qse_ntime_t tmout;
|
||||
int ret = -1, i;
|
||||
int trait;
|
||||
static qse_httpd_server_cbstd_t cbstd = { makersrc, freersrc };
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri> ...\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (attach_server (httpd, argv[i], &cbstd) == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
g_httpd = httpd;
|
||||
signal (SIGINT, sigint);
|
||||
#if defined(SIGPIPE)
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0"));
|
||||
|
||||
trait = QSE_HTTPD_CGIERRTONUL;
|
||||
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
|
||||
tmout.sec = 10;
|
||||
tmout.nsec = 0;
|
||||
ret = qse_httpd_loopstd (httpd, &tmout);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
#if defined(SIGPIPE)
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
#endif
|
||||
g_httpd = QSE_NULL;
|
||||
|
||||
if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error\n"));
|
||||
|
||||
oops:
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(_WIN32)
|
||||
char locale[100];
|
||||
UINT codepage;
|
||||
WSADATA wsadata;
|
||||
|
||||
codepage = GetConsoleOutputCP();
|
||||
if (codepage == CP_UTF8)
|
||||
{
|
||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||
setlocale (LC_ALL, locale);
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
}
|
||||
|
||||
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
setlocale (LC_ALL, "");
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
SSL_load_error_strings ();
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
|
||||
ret = qse_runmain (argc, argv, httpd_main);
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
/*ERR_remove_state ();*/
|
||||
ENGINE_cleanup ();
|
||||
ERR_free_strings ();
|
||||
EVP_cleanup ();
|
||||
CRYPTO_cleanup_all_ex_data ();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
WSACleanup ();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@
|
||||
|
||||
static qse_char_t* g_input_file = QSE_NULL;
|
||||
static qse_char_t* g_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)
|
||||
|
10
qse/configure
vendored
10
qse/configure
vendored
@ -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" ;;
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = cmn awk sed net
|
||||
SUBDIRS = cmn awk sed http
|
||||
|
||||
pkgincludedir = $(includedir)/qse
|
||||
|
||||
|
@ -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)
|
||||
|
@ -24,22 +24,37 @@
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
|
||||
typedef struct qse_muri_t qse_muri_t;
|
||||
typedef struct qse_wuri_t qse_wuri_t;
|
||||
|
||||
typedef struct qse_uri_t qse_uri_t;
|
||||
|
||||
struct qse_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
|
||||
);
|
||||
|
||||
|
4
qse/include/qse/http/Makefile.am
Normal file
4
qse/include/qse/http/Makefile.am
Normal file
@ -0,0 +1,4 @@
|
||||
pkgincludedir= $(includedir)/qse/http
|
||||
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h std.h upxd.h
|
||||
|
||||
|
@ -33,7 +33,7 @@ PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
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 \
|
@ -18,11 +18,11 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_NET_HTRD_H_
|
||||
#define _QSE_NET_HTRD_H_
|
||||
#ifndef _QSE_HTTP_HTRD_H_
|
||||
#define _QSE_HTTP_HTRD_H_
|
||||
|
||||
#include <qse/net/http.h>
|
||||
#include <qse/net/htre.h>
|
||||
#include <qse/http/http.h>
|
||||
#include <qse/http/htre.h>
|
||||
|
||||
typedef struct qse_htrd_t qse_htrd_t;
|
||||
|
@ -18,10 +18,10 @@
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_NET_HTRE_H_
|
||||
#define _QSE_NET_HTRE_H_
|
||||
#ifndef _QSE_HTTP_HTRE_H_
|
||||
#define _QSE_HTTP_HTRE_H_
|
||||
|
||||
#include <qse/net/http.h>
|
||||
#include <qse/http/http.h>
|
||||
#include <qse/cmn/htb.h>
|
||||
#include <qse/cmn/str.h>
|
||||
|
@ -18,8 +18,8 @@
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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.
|
@ -18,17 +18,18 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_NET_HTTPD_H_
|
||||
#define _QSE_NET_HTTPD_H_
|
||||
#ifndef _QSE_HTTP_HTTPD_H_
|
||||
#define _QSE_HTTP_HTTPD_H_
|
||||
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
#include <qse/net/htre.h>
|
||||
#include <qse/net/htrd.h>
|
||||
#include <qse/http/htre.h>
|
||||
#include <qse/http/htrd.h>
|
||||
#include <qse/cmn/nwad.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
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
|
@ -18,8 +18,8 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_NET_UPXD_H_
|
||||
#define _QSE_NET_UPXD_H_
|
||||
#ifndef _QSE_HTTP_UPXD_H_
|
||||
#define _QSE_HTTP_UPXD_H_
|
||||
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
@ -1,4 +0,0 @@
|
||||
pkgincludedir= $(includedir)/qse/net
|
||||
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h upxd.h
|
||||
|
||||
|
137
qse/include/qse/xli/std.h
Normal file
137
qse/include/qse/xli/std.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright 2006-2012 Chung, Hyung-Hwan.
|
||||
This file is part of QSE.
|
||||
|
||||
QSE is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
QSE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_XLI_STD_H_
|
||||
#define _QSE_XLI_STD_H_
|
||||
|
||||
#include <qse/xli/xli.h>
|
||||
#include <qse/cmn/sio.h>
|
||||
|
||||
/** \file
|
||||
* This file defines functions and data types that help you create
|
||||
* an xli interpreter with less effort. It is designed to be as close
|
||||
* to conventional xli implementations as possible.
|
||||
*
|
||||
* The source script handler does not evaluate a file name of the "var=val"
|
||||
* form as an assignment expression. Instead, it just treats it as a
|
||||
* normal file name.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The qse_xli_iostd_type_t type defines standard source I/O types.
|
||||
*/
|
||||
enum qse_xli_iostd_type_t
|
||||
{
|
||||
QSE_XLI_IOSTD_NULL = 0, /**< pseudo-value to indicate no script */
|
||||
QSE_XLI_IOSTD_FILE = 1, /**< file */
|
||||
QSE_XLI_IOSTD_STR = 2 /**< length-bounded string */
|
||||
};
|
||||
typedef enum qse_xli_iostd_type_t qse_xli_iostd_type_t;
|
||||
|
||||
/**
|
||||
* The qse_xli_iostd_t type defines a source I/O.
|
||||
*/
|
||||
struct qse_xli_iostd_t
|
||||
{
|
||||
qse_xli_iostd_type_t type;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** file path to open. #QSE_NULL or '-' for stdin/stdout. */
|
||||
const qse_char_t* path;
|
||||
|
||||
/** a stream created with the file path is set with this
|
||||
* cmgr if it is not #QSE_NULL. */
|
||||
qse_cmgr_t* cmgr;
|
||||
} file;
|
||||
|
||||
/**
|
||||
* input string or dynamically allocated output string
|
||||
*
|
||||
* For input, the ptr and the len field of str indicates the
|
||||
* pointer and the length of a string to read. You must set
|
||||
* these fields before calling qse_xli_readstd().
|
||||
*
|
||||
* For output, the ptr and the len field of str indicates the
|
||||
* pointer and the length of a dereadd source string. The output
|
||||
* string is dynamically allocated. You don't need to set these
|
||||
* fields before calling qse_xli_readstd() because they are set
|
||||
* by qse_xli_readstd() and valid while the relevant xli object
|
||||
* is alive. You must free the memory chunk pointed to by the
|
||||
* ptr field with qse_xli_freemem() once you're done with it to
|
||||
* avoid memory leaks.
|
||||
*/
|
||||
qse_xstr_t str;
|
||||
} u;
|
||||
};
|
||||
|
||||
typedef struct qse_xli_iostd_t qse_xli_iostd_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The qse_xli_openstd() function creates an xli object using the default
|
||||
* memory manager and primitive functions. Besides, it adds a set of
|
||||
* standard intrinsic functions like atan, system, etc. Use this function
|
||||
* over qse_xli_open() if you don't need finer-grained customization.
|
||||
*/
|
||||
QSE_EXPORT qse_xli_t* qse_xli_openstd (
|
||||
qse_size_t xtnsize /**< extension size in bytes */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_xli_openstdwithmmgr() function creates an xli object with a
|
||||
* user-defined memory manager. It is equivalent to qse_xli_openstd(),
|
||||
* except that you can specify your own memory manager.
|
||||
*/
|
||||
QSE_EXPORT qse_xli_t* qse_xli_openstdwithmmgr (
|
||||
qse_mmgr_t* mmgr, /**< memory manager */
|
||||
qse_size_t xtnsize /**< extension size in bytes */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_xli_getxtnstd() gets the pointer to extension area created with
|
||||
* qse_xli_openstd() or qse_xli_openstdwithmmgr(). You must not call
|
||||
* qse_xli_getxtn() for sunch an object.
|
||||
*/
|
||||
QSE_EXPORT void* qse_xli_getxtnstd (
|
||||
qse_xli_t* xli
|
||||
);
|
||||
|
||||
QSE_EXPORT int qse_xli_readstd (
|
||||
qse_xli_t* xli,
|
||||
qse_xli_iostd_t* in
|
||||
);
|
||||
|
||||
QSE_EXPORT int qse_xli_writestd (
|
||||
qse_xli_t* xli,
|
||||
qse_xli_iostd_t* out
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -39,10 +39,17 @@ enum qse_xli_errnum_t
|
||||
QSE_XLI_EEXIST, /**< '${0}' already exists */
|
||||
QSE_XLI_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
|
||||
);
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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 \
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/http/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/http/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
@ -1,4 +1,4 @@
|
||||
#include <qse/net/upxd.h>
|
||||
#include <qse/http/upxd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
Loading…
Reference in New Issue
Block a user