added file-access and dir-access to cmd/http/httpd.c

This commit is contained in:
hyung-hwan 2013-02-21 15:00:08 +00:00
parent b677b4a892
commit b420a7c0dc
10 changed files with 721 additions and 188 deletions

View File

@ -0,0 +1,23 @@
###############################################
# this file defines various mime types that
# can be @included in a mime block.
#
# file entries are inspected first.
# then suffix entries are inspected.
# 'other' comes the last.
###############################################
suffix ".htm" = "text/html";
suffix ".html" = "text/html";
suffix ".txt" = "text/plain";
suffix ".css" = "text/css";
suffix ".xml" = "text/xml";
suffix ".js" = "application/javascript";
suffix ".jpg" = "image/jpeg";
suffix ".png" = "image/png";
# use file to set the type for a particular file
#file "x.jpg" = "specific mime type";
# other can override the built-in default.
#other = "default mime type";

View File

@ -8,6 +8,7 @@
#include <qse/cmn/mbwc.h> #include <qse/cmn/mbwc.h>
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
#include <qse/cmn/path.h> #include <qse/cmn/path.h>
#include <qse/cmn/opt.h>
#include <signal.h> #include <signal.h>
#include <locale.h> #include <locale.h>
@ -27,6 +28,7 @@
#else #else
# include <unistd.h> # include <unistd.h>
# include <errno.h> # include <errno.h>
# include <fcntl.h>
#endif #endif
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
@ -38,17 +40,34 @@
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static qse_httpd_t* g_httpd = QSE_NULL; static qse_httpd_t* g_httpd = QSE_NULL;
static const qse_char_t* g_cfgfile = QSE_NULL;
static int g_daemon = 0;
static void sigint (int sig) /* --------------------------------------------------------------------- */
typedef struct httpd_xtn_t httpd_xtn_t;
struct httpd_xtn_t
{
const qse_char_t* cfgfile;
qse_xli_t* xli;
qse_httpd_impede_t orgimpede;
int impede_code;
};
/* --------------------------------------------------------------------- */
static void sig_stop (int sig)
{ {
if (g_httpd) qse_httpd_stop (g_httpd); if (g_httpd) qse_httpd_stop (g_httpd);
} }
static void sighup (int sig) static void sig_reconf (int sig)
{ {
if (g_httpd) if (g_httpd)
{ {
/* arrange to intefere with httpd to perform reconfiguration */ httpd_xtn_t* httpd_xtn;
httpd_xtn = qse_httpd_getxtnstd (g_httpd);
httpd_xtn->impede_code = sig;
qse_httpd_impede (g_httpd); qse_httpd_impede (g_httpd);
} }
} }
@ -59,15 +78,25 @@ static void setup_signal_handlers ()
#if defined(SIGINT) #if defined(SIGINT)
qse_memset (&act, 0, QSE_SIZEOF(act)); qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = sigint; act.sa_handler = sig_stop;
sigaction (SIGINT, &act, QSE_NULL); sigaction (SIGINT, &act, QSE_NULL);
#endif #endif
#if defined(SIGTERM)
qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = sig_stop;
sigaction (SIGTERM, &act, QSE_NULL);
#endif
#if defined(SIGHUP) #if defined(SIGHUP)
qse_memset (&act, 0, QSE_SIZEOF(act)); qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = sighup; act.sa_handler = sig_reconf;
sigaction (SIGHUP, &act, QSE_NULL); sigaction (SIGHUP, &act, QSE_NULL);
#endif #endif
#if defined(SIGUSR1)
qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = sig_reconf;
sigaction (SIGUSR1, &act, QSE_NULL);
#endif
#if defined(SIGPIPE) #if defined(SIGPIPE)
qse_memset (&act, 0, QSE_SIZEOF(act)); qse_memset (&act, 0, QSE_SIZEOF(act));
@ -85,12 +114,22 @@ static void restore_signal_handlers ()
act.sa_handler = SIG_DFL; act.sa_handler = SIG_DFL;
sigaction (SIGINT, &act, QSE_NULL); sigaction (SIGINT, &act, QSE_NULL);
#endif #endif
#if defined(SIGTERM)
qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = SIG_DFL;
sigaction (SIGTERM, &act, QSE_NULL);
#endif
#if defined(SIGHUP) #if defined(SIGHUP)
qse_memset (&act, 0, QSE_SIZEOF(act)); qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = SIG_DFL; act.sa_handler = SIG_DFL;
sigaction (SIGHUP, &act, QSE_NULL); sigaction (SIGHUP, &act, QSE_NULL);
#endif #endif
#if defined(SIGUSR1)
qse_memset (&act, 0, QSE_SIZEOF(act));
act.sa_handler = SIG_DFL;
sigaction (SIGUSR1, &act, QSE_NULL);
#endif
#if defined(SIGPIPE) #if defined(SIGPIPE)
qse_memset (&act, 0, QSE_SIZEOF(act)); qse_memset (&act, 0, QSE_SIZEOF(act));
@ -99,6 +138,43 @@ static void restore_signal_handlers ()
#endif #endif
} }
static int daemonize (int devnull)
{
#if defined(HAVE_FORK)
switch (fork())
{
case -1: return -1;
case 0: break; /* child */
default: _exit (0); /* parent */
}
if (setsid () <= -1) return -1;
/*umask (0);*/
chdir ("/");
if (devnull)
{
/* redirect stdin/out/err to /dev/null */
int fd = open ("/dev/null", O_RDWR);
if (fd >= 0)
{
dup2 (fd, 0);
dup2 (fd, 1);
dup2 (fd, 2);
close (fd);
}
}
return 0;
#else
return -1;
#endif
}
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
enum enum
@ -117,8 +193,7 @@ struct cgi_t
{ {
enum { enum {
CGI_SUFFIX, CGI_SUFFIX,
CGI_FILE, CGI_NAME,
CGI_MAX CGI_MAX
} type; } type;
@ -133,8 +208,8 @@ struct mime_t
{ {
enum { enum {
MIME_SUFFIX, MIME_SUFFIX,
MIME_FILE, MIME_NAME,
MIME_OTHER,
MIME_MAX MIME_MAX
} type; } type;
@ -144,6 +219,23 @@ struct mime_t
struct mime_t* next; struct mime_t* next;
}; };
struct access_t
{
/* TODO: support more types like ACCESS_GLOB
not-only the base name, find a way to use query path or xpath */
enum {
ACCESS_SUFFIX,
ACCESS_NAME,
ACCESS_OTHER,
ACCESS_MAX
} type;
qse_mchar_t* spec;
int value;
struct access_t* next;
};
typedef struct server_xtn_t server_xtn_t; typedef struct server_xtn_t server_xtn_t;
struct server_xtn_t struct server_xtn_t
{ {
@ -176,15 +268,14 @@ struct server_xtn_t
struct mime_t* head; struct mime_t* head;
struct mime_t* tail; struct mime_t* tail;
} mime[MIME_MAX]; } mime[MIME_MAX];
struct
{
struct access_t* head;
struct access_t* tail;
} access[2][ACCESS_MAX];
}; };
typedef struct httpd_xtn_t httpd_xtn_t;
struct httpd_xtn_t
{
const qse_char_t* cfgfile;
qse_xli_t* xli;
qse_httpd_impede_t orgimpede;
};
static int make_resource ( static int make_resource (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
@ -253,7 +344,7 @@ static void free_resource (
static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server) static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
server_xtn_t* server_xtn; server_xtn_t* server_xtn;
qse_size_t i; qse_size_t i, j;
server_xtn = qse_httpd_getserverstdxtn (httpd, server); server_xtn = qse_httpd_getserverstdxtn (httpd, server);
@ -306,6 +397,25 @@ static void clear_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server)
server_xtn->mime[i].head = QSE_NULL; server_xtn->mime[i].head = QSE_NULL;
server_xtn->mime[i].tail = QSE_NULL; server_xtn->mime[i].tail = QSE_NULL;
} }
for (j = 0; j < QSE_COUNTOF(server_xtn->access); j++)
{
for (i = 0; i < QSE_COUNTOF(server_xtn->access[j]); i++)
{
struct access_t* access = server_xtn->access[j][i].head;
while (access)
{
struct access_t* x = access;
access = x->next;
if (x->spec) qse_httpd_freemem (httpd, x->spec);
if (x) qse_httpd_freemem (httpd, x);
}
server_xtn->access[j][i].head = QSE_NULL;
server_xtn->access[j][i].tail = QSE_NULL;
}
}
} }
static void detach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) static void detach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
@ -369,8 +479,8 @@ static int query_server (
struct cgi_t* cgi; struct cgi_t* cgi;
for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next) for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next)
{ {
if ((cgi->type == MIME_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) || if ((cgi->type == CGI_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) ||
(cgi->type == MIME_FILE && qse_mbscmp (xpath_base, cgi->spec) == 0)) (cgi->type == CGI_NAME && qse_mbscmp (xpath_base, cgi->spec) == 0))
{ {
scgi->cgi = 1; scgi->cgi = 1;
scgi->nph = cgi->nph; scgi->nph = cgi->nph;
@ -386,7 +496,7 @@ static int query_server (
case QSE_HTTPD_SERVERSTD_MIME: case QSE_HTTPD_SERVERSTD_MIME:
{ {
qse_size_t i; qse_size_t i;
qse_mchar_t* xpath_base; const qse_mchar_t* xpath_base;
xpath_base = qse_mbsbasename (xpath); xpath_base = qse_mbsbasename (xpath);
@ -397,7 +507,8 @@ static int query_server (
for (mime = server_xtn->mime[i].head; mime; mime = mime->next) for (mime = server_xtn->mime[i].head; mime; mime = mime->next)
{ {
if ((mime->type == MIME_SUFFIX && qse_mbsend (xpath_base, mime->spec)) || if ((mime->type == MIME_SUFFIX && qse_mbsend (xpath_base, mime->spec)) ||
(mime->type == MIME_FILE && qse_mbscmp (xpath_base, mime->spec) == 0)) (mime->type == MIME_NAME && qse_mbscmp (xpath_base, mime->spec) == 0) ||
mime->type == MIME_OTHER)
{ {
*(const qse_mchar_t**)result = mime->value; *(const qse_mchar_t**)result = mime->value;
return 0; return 0;
@ -406,6 +517,35 @@ static int query_server (
} }
return 0; return 0;
} }
case QSE_HTTPD_SERVERSTD_DIRACC:
case QSE_HTTPD_SERVERSTD_FILEACC:
{
qse_size_t i;
const qse_mchar_t* xpath_base;
int id;
id = (code == QSE_HTTPD_SERVERSTD_DIRACC)? 0: 1;
xpath_base = qse_mbsbasename (xpath);
*(int*)result = 200;
for (i = 0; i < QSE_COUNTOF(server_xtn->access[id]); i++)
{
struct access_t* access;
for (access = server_xtn->access[id][i].head; access; access = access->next)
{
if ((access->type == ACCESS_SUFFIX && qse_mbsend (xpath_base, access->spec)) ||
(access->type == ACCESS_NAME && qse_mbscmp (xpath_base, access->spec) == 0) ||
access->type == ACCESS_OTHER)
{
*(int*)result = access->value;
return 0;
}
}
}
return 0;
}
} }
return server_xtn->orgquery (httpd, server, req, xpath, code, result); return server_xtn->orgquery (httpd, server, req, xpath, code, result);
@ -498,9 +638,9 @@ static int load_server_config (
{ {
type = CGI_SUFFIX; type = CGI_SUFFIX;
} }
else if (qse_strcmp (pair->key, QSE_T("file")) == 0) else if (qse_strcmp (pair->key, QSE_T("name")) == 0)
{ {
type = CGI_FILE; type = CGI_NAME;
} }
else continue; else continue;
@ -570,13 +710,14 @@ static int load_server_config (
if (atom->type != QSE_XLI_PAIR) continue; if (atom->type != QSE_XLI_PAIR) continue;
pair = (qse_xli_pair_t*)atom; pair = (qse_xli_pair_t*)atom;
if (pair->key && pair->name && pair->val->type == QSE_XLI_STR) if (pair->key && pair->val->type == QSE_XLI_STR)
{ {
struct mime_t* mime; struct mime_t* mime;
int type; int type;
if (qse_strcmp (pair->key, QSE_T("suffix")) == 0) type = MIME_SUFFIX; if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = MIME_SUFFIX;
else if (qse_strcmp (pair->key, QSE_T("file")) == 0) type = MIME_FILE; else if (qse_strcmp (pair->key, QSE_T("name")) == 0 && pair->name) type = MIME_NAME;
else if (qse_strcmp (pair->key, QSE_T("other")) == 0 && !pair->name) type = MIME_OTHER;
else continue; else continue;
mime = qse_httpd_callocmem (httpd, QSE_SIZEOF(*mime)); mime = qse_httpd_callocmem (httpd, QSE_SIZEOF(*mime));
@ -594,20 +735,16 @@ static int load_server_config (
qse_printf (QSE_T("ERROR: memory failure in copying mime\n")); qse_printf (QSE_T("ERROR: memory failure in copying mime\n"));
return -1; return -1;
} }
if (pair->val->type == QSE_XLI_STR)
mime->value = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr);
if (!mime->value)
{ {
mime->value = qse_httpd_strtombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr); qse_httpd_freemem (httpd, mime->spec);
if (!mime->value) qse_httpd_freemem (httpd, mime);
{ qse_printf (QSE_T("ERROR: memory failure in copying mime\n"));
qse_httpd_freemem (httpd, mime->spec); return -1;
qse_httpd_freemem (httpd, mime);
qse_printf (QSE_T("ERROR: memory failure in copying mime\n"));
return -1;
}
/* TODO: more sanity check */
} }
if (server_xtn->mime[type].tail) if (server_xtn->mime[type].tail)
server_xtn->mime[type].tail->next = mime; server_xtn->mime[type].tail->next = mime;
else else
@ -617,6 +754,76 @@ static int load_server_config (
} }
} }
for (i = 0; i < 2; i++)
{
static struct
{
const qse_char_t* x;
const qse_char_t* y;
} acc_items[] =
{
{ QSE_T("host['*'].location['/'].dir-access"), QSE_T("default.dir-access") },
{ QSE_T("host['*'].location['/'].file-access"), QSE_T("default.file-access") },
};
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, acc_items[i].x);
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, acc_items[i].y);
if (pair && pair->val->type == QSE_XLI_LIST)
{
qse_xli_list_t* acclist = (qse_xli_list_t*)pair->val;
for (atom = acclist->head; atom; atom = atom->next)
{
if (atom->type != QSE_XLI_PAIR) continue;
pair = (qse_xli_pair_t*)atom;
if (pair->key && pair->val->type == QSE_XLI_STR)
{
struct access_t* acc;
const qse_char_t* tmp;
int type, value;
if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = ACCESS_SUFFIX;
else if (qse_strcmp (pair->key, QSE_T("name")) == 0 && pair->name) type = ACCESS_NAME;
else if (qse_strcmp (pair->key, QSE_T("other")) == 0 && !pair->name) type = ACCESS_OTHER;
else continue;
tmp = ((qse_xli_str_t*)pair->val)->ptr;
if (qse_strcmp (tmp, QSE_T("noent")) == 0) value = 404;
else if (qse_strcmp (tmp, QSE_T("forbid")) == 0) value = 403;
else if (qse_strcmp (tmp, QSE_T("ok")) == 0) value = 200;
else continue;
/* TODO: more sanity check */
acc = qse_httpd_callocmem (httpd, QSE_SIZEOF(*acc));
if (acc == QSE_NULL)
{
qse_printf (QSE_T("ERROR: memory failure in copying acc\n"));
return -1;
}
acc->type = type;
if (pair->name)
{
acc->spec = qse_httpd_strtombsdup (httpd, pair->name);
if (!acc->spec)
{
qse_httpd_freemem (httpd, acc);
qse_printf (QSE_T("ERROR: memory failure in copying access\n"));
return -1;
}
}
acc->value = value;
if (server_xtn->access[i][type].tail)
server_xtn->access[i][type].tail->next = acc;
else
server_xtn->access[i][type].head = acc;
server_xtn->access[i][type].tail = acc;
}
}
}
}
/* perform more sanity check */ /* perform more sanity check */
if (qse_mbschr (server_xtn->scfg[SCFG_AUTH], QSE_MT(':')) == QSE_NULL) if (qse_mbschr (server_xtn->scfg[SCFG_AUTH], QSE_MT(':')) == QSE_NULL)
{ {
@ -844,58 +1051,171 @@ static void impede_httpd (qse_httpd_t* httpd)
if (httpd_xtn->orgimpede) httpd_xtn->orgimpede (httpd); if (httpd_xtn->orgimpede) httpd_xtn->orgimpede (httpd);
} }
static void logact_httpd (qse_httpd_t* httpd, qse_httpd_act_t* act) static void logact_httpd (qse_httpd_t* httpd, const qse_httpd_act_t* act)
{ {
httpd_xtn_t* httpd_xtn; httpd_xtn_t* httpd_xtn;
qse_char_t tmp[256]; qse_char_t tmp[128], tmp2[128], tmp3[128];
httpd_xtn = qse_httpd_getxtnstd (httpd); httpd_xtn = qse_httpd_getxtnstd (httpd);
switch (act->code) switch (act->code)
{ {
case QSE_HTTPD_ACCEPT_CLIENT: case QSE_HTTPD_CATCH_MERRMSG:
qse_printf (QSE_T("ERROR: %hs\n"), act->u.merrmsg);
break; break;
case QSE_HTTPD_CATCH_MDBGMSG:
qse_printf (QSE_T("DEBUG: %hs\n"), act->u.mdbgmsg);
break;
case QSE_HTTPD_ACCEPT_CLIENT:
qse_nwadtostr (&act->u.client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL);
qse_nwadtostr (&act->u.client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL);
qse_nwadtostr (&act->u.client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL);
qse_printf (QSE_T("accepted client %s(%s) from %s\n"), tmp, tmp2, tmp3);
case QSE_HTTPD_PURGE_CLIENT: case QSE_HTTPD_PURGE_CLIENT:
qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL);
qse_printf (QSE_T("purged client from %s\n"), tmp); qse_printf (QSE_T("purged client - %s\n"), tmp);
break;
case QSE_HTTPD_READERR_CLIENT:
qse_nwadtostr (&act->u.client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL);
qse_printf (QSE_T("failed to read client - %s\n"), tmp);
break; break;
} }
} }
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static void print_version (void)
{
qse_printf (QSE_T("QSEHTTPD version %hs\n"), QSE_PACKAGE_VERSION);
}
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] -c file\n"), b);
qse_fprintf (out, QSE_T(" %s [options] --config-file file\n"), b);
qse_fprintf (out, QSE_T("options as follows:\n"));
qse_fprintf (out, QSE_T(" -h/--help show this message\n"));
qse_fprintf (out, QSE_T(" --version show version\n"));
qse_fprintf (out, QSE_T(" -c/--config-file file specify a configuration file\n"));
qse_fprintf (out, QSE_T(" -d/--daemon run in the background\n"));
}
static int handle_args (int argc, qse_char_t* argv[])
{
static qse_opt_lng_t lng[] =
{
{ QSE_T(":config-file"), QSE_T('c') },
{ QSE_T("daemon"), QSE_T('d') },
{ QSE_T("help"), QSE_T('h') },
{ QSE_T("version"), QSE_T('\0') },
{ QSE_NULL, QSE_T('\0') }
};
static qse_opt_t opt =
{
QSE_T("c:dh"),
lng
};
qse_cint_t c;
while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
{
switch (c)
{
default:
goto wrongusage;
case QSE_T('?'):
qse_fprintf (QSE_STDERR,
QSE_T("ERROR: bad option - %c\n"),
opt.opt
);
goto wrongusage;
case QSE_T(':'):
qse_fprintf (QSE_STDERR,
QSE_T("ERROR: bad parameter for %c\n"),
opt.opt
);
goto wrongusage;
case QSE_T('c'):
g_cfgfile = opt.arg;
break;
case QSE_T('d'):
g_daemon = 1;
break;
case QSE_T('h'):
print_usage (QSE_STDOUT, argc, argv);
return 0;
case QSE_T('\0'):
{
if (qse_strcmp(opt.lngopt, QSE_T("version")) == 0)
{
print_version ();
return 0;
}
break;
}
}
}
if (opt.ind < argc || g_cfgfile == QSE_NULL) goto wrongusage;
return 1;
wrongusage:
print_usage (QSE_STDERR, argc, argv);
return -1;
}
static int httpd_main (int argc, qse_char_t* argv[]) static int httpd_main (int argc, qse_char_t* argv[])
{ {
qse_httpd_t* httpd = QSE_NULL; qse_httpd_t* httpd = QSE_NULL;
httpd_xtn_t* httpd_xtn; httpd_xtn_t* httpd_xtn;
qse_ntime_t tmout; qse_ntime_t tmout;
int trait, ret = -1; int trait, ret;
qse_httpd_rcb_t rcb; qse_httpd_rcb_t rcb;
if (argc != 2) ret = handle_args (argc, argv);
{ if (ret <= -1) return -1;
/* TODO: proper check... */ if (ret == 0) return 0;
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]);
goto oops;
}
httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t)); httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t));
if (httpd == QSE_NULL) if (httpd == QSE_NULL)
{ {
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n")); qse_fprintf (QSE_STDERR, QSE_T("ERROR: Cannot open httpd\n"));
goto oops; goto oops;
} }
httpd_xtn = qse_httpd_getxtnstd (httpd); httpd_xtn = qse_httpd_getxtnstd (httpd);
httpd_xtn->cfgfile = argv[1]; httpd_xtn->cfgfile = g_cfgfile;
if (load_config (httpd) <= -1) goto oops; if (load_config (httpd) <= -1) goto oops;
if (g_daemon)
{
if (daemonize (1) <= -1)
{
qse_fprintf (QSE_STDERR, QSE_T("ERROR: Cannot daemonize\n"));
goto oops;
}
}
g_httpd = httpd; g_httpd = httpd;
setup_signal_handlers (); setup_signal_handlers ();
qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait); qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait);
trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_ENABLELOG; trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_LOGACT;
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait); qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
tmout.sec = 10; tmout.sec = 10;
@ -921,7 +1241,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
oops: oops:
if (httpd) qse_httpd_close (httpd); if (httpd) qse_httpd_close (httpd);
return ret; return -1;
} }
int qse_main (int argc, qse_achar_t* argv[]) int qse_main (int argc, qse_achar_t* argv[])

