added the shebang field to cgi.

changed qse_httpd_getoption()/qse_httpd_setoption() to qse_httpd_getopt()/qse_httpd_setopt() with QSE_HTTPD_TRAIT
fixed a bug of not passing the pred argument in qse_httpd_entaskrsrc().
This commit is contained in:
hyung-hwan 2013-01-30 14:08:38 +00:00
parent 543376b7d9
commit 1dd8de1566
9 changed files with 133 additions and 82 deletions

View File

@ -185,6 +185,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
qse_httpd_t* httpd = QSE_NULL;
qse_ntime_t tmout;
int ret = -1, i;
int trait;
static qse_httpd_server_cbstd_t cbstd = { makersrc, freersrc };
if (argc <= 1)
@ -218,7 +219,8 @@ static int httpd_main (int argc, qse_char_t* argv[])
qse_httpd_setname (httpd, QSE_MT("qsehttpd 1.0"));
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
trait = QSE_HTTPD_CGIERRTONUL;
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
tmout.sec = 10;
tmout.nsec = 0;
@ -259,7 +261,6 @@ int qse_main (int argc, qse_achar_t* argv[])
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
}
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
{
qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n"));

View File

@ -58,13 +58,20 @@ enum qse_httpd_errnum_t
};
typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
enum qse_httpd_option_t
enum qse_httpd_opt_t
{
QSE_HTTPD_TRAIT
};
typedef enum qse_httpd_opt_t qse_httpd_opt_t;
enum qse_httpd_trait_t
{
QSE_HTTPD_MUTECLIENT = (1 << 0),
QSE_HTTPD_CGIERRTONUL = (1 << 1),
QSE_HTTPD_CGINOCLOEXEC = (1 << 2),
QSE_HTTPD_CGINOCHUNKED = (1 << 3)
};
typedef enum qse_httpd_trait_t qse_httpd_trait_t;
typedef struct qse_httpd_stat_t qse_httpd_stat_t;
struct qse_httpd_stat_t
@ -383,8 +390,18 @@ enum qse_httpd_rsrc_type_t
};
typedef enum qse_httpd_rsrc_type_t qse_httpd_rsrc_type_t;
typedef struct qse_httpd_rsrc_t qse_httpd_rsrc_t;
typedef struct qse_httpd_rsrc_cgi_t qse_httpd_rsrc_cgi_t;
struct qse_httpd_rsrc_cgi_t
{
const qse_mchar_t* path;
const qse_mchar_t* script;
const qse_mchar_t* suffix;
const qse_mchar_t* docroot;
const qse_mchar_t* shebang;
int nph;
};
typedef struct qse_httpd_rsrc_t qse_httpd_rsrc_t;
struct qse_httpd_rsrc_t
{
qse_httpd_rsrc_type_t type;
@ -394,14 +411,9 @@ struct qse_httpd_rsrc_t
{
const qse_mchar_t* realm;
} auth;
struct
{
const qse_mchar_t* path;
const qse_mchar_t* script;
const qse_mchar_t* suffix;
const qse_mchar_t* docroot;
int nph;
} cgi;
qse_httpd_rsrc_cgi_t cgi;
struct
{
const qse_mchar_t* path;
@ -478,9 +490,10 @@ struct qse_httpd_server_cbstd_t
typedef struct qse_httpd_server_cgistd_t qse_httpd_server_cgistd_t;
struct qse_httpd_server_cgistd_t
{
const qse_mchar_t* ext;
qse_size_t len;
int nph;
const qse_mchar_t* ext;
qse_size_t len;
int nph;
const qse_mchar_t* shebang; /* optional, can be #QSE_NULL */
};
typedef struct qse_httpd_server_mimestd_t qse_httpd_server_mimestd_t;
@ -551,13 +564,16 @@ QSE_EXPORT void qse_httpd_seterrnum (
qse_httpd_errnum_t errnum
);
QSE_EXPORT int qse_httpd_getoption (
qse_httpd_t* httpd
QSE_EXPORT int qse_httpd_getopt (
qse_httpd_t* httpd,
qse_httpd_opt_t id,
void* value
);
QSE_EXPORT void qse_httpd_setoption (
qse_httpd_t* httpd,
int option
QSE_EXPORT int qse_httpd_setopt (
qse_httpd_t* httpd,
qse_httpd_opt_t id,
const void* value
);
/**
@ -758,11 +774,7 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* path,
const qse_mchar_t* script,
const qse_mchar_t* suffix,
const qse_mchar_t* docroot,
int nph,
qse_httpd_rsrc_cgi_t* cgi,
qse_htre_t* req
);

View File

@ -504,7 +504,7 @@ int qse_awk_setopt (qse_awk_t* awk, qse_awk_opt_t id, const void* value)
return -1;
}
int qse_awk_getopt (qse_awk_t* awk, qse_awk_opt_t id, void* value)
int qse_awk_getopt (qse_awk_t* awk, qse_awk_opt_t id, void* value)
{
switch (id)
{

View File

@ -33,6 +33,7 @@ struct task_cgi_arg_t
qse_mcstr_t script;
qse_mcstr_t suffix;
qse_mcstr_t docroot;
qse_mcstr_t shebang;
int nph;
qse_htre_t* req;
};
@ -47,6 +48,7 @@ struct task_cgi_t
const qse_mchar_t* script;
const qse_mchar_t* suffix;
const qse_mchar_t* docroot;
const qse_mchar_t* shebang;
qse_http_version_t version;
int keepalive; /* taken from the request */
int nph;
@ -706,10 +708,12 @@ static int task_init_cgi (
cgi->script = cgi->path + arg->path.len + 1;
cgi->suffix = cgi->script + arg->script.len + 1;
cgi->docroot = cgi->suffix + arg->suffix.len + 1;
cgi->shebang = cgi->docroot + arg->docroot.len + 1;
qse_mbscpy ((qse_mchar_t*)cgi->path, arg->path.ptr);
qse_mbscpy ((qse_mchar_t*)cgi->script, arg->script.ptr);
qse_mbscpy ((qse_mchar_t*)cgi->suffix, arg->suffix.ptr);
qse_mbscpy ((qse_mchar_t*)cgi->docroot, arg->docroot.ptr);
qse_mbscpy ((qse_mchar_t*)cgi->shebang, arg->shebang.ptr);
cgi->version = *qse_htre_getversion(arg->req);
cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
@ -737,7 +741,7 @@ static int task_init_cgi (
* such a request to entask a cgi script dropping the
* content */
if (httpd->option & QSE_HTTPD_CGINOCHUNKED)
if (httpd->opt.trait & QSE_HTTPD_CGINOCHUNKED)
{
qse_htre_discardcontent (arg->req);
cgi->reqflags |= CGI_REQ_GOTALL;
@ -844,8 +848,8 @@ done:
}
/* get the content type header value */
tmp = qse_htre_getheaderval(arg->req, QSE_MT("Content-Type"));
if (tmp) while (tmp->next) tmp = tmp->next; /* get the last value */
tmp = qse_htre_getheaderval(arg->req, QSE_MT("Content-Type"));
if (tmp) while (tmp->next) tmp = tmp->next; /* get the last value */
if (cgi_add_env (
httpd, client, cgi->env, arg->req,
@ -1332,8 +1336,9 @@ static int task_main_cgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_cgi_t* cgi = (task_cgi_t*)task->ctx;
int pio_options;
int pio_options, x;
int http_errnum = 500;
qse_mchar_t* xpath;
if (cgi->init_failed) goto oops;
@ -1368,16 +1373,31 @@ static int task_main_cgi (
}
pio_options = QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_MBSCMD;
if (httpd->option & QSE_HTTPD_CGIERRTONUL)
if (httpd->opt.trait & QSE_HTTPD_CGIERRTONUL)
pio_options |= QSE_PIO_ERRTONUL;
else
pio_options |= QSE_PIO_ERRTOOUT;
if (httpd->option & QSE_HTTPD_CGINOCLOEXEC)
if (httpd->opt.trait & QSE_HTTPD_CGINOCLOEXEC)
pio_options |= QSE_PIO_NOCLOEXEC;
if (qse_pio_init (
&cgi->pio, httpd->mmgr, (const qse_char_t*)cgi->path,
cgi->env, pio_options) <= -1)
if (cgi->shebang[0] != QSE_MT('\0'))
{
const qse_mchar_t* tmp[4];
tmp[0] = cgi->shebang;
tmp[1] = QSE_MT(" ");
tmp[2] = cgi->path;
tmp[3] = QSE_NULL;
xpath = qse_mbsadup (tmp, QSE_NULL, httpd->mmgr);
if (xpath == QSE_NULL) goto oops;
}
else xpath = cgi->path;
x = qse_pio_init (
&cgi->pio, httpd->mmgr, (const qse_char_t*)xpath,
cgi->env, pio_options);
if (xpath != cgi->path) QSE_MMGR_FREE (httpd->mmgr, xpath);
if (x <= -1)
{
qse_pio_errnum_t errnum;
@ -1468,30 +1488,31 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* path,
const qse_mchar_t* script,
const qse_mchar_t* suffix,
const qse_mchar_t* docroot,
int nph,
qse_httpd_rsrc_cgi_t* cgi,
qse_htre_t* req)
{
qse_httpd_task_t task;
task_cgi_arg_t arg;
qse_httpd_rsrc_cgi_t rsrc;
if (script == QSE_NULL) script = qse_htre_getqpath(req);
if (suffix == QSE_NULL) suffix = QSE_MT("");
if (docroot == QSE_NULL) docroot = QSE_MT("");
rsrc = *cgi;
if (rsrc.script == QSE_NULL) rsrc.script = qse_htre_getqpath(req);
if (rsrc.suffix == QSE_NULL) rsrc.suffix = QSE_MT("");
if (rsrc.docroot == QSE_NULL) rsrc.docroot = QSE_MT("");
if (rsrc.shebang == QSE_NULL) rsrc.shebang = QSE_MT("");
arg.path.ptr = path;
arg.path.len = qse_mbslen(path);
arg.script.ptr = script;
arg.script.len = qse_mbslen(script);
arg.suffix.ptr = suffix;
arg.suffix.len = qse_mbslen(suffix);
arg.docroot.ptr = docroot;
arg.docroot.len = qse_mbslen(docroot);
arg.path.ptr = rsrc.path;
arg.path.len = qse_mbslen(rsrc.path);
arg.script.ptr = rsrc.script;
arg.script.len = qse_mbslen(rsrc.script);
arg.suffix.ptr = rsrc.suffix;
arg.suffix.len = qse_mbslen(rsrc.suffix);
arg.docroot.ptr = rsrc.docroot;
arg.docroot.len = qse_mbslen(rsrc.docroot);
arg.nph = rsrc.nph;
arg.shebang.ptr = rsrc.shebang;
arg.shebang.len = qse_mbslen(rsrc.shebang);
arg.req = req;
arg.nph = nph;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_cgi;
@ -1502,10 +1523,11 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
return qse_httpd_entask (
httpd, client, pred, &task,
QSE_SIZEOF(task_cgi_t) +
((arg.path.len + 1) * QSE_SIZEOF(*path)) +
((arg.script.len + 1) * QSE_SIZEOF(*script)) +
((arg.suffix.len + 1) * QSE_SIZEOF(*suffix)) +
((arg.docroot.len + 1) * QSE_SIZEOF(*docroot))
((arg.path.len + 1) * QSE_SIZEOF(*arg.path.ptr)) +
((arg.script.len + 1) * QSE_SIZEOF(*arg.script.ptr)) +
((arg.suffix.len + 1) * QSE_SIZEOF(*arg.suffix.ptr)) +
((arg.docroot.len + 1) * QSE_SIZEOF(*arg.docroot.ptr)) +
((arg.shebang.len + 1) * QSE_SIZEOF(*arg.shebang.ptr))
);
}

View File

@ -885,7 +885,6 @@ static int task_main_proxy_5 (
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
qse_ssize_t n;
//QSE_ASSERT (proxy->pio_inited);
qse_printf (QSE_T("task_main_proxy_5 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);
@ -932,8 +931,6 @@ static int task_main_proxy_4 (
{
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
//QSE_ASSERT (proxy->pio_inited);
qse_printf (QSE_T("task_main_proxy_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);

View File

@ -2049,6 +2049,7 @@ static int attempt_cgi (
target->u.cgi.script = script;
target->u.cgi.suffix = QSE_NULL;
target->u.cgi.docroot = docroot;
target->u.cgi.shebang = cgistd[i].shebang;
return 1;
}
}
@ -2095,6 +2096,7 @@ static int attempt_cgi (
target->u.cgi.script = script;
target->u.cgi.suffix = suffix;
target->u.cgi.docroot = docroot;
target->u.cgi.shebang = cgistd[i].shebang;
return 1;
}
}
@ -2154,7 +2156,7 @@ auth_ok:
if (stx <= -1)
{
/* this OS may fail in stat_file() if the path contains the trailing
* separator. it 's beause of the way FindFirstFile() or DosQueryPathInfo()
* separator. it's beause of the way FindFirstFile() or DosQueryPathInfo()
* is ussed in stat_file(). let me work around it here. */
qse_size_t pl = qse_mbslen(xpath);
if (pl > 1 && xpath[pl - 1] == QSE_MT('/'))
@ -2271,11 +2273,12 @@ qse_httpd_server_t* qse_httpd_attachserverstd (
qse_uint16_t default_port;
qse_uri_t xuri;
static qse_httpd_server_cgistd_t server_cgistd[] =
{
{ QSE_MT(".cgi"), 4, 0 },
{ QSE_MT(".nph"), 4, 1 },
{ QSE_NULL, 0, 0 }
{ QSE_MT(".cgi"), 4, 0, QSE_NULL },
{ QSE_MT(".nph"), 4, 1, QSE_NULL },
{ QSE_NULL, 0, 0, QSE_NULL }
};
static qse_httpd_server_mimestd_t server_mimestd[] =
@ -2458,7 +2461,7 @@ int qse_httpd_getserveroptstd (
case QSE_HTTPD_SERVER_CGISTD:
case QSE_HTTPD_SERVER_MIMESTD:
case QSE_HTTPD_SERVER_IDXSTD:
*(qse_mchar_t**)value = (void*)server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD];
*(void**)value = (void*)server_xtn->cfg2.a[id - QSE_HTTPD_SERVER_CBSTD];
return 0;
}

View File

@ -405,45 +405,42 @@ qse_httpd_task_t* qse_httpd_entaskrsrc (
switch (rsrc->type)
{
case QSE_HTTPD_RSRC_AUTH:
task = qse_httpd_entaskauth (httpd, client, QSE_NULL, rsrc->u.auth.realm, req);
task = qse_httpd_entaskauth (httpd, client, pred, rsrc->u.auth.realm, req);
break;
case QSE_HTTPD_RSRC_CGI:
task = qse_httpd_entaskcgi (
httpd, client, QSE_NULL, rsrc->u.cgi.path,
rsrc->u.cgi.script, rsrc->u.cgi.suffix,
rsrc->u.cgi.docroot, rsrc->u.cgi.nph, req);
task = qse_httpd_entaskcgi (httpd, client, pred, &rsrc->u.cgi, req);
break;
case QSE_HTTPD_RSRC_DIR:
qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, req);
task = qse_httpd_entaskdir (httpd, client, pred, rsrc->u.dir.path, req);
break;
case QSE_HTTPD_RSRC_ERR:
qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, rsrc->u.err.code, req);
task = qse_httpd_entaskerr (httpd, client, pred, rsrc->u.err.code, req);
break;
case QSE_HTTPD_RSRC_FILE:
qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskfile (httpd, client, QSE_NULL, rsrc->u.file.path, rsrc->u.file.mime, req);
task = qse_httpd_entaskfile (httpd, client, pred, rsrc->u.file.path, rsrc->u.file.mime, req);
break;
case QSE_HTTPD_RSRC_PROXY:
task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &rsrc->u.proxy.dst, &rsrc->u.proxy.src, req);
task = qse_httpd_entaskproxy (httpd, client, pred, &rsrc->u.proxy.dst, &rsrc->u.proxy.src, req);
break;
case QSE_HTTPD_RSRC_RELOC:
task = qse_httpd_entaskreloc (httpd, client, QSE_NULL, rsrc->u.reloc.dst, req);
task = qse_httpd_entaskreloc (httpd, client, pred, rsrc->u.reloc.dst, req);
break;
case QSE_HTTPD_RSRC_REDIR:
task = qse_httpd_entaskredir (httpd, client, QSE_NULL, rsrc->u.redir.dst, req);
task = qse_httpd_entaskredir (httpd, client, pred, rsrc->u.redir.dst, req);
break;
case QSE_HTTPD_RSRC_TEXT:
task = qse_httpd_entasktext (httpd, client, QSE_NULL, rsrc->u.text.ptr, rsrc->u.text.mime, req);
task = qse_httpd_entasktext (httpd, client, pred, rsrc->u.text.ptr, rsrc->u.text.mime, req);
break;
default:

View File

@ -109,14 +109,30 @@ void* qse_httpd_getxtn (qse_httpd_t* httpd)
return QSE_XTN (httpd);
}
int qse_httpd_getoption (qse_httpd_t* httpd)
int qse_httpd_getopt (qse_httpd_t* httpd, qse_httpd_opt_t id, void* value)
{
return httpd->option;
switch (id)
{
case QSE_HTTPD_TRAIT:
*(int*)value = httpd->opt.trait;
return 0;
}
httpd->errnum = QSE_HTTPD_EINVAL;
return -1;
}
void qse_httpd_setoption (qse_httpd_t* httpd, int option)
int qse_httpd_setopt (qse_httpd_t* httpd, qse_httpd_opt_t id, const void* value)
{
httpd->option = option;
switch (id)
{
case QSE_HTTPD_TRAIT:
httpd->opt.trait = *(const int*)value;
return 0;
}
httpd->errnum = QSE_HTTPD_EINVAL;
return -1;
}
/* --------------------------------------------------- */
@ -640,7 +656,7 @@ qse_printf (QSE_T("Debug: connection closed %d\n"), client->handle.i);
* if QSE_HTTPD_MUTECLIENT is on, attempt to handle
* it as a half-close under a certain condition. */
if (httpd->option & QSE_HTTPD_MUTECLIENT &&
if (httpd->opt.trait & QSE_HTTPD_MUTECLIENT &&
client->task.head && client->htrd->clean)
{
/* there is still more tasks to finish and

View File

@ -35,7 +35,10 @@ struct qse_httpd_t
qse_httpd_scb_t* scb; /* system callbacks */
qse_httpd_rcb_t* rcb; /* request callbacks */
int option;
struct
{
int trait;
} opt;
int stopreq;
qse_mchar_t sname[128]; /* server name for the server header */