moved directory list formatting to qse_httpd_rcb_t.

added some entask variants
modified qse_mbsadup()/qse_mbsxadup()/qse_wcsadup(0/qse_wcsxadup() to return length
This commit is contained in:
hyung-hwan 2012-10-16 08:54:07 +00:00
parent 7940a758d0
commit c6530a1c13
13 changed files with 502 additions and 305 deletions

View File

@ -994,11 +994,13 @@ qse_mchar_t* qse_mbsxdup2 (
qse_mchar_t* qse_mbsadup (
const qse_mchar_t* str[],
qse_size_t* len,
qse_mmgr_t* mmgr
);
qse_mchar_t* qse_mbsxadup (
const qse_mcstr_t str[],
qse_size_t* len,
qse_mmgr_t* mmgr
);
@ -1029,11 +1031,13 @@ qse_wchar_t* qse_wcsxdup2 (
qse_wchar_t* qse_wcsadup (
const qse_wchar_t* str[],
qse_size_t* len,
qse_mmgr_t* mmgr
);
qse_wchar_t* qse_wcsxadup (
const qse_wcstr_t str[],
qse_size_t* len,
qse_mmgr_t* mmgr
);
@ -1042,15 +1046,15 @@ qse_wchar_t* qse_wcsxadup (
# define qse_strdup2(s1,s2,mmgr) qse_mbsdup2(s1,s2,mmgr)
# define qse_strxdup(s,l,mmgr) qse_mbsxdup(s,l,mmgr)
# define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_mbsxdup(s1,l1,s2,l2,mmgr)
# define qse_stradup(sa,mmgr) qse_mbsadup(sa,mmgr)
# define qse_strxadup(sa,mmgr) qse_mbsxadup(sa,mmgr)
# define qse_stradup(sa,len,mmgr) qse_mbsadup(sa,len,mmgr)
# define qse_strxadup(sa,len,mmgr) qse_mbsxadup(sa,len,mmgr)
#else
# define qse_strdup(s,mmgr) qse_wcsdup(s,mmgr)
# define qse_strdup2(s1,s2,mmgr) qse_wcsdup2(s1,s2,mmgr)
# define qse_strxdup(s,l,mmgr) qse_wcsxdup(s,l,mmgr)
# define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_wcsxdup(s1,l1,s2,l2,mmgr)
# define qse_stradup(sa,mmgr) qse_wcsadup(sa,mmgr)
# define qse_strxadup(sa,mmgr) qse_wcsxadup(sa,mmgr)
# define qse_stradup(sa,len,mmgr) qse_wcsadup(sa,len,mmgr)
# define qse_strxadup(sa,len,mmgr) qse_wcsxadup(sa,len,mmgr)
#endif
/**

View File

@ -163,6 +163,10 @@ int qse_comparehttpversions (
const qse_http_version_t* v2
);
const qse_mchar_t* qse_httpstatustombs (
int code
);
const qse_mchar_t* qse_httpmethodtombs (
qse_http_method_t type
);

View File

@ -46,6 +46,7 @@ enum qse_httpd_errnum_t
QSE_HTTPD_EEXIST,
QSE_HTTPD_EINTR,
QSE_HTTPD_EAGAIN,
QSE_HTTPD_ENOBUF,
QSE_HTTPD_EIOMUX,
QSE_HTTPD_EDISCON, /* client disconnnected */
@ -255,6 +256,14 @@ struct qse_httpd_rcb_t
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
int (*handle_request) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
int (*format_error) (
qse_httpd_t* httpd, qse_httpd_client_t* client,
int code, qse_mchar_t* buf, int bufsz);
int (*format_dir) (
qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_mchar_t* qpath, const qse_httpd_dirent_t* dirent,
qse_mchar_t* buf, int bufsz);
};
typedef struct qse_httpd_task_t qse_httpd_task_t;
@ -358,6 +367,7 @@ enum qse_httpd_rsrc_type_t
QSE_HTTPD_RSRC_FILE,
QSE_HTTPD_RSRC_PROXY,
QSE_HTTPD_RSRC_RELOC,
QSE_HTTPD_RSRC_REDIR,
QSE_HTTPD_RSRC_TEXT
};
typedef enum qse_httpd_rsrc_type_t qse_httpd_rsrc_type_t;
@ -384,7 +394,6 @@ struct qse_httpd_rsrc_t
struct
{
const qse_mchar_t* path;
const qse_mchar_t* css;
} dir;
struct
@ -403,11 +412,17 @@ struct qse_httpd_rsrc_t
qse_nwad_t dst;
qse_nwad_t src;
} proxy;
struct
{
const qse_mchar_t* dst;
} reloc;
struct
{
const qse_mchar_t* dst;
} redir;
struct
{
const qse_mchar_t* ptr;
@ -488,7 +503,7 @@ enum qse_httpd_server_xtn_cfg_idx_t
struct qse_httpd_server_xtn_t
{
qse_mxstr_t cfg[QSE_HTTPD_SERVER_XTN_CFG_MAX];
qse_mchar_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;
@ -699,12 +714,27 @@ qse_httpd_task_t* qse_httpd_entaskreloc (
qse_htre_t* req
);
qse_httpd_task_t* qse_httpd_entaskredir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* dst,
qse_htre_t* req
);
qse_httpd_task_t* qse_httpd_entasknomod (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
qse_htre_t* req
);
qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* name,
const qse_mchar_t* css,
qse_htre_t* req
);

View File

@ -270,7 +270,7 @@ int qse_fs_move (
arr[2] = qse_basename(oldpath);
arr[3] = QSE_NULL;
#if defined(QSE_CHAR_IS_MCHAR)
fop.new_path2 = qse_stradup (arr, fs->mmgr);
fop.new_path2 = qse_stradup (arr, QSE_NULL, fs->mmgr);
#else
fop.new_path2 = qse_wcsatombsdup (arr, fs->mmgr);
#endif

View File

@ -199,7 +199,7 @@ int qse_fs_chdir (qse_fs_t* fs, const qse_char_t* name)
tmp_name[idx] = QSE_NULL;
fsname = qse_stradup (tmp_name, fs->mmgr);
fsname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr);
if (fsname == QSE_NULL)
{
fs->errnum = QSE_FS_ENOMEM;
@ -260,7 +260,7 @@ int qse_fs_chdir (qse_fs_t* fs, const qse_char_t* name)
tmp_name[idx++] = name;
tmp_name[idx] = QSE_NULL;
fsname = qse_stradup (tmp_name, fs->mmgr);
fsname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr);
if (fsname == QSE_NULL)
{
fs->errnum = QSE_FS_ENOMEM;
@ -453,7 +453,7 @@ qse_fs_ent_t* qse_fs_read (qse_fs_t* fs, int flags)
tmp_name[1] = QSE_T("\\");
tmp_name[2] = info->wfd.cFileName;
tmp_name[3] = QSE_NULL;
fname = qse_stradup (tmp_name, fs->mmgr);
fname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr);
if (fname == QSE_NULL)
{
fs->errnum = QSE_FS_ENOMEM;
@ -564,7 +564,7 @@ qse_fs_ent_t* qse_fs_read (qse_fs_t* fs, int flags)
tmp_name[1] = QSE_MT("/");
tmp_name[2] = ent->d_name;
tmp_name[3] = QSE_NULL;
mfname = qse_mbsadup (tmp_name, fs->mmgr);
mfname = qse_mbsadup (tmp_name, QSE_NULL, fs->mmgr);
if (mfname == QSE_NULL)
{
fs->errnum = QSE_FS_ENOMEM;

View File

@ -72,7 +72,7 @@ qse_mchar_t* qse_mbsxdup2 (
return tmp;
}
qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_mmgr_t* mmgr)
qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_size_t* len, qse_mmgr_t* mmgr)
{
qse_mchar_t* buf, * ptr;
qse_size_t i;
@ -88,10 +88,11 @@ qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_mmgr_t* mmgr)
ptr = buf;
for (i = 0; str[i]; i++) ptr += qse_mbscpy (ptr, str[i]);
if (len) *len = capa;
return buf;
}
qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_mmgr_t* mmgr)
qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_size_t* len, qse_mmgr_t* mmgr)
{
qse_mchar_t* buf, * ptr;
qse_size_t i;
@ -107,6 +108,7 @@ qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_mmgr_t* mmgr)
ptr = buf;
for (i = 0; str[i].ptr; i++) ptr += qse_mbsncpy (ptr, str[i].ptr, str[i].len);
if (len) *len = capa;
return buf;
}
@ -165,7 +167,7 @@ qse_wchar_t* qse_wcsxdup2 (
return tmp;
}
qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_mmgr_t* mmgr)
qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_size_t* len, qse_mmgr_t* mmgr)
{
qse_wchar_t* buf, * ptr;
qse_size_t i;
@ -181,10 +183,11 @@ qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_mmgr_t* mmgr)
ptr = buf;
for (i = 0; str[i]; i++) ptr += qse_wcscpy (ptr, str[i]);
if (len) *len = capa;
return buf;
}
qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_mmgr_t* mmgr)
qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_size_t* len, qse_mmgr_t* mmgr)
{
qse_wchar_t* buf, * ptr;
qse_size_t i;
@ -200,5 +203,6 @@ qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_mmgr_t* mmgr)
ptr = buf;
for (i = 0; str[i].ptr; i++) ptr += qse_wcsncpy (ptr, str[i].ptr, str[i].len);
if (len) *len = capa;
return buf;
}