View File

@ -2,43 +2,119 @@
# this is a sample configuration file for qsehttpd. # this is a sample configuration file for qsehttpd.
# #
server { default {
bind = "0.0.0.0:80"; # the default name is used in http headers and in pages
# generated by httpd.
name = "QSEHTTPD v1";
ssl { docroot = "/";
certificate {
private = "xxxx";
public = "xxxx";
}
}
root = "/home/www/default"; realm = "default realm";
option = "xxxx,xxx,xxxx"; auth = "username:password";
index = "index.ant",
realm { "index.html",
name = "xxxxxx"; "index.cgi";
password = "zzzzzzzzzzzzzzzz";
}
cgi { cgi {
suffix ".ant" = "xxxxx"; name "t3.nph" = "nph";
suffix ".cgi"; suffix ".cgi";
suffix ".nph"; suffix ".ant" = "nph", "";
suffix ".awk" = "cgi", "/usr/bin/qseawk -f";
# glob is not supported yet
# glob "x*.xxx";
} }
mime { mime {
suffix ".jpg" = "image/picture"; @include "httpd-mime.conf";
suffix ".txt" = "text/plain";
} }
# virtual host # control access to directories
host "www.google.com" { dir-access {
root = "/home/www/google"; # suffix ".xxxx" = ok;
option = "xxx, xxx, xxxx"; # name "xxxxx" = ok;
other = noent;
realm {
name = "www.google.com";
password = "zzzzzzzzzzzzzzzz";
}
} }
# control access to normal files.
# cgi scripts are not control by these.
file-access {
suffix ".html" = ok;
suffix ".css" = ok;
suffix ".js" = ok;
suffix ".png" = ok;
suffix ".jpg" = ok;
other = noent;
}
dir-css = "<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>";
error-css = "<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>";
}
server {
bind = "0.0.0.0:1999";
# ssl is not supported yet.
#ssl {
# certificate {
# private = "xxxx";
# public = "xxxx";
# }
#}
host "*" {
location "/" {
# the location-specific name is used in pages
# generated by httpd, not in http headers.
# you can't override the default name for use in
# http headers.
#name = "QSEHTTPD v1";
# uncomment the followng block to override the default.
#docroot = "/var/www";
# uncomment the followng block to override the default.
# if you want to disable authentication while the default
# enables it, don't put a value like 'realm;'
#realm = "default realm";
#auth = "username:password";
# uncomment the following block to override the default
#index = "index.cgi", "index.html";
# uncomment the following block to override the default
#cgi {
# suffix ".cgi";
# suffix ".awk" = "/usr/bin/qseawk -f";
#}
# uncomment the following block to override the default.
#mime {
# suffix ".htm" = "text/html";
# suffix ".html" = "text/html";
# suffix ".txt" = "text/html";
# suffix ".css" = "text/css";
# suffix ".xml" = "text/xml";
# suffix ".js" = "application/javascript";
# suffix ".jpg" = "image/jpeg";
# suffix ".png" = "image/png";
#}
}
# other locations than / are not supported yet.
#location "/help" {
#}
}
# virtual hosts are not supported yet.
#host "www.google.com" {
# location "/" {
# docroot = "/home/www/google";
# auth {
# realm = "jjjjjjjj";
# name = "www.google.com";
# password = "zzzzzzzzzzzzzzzz";
# }
# }
#}
} }

