improved httpd
This commit is contained in:
parent
99f1b5453b
commit
fdba865863
@ -65,6 +65,8 @@ enum qse_httpd_option_t
|
||||
typedef struct qse_httpd_stat_t qse_httpd_stat_t;
|
||||
struct qse_httpd_stat_t
|
||||
{
|
||||
qse_long_t dev;
|
||||
qse_long_t ino;
|
||||
qse_foff_t size;
|
||||
qse_ntime_t mtime;
|
||||
const qse_mchar_t* mime;
|
||||
@ -556,14 +558,9 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_mchar_t* path,
|
||||
qse_htre_t* req
|
||||
);
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entasknph (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_mchar_t* path,
|
||||
const qse_mchar_t* script,
|
||||
const qse_mchar_t* suffix,
|
||||
int nph,
|
||||
qse_htre_t* req
|
||||
);
|
||||
|
||||
|
@ -64,39 +64,39 @@
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#if defined(SYS_open)
|
||||
#if defined(SYS_open) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_OPEN(path,flags,mode) syscall(SYS_open,path,flags,mode)
|
||||
#else
|
||||
# define QSE_OPEN(path,flags,mode) open(path,flags,mode)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_close)
|
||||
#if defined(SYS_close) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_CLOSE(handle) syscall(SYS_close,handle)
|
||||
#else
|
||||
# define QSE_CLOSE(handle) close(handle)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_read)
|
||||
#if defined(SYS_read) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_READ(handle,buf,size) syscall(SYS_read,handle,buf,size)
|
||||
#else
|
||||
# define QSE_READ(handle,buf,size) read(handle,buf,size)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_write)
|
||||
#if defined(SYS_write) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_WRITE(handle,buf,size) syscall(SYS_write,handle,buf,size)
|
||||
#else
|
||||
# define QSE_WRITE(handle,buf,size) write(handle,buf,size)
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS__llseek)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS__llseek) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LLSEEK(handle,hoffset,loffset,out,whence) syscall(SYS__llseek,handle,hoffset,loffset,out,whence)
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE__LLSEEK)
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE__LLSEEK) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LLSEEK(handle,hoffset,loffset,out,whence) _llseek(handle,hoffset,loffset,out,whence)
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_lseek64)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_lseek64) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LSEEK(handle,offset,whence) syscall(SYS_lseek64,handle,offset,whence)
|
||||
#elif defined(SYS_lseek)
|
||||
#elif defined(SYS_lseek) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LSEEK(handle,offset,whence) syscall(SYS_lseek,handle,offset,whence)
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSEEK64)
|
||||
# define QSE_LSEEK(handle,offset,whence) lseek64(handle,offset,whence)
|
||||
@ -104,10 +104,10 @@
|
||||
# define QSE_LSEEK(handle,offset,whence) lseek(handle,offset,whence)
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_fstat64)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_fstat64) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat64,handle,stbuf)
|
||||
typedef struct stat64 qse_fstat_t;
|
||||
#elif defined(SYS_fstat)
|
||||
#elif defined(SYS_fstat) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat,handle,stbuf)
|
||||
typedef struct stat qse_fstat_t;
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTAT64)
|
||||
@ -118,9 +118,9 @@
|
||||
typedef struct stat qse_fstat_t;
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_ftruncate64)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_ftruncate64) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FTRUNCATE(handle,size) syscall(SYS_ftruncate64,handle,size)
|
||||
#elif defined(SYS_ftruncate)
|
||||
#elif defined(SYS_ftruncate) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FTRUNCATE(handle,size) syscall(SYS_ftruncate,handle,size)
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FTRUNCATE64)
|
||||
# define QSE_FTRUNCATE(handle,size) ftruncate64(handle,size)
|
||||
@ -128,127 +128,127 @@
|
||||
# define QSE_FTRUNCATE(handle,size) ftruncate(handle,size)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_fchmod)
|
||||
#if defined(SYS_fchmod) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FCHMOD(handle,mode) syscall(SYS_fchmod,handle,mode)
|
||||
#else
|
||||
# define QSE_FCHMOD(handle,mode) fchmod(handle,mode)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_fchown)
|
||||
#if defined(SYS_fchown) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FCHOWN(handle,owner,group) syscall(SYS_fchown,handle,owner,group)
|
||||
#else
|
||||
# define QSE_FCHOWN(handle,owner,group) fchown(handle,owner,group)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_fsync)
|
||||
#if defined(SYS_fsync) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FSYNC(handle) syscall(SYS_fsync,handle)
|
||||
#else
|
||||
# define QSE_FSYNC(handle) fsync(handle)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_fcntl)
|
||||
#if defined(SYS_fcntl) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FCNTL(handle,cmd,arg) syscall(SYS_fcntl,handle,cmd,arg)
|
||||
#else
|
||||
# define QSE_FCNTL(handle,cmd,arg) fcntl(handle,cmd,arg)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_dup2)
|
||||
#if defined(SYS_dup2) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_DUP2(ofd,nfd) syscall(SYS_dup2,ofd,nfd)
|
||||
#else
|
||||
# define QSE_DUP2(ofd,nfd) dup2(ofd,nfd)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_pipe)
|
||||
#if defined(SYS_pipe) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_PIPE(pfds) syscall(SYS_pipe,pfds)
|
||||
#else
|
||||
# define QSE_PIPE(pfds) pipe(pfds)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_exit)
|
||||
#if defined(SYS_exit) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_EXIT(code) syscall(SYS_exit,code)
|
||||
#else
|
||||
# define QSE_EXIT(code) _exit(code)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_fork)
|
||||
#if defined(SYS_fork) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_FORK() syscall(SYS_fork)
|
||||
#else
|
||||
# define QSE_FORK() fork()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_vfork)
|
||||
#if defined(SYS_vfork) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_VFORK() syscall(SYS_vfork)
|
||||
#else
|
||||
# define QSE_VFORK() vfork()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_execve)
|
||||
#if defined(SYS_execve) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_EXECVE(path,argv,envp) syscall(SYS_execve,path,argv,envp)
|
||||
#else
|
||||
# define QSE_EXECVE(path,argv,envp) execve(path,argv,envp)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_waitpid)
|
||||
#if defined(SYS_waitpid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_WAITPID(pid,status,options) syscall(SYS_waitpid,pid,status,options)
|
||||
#else
|
||||
# define QSE_WAITPID(pid,status,options) waitpid(pid,status,options)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_kill)
|
||||
#if defined(SYS_kill) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_KILL(pid,sig) syscall(SYS_kill,pid,sig)
|
||||
#else
|
||||
# define QSE_KILL(pid,sig) kill(pid,sig)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_getpid)
|
||||
#if defined(SYS_getpid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETPID() syscall(SYS_getpid)
|
||||
#else
|
||||
# define QSE_GETPID() getpid()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_getuid)
|
||||
#if defined(SYS_getuid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETUID() syscall(SYS_getuid)
|
||||
#else
|
||||
# define QSE_GETUID() getuid()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_geteuid)
|
||||
#if defined(SYS_geteuid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETEUID() syscall(SYS_geteuid)
|
||||
#else
|
||||
# define QSE_GETEUID() geteuid()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_getgid)
|
||||
#if defined(SYS_getgid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETGID() syscall(SYS_getgid)
|
||||
#else
|
||||
# define QSE_GETGID() getgid()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_getegid)
|
||||
#if defined(SYS_getegid) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETEGID() syscall(SYS_getegid)
|
||||
#else
|
||||
# define QSE_GETEGID() getegid()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_gettimeofday)
|
||||
#if defined(SYS_gettimeofday) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETTIMEOFDAY(tv,tz) syscall(SYS_gettimeofday,tv,tz)
|
||||
#else
|
||||
# define QSE_GETTIMEOFDAY(tv,tz) gettimeofday(tv,tz)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_settimeofday)
|
||||
#if defined(SYS_settimeofday) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_SETTIMEOFDAY(tv,tz) syscall(SYS_settimeofday,tv,tz)
|
||||
#else
|
||||
# define QSE_SETTIMEOFDAY(tv,tz) settimeofday(tv,tz)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_getrlimit)
|
||||
#if defined(SYS_getrlimit) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_GETRLIMIT(res,lim) syscall(SYS_getrlimit,res,lim)
|
||||
#else
|
||||
# define QSE_GETRLIMIT(res,lim) getrlimit(res,lim)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_setrlimit)
|
||||
#if defined(SYS_setrlimit) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_SETRLIMIT(res,lim) syscall(SYS_setrlimit,res,lim)
|
||||
#else
|
||||
# define QSE_SETRLIMIT(res,lim) setrlimit(res,lim)
|
||||
@ -257,40 +257,40 @@
|
||||
|
||||
/* ===== FILE SYSTEM CALLS ===== */
|
||||
|
||||
#if defined(SYS_chmod)
|
||||
#if defined(SYS_chmod) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_CHMOD(path,mode) syscall(SYS_chmod,path,mode)
|
||||
#else
|
||||
# define QSE_CHMOD(path,mode) chmod(path,mode)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_chown)
|
||||
#if defined(SYS_chown) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_CHOWN(path,owner,group) syscall(SYS_chown,path,owner,group)
|
||||
#else
|
||||
# define QSE_CHOWN(path,owner,group) chown(path,owner,group)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_chroot)
|
||||
#if defined(SYS_chroot) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_CHROOT(path) syscall(SYS_chroot,path)
|
||||
#else
|
||||
# define QSE_CHROOT(path) chroot(path)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_lchown)
|
||||
#if defined(SYS_lchown) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LCHOWN(path,owner,group) syscall(SYS_lchown,path,owner,group)
|
||||
#else
|
||||
# define QSE_LCHOWN(path,owner,group) lchown(path,owner,group)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_link)
|
||||
#if defined(SYS_link) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LINK(oldpath,newpath) syscall(SYS_link,oldpath,newpath)
|
||||
#else
|
||||
# define QSE_LINK(oldpath,newpath) link(oldpath,newpath)
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_lstat64)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_lstat64) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LSTAT(path,stbuf) syscall(SYS_lstat,path,stbuf)
|
||||
typedef struct stat64 qse_lstat_t;
|
||||
#elif defined(SYS_lstat)
|
||||
#elif defined(SYS_lstat) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_LSTAT(path,stbuf) syscall(SYS_lstat,path,stbuf)
|
||||
typedef struct stat qse_lstat_t;
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSTAT64)
|
||||
@ -301,29 +301,29 @@
|
||||
typedef struct stat qse_lstat_t;
|
||||
#endif
|
||||
|
||||
#if defined(SYS_access)
|
||||
#if defined(SYS_access) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_ACCESS(path,mode) syscall(SYS_access,path,mode)
|
||||
#else
|
||||
# define QSE_ACCESS(path,mode) access(path,mode)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_rename)
|
||||
#if defined(SYS_rename) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath)
|
||||
#else
|
||||
int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */
|
||||
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_rmdir)
|
||||
#if defined(SYS_rmdir) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_RMDIR(path) syscall(SYS_rmdir,path)
|
||||
#else
|
||||
# define QSE_RMDIR(path) rmdir(path)
|
||||
#endif
|
||||
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_stat64)
|
||||
#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_stat64) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_STAT(path,stbuf) syscall(SYS_stat64,path,stbuf)
|
||||
typedef struct stat64 qse_stat_t;
|
||||
#elif defined(SYS_stat)
|
||||
#elif defined(SYS_stat) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_STAT(path,stbuf) syscall(SYS_stat,path,stbuf)
|
||||
typedef struct stat qse_stat_t;
|
||||
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_STAT64)
|
||||
@ -334,25 +334,25 @@
|
||||
typedef struct stat qse_stat_t;
|
||||
#endif
|
||||
|
||||
#if defined(SYS_symlink)
|
||||
#if defined(SYS_symlink) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_SYMLINK(oldpath,newpath) syscall(SYS_symlink,oldpath,newpath)
|
||||
#else
|
||||
# define QSE_SYMLINK(oldpath,newpath) symlink(oldpath,newpath)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_unlink)
|
||||
#if defined(SYS_unlink) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_UNLINK(path) syscall(SYS_unlink,path)
|
||||
#else
|
||||
# define QSE_UNLINK(path) unlink(path)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_utime)
|
||||
#if defined(SYS_utime) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_UTIME(path,t) syscall(SYS_utime,path,t)
|
||||
#else
|
||||
# define QSE_UTIME(path,t) utime(path,t)
|
||||
#endif
|
||||
|
||||
#if defined(SYS_utimes)
|
||||
#if defined(SYS_utimes) && defined(QSE_USE_SYSCALL)
|
||||
# define QSE_UTIMES(path,t) syscall(SYS_utimes,path,t)
|
||||
#else
|
||||
# define QSE_UTIMES(path,t) utimes(path,t)
|
||||
|
@ -18,11 +18,6 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
|
||||
/* UNSUPPORTED YET.. */
|
||||
/* TODO: IMPLEMENT THIS */
|
||||
#else
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem.h"
|
||||
#include <qse/cmn/str.h>
|
||||
@ -34,9 +29,11 @@
|
||||
typedef struct task_cgi_arg_t task_cgi_arg_t;
|
||||
struct task_cgi_arg_t
|
||||
{
|
||||
const qse_mchar_t* path;
|
||||
qse_htre_t* req;
|
||||
qse_mcstr_t path;
|
||||
qse_mcstr_t script;
|
||||
qse_mcstr_t suffix;
|
||||
int nph;
|
||||
qse_htre_t* req;
|
||||
};
|
||||
|
||||
typedef struct task_cgi_t task_cgi_t;
|
||||
@ -46,6 +43,8 @@ struct task_cgi_t
|
||||
qse_httpd_t* httpd;
|
||||
|
||||
const qse_mchar_t* path;
|
||||
const qse_mchar_t* script;
|
||||
const qse_mchar_t* suffix;
|
||||
qse_http_version_t version;
|
||||
int keepalive; /* taken from the request */
|
||||
int nph;
|
||||
@ -407,8 +406,13 @@ static qse_htrd_recbs_t cgi_script_htrd_cbs =
|
||||
|
||||
static int cgi_add_env (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_env_t* env, qse_htre_t* req, const
|
||||
qse_mchar_t* path, qse_size_t length, int chunked)
|
||||
qse_env_t* env, qse_htre_t* req,
|
||||
const qse_mchar_t* path,
|
||||
const qse_mchar_t* script,
|
||||
const qse_mchar_t* suffix,
|
||||
const qse_mchar_t* content_type,
|
||||
qse_size_t content_length,
|
||||
int chunked)
|
||||
{
|
||||
/* TODO: error check */
|
||||
cgi_client_req_hdr_ctx_t ctx;
|
||||
@ -430,22 +434,21 @@ static int cgi_add_env (
|
||||
snprintf (buf, QSE_COUNTOF(buf), QSE_MT("HTTP/%d.%d"), (int)v->major, (int)v->minor);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), buf);
|
||||
|
||||
{
|
||||
qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path);
|
||||
qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), script);
|
||||
if (suffix && suffix[0] != QSE_MT('\0'))
|
||||
qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix);
|
||||
|
||||
/* TODO: corrent all these name??? */
|
||||
//qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), qse_htre_getqpath(req));
|
||||
//qse_env_insertmbs (env, QSE_MT("PATH_INFO"), qse_htre_getqpath(req));
|
||||
//qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), qse_htre_getqpath(req));
|
||||
//qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), QSE_MT("/"));
|
||||
}
|
||||
|
||||
|
||||
//qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path);
|
||||
qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req));
|
||||
qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req));
|
||||
if (qparam) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), qparam);
|
||||
|
||||
qse_fmtuintmaxtombs (buf, QSE_COUNTOF(buf), length, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_fmtuintmaxtombs (buf, QSE_COUNTOF(buf), content_length, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), buf);
|
||||
if (content_type) qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), content_type);
|
||||
|
||||
if (chunked) qse_env_insertmbs (env, QSE_MT("TRANSFER_ENCODING"), QSE_MT("chunked"));
|
||||
|
||||
@ -459,6 +462,7 @@ static int cgi_add_env (
|
||||
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf);
|
||||
|
||||
#if 0
|
||||
//qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), QSE_MT("/"));
|
||||
qse_env_insertmbs (env, "SERVER_NAME",
|
||||
qse_env_insertmbs (env, "SERVER_ROOT",
|
||||
qse_env_insertmbs (env, "DOCUMENT_ROOT",
|
||||
@ -680,7 +684,8 @@ static int task_init_cgi (
|
||||
qse_size_t content_length;
|
||||
qse_size_t len;
|
||||
const qse_mchar_t* ptr;
|
||||
|
||||
const qse_htre_hdrval_t* tmp;
|
||||
|
||||
cgi = (task_cgi_t*)qse_httpd_gettaskxtn (httpd, task);
|
||||
arg = (task_cgi_arg_t*)task->ctx;
|
||||
|
||||
@ -692,8 +697,13 @@ static int task_init_cgi (
|
||||
QSE_MEMSET (cgi, 0, QSE_SIZEOF(*cgi));
|
||||
cgi->httpd = httpd;
|
||||
|
||||
qse_mbscpy ((qse_mchar_t*)(cgi + 1), arg->path);
|
||||
cgi->path = (qse_mchar_t*)(cgi + 1);
|
||||
cgi->script = cgi->path + arg->path.len + 1;
|
||||
cgi->suffix = cgi->script + arg->script.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)cgi->path, arg->path.ptr);
|
||||
qse_mbscpy ((qse_mchar_t*)cgi->script, arg->script.ptr);
|
||||
qse_mbscpy ((qse_mchar_t*)cgi->suffix, arg->suffix.ptr);
|
||||
|
||||
cgi->version = *qse_htre_getversion(arg->req);
|
||||
cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||
cgi->nph = arg->nph;
|
||||
@ -826,8 +836,14 @@ done:
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* get the content type header value */
|
||||
tmp = qse_htre_getheaderval(arg->req, QSE_MT("Content-Type"));
|
||||
if (tmp) while (tmp->next) tmp = tmp->next; /* get the last value */
|
||||
|
||||
if (cgi_add_env (
|
||||
httpd, client, cgi->env, arg->req, arg->path, content_length,
|
||||
httpd, client, cgi->env, arg->req,
|
||||
cgi->path, cgi->script, cgi->suffix,
|
||||
(tmp? tmp->ptr: QSE_NULL), content_length,
|
||||
(cgi->reqflags & CGI_REQ_FWDCHUNKED)) <= -1)
|
||||
{
|
||||
goto oops;
|
||||
@ -1434,15 +1450,28 @@ oops:
|
||||
* non-blocking pio read ...
|
||||
*/
|
||||
|
||||
static QSE_INLINE qse_httpd_task_t* entask_cgi (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* path,
|
||||
qse_htre_t* req, int nph)
|
||||
qse_httpd_task_t* qse_httpd_entaskcgi (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_mchar_t* path,
|
||||
const qse_mchar_t* script,
|
||||
const qse_mchar_t* suffix,
|
||||
int nph,
|
||||
qse_htre_t* req)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_cgi_arg_t arg;
|
||||
|
||||
arg.path = path;
|
||||
if (script == QSE_NULL) script = qse_htre_getqpath(req);
|
||||
if (suffix == QSE_NULL) suffix = QSE_MT("");
|
||||
|
||||
arg.path.ptr = path;
|
||||
arg.path.len = qse_mbslen(path);
|
||||
arg.script.ptr = script;
|
||||
arg.script.len = qse_mbslen(script);
|
||||
arg.suffix.ptr = suffix;
|
||||
arg.suffix.len = qse_mbslen(suffix);
|
||||
arg.req = req;
|
||||
arg.nph = nph;
|
||||
|
||||
@ -1454,22 +1483,10 @@ static QSE_INLINE qse_httpd_task_t* entask_cgi (
|
||||
|
||||
return qse_httpd_entask (
|
||||
httpd, client, pred, &task,
|
||||
QSE_SIZEOF(task_cgi_t) + ((qse_mbslen(path) + 1) * QSE_SIZEOF(*path))
|
||||
QSE_SIZEOF(task_cgi_t) +
|
||||
((arg.path.len + 1) * QSE_SIZEOF(*path)) +
|
||||
((arg.script.len + 1) * QSE_SIZEOF(*script)) +
|
||||
((arg.suffix.len + 1) * QSE_SIZEOF(*suffix))
|
||||
);
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskcgi (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req)
|
||||
{
|
||||
return entask_cgi (httpd, client, pred, path, req, 0);
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entasknph (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req)
|
||||
{
|
||||
return entask_cgi (httpd, client, pred, path, req, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,11 +27,14 @@
|
||||
#include <qse/cmn/time.h>
|
||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||
|
||||
#define ETAG_LEN_MAX 127
|
||||
|
||||
typedef struct task_file_t task_file_t;
|
||||
struct task_file_t
|
||||
{
|
||||
const qse_mchar_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;
|
||||
int keepalive;
|
||||
@ -178,6 +181,8 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
if (file->range.type != QSE_HTTP_RANGE_NONE)
|
||||
{
|
||||
qse_mchar_t tmp[4][64];
|
||||
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
||||
qse_size_t etag_len;
|
||||
|
||||
if (file->range.type == QSE_HTTP_RANGE_SUFFIX)
|
||||
{
|
||||
@ -201,9 +206,17 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
qse_fmtuintmaxtombs (tmp[2], QSE_COUNTOF(tmp[2]), file->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);
|
||||
|
||||
etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag) - etag_len, st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.size, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.ino, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
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);
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 206 Partial Content\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nContent-Range: bytes %s-%s/%s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\n\r\n"),
|
||||
QSE_MT("HTTP/%d.%d 206 Partial Content\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nContent-Range: bytes %s-%s/%s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\nETag: %s\r\n\r\n"),
|
||||
file->version.major, file->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
@ -211,7 +224,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
(st.mime? QSE_MT("Content-Type: "): QSE_MT("")),
|
||||
(st.mime? st.mime: QSE_MT("")),
|
||||
(st.mime? QSE_MT("\r\n"): QSE_MT("")),
|
||||
tmp[0], tmp[1], tmp[2], tmp[3]
|
||||
tmp[0], tmp[1], tmp[2], tmp[3], etag
|
||||
);
|
||||
if (x)
|
||||
{
|
||||
@ -226,13 +239,24 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
else
|
||||
{
|
||||
qse_mchar_t b_fsize[64];
|
||||
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
||||
qse_size_t etag_len;
|
||||
|
||||
if (file->if_modified_since > 0 &&
|
||||
QSE_MSEC_TO_SEC(st.mtime) <= QSE_MSEC_TO_SEC(file->if_modified_since))
|
||||
etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag) - etag_len, st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.size, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.ino, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
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);
|
||||
|
||||
if ((file->if_none_match[0] != QSE_MT('\0') && qse_mbscmp (etag, file->if_none_match) == 0) ||
|
||||
(file->if_modified_since > 0 && QSE_MSEC_TO_SEC(st.mtime) <= QSE_MSEC_TO_SEC(file->if_modified_since)))
|
||||
{
|
||||
/* i've converted milliseconds to seconds before comparison
|
||||
/* i've converted milliseconds to seconds before timestamp comparison
|
||||
* because st.mtime has the actual milliseconds less than 1 second
|
||||
* while if_modified_since doesn't have such small milliseconds */
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 304 Not Modified\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Length: 0\r\n\r\n"),
|
||||
@ -252,7 +276,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\n\r\n"),
|
||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\nETag: %s\r\n\r\n"),
|
||||
file->version.major, file->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
@ -261,7 +285,8 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
(st.mime? st.mime: QSE_MT("")),
|
||||
(st.mime? QSE_MT("\r\n"): QSE_MT("")),
|
||||
b_fsize,
|
||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1)
|
||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||
etag
|
||||
);
|
||||
if (x) x = entask_file_segment (httpd, client, x, handle, 0, st.size);
|
||||
}
|
||||
@ -305,14 +330,31 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
||||
data.range.type = QSE_HTTP_RANGE_NONE;
|
||||
}
|
||||
|
||||
/* TODO: support Etag and If-None-Match */
|
||||
data.if_modified_since = 0; /* 0 should be old enough */
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-None-Match"));
|
||||
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 = 0;
|
||||
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 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
|
@ -155,6 +155,13 @@ static qse_httpd_errnum_t syserr_to_errnum (int e)
|
||||
return QSE_HTTPD_EACCES;
|
||||
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
/* ENOTDIR can be returned in this situation.
|
||||
* i want to access /tmp/t1.cgi/abc/def
|
||||
* while /tmp/t1.cgi is an existing file.
|
||||
* I'm not sure if it is really good to translate
|
||||
* ENOTDIR to QSE_HTTPD_ENOENT.
|
||||
*/
|
||||
return QSE_HTTPD_ENOENT;
|
||||
|
||||
case EEXIST:
|
||||
@ -328,6 +335,7 @@ static int init_xtn_ssl (
|
||||
/* TODO: CRYPTO_set_id_callback ();
|
||||
TODO: CRYPTO_set_locking_callback ();*/
|
||||
|
||||
SSL_CTX_set_read_ahead (ctx, 0);
|
||||
xtn->ssl_ctx = ctx;
|
||||
return 0;
|
||||
}
|
||||
@ -987,6 +995,8 @@ static int file_stat (
|
||||
|
||||
QSE_MEMSET (hst, 0, QSE_SIZEOF(*hst));
|
||||
|
||||
hst->dev = st.st_dev;
|
||||
hst->ino = st.st_ino;
|
||||
hst->size = st.st_size;
|
||||
#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
|
||||
hst->mtime = QSE_SECNSEC_TO_MSEC(st.st_mtim.tv_sec,st.st_mtim.tv_nsec);
|
||||
@ -1110,6 +1120,12 @@ static qse_ssize_t client_recv (
|
||||
else
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||
}
|
||||
|
||||
if (SSL_pending (client->handle2.ptr) > 0)
|
||||
client->status |= CLIENT_PENDING;
|
||||
else
|
||||
client->status &= ~CLIENT_PENDING;
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
@ -1209,6 +1225,8 @@ qse_fflush (QSE_STDOUT);
|
||||
* will free it */
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_read_ahead (ssl, 0);
|
||||
}
|
||||
|
||||
ret = SSL_accept (ssl);
|
||||
@ -1224,7 +1242,10 @@ qse_fflush (QSE_STDOUT);
|
||||
/* SSL_free (ssl); */
|
||||
return -1;
|
||||
}
|
||||
qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i);
|
||||
qse_fflush (QSE_STDOUT);
|
||||
#else
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: NO SSL SUPPORT\n"));
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
@ -1260,6 +1281,178 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_
|
||||
return QSE_HTB_WALK_FORWARD;
|
||||
}
|
||||
|
||||
typedef struct target_t target_t;
|
||||
struct target_t
|
||||
{
|
||||
enum
|
||||
{
|
||||
TARGET_DIR,
|
||||
TARGET_FILE,
|
||||
TARGET_CGI
|
||||
} type;
|
||||
union
|
||||
{
|
||||
const qse_mchar_t* dir;
|
||||
const qse_mchar_t* file;
|
||||
struct
|
||||
{
|
||||
qse_mchar_t* path;
|
||||
qse_mchar_t* script;
|
||||
qse_mchar_t* suffix;
|
||||
int nph;
|
||||
} cgi;
|
||||
} u;
|
||||
};
|
||||
|
||||
static void dispose_target (qse_httpd_t* httpd, target_t* target)
|
||||
{
|
||||
if (target->type == TARGET_CGI)
|
||||
{
|
||||
if (target->u.cgi.suffix) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.suffix);
|
||||
if (target->u.cgi.script) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.script);
|
||||
if (target->u.cgi.path) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.path);
|
||||
}
|
||||
}
|
||||
|
||||
static int resolve_target (
|
||||
qse_httpd_t* httpd, qse_htre_t* req, target_t* target)
|
||||
{
|
||||
static struct extinfo_t
|
||||
{
|
||||
const qse_mchar_t* ptr;
|
||||
qse_size_t len;
|
||||
int nph;
|
||||
} extinfo[] =
|
||||
{
|
||||
{ QSE_MT(".cgi"), 4, 0 },
|
||||
{ QSE_MT(".nph"), 4, 1 }
|
||||
};
|
||||
|
||||
qse_size_t i;
|
||||
const qse_mchar_t* qpath;
|
||||
qse_stat_t st;
|
||||
|
||||
qpath = qse_htre_getqpath(req);
|
||||
|
||||
QSE_MEMSET (target, 0, QSE_SIZEOF(*target));
|
||||
|
||||
if (QSE_STAT (qpath, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
{
|
||||
/* TODO: attempt the index file like index.html, index.cgi, etc. */
|
||||
/* it is a directory */
|
||||
target->type = TARGET_DIR;
|
||||
target->u.dir = qpath;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: attempt other segments if qpath is like
|
||||
* /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only.
|
||||
* x.cgi could be a directory name .
|
||||
*/
|
||||
for (i = 0; i < QSE_COUNTOF(extinfo); i++)
|
||||
{
|
||||
const qse_mchar_t* ext;
|
||||
|
||||
ext = qse_mbsstr (qpath, extinfo[i].ptr);
|
||||
if (ext && (ext[extinfo[i].len] == QSE_MT('/') ||
|
||||
ext[extinfo[i].len] == QSE_MT('\0')))
|
||||
{
|
||||
target->type = TARGET_CGI;
|
||||
target->u.cgi.nph = extinfo[i].nph;
|
||||
|
||||
if (ext[extinfo[i].len] == QSE_MT('/'))
|
||||
{
|
||||
/* TODO: combine path with document root */
|
||||
target->u.cgi.path = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr);
|
||||
|
||||
target->u.cgi.script = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr);
|
||||
target->u.cgi.suffix = qse_mbsdup (&ext[extinfo[i].len], httpd->mmgr);
|
||||
|
||||
if (target->u.cgi.path == QSE_NULL ||
|
||||
target->u.cgi.script == QSE_NULL ||
|
||||
target->u.cgi.suffix == QSE_NULL)
|
||||
{
|
||||
dispose_target (httpd, target);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: combine path with document root */
|
||||
target->u.cgi.path = qse_mbsdup (qpath, httpd->mmgr);
|
||||
|
||||
target->u.cgi.script = qse_mbsdup (qpath, httpd->mmgr);
|
||||
|
||||
if (target->u.cgi.path == QSE_NULL ||
|
||||
target->u.cgi.script == QSE_NULL)
|
||||
{
|
||||
dispose_target (httpd, target);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
target->type = TARGET_FILE;
|
||||
target->u.file = qpath;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static qse_httpd_task_t* entask_target (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, target_t* target)
|
||||
{
|
||||
qse_httpd_task_t* task;
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case TARGET_DIR:
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, target->u.dir, req);
|
||||
break;
|
||||
|
||||
case TARGET_FILE:
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskfile (httpd, client, QSE_NULL, target->u.file, req);
|
||||
break;
|
||||
|
||||
case TARGET_CGI:
|
||||
if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 411, req);
|
||||
if (task)
|
||||
{
|
||||
/* 411 Length Required - can't keep alive */
|
||||
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskcgi (
|
||||
httpd, client, QSE_NULL, target->u.cgi.path,
|
||||
target->u.cgi.script, target->u.cgi.suffix,
|
||||
target->u.cgi.nph, req);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
task = QSE_NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static int process_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, int peek)
|
||||
@ -1315,7 +1508,7 @@ if (qse_htre_getcontentlen(req) > 0)
|
||||
/* "expect" in the header, version 1.1 or higher,
|
||||
* and no content received yet */
|
||||
|
||||
/* TODO: determine if to return 100-continue or other errors */
|
||||
/* TODO: determine if to return 100-continue or other errors */
|
||||
{
|
||||
qse_ntime_t now;
|
||||
qse_gettime (&now);
|
||||
@ -1333,117 +1526,60 @@ if (qse_htre_getcontentlen(req) > 0)
|
||||
|
||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||
{
|
||||
const qse_mchar_t* qpath = qse_htre_getqpath(req);
|
||||
const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.'));
|
||||
|
||||
if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0)
|
||||
if (peek)
|
||||
{
|
||||
if (peek)
|
||||
{
|
||||
/* cgi */
|
||||
#if 0
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
|
||||
{
|
||||
qse_printf (QSE_T("chunked cgi... delaying until contents are received\n"));
|
||||
#if 0
|
||||
req->attr.keepalive = 0;
|
||||
task = qse_httpd_entaskerror (
|
||||
httpd, client, QSE_NULL, 411, req);
|
||||
/* 411 can't keep alive */
|
||||
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
target_t target;
|
||||
|
||||
/*if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))*/
|
||||
if (method == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
task = qse_httpd_entaskerror (
|
||||
httpd, client, QSE_NULL, 411, req);
|
||||
/* 411 can't keep alive */
|
||||
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskcgi (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
/* to support the chunked request,
|
||||
* i need to wait until it's completed and invoke cgi */
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
|
||||
{
|
||||
qse_printf (QSE_T("Entasking chunked CGI...\n"));
|
||||
task = qse_httpd_entaskcgi (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if (dot && qse_mbscmp (dot, QSE_MT(".nph")) == 0)
|
||||
{
|
||||
if (peek)
|
||||
{
|
||||
const qse_htre_hdrval_t* auth;
|
||||
int authorized = 0;
|
||||
|
||||
auth = qse_htre_getheaderval (req, QSE_MT("Authorization"));
|
||||
if (auth)
|
||||
{
|
||||
/* TODO: PERFORM authorization... */
|
||||
/* BASE64 decode... */
|
||||
while (auth->next) auth = auth->next;
|
||||
authorized = 1;
|
||||
}
|
||||
|
||||
if (authorized)
|
||||
{
|
||||
/* nph-cgi */
|
||||
task = qse_httpd_entasknph (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskauth (
|
||||
httpd, client, QSE_NULL, QSE_MT("Secure Area"), req);
|
||||
}
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
if (!peek)
|
||||
{
|
||||
/* file or directory */
|
||||
task = qse_httpd_entaskfile (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
#else
|
||||
if (peek)
|
||||
if (resolve_target (httpd, req, &target) <= -1)
|
||||
{
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
task = entask_target (httpd, client, req, &target);
|
||||
dispose_target (httpd, &target);
|
||||
}
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (peek)
|
||||
{
|
||||
const qse_htre_hdrval_t* auth;
|
||||
int authorized = 0;
|
||||
|
||||
auth = qse_htre_getheaderval (req, QSE_MT("Authorization"));
|
||||
if (auth)
|
||||
{
|
||||
/* TODO: PERFORM authorization... */
|
||||
/* BASE64 decode... */
|
||||
while (auth->next) auth = auth->next;
|
||||
authorized = 1;
|
||||
}
|
||||
|
||||
if (authorized)
|
||||
{
|
||||
/* nph-cgi */
|
||||
task = qse_httpd_entasknph (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskauth (
|
||||
httpd, client, QSE_NULL, QSE_MT("Secure Area"), req);
|
||||
}
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!peek)
|
||||
if (peek)
|
||||
{
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
|
@ -446,6 +446,7 @@ qse_httpd_task_t* qse_httpd_entaskauth (
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskpath (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* name, qse_htre_t* req)
|
||||
@ -453,13 +454,16 @@ qse_httpd_task_t* qse_httpd_entaskpath (
|
||||
qse_stat_t st;
|
||||
qse_httpd_task_t* task;
|
||||
|
||||
if (QSE_LSTAT (name, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
/* TODO: LSTAT or STAT? should i not follow the symbolic link? */
|
||||
/* if (QSE_LSTAT (name, &st) == 0 && S_ISDIR(st.st_mode))*/
|
||||
if (QSE_STAT (name, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
task = qse_httpd_entaskdir (httpd, client, pred, name, req);
|
||||
else
|
||||
task = qse_httpd_entaskfile (httpd, client, pred, name, req);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
|
@ -758,6 +758,25 @@ qse_printf (QSE_T("]\n"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i);
|
||||
|
||||
if (client->status & CLIENT_PENDING)
|
||||
{
|
||||
/* this CLIENT_PENDING thing is a dirty hack for SSL.
|
||||
* In SSL, data is transmitted in a record. a record can be
|
||||
* as large as 16K bytes since its length field is 2 bytes.
|
||||
* If SSL_read() has record a record but it's given a
|
||||
* smaller buffer than the actuaal record, the next call
|
||||
* to select() won't return. there is no data to read
|
||||
* at the socket layer. SSL_pending() can tell you the
|
||||
* amount of data in the SSL buffer. I try to consume
|
||||
* the pending data if the client.recv handler set CLIENT_PENDING.
|
||||
*
|
||||
* TODO: Investigate if there is any starvation issues.
|
||||
* What if a single client never stops sending?
|
||||
*/
|
||||
goto reread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -771,6 +790,7 @@ static int invoke_client_task (
|
||||
int n, trigger_fired, client_handle_writable;
|
||||
|
||||
/* TODO: handle comparison callback ... */
|
||||
qse_printf (QSE_T("INVOKE CLIENT TASK..........\n"));
|
||||
if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */
|
||||
{
|
||||
if (!(client->status & CLIENT_MUTE) &&
|
||||
@ -899,7 +919,7 @@ qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
|
||||
{
|
||||
/* the code here is pretty fragile. there is a high chance
|
||||
* that something can go wrong if the task handler plays
|
||||
* with the trigger field in an unexpected mannger.
|
||||
* with the trigger field in an unexpected manner.
|
||||
*/
|
||||
|
||||
for (i = 0; i < QSE_COUNTOF(task->trigger); i++)
|
||||
|
@ -74,12 +74,13 @@ struct qse_httpd_t
|
||||
#define CLIENT_BAD (1 << 0)
|
||||
#define CLIENT_READY (1 << 1)
|
||||
#define CLIENT_SECURE (1 << 2)
|
||||
#define CLIENT_MUTE (1 << 3)
|
||||
#define CLIENT_MUTE_DELETED (1 << 4)
|
||||
#define CLIENT_HANDLE_READ_IN_MUX (1 << 5)
|
||||
#define CLIENT_HANDLE_WRITE_IN_MUX (1 << 6)
|
||||
#define CLIENT_PENDING (1 << 3)
|
||||
#define CLIENT_MUTE (1 << 4)
|
||||
#define CLIENT_MUTE_DELETED (1 << 5)
|
||||
#define CLIENT_HANDLE_READ_IN_MUX (1 << 6)
|
||||
#define CLIENT_HANDLE_WRITE_IN_MUX (1 << 7)
|
||||
#define CLIENT_HANDLE_IN_MUX (CLIENT_HANDLE_READ_IN_MUX|CLIENT_HANDLE_WRITE_IN_MUX)
|
||||
#define CLIENT_TASK_TRIGGER_IN_MUX(i) (1 << ((i) + 7))
|
||||
#define CLIENT_TASK_TRIGGER_IN_MUX(i) (1 << ((i) + 8))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -111,7 +111,7 @@ if (qse_htre_getqparam(req))
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskcgi (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
httpd, client, QSE_NULL, qpath, QSE_NULL, QSE_NULL, 0, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user