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:
parent
d2572d9c46
commit
5281c22503
@ -170,11 +170,10 @@ qse_uint64_t qse_randxs64 (
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
qse_size_t qse_enbase64 (
|
||||
const qse_uint8_t* in,
|
||||
const void* in,
|
||||
qse_size_t isz,
|
||||
qse_mchar_t* out,
|
||||
qse_mchar_t* out,
|
||||
qse_size_t osz,
|
||||
qse_size_t* xsz
|
||||
);
|
||||
@ -182,7 +181,7 @@ qse_size_t qse_enbase64 (
|
||||
qse_size_t qse_debase64 (
|
||||
const qse_mchar_t* in,
|
||||
qse_size_t isz,
|
||||
qse_uint8_t* out,
|
||||
void* out,
|
||||
qse_size_t osz,
|
||||
qse_size_t* xsz
|
||||
);
|
||||
|
@ -79,20 +79,26 @@ enum qse_httpd_server_flag_t
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_server_t qse_httpd_server_t;
|
||||
|
||||
typedef void (*qse_httpd_server_predetach_t) (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_server_t* server
|
||||
);
|
||||
|
||||
struct qse_httpd_server_t
|
||||
{
|
||||
/* ---------------------------------------------- */
|
||||
int flags;
|
||||
qse_nwad_t nwad; /* binding address */
|
||||
unsigned int nwif; /* interface number to bind to */
|
||||
void (*predetach) (qse_httpd_t*, qse_httpd_server_t*);
|
||||
|
||||
/* set by server.open callback */
|
||||
qse_ubi_t handle;
|
||||
|
||||
/* private */
|
||||
qse_httpd_server_t* next;
|
||||
qse_httpd_server_t* prev;
|
||||
qse_httpd_server_predetach_t predetach;
|
||||
qse_httpd_server_t* next;
|
||||
qse_httpd_server_t* prev;
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_peer_t qse_httpd_peer_t;
|
||||
@ -414,14 +420,61 @@ struct qse_httpd_ecb_t
|
||||
qse_httpd_ecb_t* next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct qse_httpd_cbstd_t qse_httpd_cbstd_t;
|
||||
struct qse_httpd_cbstd_t
|
||||
typedef struct qse_httpd_server_cbstd_t qse_httpd_server_cbstd_t;
|
||||
struct qse_httpd_server_cbstd_t
|
||||
{
|
||||
int (*makersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* required */
|
||||
void (*freersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* optional */
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_server_mimestd_t qse_httpd_server_mimestd_t;
|
||||
struct qse_httpd_server_mimestd_t
|
||||
{
|
||||
const qse_mchar_t* ext;
|
||||
const qse_mchar_t* type;
|
||||
};
|
||||
|
||||
/**
|
||||
* The qse_httpd_server_idxstd_t type defines a structure to hold
|
||||
* an index file name.
|
||||
*/
|
||||
typedef struct qse_httpd_server_idxstd_t qse_httpd_server_idxstd_t;
|
||||
struct qse_httpd_server_idxstd_t
|
||||
{
|
||||
const qse_mchar_t* name;
|
||||
};
|
||||
|
||||
enum qse_httpd_server_xtn_cfg_idx_t
|
||||
{
|
||||
QSE_HTTPD_SERVER_XTN_CFG_DOCROOT = 0,
|
||||
QSE_HTTPD_SERVER_XTN_CFG_REALM,
|
||||
QSE_HTTPD_SERVER_XTN_CFG_USERNAME,
|
||||
QSE_HTTPD_SERVER_XTN_CFG_PASSWORD,
|
||||
QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH,
|
||||
QSE_HTTPD_SERVER_XTN_CFG_MAX
|
||||
};
|
||||
|
||||
struct qse_httpd_server_xtn_t
|
||||
{
|
||||
qse_mxstr_t cfg[QSE_HTTPD_SERVER_XTN_CFG_MAX];
|
||||
qse_httpd_server_cbstd_t* cbstd;
|
||||
qse_httpd_server_cgistd_t* cgistd;
|
||||
qse_httpd_server_mimestd_t* mimestd;
|
||||
qse_httpd_server_idxstd_t* idxstd;
|
||||
|
||||
/* private */
|
||||
qse_httpd_server_predetach_t predetach;
|
||||
};
|
||||
typedef struct qse_httpd_server_xtn_t qse_httpd_server_xtn_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -498,9 +551,10 @@ void qse_httpd_stop (
|
||||
#define qse_httpd_getserverxtn(httpd,server) ((void*)(server+1))
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
void qse_httpd_detachserver (
|
||||
@ -689,7 +743,6 @@ void qse_httpd_freemem (
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
|
||||
qse_httpd_t* qse_httpd_openstd (
|
||||
qse_size_t xtnsize
|
||||
);
|
||||
@ -704,9 +757,10 @@ void* qse_httpd_getxtnstd (
|
||||
);
|
||||
|
||||
qse_httpd_server_t* qse_httpd_attachserverstd (
|
||||
qse_httpd_t* httpd,
|
||||
const qse_char_t* uri,
|
||||
qse_size_t xtnsize
|
||||
qse_httpd_t* httpd,
|
||||
const qse_char_t* uri,
|
||||
qse_httpd_server_predetach_t predetach,
|
||||
qse_size_t xtnsize
|
||||
);
|
||||
|
||||
void* qse_httpd_getserverxtnstd (
|
||||
@ -714,16 +768,12 @@ void* qse_httpd_getserverxtnstd (
|
||||
qse_httpd_server_t* server
|
||||
);
|
||||
|
||||
qse_httpd_cbstd_t* qse_httpd_getdflcbstd (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
int qse_httpd_loopstd (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_cbstd_t* cbstd,
|
||||
qse_ntime_t timeout
|
||||
);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -59,7 +59,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (qse_httpd_attachserverstd (httpd, argv[i], 0) == QSE_NULL)
|
||||
if (qse_httpd_attachserverstd (httpd, argv[i], QSE_NULL, 0) == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||
@ -72,7 +72,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
|
||||
ret = qse_httpd_loopstd (httpd, QSE_NULL, 10000);
|
||||
ret = qse_httpd_loopstd (httpd, 10000);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
|
@ -35,10 +35,20 @@
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct server_xtn_t server_xtn_t;
|
||||
struct server_xtn_t
|
||||
{
|
||||
int tproxy;
|
||||
qse_httpd_server_cbstd_t* orgcbstd;
|
||||
};
|
||||
|
||||
static int makersrc (
|
||||
@ -74,7 +84,6 @@ static int makersrc (
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_httpd_cbstd_t* dflcbstd = qse_httpd_getdflcbstd (httpd);
|
||||
#if 0
|
||||
if (dflcbstd->makersrc (httpd, client, req, rsrc) <= -1) return -1;
|
||||
if (rsrc->type == QSE_HTTPD_RSRC_DIR)
|
||||
@ -85,7 +94,7 @@ static int makersrc (
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
return dflcbstd->makersrc (httpd, client, req, rsrc);
|
||||
return server_xtn->orgcbstd->makersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,48 +110,63 @@ static void freersrc (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_httpd_cbstd_t* dflcbstd = qse_httpd_getdflcbstd (httpd);
|
||||
return dflcbstd->freersrc (httpd, client, req, rsrc);
|
||||
if (server_xtn->orgcbstd->freersrc)
|
||||
server_xtn->orgcbstd->freersrc (httpd, client, req, rsrc);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, qse_char_t* uri)
|
||||
static qse_httpd_server_t* attach_server (
|
||||
qse_httpd_t* httpd, qse_char_t* uri, qse_httpd_server_cbstd_t* cbstd)
|
||||
{
|
||||
qse_httpd_server_t* server;
|
||||
qse_httpd_server_xtn_t* server_xtn_inner;
|
||||
server_xtn_t* server_xtn;
|
||||
int tproxy = 0;
|
||||
|
||||
static qse_httpd_server_idxstd_t idxstd[] =
|
||||
{
|
||||
{ QSE_MT("index.cgi") },
|
||||
{ QSE_MT("index.html") },
|
||||
{ QSE_NULL }
|
||||
};
|
||||
|
||||
if (qse_strzcasecmp (uri, QSE_T("http-tproxy://"), 14) == 0)
|
||||
{
|
||||
tproxy = 1;
|
||||
qse_strcpy (&uri[4], &uri[11]);
|
||||
}
|
||||
|
||||
server = qse_httpd_attachserverstd (httpd, uri, QSE_SIZEOF(server_xtn_t));
|
||||
server = qse_httpd_attachserverstd (
|
||||
httpd, uri, QSE_NULL, QSE_SIZEOF(server_xtn_t));
|
||||
if (server == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* qse_httpd_getserverxtnstd() returns the pointer to
|
||||
* the extension space requested above, of the size
|
||||
* QSE_SIZEOF(server_xtn_t) */
|
||||
server_xtn = qse_httpd_getserverxtnstd (httpd, server);
|
||||
server_xtn->tproxy = tproxy;
|
||||
|
||||
/* qse_httpd_getserverxtn() returns the pointer to the
|
||||
* extension space created by qse_httpd_attachserverstd()
|
||||
* internally.
|
||||
*/
|
||||
server_xtn_inner = qse_httpd_getserverxtn (httpd, server);
|
||||
/* remember the callback set in qse_httpd_attachserverstd() */
|
||||
server_xtn->orgcbstd = server_xtn_inner->cbstd;
|
||||
/* override it with a new callback for chaining */
|
||||
server_xtn_inner->cbstd = cbstd;
|
||||
server_xtn_inner->idxstd = idxstd; /* override index file list */
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
int ret = -1, i;
|
||||
static qse_httpd_cbstd_t cbstd = { makersrc, freersrc };
|
||||
static qse_httpd_server_cbstd_t cbstd = { makersrc, freersrc };
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
@ -159,7 +183,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (attach_server (httpd, argv[i]) == QSE_NULL)
|
||||
if (attach_server (httpd, argv[i], &cbstd) == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||
@ -174,7 +198,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
qse_httpd_setname (httpd, QSE_MT("httpd02/qse 1.0"));
|
||||
|
||||
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
|
||||
ret = qse_httpd_loopstd (httpd, &cbstd, 10000);
|
||||
ret = qse_httpd_loopstd (httpd, 10000);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user