View File

@ -75,7 +75,7 @@ enum qse_httpd_trait_t
QSE_HTTPD_CGIERRTONUL = (1 << 1), QSE_HTTPD_CGIERRTONUL = (1 << 1),
QSE_HTTPD_CGINOCLOEXEC = (1 << 2), QSE_HTTPD_CGINOCLOEXEC = (1 << 2),
QSE_HTTPD_CGINOCHUNKED = (1 << 3), QSE_HTTPD_CGINOCHUNKED = (1 << 3),
QSE_HTTPD_ENABLELOG = (1 << 4) QSE_HTTPD_LOGACT = (1 << 4)
}; };
typedef enum qse_httpd_trait_t qse_httpd_trait_t; typedef enum qse_httpd_trait_t qse_httpd_trait_t;
@ -115,8 +115,8 @@ typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
struct qse_httpd_dirent_t struct qse_httpd_dirent_t
{ {
qse_mchar_t* name; const qse_mchar_t* name;
qse_httpd_stat_t stat; qse_httpd_stat_t stat;
}; };
typedef struct qse_httpd_scb_t qse_httpd_scb_t; typedef struct qse_httpd_scb_t qse_httpd_scb_t;
@ -266,8 +266,11 @@ typedef void (*qse_httpd_impede_t) (
enum qse_httpd_act_code_t enum qse_httpd_act_code_t
{ {
QSE_HTTPD_CATCH_MERRMSG,
QSE_HTTPD_CATCH_MDBGMSG,
QSE_HTTPD_ACCEPT_CLIENT, QSE_HTTPD_ACCEPT_CLIENT,
QSE_HTTPD_PURGE_CLIENT, QSE_HTTPD_PURGE_CLIENT,
QSE_HTTPD_READERR_CLIENT
}; };
typedef enum qse_httpd_act_code_t qse_httpd_act_code_t; typedef enum qse_httpd_act_code_t qse_httpd_act_code_t;
@ -277,6 +280,8 @@ struct qse_httpd_act_t
union union
{ {
qse_httpd_client_t* client; qse_httpd_client_t* client;
qse_mchar_t merrmsg[128];
qse_mchar_t mdbgmsg[128];
} u; } u;
}; };
typedef struct qse_httpd_act_t qse_httpd_act_t; typedef struct qse_httpd_act_t qse_httpd_act_t;