View File

@ -34,6 +34,67 @@ int qse_comparehttpversions (
return v1->major - v2->major;
}
const qse_mchar_t* qse_httpstatustombs (int code)
{
const qse_mchar_t* msg;
switch (code)
{
case 100: msg = QSE_MT("Continue"); break;
case 101: msg = QSE_MT("Switching Protocols"); break;
case 200: msg = QSE_MT("OK"); break;
case 201: msg = QSE_MT("Created"); break;
case 202: msg = QSE_MT("Accepted"); break;
case 203: msg = QSE_MT("Non-Authoritative Information"); break;
case 204: msg = QSE_MT("No Content"); break;
case 205: msg = QSE_MT("Reset Content"); break;
case 206: msg = QSE_MT("Partial Content"); break;
case 300: msg = QSE_MT("Multiple Choices"); break;
case 301: msg = QSE_MT("Moved Permanently"); break;
case 302: msg = QSE_MT("Found"); break;
case 303: msg = QSE_MT("See Other"); break;
case 304: msg = QSE_MT("Not Modified"); break;
case 305: msg = QSE_MT("Use Proxy"); break;
case 307: msg = QSE_MT("Temporary Redirect"); break;
case 400: msg = QSE_MT("Bad Request"); break;
case 401: msg = QSE_MT("Unauthorized"); break;
case 402: msg = QSE_MT("Payment Required"); break;
case 403: msg = QSE_MT("Forbidden"); break;
case 404: msg = QSE_MT("Not Found"); break;
case 405: msg = QSE_MT("Method Not Allowed"); break;
case 406: msg = QSE_MT("Not Acceptable"); break;
case 407: msg = QSE_MT("Proxy Authentication Required"); break;
case 408: msg = QSE_MT("Request Timeout"); break;
case 409: msg = QSE_MT("Conflict"); break;
case 410: msg = QSE_MT("Gone"); break;
case 411: msg = QSE_MT("Length Required"); break;
case 412: msg = QSE_MT("Precondition Failed"); break;
case 413: msg = QSE_MT("Request Entity Too Large"); break;
case 414: msg = QSE_MT("Request-URI Too Long"); break;
case 415: msg = QSE_MT("Unsupported Media Type"); break;
case 416: msg = QSE_MT("Requested Range Not Satisfiable"); break;
case 417: msg = QSE_MT("Expectation Failed"); break;
case 426: msg = QSE_MT("Upgrade Required"); break;
case 428: msg = QSE_MT("Precondition Required"); break;
case 429: msg = QSE_MT("Too Many Requests"); break;
case 431: msg = QSE_MT("Request Header Fields Too Large"); break;
case 500: msg = QSE_MT("Internal Server Error"); break;
case 501: msg = QSE_MT("Not Implemented"); break;
case 502: msg = QSE_MT("Bad Gateway"); break;
case 503: msg = QSE_MT("Service Unavailable"); break;
case 504: msg = QSE_MT("Gateway Timeout"); break;
case 505: msg = QSE_MT("HTTP Version Not Supported"); break;
default: msg = QSE_MT("Unknown Error"); break;
}
return msg;
}
const qse_mchar_t* qse_httpmethodtombs (qse_http_method_t type)
{
/* keep this table in the same order as qse_httpd_method_t enumerators */
@ -410,3 +471,4 @@ qse_mchar_t* qse_perenchttpstrdup (const qse_mchar_t* str, qse_mmgr_t* mmgr)
return buf;
}

