added directory handler to qse_httpd_scb_t

This commit is contained in:
hyung-hwan 2012-10-15 16:39:23 +00:00
parent d9b42ca785
commit 7940a758d0
5 changed files with 241 additions and 65 deletions

View File

@ -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
); );

View File

@ -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);
} }

View File

@ -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
{ {

View File

@ -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:

View File

@ -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;