View File

@ -385,8 +385,13 @@ static int get_highest_fd (void)
#endif #endif
} }
else fd = rlim.rlim_max; else fd = rlim.rlim_max;
if (fd == -1) fd = 1024; /* fallback */
/* F_MAXFD is the highest fd. but RLIMIT_NOFILE and
* _SC_OPEN_MAX returnes the maximum number of file
* descriptors. make adjustment */
if (fd > 0) fd--;
} }
if (fd == -1) fd = 1024; /* fallback */
return fd; return fd;
} }

View File

@ -23,6 +23,7 @@
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
#include <qse/cmn/pio.h> #include <qse/cmn/pio.h>
#include <qse/cmn/fmt.h> #include <qse/cmn/fmt.h>
#include <qse/cmn/path.h>
#include <stdio.h> /* TODO: remove this */ #include <stdio.h> /* TODO: remove this */
@ -196,6 +197,17 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c
return 0; return 0;
} }
static void log_cgi_script_error (task_cgi_t* cgi, const qse_mchar_t* shortmsg)
{
qse_httpd_act_t msg;
qse_size_t pos = 0;
msg.code = QSE_HTTPD_CATCH_MERRMSG;
pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, shortmsg);
pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, cgi->script);
cgi->httpd->opt.rcb.logact (cgi->httpd, &msg);
}
static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req)
{ {
cgi_script_htrd_xtn_t* xtn; cgi_script_htrd_xtn_t* xtn;
@ -355,8 +367,9 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req)
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
cgi->script_output_received > cgi->script_output_length) cgi->script_output_received > cgi->script_output_length)
{ {
/* TODO: cgi returning too much data... something is wrong in CGI */ /* cgi returning too much data... something is wrong in CGI */
qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n")); if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi redundant output - "));
cgi->httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ cgi->httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */
return -1; return -1;
} }
@ -501,8 +514,10 @@ static int cgi_snatch_client_input (
task = (qse_httpd_task_t*)ctx; task = (qse_httpd_task_t*)ctx;
cgi = (task_cgi_t*)task->ctx; cgi = (task_cgi_t*)task->ctx;
#if 0
if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr); if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr);
else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
#endif
QSE_ASSERT (cgi->req); QSE_ASSERT (cgi->req);
QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL));
@ -587,7 +602,9 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
/* output pipe to child */ /* output pipe to child */
task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE;
#if 0
qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr); qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr);
#endif
} }
return 0; return 0;
@ -608,7 +625,9 @@ static void cgi_forward_client_input_to_script (
{ {
/* a forwarding error has occurred previously. /* a forwarding error has occurred previously.
* clear the forwarding buffer */ * clear the forwarding buffer */
#if 0
qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
#endif
qse_mbs_clear (cgi->reqfwdbuf); qse_mbs_clear (cgi->reqfwdbuf);
} }
else else
@ -624,9 +643,11 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
{ {
forward: forward:
/* writable */ /* writable */
#if 0
qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
(int)QSE_MBS_LEN(cgi->reqfwdbuf), (int)QSE_MBS_LEN(cgi->reqfwdbuf),
QSE_MBS_PTR(cgi->reqfwdbuf)); QSE_MBS_PTR(cgi->reqfwdbuf));
#endif
n = qse_pio_write ( n = qse_pio_write (
&cgi->pio, QSE_PIO_IN, &cgi->pio, QSE_PIO_IN,
QSE_MBS_PTR(cgi->reqfwdbuf), QSE_MBS_PTR(cgi->reqfwdbuf),
@ -647,8 +668,9 @@ to the head all the time.. grow the buffer to a certain limit. */
if (n <= -1) if (n <= -1)
{ {
qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n")); if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
/* TODO: logging ... */ log_cgi_script_error (cgi, QSE_MT("cgi pio write error - "));
cgi->reqflags |= CGI_REQ_FWDERR; cgi->reqflags |= CGI_REQ_FWDERR;
qse_mbs_clear (cgi->reqfwdbuf); qse_mbs_clear (cgi->reqfwdbuf);
@ -679,7 +701,9 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n"));
* there is nothing more to forward in the forwarding buffer. * there is nothing more to forward in the forwarding buffer.
* clear the relay and write triggers for the time being. * clear the relay and write triggers for the time being.
*/ */
#if 0
qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n")); qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n"));
#endif
QSE_ASSERT (cgi->req == QSE_NULL); QSE_ASSERT (cgi->req == QSE_NULL);
/* mark the end of input to the child explicitly. */ /* mark the end of input to the child explicitly. */
@ -919,8 +943,6 @@ static void task_fini_cgi (
QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL)); QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL));
qse_htre_unsetconcb (cgi->req); qse_htre_unsetconcb (cgi->req);
} }
qse_printf (QSE_T("task_fini_cgi\n"));
} }
static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer ( static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer (
@ -934,6 +956,10 @@ static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer (
QSE_SIZEOF(cgi->buf) - cgi->buflen QSE_SIZEOF(cgi->buf) - cgi->buflen
); );
if (n > 0) cgi->buflen += n; if (n > 0) cgi->buflen += n;
if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return n; return n;
} }
@ -942,13 +968,16 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client (
{ {
qse_ssize_t n; qse_ssize_t n;
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen);
if (n > 0) if (n > 0)
{ {
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
cgi->buflen -= n; cgi->buflen -= n;
} }
if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi write error to client - "));
return n; return n;
} }
@ -971,13 +1000,11 @@ static int task_main_cgi_5 (
if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||
(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{ {
qse_printf (QSE_T("task_main_cgi_5 about to write %d bytes\n"), (int)cgi->buflen);
if (cgi->buflen > 0) if (cgi->buflen > 0)
{ {
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
/* TODO: logging ... */
return -1; return -1;
} }
} }
@ -1024,11 +1051,7 @@ static int task_main_cgi_4_nph (
} }
QSE_ASSERT (cgi->buflen > 0); QSE_ASSERT (cgi->buflen > 0);
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
{
/* TODO: logging ... */
return -1;
}
} }
return 1; return 1;
@ -1043,8 +1066,10 @@ static int task_main_cgi_4 (
QSE_ASSERT (!cgi->nph); QSE_ASSERT (!cgi->nph);
QSE_ASSERT (cgi->pio_inited); QSE_ASSERT (cgi->pio_inited);
#if 0
qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
#endif
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
@ -1057,7 +1082,6 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger
if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
if (cgi->resflags & CGI_RES_CLIENT_CHUNK) if (cgi->resflags & CGI_RES_CLIENT_CHUNK)
{ {
qse_size_t count, extra; qse_size_t count, extra;
@ -1068,7 +1092,6 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
#define CHLEN_RESERVE 6 #define CHLEN_RESERVE 6
qse_printf (QSE_T("READING CHUNKED MODE...\n"));
extra = CHLEN_RESERVE + 2; extra = CHLEN_RESERVE + 2;
count = QSE_SIZEOF(cgi->buf) - cgi->buflen; count = QSE_SIZEOF(cgi->buf) - cgi->buflen;
if (count > extra) if (count > extra)
@ -1080,7 +1103,8 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
); );
if (n <= -1) if (n <= -1)
{ {
/* TODO: logging ... */ if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return -1; return -1;
} }
if (n == 0) if (n == 0)
@ -1121,15 +1145,15 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
cgi->script_output_received > cgi->script_output_length) cgi->script_output_received > cgi->script_output_length)
{ {
/* TODO: cgi returning too much data... something is wrong in CGI */ /* cgi returning too much data... something is wrong in CGI */
qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi redundant output - "));
return -1; return -1;
} }
} }
} }
else else
{ {
qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n"));
if (cgi->buflen < QSE_SIZEOF(cgi->buf)) if (cgi->buflen < QSE_SIZEOF(cgi->buf))
{ {
n = cgi_read_script_output_to_buffer (httpd, client, cgi); n = cgi_read_script_output_to_buffer (httpd, client, cgi);
@ -1147,9 +1171,9 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
cgi->script_output_received > cgi->script_output_length) cgi->script_output_received > cgi->script_output_length)
{ {
/* TODO: logging */ /* cgi returning too much data... something is wrong in CGI */
/* TODO: cgi returning too much data... something is wrong in CGI */ if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); log_cgi_script_error (cgi, QSE_MT("cgi redundant output - "));
return -1; return -1;
} }
} }
@ -1159,11 +1183,7 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
* side is writable. it should be safe to write whenever * side is writable. it should be safe to write whenever
* this task function is called. */ * this task function is called. */
QSE_ASSERT (cgi->buflen > 0); QSE_ASSERT (cgi->buflen > 0);
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
{
/* TODO: logging ... */
return -1;
}
} }
return 1; return 1;
@ -1181,8 +1201,10 @@ static int task_main_cgi_3 (
QSE_ASSERT (!cgi->nph); QSE_ASSERT (!cgi->nph);
#if 0
qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
#endif
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
cgi_forward_client_input_to_script (httpd, task, 0); cgi_forward_client_input_to_script (httpd, task, 0);
@ -1200,15 +1222,13 @@ qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger
count = MAX_SEND_SIZE; count = MAX_SEND_SIZE;
if (count >= cgi->res_left) count = cgi->res_left; if (count >= cgi->res_left) count = cgi->res_left;
qse_printf (QSE_T("[cgi_3 sending %d bytes]\n"), (int)count);
if (count > 0) if (count > 0)
{ {
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count);
if (n <= -1) if (n <= -1)
{ {
qse_printf (QSE_T("[cgi-3 send failure....\n")); if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - "));
return -1; return -1;
} }
@ -1223,7 +1243,6 @@ qse_printf (QSE_T("[cgi-3 send failure....\n"));
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
cgi->script_output_received >= cgi->script_output_length) cgi->script_output_received >= cgi->script_output_length)
{ {
qse_printf (QSE_T("[switching to cgi-5....\n"));
/* if a cgi script specified the content length /* if a cgi script specified the content length
* and it has emitted as much as the length, * and it has emitted as much as the length,
* i don't wait for the script to finish. * i don't wait for the script to finish.
@ -1236,7 +1255,6 @@ qse_printf (QSE_T("[switching to cgi-5....\n"));
} }
else else
{ {
qse_printf (QSE_T("[switching to cgi-4....\n"));
task->main = task_main_cgi_4; task->main = task_main_cgi_4;
task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
} }
@ -1262,12 +1280,13 @@ static int task_main_cgi_2 (
QSE_ASSERT (!cgi->nph); QSE_ASSERT (!cgi->nph);
QSE_ASSERT (cgi->pio_inited); QSE_ASSERT (cgi->pio_inited);
#if 0
qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask); task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
#endif
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
qse_printf (QSE_T("[cgi_2 write]\n"));
cgi_forward_client_input_to_script (httpd, task, 0); cgi_forward_client_input_to_script (httpd, task, 0);
} }
else if (task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) else if (task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)
@ -1277,7 +1296,6 @@ qse_printf (QSE_T("[cgi_2 write]\n"));
if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
qse_printf (QSE_T("[cgi_2 read]\n"));
n = qse_pio_read ( n = qse_pio_read (
&cgi->pio, QSE_PIO_OUT, &cgi->pio, QSE_PIO_OUT,
&cgi->buf[cgi->buflen], &cgi->buf[cgi->buflen],
@ -1286,25 +1304,24 @@ qse_printf (QSE_T("[cgi_2 read]\n"));
if (n <= -1) if (n <= -1)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
/* TODO: logging ... */ if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
goto oops; goto oops;
} }
if (n == 0) if (n == 0)
{ {
/* end of output from cgi before it has seen a header. /* end of output from cgi before it has seen a header.
* the cgi script must be crooked. */ * the cgi script must be crooked. */
/* TODO: logging */ if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
qse_printf (QSE_T("#####PREMATURE EOF FROM CHILD\n")); log_cgi_script_error (cgi, QSE_MT("cgi premature eof - "));
goto oops; goto oops;
} }
cgi->buflen += n; cgi->buflen += n;
qse_printf (QSE_T("#####CGI FEED [%.*hs]\n"), (int)cgi->buflen, cgi->buf);
if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1)
{ {
/* TODO: logging */ if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->buflen, cgi->buf); log_cgi_script_error (cgi, QSE_MT("cgi feed error - "));
goto oops; goto oops;
} }
@ -1324,7 +1341,9 @@ qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->bu
cgi->res_ptr = QSE_MBS_PTR(cgi->res); cgi->res_ptr = QSE_MBS_PTR(cgi->res);
cgi->res_left = QSE_MBS_LEN(cgi->res); cgi->res_left = QSE_MBS_LEN(cgi->res);
#if 0
qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res)); qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res));
#endif
task->main = task_main_cgi_3; task->main = task_main_cgi_3;
task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
return 1; return 1;
@ -1447,7 +1466,6 @@ static int task_main_cgi (
* this is possible because the main loop can still read * this is possible because the main loop can still read
* between the initializer function (task_init_cgi()) and * between the initializer function (task_init_cgi()) and
* this function. so let's forward it initially. */ * this function. so let's forward it initially. */
qse_printf (QSE_T("FORWARDING INITIAL PART OF CONTENT...\n"));
cgi_forward_client_input_to_script (httpd, task, 0); cgi_forward_client_input_to_script (httpd, task, 0);
/* if the initial forwarding clears the forwarding /* if the initial forwarding clears the forwarding

View File

@ -29,8 +29,8 @@
typedef struct task_proxy_arg_t task_proxy_arg_t; typedef struct task_proxy_arg_t task_proxy_arg_t;
struct task_proxy_arg_t struct task_proxy_arg_t
{ {
qse_nwad_t* peer_nwad; const qse_nwad_t* peer_nwad;
qse_nwad_t* peer_local; const qse_nwad_t* peer_local;
qse_htre_t* req; qse_htre_t* req;
}; };

View File

@ -531,12 +531,15 @@ struct httpd_xtn_t
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
static int init_xtn_ssl ( static int init_xtn_ssl (
httpd_xtn_t* xtn, qse_httpd_t* httpd,
const qse_mchar_t* pemfile, const qse_mchar_t* pemfile,
const qse_mchar_t* keyfile/*, const qse_mchar_t* keyfile/*,
const qse_mchar_t* chainfile*/) const qse_mchar_t* chainfile*/)
{ {
SSL_CTX* ctx; SSL_CTX* ctx;
httpd_xtn_t* xtn;
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
ctx = SSL_CTX_new (SSLv23_server_method()); ctx = SSL_CTX_new (SSLv23_server_method());
if (ctx == QSE_NULL) return -1; if (ctx == QSE_NULL) return -1;
@ -548,10 +551,14 @@ static int init_xtn_ssl (
SSL_CTX_check_private_key (ctx) == 0 /*|| SSL_CTX_check_private_key (ctx) == 0 /*||
SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/) SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/)
{ {
qse_mchar_t buf[128]; if (httpd->opt.trait & QSE_HTTPD_LOGACT)
ERR_error_string_n(ERR_get_error(), buf, QSE_COUNTOF(buf)); {
/* TODO: logging */ qse_httpd_act_t msg;
qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf); msg.code = QSE_HTTPD_CATCH_MERRMSG;
ERR_error_string_n (ERR_get_error(), msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg));
httpd->opt.rcb.logact (httpd, &msg);
}
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
return -1; return -1;
} }
@ -600,7 +607,7 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize)
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
/*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/ /*init_xtn_ssl (httpd, "http01.pem", "http01.key");*/
#endif #endif
set_httpd_callbacks (httpd); set_httpd_callbacks (httpd);
@ -1409,7 +1416,16 @@ static int file_ropen (
} }
handle->ptr = fio; handle->ptr = fio;
qse_printf (QSE_T("opened rfile [%hs][%p][%p]\n"), path, handle->ptr, fio->handle);
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{
qse_httpd_act_t msg;
qse_size_t pos;
msg.code = QSE_HTTPD_CATCH_MDBGMSG;
pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("ropened file "));
qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path);
httpd->opt.rcb.logact (httpd, &msg);
}
return 0; return 0;
} }
@ -1438,13 +1454,22 @@ static int file_wopen (
} }
handle->ptr = fio; handle->ptr = fio;
qse_printf (QSE_T("opened wfile [%hs][%p][%p]\n"), path, handle->ptr, fio->handle);
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{
qse_httpd_act_t msg;
qse_size_t pos;
msg.code = QSE_HTTPD_CATCH_MDBGMSG;
pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("wopened file "));
qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path);
httpd->opt.rcb.logact (httpd, &msg);
}
return 0; return 0;
} }
static void file_close (qse_httpd_t* httpd, qse_ubi_t handle) static void file_close (qse_httpd_t* httpd, qse_ubi_t handle)
{ {
qse_printf (QSE_T("closed file....%p\n"), handle.ptr);
qse_fio_fini (handle.ptr); qse_fio_fini (handle.ptr);
QSE_MMGR_FREE (httpd->mmgr, handle.ptr); QSE_MMGR_FREE (httpd->mmgr, handle.ptr);
} }
@ -1512,7 +1537,16 @@ static int dir_open (qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* han
return -1; return -1;
} }
qse_printf (QSE_T("OPENED DIRECTORY [%hs]\n"), path); if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{
qse_httpd_act_t msg;
qse_size_t pos;
msg.code = QSE_HTTPD_CATCH_MDBGMSG;
pos = qse_mbscpy (msg.u.mdbgmsg, QSE_MT("opened dir "));
qse_mbsxcpy (&msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, path);
httpd->opt.rcb.logact (httpd, &msg);
}
handle->ptr = d; handle->ptr = d;
return 0; return 0;
} }
@ -1693,7 +1727,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
{ {
/* delayed initialization of ssl */ /* delayed initialization of ssl */
/* TODO: certificate from options */ /* TODO: certificate from options */
if (init_xtn_ssl (xtn, "http01.pem", "http01.key") <= -1) if (init_xtn_ssl (httpd, "http01.pem", "http01.key") <= -1)
{ {
return -1; return -1;
} }
@ -1711,9 +1745,6 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
if (ssl == QSE_NULL) return -1; if (ssl == QSE_NULL) return -1;
client->handle2.ptr = ssl; client->handle2.ptr = ssl;
qse_printf (QSE_T("SSL ACCEPTING %d\n"), client->handle.i);
qse_fflush (QSE_STDOUT);
if (SSL_set_fd (ssl, client->handle.i) == 0) if (SSL_set_fd (ssl, client->handle.i) == 0)
{ {
/* don't free ssl here since client_closed() /* don't free ssl here since client_closed()
@ -1727,18 +1758,25 @@ qse_fflush (QSE_STDOUT);
ret = SSL_accept (ssl); ret = SSL_accept (ssl);
if (ret <= 0) if (ret <= 0)
{ {
if (SSL_get_error(ssl,ret) == SSL_ERROR_WANT_READ) int err;
if ((err = SSL_get_error(ssl,ret)) == SSL_ERROR_WANT_READ)
{ {
/* handshaking isn't complete. */ /* handshaking isn't complete. */
return 0; return 0;
} }
qse_fprintf (QSE_STDERR, QSE_T("Error: SSL ACCEPT ERROR\n")); if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{
qse_httpd_act_t msg;
msg.code = QSE_HTTPD_CATCH_MERRMSG;
ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg));
httpd->opt.rcb.logact (httpd, &msg);
}
/* SSL_free (ssl); */ /* SSL_free (ssl); */
return -1; return -1;
} }
qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i);
qse_fflush (QSE_STDOUT);
#else #else
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
return -1; return -1;
@ -1763,6 +1801,7 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client)
} }
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
#if 0
static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
{ {
qse_htre_hdrval_t* val; qse_htre_hdrval_t* val;
@ -1775,6 +1814,7 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_
} }
return QSE_HTB_WALK_FORWARD; return QSE_HTB_WALK_FORWARD;
} }
#endif
static int process_request ( static int process_request (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek)
@ -1796,6 +1836,7 @@ static int process_request (
* non-peek mode as well */ * non-peek mode as well */
if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req)); if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
#if 0
qse_printf (QSE_T("================================\n")); qse_printf (QSE_T("================================\n"));
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
(unsigned long)time(NULL), (unsigned long)time(NULL),
@ -1814,6 +1855,7 @@ if (qse_htre_getcontentlen(req) > 0)
{ {
qse_printf (QSE_T("CONTENT [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); qse_printf (QSE_T("CONTENT [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
} }
#endif
if (peek) if (peek)
{ {
@ -2044,11 +2086,12 @@ static void impede_httpd (qse_httpd_t* httpd)
/* do nothing */ /* do nothing */
} }
static void logact_httpd (qse_httpd_t* httpd, qse_httpd_act_t* act) static void logact_httpd (qse_httpd_t* httpd, const qse_httpd_act_t* act)
{ {
/* do nothing */ /* do nothing */
} }
static qse_httpd_scb_t httpd_system_callbacks = static qse_httpd_scb_t httpd_system_callbacks =
{ {
/* server */ /* server */
@ -2341,11 +2384,11 @@ static int make_resource (
QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); QSE_MEMSET (target, 0, QSE_SIZEOF(*target));
qse_printf (QSE_T(">>> MAKING RESOURCE [%hs]\n"), tmp.qpath);
server_xtn = qse_httpd_getserverxtn (httpd, client->server); server_xtn = qse_httpd_getserverxtn (httpd, client->server);
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1 || if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1) return -1;
server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
if (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_AUTH, &tmp.auth) <= -1 ||
server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1) server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1)
{ {
@ -2455,8 +2498,19 @@ auth_ok:
} }
} }
target->type = QSE_HTTPD_RSRC_DIR; /* it is a directory - should i allow it? */
target->u.dir.path = tmp.xpath; if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRACC, &target->u.err.code) <= -1) target->u.err.code = 500;
if (target->u.err.code != 200)
{
target->type = QSE_HTTPD_RSRC_ERR;
/* free xpath since it won't be used */
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
}
else
{
target->type = QSE_HTTPD_RSRC_DIR;
target->u.dir.path = tmp.xpath;
}
} }
else else
{ {
@ -2478,14 +2532,25 @@ auth_ok:
} }
if (n >= 1) return 0; if (n >= 1) return 0;
/* fall back to a normal file. */ /* check file's access permission */
target->type = QSE_HTTPD_RSRC_FILE; if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_FILEACC, &target->u.err.code) <= -1) target->u.err.code = 500;
target->u.file.path = tmp.xpath; if (target->u.err.code != 200)
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->type = QSE_HTTPD_RSRC_ERR;
target->u.file.mime = QSE_NULL; /* free xpath since it won't be used */
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
}
else
{
/* fall back to a normal file. */
target->type = QSE_HTTPD_RSRC_FILE;
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;
}
} }
} }
@ -2581,6 +2646,12 @@ static int query_server (
*(const qse_mchar_t**)result = QSE_NULL; *(const qse_mchar_t**)result = QSE_NULL;
return 0; return 0;
case QSE_HTTPD_SERVERSTD_DIRACC:
case QSE_HTTPD_SERVERSTD_FILEACC:
*(int*)result = 200;
return 0;
} }
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);

