diff --git a/qse/cmd/net/httpd.c b/qse/cmd/net/httpd.c index 7acc1102..5ed04388 100644 --- a/qse/cmd/net/httpd.c +++ b/qse/cmd/net/httpd.c @@ -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")); diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index e1827e31..927ee2a8 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -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 ); diff --git a/qse/lib/awk/awk.c b/qse/lib/awk/awk.c index 0e9e4c8c..5d5a9443 100644 --- a/qse/lib/awk/awk.c +++ b/qse/lib/awk/awk.c @@ -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) { diff --git a/qse/lib/net/httpd-cgi.c b/qse/lib/net/httpd-cgi.c index 16630261..2872d04a 100644 --- a/qse/lib/net/httpd-cgi.c +++ b/qse/lib/net/httpd-cgi.c @@ -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)) ); } diff --git a/qse/lib/net/httpd-proxy.c b/qse/lib/net/httpd-proxy.c index 59a0258a..836df521 100644 --- a/qse/lib/net/httpd-proxy.c +++ b/qse/lib/net/httpd-proxy.c @@ -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); diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index 1c64e751..45c97e99 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -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; } diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index 9b3c99fb..8397d157 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -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: diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index deba6258..c8b29cbc 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -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 diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index b7e1fbf2..972a3393 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -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 */