revising httpd
This commit is contained in:
@ -1,2 +1,2 @@
|
||||
SUBDIRS = awk sed xli net
|
||||
SUBDIRS = awk sed xli http
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
|
@ -270,7 +270,7 @@ target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
SUBDIRS = awk sed xli net
|
||||
SUBDIRS = awk sed xli http
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
all: all-recursive
|
||||
|
||||
|
@ -8,8 +8,8 @@ AM_CPPFLAGS = \
|
||||
bin_PROGRAMS = qsehttpd
|
||||
|
||||
qsehttpd_SOURCES = httpd.c
|
||||
qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir)
|
||||
qsehttpd_LDADD = -lqsenet -lqsecmn
|
||||
qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir)
|
||||
qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn
|
||||
|
||||
if WIN32
|
||||
if WCHAR
|
@ -36,7 +36,7 @@ build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
bin_PROGRAMS = qsehttpd$(EXEEXT)
|
||||
@WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
||||
subdir = cmd/net
|
||||
subdir = cmd/http
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
|
||||
@ -276,8 +276,8 @@ AM_CPPFLAGS = \
|
||||
-I$(includedir)
|
||||
|
||||
qsehttpd_SOURCES = httpd.c
|
||||
qsehttpd_LDFLAGS = -L../../lib/net -L../../lib/cmn -L$(libdir)
|
||||
qsehttpd_LDADD = -lqsenet -lqsecmn $(am__append_1)
|
||||
qsehttpd_LDFLAGS = -L../../lib/xli -L../../lib/http -L../../lib/cmn -L$(libdir)
|
||||
qsehttpd_LDADD = -lqsexli -lqsehttp -lqsecmn $(am__append_1)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
@ -291,9 +291,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/net/Makefile'; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cmd/http/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign cmd/net/Makefile
|
||||
$(AUTOMAKE) --foreign cmd/http/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
555
qse/cmd/http/httpd.c
Normal file
555
qse/cmd/http/httpd.c
Normal file
@ -0,0 +1,555 @@
|
||||
|
||||
#include <qse/http/std.h>
|
||||
#include <qse/xli/std.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <process.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSEXCEPTIONS
|
||||
# define INCL_ERRORS
|
||||
# include <os2.h>
|
||||
#elif defined(__DOS__)
|
||||
# include <dos.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
static void sighup (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_reconfig (g_httpd);
|
||||
}
|
||||
|
||||
static void setup_signal_handlers ()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
#if defined(SIGINT)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sigint;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGHUP)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sighup;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGPIPE)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction (SIGPIPE, &act, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void restore_signal_handlers ()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
#if defined(SIGINT)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGHUP)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#endif
|
||||
|
||||
#if defined(SIGPIPE)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGPIPE, &act, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct server_xtn_t server_xtn_t;
|
||||
struct server_xtn_t
|
||||
{
|
||||
int tproxy;
|
||||
int nodir; /* no directory listing */
|
||||
|
||||
qse_httpd_serverstd_makersrc_t orgmakersrc;
|
||||
qse_httpd_serverstd_freersrc_t orgfreersrc;
|
||||
qse_httpd_serverstd_query_t orgquery;
|
||||
|
||||
qse_mchar_t* docroot;
|
||||
qse_mchar_t* realm;
|
||||
qse_mchar_t* auth;
|
||||
qse_mchar_t* dircss;
|
||||
qse_mchar_t* errcss;
|
||||
|
||||
qse_httpd_serverstd_index_t index;
|
||||
};
|
||||
|
||||
static int make_resource (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */
|
||||
{
|
||||
/* TODO: implement a better check that the
|
||||
* destination is not one of the local addresses */
|
||||
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsrc->type = QSE_HTTPD_RSRC_PROXY;
|
||||
rsrc->u.proxy.dst = client->orgdst_addr;
|
||||
rsrc->u.proxy.src = client->remote_addr;
|
||||
|
||||
if (rsrc->u.proxy.src.type == QSE_NWAD_IN4)
|
||||
rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */
|
||||
else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6)
|
||||
rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgmakersrc (httpd, client, req, rsrc) <= -1) return -1;
|
||||
if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR)
|
||||
{
|
||||
/* prohibit no directory listing */
|
||||
if (server_xtn->orgfreersrc)
|
||||
server_xtn->orgfreersrc (httpd, client, req, rsrc);
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 403;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_resource (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgfreersrc)
|
||||
server_xtn->orgfreersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
|
||||
if (server_xtn->docroot) qse_httpd_freemem (httpd, server_xtn->docroot);
|
||||
if (server_xtn->realm) qse_httpd_freemem (httpd, server_xtn->realm);
|
||||
if (server_xtn->auth) qse_httpd_freemem (httpd, server_xtn->auth);
|
||||
if (server_xtn->dircss) qse_httpd_freemem (httpd, server_xtn->dircss);
|
||||
if (server_xtn->errcss) qse_httpd_freemem (httpd, server_xtn->errcss);
|
||||
if (server_xtn->index.files) qse_httpd_freemem (httpd, server_xtn->index.files);
|
||||
}
|
||||
|
||||
static void reconfig_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
qse_printf (QSE_T("reconfiguring server.....\n"));
|
||||
}
|
||||
|
||||
static int query_server (
|
||||
qse_httpd_t* httpd, qse_httpd_server_t* server,
|
||||
qse_htre_t* req, const qse_mchar_t* xpath,
|
||||
qse_httpd_serverstd_query_code_t code, void* result)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case QSE_HTTPD_SERVERSTD_DOCROOT:
|
||||
*(const qse_mchar_t**)result = server_xtn->docroot;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_REALM:
|
||||
*(const qse_mchar_t**)result = server_xtn->realm;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_AUTH:
|
||||
*(const qse_mchar_t**)result = server_xtn->auth;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_DIRCSS:
|
||||
*(const qse_mchar_t**)result = server_xtn->dircss;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_ERRCSS:
|
||||
*(const qse_mchar_t**)result = server_xtn->errcss;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_INDEX:
|
||||
*(qse_httpd_serverstd_index_t*)result = server_xtn->index;
|
||||
return 0;
|
||||
|
||||
|
||||
#if 0
|
||||
case QSE_HTTPD_SERVERSTD_CGI:
|
||||
case QSE_HTTPD_SERVERSTD_MIME:
|
||||
#endif
|
||||
}
|
||||
|
||||
return server_xtn->orgquery (httpd, server, req, xpath, code, result);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int load_server (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list)
|
||||
{
|
||||
qse_httpd_serverstd_t server;
|
||||
qse_httpd_server_t* xserver;
|
||||
server_xtn_t* server_xtn;
|
||||
qse_xli_pair_t* pair;
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("bind"));
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: no bind specified for ....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pair->val->type != QSE_XLI_STR)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: non-string value for bind\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_memset (&server, 0, QSE_SIZEOF(server));
|
||||
if (qse_strtonwad (((qse_xli_str_t*)pair->val)->ptr, &server.nwad) <= -1)
|
||||
{
|
||||
/* TOOD: logging */
|
||||
qse_printf (QSE_T("WARNING: invalid value for bind - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
server.predetach = predetach_server;
|
||||
xserver = qse_httpd_attachserverstd (httpd, &server, QSE_SIZEOF(server_xtn_t));
|
||||
if (xserver == QSE_NULL)
|
||||
{
|
||||
/* TODO: logging */
|
||||
qse_printf (QSE_T("WARNING: failed to attach server\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, xserver);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, &server_xtn->orgquery);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_QUERY, query_server);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, &server_xtn->orgmakersrc);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_MAKERSRC, make_resource);
|
||||
|
||||
qse_httpd_getserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, &server_xtn->orgfreersrc);
|
||||
qse_httpd_setserveroptstd (httpd, xserver, QSE_HTTPD_SERVERSTD_FREERSRC, free_resource);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].docroot"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.docroot"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->docroot = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->docroot == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy docroot - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].realm"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.realm"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->realm = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->realm == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy realm - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].auth"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.auth"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
server_xtn->auth = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->auth == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy auth - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qse_mbschr (server_xtn->auth, QSE_MT(':')) == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: no colon in the auth string - [%hs]\n"), server_xtn->auth);
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.dir"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.dir"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
server_xtn->dircss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->dircss == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].css.error"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.css.error"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
/* TODO: use a table */
|
||||
|
||||
server_xtn->errcss = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
|
||||
if (server_xtn->errcss == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy dircss - %s\n"), ((qse_xli_str_t*)pair->val)->ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pair = qse_xli_findpairbyname (xli, list, QSE_T("host['*'].location['/'].index"));
|
||||
if (!pair) pair = qse_xli_findpairbyname (xli, QSE_NULL, QSE_T("default.index"));
|
||||
if (pair && pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
const qse_char_t* tmpptr, * tmpend;
|
||||
qse_size_t count;
|
||||
|
||||
tmpptr = ((qse_xli_str_t*)pair->val)->ptr;
|
||||
tmpend = tmpptr + ((qse_xli_str_t*)pair->val)->len;
|
||||
|
||||
for (count = 0; tmpptr < tmpend; count++) tmpptr += qse_strlen (tmpptr) + 1;
|
||||
|
||||
server_xtn->index.count = count;
|
||||
server_xtn->index.files = qse_httpd_strntombsdup (
|
||||
httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len);
|
||||
if (server_xtn->index.files == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("WARNING: fail to copy index\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_config (qse_httpd_t* httpd, qse_xli_t* xli, const qse_char_t* file)
|
||||
{
|
||||
qse_xli_iostd_t xli_in;
|
||||
qse_xli_pair_t* pair;
|
||||
int i;
|
||||
|
||||
xli_in.type = QSE_XLI_IOSTD_FILE;
|
||||
xli_in.u.file.path = file;
|
||||
xli_in.u.file.cmgr = QSE_NULL;
|
||||
|
||||
if (qse_xli_readstd (xli, &xli_in) <= -1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot load %s - %s\n"), xli_in.u.file.path, qse_xli_geterrmsg(xli));
|
||||
return - 1;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
qse_char_t buf[32];
|
||||
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("server[%d]"), i);
|
||||
pair = qse_xli_findpairbyname (xli, QSE_NULL, buf);
|
||||
if (pair == QSE_NULL) break;
|
||||
|
||||
if (pair->val->type != QSE_XLI_LIST)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("WARNING: non-list value for server\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
load_server (httpd, xli, (qse_xli_list_t*)pair->val);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("No valid server specified in %s\n"), xli_in.u.file.path);
|
||||
return - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
qse_xli_t* xli = QSE_NULL;
|
||||
qse_ntime_t tmout;
|
||||
int ret = -1, i;
|
||||
int trait;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
/* TODO: proper check... */
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
xli = qse_xli_openstd (0);
|
||||
if (xli == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open xli\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
qse_xli_getopt (xli, QSE_XLI_TRAIT, &trait);
|
||||
trait |= QSE_XLI_KEYNAME;
|
||||
qse_xli_setopt (xli, QSE_XLI_TRAIT, &trait);
|
||||
if (load_config (httpd, xli, argv[1]) <= -1) goto oops;
|
||||
|
||||
|
||||
g_httpd = httpd;
|
||||
setup_signal_handlers ();
|
||||
|
||||
qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0"));
|
||||
|
||||
qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
trait |= QSE_HTTPD_CGIERRTONUL;
|
||||
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
|
||||
tmout.sec = 10;
|
||||
tmout.nsec = 0;
|
||||
ret = qse_httpd_loopstd (httpd, &tmout);
|
||||
|
||||
restore_signal_handlers ();
|
||||
g_httpd = QSE_NULL;
|
||||
|
||||
if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error - %d\n"), qse_httpd_geterrnum (httpd));
|
||||
|
||||
oops:
|
||||
if (xli) qse_xli_close (xli);
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(_WIN32)
|
||||
char locale[100];
|
||||
UINT codepage;
|
||||
WSADATA wsadata;
|
||||
|
||||
codepage = GetConsoleOutputCP();
|
||||
if (codepage == CP_UTF8)
|
||||
{
|
||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||
setlocale (LC_ALL, locale);
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
}
|
||||
|
||||
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
setlocale (LC_ALL, "");
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
SSL_load_error_strings ();
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
|
||||
ret = qse_runmain (argc, argv, httpd_main);
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
/*ERR_remove_state ();*/
|
||||
ENGINE_cleanup ();
|
||||
ERR_free_strings ();
|
||||
EVP_cleanup ();
|
||||
CRYPTO_cleanup_all_ex_data ();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
WSACleanup ();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
44
qse/cmd/http/httpd.conf
Normal file
44
qse/cmd/http/httpd.conf
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# this is a sample configuration file for qsehttpd.
|
||||
#
|
||||
|
||||
server {
|
||||
bind = "0.0.0.0:80";
|
||||
|
||||
ssl {
|
||||
certificate {
|
||||
private = "xxxx";
|
||||
public = "xxxx";
|
||||
}
|
||||
}
|
||||
|
||||
root = "/home/www/default";
|
||||
option = "xxxx,xxx,xxxx";
|
||||
|
||||
realm {
|
||||
name = "xxxxxx";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
|
||||
cgi {
|
||||
suffix ".ant" = "xxxxx";
|
||||
suffix ".cgi";
|
||||
suffix ".nph";
|
||||
}
|
||||
|
||||
mime {
|
||||
suffix ".jpg" = "image/picture";
|
||||
suffix ".txt" = "text/plain";
|
||||
}
|
||||
|
||||
# virtual host
|
||||
host "www.google.com" {
|
||||
root = "/home/www/google";
|
||||
option = "xxx, xxx, xxxx";
|
||||
|
||||
realm {
|
||||
name = "www.google.com";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,296 +0,0 @@
|
||||
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <process.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSEXCEPTIONS
|
||||
# define INCL_ERRORS
|
||||
# include <os2.h>
|
||||
#elif defined(__DOS__)
|
||||
# include <dos.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct server_xtn_t server_xtn_t;
|
||||
struct server_xtn_t
|
||||
{
|
||||
int tproxy;
|
||||
int nodir; /* no directory listing */
|
||||
qse_httpd_server_cbstd_t* orgcbstd;
|
||||
};
|
||||
|
||||
static int makersrc (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */
|
||||
{
|
||||
/* TODO: implement a better check that the
|
||||
* destination is not one of the local addresses */
|
||||
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsrc->type = QSE_HTTPD_RSRC_PROXY;
|
||||
rsrc->u.proxy.dst = client->orgdst_addr;
|
||||
rsrc->u.proxy.src = client->remote_addr;
|
||||
|
||||
if (rsrc->u.proxy.src.type == QSE_NWAD_IN4)
|
||||
rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */
|
||||
else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6)
|
||||
rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgcbstd->makersrc (httpd, client, req, rsrc) <= -1) return -1;
|
||||
if (server_xtn->nodir && rsrc->type == QSE_HTTPD_RSRC_DIR)
|
||||
{
|
||||
/* prohibit no directory listing */
|
||||
if (server_xtn->orgcbstd->freersrc)
|
||||
server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc);
|
||||
rsrc->type = QSE_HTTPD_RSRC_ERR;
|
||||
rsrc->u.err.code = 403;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void freersrc (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, qse_httpd_rsrc_t* rsrc)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, client->server);
|
||||
|
||||
if (server_xtn->tproxy)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server_xtn->orgcbstd->freersrc)
|
||||
server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_server_t* attach_server (
|
||||
qse_httpd_t* httpd, qse_char_t* uri, qse_httpd_server_cbstd_t* cbstd)
|
||||
{
|
||||
qse_httpd_server_t* server;
|
||||
server_xtn_t* server_xtn;
|
||||
int tproxy = 0;
|
||||
|
||||
static qse_httpd_server_idxstd_t idxstd[] =
|
||||
{
|
||||
{ QSE_MT("index.cgi") },
|
||||
{ QSE_MT("index.html") },
|
||||
{ QSE_NULL }
|
||||
};
|
||||
|
||||
if (qse_strzcasecmp (uri, QSE_T("http-tproxy://"), 14) == 0)
|
||||
{
|
||||
tproxy = 1;
|
||||
qse_strcpy (&uri[4], &uri[11]);
|
||||
}
|
||||
|
||||
server = qse_httpd_attachserverstd (
|
||||
httpd, uri, QSE_NULL, QSE_SIZEOF(server_xtn_t));
|
||||
if (server == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* qse_httpd_getserverxtnstd() returns the pointer to
|
||||
* the extension space requested above, of the size
|
||||
* QSE_SIZEOF(server_xtn_t) */
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
server_xtn->tproxy = tproxy;
|
||||
|
||||
/* qse_httpd_getserverxtn() returns the pointer to the
|
||||
* extension space created by qse_httpd_attachserverstd()
|
||||
* internally.
|
||||
*/
|
||||
/* remember the callback set in qse_httpd_attachserverstd() */
|
||||
qse_httpd_getserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_CBSTD, (void**)&server_xtn->orgcbstd);
|
||||
/* override it with a new callback for chaining */
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_CBSTD, cbstd);
|
||||
|
||||
/* totally override idxstd without remembering the old idxstd */
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server,
|
||||
QSE_HTTPD_SERVER_IDXSTD, idxstd);
|
||||
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server, QSE_HTTPD_SERVER_DIRCSS,
|
||||
QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; } table { font-size: 0.9em; } td { white-space: nowrap; } td.size { text-align: right; }</style>"));
|
||||
|
||||
qse_httpd_setserveroptstd (
|
||||
httpd, server, QSE_HTTPD_SERVER_ERRCSS,
|
||||
QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; }</style>"));
|
||||
|
||||
return server;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
qse_ntime_t tmout;
|
||||
int ret = -1, i;
|
||||
int trait;
|
||||
static qse_httpd_server_cbstd_t cbstd = { makersrc, freersrc };
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri> ...\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (attach_server (httpd, argv[i], &cbstd) == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
g_httpd = httpd;
|
||||
signal (SIGINT, sigint);
|
||||
#if defined(SIGPIPE)
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0"));
|
||||
|
||||
trait = QSE_HTTPD_CGIERRTONUL;
|
||||
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
|
||||
tmout.sec = 10;
|
||||
tmout.nsec = 0;
|
||||
ret = qse_httpd_loopstd (httpd, &tmout);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
#if defined(SIGPIPE)
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
#endif
|
||||
g_httpd = QSE_NULL;
|
||||
|
||||
if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error\n"));
|
||||
|
||||
oops:
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(_WIN32)
|
||||
char locale[100];
|
||||
UINT codepage;
|
||||
WSADATA wsadata;
|
||||
|
||||
codepage = GetConsoleOutputCP();
|
||||
if (codepage == CP_UTF8)
|
||||
{
|
||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||
setlocale (LC_ALL, locale);
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
}
|
||||
|
||||
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
setlocale (LC_ALL, "");
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
SSL_load_error_strings ();
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
|
||||
ret = qse_runmain (argc, argv, httpd_main);
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
/*ERR_remove_state ();*/
|
||||
ENGINE_cleanup ();
|
||||
ERR_free_strings ();
|
||||
EVP_cleanup ();
|
||||
CRYPTO_cleanup_all_ex_data ();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
WSACleanup ();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@
|
||||
|
||||
static qse_char_t* g_input_file = QSE_NULL;
|
||||
static qse_char_t* g_output_file = QSE_NULL;
|
||||
static qse_char_t* g_lookup_key = QSE_NULL;
|
||||
static qse_ulong_t g_memlimit = 0;
|
||||
static int g_trait = 0;
|
||||
|
||||
@ -122,7 +123,7 @@ static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[])
|
||||
{
|
||||
const qse_char_t* b = qse_basename (argv[0]);
|
||||
|
||||
qse_fprintf (out, QSE_T("USAGE: %s [options] -f input-file\n"), b);
|
||||
qse_fprintf (out, QSE_T("USAGE: %s [options] -f input-file [key]\n"), b);
|
||||
|
||||
qse_fprintf (out, QSE_T("options as follows:\n"));
|
||||
qse_fprintf (out, QSE_T(" -h/--help show this message\n"));
|
||||
@ -201,7 +202,7 @@ static int handle_args (int argc, qse_char_t* argv[])
|
||||
break;
|
||||
|
||||
case QSE_T('n'):
|
||||
g_trait |= QSE_XLI_NAMEDKEY;
|
||||
g_trait |= QSE_XLI_KEYNAME;
|
||||
break;
|
||||
|
||||
case QSE_T('m'):
|
||||
@ -251,6 +252,14 @@ static int handle_args (int argc, qse_char_t* argv[])
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (opt.ind < argc) g_lookup_key = argv[opt.ind++];
|
||||
|
||||
if (opt.ind < argc)
|
||||
{
|
||||
print_usage (QSE_STDERR, argc, argv);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
oops:
|
||||
@ -287,7 +296,6 @@ static int xli_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_mmgr_t* mmgr = QSE_MMGR_GETDFL();
|
||||
qse_xli_t* xli = QSE_NULL;
|
||||
qse_fs_t* fs = QSE_NULL;
|
||||
qse_xli_iostd_t in, out;
|
||||
int ret = -1;
|
||||
|
||||
@ -361,11 +369,41 @@ static int xli_main (int argc, qse_char_t* argv[])
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (g_lookup_key)
|
||||
{
|
||||
qse_xli_pair_t* pair;
|
||||
pair = qse_xli_findpairbyname (xli, QSE_NULL, g_lookup_key);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("ERROR: cannot find %s - %s \n"),
|
||||
g_lookup_key,
|
||||
qse_xli_geterrmsg(xli)
|
||||
);
|
||||
goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pair->val->type == QSE_XLI_STR)
|
||||
{
|
||||
qse_xli_str_t* str = (qse_xli_str_t*)pair->val;
|
||||
qse_printf (QSE_T("[%.*s]\n"), (int)str->len, str->ptr);
|
||||
}
|
||||
else if (pair->val->type == QSE_XLI_NIL)
|
||||
{
|
||||
qse_printf (QSE_T("#NIL\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("#LIST\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
oops:
|
||||
if (xli) qse_xli_close (xli);
|
||||
if (fs) qse_fs_close (fs);
|
||||
if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx);
|
||||
|
||||
#if defined(QSE_BUILD_DEBUG)
|
||||
|
Reference in New Issue
Block a user