revising httpd

This commit is contained in:
hyung-hwan 2013-02-18 13:45:50 +00:00
parent bbdf168ee8
commit 5bc774db3a
56 changed files with 1774 additions and 953 deletions

View File

@ -1,2 +1,2 @@
SUBDIRS = awk sed xli net
SUBDIRS = awk sed xli http
DIST_SUBDIRS = $(SUBDIRS)

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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";
}
}
}

View File

@ -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;
}

View File

@ -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
View File

@ -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" ;;

View File

@ -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

View File

@ -1,4 +1,4 @@
SUBDIRS = cmn awk sed net
SUBDIRS = cmn awk sed http
pkgincludedir = $(includedir)/qse

View File

@ -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)

View File

@ -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
);

View File

@ -0,0 +1,4 @@
pkgincludedir= $(includedir)/qse/http
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h std.h upxd.h

View File

@ -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 \

View File

@ -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;

View File

@ -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>

View File

@ -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.

View File

@ -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,20 +364,34 @@ 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;
};
@ -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,12 +588,15 @@ 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,
const qse_httpd_server_dope_t* dope,
qse_size_t xtnsize
);
@ -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_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_EXPORT qse_mchar_t* qse_httpd_strtombsdup (
qse_httpd_t* httpd,
const qse_char_t* uri,
qse_httpd_server_predetach_t predetach,
qse_size_t xtnsize
const qse_char_t* str
);
QSE_EXPORT int qse_httpd_getserveroptstd (
QSE_EXPORT qse_mchar_t* qse_httpd_strntombsdup (
qse_httpd_t* httpd,
qse_httpd_server_t* server,
qse_httpd_server_optstd_t id,
void* value
const qse_char_t* str,
qse_size_t len
);
QSE_EXPORT int qse_httpd_setserveroptstd (
qse_httpd_t* httpd,
qse_httpd_server_t* server,
qse_httpd_server_optstd_t id,
const void* value
);
QSE_EXPORT void* qse_httpd_getserverxtnstd (
qse_httpd_t* httpd,
qse_httpd_server_t* server
);
QSE_EXPORT int qse_httpd_loopstd (
qse_httpd_t* httpd,
const qse_ntime_t* tmout
);
#ifdef __cplusplus
}
#endif

View File

@ -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>

View File

@ -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
View 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

View File

@ -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
);

View File

@ -1,2 +1,2 @@
SUBDIRS = cmn awk sed net
SUBDIRS = cmn awk sed xli http
DIST_SUBDIRS = $(SUBDIRS)

View File

@ -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

View File

@ -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"),

View File

@ -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;
}

View File

@ -20,6 +20,7 @@
#include <qse/cmn/main.h>
#include <qse/cmn/mbwc.h>
#include "mem.h"
int qse_runmain (

View File

@ -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));

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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)

View File

@ -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>

View File

@ -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));

View File