View File

@ -22,7 +22,6 @@
#include "../cmn/mem.h"
#include <qse/cmn/str.h>
#include <qse/cmn/fmt.h>
#include <qse/cmn/path.h>
#include <qse/cmn/stdio.h> /* TODO: remove this */
@ -30,7 +29,6 @@ typedef struct task_dir_t task_dir_t;
struct task_dir_t
{
qse_mcstr_t path;
qse_mcstr_t css;
qse_mcstr_t qpath;
qse_http_version_t version;
int keepalive;
@ -44,7 +42,6 @@ struct task_dseg_t
int chunked;
qse_mcstr_t path;
qse_mcstr_t css;
qse_mcstr_t qpath;
qse_ubi_t handle;
qse_httpd_dirent_t dent;
@ -59,13 +56,10 @@ struct task_dseg_t
qse_size_t tcount; /* total directory entries */
qse_size_t dcount; /* the number of items in the buffer */
qse_mchar_t tmbuf[128];
qse_mchar_t fszbuf[128];
qse_mchar_t buf[4096];
qse_size_t bufpos;
qse_size_t buflen;
qse_size_t bufrem;
qse_mchar_t buf[4096*2];
int bufpos;
int buflen;
int bufrem;
qse_size_t chunklen;
};
@ -79,9 +73,7 @@ static int task_init_dseg (
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
xtn->css.ptr = xtn->path.ptr + xtn->path.len + 1;
qse_mbscpy ((qse_mchar_t*)xtn->css.ptr, arg->css.ptr);
xtn->qpath.ptr = xtn->css.ptr + xtn->css.len + 1;
xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1;
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
task->ctx = xtn;
@ -135,35 +127,36 @@ static void fill_chunk_length (task_dseg_t* ctx)
while (ctx->buf[ctx->bufpos] == QSE_MT(' ')) ctx->bufpos++;
}
static int add_footer (task_dseg_t* ctx)
static int add_footer (qse_httpd_t* httpd, qse_httpd_client_t* client, task_dseg_t* ctx)
{
int x;
int x, rem;
if (ctx->chunked)
rem = ctx->chunked? (ctx->buflen - 5): ctx->buflen;
if (rem < 1)
{
x = snprintf (
&ctx->buf[ctx->buflen], ctx->bufrem,
QSE_MT("</table></body></html>\r\n0\r\n"));
}
else
{
x = snprintf (
&ctx->buf[ctx->buflen], ctx->bufrem,
QSE_MT("</table></body></html>"));
}
if (x == -1 || x >= ctx->bufrem)
{
/* return an error if the buffer is too small to hold the
* trailing footer. you need to increate the buffer size */
httpd->errnum = QSE_HTTPD_ENOBUF;
return -1;
}
x = httpd->rcb->format_dir (
httpd, client, QSE_NULL, QSE_NULL,
&ctx->buf[ctx->buflen], rem);
if (x <= -1) return -1;
QSE_ASSERT (x < rem);
ctx->buflen += x;
ctx->bufrem -= x;
/* -5 for \r\n0\r\n added above */
if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5);
if (ctx->chunked)
{
qse_mbscpy (&ctx->buf[ctx->buflen], QSE_MT("\r\n0\r\n"));
ctx->buflen += 5;
ctx->bufrem -= 5;
/* -5 for \r\n0\r\n added above */
if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5);
}
return 0;
}
@ -226,11 +219,10 @@ static int task_main_dseg (
if (ctx->state & FOOTER_PENDING)
{
/* only footers yet to be sent */
if (add_footer (ctx) <= -1)
if (add_footer (httpd, client, ctx) <= -1)
{
/* return an error if the buffer is too small to hold the
* trailing footer. you need to increate the buffer size */
httpd->errnum = QSE_HTTPD_EINTERN;
return -1;
}
@ -243,31 +235,21 @@ static int task_main_dseg (
if (!(ctx->state & HEADER_ADDED))
{
int is_root;
is_root = (qse_mbscmp (ctx->qpath.ptr, QSE_MT("/")) == 0);
/* compose the header since this is the first time. */
/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */
/* TODO: html escaping of ctx->qpath.ptr */
x = snprintf (
&ctx->buf[ctx->buflen], ctx->bufrem,
QSE_MT("<html><head>%s%s%s</head><body><b>%s</b><table>%s"),
(ctx->css.len > 0? QSE_MT("<style type='text/css'>"): QSE_MT("")),
(ctx->css.len > 0? ctx->css.ptr: QSE_MT("")),
(ctx->css.len > 0? QSE_MT("</style>"): QSE_MT("")),
ctx->qpath.ptr,
(is_root? QSE_MT(""): QSE_MT("<tr><td><a href='../'>..</a></td><td></td><td></td></tr>"))
);
if (x == -1 || x >= ctx->bufrem)
x = httpd->rcb->format_dir (
httpd, client, ctx->qpath.ptr, QSE_NULL,
&ctx->buf[ctx->buflen], ctx->bufrem);
if (x <= -1)
{
/* return an error if the buffer is too small to hold the header.
* you need to increate the buffer size. or i have make the buffer
* dynamic. */
httpd->errnum = QSE_HTTPD_EINTERN;
/* return an error if the buffer is too small to
* hold the header(httpd->errnum == QSE_HTTPD_ENOBUF).
* i need to increate the buffer size. or i have make
* the buffer dynamic. */
return -1;
}
QSE_ASSERT (x < ctx->bufrem);
ctx->buflen += x;
ctx->bufrem -= x;
@ -291,7 +273,7 @@ static int task_main_dseg (
{
/* no more directory entry */
if (add_footer (ctx) <= -1)
if (add_footer (httpd, client, ctx) <= -1)
{
/* failed to add the footer part */
if (ctx->chunked)
@ -309,52 +291,10 @@ static int task_main_dseg (
if (qse_mbscmp (ctx->dent.name, QSE_MT(".")) != 0 &&
qse_mbscmp (ctx->dent.name, QSE_MT("..")) != 0)
{
qse_mchar_t* encname;
qse_btime_t bt;
/* TODO: better buffer management in case there are
* a lot of file names to escape. */
encname = qse_perenchttpstrdup (ctx->dent.name, httpd->mmgr);
if (encname == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
qse_printf (QSE_T("ADDING [%hs]\n"), ctx->dent.name);
qse_localtime (ctx->dent.stat.mtime, &bt);
snprintf (ctx->tmbuf, QSE_COUNTOF(ctx->tmbuf),
QSE_MT("%04d-%02d-%02d %02d:%02d:%02d"),
bt.year + QSE_BTIME_YEAR_BASE, bt.mon + 1, bt.mday,
bt.hour, bt.min, bt.sec);
if (ctx->dent.stat.isdir)
{
ctx->fszbuf[0] = QSE_MT('\0');
}
else
{
qse_fmtuintmaxtombs (
ctx->fszbuf, QSE_COUNTOF(ctx->fszbuf),
ctx->dent.stat.size, 10, -1, QSE_MT('\0'), QSE_NULL
);
}
x = snprintf (
&ctx->buf[ctx->buflen],
ctx->bufrem,
QSE_MT("<tr><td><a href='%s%s'>%s%s</a></td><td>%s</td><td align='right'>%s</td></tr>"),
encname,
(ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")),
ctx->dent.name, /* TODO: html escaping */
(ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")),
ctx->tmbuf, ctx->fszbuf
);
if (encname != ctx->dent.name) QSE_MMGR_FREE (httpd->mmgr, encname);
if (x == -1 || x >= ctx->bufrem)
x = httpd->rcb->format_dir (
httpd, client, ctx->qpath.ptr, &ctx->dent,
&ctx->buf[ctx->buflen], ctx->bufrem);
if (x <= -1)
{
/* buffer not large enough to hold this entry */
if (ctx->dcount <= 0)
@ -378,6 +318,8 @@ qse_printf (QSE_T("ADDING [%hs]\n"), ctx->dent.name);
}
else
{
QSE_ASSERT (x < ctx->bufrem);
ctx->buflen += x;
ctx->bufrem -= x;
ctx->dcount++;
@ -416,7 +358,6 @@ static qse_httpd_task_t* entask_directory_segment (
data.keepalive = dir->keepalive;
data.chunked = dir->keepalive;
data.path = dir->path;
data.css = dir->css;
data.qpath = dir->qpath;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
@ -425,7 +366,7 @@ static qse_httpd_task_t* entask_directory_segment (
task.fini = task_fini_dseg;
task.ctx = &data;
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1);
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.qpath.len + 1);
}
/*------------------------------------------------------------------------*/
@ -441,9 +382,7 @@ static int task_init_dir (
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
xtn->css.ptr = xtn->path.ptr + xtn->path.len + 1;
qse_mbscpy ((qse_mchar_t*)xtn->css.ptr, arg->css.ptr);
xtn->qpath.ptr = xtn->css.ptr + xtn->css.len + 1;
xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1;
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
/* switch the context to the extension area */
@ -495,15 +434,10 @@ static QSE_INLINE int task_main_dir (
}
else
{
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\nServer: %s\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\nLocation: %s/\r\n\r\n"),
dir->version.major, dir->version.minor,
qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
dir->qpath.ptr
);
x = qse_httpd_entask_redir (
httpd, client, x, dir->qpath.ptr,
&dir->version, dir->keepalive);
return (x == QSE_NULL)? -1: 0;
}
}
@ -513,19 +447,14 @@ qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* path,
const qse_mchar_t* css,
qse_htre_t* req)
{
qse_httpd_task_t task;
task_dir_t data;
if (css == QSE_NULL) css = QSE_MT("");
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
data.path.ptr = path;
data.path.len = qse_mbslen(data.path.ptr);
data.css.ptr = css;
data.css.len = qse_mbslen(data.css.ptr);
data.qpath.ptr = qse_htre_getqpath(req);
data.qpath.len = qse_mbslen(data.qpath.ptr);
data.version = *qse_htre_getversion(req);
@ -537,6 +466,6 @@ qse_httpd_task_t* qse_httpd_entaskdir (
task.ctx = &data;
return qse_httpd_entask (httpd, client, pred, &task,
QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1);
QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.qpath.len + 1);
}

View File

@ -22,8 +22,6 @@
#include "../cmn/mem.h"
#include <qse/cmn/str.h>
#include <qse/cmn/fmt.h>
#include <qse/cmn/path.h>
#include <qse/cmn/time.h>
#if defined(_WIN32)
/* TODO: */
@ -274,15 +272,7 @@ static QSE_INLINE int task_main_file (
/* i've converted milliseconds to seconds before timestamp comparison
* because st.mtime has the actual milliseconds less than 1 second
* while if_modified_since doesn't have such small milliseconds */
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 304 Not Modified\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Length: 0\r\n\r\n"),
file->version.major, file->version.minor,
qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close"))
);
x = qse_httpd_entask_nomod (httpd, client, x, &file->version, file->keepalive);
goto no_file_send;
}

View File

@ -26,6 +26,7 @@
#include <qse/cmn/str.h>
#include <qse/cmn/uri.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/fmt.h>
#include <qse/cmn/path.h>
#if defined(_WIN32)
@ -1584,6 +1585,125 @@ static int handle_request (
return process_request (httpd, client, req, 0);
}
static int format_error (
qse_httpd_t* httpd, qse_httpd_client_t* client, int code, qse_mchar_t* buf, int bufsz)
{
int n;
server_xtn_t* server_xtn;
const qse_mchar_t* css, * msg;
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
css = server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_ERRORCSS];
if (!css) css = QSE_MT("");
msg = qse_httpstatustombs(code);
/* TODO: use my own version of snprintf replacement */
n = snprintf (buf, bufsz,
QSE_MT("<html><head>%s<title>%s</title></head><body><div class='header'>HTTP ERROR</div><div class='body'>%d %s</div><div class='footer'>%s</div></body></html>"),
css, msg, code, msg, qse_httpd_getname(httpd));
if (n < 0 || n >= bufsz)
{
httpd->errnum = QSE_HTTPD_ENOBUF;
return -1;
}
return n;
}
static int format_dir (
qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_mchar_t* qpath, const qse_httpd_dirent_t* dirent,
qse_mchar_t* buf, int bufsz)
{
/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */
/* TODO: html escaping of ctx->qpath.ptr */
int n;
server_xtn_t* server_xtn;
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
if (dirent == QSE_NULL)
{
if (qpath)
{
/* header */
const qse_mchar_t* css;
int is_root = (qse_mbscmp (qpath, QSE_MT("/")) == 0);
css = server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS];
if (!css) css = QSE_MT("");
/* TODO: html escaping of qpath */
n = snprintf (buf, bufsz,
QSE_MT("<html><head>%s</head><body><div class='header'>%s</div><div class='body'><table>%s"), css, qpath,
(is_root? QSE_MT(""): QSE_MT("<tr><td class='name'><a href='../'>..</a></td><td class='time'></td><td class='size'></td></tr>"))
);
}
else
{
/* footer */
n = snprintf (buf, bufsz, QSE_MT("</table></div><div class='footer'>%s</div></body></html>"), qse_httpd_getname(httpd));
}
}
else
{
/* main entry */
qse_mchar_t* encname;
qse_btime_t bt;
qse_mchar_t tmbuf[32];
qse_mchar_t fszbuf[64];
/* TODO: better buffer management in case there are
* a lot of file names to escape. */
encname = qse_perenchttpstrdup (dirent->name, httpd->mmgr);
if (encname == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
qse_localtime (dirent->stat.mtime, &bt);
snprintf (tmbuf, QSE_COUNTOF(tmbuf),
QSE_MT("%04d-%02d-%02d %02d:%02d:%02d"),
bt.year + QSE_BTIME_YEAR_BASE, bt.mon + 1, bt.mday,
bt.hour, bt.min, bt.sec);
if (dirent->stat.isdir)
{
fszbuf[0] = QSE_MT('\0');
}
else
{
qse_fmtuintmaxtombs (
fszbuf, QSE_COUNTOF(fszbuf),
dirent->stat.size, 10, -1, QSE_MT('\0'), QSE_NULL
);
}
n = snprintf (
buf, bufsz,
QSE_MT("<tr><td class='name'><a href='%s%s'>%s%s</a></td><td class='time'>%s</td><td class='size'>%s</td></tr>"),
encname,
(dirent->stat.isdir? QSE_MT("/"): QSE_MT("")),
dirent->name, /* TODO: html escaping for entry name */
(dirent->stat.isdir? QSE_MT("/"): QSE_MT("")),
tmbuf, fszbuf
);
if (encname != dirent->name) QSE_MMGR_FREE (httpd->mmgr, encname);
}
if (n <= -1 || n >= bufsz)
{
httpd->errnum = QSE_HTTPD_ENOBUF;
return -1;
}
return n;
}
static qse_httpd_scb_t httpd_system_callbacks =
{
/* server */
@ -1638,7 +1758,9 @@ static qse_httpd_scb_t httpd_system_callbacks =
static qse_httpd_rcb_t httpd_request_callbacks =
{
peek_request,
handle_request
handle_request,
format_error,
format_dir
};
/* ------------------------------------------------------------------- */
@ -1688,7 +1810,7 @@ static qse_mchar_t* merge_paths (
ta[idx++] = QSE_MT("/");
ta[idx++] = path;
ta[idx++] = QSE_NULL;
xpath = qse_mbsadup (ta, httpd->mmgr);
xpath = qse_mbsadup (ta, QSE_NULL, httpd->mmgr);
if (xpath == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
@ -1796,8 +1918,8 @@ static int make_resource (
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
if (server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr &&
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr)
if (server_xtn->cfg[SERVER_XTN_CFG_REALM] &&
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH])
{
const qse_htre_hdrval_t* auth;
@ -1808,18 +1930,18 @@ static int make_resource (
if (qse_mbszcasecmp(auth->ptr, QSE_MT("Basic "), 6) == 0)
{
if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr) == 0) goto auth_ok;
if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH]) == 0) goto auth_ok;
}
}
target->type = QSE_HTTPD_RSRC_AUTH;
target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr;
target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM];
return 0;
}
auth_ok:
idxfile = QSE_NULL;
xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr, qpath);
xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], qpath);
if (xpath == QSE_NULL) return -1;
if (QSE_STAT (xpath, &st) == 0 && S_ISDIR(st.st_mode))
@ -1854,7 +1976,6 @@ auth_ok:
target->type = QSE_HTTPD_RSRC_DIR;
target->u.dir.path = xpath;
target->u.dir.css = server_xtn->cfg[SERVER_XTN_CFG_DIRCSS].ptr;
}
else
{
@ -1862,7 +1983,7 @@ auth_ok:
if (server_xtn->cgistd)
{
/* check if the request can resolve to a cgi script */
n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr,
n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT],
xpath, qpath, idxfile, server_xtn->cgistd, target);
if (n <= -1)
{
@ -1908,12 +2029,10 @@ static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
for (i = QSE_COUNTOF(server_xtn->cfg); i > 0; )
{
i--;
if (server_xtn->cfg[i].ptr)
if (server_xtn->cfg[--i])
{
QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i].ptr);
server_xtn->cfg[i].ptr = QSE_NULL;
server_xtn->cfg[i].len = 0;
QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i]);
server_xtn->cfg[i] = QSE_NULL;
}
}
}
@ -1925,11 +2044,11 @@ qse_httpd_server_t* qse_httpd_attachserverstd (
qse_httpd_server_t server;
qse_httpd_server_t* xserver;
server_xtn_t* server_xtn;
qse_mcstr_t tmp[4];
const qse_mchar_t* tmp[4];
qse_mxstr_t ba;
qse_size_t balen2;
qse_uint16_t default_port;
qse_size_t i;
qse_uri_t xuri;
static qse_httpd_server_cgistd_t server_cgistd[] =
@ -2007,49 +2126,36 @@ qse_httpd_server_t* qse_httpd_attachserverstd (
}
#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);
server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.path.ptr) server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME] = qse_mbsxdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD] = qse_mbsxdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = 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);
server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, httpd->mmgr);
if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME] = qse_wcsntombsdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr);
if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD] = qse_wcsntombsdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr);
if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = 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;
if ((!server_xtn->cfg[SERVER_XTN_CFG_DOCROOT]) ||
(xuri.auth.user.ptr && !server_xtn->cfg[SERVER_XTN_CFG_USERNAME]) ||
(xuri.auth.pass.ptr && !server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]) ||
(xuri.frag.ptr && !server_xtn->cfg[SERVER_XTN_CFG_REALM])) 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] = server_xtn->cfg[SERVER_XTN_CFG_USERNAME]? server_xtn->cfg[SERVER_XTN_CFG_USERNAME]: QSE_MT("");
tmp[1] = QSE_MT(":");
tmp[2] = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]? server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]: QSE_MT("");
tmp[3] = QSE_NULL;
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);
ba.ptr = qse_mbsadup (tmp, &ba.len, 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)
balen2 = ((ba.len / 3) + 1) * 4;
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH] = QSE_MMGR_ALLOC (
httpd->mmgr, (balen2 + 1) * QSE_SIZEOF(qse_mchar_t));
if (!server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH])
{
QSE_MMGR_FREE (httpd->mmgr, ba.ptr);
goto nomem_after_attach;
@ -2057,12 +2163,12 @@ qse_httpd_server_t* qse_httpd_attachserverstd (
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
server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH],
balen2,
&balen2
);
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->cfg[SERVER_XTN_CFG_BASICAUTH])[balen2] = QSE_MT('\0');
server_xtn->predetach = predetach;
server_xtn->cbstd = &server_cbstd;

