enhanced qse_httpd_entaskfile() and qse_httpd_entaskdir() to handle more methods.
added qse_httpd_entaskallow(). removed some unused functions.
This commit is contained in:
parent
595e3be043
commit
28119c7289
@ -466,6 +466,17 @@ static int query_server (
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case QSE_HTTPD_SERVERSTD_ROOT:
|
case QSE_HTTPD_SERVERSTD_ROOT:
|
||||||
|
#if 0
|
||||||
|
if (qse_mbscmp (qse_htre_getqpath(req), QSE_MT("/version")) == 0)
|
||||||
|
{
|
||||||
|
/* return static text without inspecting further */
|
||||||
|
((qse_httpd_serverstd_root_t*)result)->type = QSE_HTTPD_SERVERSTD_ROOT_TEXT;
|
||||||
|
((qse_httpd_serverstd_root_t*)result)->u.text.ptr = QSE_MT(QSE_PACKAGE_NAME " " QSE_PACKAGE_VERSION);
|
||||||
|
((qse_httpd_serverstd_root_t*)result)->u.text.mime = QSE_MT("text/plain");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
|
||||||
if (loccfg->root_is_nwad)
|
if (loccfg->root_is_nwad)
|
||||||
{
|
{
|
||||||
((qse_httpd_serverstd_root_t*)result)->type = QSE_HTTPD_SERVERSTD_ROOT_NWAD;
|
((qse_httpd_serverstd_root_t*)result)->type = QSE_HTTPD_SERVERSTD_ROOT_NWAD;
|
||||||
@ -574,30 +585,47 @@ static int query_server (
|
|||||||
case QSE_HTTPD_SERVERSTD_DIRACC:
|
case QSE_HTTPD_SERVERSTD_DIRACC:
|
||||||
case QSE_HTTPD_SERVERSTD_FILEACC:
|
case QSE_HTTPD_SERVERSTD_FILEACC:
|
||||||
{
|
{
|
||||||
qse_size_t i;
|
switch (qse_htre_getqmethodtype(req))
|
||||||
const qse_mchar_t* xpath_base;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
id = (code == QSE_HTTPD_SERVERSTD_DIRACC)? 0: 1;
|
|
||||||
|
|
||||||
xpath_base = qse_mbsbasename (xpath);
|
|
||||||
|
|
||||||
*(int*)result = 200;
|
|
||||||
for (i = 0; i < QSE_COUNTOF(loccfg->access[id]); i++)
|
|
||||||
{
|
{
|
||||||
struct access_t* access;
|
case QSE_HTTP_OPTIONS:
|
||||||
for (access = loccfg->access[id][i].head; access; access = access->next)
|
case QSE_HTTP_HEAD:
|
||||||
|
case QSE_HTTP_GET:
|
||||||
|
case QSE_HTTP_POST:
|
||||||
|
case QSE_HTTP_PUT:
|
||||||
|
case QSE_HTTP_DELETE:
|
||||||
{
|
{
|
||||||
if ((access->type == ACCESS_PREFIX && qse_mbsbeg (xpath_base, access->spec)) ||
|
qse_size_t i;
|
||||||
(access->type == ACCESS_SUFFIX && qse_mbsend (xpath_base, access->spec)) ||
|
const qse_mchar_t* xpath_base;
|
||||||
(access->type == ACCESS_NAME && qse_mbscmp (xpath_base, access->spec) == 0) ||
|
int id;
|
||||||
access->type == ACCESS_OTHER)
|
|
||||||
|
id = (code == QSE_HTTPD_SERVERSTD_DIRACC)? 0: 1;
|
||||||
|
|
||||||
|
xpath_base = qse_mbsbasename (xpath);
|
||||||
|
|
||||||
|
*(int*)result = 200;
|
||||||
|
for (i = 0; i < QSE_COUNTOF(loccfg->access[id]); i++)
|
||||||
{
|
{
|
||||||
*(int*)result = access->value;
|
struct access_t* access;
|
||||||
return 0;
|
for (access = loccfg->access[id][i].head; access; access = access->next)
|
||||||
|
{
|
||||||
|
if ((access->type == ACCESS_PREFIX && qse_mbsbeg (xpath_base, access->spec)) ||
|
||||||
|
(access->type == ACCESS_SUFFIX && qse_mbsend (xpath_base, access->spec)) ||
|
||||||
|
(access->type == ACCESS_NAME && qse_mbscmp (xpath_base, access->spec) == 0) ||
|
||||||
|
access->type == ACCESS_OTHER)
|
||||||
|
{
|
||||||
|
*(int*)result = access->value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
*(int*)result = 405; /* method not allowed */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ struct qse_httpd_scb_t
|
|||||||
int (*stat) (
|
int (*stat) (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path,
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
qse_httpd_stat_t* stat);
|
qse_httpd_stat_t* stat);
|
||||||
|
int (*purge) (qse_httpd_t* httpd, const qse_mchar_t* path);
|
||||||
|
|
||||||
int (*ropen) (
|
int (*ropen) (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path,
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
@ -185,6 +186,12 @@ struct qse_httpd_scb_t
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
int (*stat) (
|
||||||
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
|
qse_httpd_stat_t* stat);
|
||||||
|
int (*make) (qse_httpd_t* httpd, const qse_mchar_t* path);
|
||||||
|
int (*purge) (qse_httpd_t* httpd, const qse_mchar_t* path);
|
||||||
|
|
||||||
int (*open) (
|
int (*open) (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path,
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
qse_ubi_t* handle);
|
qse_ubi_t* handle);
|
||||||
@ -808,6 +815,14 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entasknomod (
|
|||||||
qse_htre_t* req
|
qse_htre_t* req
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskallow (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
qse_httpd_task_t* pred,
|
||||||
|
const qse_mchar_t* allow,
|
||||||
|
qse_htre_t* req
|
||||||
|
);
|
||||||
|
|
||||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskdir (
|
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskdir (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
|
@ -41,7 +41,8 @@ typedef void (*qse_httpd_serverstd_freersrc_t) (
|
|||||||
enum qse_httpd_serverstd_root_type_t
|
enum qse_httpd_serverstd_root_type_t
|
||||||
{
|
{
|
||||||
QSE_HTTPD_SERVERSTD_ROOT_PATH,
|
QSE_HTTPD_SERVERSTD_ROOT_PATH,
|
||||||
QSE_HTTPD_SERVERSTD_ROOT_NWAD
|
QSE_HTTPD_SERVERSTD_ROOT_NWAD,
|
||||||
|
QSE_HTTPD_SERVERSTD_ROOT_TEXT
|
||||||
};
|
};
|
||||||
typedef enum qse_httpd_serverstd_root_type_t qse_httpd_serverstd_root_type_t;
|
typedef enum qse_httpd_serverstd_root_type_t qse_httpd_serverstd_root_type_t;
|
||||||
|
|
||||||
@ -57,6 +58,11 @@ struct qse_httpd_serverstd_root_t
|
|||||||
qse_size_t rpl; /* replacement length */
|
qse_size_t rpl; /* replacement length */
|
||||||
} path;
|
} path;
|
||||||
qse_nwad_t nwad;
|
qse_nwad_t nwad;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const qse_mchar_t* ptr;
|
||||||
|
const qse_mchar_t* mime;
|
||||||
|
} text;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -318,6 +318,12 @@
|
|||||||
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
|
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SYS_mkdir) && defined(QSE_USE_SYSCALL)
|
||||||
|
# define QSE_MKDIR(path,mode) syscall(SYS_mkdir,path,mode)
|
||||||
|
#else
|
||||||
|
# define QSE_MKDIR(path,mode) mkdir(path,mode)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SYS_rmdir) && defined(QSE_USE_SYSCALL)
|
#if defined(SYS_rmdir) && defined(QSE_USE_SYSCALL)
|
||||||
# define QSE_RMDIR(path) syscall(SYS_rmdir,path)
|
# define QSE_RMDIR(path) syscall(SYS_rmdir,path)
|
||||||
#else
|
#else
|
||||||
|
@ -128,6 +128,7 @@
|
|||||||
{ \
|
{ \
|
||||||
case ENOMEM: return __SYSERRNUM__ (obj2, ENOMEM); \
|
case ENOMEM: return __SYSERRNUM__ (obj2, ENOMEM); \
|
||||||
case EINVAL: return __SYSERRNUM__ (obj2, EINVAL); \
|
case EINVAL: return __SYSERRNUM__ (obj2, EINVAL); \
|
||||||
|
case EBUSY: \
|
||||||
case EACCES: return __SYSERRNUM__ (obj2, EACCES); \
|
case EACCES: return __SYSERRNUM__ (obj2, EACCES); \
|
||||||
case ENOTDIR: \
|
case ENOTDIR: \
|
||||||
case ENOENT: return __SYSERRNUM__ (obj2, ENOENT); \
|
case ENOENT: return __SYSERRNUM__ (obj2, ENOENT); \
|
||||||
|
@ -50,6 +50,8 @@ struct task_cgi_t
|
|||||||
const qse_mchar_t* suffix;
|
const qse_mchar_t* suffix;
|
||||||
const qse_mchar_t* root;
|
const qse_mchar_t* root;
|
||||||
const qse_mchar_t* shebang;
|
const qse_mchar_t* shebang;
|
||||||
|
|
||||||
|
int method;
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive; /* taken from the request */
|
int keepalive; /* taken from the request */
|
||||||
int nph;
|
int nph;
|
||||||
@ -746,6 +748,7 @@ static int task_init_cgi (
|
|||||||
qse_mbscpy ((qse_mchar_t*)cgi->root, arg->root.ptr);
|
qse_mbscpy ((qse_mchar_t*)cgi->root, arg->root.ptr);
|
||||||
qse_mbscpy ((qse_mchar_t*)cgi->shebang, arg->shebang.ptr);
|
qse_mbscpy ((qse_mchar_t*)cgi->shebang, arg->shebang.ptr);
|
||||||
|
|
||||||
|
cgi->method = qse_htre_getqmethodtype(arg->req);
|
||||||
cgi->version = *qse_htre_getversion(arg->req);
|
cgi->version = *qse_htre_getversion(arg->req);
|
||||||
cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||||
cgi->nph = arg->nph;
|
cgi->nph = arg->nph;
|
||||||
@ -1355,7 +1358,7 @@ qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MB
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
return (qse_httpd_entask_err (httpd, client, task, 500, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
return (qse_httpd_entask_err (httpd, client, task, 500, cgi->method, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int task_main_cgi (
|
static int task_main_cgi (
|
||||||
@ -1502,7 +1505,7 @@ oops:
|
|||||||
|
|
||||||
return (qse_httpd_entask_err (
|
return (qse_httpd_entask_err (
|
||||||
httpd, client, task, http_errnum,
|
httpd, client, task, http_errnum,
|
||||||
&cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
cgi->method, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: global option or individual paramter for max cgi lifetime
|
/* TODO: global option or individual paramter for max cgi lifetime
|
||||||
|
@ -30,7 +30,7 @@ struct task_dir_t
|
|||||||
qse_mcstr_t qpath;
|
qse_mcstr_t qpath;
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
int headonly;
|
int method;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct task_dseg_t task_dseg_t;
|
typedef struct task_dseg_t task_dseg_t;
|
||||||
@ -370,7 +370,7 @@ static qse_httpd_task_t* entask_directory_segment (
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static int task_init_dir (
|
static int task_init_getdir (
|
||||||
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_dir_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
task_dir_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||||
@ -390,7 +390,7 @@ static int task_init_dir (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int task_main_dir (
|
static QSE_INLINE int task_main_getdir (
|
||||||
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_dir_t* dir;
|
task_dir_t* dir;
|
||||||
@ -415,26 +415,46 @@ static QSE_INLINE int task_main_dir (
|
|||||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
x = qse_httpd_entask_err (
|
x = qse_httpd_entask_err (
|
||||||
httpd, client, x, http_errnum,
|
httpd, client, x, http_errnum,
|
||||||
&dir->version, dir->keepalive);
|
dir->method, &dir->version, dir->keepalive);
|
||||||
|
|
||||||
return (x == QSE_NULL)? -1: 0;
|
return (x == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x = qse_httpd_entaskformat (
|
if (dir->method == QSE_HTTP_HEAD)
|
||||||
httpd, client, x,
|
{
|
||||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\n%s\r\n"),
|
x = qse_httpd_entaskformat (
|
||||||
dir->version.major, dir->version.minor,
|
httpd, client, x,
|
||||||
qse_httpd_getname (httpd),
|
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\n"),
|
||||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
dir->version.major, dir->version.minor,
|
||||||
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
qse_httpd_getname (httpd),
|
||||||
(dir->keepalive? QSE_MT("Transfer-Encoding: chunked\r\n"): QSE_MT(""))
|
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||||
);
|
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close"))
|
||||||
if (x) x = entask_directory_segment (httpd, client, x, handle, dir);
|
);
|
||||||
if (x) return 0;
|
|
||||||
|
|
||||||
httpd->opt.scb.dir.close (httpd, handle);
|
httpd->opt.scb.dir.close (httpd, handle);
|
||||||
return -1;
|
return (x == QSE_NULL)? -1: 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = qse_httpd_entaskformat (
|
||||||
|
httpd, client, x,
|
||||||
|
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\n%s\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->keepalive? QSE_MT("Transfer-Encoding: chunked\r\n"): QSE_MT(""))
|
||||||
|
);
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
x = entask_directory_segment (httpd, client, x, handle, dir);
|
||||||
|
if (x) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpd->opt.scb.dir.close (httpd, handle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
}
|
}
|
||||||
@ -458,9 +478,6 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
|||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
task_dir_t data;
|
task_dir_t data;
|
||||||
int meth;
|
|
||||||
|
|
||||||
meth = qse_htre_getqmethodtype(req);
|
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
data.path.ptr = path;
|
data.path.ptr = path;
|
||||||
@ -469,28 +486,71 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
|||||||
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);
|
||||||
data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||||
|
data.method = qse_htre_getqmethodtype(req);
|
||||||
|
|
||||||
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
|
|
||||||
qse_htre_discardcontent (req); /* TODO: don't discard for put??? */
|
/* i don't need contents for directories */
|
||||||
switch (meth)
|
qse_htre_discardcontent (req);
|
||||||
|
|
||||||
|
switch (data.method)
|
||||||
{
|
{
|
||||||
|
case QSE_HTTP_OPTIONS:
|
||||||
|
return qse_httpd_entaskallow (httpd, client, pred,
|
||||||
|
QSE_MT("OPTIONS,GET,HEAD,POST,PUT,DELETE"), req);
|
||||||
|
|
||||||
case QSE_HTTP_HEAD:
|
case QSE_HTTP_HEAD:
|
||||||
data.headonly = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QSE_HTTP_GET:
|
case QSE_HTTP_GET:
|
||||||
case QSE_HTTP_POST:
|
case QSE_HTTP_POST:
|
||||||
case QSE_HTTP_PUT:
|
task.init = task_init_getdir;
|
||||||
|
task.main = task_main_getdir;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QSE_HTTP_PUT:
|
||||||
|
{
|
||||||
|
int status = 201; /* 201 Created */
|
||||||
|
|
||||||
|
|
||||||
|
if (httpd->opt.scb.dir.make (httpd, path) <= -1)
|
||||||
|
{
|
||||||
|
if (httpd->errnum == QSE_HTTPD_EEXIST)
|
||||||
|
{
|
||||||
|
/* an entry with the same name exists.
|
||||||
|
* if it is a directory, it's considered ok.
|
||||||
|
* if not, send '403 forbidden' indicating you can't
|
||||||
|
* change a file to a directory */
|
||||||
|
qse_httpd_stat_t st;
|
||||||
|
status = (httpd->opt.scb.dir.stat (httpd, path, &st) <= -1)? 403: 204;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||||
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qse_httpd_entaskerr (httpd, client, pred, status, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case QSE_HTTP_DELETE:
|
||||||
|
{
|
||||||
|
int status = 200;
|
||||||
|
|
||||||
|
if (httpd->opt.scb.dir.purge (httpd, path) <= -1)
|
||||||
|
{
|
||||||
|
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||||
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
return qse_httpd_entaskerr (httpd, client, pred, status, req);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Method not allowed */
|
/* Method not allowed */
|
||||||
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
|
||||||
task.init = task_init_dir;
|
|
||||||
task.main = task_main_dir;
|
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (httpd, client, pred, &task,
|
return qse_httpd_entask (httpd, client, pred, &task,
|
||||||
|
@ -25,30 +25,32 @@
|
|||||||
|
|
||||||
#define ETAG_LEN_MAX 127
|
#define ETAG_LEN_MAX 127
|
||||||
|
|
||||||
#define PUTFILE_INIT_FAILED (1 << 0)
|
#define PUTFILE_INIT_FAILED (1 << 0)
|
||||||
|
#define PUTFILE_WRITE_FAILED (1 << 1)
|
||||||
|
|
||||||
typedef struct task_file_t task_file_t;
|
typedef struct task_file_t task_file_t;
|
||||||
struct task_file_t
|
struct task_file_t
|
||||||
{
|
{
|
||||||
qse_mcstr_t path;
|
qse_mcstr_t path;
|
||||||
|
|
||||||
qse_http_range_t range;
|
|
||||||
qse_mchar_t if_none_match[ETAG_LEN_MAX + 1];
|
|
||||||
qse_ntime_t if_modified_since;
|
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
int method;
|
int method;
|
||||||
|
|
||||||
/* only for put file... */
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_mcstr_t mime;
|
qse_mcstr_t mime;
|
||||||
|
qse_mchar_t if_none_match[ETAG_LEN_MAX + 1];
|
||||||
|
qse_ntime_t if_modified_since;
|
||||||
|
qse_http_range_t range;
|
||||||
} get;
|
} get;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
qse_httpd_t* httpd;
|
||||||
int flags;
|
int flags;
|
||||||
|
int status;
|
||||||
qse_htre_t* req;
|
qse_htre_t* req;
|
||||||
qse_ubi_t handle;
|
qse_ubi_t handle;
|
||||||
} put;
|
} put;
|
||||||
@ -91,7 +93,6 @@ static int task_main_getfseg (
|
|||||||
count = MAX_SEND_SIZE;
|
count = MAX_SEND_SIZE;
|
||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
|
|
||||||
/* TODO: more adjustment needed for OS with different sendfile semantics... */
|
|
||||||
n = httpd->opt.scb.client.sendfile (
|
n = httpd->opt.scb.client.sendfile (
|
||||||
httpd, client, ctx->handle, &ctx->offset, count);
|
httpd, client, ctx->handle, &ctx->offset, count);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
@ -184,7 +185,7 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
x = qse_httpd_entask_err (
|
x = qse_httpd_entask_err (
|
||||||
httpd, client, x, http_errnum,
|
httpd, client, x, http_errnum,
|
||||||
&file->version, file->keepalive);
|
file->method, &file->version, file->keepalive);
|
||||||
goto no_file_send;
|
goto no_file_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,37 +197,37 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
x = qse_httpd_entask_err (
|
x = qse_httpd_entask_err (
|
||||||
httpd, client, x, http_errnum,
|
httpd, client, x, http_errnum,
|
||||||
&file->version, file->keepalive);
|
file->method, &file->version, file->keepalive);
|
||||||
goto no_file_send;
|
goto no_file_send;
|
||||||
}
|
}
|
||||||
fileopen = 1;
|
fileopen = 1;
|
||||||
|
|
||||||
if (file->range.type != QSE_HTTP_RANGE_NONE)
|
if (file->u.get.range.type != QSE_HTTP_RANGE_NONE)
|
||||||
{
|
{
|
||||||
qse_mchar_t tmp[4][64];
|
qse_mchar_t tmp[4][64];
|
||||||
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
||||||
qse_size_t etag_len;
|
qse_size_t etag_len;
|
||||||
|
|
||||||
if (file->range.type == QSE_HTTP_RANGE_SUFFIX)
|
if (file->u.get.range.type == QSE_HTTP_RANGE_SUFFIX)
|
||||||
{
|
{
|
||||||
if (file->range.to > st.size) file->range.to = st.size;
|
if (file->u.get.range.to > st.size) file->u.get.range.to = st.size;
|
||||||
file->range.from = st.size - file->range.to;
|
file->u.get.range.from = st.size - file->u.get.range.to;
|
||||||
file->range.to = file->range.to + file->range.from;
|
file->u.get.range.to = file->u.get.range.to + file->u.get.range.from;
|
||||||
if (st.size > 0) file->range.to--;
|
if (st.size > 0) file->u.get.range.to--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->range.from >= st.size)
|
if (file->u.get.range.from >= st.size)
|
||||||
{
|
{
|
||||||
x = qse_httpd_entask_err (
|
x = qse_httpd_entask_err (
|
||||||
httpd, client, x, 416, &file->version, file->keepalive);
|
httpd, client, x, 416, file->method, &file->version, file->keepalive);
|
||||||
goto no_file_send;
|
goto no_file_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->range.to >= st.size) file->range.to = st.size - 1;
|
if (file->u.get.range.to >= st.size) file->u.get.range.to = st.size - 1;
|
||||||
|
|
||||||
qse_fmtuintmaxtombs (tmp[0], QSE_COUNTOF(tmp[0]), (file->range.to - file->range.from + 1), 10, -1, QSE_MT('\0'), QSE_NULL);
|
qse_fmtuintmaxtombs (tmp[0], QSE_COUNTOF(tmp[0]), (file->u.get.range.to - file->u.get.range.from + 1), 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
qse_fmtuintmaxtombs (tmp[1], QSE_COUNTOF(tmp[1]), file->range.from, 10, -1, QSE_MT('\0'), QSE_NULL);
|
qse_fmtuintmaxtombs (tmp[1], QSE_COUNTOF(tmp[1]), file->u.get.range.from, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
qse_fmtuintmaxtombs (tmp[2], QSE_COUNTOF(tmp[2]), file->range.to, 10, -1, QSE_MT('\0'), QSE_NULL);
|
qse_fmtuintmaxtombs (tmp[2], QSE_COUNTOF(tmp[2]), file->u.get.range.to, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
qse_fmtuintmaxtombs (tmp[3], QSE_COUNTOF(tmp[3]), st.size, 10, -1, QSE_MT('\0'), QSE_NULL);
|
qse_fmtuintmaxtombs (tmp[3], QSE_COUNTOF(tmp[3]), st.size, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
|
|
||||||
etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag), st.mtime.sec, 16, -1, QSE_MT('\0'), QSE_NULL);
|
etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag), st.mtime.sec, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
@ -249,7 +250,10 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
||||||
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
||||||
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
||||||
tmp[0], tmp[1], tmp[2], tmp[3], etag
|
((file->method == QSE_HTTP_HEAD)? QSE_MT("0"): tmp[0]),
|
||||||
|
tmp[1], tmp[2], tmp[3],
|
||||||
|
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||||
|
etag
|
||||||
);
|
);
|
||||||
if (x)
|
if (x)
|
||||||
{
|
{
|
||||||
@ -257,8 +261,8 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
x = entask_getfseg (
|
x = entask_getfseg (
|
||||||
httpd, client, x,
|
httpd, client, x,
|
||||||
handle,
|
handle,
|
||||||
file->range.from,
|
file->u.get.range.from,
|
||||||
(file->range.to - file->range.from + 1)
|
(file->u.get.range.to - file->u.get.range.from + 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,13 +282,13 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
etag[etag_len++] = QSE_MT('-');
|
etag[etag_len++] = QSE_MT('-');
|
||||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.dev, 16, -1, QSE_MT('\0'), QSE_NULL);
|
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.dev, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
|
|
||||||
if ((file->if_none_match[0] != QSE_MT('\0') && qse_mbscmp (etag, file->if_none_match) == 0) ||
|
if ((file->u.get.if_none_match[0] != QSE_MT('\0') && qse_mbscmp (etag, file->u.get.if_none_match) == 0) ||
|
||||||
(file->if_modified_since.sec > 0 && st.mtime.sec <= file->if_modified_since.sec))
|
(file->u.get.if_modified_since.sec > 0 && st.mtime.sec <= file->u.get.if_modified_since.sec))
|
||||||
{
|
{
|
||||||
/* i've converted milliseconds to seconds before timestamp comparison
|
/* i've converted milliseconds to seconds before timestamp comparison
|
||||||
* because st.mtime has the actual milliseconds less than 1 second
|
* because st.mtime has the actual milliseconds less than 1 second
|
||||||
* while if_modified_since doesn't have such small milliseconds */
|
* while if_modified_since doesn't have such small milliseconds */
|
||||||
x = qse_httpd_entask_nomod (httpd, client, x, &file->version, file->keepalive);
|
x = qse_httpd_entask_nomod (httpd, client, x, file->method, &file->version, file->keepalive);
|
||||||
goto no_file_send;
|
goto no_file_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +308,7 @@ static QSE_INLINE int task_main_getfile (
|
|||||||
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
||||||
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
||||||
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
||||||
b_fsize,
|
((file->method == QSE_HTTP_HEAD)? QSE_MT("0"): b_fsize),
|
||||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||||
etag
|
etag
|
||||||
);
|
);
|
||||||
@ -326,6 +330,24 @@ no_file_send:
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static int write_file (qse_httpd_t* httpd, qse_ubi_t handle, const qse_mchar_t* ptr, qse_size_t len)
|
||||||
|
{
|
||||||
|
qse_ssize_t n;
|
||||||
|
qse_size_t pos = 0;
|
||||||
|
|
||||||
|
/* this implementation assumes that file writing will never get
|
||||||
|
* blocked in practice. so no i/o multiplexing is performed over
|
||||||
|
* file descriptors */
|
||||||
|
while (pos < len)
|
||||||
|
{
|
||||||
|
n = httpd->opt.scb.file.write (httpd, handle, &ptr[pos], len - pos);
|
||||||
|
if (n <= 0) return -1;
|
||||||
|
pos += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int putfile_snatch_client_input (
|
static int putfile_snatch_client_input (
|
||||||
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
|
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
|
||||||
{
|
{
|
||||||
@ -354,10 +376,13 @@ static int putfile_snatch_client_input (
|
|||||||
* the trigger is not needed any more. */
|
* the trigger is not needed any more. */
|
||||||
task->trigger[0].mask = 0;
|
task->trigger[0].mask = 0;
|
||||||
}
|
}
|
||||||
else /*if (!(file->reqflags & PROXY_REQ_FWDERR))*/
|
else if (!(file->u.put.flags & PUTFILE_WRITE_FAILED))
|
||||||
{
|
{
|
||||||
/* TODO: write to file */
|
if (write_file (file->u.put.httpd, file->u.put.handle, ptr, len) <= -1)
|
||||||
qse_printf (QSE_T("WRITING 4 [%.*hs]\n"), (int)len, ptr);
|
{
|
||||||
|
file->u.put.flags |= PUTFILE_WRITE_FAILED;
|
||||||
|
file->u.put.status = 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -368,7 +393,7 @@ static int task_init_putfile (
|
|||||||
{
|
{
|
||||||
task_file_t* file = qse_httpd_gettaskxtn (httpd, task);
|
task_file_t* file = qse_httpd_gettaskxtn (httpd, task);
|
||||||
task_file_t* arg = (task_file_t*)task->ctx;
|
task_file_t* arg = (task_file_t*)task->ctx;
|
||||||
int snatch_needed;
|
qse_httpd_stat_t st;
|
||||||
|
|
||||||
/* zero out the task's extension area */
|
/* zero out the task's extension area */
|
||||||
QSE_MEMCPY (file, arg, QSE_SIZEOF(*file));
|
QSE_MEMCPY (file, arg, QSE_SIZEOF(*file));
|
||||||
@ -377,87 +402,36 @@ static int task_init_putfile (
|
|||||||
/* copy in the path name to the area */
|
/* copy in the path name to the area */
|
||||||
file->path.ptr = (qse_mchar_t*)(file + 1);
|
file->path.ptr = (qse_mchar_t*)(file + 1);
|
||||||
qse_mbscpy ((qse_mchar_t*)file->path.ptr, arg->path.ptr);
|
qse_mbscpy ((qse_mchar_t*)file->path.ptr, arg->path.ptr);
|
||||||
|
file->u.put.status = 204; /* 200 should also be ok to indicate success. */
|
||||||
|
task->ctx = file; /* switch the task context to the extension area */
|
||||||
|
|
||||||
snatch_needed = 0;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
if (httpd->opt.scb.file.stat (httpd, file->path.ptr, &st) <= -1)
|
if (httpd->opt.scb.file.stat (httpd, file->path.ptr, &st) <= -1)
|
||||||
{
|
{
|
||||||
int http_errnum = 500;
|
if (httpd->errnum == QSE_HTTPD_ENOENT)
|
||||||
|
|
||||||
switch (httpd->errnum)
|
|
||||||
{
|
{
|
||||||
case QSE_HTTPD_ENOENT:
|
/* stat found no such file. so if the request is achived
|
||||||
/* nothing to do */
|
* successfully, it should send '201 Created' */
|
||||||
break;
|
file->u.put.status = 201;
|
||||||
|
|
||||||
case QSE_HTTPD_EACCES:
|
|
||||||
http_errnum = 403;
|
|
||||||
default:
|
|
||||||
|
|
||||||
goto no_file_write;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (httpd->opt.scb.file.wopen (httpd, file->path.ptr, &file->u.put.handle) <= -1) goto oops;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
|
if (httpd->opt.scb.file.wopen (httpd, file->path.ptr, &file->u.put.handle) <= -1)
|
||||||
if (arg->u.put.req->state & QSE_HTRE_DISCARDED)
|
|
||||||
{
|
{
|
||||||
/* no content to add */
|
file->u.put.status = (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
/* TODO: return what??? */
|
goto oops;
|
||||||
qse_printf (QSE_T("ALL DISCARDED...\n"));
|
|
||||||
}
|
|
||||||
else if (arg->u.put.req->state & QSE_HTRE_COMPLETED)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
len = qse_htre_getcontentlen(arg->u.put.req);
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
ptr = qse_htre_getcontentptr(arg->u.put.req);
|
|
||||||
/* TODO: write this to a file */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
qse_printf (QSE_T("WRITING 1 [%.*hs]\n"), (int)qse_htre_getcontentlen(arg->u.put.req), qse_htre_getcontentptr(arg->u.put.req));
|
|
||||||
}
|
|
||||||
else if (arg->u.put.req->attr.flags & QSE_HTRE_ATTR_LENGTH)
|
|
||||||
{
|
|
||||||
/* Content-Length is included and the content
|
|
||||||
* has been received partially so far */
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
len = qse_htre_getcontentlen(arg->u.put.req);
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
ptr = qse_htre_getcontentptr(arg->u.put.req);
|
|
||||||
/* TODO: write to a file */
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
qse_printf (QSE_T("WRITING 2 [%.*hs]\n"), (int)qse_htre_getcontentlen(arg->u.put.req), qse_htre_getcontentptr(arg->u.put.req));
|
|
||||||
snatch_needed = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* if this request is not chunked nor not length based,
|
|
||||||
* the state should be QSE_HTRE_COMPLETED. so only a
|
|
||||||
* chunked request should reach here */
|
|
||||||
QSE_ASSERT (arg->u.put.req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
|
|
||||||
|
|
||||||
qse_printf (QSE_T("WRITING 3 [%.*hs]\n"), (int)qse_htre_getcontentlen(arg->u.put.req), qse_htre_getcontentptr(arg->u.put.req));
|
|
||||||
#if 0
|
|
||||||
len = qse_htre_getcontentlen(arg->u.put.req);
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
ptr = qse_htre_getcontentptr(arg->u.put.req);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
snatch_needed = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snatch_needed)
|
if (write_file (httpd, file->u.put.handle, qse_htre_getcontentptr(arg->u.put.req), qse_htre_getcontentlen(arg->u.put.req)) <= -1)
|
||||||
|
{
|
||||||
|
httpd->opt.scb.file.close (httpd, file->u.put.handle);
|
||||||
|
file->u.put.status = 500;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(arg->u.put.req->state & QSE_HTRE_DISCARDED) &&
|
||||||
|
!(arg->u.put.req->state & QSE_HTRE_COMPLETED))
|
||||||
{
|
{
|
||||||
/* set up a callback to be called when the request content
|
/* set up a callback to be called when the request content
|
||||||
* is fed to the htrd reader. qse_htre_addcontent() that
|
* is fed to the htrd reader. qse_htre_addcontent() that
|
||||||
@ -470,16 +444,14 @@ qse_printf (QSE_T("WRITING 3 [%.*hs]\n"), (int)qse_htre_getcontentlen(arg->u.put
|
|||||||
* triggers in the task initializer. however the main task handler
|
* triggers in the task initializer. however the main task handler
|
||||||
* will be invoked so long as the client handle is writable by
|
* will be invoked so long as the client handle is writable by
|
||||||
* the main loop. */
|
* the main loop. */
|
||||||
|
|
||||||
task->ctx = file; /* switch the task context to the extension area */
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
/* since a new task can't be added in the initializer,
|
/* since a new task can't be added in the initializer,
|
||||||
* i mark that initialization failed and let task_main_putfile()
|
* i mark that initialization failed and let task_main_putfile()
|
||||||
* add an error task */
|
* add an error task */
|
||||||
|
qse_htre_discardcontent (arg->u.put.req);
|
||||||
file->u.put.flags |= PUTFILE_INIT_FAILED;
|
file->u.put.flags |= PUTFILE_INIT_FAILED;
|
||||||
task->ctx = file;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,37 +460,58 @@ static void task_fini_putfile (
|
|||||||
{
|
{
|
||||||
task_file_t* file = (task_file_t*)task->ctx;
|
task_file_t* file = (task_file_t*)task->ctx;
|
||||||
|
|
||||||
qse_printf (QSE_T("put fini....\n"));
|
|
||||||
if (!(file->u.put.flags & PUTFILE_INIT_FAILED))
|
if (!(file->u.put.flags & PUTFILE_INIT_FAILED))
|
||||||
httpd->opt.scb.file.close (httpd, file->u.put.handle);
|
httpd->opt.scb.file.close (httpd, file->u.put.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int task_main_putfile_2 (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
|
{
|
||||||
|
task_file_t* file = (task_file_t*)task->ctx;
|
||||||
|
|
||||||
|
if (file->u.put.req)
|
||||||
|
{
|
||||||
|
/* file->u.put.req is set to a non-NULL value if snatching
|
||||||
|
* is needed in the task_init_putfile(). and it's reset to
|
||||||
|
* QSE_NULL when snatching is over in putfile_snatch_client_input().
|
||||||
|
* i set a trigger so that the task is executed
|
||||||
|
* while there is input from the client side */
|
||||||
|
task->trigger[0].mask = QSE_HTTPD_TASK_TRIGGER_READ;
|
||||||
|
task->trigger[0].handle = client->handle;
|
||||||
|
return 1; /* trigger me when a client sends data */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* snatching is over. writing error may have occurred as well.
|
||||||
|
* file->u.put.status should hold a proper status code */
|
||||||
|
if (qse_httpd_entask_err (
|
||||||
|
httpd, client, task, file->u.put.status,
|
||||||
|
file->method, &file->version, file->keepalive) == QSE_NULL) return -1;
|
||||||
|
return 0; /* no more data to read. task over */
|
||||||
|
}
|
||||||
|
|
||||||
static int task_main_putfile (
|
static int task_main_putfile (
|
||||||
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_file_t* file = (task_file_t*)task->ctx;
|
task_file_t* file = (task_file_t*)task->ctx;
|
||||||
qse_printf (QSE_T("put main....\n"));
|
|
||||||
|
|
||||||
if (file->u.put.req)
|
if (!(file->u.put.flags & PUTFILE_INIT_FAILED) && file->u.put.req)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("put xxxxx....\n"));
|
/* initialization was successful and snatching is required.
|
||||||
/* still snatching the content body */
|
* switch to the next phase. */
|
||||||
task->trigger[0].mask = QSE_HTTPD_TASK_TRIGGER_READ;
|
task->main = task_main_putfile_2;
|
||||||
task->trigger[0].handle = client->handle;
|
return task_main_putfile_2 (httpd, client, task);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_printf (QSE_T("put what....\n"));
|
/* snatching is not required or initialization error has occurred.
|
||||||
return 0;
|
* file->u.put.status should hold a proper status code.
|
||||||
}
|
*
|
||||||
|
* note: if initialization error occurred and there is contents for the
|
||||||
/*------------------------------------------------------------------------*/
|
* client to send, this reply may get to the client before it finishes
|
||||||
|
* sending the contents. */
|
||||||
static QSE_INLINE int task_main_delfile (
|
if (qse_httpd_entask_err (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
httpd, client, task, file->u.put.status,
|
||||||
{
|
file->method, &file->version, file->keepalive) == QSE_NULL) return -1;
|
||||||
/* TODO: implement this */
|
return 0; /* task over */
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@ -549,6 +542,11 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
|||||||
|
|
||||||
switch (data.method)
|
switch (data.method)
|
||||||
{
|
{
|
||||||
|
case QSE_HTTP_OPTIONS:
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
|
return qse_httpd_entaskallow (httpd, client, pred,
|
||||||
|
QSE_MT("OPTIONS,GET,HEAD,POST,PUT,DELETE"), req);
|
||||||
|
|
||||||
case QSE_HTTP_HEAD:
|
case QSE_HTTP_HEAD:
|
||||||
case QSE_HTTP_GET:
|
case QSE_HTTP_GET:
|
||||||
case QSE_HTTP_POST:
|
case QSE_HTTP_POST:
|
||||||
@ -561,72 +559,84 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
|||||||
xtnsize += data.u.get.mime.len + 1;
|
xtnsize += data.u.get.mime.len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp = qse_htre_getheaderval(req, QSE_MT("If-None-Match"));
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||||
|
qse_mbsxcpy (data.u.get.if_none_match, QSE_COUNTOF(data.u.get.if_none_match), tmp->ptr);
|
||||||
|
}
|
||||||
|
if (data.u.get.if_none_match[0] == QSE_MT('\0'))
|
||||||
|
{
|
||||||
|
/* Both ETag and Last-Modified are included in the reply.
|
||||||
|
* If the client understand ETag, it can choose to include
|
||||||
|
* If-None-Match in the request. If it understands Last-Modified,
|
||||||
|
* it can choose to include If-Modified-Since. I don't care
|
||||||
|
* the client understands both and include both of them
|
||||||
|
* in the request.
|
||||||
|
*
|
||||||
|
* I check If-None-Match if it's included.
|
||||||
|
* I check If-Modified-Since if If-None-Match is not included.
|
||||||
|
*/
|
||||||
|
tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||||
|
if (qse_parsehttptime (tmp->ptr, &data.u.get.if_modified_since) <= -1)
|
||||||
|
{
|
||||||
|
data.u.get.if_modified_since.sec = 0;
|
||||||
|
data.u.get.if_modified_since.nsec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||||
|
if (qse_parsehttprange (tmp->ptr, &data.u.get.range) <= -1)
|
||||||
|
{
|
||||||
|
return qse_httpd_entaskerr (httpd, client, pred, 416, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.u.get.range.type = QSE_HTTP_RANGE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
task.init = task_init_getfile;
|
task.init = task_init_getfile;
|
||||||
task.main = task_main_getfile;
|
task.main = task_main_getfile;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSE_HTTP_PUT:
|
case QSE_HTTP_PUT:
|
||||||
|
/* note that no partial update is supported for PUT */
|
||||||
|
data.u.put.httpd = httpd;
|
||||||
data.u.put.req = req;
|
data.u.put.req = req;
|
||||||
task.init = task_init_putfile;
|
task.init = task_init_putfile;
|
||||||
task.main = task_main_putfile;
|
task.main = task_main_putfile;
|
||||||
task.fini = task_fini_putfile;
|
task.fini = task_fini_putfile;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case QSE_HTTP_DELETE:
|
case QSE_HTTP_DELETE:
|
||||||
task.main = task_main_delfile;
|
{
|
||||||
break;
|
int status = 200;
|
||||||
#endif
|
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
|
if (httpd->opt.scb.file.purge (httpd, path) <= -1)
|
||||||
|
{
|
||||||
|
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||||
|
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
return qse_httpd_entaskerr (httpd, client, pred, status, req);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Method not allowed */
|
/* Method not allowed */
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
while (tmp->next) tmp = tmp->next; /* get the last value */
|
|
||||||
if (qse_parsehttprange (tmp->ptr, &data.range) <= -1)
|
|
||||||
{
|
|
||||||
return qse_httpd_entaskerr (httpd, client, pred, 416, req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data.range.type = QSE_HTTP_RANGE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-None-Match"));
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
while (tmp->next) tmp = tmp->next; /* get the last value */
|
|
||||||
qse_mbsxcpy (data.if_none_match, QSE_COUNTOF(data.if_none_match), tmp->ptr);
|
|
||||||
}
|
|
||||||
if (data.if_none_match[0] == QSE_MT('\0'))
|
|
||||||
{
|
|
||||||
/* Both ETag and Last-Modified are included in the reply.
|
|
||||||
* If the client understand ETag, it can choose to include
|
|
||||||
* If-None-Match in the request. If it understands Last-Modified,
|
|
||||||
* it can choose to include If-Modified-Since. I don't care
|
|
||||||
* the client understands both and include both of them
|
|
||||||
* in the request.
|
|
||||||
*
|
|
||||||
* I check If-None-Match if it's included.
|
|
||||||
* I check If-Modified-Since if If-None-Match is not included.
|
|
||||||
*/
|
|
||||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
while (tmp->next) tmp = tmp->next; /* get the last value */
|
|
||||||
if (qse_parsehttptime (tmp->ptr, &data.if_modified_since) <= -1)
|
|
||||||
{
|
|
||||||
data.if_modified_since.sec = 0;
|
|
||||||
data.if_modified_since.nsec = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
return qse_httpd_entask (httpd, client, pred, &task, xtnsize);
|
return qse_httpd_entask (httpd, client, pred, &task, xtnsize);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ struct task_proxy_t
|
|||||||
qse_httpd_t* httpd;
|
qse_httpd_t* httpd;
|
||||||
|
|
||||||
const qse_mchar_t* host;
|
const qse_mchar_t* host;
|
||||||
|
|
||||||
|
int method;
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive; /* taken from the request */
|
int keepalive; /* taken from the request */
|
||||||
|
|
||||||
@ -714,6 +716,7 @@ static int task_init_proxy (
|
|||||||
QSE_MEMSET (proxy, 0, QSE_SIZEOF(*proxy));
|
QSE_MEMSET (proxy, 0, QSE_SIZEOF(*proxy));
|
||||||
proxy->httpd = httpd;
|
proxy->httpd = httpd;
|
||||||
|
|
||||||
|
proxy->method = qse_htre_getqmethodtype(arg->req);
|
||||||
proxy->version = *qse_htre_getversion(arg->req);
|
proxy->version = *qse_htre_getversion(arg->req);
|
||||||
proxy->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
proxy->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||||
proxy->peer.nwad = *arg->peer_nwad;
|
proxy->peer.nwad = *arg->peer_nwad;
|
||||||
@ -1356,7 +1359,7 @@ qse_printf (QSE_T("TRAILING DATA=%d, [%hs]\n"), (int)QSE_MBS_LEN(proxy->res), QS
|
|||||||
|
|
||||||
oops:
|
oops:
|
||||||
if (proxy->resflags & PROXY_RES_EVER_SENTBACK) return -1;
|
if (proxy->resflags & PROXY_RES_EVER_SENTBACK) return -1;
|
||||||
return (qse_httpd_entask_err (httpd, client, task, http_errnum, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
return (qse_httpd_entask_err (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int task_main_proxy_1 (
|
static int task_main_proxy_1 (
|
||||||
@ -1419,7 +1422,7 @@ static int task_main_proxy_1 (
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
return (qse_httpd_entask_err (httpd, client, task, http_errnum, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
return (qse_httpd_entask_err (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int task_main_proxy (
|
static int task_main_proxy (
|
||||||
@ -1509,7 +1512,7 @@ oops:
|
|||||||
|
|
||||||
return (qse_httpd_entask_err (
|
return (qse_httpd_entask_err (
|
||||||
httpd, client, task, http_errnum,
|
httpd, client, task, http_errnum,
|
||||||
&proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entaskproxy (
|
qse_httpd_task_t* qse_httpd_entaskproxy (
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
#include <qse/cmn/dir.h>
|
#include <qse/cmn/dir.h>
|
||||||
#include <qse/cmn/fio.h>
|
#include <qse/cmn/fio.h>
|
||||||
|
|
||||||
|
#define STAT_REG 1
|
||||||
|
#define STAT_DIR 2
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
# include <ws2tcpip.h> /* sockaddr_in6 */
|
# include <ws2tcpip.h> /* sockaddr_in6 */
|
||||||
@ -1250,7 +1253,7 @@ static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, const qse_ntime_t
|
|||||||
|
|
||||||
static int stat_file (
|
static int stat_file (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path,
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
qse_httpd_stat_t* hst, int regonly)
|
qse_httpd_stat_t* hst, int filter)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -1360,9 +1363,8 @@ static int stat_file (
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stating for a file. it should be a regular file.
|
if ((filter == STAT_REG && !S_ISREG(st.st_mode)) ||
|
||||||
* i don't allow other file types. */
|
(filter == STAT_DIR && !S_ISDIR(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;
|
||||||
@ -1397,8 +1399,47 @@ static int file_stat (
|
|||||||
/* this callback is not required to be a general stat function
|
/* this callback is not required to be a general stat function
|
||||||
* for a file. it is mainly used to get a file size and timestamps
|
* for a file. it is mainly used to get a file size and timestamps
|
||||||
* of a regular file. so it should fail for a non-regular file.
|
* of a regular file. so it should fail for a non-regular file.
|
||||||
* note that 1 passes 1 to stat_file for it */
|
* note that STAT_REG is passed to stat_file for it */
|
||||||
return stat_file (httpd, path, hst, 1);
|
return stat_file (httpd, path, hst, STAT_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_purge (qse_httpd_t* httpd, const qse_mchar_t* path)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (DeleteFileA (path) == FALSE)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(GetLastError()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__OS2__)
|
||||||
|
|
||||||
|
APIRET rc;
|
||||||
|
|
||||||
|
rc = DosDelete (path); /* TODO: is DosForceDelete better? */
|
||||||
|
if (rc != NO_ERROR)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__DOS__)
|
||||||
|
/* TODO: */
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (QSE_UNLINK (path) <= -1)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_ropen (
|
static int file_ropen (
|
||||||
@ -1503,6 +1544,90 @@ static qse_ssize_t file_write (
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static int dir_stat (
|
||||||
|
qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst)
|
||||||
|
{
|
||||||
|
/* this callback is not required to be a general stat function
|
||||||
|
* for a file. it is mainly used to get a file size and timestamps
|
||||||
|
* of a regular file. so it should fail for a non-regular file.
|
||||||
|
* note that STAT_REG is passed to stat_file for it */
|
||||||
|
return stat_file (httpd, path, hst, STAT_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dir_make (qse_httpd_t* httpd, const qse_mchar_t* path)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
if (CreateDirectoryA (path, QSE_NULL) == FALSE)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(GetLastError()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__OS2__)
|
||||||
|
|
||||||
|
APIRET rc;
|
||||||
|
|
||||||
|
rc = DosCreateDir (path, QSE_NULL); /* TODO: is DosForceDelete better? */
|
||||||
|
if (rc != NO_ERROR)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__DOS__)
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (QSE_MKDIR (path, 0755) <= -1)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dir_purge (qse_httpd_t* httpd, const qse_mchar_t* path)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (RemoveDirectoryA (path) == FALSE)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(GetLastError()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#elif defined(__OS2__)
|
||||||
|
|
||||||
|
APIRET rc;
|
||||||
|
|
||||||
|
rc = DosDeleteDir (path); /* TODO: is DosForceDelete better? */
|
||||||
|
if (rc != NO_ERROR)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__DOS__)
|
||||||
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (QSE_RMDIR (path) <= -1)
|
||||||
|
{
|
||||||
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct dir_t dir_t;
|
typedef struct dir_t dir_t;
|
||||||
struct dir_t
|
struct dir_t
|
||||||
{
|
{
|
||||||
@ -1868,6 +1993,19 @@ if (qse_htre_getcontentlen(req) > 0)
|
|||||||
* if you don't like this behavior, you must implement your own
|
* if you don't like this behavior, you must implement your own
|
||||||
* callback function for request handling. */
|
* callback function for request handling. */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* TODO support X-HTTP-Method-Override */
|
||||||
|
if (data.method == QSE_HTTP_POST)
|
||||||
|
{
|
||||||
|
tmp = qse_htre_getheaderval(req, QSE_MT("X-HTTP-Method-Override"));
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||||
|
data.method = qse_mbstohttpmethod (tmp->ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST &&
|
if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST &&
|
||||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||||
@ -1908,7 +2046,6 @@ if (qse_htre_getcontentlen(req) > 0)
|
|||||||
* discard the contents since i won't return them */
|
* discard the contents since i won't return them */
|
||||||
if (rsrc.type == QSE_HTTPD_RSRC_ERR)
|
if (rsrc.type == QSE_HTTPD_RSRC_ERR)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("DISCARD 3\n"));
|
|
||||||
qse_httpd_discardcontent (httpd, req);
|
qse_httpd_discardcontent (httpd, req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2122,6 +2259,7 @@ static qse_httpd_scb_t httpd_system_callbacks =
|
|||||||
|
|
||||||
/* file operation */
|
/* file operation */
|
||||||
{ file_stat,
|
{ file_stat,
|
||||||
|
file_purge,
|
||||||
file_ropen,
|
file_ropen,
|
||||||
file_wopen,
|
file_wopen,
|
||||||
file_close,
|
file_close,
|
||||||
@ -2130,7 +2268,10 @@ static qse_httpd_scb_t httpd_system_callbacks =
|
|||||||
},
|
},
|
||||||
|
|
||||||
/* directory operation */
|
/* directory operation */
|
||||||
{ dir_open,
|
{ dir_stat,
|
||||||
|
dir_make,
|
||||||
|
dir_purge,
|
||||||
|
dir_open,
|
||||||
dir_close,
|
dir_close,
|
||||||
dir_read
|
dir_read
|
||||||
},
|
},
|
||||||
@ -2418,7 +2559,7 @@ static int make_resource (
|
|||||||
struct rsrc_tmp_t tmp;
|
struct rsrc_tmp_t tmp;
|
||||||
|
|
||||||
qse_httpd_stat_t st;
|
qse_httpd_stat_t st;
|
||||||
int n, stx, method;
|
int n, stx, acc;
|
||||||
|
|
||||||
QSE_MEMSET (&tmp, 0, QSE_SIZEOF(tmp));
|
QSE_MEMSET (&tmp, 0, QSE_SIZEOF(tmp));
|
||||||
tmp.qpath = qse_htre_getqpath(req);
|
tmp.qpath = qse_htre_getqpath(req);
|
||||||
@ -2429,41 +2570,27 @@ static int make_resource (
|
|||||||
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
|
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
|
||||||
|
|
||||||
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1;
|
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1;
|
||||||
if (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_NWAD)
|
switch (tmp.root.type)
|
||||||
{
|
{
|
||||||
/* proxy the request */
|
case QSE_HTTPD_SERVERSTD_ROOT_NWAD:
|
||||||
target->type = QSE_HTTPD_RSRC_PROXY;
|
/* proxy the request */
|
||||||
/*target->u.proxy.dst = client->orgdst_addr;*/
|
target->type = QSE_HTTPD_RSRC_PROXY;
|
||||||
target->u.proxy.dst = tmp.root.u.nwad;
|
/*target->u.proxy.dst = client->orgdst_addr;*/
|
||||||
target->u.proxy.src = client->remote_addr;
|
target->u.proxy.dst = tmp.root.u.nwad;
|
||||||
|
target->u.proxy.src = client->remote_addr;
|
||||||
|
|
||||||
/* mark that this request is going to be proxied. */
|
/* mark that this request is going to be proxied. */
|
||||||
req->attr.flags |= QSE_HTRE_ATTR_PROXIED;
|
req->attr.flags |= QSE_HTRE_ATTR_PROXIED;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case QSE_HTTPD_SERVERSTD_ROOT_TEXT:
|
||||||
|
target->type = QSE_HTTPD_RSRC_TEXT;
|
||||||
|
target->u.text.ptr = tmp.root.u.text.ptr;
|
||||||
|
target->u.text.mime = tmp.root.u.text.mime;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle the request locally */
|
/* handle the request locally */
|
||||||
#if 0
|
|
||||||
method = qse_htre_getqmethodtype(req);
|
|
||||||
switch (method)
|
|
||||||
{
|
|
||||||
case QSE_HTTP_HEAD:
|
|
||||||
case QSE_HTTP_GET:
|
|
||||||
case QSE_HTTP_POST:
|
|
||||||
case QSE_HTTP_PUT:
|
|
||||||
case QSE_HTTP_DELETE:
|
|
||||||
case QSE_HTTP_OPTIONS:
|
|
||||||
/* let these methods be handled locally */
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* method not allowed */
|
|
||||||
target->type = QSE_HTTPD_RSRC_ERR;
|
|
||||||
target->u.err.code = 405;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QSE_ASSERT (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_PATH);
|
QSE_ASSERT (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_PATH);
|
||||||
|
|
||||||
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
|
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
|
||||||
@ -2543,6 +2670,7 @@ auth_ok:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Expectation Failed */
|
/* Expectation Failed */
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
target->type = QSE_HTTPD_RSRC_ERR;
|
target->type = QSE_HTTPD_RSRC_ERR;
|
||||||
target->u.err.code = 417;
|
target->u.err.code = 417;
|
||||||
return 0;
|
return 0;
|
||||||
@ -2611,8 +2739,9 @@ auth_ok:
|
|||||||
|
|
||||||
/* it is a directory - should i allow it? */
|
/* it is a directory - should i allow it? */
|
||||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRACC, &target->u.err.code) <= -1) target->u.err.code = 500;
|
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRACC, &target->u.err.code) <= -1) target->u.err.code = 500;
|
||||||
if (target->u.err.code != 200)
|
if (target->u.err.code < 200 || target->u.err.code > 299)
|
||||||
{
|
{
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
target->type = QSE_HTTPD_RSRC_ERR;
|
target->type = QSE_HTTPD_RSRC_ERR;
|
||||||
/* free xpath since it won't be used */
|
/* free xpath since it won't be used */
|
||||||
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
||||||
@ -2620,6 +2749,7 @@ auth_ok:
|
|||||||
else if (tmp.qpath[tmp.qpath_len - 1] != QSE_MT('/'))
|
else if (tmp.qpath[tmp.qpath_len - 1] != QSE_MT('/'))
|
||||||
{
|
{
|
||||||
/* the query path doesn't end with a slash. so redirect it */
|
/* the query path doesn't end with a slash. so redirect it */
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
target->type = QSE_HTTPD_RSRC_REDIR;
|
target->type = QSE_HTTPD_RSRC_REDIR;
|
||||||
target->u.redir.dst = tmp.qpath;
|
target->u.redir.dst = tmp.qpath;
|
||||||
/* free xpath since it won't be used */
|
/* free xpath since it won't be used */
|
||||||
@ -2651,11 +2781,16 @@ auth_ok:
|
|||||||
}
|
}
|
||||||
if (n >= 1) return 0;
|
if (n >= 1) return 0;
|
||||||
|
|
||||||
|
acc = (tmp.idxfile || !qse_mbsend(tmp.qpath, QSE_MT("/")))?
|
||||||
|
QSE_HTTPD_SERVERSTD_FILEACC: QSE_HTTPD_SERVERSTD_DIRACC;
|
||||||
|
|
||||||
/* check file's access permission */
|
/* check file's access permission */
|
||||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_FILEACC, &target->u.err.code) <= -1) target->u.err.code = 500;
|
if (server_xtn->query (httpd, client->server, req, tmp.xpath, acc, &target->u.err.code) <= -1) target->u.err.code = 500;
|
||||||
if (target->u.err.code != 200)
|
|
||||||
|
if (target->u.err.code < 200 || target->u.err.code > 299)
|
||||||
{
|
{
|
||||||
/* free xpath since it won't be used */
|
/* free xpath since it won't be used */
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
||||||
target->type = QSE_HTTPD_RSRC_ERR;
|
target->type = QSE_HTTPD_RSRC_ERR;
|
||||||
}
|
}
|
||||||
@ -2664,6 +2799,8 @@ auth_ok:
|
|||||||
/* fall back to a normal file. */
|
/* fall back to a normal file. */
|
||||||
if (tmp.idxfile)
|
if (tmp.idxfile)
|
||||||
{
|
{
|
||||||
|
qse_htre_discardcontent (req);
|
||||||
|
|
||||||
/* free xpath since it won't be used */
|
/* free xpath since it won't be used */
|
||||||
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
QSE_MMGR_FREE (httpd->mmgr, tmp.xpath);
|
||||||
|
|
||||||
@ -2672,6 +2809,11 @@ auth_ok:
|
|||||||
target->u.reloc.dst = merge_paths (httpd, tmp.qpath, tmp.idxfile);
|
target->u.reloc.dst = merge_paths (httpd, tmp.qpath, tmp.idxfile);
|
||||||
if (target->u.reloc.dst == QSE_NULL) return -1;
|
if (target->u.reloc.dst == QSE_NULL) return -1;
|
||||||
}
|
}
|
||||||
|
else if (acc == QSE_HTTPD_SERVERSTD_DIRACC)
|
||||||
|
{
|
||||||
|
target->type = QSE_HTTPD_RSRC_DIR;
|
||||||
|
target->u.dir.path = tmp.xpath;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
target->type = QSE_HTTPD_RSRC_FILE;
|
target->type = QSE_HTTPD_RSRC_FILE;
|
||||||
@ -2802,8 +2944,26 @@ static int query_server (
|
|||||||
|
|
||||||
case QSE_HTTPD_SERVERSTD_DIRACC:
|
case QSE_HTTPD_SERVERSTD_DIRACC:
|
||||||
case QSE_HTTPD_SERVERSTD_FILEACC:
|
case QSE_HTTPD_SERVERSTD_FILEACC:
|
||||||
*(int*)result = 200;
|
{
|
||||||
|
/* i don't allow PUT or DELET by default.
|
||||||
|
* override this query result if you want to change
|
||||||
|
* the behavior. */
|
||||||
|
switch (qse_htre_getqmethodtype(req))
|
||||||
|
{
|
||||||
|
case QSE_HTTP_OPTIONS:
|
||||||
|
case QSE_HTTP_HEAD:
|
||||||
|
case QSE_HTTP_GET:
|
||||||
|
case QSE_HTTP_POST:
|
||||||
|
*(int*)result = 200;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* method not allowed */
|
||||||
|
*(int*)result = 405;
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||||
|
@ -201,7 +201,8 @@ struct status_reloc_t
|
|||||||
static qse_httpd_task_t* entask_status (
|
static qse_httpd_task_t* entask_status (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred, int code, void* extra,
|
qse_httpd_task_t* pred, int code, void* extra,
|
||||||
const qse_http_version_t* version, int keepalive)
|
qse_http_method_t method, const qse_http_version_t* version,
|
||||||
|
int keepalive)
|
||||||
{
|
{
|
||||||
const qse_mchar_t* msg;
|
const qse_mchar_t* msg;
|
||||||
|
|
||||||
@ -209,34 +210,44 @@ static qse_httpd_task_t* entask_status (
|
|||||||
const qse_mchar_t* extrapst = QSE_MT("");
|
const qse_mchar_t* extrapst = QSE_MT("");
|
||||||
const qse_mchar_t* extraval = QSE_MT("");
|
const qse_mchar_t* extraval = QSE_MT("");
|
||||||
|
|
||||||
qse_mchar_t text[1024]; /* TODO: make this buffer dynamic or scalable */
|
qse_mchar_t text[1024] = QSE_MT(""); /* TODO: make this buffer dynamic or scalable */
|
||||||
|
|
||||||
msg = qse_httpstatustombs (code);
|
msg = qse_httpstatustombs (code);
|
||||||
if (code == 301 || code == 307)
|
switch (code)
|
||||||
{
|
{
|
||||||
status_reloc_t* reloc;
|
case 301:
|
||||||
|
case 307:
|
||||||
reloc = (status_reloc_t*)extra;
|
|
||||||
extrapre = QSE_MT("Location: ");
|
|
||||||
extrapst = reloc->redir? QSE_MT("/\r\n"): QSE_MT("\r\n");
|
|
||||||
extraval = reloc->dst;
|
|
||||||
|
|
||||||
text[0] = QSE_MT('\0');
|
|
||||||
}
|
|
||||||
else if (code == 304)
|
|
||||||
{
|
|
||||||
text[0] = QSE_MT('\0');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (httpd->opt.rcb.fmterr (httpd, client, code, text, QSE_COUNTOF(text)) <= -1) return QSE_NULL;
|
|
||||||
|
|
||||||
if (code == 401)
|
|
||||||
{
|
{
|
||||||
extrapre = QSE_MT("WWW-Authenticate: Basic realm=\"");
|
status_reloc_t* reloc;
|
||||||
extrapst = QSE_MT("\"\r\n");
|
reloc = (status_reloc_t*)extra;
|
||||||
extraval = (const qse_mchar_t*)extra;
|
extrapre = QSE_MT("Location: ");
|
||||||
|
extrapst = reloc->redir? QSE_MT("/\r\n"): QSE_MT("\r\n");
|
||||||
|
extraval = reloc->dst;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 304:
|
||||||
|
case 200:
|
||||||
|
case 201:
|
||||||
|
case 202:
|
||||||
|
case 203:
|
||||||
|
case 204:
|
||||||
|
case 205:
|
||||||
|
case 206:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (method != QSE_HTTP_HEAD &&
|
||||||
|
httpd->opt.rcb.fmterr (httpd, client, code, text, QSE_COUNTOF(text)) <= -1) return QSE_NULL;
|
||||||
|
|
||||||
|
if (code == 401)
|
||||||
|
{
|
||||||
|
extrapre = QSE_MT("WWW-Authenticate: Basic realm=\"");
|
||||||
|
extrapst = QSE_MT("\"\r\n");
|
||||||
|
extraval = (const qse_mchar_t*)extra;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return qse_httpd_entaskformat (
|
return qse_httpd_entaskformat (
|
||||||
@ -254,19 +265,21 @@ static qse_httpd_task_t* entask_status (
|
|||||||
qse_httpd_task_t* qse_httpd_entask_err (
|
qse_httpd_task_t* qse_httpd_entask_err (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred, int code,
|
qse_httpd_task_t* pred, int code,
|
||||||
const qse_http_version_t* version, int keepalive)
|
qse_http_method_t method, const qse_http_version_t* version, int keepalive)
|
||||||
{
|
{
|
||||||
return entask_status (httpd, client, pred, code, QSE_NULL, version, keepalive);
|
return entask_status (httpd, client, pred, code, QSE_NULL, method, version, keepalive);
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entaskerr (
|
qse_httpd_task_t* qse_httpd_entaskerr (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred, int code, qse_htre_t* req)
|
qse_httpd_task_t* pred, int code, qse_htre_t* req)
|
||||||
{
|
{
|
||||||
qse_htre_discardcontent (req);
|
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, code, QSE_NULL,
|
httpd, client, pred, code, QSE_NULL,
|
||||||
qse_htre_getversion(req), (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
qse_htre_getqmethodtype(req),
|
||||||
|
qse_htre_getversion(req),
|
||||||
|
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@ -289,6 +302,7 @@ qse_httpd_task_t* qse_httpd_entaskauth (
|
|||||||
{
|
{
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, 401, (void*)realm,
|
httpd, client, pred, 401, (void*)realm,
|
||||||
|
qse_htre_getqmethodtype(req),
|
||||||
qse_htre_getversion(req),
|
qse_htre_getversion(req),
|
||||||
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||||
}
|
}
|
||||||
@ -296,21 +310,6 @@ qse_httpd_task_t* qse_httpd_entaskauth (
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
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_task_t* qse_httpd_entaskreloc (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
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* pred, const qse_mchar_t* dst, qse_htre_t* req)
|
||||||
@ -322,25 +321,11 @@ qse_httpd_task_t* qse_httpd_entaskreloc (
|
|||||||
|
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, 301, (void*)&reloc,
|
httpd, client, pred, 301, (void*)&reloc,
|
||||||
|
qse_htre_getqmethodtype(req),
|
||||||
qse_htre_getversion(req),
|
qse_htre_getversion(req),
|
||||||
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
(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_task_t* qse_httpd_entaskredir (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
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* pred, const qse_mchar_t* dst, qse_htre_t* req)
|
||||||
@ -352,6 +337,7 @@ qse_httpd_task_t* qse_httpd_entaskredir (
|
|||||||
|
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, 301, (void*)&reloc,
|
httpd, client, pred, 301, (void*)&reloc,
|
||||||
|
qse_htre_getqmethodtype(req),
|
||||||
qse_htre_getversion(req),
|
qse_htre_getversion(req),
|
||||||
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||||
}
|
}
|
||||||
@ -359,12 +345,11 @@ qse_httpd_task_t* qse_httpd_entaskredir (
|
|||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entask_nomod (
|
qse_httpd_task_t* qse_httpd_entask_nomod (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred,
|
||||||
qse_httpd_task_t* pred, const qse_http_version_t* version, int keepalive)
|
qse_http_method_t method, const qse_http_version_t* version, int keepalive)
|
||||||
{
|
{
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, 304,
|
httpd, client, pred, 304, QSE_NULL, method, version, keepalive);
|
||||||
QSE_NULL, version, keepalive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entasknomod (
|
qse_httpd_task_t* qse_httpd_entasknomod (
|
||||||
@ -372,13 +357,39 @@ qse_httpd_task_t* qse_httpd_entasknomod (
|
|||||||
qse_httpd_task_t* pred, qse_htre_t* req)
|
qse_httpd_task_t* pred, qse_htre_t* req)
|
||||||
{
|
{
|
||||||
return entask_status (
|
return entask_status (
|
||||||
httpd, client, pred, 304,
|
httpd, client, pred, 304, QSE_NULL,
|
||||||
QSE_NULL, qse_htre_getversion(req),
|
qse_htre_getqmethodtype(req),
|
||||||
|
qse_htre_getversion(req),
|
||||||
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
qse_httpd_task_t* qse_httpd_entaskallow (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
|
qse_httpd_task_t* pred, const qse_mchar_t* allow, qse_htre_t* req)
|
||||||
|
{
|
||||||
|
int code = 200;
|
||||||
|
const qse_mchar_t* msg;
|
||||||
|
const qse_http_version_t* version;
|
||||||
|
int keepalive;
|
||||||
|
|
||||||
|
msg = qse_httpstatustombs (code);
|
||||||
|
version = qse_htre_getversion(req);
|
||||||
|
keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||||
|
return qse_httpd_entaskformat (
|
||||||
|
httpd, client, pred,
|
||||||
|
QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nAllow: %s\r\nContent-Length: 0\r\n\r\n"),
|
||||||
|
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")),
|
||||||
|
allow
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
qse_httpd_task_t* qse_httpd_entaskconnect (
|
qse_httpd_task_t* qse_httpd_entaskconnect (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
|
@ -63,31 +63,6 @@ static int task_main_text (
|
|||||||
return 1; /* more work to do */
|
return 1; /* more work to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entask_text (
|
|
||||||
qse_httpd_t* httpd,
|
|
||||||
qse_httpd_client_t* client,
|
|
||||||
qse_httpd_task_t* pred,
|
|
||||||
const qse_mchar_t* ptr,
|
|
||||||
qse_size_t len)
|
|
||||||
{
|
|
||||||
qse_httpd_task_t task;
|
|
||||||
task_text_t data;
|
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
|
||||||
data.ptr = ptr;
|
|
||||||
data.left = len;
|
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
|
||||||
task.init = task_init_text;
|
|
||||||
task.main = task_main_text;
|
|
||||||
task.ctx = &data;
|
|
||||||
|
|
||||||
return qse_httpd_entask (
|
|
||||||
httpd, client, pred,
|
|
||||||
&task, QSE_SIZEOF(data) + data.left);
|
|
||||||
}
|
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entasktext (
|
qse_httpd_task_t* qse_httpd_entasktext (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
@ -98,13 +73,33 @@ qse_httpd_task_t* qse_httpd_entasktext (
|
|||||||
{
|
{
|
||||||
qse_size_t tlen;
|
qse_size_t tlen;
|
||||||
qse_mchar_t b_tlen[64];
|
qse_mchar_t b_tlen[64];
|
||||||
|
qse_http_method_t method;
|
||||||
qse_http_version_t* version;
|
qse_http_version_t* version;
|
||||||
|
|
||||||
|
qse_httpd_task_t task;
|
||||||
|
task_text_t data;
|
||||||
|
|
||||||
|
method = qse_htre_getqmethodtype (req);
|
||||||
version = qse_htre_getversion (req);
|
version = qse_htre_getversion (req);
|
||||||
|
|
||||||
tlen = qse_mbslen(text);
|
qse_htre_discardcontent (req);
|
||||||
qse_fmtuintmaxtombs (b_tlen, QSE_COUNTOF(b_tlen), tlen, 10, -1, QSE_MT('\0'), QSE_NULL);
|
switch (method)
|
||||||
|
{
|
||||||
|
case QSE_HTTP_HEAD:
|
||||||
|
tlen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QSE_HTTP_GET:
|
||||||
|
case QSE_HTTP_POST:
|
||||||
|
tlen = qse_mbslen(text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Method not allowed */
|
||||||
|
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
qse_fmtuintmaxtombs (b_tlen, QSE_COUNTOF(b_tlen), tlen, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
pred = qse_httpd_entaskformat (
|
pred = qse_httpd_entaskformat (
|
||||||
httpd, client, pred,
|
httpd, client, pred,
|
||||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: %s\r\nContent-Length: %s\r\n\r\n"),
|
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: %s\r\nContent-Length: %s\r\n\r\n"),
|
||||||
@ -116,5 +111,14 @@ qse_httpd_task_t* qse_httpd_entasktext (
|
|||||||
);
|
);
|
||||||
if (pred == QSE_NULL) return QSE_NULL;
|
if (pred == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
return qse_httpd_entask_text (httpd, client, pred, text, tlen);
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
|
data.ptr = text;
|
||||||
|
data.left = tlen;
|
||||||
|
|
||||||
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
|
task.init = task_init_text;
|
||||||
|
task.main = task_main_text;
|
||||||
|
task.ctx = &data;
|
||||||
|
|
||||||
|
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.left);
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ qse_httpd_task_t* qse_httpd_entask_err (
|
|||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred,
|
qse_httpd_task_t* pred,
|
||||||
int code,
|
int code,
|
||||||
|
qse_http_method_t method,
|
||||||
const qse_http_version_t* version,
|
const qse_http_version_t* version,
|
||||||
int keepalive
|
int keepalive
|
||||||
);
|
);
|
||||||
@ -129,37 +130,11 @@ qse_httpd_task_t* qse_httpd_entask_nomod (
|
|||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* pred,
|
qse_httpd_task_t* pred,
|
||||||
|
qse_http_method_t method,
|
||||||
const qse_http_version_t* version,
|
const qse_http_version_t* version,
|
||||||
int keepalive
|
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,
|
|
||||||
qse_httpd_task_t* pred,
|
|
||||||
const qse_mchar_t* ptr,
|
|
||||||
qse_size_t len
|
|
||||||
);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user