added file-access and dir-access to cmd/http/httpd.c
This commit is contained in:
parent
b677b4a892
commit
b420a7c0dc
23
qse/cmd/http/httpd-mime.conf
Normal file
23
qse/cmd/http/httpd-mime.conf
Normal 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";
|
@ -8,6 +8,7 @@
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include <qse/cmn/opt.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
@ -27,6 +28,7 @@
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
@ -38,17 +40,34 @@
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void sighup (int sig)
|
||||
static void sig_reconf (int sig)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -59,15 +78,25 @@ static void setup_signal_handlers ()
|
||||
|
||||
#if defined(SIGINT)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sigint;
|
||||
act.sa_handler = sig_stop;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#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)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = sighup;
|
||||
act.sa_handler = sig_reconf;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#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)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
@ -85,12 +114,22 @@ static void restore_signal_handlers ()
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGINT, &act, QSE_NULL);
|
||||
#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)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction (SIGHUP, &act, QSE_NULL);
|
||||
#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)
|
||||
qse_memset (&act, 0, QSE_SIZEOF(act));
|
||||
@ -99,6 +138,43 @@ static void restore_signal_handlers ()
|
||||
#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
|
||||
@ -117,8 +193,7 @@ struct cgi_t
|
||||
{
|
||||
enum {
|
||||
CGI_SUFFIX,
|
||||
CGI_FILE,
|
||||
|
||||
CGI_NAME,
|
||||
CGI_MAX
|
||||
} type;
|
||||
|
||||
@ -133,8 +208,8 @@ struct mime_t
|
||||
{
|
||||
enum {
|
||||
MIME_SUFFIX,
|
||||
MIME_FILE,
|
||||
|
||||
MIME_NAME,
|
||||
MIME_OTHER,
|
||||
MIME_MAX
|
||||
} type;
|
||||
|
||||
@ -144,6 +219,23 @@ struct mime_t
|
||||
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;
|
||||
struct server_xtn_t
|
||||
{
|
||||
@ -176,15 +268,14 @@ struct server_xtn_t
|
||||
struct mime_t* head;
|
||||
struct mime_t* tail;
|
||||
} 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 (
|
||||
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)
|
||||
{
|
||||
server_xtn_t* server_xtn;
|
||||
qse_size_t i;
|
||||
qse_size_t i, j;
|
||||
|
||||
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].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)
|
||||
@ -369,8 +479,8 @@ static int query_server (
|
||||
struct cgi_t* cgi;
|
||||
for (cgi = server_xtn->cgi[i].head; cgi; cgi = cgi->next)
|
||||
{
|
||||
if ((cgi->type == MIME_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) ||
|
||||
(cgi->type == MIME_FILE && qse_mbscmp (xpath_base, cgi->spec) == 0))
|
||||
if ((cgi->type == CGI_SUFFIX && qse_mbsend (xpath_base, cgi->spec)) ||
|
||||
(cgi->type == CGI_NAME && qse_mbscmp (xpath_base, cgi->spec) == 0))
|
||||
{
|
||||
scgi->cgi = 1;
|
||||
scgi->nph = cgi->nph;
|
||||
@ -386,7 +496,7 @@ static int query_server (
|
||||
case QSE_HTTPD_SERVERSTD_MIME:
|
||||
{
|
||||
qse_size_t i;
|
||||
qse_mchar_t* xpath_base;
|
||||
const qse_mchar_t* xpath_base;
|
||||
|
||||
xpath_base = qse_mbsbasename (xpath);
|
||||
|
||||
@ -397,7 +507,8 @@ static int query_server (
|
||||
for (mime = server_xtn->mime[i].head; mime; mime = mime->next)
|
||||
{
|
||||
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;
|
||||
return 0;
|
||||
@ -406,6 +517,35 @@ static int query_server (
|
||||
}
|
||||
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);
|
||||
@ -498,9 +638,9 @@ static int load_server_config (
|
||||
{
|
||||
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;
|
||||
|
||||
@ -570,13 +710,14 @@ static int load_server_config (
|
||||
if (atom->type != QSE_XLI_PAIR) continue;
|
||||
|
||||
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;
|
||||
int type;
|
||||
|
||||
if (qse_strcmp (pair->key, QSE_T("suffix")) == 0) type = MIME_SUFFIX;
|
||||
else if (qse_strcmp (pair->key, QSE_T("file")) == 0) type = MIME_FILE;
|
||||
if (qse_strcmp (pair->key, QSE_T("suffix")) == 0 && pair->name) type = MIME_SUFFIX;
|
||||
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;
|
||||
|
||||
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"));
|
||||
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);
|
||||
if (!mime->value)
|
||||
{
|
||||
qse_httpd_freemem (httpd, mime->spec);
|
||||
qse_httpd_freemem (httpd, mime);
|
||||
qse_printf (QSE_T("ERROR: memory failure in copying mime\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: more sanity check */
|
||||
|
||||
qse_httpd_freemem (httpd, mime->spec);
|
||||
qse_httpd_freemem (httpd, mime);
|
||||
qse_printf (QSE_T("ERROR: memory failure in copying mime\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (server_xtn->mime[type].tail)
|
||||
server_xtn->mime[type].tail->next = mime;
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
qse_char_t tmp[256];
|
||||
qse_char_t tmp[128], tmp2[128], tmp3[128];
|
||||
|
||||
httpd_xtn = qse_httpd_getxtnstd (httpd);
|
||||
|
||||
switch (act->code)
|
||||
{
|
||||
case QSE_HTTPD_ACCEPT_CLIENT:
|
||||
case QSE_HTTPD_CATCH_MERRMSG:
|
||||
qse_printf (QSE_T("ERROR: %hs\n"), act->u.merrmsg);
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
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[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
qse_ntime_t tmout;
|
||||
int trait, ret = -1;
|
||||
int trait, ret;
|
||||
qse_httpd_rcb_t rcb;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
/* TODO: proper check... */
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s -f config-file\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
ret = handle_args (argc, argv);
|
||||
if (ret <= -1) return -1;
|
||||
if (ret == 0) return 0;
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(httpd_xtn_t));
|
||||
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;
|
||||
}
|
||||
|
||||
httpd_xtn = qse_httpd_getxtnstd (httpd);
|
||||
httpd_xtn->cfgfile = argv[1];
|
||||
httpd_xtn->cfgfile = g_cfgfile;
|
||||
|
||||
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;
|
||||
setup_signal_handlers ();
|
||||
|
||||
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);
|
||||
|
||||
tmout.sec = 10;
|
||||
@ -921,7 +1241,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
|
||||
oops:
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
|
@ -2,43 +2,119 @@
|
||||
# this is a sample configuration file for qsehttpd.
|
||||
#
|
||||
|
||||
server {
|
||||
bind = "0.0.0.0:80";
|
||||
default {
|
||||
# the default name is used in http headers and in pages
|
||||
# generated by httpd.
|
||||
name = "QSEHTTPD v1";
|
||||
|
||||
ssl {
|
||||
certificate {
|
||||
private = "xxxx";
|
||||
public = "xxxx";
|
||||
}
|
||||
}
|
||||
docroot = "/";
|
||||
|
||||
root = "/home/www/default";
|
||||
option = "xxxx,xxx,xxxx";
|
||||
|
||||
realm {
|
||||
name = "xxxxxx";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
realm = "default realm";
|
||||
auth = "username:password";
|
||||
index = "index.ant",
|
||||
"index.html",
|
||||
"index.cgi";
|
||||
|
||||
cgi {
|
||||
suffix ".ant" = "xxxxx";
|
||||
name "t3.nph" = "nph";
|
||||
suffix ".cgi";
|
||||
suffix ".nph";
|
||||
suffix ".ant" = "nph", "";
|
||||
suffix ".awk" = "cgi", "/usr/bin/qseawk -f";
|
||||
|
||||
# glob is not supported yet
|
||||
# glob "x*.xxx";
|
||||
}
|
||||
|
||||
mime {
|
||||
suffix ".jpg" = "image/picture";
|
||||
suffix ".txt" = "text/plain";
|
||||
@include "httpd-mime.conf";
|
||||
}
|
||||
|
||||
# virtual host
|
||||
host "www.google.com" {
|
||||
root = "/home/www/google";
|
||||
option = "xxx, xxx, xxxx";
|
||||
|
||||
realm {
|
||||
name = "www.google.com";
|
||||
password = "zzzzzzzzzzzzzzzz";
|
||||
}
|
||||
# control access to directories
|
||||
dir-access {
|
||||
# suffix ".xxxx" = ok;
|
||||
# name "xxxxx" = ok;
|
||||
other = noent;
|
||||
}
|
||||
|
||||
# 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";
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ enum qse_httpd_trait_t
|
||||
QSE_HTTPD_CGIERRTONUL = (1 << 1),
|
||||
QSE_HTTPD_CGINOCLOEXEC = (1 << 2),
|
||||
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;
|
||||
|
||||
@ -115,8 +115,8 @@ typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
|
||||
|
||||
struct qse_httpd_dirent_t
|
||||
{
|
||||
qse_mchar_t* name;
|
||||
qse_httpd_stat_t stat;
|
||||
const qse_mchar_t* name;
|
||||
qse_httpd_stat_t stat;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
QSE_HTTPD_CATCH_MERRMSG,
|
||||
QSE_HTTPD_CATCH_MDBGMSG,
|
||||
QSE_HTTPD_ACCEPT_CLIENT,
|
||||
QSE_HTTPD_PURGE_CLIENT,
|
||||
QSE_HTTPD_READERR_CLIENT
|
||||
};
|
||||
typedef enum qse_httpd_act_code_t qse_httpd_act_code_t;
|
||||
|
||||
@ -277,6 +280,8 @@ struct qse_httpd_act_t
|
||||
union
|
||||
{
|
||||
qse_httpd_client_t* client;
|
||||
qse_mchar_t merrmsg[128];
|
||||
qse_mchar_t mdbgmsg[128];
|
||||
} u;
|
||||
};
|
||||
typedef struct qse_httpd_act_t qse_httpd_act_t;
|
||||
|
@ -385,8 +385,13 @@ static int get_highest_fd (void)
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/pio.h>
|
||||
#include <qse/cmn/fmt.h>
|
||||
#include <qse/cmn/path.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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) &&
|
||||
cgi->script_output_received > cgi->script_output_length)
|
||||
{
|
||||
/* TODO: cgi returning too much data... something is wrong in CGI */
|
||||
qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n"));
|
||||
/* cgi returning too much data... something is wrong in CGI */
|
||||
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 */
|
||||
return -1;
|
||||
}
|
||||
@ -501,8 +514,10 @@ static int cgi_snatch_client_input (
|
||||
task = (qse_httpd_task_t*)ctx;
|
||||
cgi = (task_cgi_t*)task->ctx;
|
||||
|
||||
#if 0
|
||||
if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr);
|
||||
else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
|
||||
#endif
|
||||
|
||||
QSE_ASSERT (cgi->req);
|
||||
QSE_ASSERT (!(cgi->reqflags & CGI_REQ_GOTALL));
|
||||
@ -587,7 +602,9 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
|
||||
|
||||
/* output pipe to child */
|
||||
task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
#if 0
|
||||
qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -608,7 +625,9 @@ static void cgi_forward_client_input_to_script (
|
||||
{
|
||||
/* a forwarding error has occurred previously.
|
||||
* clear the forwarding buffer */
|
||||
#if 0
|
||||
qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
|
||||
#endif
|
||||
qse_mbs_clear (cgi->reqfwdbuf);
|
||||
}
|
||||
else
|
||||
@ -624,9 +643,11 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
|
||||
{
|
||||
forward:
|
||||
/* writable */
|
||||
#if 0
|
||||
qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
|
||||
(int)QSE_MBS_LEN(cgi->reqfwdbuf),
|
||||
QSE_MBS_PTR(cgi->reqfwdbuf));
|
||||
#endif
|
||||
n = qse_pio_write (
|
||||
&cgi->pio, QSE_PIO_IN,
|
||||
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)
|
||||
{
|
||||
qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n"));
|
||||
/* TODO: logging ... */
|
||||
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
log_cgi_script_error (cgi, QSE_MT("cgi pio write error - "));
|
||||
|
||||
cgi->reqflags |= CGI_REQ_FWDERR;
|
||||
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.
|
||||
* clear the relay and write triggers for the time being.
|
||||
*/
|
||||
#if 0
|
||||
qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n"));
|
||||
#endif
|
||||
QSE_ASSERT (cgi->req == QSE_NULL);
|
||||
|
||||
/* 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_htre_unsetconcb (cgi->req);
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("task_fini_cgi\n"));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -942,13 +968,16 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client (
|
||||
{
|
||||
qse_ssize_t n;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen);
|
||||
if (n > 0)
|
||||
{
|
||||
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[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;
|
||||
}
|
||||
|
||||
@ -971,13 +1000,11 @@ static int task_main_cgi_5 (
|
||||
if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||
|
||||
(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_write_script_output_to_client (httpd, client, cgi) <= -1)
|
||||
{
|
||||
/* can't return internal server error any more... */
|
||||
/* TODO: logging ... */
|
||||
/* can't return internal server error any more... */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1024,11 +1051,7 @@ static int task_main_cgi_4_nph (
|
||||
}
|
||||
|
||||
QSE_ASSERT (cgi->buflen > 0);
|
||||
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1)
|
||||
{
|
||||
/* TODO: logging ... */
|
||||
return -1;
|
||||
}
|
||||
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -1043,8 +1066,10 @@ static int task_main_cgi_4 (
|
||||
QSE_ASSERT (!cgi->nph);
|
||||
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"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
|
||||
if (cgi->resflags & CGI_RES_CLIENT_CHUNK)
|
||||
{
|
||||
qse_size_t count, extra;
|
||||
@ -1068,7 +1092,6 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
|
||||
|
||||
#define CHLEN_RESERVE 6
|
||||
|
||||
qse_printf (QSE_T("READING CHUNKED MODE...\n"));
|
||||
extra = CHLEN_RESERVE + 2;
|
||||
count = QSE_SIZEOF(cgi->buf) - cgi->buflen;
|
||||
if (count > extra)
|
||||
@ -1080,7 +1103,8 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
|
||||
);
|
||||
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;
|
||||
}
|
||||
if (n == 0)
|
||||
@ -1121,15 +1145,15 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
|
||||
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
|
||||
cgi->script_output_received > cgi->script_output_length)
|
||||
{
|
||||
/* TODO: cgi returning too much data... something is wrong in CGI */
|
||||
qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n"));
|
||||
/* cgi returning too much data... something is wrong in CGI */
|
||||
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
log_cgi_script_error (cgi, QSE_MT("cgi redundant output - "));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n"));
|
||||
if (cgi->buflen < QSE_SIZEOF(cgi->buf))
|
||||
{
|
||||
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) &&
|
||||
cgi->script_output_received > cgi->script_output_length)
|
||||
{
|
||||
/* TODO: logging */
|
||||
/* TODO: cgi returning too much data... something is wrong in CGI */
|
||||
qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n"));
|
||||
/* cgi returning too much data... something is wrong in CGI */
|
||||
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
log_cgi_script_error (cgi, QSE_MT("cgi redundant output - "));
|
||||
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
|
||||
* this task function is called. */
|
||||
QSE_ASSERT (cgi->buflen > 0);
|
||||
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1)
|
||||
{
|
||||
/* TODO: logging ... */
|
||||
return -1;
|
||||
}
|
||||
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -1181,8 +1201,10 @@ static int task_main_cgi_3 (
|
||||
|
||||
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"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
#endif
|
||||
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
|
||||
{
|
||||
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;
|
||||
if (count >= cgi->res_left) count = cgi->res_left;
|
||||
|
||||
qse_printf (QSE_T("[cgi_3 sending %d bytes]\n"), (int)count);
|
||||
if (count > 0)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1223,7 +1243,6 @@ qse_printf (QSE_T("[cgi-3 send failure....\n"));
|
||||
if ((cgi->resflags & CGI_RES_SCRIPT_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
|
||||
* and it has emitted as much as the length,
|
||||
* i don't wait for the script to finish.
|
||||
@ -1236,7 +1255,6 @@ qse_printf (QSE_T("[switching to cgi-5....\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("[switching to cgi-4....\n"));
|
||||
task->main = task_main_cgi_4;
|
||||
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->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"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
qse_printf (QSE_T("[cgi_2 read]\n"));
|
||||
n = qse_pio_read (
|
||||
&cgi->pio, QSE_PIO_OUT,
|
||||
&cgi->buf[cgi->buflen],
|
||||
@ -1286,25 +1304,24 @@ qse_printf (QSE_T("[cgi_2 read]\n"));
|
||||
if (n <= -1)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
if (n == 0)
|
||||
{
|
||||
/* end of output from cgi before it has seen a header.
|
||||
* the cgi script must be crooked. */
|
||||
/* TODO: logging */
|
||||
qse_printf (QSE_T("#####PREMATURE EOF FROM CHILD\n"));
|
||||
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
log_cgi_script_error (cgi, QSE_MT("cgi premature eof - "));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* TODO: logging */
|
||||
qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->buflen, cgi->buf);
|
||||
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
log_cgi_script_error (cgi, QSE_MT("cgi feed error - "));
|
||||
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_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));
|
||||
#endif
|
||||
task->main = task_main_cgi_3;
|
||||
task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
return 1;
|
||||
@ -1447,7 +1466,6 @@ static int task_main_cgi (
|
||||
* this is possible because the main loop can still read
|
||||
* between the initializer function (task_init_cgi()) and
|
||||
* 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);
|
||||
|
||||
/* if the initial forwarding clears the forwarding
|
||||
|
@ -29,8 +29,8 @@
|
||||
typedef struct task_proxy_arg_t task_proxy_arg_t;
|
||||
struct task_proxy_arg_t
|
||||
{
|
||||
qse_nwad_t* peer_nwad;
|
||||
qse_nwad_t* peer_local;
|
||||
const qse_nwad_t* peer_nwad;
|
||||
const qse_nwad_t* peer_local;
|
||||
qse_htre_t* req;
|
||||
};
|
||||
|
||||
|
@ -531,12 +531,15 @@ struct httpd_xtn_t
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
static int init_xtn_ssl (
|
||||
httpd_xtn_t* xtn,
|
||||
qse_httpd_t* httpd,
|
||||
const qse_mchar_t* pemfile,
|
||||
const qse_mchar_t* keyfile/*,
|
||||
const qse_mchar_t* chainfile*/)
|
||||
{
|
||||
SSL_CTX* ctx;
|
||||
httpd_xtn_t* xtn;
|
||||
|
||||
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
|
||||
|
||||
ctx = SSL_CTX_new (SSLv23_server_method());
|
||||
if (ctx == QSE_NULL) return -1;
|
||||
@ -548,10 +551,14 @@ static int init_xtn_ssl (
|
||||
SSL_CTX_check_private_key (ctx) == 0 /*||
|
||||
SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/)
|
||||
{
|
||||
qse_mchar_t buf[128];
|
||||
ERR_error_string_n(ERR_get_error(), buf, QSE_COUNTOF(buf));
|
||||
/* TODO: logging */
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf);
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
qse_httpd_act_t msg;
|
||||
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);
|
||||
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);
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
/*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/
|
||||
/*init_xtn_ssl (httpd, "http01.pem", "http01.key");*/
|
||||
#endif
|
||||
|
||||
set_httpd_callbacks (httpd);
|
||||
@ -1409,7 +1416,16 @@ static int file_ropen (
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@ -1438,13 +1454,22 @@ static int file_wopen (
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
@ -1693,7 +1727,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
{
|
||||
/* delayed initialization of ssl */
|
||||
/* 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;
|
||||
}
|
||||
@ -1711,9 +1745,6 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
if (ssl == QSE_NULL) return -1;
|
||||
|
||||
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)
|
||||
{
|
||||
/* don't free ssl here since client_closed()
|
||||
@ -1727,18 +1758,25 @@ qse_fflush (QSE_STDOUT);
|
||||
ret = SSL_accept (ssl);
|
||||
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. */
|
||||
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); */
|
||||
return -1;
|
||||
}
|
||||
qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i);
|
||||
qse_fflush (QSE_STDOUT);
|
||||
|
||||
#else
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int process_request (
|
||||
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 */
|
||||
if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
||||
|
||||
#if 0
|
||||
qse_printf (QSE_T("================================\n"));
|
||||
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
|
||||
(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));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (peek)
|
||||
{
|
||||
@ -2044,11 +2086,12 @@ static void impede_httpd (qse_httpd_t* httpd)
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
|
||||
static qse_httpd_scb_t httpd_system_callbacks =
|
||||
{
|
||||
/* server */
|
||||
@ -2341,11 +2384,11 @@ static int make_resource (
|
||||
|
||||
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);
|
||||
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1 ||
|
||||
server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DOCROOT, &tmp.docroot) <= -1) return -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_INDEX, &tmp.index) <= -1)
|
||||
{
|
||||
@ -2455,8 +2498,19 @@ auth_ok:
|
||||
}
|
||||
}
|
||||
|
||||
target->type = QSE_HTTPD_RSRC_DIR;
|
||||
target->u.dir.path = tmp.xpath;
|
||||
/* it is a directory - should i allow it? */
|
||||
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
|
||||
{
|
||||
@ -2478,14 +2532,25 @@ auth_ok:
|
||||
}
|
||||
if (n >= 1) return 0;
|
||||
|
||||
/* 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)
|
||||
/* check file's access permission */
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_FILEACC, &target->u.err.code) <= -1) target->u.err.code = 500;
|
||||
if (target->u.err.code != 200)
|
||||
{
|
||||
/* don't care about failure */
|
||||
target->u.file.mime = QSE_NULL;
|
||||
target->type = QSE_HTTPD_RSRC_ERR;
|
||||
/* 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;
|
||||
return 0;
|
||||
|
||||
case QSE_HTTPD_SERVERSTD_DIRACC:
|
||||
case QSE_HTTPD_SERVERSTD_FILEACC:
|
||||
*(int*)result = 200;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
|
@ -457,7 +457,7 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
prev = client->prev;
|
||||
next = client->next;
|
||||
|
||||
if (httpd->opt.trait & QSE_HTTPD_ENABLELOG)
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
qse_httpd_act_t msg;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
/* TODO: proper logging */
|
||||
qse_char_t tmp[128], tmp2[128], tmp3[128];
|
||||
qse_nwadtostr (&client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL);
|
||||
qse_nwadtostr (&client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL);
|
||||
qse_nwadtostr (&client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL);
|
||||
qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, tmp, tmp2, tmp3);
|
||||
}
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
qse_httpd_act_t msg;
|
||||
msg.code = QSE_HTTPD_ACCEPT_CLIENT;
|
||||
msg.u.client = client;
|
||||
httpd->opt.rcb.logact (httpd, &msg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -733,7 +732,6 @@ reread:
|
||||
if (httpd->errnum == QSE_HTTPD_EAGAIN)
|
||||
{
|
||||
/* nothing to read yet. */
|
||||
qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i);
|
||||
return 0; /* return ok */
|
||||
}
|
||||
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
|
||||
{
|
||||
/* 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);
|
||||
/* TODO: find a way to disconnect */
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (m == 0)
|
||||
{
|
||||
#if 0
|
||||
qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i);
|
||||
#endif
|
||||
/* reading from the client returned 0. this typically
|
||||
* happens when the client closes the connection or
|
||||
* 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
|
||||
* http reader is not waiting for any more feeds. */
|
||||
client->status |= CLIENT_MUTE;
|
||||
#if 0
|
||||
qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i);
|
||||
#endif
|
||||
httpd->errnum = QSE_HTTPD_EDISCON;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i);
|
||||
#if !defined(__WATCOMC__)
|
||||
{
|
||||
@ -783,6 +794,7 @@ for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
|
||||
}
|
||||
#endif
|
||||
qse_printf (QSE_T("]\n"));
|
||||
#endif
|
||||
|
||||
/* qse_htrd_feed() may call the request callback
|
||||
* 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 */
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
|
||||
}
|
||||
qse_printf (QSE_T("]\n"));
|
||||
#endif
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
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)
|
||||
{
|
||||
@ -840,7 +856,6 @@ static int invoke_client_task (
|
||||
int n, trigger_fired, client_handle_writable;
|
||||
|
||||
/* 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 (!(client->status & CLIENT_MUTE) &&
|
||||
@ -850,7 +865,6 @@ qse_printf (QSE_T("INVOKE CLIENT TASK..........\n"));
|
||||
* purge the client in perform_client_task().
|
||||
* thus the following line isn't necessary.
|
||||
*if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/
|
||||
qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i);
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
qse_printf (QSE_T("task returend %d\n"), n);
|
||||
if (n <= -1) return -1;
|
||||
else if (n == 0)
|
||||
{
|
||||
@ -1118,17 +1130,12 @@ static int perform_client_task (
|
||||
qse_gettime (&client->last_active); /* TODO: error check??? */
|
||||
move_client_to_tail (httpd, client);
|
||||
|
||||
if (invoke_client_task (httpd, client, handle, mask) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("OOPS AFTER CLIENT TASK BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
|
||||
goto oops;
|
||||
}
|
||||
if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
|
||||
/*purge_client (httpd, client);*/
|
||||
client->status |= 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]));
|
||||
return httpd->gtbuf[idx];
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------- */
|
||||
|
||||
|
||||
|
@ -235,13 +235,16 @@ qse_xli_pair_t* qse_xli_insertpair (
|
||||
if (pair == QSE_NULL) return QSE_NULL;
|
||||
|
||||
kptr = (qse_char_t*)(pair + 1);
|
||||
nptr = kptr + klen + 1;
|
||||
qse_strcpy (kptr, key);
|
||||
if (name) qse_strcpy (nptr, name);
|
||||
|
||||
pair->type = QSE_XLI_PAIR;
|
||||
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 */
|
||||
|
||||
insert_atom (xli, parent, peer, (qse_xli_atom_t*)pair);
|
||||
|
Loading…
Reference in New Issue
Block a user