added qse_httpd_server_cgistd_t, qse_httpd_server_idxstd_t, qse_httpd_server_mimestd_t.

changed qse_httpd_cbstd_t to qse_httpd_server_cbstd_t.
change qse_httpd_attachserver() and qse_httpd_attacheserverstd()
This commit is contained in:
2012-10-02 17:33:29 +00:00
parent d2572d9c46
commit 5281c22503
7 changed files with 491 additions and 330 deletions

View File

@ -33,9 +33,10 @@
(x == QSE_MT('+'))? 62: 63)
qse_size_t qse_enbase64 (
const qse_uint8_t* in, qse_size_t isz,
const void* in, qse_size_t isz,
qse_mchar_t* out, qse_size_t osz, qse_size_t* xsz)
{
const qse_uint8_t* ib = (const qse_uint8_t*)in;
qse_size_t idx = 0, idx2 = 0, i;
/* 3 8-bit values to 4 6-bit values */
@ -45,9 +46,9 @@ qse_size_t qse_enbase64 (
qse_uint8_t b1, b2, b3;
qse_uint8_t c1, c2, c3, c4;
b1 = in[i];
b2 = (i + 1 < isz)? in[i + 1]: 0;
b3 = (i + 2 < isz)? in[i + 2]: 0;
b1 = ib[i];
b2 = (i + 1 < isz)? ib[i + 1]: 0;
b3 = (i + 2 < isz)? ib[i + 2]: 0;
c1 = b1 >> 2;
c2 = ((b1 & 0x03) << 4) | (b2 >> 4);
@ -70,8 +71,9 @@ qse_size_t qse_enbase64 (
qse_size_t qse_debase64 (
const qse_mchar_t* in, qse_size_t isz,
qse_uint8_t* out, qse_size_t osz, qse_size_t* xsz)
void* out, qse_size_t osz, qse_size_t* xsz)
{
qse_uint8_t* ob = (qse_uint8_t*)out;
qse_size_t idx = 0, idx2 = 0, i;
for (i = 0; i < isz; i += 4)
@ -90,17 +92,17 @@ qse_size_t qse_debase64 (
b4 = DEC(c4);
idx2++;
if (idx < osz) out[idx++] = (b1 << 2) | (b2 >> 4);
if (idx < osz) ob[idx++] = (b1 << 2) | (b2 >> 4);
if (c3 != QSE_MT('='))
{
idx2++;
if (idx < osz) out[idx++] = ((b2 & 0x0F) << 4) | (b3 >> 2);
if (idx < osz) ob[idx++] = ((b2 & 0x0F) << 4) | (b3 >> 2);
}
if (c4 != QSE_MT('='))
{
idx2++;
if (idx < osz) out[idx++] = ((b3 & 0x03) << 6) | b4;
if (idx < osz) ob[idx++] = ((b3 & 0x03) << 6) | b4;
}
}

View File

@ -26,6 +26,7 @@
#include <qse/cmn/str.h>
#include <qse/cmn/uri.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/path.h>
#if defined(_WIN32)
# include <winsock2.h>
@ -68,19 +69,12 @@
#define DEFAULT_PORT 80
#define DEFAULT_SECURE_PORT 443
struct server_xtn_t
{
#define CFG_DOCROOT 0
#define CFG_REALM 1
#define CFG_USERNAME 2
#define CFG_PASSWORD 3
#define CFG_BASICAUTH 4
#define CFG_BASICAUTH_B64 5
qse_mxstr_t cfg[6];
};
typedef struct server_xtn_t server_xtn_t;
#define server_xtn_t qse_httpd_server_xtn_t
#define SERVER_XTN_CFG_DOCROOT QSE_HTTPD_SERVER_XTN_CFG_DOCROOT
#define SERVER_XTN_CFG_REALM QSE_HTTPD_SERVER_XTN_CFG_REALM
#define SERVER_XTN_CFG_USERNAME QSE_HTTPD_SERVER_XTN_CFG_USERNAME
#define SERVER_XTN_CFG_PASSWORD QSE_HTTPD_SERVER_XTN_CFG_PASSWORD
#define SERVER_XTN_CFG_BASICAUTH QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH
/* ------------------------------------------------------------------- */
#if defined(_WIN32)
@ -322,7 +316,6 @@ static qse_ssize_t xsendfile_ssl (
typedef struct httpd_xtn_t httpd_xtn_t;
struct httpd_xtn_t
{
qse_httpd_cbstd_t* cbstd;
#if defined(HAVE_SSL)
SSL_CTX* ssl_ctx;
#endif
@ -419,143 +412,6 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd)
return (void*)((httpd_xtn_t*)QSE_XTN(httpd) + 1);
}
static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
{
server_xtn_t* server_xtn;
qse_size_t i;
server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server);
for (i = QSE_COUNTOF(server_xtn->cfg); i > 0; )
{
i--;
if (server_xtn->cfg[i].ptr)
{
QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i].ptr);
server_xtn->cfg[i].ptr = QSE_NULL;
server_xtn->cfg[i].len = 0;
}
}
}
qse_httpd_server_t* qse_httpd_attachserverstd (
qse_httpd_t* httpd, const qse_char_t* uri, qse_size_t xtnsize)
{
qse_httpd_server_t server;
qse_httpd_server_t* xserver;
server_xtn_t* server_xtn;
qse_mcstr_t tmp[4];
qse_uint16_t default_port;
qse_size_t i;
qse_uri_t xuri;
QSE_MEMSET (&server, 0, QSE_SIZEOF(server));
if (qse_strtouri (uri, &xuri, QSE_STRTOURI_NOQUERY) <= -1) goto invalid;
if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("http")) == 0)
{
default_port = DEFAULT_PORT;
}
else if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("https")) == 0)
{
server.flags |= QSE_HTTPD_SERVER_SECURE;
default_port = DEFAULT_SECURE_PORT;
}
else goto invalid;
if (qse_strntonwad (
xuri.host.ptr,
xuri.host.len + (xuri.port.ptr? (xuri.port.len + 1): 0),
&server.nwad) <= -1) goto invalid;
if (server.nwad.type == QSE_NWAD_IN4)
{
if (server.nwad.u.in4.port == 0)
server.nwad.u.in4.port = qse_hton16(default_port);
}
else if (server.nwad.type == QSE_NWAD_IN6)
{
if (server.nwad.u.in6.port == 0)
server.nwad.u.in6.port = qse_hton16(default_port);
}
server.predetach = predetach_server;
xserver = qse_httpd_attachserver (httpd, &server, QSE_SIZEOF(*server_xtn) + xtnsize);
if (xserver == QSE_NULL) return QSE_NULL;
server_xtn = qse_httpd_getserverxtn (httpd, xserver);
#if defined(QSE_CHAR_IS_MCHAR)
if (xuri.path.ptr) server_xtn->cfg[CFG_DOCROOT].ptr = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[CFG_USERNAME].ptr = qse_mbsxdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[CFG_PASSWORD].ptr = qse_mbsxdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[CFG_REALM].ptr = qse_mbsxdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr);
#else
if (xuri.path.ptr) server_xtn->cfg[CFG_DOCROOT].ptr = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[CFG_USERNAME].ptr = qse_wcsntombsdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[CFG_PASSWORD].ptr = qse_wcsntombsdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[CFG_REALM].ptr = qse_wcsntombsdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr);
#endif
if ((xuri.path.ptr && !server_xtn->cfg[CFG_DOCROOT].ptr) ||
(xuri.auth.user.ptr && !server_xtn->cfg[CFG_USERNAME].ptr) ||
(xuri.auth.pass.ptr && !server_xtn->cfg[CFG_PASSWORD].ptr) ||
(xuri.frag.ptr && !server_xtn->cfg[CFG_REALM].ptr)) goto nomem_after_attach;
for (i = 0; i < QSE_COUNTOF(server_xtn->cfg); i++)
{
if (server_xtn->cfg[i].ptr)
server_xtn->cfg[i].len = qse_mbslen(server_xtn->cfg[i].ptr);
}
tmp[0].ptr = server_xtn->cfg[CFG_USERNAME].ptr? server_xtn->cfg[CFG_USERNAME].ptr: QSE_MT("");
tmp[0].len = server_xtn->cfg[CFG_USERNAME].len;
tmp[1].ptr = QSE_MT(":");
tmp[1].len = 1;
tmp[2].ptr = server_xtn->cfg[CFG_PASSWORD].ptr? server_xtn->cfg[CFG_PASSWORD].ptr: QSE_MT("");
tmp[2].len = server_xtn->cfg[CFG_PASSWORD].len;
tmp[3].ptr = QSE_NULL;
tmp[3].len = 0;
server_xtn->cfg[CFG_BASICAUTH].ptr = qse_mbsxadup (tmp, httpd->mmgr);
if (!server_xtn->cfg[CFG_BASICAUTH].ptr) goto nomem_after_attach;
server_xtn->cfg[CFG_BASICAUTH].len = qse_mbslen (server_xtn->cfg[CFG_BASICAUTH].ptr);
server_xtn->cfg[CFG_BASICAUTH_B64].len = ((server_xtn->cfg[CFG_BASICAUTH].len / 3) + 1) * 4;
server_xtn->cfg[CFG_BASICAUTH_B64].ptr = QSE_MMGR_ALLOC (
httpd->mmgr,
(server_xtn->cfg[CFG_BASICAUTH_B64].len + 1) * QSE_SIZEOF(qse_mchar_t));
if (!server_xtn->cfg[CFG_BASICAUTH_B64].ptr) goto nomem_after_attach;
qse_enbase64 (
server_xtn->cfg[CFG_BASICAUTH].ptr,
server_xtn->cfg[CFG_BASICAUTH].len,
server_xtn->cfg[CFG_BASICAUTH_B64].ptr,
server_xtn->cfg[CFG_BASICAUTH_B64].len,
&server_xtn->cfg[CFG_BASICAUTH_B64].len
);
server_xtn->cfg[CFG_BASICAUTH_B64].ptr[server_xtn->cfg[CFG_BASICAUTH_B64].len] = QSE_MT('\0');
return xserver;
invalid:
httpd->errnum = QSE_HTTPD_EINVAL;
return QSE_NULL;
nomem_after_attach:
qse_httpd_detachserver (httpd, xserver);
httpd->errnum = QSE_HTTPD_ENOMEM;
return QSE_NULL;
}
void* qse_httpd_getserverxtnstd (qse_httpd_t* httpd, qse_httpd_server_t* server)
{
server_xtn_t* xtn = qse_httpd_getserverxtn (httpd, server);
return (void*)(xtn + 1);
}
/* ------------------------------------------------------------------- */
union sockaddr_t
@ -1500,9 +1356,9 @@ static int process_request (
int method;
qse_httpd_task_t* task;
int content_received;
httpd_xtn_t* xtn;
server_xtn_t* server_xtn;
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server);
method = qse_htre_getqmethodtype(req);
content_received = (qse_htre_getcontentlen(req) > 0);
@ -1576,7 +1432,7 @@ if (qse_htre_getcontentlen(req) > 0)
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
}
}
else if (xtn->cbstd->makersrc (httpd, client, req, &rsrc) <= -1)
else if (server_xtn->cbstd->makersrc (httpd, client, req, &rsrc) <= -1)
{
qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req);
@ -1584,7 +1440,7 @@ if (qse_htre_getcontentlen(req) > 0)
else
{
task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req);
if (xtn->cbstd->freersrc) xtn->cbstd->freersrc (httpd, client, req, &rsrc);
if (server_xtn->cbstd->freersrc) server_xtn->cbstd->freersrc (httpd, client, req, &rsrc);
}
if (task == QSE_NULL) goto oops;
}
@ -1680,6 +1536,7 @@ static qse_httpd_rcb_t httpd_request_callbacks =
handle_request
};
/* ------------------------------------------------------------------- */
static void free_resource (
qse_httpd_t* httpd, qse_httpd_client_t* client,
@ -1715,41 +1572,127 @@ static void free_resource (
}
}
static qse_mchar_t* merge_paths (
qse_httpd_t* httpd, const qse_mchar_t* base, const qse_mchar_t* path)
{
qse_mchar_t* xpath;
const qse_mchar_t* ta[4];
qse_size_t idx = 0;
ta[idx++] = base;
ta[idx++] = QSE_MT("/");
ta[idx++] = path;
ta[idx++] = QSE_NULL;
xpath = qse_mbsadup (ta, httpd->mmgr);
if (xpath == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
return QSE_NULL;
}
qse_canonmbspath (xpath, xpath, 0);
return xpath;
}
static int attempt_cgi (
qse_httpd_t* httpd, const qse_mchar_t* docroot,
qse_mchar_t* xpath, const qse_mchar_t* qpath, const qse_mchar_t* idxfile,
qse_httpd_server_cgistd_t cgistd[], qse_httpd_rsrc_t* target)
{
qse_mchar_t* ext;
qse_mchar_t* script, * suffix;
qse_size_t i;
if (idxfile)
{
for (i = 0; cgistd[i].ext; i++)
{
if (qse_mbsend (idxfile, cgistd[i].ext))
{
script = merge_paths (httpd, qpath, idxfile);
if (script == QSE_NULL) return -1;
target->type = QSE_HTTPD_RSRC_CGI;
target->u.cgi.nph = cgistd[i].nph;
target->u.cgi.path = xpath;
target->u.cgi.script = script;
target->u.cgi.suffix = QSE_NULL;
target->u.cgi.docroot = docroot;
return 1;
}
}
}
else
{
for (i = 0; cgistd[i].ext; i++)
{
/* TODO: attempt other segments if qpath is like
* /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only.
* x.cgi could be a directory name .
*/
ext = qse_mbsstr (qpath, cgistd[i].ext);
if (ext && (ext[cgistd[i].len] == QSE_MT('/') ||
ext[cgistd[i].len] == QSE_MT('\0')))
{
if (ext[cgistd[i].len] == QSE_MT('/'))
{
/* it has a path suffix */
script = qse_mbsxdup (qpath, ext - qpath + cgistd[i].len, httpd->mmgr);
suffix = qse_mbsdup (&ext[cgistd[i].len], httpd->mmgr);
if (script == QSE_NULL || suffix == QSE_NULL)
{
if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix);
if (script) QSE_MMGR_FREE (httpd->mmgr, script);
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
/* drop the suffix part */
xpath[qse_mbslen(xpath) - qse_mbslen(suffix)] = QSE_MT('\0');
}
else
{
/* it has no path suffix */
script = qpath;
suffix = QSE_NULL;
}
target->type = QSE_HTTPD_RSRC_CGI;
target->u.cgi.nph = cgistd[i].nph;
target->u.cgi.path = xpath;
target->u.cgi.script = script;
target->u.cgi.suffix = suffix;
target->u.cgi.docroot = docroot;
return 1;
}
}
}
return 0;
}
static int make_resource (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_htre_t* req, qse_httpd_rsrc_t* target)
{
static struct extinfo_t
{
const qse_mchar_t* ptr;
qse_size_t len;
int nph;
} extinfo[] =
{
{ QSE_MT(".cgi"), 4, 0 },
{ QSE_MT(".nph"), 4, 1 }
};
qse_size_t i;
const qse_mchar_t* qpath;
qse_stat_t st;
server_xtn_t* server_xtn;
qse_mchar_t* xpath;
const qse_mchar_t* qpath;
const qse_mchar_t* idxfile;
qse_mchar_t* xpath;
qse_stat_t st;
qse_size_t i;
int n;
qpath = qse_htre_getqpath(req);
QSE_MEMSET (target, 0, QSE_SIZEOF(*target));
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
#if 0
target->type = QSE_HTTPD_RSRC_PROXY;
target->u.proxy.dst = client->orgdst_addr;
target->u.proxy.src = client->remote_addr;
target->u.proxy.src.u.in4.port = 0;
return 0;
#endif
if (server_xtn->cfg[CFG_REALM].ptr && server_xtn->cfg[CFG_BASICAUTH_B64].ptr)
if (server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr &&
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr)
{
const qse_htre_hdrval_t* auth;
@ -1760,148 +1703,289 @@ return 0;
if (qse_mbszcasecmp(auth->ptr, QSE_MT("Basic "), 6) == 0)
{
if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[CFG_BASICAUTH_B64].ptr) == 0) goto auth_ok;
if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr) == 0) goto auth_ok;
}
}
target->type = QSE_HTTPD_RSRC_AUTH;
target->u.auth.realm = server_xtn->cfg[CFG_REALM].ptr;
target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr;
return 0;
}
auth_ok:
if (server_xtn->cfg[CFG_DOCROOT].ptr || qpath[0] != QSE_MT('/'))
{
const qse_mchar_t* ta[4];
qse_size_t idx = 0;
if (server_xtn->cfg[CFG_DOCROOT].ptr) ta[idx++] = server_xtn->cfg[CFG_DOCROOT].ptr;
if (qpath[0] != QSE_MT('/')) ta[idx++] = QSE_MT("/");
ta[idx++] = qpath;
ta[idx++] = QSE_NULL;
xpath = qse_mbsadup (ta, httpd->mmgr);
if (xpath == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
else xpath = qpath;
idxfile = QSE_NULL;
xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr, qpath);
if (xpath == QSE_NULL) return -1;
if (QSE_STAT (xpath, &st) == 0 && S_ISDIR(st.st_mode))
{
/* TODO: attempt the index file like index.html, index.cgi, etc. */
/* it is a directory */
if (server_xtn->idxstd)
{
/* try to locate an index file */
for (i = 0; server_xtn->idxstd[i].name; i++)
{
qse_mchar_t* tpath;
tpath = merge_paths (httpd, xpath, server_xtn->idxstd[i].name);
if (tpath == QSE_NULL)
{
QSE_MMGR_FREE (httpd->mmgr, xpath);
return -1;
}
if (QSE_STAT (tpath, &st) == 0 && S_ISREG(st.st_mode))
{
/* the index file is found */
QSE_MMGR_FREE (httpd->mmgr, xpath);
xpath = tpath;
idxfile = server_xtn->idxstd[i].name;
goto attempt_file;
}
QSE_MMGR_FREE (httpd->mmgr, tpath);
}
}
target->type = QSE_HTTPD_RSRC_DIR;
target->u.dir.path = xpath;
}
else
{
/* TODO: attempt other segments if qpath is like
* /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only.
* x.cgi could be a directory name .
*/
for (i = 0; i < QSE_COUNTOF(extinfo); i++)
attempt_file:
if (server_xtn->cgistd)
{
const qse_mchar_t* ext;
ext = qse_mbsstr (qpath, extinfo[i].ptr);
if (ext && (ext[extinfo[i].len] == QSE_MT('/') ||
ext[extinfo[i].len] == QSE_MT('\0')))
/* check if the request can resolve to a cgi script */
n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr,
xpath, qpath, idxfile, server_xtn->cgistd, target);
if (n <= -1)
{
qse_mchar_t* script, * suffix, * docroot;
if (ext[extinfo[i].len] == QSE_MT('/'))
{
if (xpath != qpath)
QSE_MMGR_FREE (httpd->mmgr, xpath);
if (server_xtn->cfg[CFG_DOCROOT].ptr)
{
xpath = qse_mbsxdup2 (
server_xtn->cfg[CFG_DOCROOT].ptr,
server_xtn->cfg[CFG_DOCROOT].len,
qpath, ext - qpath + extinfo[i].len, httpd->mmgr);
}
else
{
xpath = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr);
}
script = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr);
suffix = qse_mbsdup (&ext[extinfo[i].len], httpd->mmgr);
if (xpath == QSE_NULL || script == QSE_NULL || suffix == QSE_NULL)
{
if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix);
if (script) QSE_MMGR_FREE (httpd->mmgr, script);
if (xpath) QSE_MMGR_FREE (httpd->mmgr, xpath);
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
docroot = server_xtn->cfg[CFG_DOCROOT].ptr;
}
else
{
script = qpath;
suffix = QSE_NULL;
docroot = QSE_NULL;
}
target->type = QSE_HTTPD_RSRC_CGI;
target->u.cgi.nph = extinfo[i].nph;
target->u.cgi.path = xpath;
target->u.cgi.script = script;
target->u.cgi.suffix = suffix;
target->u.cgi.docroot = docroot;
return 0;
QSE_MMGR_FREE (httpd->mmgr, xpath);
return -1;
}
if (n >= 1) return 0;
}
/* fall back to a normal file. */
target->type = QSE_HTTPD_RSRC_FILE;
target->u.file.path = xpath;
target->u.file.mime =
qse_mbsend (qpath, QSE_MT(".html"))? QSE_MT("text/html"):
qse_mbsend (qpath, QSE_MT(".txt"))? QSE_MT("text/plain"):
qse_mbsend (qpath, QSE_MT(".log"))? QSE_MT("text/plain"):
qse_mbsend (qpath, QSE_MT(".css"))? QSE_MT("text/css"):
qse_mbsend (qpath, QSE_MT(".xml"))? QSE_MT("text/xml"):
qse_mbsend (qpath, QSE_MT(".js"))? QSE_MT("application/javascript"):
qse_mbsend (qpath, QSE_MT(".jpg"))? QSE_MT("image/jpeg"):
qse_mbsend (qpath, QSE_MT(".png"))? QSE_MT("image/png"):
qse_mbsend (qpath, QSE_MT(".mp4"))? QSE_MT("video/mp4"):
qse_mbsend (qpath, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"):
qse_mbsend (qpath, QSE_MT(".c"))? QSE_MT("text/plain"):
qse_mbsend (qpath, QSE_MT(".h"))? QSE_MT("text/plain"):
QSE_NULL;
target->u.file.mime = QSE_NULL;
if (server_xtn->mimestd)
{
for (i = 0; server_xtn->mimestd[i].ext; i++)
{
/* TODO: require the table sorted and so the binary search */
if (qse_mbsend (qpath, server_xtn->mimestd[i].ext))
target->u.file.mime = server_xtn->mimestd[i].type;
}
}
}
return 0;
}
static qse_httpd_cbstd_t httpd_cbstd =
static qse_httpd_server_cbstd_t server_cbstd =
{
make_resource,
free_resource
};
/* ------------------------------------------------------------------- */
qse_httpd_cbstd_t* qse_httpd_getdflcbstd (qse_httpd_t* httpd)
static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
{
return &httpd_cbstd;
server_xtn_t* server_xtn;
qse_size_t i;
server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server);
if (server_xtn->predetach) server_xtn->predetach (httpd, server);
for (i = QSE_COUNTOF(server_xtn->cfg); i > 0; )
{
i--;
if (server_xtn->cfg[i].ptr)
{
QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i].ptr);
server_xtn->cfg[i].ptr = QSE_NULL;
server_xtn->cfg[i].len = 0;
}
}
}
int qse_httpd_loopstd (qse_httpd_t* httpd, qse_httpd_cbstd_t* cbstd, qse_ntime_t timeout)
qse_httpd_server_t* qse_httpd_attachserverstd (
qse_httpd_t* httpd, const qse_char_t* uri,
qse_httpd_server_predetach_t predetach, qse_size_t xtnsize)
{
httpd_xtn_t* xtn;
qse_httpd_server_t server;
qse_httpd_server_t* xserver;
server_xtn_t* server_xtn;
qse_mcstr_t tmp[4];
qse_mxstr_t ba;
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
qse_uint16_t default_port;
qse_size_t i;
qse_uri_t xuri;
if (cbstd) xtn->cbstd = cbstd;
else xtn->cbstd = &httpd_cbstd;
static qse_httpd_server_cgistd_t server_cgistd[] =
{
{ QSE_MT(".cgi"), 4, 0 },
{ QSE_MT(".nph"), 4, 1 },
{ QSE_NULL, 0, 0 }
};
static qse_httpd_server_mimestd_t server_mimestd[] =
{
{ QSE_MT(".html"), QSE_MT("text/html") },
{ QSE_MT(".htm"), QSE_MT("text/htm") },
{ QSE_MT(".txt"), QSE_MT("text/plain") },
{ QSE_MT(".log"), QSE_MT("text/plain") },
{ QSE_MT(".css"), QSE_MT("text/css") },
{ QSE_MT(".xml"), QSE_MT("text/xml") },
{ QSE_MT(".js"), QSE_MT("application/javascript") },
{ QSE_MT(".jpg"), QSE_MT("image/jpeg") },
{ QSE_MT(".png"), QSE_MT("image/png") },
{ QSE_MT(".mp4"), QSE_MT("video/mp4") },
{ QSE_MT(".mp3"), QSE_MT("audio/mpeg") },
{ QSE_MT(".c"), QSE_MT("text/plain") },
{ QSE_MT(".h"), QSE_MT("text/plain") },
{ QSE_MT(".cpp"), QSE_MT("text/plain") },
{ QSE_MT(".hpp"), QSE_MT("text/plain") },
{ QSE_NULL, QSE_NULL }
};
QSE_MEMSET (&server, 0, QSE_SIZEOF(server));
if (qse_strtouri (uri, &xuri, QSE_STRTOURI_NOQUERY) <= -1) goto invalid;
if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("http")) == 0)
{
default_port = DEFAULT_PORT;
}
else if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("https")) == 0)
{
server.flags |= QSE_HTTPD_SERVER_SECURE;
default_port = DEFAULT_SECURE_PORT;
}
else goto invalid;
if (qse_strntonwad (
xuri.host.ptr,
xuri.host.len + (xuri.port.ptr? (xuri.port.len + 1): 0),
&server.nwad) <= -1) goto invalid;
if (server.nwad.type == QSE_NWAD_IN4)
{
if (server.nwad.u.in4.port == 0)
server.nwad.u.in4.port = qse_hton16(default_port);
}
else if (server.nwad.type == QSE_NWAD_IN6)
{
if (server.nwad.u.in6.port == 0)
server.nwad.u.in6.port = qse_hton16(default_port);
}
xserver = qse_httpd_attachserver (
httpd, &server, predetach_server, QSE_SIZEOF(*server_xtn) + xtnsize);
if (xserver == QSE_NULL) return QSE_NULL;
server_xtn = qse_httpd_getserverxtn (httpd, xserver);
if (!xuri.path.ptr)
{
#if defined(QSE_CHAR_IS_MCHAR)
xuri.path.ptr = QSE_MT("/");
#else
xuri.path.ptr = QSE_WT("/");
#endif
xuri.path.len = 1;
}
#if defined(QSE_CHAR_IS_MCHAR)
server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.path.ptr) server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr = qse_mbsxdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr = qse_mbsxdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr = qse_mbsxdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr);
#else
server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr = qse_wcsntombsdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr = qse_wcsntombsdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr = qse_wcsntombsdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr);
#endif
if ((!server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr) ||
(xuri.auth.user.ptr && !server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr) ||
(xuri.auth.pass.ptr && !server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr) ||
(xuri.frag.ptr && !server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr)) goto nomem_after_attach;
for (i = 0; i < QSE_COUNTOF(server_xtn->cfg); i++)
{
if (server_xtn->cfg[i].ptr)
server_xtn->cfg[i].len = qse_mbslen(server_xtn->cfg[i].ptr);
}
tmp[0].ptr = server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr? server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr: QSE_MT("");
tmp[0].len = server_xtn->cfg[SERVER_XTN_CFG_USERNAME].len;
tmp[1].ptr = QSE_MT(":");
tmp[1].len = 1;
tmp[2].ptr = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr? server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr: QSE_MT("");
tmp[2].len = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].len;
tmp[3].ptr = QSE_NULL;
tmp[3].len = 0;
ba.ptr = qse_mbsxadup (tmp, httpd->mmgr);
if (!ba.ptr) goto nomem_after_attach;
ba.len = tmp[0].len + tmp[1].len + tmp[2].len;
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len = ((ba.len / 3) + 1) * 4;
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr = QSE_MMGR_ALLOC (
httpd->mmgr,
(server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len + 1) * QSE_SIZEOF(qse_mchar_t)
);
if (!server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr)
{
QSE_MMGR_FREE (httpd->mmgr, ba.ptr);
goto nomem_after_attach;
}
qse_enbase64 (
ba.ptr, ba.len,
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr,
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len,
&server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len
);
QSE_MMGR_FREE (httpd->mmgr, ba.ptr);
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr[server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len] = QSE_MT('\0');
server_xtn->predetach = predetach;
server_xtn->cbstd = &server_cbstd;
server_xtn->cgistd = server_cgistd;
server_xtn->mimestd = server_mimestd;
server_xtn->idxstd = QSE_NULL;
return xserver;
invalid:
httpd->errnum = QSE_HTTPD_EINVAL;
return QSE_NULL;
nomem_after_attach:
qse_httpd_detachserver (httpd, xserver);
httpd->errnum = QSE_HTTPD_ENOMEM;
return QSE_NULL;
}
void* qse_httpd_getserverxtnstd (qse_httpd_t* httpd, qse_httpd_server_t* server)
{
server_xtn_t* xtn = qse_httpd_getserverxtn (httpd, server);
return (void*)(xtn + 1);
}
/* ------------------------------------------------------------------- */
int qse_httpd_loopstd (qse_httpd_t* httpd, qse_ntime_t timeout)
{
return qse_httpd_loop (
httpd, &httpd_system_callbacks,
&httpd_request_callbacks, timeout);

View File

@ -532,7 +532,8 @@ static void free_server_list (qse_httpd_t* httpd)
}
qse_httpd_server_t* qse_httpd_attachserver (
qse_httpd_t* httpd, const qse_httpd_server_t* tmpl, qse_size_t xtnsize)
qse_httpd_t* httpd, const qse_httpd_server_t* tmpl,
qse_httpd_server_predetach_t predetach, qse_size_t xtnsize)
{
qse_httpd_server_t* server;
@ -543,6 +544,7 @@ qse_httpd_server_t* qse_httpd_attachserver (
QSE_MEMSET (server + 1, 0, xtnsize);
server->flags &= ~QSE_HTTPD_SERVER_ACTIVE;
server->predetach = predetach;
/* chain the server to the tail of the list */
server->prev = httpd->server.list.tail;