@ -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 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)
{
/* 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);
}
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, 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)
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req,
struct rsrc_tmp_t* tmp, qse_httpd_rsrc_t* target)
{
qse_mchar_t* ext;
qse_mchar_t* script, * suffix;
qse_size_t i;
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;
if (idxfile)
{
for (i = 0; cgistd[i].ext; i++)
{
if (qse_mbsend (idxfile, cgistd[i].ext))
{
script = merge_paths (httpd, qpath, idxfile);
if (script == QSE_NULL) return -1;
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
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;
if (tmp->final_match)
{
/* 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 (tmp->idxfile)
{
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++)
{
/* 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);
/* inspect each segment from the head. */
const qse_mchar_t* ptr;
const qse_mchar_t* slash;
if (ext && (ext[cgistd[i].len] == QSE_MT('/') ||
ext[cgistd[i].len] == QSE_MT('\0')))
QSE_ASSERT (tmp->qpath[0] == QSE_T('/'));
ptr = tmp->qpath + 1;
while (*ptr != QSE_MT('\0'))
{
if (ext[cgistd[i].len] == QSE_MT('/'))
slash = qse_mbschr (ptr, QSE_MT('/'));
if (slash)
{
/* 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)
if (slash > ptr)
{
if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix);
if (script) QSE_MMGR_FREE (httpd->mmgr, script);
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
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 (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;
}
/* drop the suffix part */
xpath[qse_mbslen(xpath) - qse_mbslen(suffix)] = QSE_MT('\0');
goto bingo;
}
}
}
ptr = slash + 1;
}
else
{
/* it has no path suffix */
script = qpath;
suffix = QSE_NULL;
/* no more slash is found. the last segement doesn't have to be checked
* here since it's attempted by the caller. */
break;
}
}
}
return 0; /* not a cgi */
bingo:
target->type = QSE_HTTPD_RSRC_CGI;
target->u.cgi.nph = cgistd[i].nph;
target->u.cgi.path = xpath;
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 = docroot;
target->u.cgi.shebang = cgistd[i].shebang;
target->u.cgi.docroot = tmp->docroot;
target->u.cgi.shebang = shebang;
return 1;
}
}
}
return 0;
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,85 +2288,123 @@ 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)
{
while (auth->next) auth = auth->next;
/* default to the root directory. */
if (!tmp.docroot) tmp.docroot = QSE_MT("/");
if (qse_mbszcasecmp(auth->ptr, QSE_MT("Basic "), 6) == 0)
if (tmp.realm && tmp.auth)
{
if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_AUTH]) == 0) goto auth_ok;
const qse_htre_hdrval_t* authv;
authv = qse_htre_getheaderval (req, QSE_MT("Authorization"));
if (authv)
{
while (authv->next) authv = authv->next;
if (qse_mbszcasecmp(authv->ptr, QSE_MT("Basic "), 6) == 0)
{
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)
{
/* 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 (server_xtn->cfg2.s.idxstd)
if (tmp.index.count > 0)
{
/* try to locate an index file */
for (i = 0; server_xtn->cfg2.s.idxstd[i].name; i++)
qse_size_t i;
const qse_mchar_t* ptr;
ptr = tmp.index.files;
for (i = 0; i < tmp.index.count; i++, ptr += qse_mbslen(ptr) + 1)
{
qse_mchar_t* tpath;
tpath = merge_paths (httpd, xpath, server_xtn->cfg2.s.idxstd[i].name);
tpath = merge_paths (httpd, tmp.xpath, ptr);
if (tpath == QSE_NULL)
{
QSE_MMGR_FREE (httpd->mmgr, xpath);
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, xpath);
xpath = tpath;
idxfile = server_xtn->cfg2.s.idxstd[i].name;
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
tmp.xpath = tpath;
tmp.idxfile = ptr;
goto attempt_file;
}
@ -2333,127 +2413,183 @@ auth_ok:
}
target->type = QSE_HTTPD_RSRC_DIR;
target->u.dir.path = xpath;
target->u.dir.path = tmp.xpath;
}
else
{
attempt_file:
if (server_xtn->cfg2.s.cgistd)
/* 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:
/* 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);
n = attempt_cgi (httpd, client, req, &tmp, target);
if (n <= -1)
{
QSE_MMGR_FREE (httpd->mmgr, xpath);
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.path = tmp.xpath;
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1)
{
/* don't care about failure */
target->u.file.mime = QSE_NULL;
if (server_xtn->cfg2.s.mimestd)
{
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;
}
}
}
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)
{
if (server_xtn->cfg[--i])
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
{
QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i]);
server_xtn->cfg[i] = QSE_NULL;
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)
{
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_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;
}

View File

@ -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)
@ -1165,13 +1215,22 @@ int qse_httpd_loop (
count = httpd->scb->mux.poll (httpd, httpd->mux, tmout);
if (count <= -1)
{
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);

View File

@ -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 */

View File

@ -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;

View File

@ -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))?

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,11 +314,14 @@ 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 != &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, 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;
}

View File

@ -52,7 +52,9 @@ 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
{

View File

@ -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

View File

@ -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 \

View File

@ -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>

View File

@ -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>

View File

@ -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>