View File

@ -205,96 +205,76 @@ qse_printf (QSE_T("SEND: [%.*hs]\n"), (int)l, buf);
/*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entask_error (
typedef struct status_reloc_t status_reloc_t;
struct status_reloc_t
{
const qse_mchar_t* dst;
int redir;
};
static qse_httpd_task_t* entask_status (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, int code,
qse_httpd_task_t* pred, int code, void* extra,
const qse_http_version_t* version, int keepalive)
{
const qse_mchar_t* smsg;
const qse_mchar_t* lmsg;
const qse_mchar_t* msg;
switch (code)
const qse_mchar_t* extrapre = QSE_MT("");
const qse_mchar_t* extrapst = QSE_MT("");
const qse_mchar_t* extraval = QSE_MT("");
qse_mchar_t text[1024] = QSE_MT(""); /* TODO: make this buffer dynamic or scalable */
msg = qse_httpstatustombs (code);
if (code == 301 || code == 307)
{
case 403:
smsg = QSE_MT("Forbidden");
lmsg = QSE_MT("<html><head><title>Forbidden</title></head><body><b>FORBIDDEN<b></body></html>");
break;
case 404:
smsg = QSE_MT("Not Found");
lmsg = QSE_MT("<html><head><title>Not Found</title></head><body><b>REQUESTED PATH NOT FOUND<b></body></html>");
break;
case 405:
smsg = QSE_MT("Method Not Allowed");
lmsg = QSE_MT("<html><head><title>Method Not Allowed</title></head><body><b>REQUESTED METHOD NOT ALLOWED<b></body></html>");
break;
case 411:
smsg = QSE_MT("Length Required");
lmsg = QSE_MT("<html><head><title>Length Required</title></head><body><b>LENGTH REQUIRED<b></body></html>");
break;
case 416:
smsg = QSE_MT("Requested Range Not Satisfiable");
lmsg = QSE_MT("<html><head><title>Requested Range Not Satsfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE<b></body></html>");
break;
case 417:
smsg = QSE_MT("Expectation Failed");
lmsg = QSE_MT("<html><head><title>Expectation Failed</title></head><body><b>EXPECTATION FAILED<b></body></html>");
break;
case 500:
smsg = QSE_MT("Internal Server Error");
lmsg = QSE_MT("<html><head><title>Internal Server Error</title></head><body><b>INTERNAL SERVER ERROR<b></body></html>");
break;
case 501:
smsg = QSE_MT("Not Implemented");
lmsg = QSE_MT("<html><head><title>Not Implemented</title></head><body><b>NOT IMPLEMENTED<b></body></html>");
break;
case 502:
smsg = QSE_MT("Bad Gateway");
lmsg = QSE_MT("<html><head><title>Bad Gateway</title></head><body><b>BAD GATEWAY<b></body></html>");
break;
case 503:
smsg = QSE_MT("Service Unavailable");
lmsg = QSE_MT("<html><head><title>Service Unavailable</title></head><body><b>SERVICE UNAVAILABLE<b></body></html>");
break;
case 504:
smsg = QSE_MT("Gateway Timeout");
lmsg = QSE_MT("<html><head><title>Gateway Timeout</title></head><body><b>GATEWAY TIMEOUT<b></body></html>");
break;
default:
smsg = QSE_MT("Unknown");
lmsg = QSE_MT("<html><head><title>Unknown Error</title></head><body><b>UNKNOWN ERROR<b></body></html>");
break;
status_reloc_t* reloc = (status_reloc_t*)extra;
extrapre = QSE_MT("Location: ");
extrapst = reloc->redir? QSE_MT("/\r\n"): QSE_MT("\r\n");
extraval = reloc->dst;
}
else if (code == 304)
{
/* nothing to do */
}
else
{
if (httpd->rcb->format_error (httpd, client, code, text, QSE_COUNTOF(text)) <= -1) return -1;
if (code == 401)
{
extrapre = QSE_MT("WWW-Authenticate: Basic realm=\"");
extrapst = QSE_MT("\"\r\n");
extraval = (const qse_mchar_t*)extra;
}
}
return qse_httpd_entaskformat (
httpd, client, pred,
QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"),
version->major, version->minor, code, smsg,
qse_httpd_getname (httpd),
QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n%s%s%s\r\n%s"),
version->major, version->minor,
code, msg, qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
(unsigned long)qse_mbslen(lmsg) + 4, lmsg
);
(unsigned long)qse_mbslen(text),
extrapre, extraval, extrapst, text);
}
/*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entask_error (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, int code,
const qse_http_version_t* version, int keepalive)
{
return entask_status (httpd, client, pred, code, QSE_NULL, version, keepalive);
}
qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, int code, qse_htre_t* req)
{
return qse_httpd_entask_error (
httpd, client, pred, code,
qse_htre_getversion(req),
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
return entask_status (
httpd, client, pred, code, QSE_NULL,
qse_htre_getversion(req), (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
}
/*------------------------------------------------------------------------*/
@ -315,40 +295,94 @@ qse_httpd_task_t* qse_httpd_entaskauth (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_mchar_t* realm, qse_htre_t* req)
{
const qse_http_version_t* version;
const qse_mchar_t* lmsg;
version = qse_htre_getversion(req);
lmsg = QSE_MT("<html><head><title>Unauthorized</title></head><body><b>UNAUTHORIZED<b></body></html>");
return qse_httpd_entaskformat (
httpd, client, pred,
QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nWWW-Authenticate: Basic realm=\"%s\"\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"),
version->major, version->minor,
qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
((req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")),
realm, (unsigned long)qse_mbslen(lmsg) + 4, lmsg);
return entask_status (
httpd, client, pred, 401, (void*)realm,
qse_htre_getversion(req),
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
}
/*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entask_reloc (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_mchar_t* dst,
const qse_http_version_t* version, int keepalive)
{
status_reloc_t reloc;
reloc.dst = dst;
reloc.redir = 0;
return entask_status (
httpd, client, pred, 301, (void*)&reloc,
version, keepalive);
}
qse_httpd_task_t* qse_httpd_entaskreloc (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_mchar_t* dst, qse_htre_t* req)
{
const qse_http_version_t* version;
status_reloc_t reloc;
version = qse_htre_getversion(req);
reloc.dst = dst;
reloc.redir = 0;
return qse_httpd_entaskformat (
httpd, client, pred,
QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\nServer: %s\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\nLocation: %s\r\n\r\n"),
version->major, version->minor,
qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
((req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")),
dst);
return entask_status (
httpd, client, pred, 301, (void*)&reloc,
qse_htre_getversion(req),
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
}
qse_httpd_task_t* qse_httpd_entask_redir (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_mchar_t* dst,
const qse_http_version_t* version, int keepalive)
{
status_reloc_t reloc;
reloc.dst = dst;
reloc.redir = 1;
return entask_status (
httpd, client, pred, 301, (void*)&reloc,
version, keepalive);
}
qse_httpd_task_t* qse_httpd_entaskredir (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_mchar_t* dst, qse_htre_t* req)
{
status_reloc_t reloc;
reloc.dst = dst;
reloc.redir = 1;
return entask_status (
httpd, client, pred, 301, (void*)&reloc,
qse_htre_getversion(req),
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
}
/*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entask_nomod (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, const qse_http_version_t* version, int keepalive)
{
return entask_status (
httpd, client, pred, 304,
QSE_NULL, version, keepalive);
}
qse_httpd_task_t* qse_httpd_entasknomod (
qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_httpd_task_t* pred, qse_htre_t* req)
{
return entask_status (
httpd, client, pred, 304,
QSE_NULL, qse_htre_getversion(req),
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
}
/*------------------------------------------------------------------------*/
@ -390,7 +424,7 @@ qse_httpd_task_t* qse_httpd_entaskrsrc (
case QSE_HTTPD_RSRC_DIR:
qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, rsrc->u.dir.css, req);
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, req);
break;
case QSE_HTTPD_RSRC_ERROR:
@ -411,6 +445,10 @@ qse_httpd_task_t* qse_httpd_entaskrsrc (
task = qse_httpd_entaskreloc (httpd, client, QSE_NULL, rsrc->u.reloc.dst, req);
break;
case QSE_HTTPD_RSRC_REDIR:
task = qse_httpd_entaskredir (httpd, client, QSE_NULL, 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);
break;

View File

@ -110,6 +110,33 @@ qse_httpd_task_t* qse_httpd_entask_error (
int keepalive
);
qse_httpd_task_t* qse_httpd_entask_nomod (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_http_version_t* version,
int keepalive
);
qse_httpd_task_t* qse_httpd_entask_reloc (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* dst,
const qse_http_version_t* version,
int keepalive
);
qse_httpd_task_t* qse_httpd_entask_redir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
qse_httpd_task_t* pred,
const qse_mchar_t* dst,
const qse_http_version_t* version,
int keepalive
);
qse_httpd_task_t* qse_httpd_entask_text (
qse_httpd_t* httpd,
qse_httpd_client_t* client,

View File

@ -5,7 +5,6 @@
#include <qse/cmn/str.h>
#include <qse/cmn/mem.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/time.h>
#include <signal.h>
#include <locale.h>
@ -71,8 +70,12 @@ static int httpd_main (int argc, qse_char_t* argv[])
}
server_xtn = qse_httpd_getserverxtn (httpd, server);
server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].ptr = QSE_MT("body { background-color:#d0e4fe; font-size: 0.9em; font-family: Ubuntu,'Trebuchet MS',sans-serif; }");
server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].len = qse_mbslen(server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].ptr);
/* don't care about failure */
server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS] =
qse_mbsdup (QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; } table { font-size: 0.9em; } td { white-space: nowrap; } td.size { text-align: right; }</style>"), qse_httpd_getmmgr(httpd));
server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_ERRORCSS] =
qse_mbsdup (QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; }</style>"), qse_httpd_getmmgr(httpd));
}
g_httpd = httpd;