added directory handler to qse_httpd_scb_t
This commit is contained in:
parent
d9b42ca785
commit
7940a758d0
@ -65,6 +65,7 @@ enum qse_httpd_option_t
|
|||||||
typedef struct qse_httpd_stat_t qse_httpd_stat_t;
|
typedef struct qse_httpd_stat_t qse_httpd_stat_t;
|
||||||
struct qse_httpd_stat_t
|
struct qse_httpd_stat_t
|
||||||
{
|
{
|
||||||
|
int isdir;
|
||||||
qse_long_t dev;
|
qse_long_t dev;
|
||||||
qse_long_t ino;
|
qse_long_t ino;
|
||||||
qse_foff_t size;
|
qse_foff_t size;
|
||||||
@ -123,6 +124,14 @@ typedef int (*qse_httpd_muxcb_t) (
|
|||||||
void* cbarg
|
void* cbarg
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
|
||||||
|
|
||||||
|
struct qse_httpd_dirent_t
|
||||||
|
{
|
||||||
|
qse_mchar_t* name;
|
||||||
|
qse_httpd_stat_t stat;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct qse_httpd_scb_t qse_httpd_scb_t;
|
typedef struct qse_httpd_scb_t qse_httpd_scb_t;
|
||||||
struct qse_httpd_scb_t
|
struct qse_httpd_scb_t
|
||||||
{
|
{
|
||||||
@ -191,6 +200,17 @@ struct qse_httpd_scb_t
|
|||||||
const qse_mchar_t* buf, qse_size_t len);
|
const qse_mchar_t* buf, qse_size_t len);
|
||||||
} file;
|
} file;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int (*open) (
|
||||||
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
|
qse_ubi_t* handle);
|
||||||
|
void (*close) (qse_httpd_t* httpd, qse_ubi_t handle);
|
||||||
|
int (*read) (
|
||||||
|
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||||
|
qse_httpd_dirent_t* ent);
|
||||||
|
} dir;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
void (*close) (
|
void (*close) (
|
||||||
@ -225,6 +245,7 @@ struct qse_httpd_scb_t
|
|||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client); /* optional */
|
qse_httpd_client_t* client); /* optional */
|
||||||
} client;
|
} client;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct qse_httpd_rcb_t qse_httpd_rcb_t;
|
typedef struct qse_httpd_rcb_t qse_httpd_rcb_t;
|
||||||
@ -363,6 +384,7 @@ struct qse_httpd_rsrc_t
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const qse_mchar_t* path;
|
const qse_mchar_t* path;
|
||||||
|
const qse_mchar_t* css;
|
||||||
} dir;
|
} dir;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -459,6 +481,8 @@ enum qse_httpd_server_xtn_cfg_idx_t
|
|||||||
QSE_HTTPD_SERVER_XTN_CFG_USERNAME,
|
QSE_HTTPD_SERVER_XTN_CFG_USERNAME,
|
||||||
QSE_HTTPD_SERVER_XTN_CFG_PASSWORD,
|
QSE_HTTPD_SERVER_XTN_CFG_PASSWORD,
|
||||||
QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH,
|
QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH,
|
||||||
|
QSE_HTTPD_SERVER_XTN_CFG_DIRCSS, /* can't be too long due to internal buffer size */
|
||||||
|
QSE_HTTPD_SERVER_XTN_CFG_ERRORCSS,
|
||||||
QSE_HTTPD_SERVER_XTN_CFG_MAX
|
QSE_HTTPD_SERVER_XTN_CFG_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -680,6 +704,7 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
|||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred,
|
qse_httpd_task_t* pred,
|
||||||
const qse_mchar_t* name,
|
const qse_mchar_t* name,
|
||||||
|
const qse_mchar_t* css,
|
||||||
qse_htre_t* req
|
qse_htre_t* req
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -24,22 +24,13 @@
|
|||||||
#include <qse/cmn/fmt.h>
|
#include <qse/cmn/fmt.h>
|
||||||
#include <qse/cmn/path.h>
|
#include <qse/cmn/path.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
/* TODO: */
|
|
||||||
#elif defined(__OS2__)
|
|
||||||
/* TODO: */
|
|
||||||
#elif defined(__DOS__)
|
|
||||||
/* TODO: */
|
|
||||||
#else
|
|
||||||
# include "../cmn/syscall.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||||
|
|
||||||
typedef struct task_dir_t task_dir_t;
|
typedef struct task_dir_t task_dir_t;
|
||||||
struct task_dir_t
|
struct task_dir_t
|
||||||
{
|
{
|
||||||
qse_mcstr_t path;
|
qse_mcstr_t path;
|
||||||
|
qse_mcstr_t css;
|
||||||
qse_mcstr_t qpath;
|
qse_mcstr_t qpath;
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
@ -53,19 +44,24 @@ struct task_dseg_t
|
|||||||
int chunked;
|
int chunked;
|
||||||
|
|
||||||
qse_mcstr_t path;
|
qse_mcstr_t path;
|
||||||
|
qse_mcstr_t css;
|
||||||
qse_mcstr_t qpath;
|
qse_mcstr_t qpath;
|
||||||
qse_dir_t* handle;
|
qse_ubi_t handle;
|
||||||
qse_dirent_t* dent;
|
qse_httpd_dirent_t dent;
|
||||||
|
|
||||||
#define HEADER_ADDED (1 << 0)
|
#define HEADER_ADDED (1 << 0)
|
||||||
#define FOOTER_ADDED (1 << 1)
|
#define FOOTER_ADDED (1 << 1)
|
||||||
#define FOOTER_PENDING (1 << 2)
|
#define FOOTER_PENDING (1 << 2)
|
||||||
#define DIRENT_PENDING (1 << 3)
|
#define DIRENT_PENDING (1 << 3)
|
||||||
|
#define DIRENT_NOMORE (1 << 4)
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
qse_size_t tcount; /* total directory entries */
|
qse_size_t tcount; /* total directory entries */
|
||||||
qse_size_t dcount; /* the number of items in the buffer */
|
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_mchar_t buf[4096];
|
||||||
qse_size_t bufpos;
|
qse_size_t bufpos;
|
||||||
qse_size_t buflen;
|
qse_size_t buflen;
|
||||||
@ -83,7 +79,9 @@ static int task_init_dseg (
|
|||||||
|
|
||||||
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
|
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
|
||||||
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
|
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
|
||||||
xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1;
|
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;
|
||||||
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
|
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
|
||||||
|
|
||||||
task->ctx = xtn;
|
task->ctx = xtn;
|
||||||
@ -95,7 +93,7 @@ static void task_fini_dseg (
|
|||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
{
|
{
|
||||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||||
QSE_CLOSEDIR (ctx->handle);
|
httpd->scb->dir.close (httpd, ctx->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIZE_CHLEN 4 /* the space size to hold the hexadecimal chunk length */
|
#define SIZE_CHLEN 4 /* the space size to hold the hexadecimal chunk length */
|
||||||
@ -145,13 +143,13 @@ static int add_footer (task_dseg_t* ctx)
|
|||||||
{
|
{
|
||||||
x = snprintf (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||||
QSE_MT("</ul>Total %lu entries</body></html>\r\n0\r\n"), (unsigned long)ctx->tcount);
|
QSE_MT("</table></body></html>\r\n0\r\n"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x = snprintf (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||||
QSE_MT("</ul>Total %lu entries</body></html>"), (unsigned long)ctx->tcount);
|
QSE_MT("</table></body></html>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x == -1 || x >= ctx->bufrem)
|
if (x == -1 || x >= ctx->bufrem)
|
||||||
@ -254,8 +252,12 @@ static int task_main_dseg (
|
|||||||
/* TODO: html escaping of ctx->qpath.ptr */
|
/* TODO: html escaping of ctx->qpath.ptr */
|
||||||
x = snprintf (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||||
QSE_MT("<html><head></head><body><b>%s</b><ul>%s"),
|
QSE_MT("<html><head>%s%s%s</head><body><b>%s</b><table>%s"),
|
||||||
ctx->qpath.ptr, (is_root? QSE_MT(""): QSE_MT("<li><a href='../'>..</a></li>"))
|
(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)
|
if (x == -1 || x >= ctx->bufrem)
|
||||||
{
|
{
|
||||||
@ -273,18 +275,22 @@ static int task_main_dseg (
|
|||||||
ctx->dcount++;
|
ctx->dcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (!ctx->dent) ctx->dent = QSE_READDIR (ctx->handle); */
|
|
||||||
if (ctx->state & DIRENT_PENDING)
|
if (ctx->state & DIRENT_PENDING)
|
||||||
|
{
|
||||||
ctx->state &= ~DIRENT_PENDING;
|
ctx->state &= ~DIRENT_PENDING;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ctx->dent = QSE_READDIR (ctx->handle);
|
{
|
||||||
|
if (httpd->scb->dir.read (httpd, ctx->handle, &ctx->dent) <= 0)
|
||||||
|
ctx->state |= DIRENT_NOMORE;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!ctx->dent)
|
if (ctx->state & DIRENT_NOMORE)
|
||||||
{
|
{
|
||||||
/* TODO: check if errno has changed from before QSE_READDIR().
|
/* no more directory entry */
|
||||||
and return -1 if so. */
|
|
||||||
if (add_footer (ctx) <= -1)
|
if (add_footer (ctx) <= -1)
|
||||||
{
|
{
|
||||||
/* failed to add the footer part */
|
/* failed to add the footer part */
|
||||||
@ -298,31 +304,55 @@ static int task_main_dseg (
|
|||||||
else if (ctx->chunked) fill_chunk_length (ctx);
|
else if (ctx->chunked) fill_chunk_length (ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (qse_mbscmp (ctx->dent->d_name, QSE_MT(".")) != 0 &&
|
|
||||||
qse_mbscmp (ctx->dent->d_name, QSE_MT("..")) != 0)
|
|
||||||
|
if (qse_mbscmp (ctx->dent.name, QSE_MT(".")) != 0 &&
|
||||||
|
qse_mbscmp (ctx->dent.name, QSE_MT("..")) != 0)
|
||||||
{
|
{
|
||||||
qse_mchar_t* encname;
|
qse_mchar_t* encname;
|
||||||
|
qse_btime_t bt;
|
||||||
|
|
||||||
/* TODO: better buffer management in case there are
|
/* TODO: better buffer management in case there are
|
||||||
* a lot of file names to escape. */
|
* a lot of file names to escape. */
|
||||||
encname = qse_perenchttpstrdup (ctx->dent->d_name, httpd->mmgr);
|
encname = qse_perenchttpstrdup (ctx->dent.name, httpd->mmgr);
|
||||||
if (encname == QSE_NULL)
|
if (encname == QSE_NULL)
|
||||||
{
|
{
|
||||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||||
return -1;
|
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 (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen],
|
&ctx->buf[ctx->buflen],
|
||||||
ctx->bufrem,
|
ctx->bufrem,
|
||||||
QSE_MT("<li><a href='%s%s'>%s%s</a></li>"),
|
QSE_MT("<tr><td><a href='%s%s'>%s%s</a></td><td>%s</td><td align='right'>%s</td></tr>"),
|
||||||
encname,
|
encname,
|
||||||
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT("")),
|
(ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")),
|
||||||
ctx->dent->d_name, /* TODO: html escaping */
|
ctx->dent.name, /* TODO: html escaping */
|
||||||
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT(""))
|
(ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")),
|
||||||
|
ctx->tmbuf, ctx->fszbuf
|
||||||
);
|
);
|
||||||
|
|
||||||
if (encname != ctx->dent->d_name) QSE_MMGR_FREE (httpd->mmgr, encname);
|
if (encname != ctx->dent.name) QSE_MMGR_FREE (httpd->mmgr, encname);
|
||||||
|
|
||||||
if (x == -1 || x >= ctx->bufrem)
|
if (x == -1 || x >= ctx->bufrem)
|
||||||
{
|
{
|
||||||
@ -355,7 +385,8 @@ static int task_main_dseg (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->dent = QSE_READDIR (ctx->handle);
|
if (httpd->scb->dir.read (httpd, ctx->handle, &ctx->dent) <= 0)
|
||||||
|
ctx->state |= DIRENT_NOMORE;
|
||||||
}
|
}
|
||||||
while (1);
|
while (1);
|
||||||
|
|
||||||
@ -369,12 +400,12 @@ send_dirlist:
|
|||||||
/* NOTE if (n == 0), it will enter an infinite loop */
|
/* NOTE if (n == 0), it will enter an infinite loop */
|
||||||
|
|
||||||
ctx->bufpos += n;
|
ctx->bufpos += n;
|
||||||
return (ctx->bufpos < ctx->buflen || (ctx->state & FOOTER_PENDING) || ctx->dent)? 1: 0;
|
return (ctx->bufpos < ctx->buflen || (ctx->state & FOOTER_PENDING) || !(ctx->state & DIRENT_NOMORE))? 1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_httpd_task_t* entask_directory_segment (
|
static qse_httpd_task_t* entask_directory_segment (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred, qse_dir_t* handle, task_dir_t* dir)
|
qse_httpd_task_t* pred, qse_ubi_t handle, task_dir_t* dir)
|
||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
task_dseg_t data;
|
task_dseg_t data;
|
||||||
@ -385,6 +416,7 @@ static qse_httpd_task_t* entask_directory_segment (
|
|||||||
data.keepalive = dir->keepalive;
|
data.keepalive = dir->keepalive;
|
||||||
data.chunked = dir->keepalive;
|
data.chunked = dir->keepalive;
|
||||||
data.path = dir->path;
|
data.path = dir->path;
|
||||||
|
data.css = dir->css;
|
||||||
data.qpath = dir->qpath;
|
data.qpath = dir->qpath;
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
@ -393,7 +425,7 @@ static qse_httpd_task_t* entask_directory_segment (
|
|||||||
task.fini = task_fini_dseg;
|
task.fini = task_fini_dseg;
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.qpath.len + 1);
|
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@ -409,7 +441,9 @@ static int task_init_dir (
|
|||||||
|
|
||||||
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
|
xtn->path.ptr = (qse_mchar_t*)(xtn + 1);
|
||||||
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
|
qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr);
|
||||||
xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1;
|
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;
|
||||||
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
|
qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr);
|
||||||
|
|
||||||
/* switch the context to the extension area */
|
/* switch the context to the extension area */
|
||||||
@ -423,15 +457,25 @@ static QSE_INLINE int task_main_dir (
|
|||||||
{
|
{
|
||||||
task_dir_t* dir;
|
task_dir_t* dir;
|
||||||
qse_httpd_task_t* x;
|
qse_httpd_task_t* x;
|
||||||
qse_dir_t* handle = QSE_NULL;
|
qse_ubi_t handle;
|
||||||
|
|
||||||
dir = (task_dir_t*)task->ctx;
|
dir = (task_dir_t*)task->ctx;
|
||||||
x = task;
|
x = task;
|
||||||
|
|
||||||
if (qse_mbsend (dir->path.ptr, QSE_MT("/")))
|
if (qse_mbsend (dir->path.ptr, QSE_MT("/")))
|
||||||
{
|
{
|
||||||
handle = QSE_OPENDIR (dir->path.ptr);
|
if (httpd->scb->dir.open (httpd, dir->path.ptr, &handle) <= -1)
|
||||||
if (handle)
|
{
|
||||||
|
int http_errnum;
|
||||||
|
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||||
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
|
x = qse_httpd_entask_error (
|
||||||
|
httpd, client, x, http_errnum,
|
||||||
|
&dir->version, dir->keepalive);
|
||||||
|
|
||||||
|
return (x == QSE_NULL)? -1: 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
x = qse_httpd_entaskformat (
|
x = qse_httpd_entaskformat (
|
||||||
httpd, client, x,
|
httpd, client, x,
|
||||||
@ -445,21 +489,9 @@ static QSE_INLINE int task_main_dir (
|
|||||||
if (x) x = entask_directory_segment (httpd, client, x, handle, dir);
|
if (x) x = entask_directory_segment (httpd, client, x, handle, dir);
|
||||||
if (x) return 0;
|
if (x) return 0;
|
||||||
|
|
||||||
QSE_CLOSEDIR (handle);
|
httpd->scb->dir.close (httpd, handle);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
int http_errnum;
|
|
||||||
http_errnum = (errno == ENOENT)? 404:
|
|
||||||
(errno == EACCES)? 403: 500;
|
|
||||||
x = qse_httpd_entask_error (
|
|
||||||
httpd, client, x, http_errnum,
|
|
||||||
&dir->version, dir->keepalive);
|
|
||||||
|
|
||||||
QSE_CLOSEDIR (handle);
|
|
||||||
return (x == QSE_NULL)? -1: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -481,14 +513,19 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
|||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred,
|
qse_httpd_task_t* pred,
|
||||||
const qse_mchar_t* path,
|
const qse_mchar_t* path,
|
||||||
|
const qse_mchar_t* css,
|
||||||
qse_htre_t* req)
|
qse_htre_t* req)
|
||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
task_dir_t data;
|
task_dir_t data;
|
||||||
|
|
||||||
|
if (css == QSE_NULL) css = QSE_MT("");
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
data.path.ptr = path;
|
data.path.ptr = path;
|
||||||
data.path.len = qse_mbslen(data.path.ptr);
|
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.ptr = qse_htre_getqpath(req);
|
||||||
data.qpath.len = qse_mbslen(data.qpath.ptr);
|
data.qpath.len = qse_mbslen(data.qpath.ptr);
|
||||||
data.version = *qse_htre_getversion(req);
|
data.version = *qse_htre_getversion(req);
|
||||||
@ -500,6 +537,6 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
|||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (httpd, client, pred, &task,
|
return qse_httpd_entask (httpd, client, pred, &task,
|
||||||
QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.qpath.len + 1);
|
QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
#define SERVER_XTN_CFG_USERNAME QSE_HTTPD_SERVER_XTN_CFG_USERNAME
|
#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_PASSWORD QSE_HTTPD_SERVER_XTN_CFG_PASSWORD
|
||||||
#define SERVER_XTN_CFG_BASICAUTH QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH
|
#define SERVER_XTN_CFG_BASICAUTH QSE_HTTPD_SERVER_XTN_CFG_BASICAUTH
|
||||||
|
#define SERVER_XTN_CFG_DIRCSS QSE_HTTPD_SERVER_XTN_CFG_DIRCSS
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -1042,20 +1043,14 @@ static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int file_executable (qse_httpd_t* httpd, const qse_mchar_t* path)
|
|
||||||
{
|
|
||||||
if (access (path, X_OK) == -1)
|
|
||||||
return (errno == EACCES)? 0 /*no*/: -1 /*error*/;
|
|
||||||
return 1; /* yes */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int file_stat (
|
static int stat_file (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst)
|
qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst, int regonly)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
/* TODO: lstat? or stat? */
|
/* TODO: lstat? or stat? */
|
||||||
if (stat (path, &st) <= -1)
|
if (QSE_STAT (path, &st) <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@ -1063,7 +1058,7 @@ static int file_stat (
|
|||||||
|
|
||||||
/* stating for a file. it should be a regular file.
|
/* stating for a file. it should be a regular file.
|
||||||
* i don't allow other file types. */
|
* i don't allow other file types. */
|
||||||
if (!S_ISREG(st.st_mode))
|
if (regonly && !S_ISREG(st.st_mode))
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1071,6 +1066,7 @@ static int file_stat (
|
|||||||
|
|
||||||
QSE_MEMSET (hst, 0, QSE_SIZEOF(*hst));
|
QSE_MEMSET (hst, 0, QSE_SIZEOF(*hst));
|
||||||
|
|
||||||
|
hst->isdir = S_ISDIR(st.st_mode);
|
||||||
hst->dev = st.st_dev;
|
hst->dev = st.st_dev;
|
||||||
hst->ino = st.st_ino;
|
hst->ino = st.st_ino;
|
||||||
hst->size = st.st_size;
|
hst->size = st.st_size;
|
||||||
@ -1085,6 +1081,21 @@ static int file_stat (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static int file_executable (qse_httpd_t* httpd, const qse_mchar_t* path)
|
||||||
|
{
|
||||||
|
if (access (path, X_OK) == -1)
|
||||||
|
return (errno == EACCES)? 0 /*no*/: -1 /*error*/;
|
||||||
|
return 1; /* yes */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_stat (
|
||||||
|
qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst)
|
||||||
|
{
|
||||||
|
return stat_file (httpd, path, hst, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static int file_ropen (
|
static int file_ropen (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle)
|
qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle)
|
||||||
{
|
{
|
||||||
@ -1156,6 +1167,93 @@ static qse_ssize_t file_write (
|
|||||||
return QSE_WRITE (handle.i, buf, len);
|
return QSE_WRITE (handle.i, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct dir_t dir_t;
|
||||||
|
struct dir_t
|
||||||
|
{
|
||||||
|
qse_mchar_t* path;
|
||||||
|
qse_dir_t* dp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dir_open (qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle)
|
||||||
|
{
|
||||||
|
dir_t* d;
|
||||||
|
|
||||||
|
d = QSE_MMGR_ALLOC (httpd->mmgr, QSE_SIZEOF(*d));
|
||||||
|
if (d == QSE_NULL)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->path = qse_mbsdup (path, httpd->mmgr);
|
||||||
|
if (d->path == QSE_NULL)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, d);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->dp = QSE_OPENDIR (path);
|
||||||
|
if (d->dp == QSE_NULL)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, d->path);
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, d);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle->ptr = d;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dir_close (qse_httpd_t* httpd, qse_ubi_t handle)
|
||||||
|
{
|
||||||
|
dir_t* d;
|
||||||
|
|
||||||
|
d = (dir_t*)handle.ptr;
|
||||||
|
|
||||||
|
QSE_CLOSEDIR (d->dp);
|
||||||
|
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, d->path);
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dir_read (qse_httpd_t* httpd, qse_ubi_t handle, qse_httpd_dirent_t* dirent)
|
||||||
|
{
|
||||||
|
dir_t* d;
|
||||||
|
qse_dirent_t* de;
|
||||||
|
qse_mchar_t* fpath;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
d = (dir_t*)handle.ptr;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
de = QSE_READDIR (d->dp);
|
||||||
|
if (de == QSE_NULL)
|
||||||
|
{
|
||||||
|
if (errno == 0) return 0;
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* i assume that d->path ends with a slash */
|
||||||
|
fpath = qse_mbsdup2 (d->path, de->d_name, httpd->mmgr);
|
||||||
|
if (fpath == QSE_NULL)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = stat_file (httpd, fpath, &dirent->stat, 0);
|
||||||
|
QSE_MMGR_FREE (httpd->mmgr, fpath);
|
||||||
|
if (n <= -1) QSE_MEMSET (dirent, 0, QSE_SIZEOF(*dirent));
|
||||||
|
|
||||||
|
dirent->name = de->d_name;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
static void client_close (
|
static void client_close (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||||
@ -1520,6 +1618,13 @@ static qse_httpd_scb_t httpd_system_callbacks =
|
|||||||
file_write
|
file_write
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* directory operation */
|
||||||
|
{ dir_open,
|
||||||
|
dir_close,
|
||||||
|
dir_read
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/* client connection */
|
/* client connection */
|
||||||
{ client_close,
|
{ client_close,
|
||||||
client_shutdown,
|
client_shutdown,
|
||||||
@ -1749,6 +1854,7 @@ auth_ok:
|
|||||||
|
|
||||||
target->type = QSE_HTTPD_RSRC_DIR;
|
target->type = QSE_HTTPD_RSRC_DIR;
|
||||||
target->u.dir.path = xpath;
|
target->u.dir.path = xpath;
|
||||||
|
target->u.dir.css = server_xtn->cfg[SERVER_XTN_CFG_DIRCSS].ptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -390,7 +390,7 @@ qse_httpd_task_t* qse_httpd_entaskrsrc (
|
|||||||
|
|
||||||
case QSE_HTTPD_RSRC_DIR:
|
case QSE_HTTPD_RSRC_DIR:
|
||||||
qse_httpd_discardcontent (httpd, req);
|
qse_httpd_discardcontent (httpd, req);
|
||||||
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, req);
|
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, rsrc->u.dir.css, req);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSE_HTTPD_RSRC_ERROR:
|
case QSE_HTTPD_RSRC_ERROR:
|
||||||
|
@ -59,12 +59,20 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
|||||||
|
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
if (qse_httpd_attachserverstd (httpd, argv[i], QSE_NULL, 0) == QSE_NULL)
|
qse_httpd_server_t* server;
|
||||||
|
qse_httpd_server_xtn_t* server_xtn;
|
||||||
|
|
||||||
|
server = qse_httpd_attachserverstd (httpd, argv[i], QSE_NULL, 0);
|
||||||
|
if (server == QSE_NULL)
|
||||||
{
|
{
|
||||||
qse_fprintf (QSE_STDERR,
|
qse_fprintf (QSE_STDERR,
|
||||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_httpd = httpd;
|
g_httpd = httpd;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user