View File

@ -457,7 +457,7 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
prev = client->prev; prev = client->prev;
next = client->next; next = client->next;
if (httpd->opt.trait & QSE_HTTPD_ENABLELOG) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{ {
qse_httpd_act_t msg; qse_httpd_act_t msg;
msg.code = QSE_HTTPD_PURGE_CLIENT; msg.code = QSE_HTTPD_PURGE_CLIENT;
@ -562,14 +562,13 @@ qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i);
httpd->client.list.tail = client; httpd->client.list.tail = client;
} }
{ if (httpd->opt.trait & QSE_HTTPD_LOGACT)
/* TODO: proper logging */ {
qse_char_t tmp[128], tmp2[128], tmp3[128]; qse_httpd_act_t msg;
qse_nwadtostr (&client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); msg.code = QSE_HTTPD_ACCEPT_CLIENT;
qse_nwadtostr (&client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); msg.u.client = client;
qse_nwadtostr (&client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL); httpd->opt.rcb.logact (httpd, &msg);
qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, tmp, tmp2, tmp3); }
}
} }
return 0; return 0;
} }
@ -733,7 +732,6 @@ reread:
if (httpd->errnum == QSE_HTTPD_EAGAIN) if (httpd->errnum == QSE_HTTPD_EAGAIN)
{ {
/* nothing to read yet. */ /* nothing to read yet. */
qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i);
return 0; /* return ok */ return 0; /* return ok */
} }
else if (httpd->errnum == QSE_HTTPD_EINTR) else if (httpd->errnum == QSE_HTTPD_EINTR)
@ -743,14 +741,22 @@ qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle
else else
{ {
/* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */ /* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */
qse_printf (QSE_T("Error: failed to read from a client %d\n"), client->handle.i); if (httpd->opt.trait & QSE_HTTPD_LOGACT)
/* TODO: find a way to disconnect */ {
qse_httpd_act_t msg;
msg.code = QSE_HTTPD_READERR_CLIENT;
msg.u.client = client;
httpd->opt.rcb.logact (httpd, &msg);
}
/* TODO: find a way to disconnect */
return -1; return -1;
} }
} }
else if (m == 0) else if (m == 0)
{ {
#if 0
qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i); qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i);
#endif
/* reading from the client returned 0. this typically /* reading from the client returned 0. this typically
* happens when the client closes the connection or * happens when the client closes the connection or
* shutdown the writing half of the socket. it's * shutdown the writing half of the socket. it's
@ -764,17 +770,22 @@ qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i);
/* there is still more tasks to finish and /* there is still more tasks to finish and
* http reader is not waiting for any more feeds. */ * http reader is not waiting for any more feeds. */
client->status |= CLIENT_MUTE; client->status |= CLIENT_MUTE;
#if 0
qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i); qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i);
#endif
return 0; return 0;
} }
else else
{ {
#if 0
qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i); qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i);
#endif
httpd->errnum = QSE_HTTPD_EDISCON; httpd->errnum = QSE_HTTPD_EDISCON;
return -1; return -1;
} }
} }
#if 0
qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i); qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i);
#if !defined(__WATCOMC__) #if !defined(__WATCOMC__)
{ {
@ -783,6 +794,7 @@ for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
} }
#endif #endif
qse_printf (QSE_T("]\n")); qse_printf (QSE_T("]\n"));
#endif
/* qse_htrd_feed() may call the request callback /* qse_htrd_feed() may call the request callback
* multiple times. that's because we don't know * multiple times. that's because we don't know
@ -798,17 +810,21 @@ qse_printf (QSE_T("]\n"));
else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */ else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */
} }
#if 0
qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i); qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i);
{ {
int i; int i;
for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]); for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
} }
qse_printf (QSE_T("]\n")); qse_printf (QSE_T("]\n"));
#endif
return -1; return -1;
} }
#if 0
qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i); qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i);
#endif
if (client->status & CLIENT_PENDING) if (client->status & CLIENT_PENDING)
{ {
@ -840,7 +856,6 @@ static int invoke_client_task (
int n, trigger_fired, client_handle_writable; int n, trigger_fired, client_handle_writable;
/* TODO: handle comparison callback ... */ /* TODO: handle comparison callback ... */
qse_printf (QSE_T("INVOKE CLIENT TASK..........\n"));
if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */ if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */
{ {
if (!(client->status & CLIENT_MUTE) && if (!(client->status & CLIENT_MUTE) &&
@ -850,7 +865,6 @@ qse_printf (QSE_T("INVOKE CLIENT TASK..........\n"));
* purge the client in perform_client_task(). * purge the client in perform_client_task().
* thus the following line isn't necessary. * thus the following line isn't necessary.
*if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/ *if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/
qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i);
return -1; return -1;
} }
} }
@ -862,7 +876,6 @@ qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i);
if (client->status & CLIENT_MUTE) if (client->status & CLIENT_MUTE)
{ {
/* handle this delayed client disconnection */ /* handle this delayed client disconnection */
qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int)client->handle.i);
return -1; return -1;
} }
@ -908,7 +921,6 @@ qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int)
} }
n = task->main (httpd, client, task); n = task->main (httpd, client, task);
qse_printf (QSE_T("task returend %d\n"), n);
if (n <= -1) return -1; if (n <= -1) return -1;
else if (n == 0) else if (n == 0)
{ {
@ -1118,17 +1130,12 @@ static int perform_client_task (
qse_gettime (&client->last_active); /* TODO: error check??? */ qse_gettime (&client->last_active); /* TODO: error check??? */
move_client_to_tail (httpd, client); move_client_to_tail (httpd, client);
if (invoke_client_task (httpd, client, handle, mask) <= -1) if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops;
{
qse_printf (QSE_T("OOPS AFTER CLIENT TASK BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
goto oops;
}
} }
return 0; return 0;
oops: oops:
qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
/*purge_client (httpd, client);*/ /*purge_client (httpd, client);*/
client->status |= CLIENT_BAD; client->status |= CLIENT_BAD;
client->bad_next = httpd->client.bad; client->bad_next = httpd->client.bad;
@ -1336,3 +1343,8 @@ const qse_mchar_t* qse_httpd_fmtgmtimetobb (
qse_fmthttptime (nt, httpd->gtbuf[idx], QSE_COUNTOF(httpd->gtbuf[idx])); qse_fmthttptime (nt, httpd->gtbuf[idx], QSE_COUNTOF(httpd->gtbuf[idx]));
return httpd->gtbuf[idx]; return httpd->gtbuf[idx];
} }
/* --------------------------------------------------- */

View File

@ -235,13 +235,16 @@ qse_xli_pair_t* qse_xli_insertpair (
if (pair == QSE_NULL) return QSE_NULL; if (pair == QSE_NULL) return QSE_NULL;
kptr = (qse_char_t*)(pair + 1); kptr = (qse_char_t*)(pair + 1);
nptr = kptr + klen + 1;
qse_strcpy (kptr, key); qse_strcpy (kptr, key);
if (name) qse_strcpy (nptr, name);
pair->type = QSE_XLI_PAIR; pair->type = QSE_XLI_PAIR;
pair->key = kptr; pair->key = kptr;
pair->name = nptr; if (name)
{
nptr = kptr + klen + 1;
qse_strcpy (nptr, name);
pair->name = nptr;
}
pair->val = value; /* this assumes it points to a dynamically allocated atom */ pair->val = value; /* this assumes it points to a dynamically allocated atom */
insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair); insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair);