improved httpd

This commit is contained in:
hyung-hwan 2012-09-18 13:03:57 +00:00
parent 99f1b5453b
commit fdba865863
9 changed files with 438 additions and 221 deletions

View File

@ -65,6 +65,8 @@ enum qse_httpd_option_t
typedef struct qse_httpd_stat_t qse_httpd_stat_t; typedef struct qse_httpd_stat_t qse_httpd_stat_t;
struct qse_httpd_stat_t struct qse_httpd_stat_t
{ {
qse_long_t dev;
qse_long_t ino;
qse_foff_t size; qse_foff_t size;
qse_ntime_t mtime; qse_ntime_t mtime;
const qse_mchar_t* mime; const qse_mchar_t* mime;
@ -556,14 +558,9 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_client_t* client, qse_httpd_client_t* client,
qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* path, const qse_mchar_t* path,
qse_htre_t* req const qse_mchar_t* script,
); const qse_mchar_t* suffix,
int nph,
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 qse_htre_t* req
); );

View File

@ -64,39 +64,39 @@
# include <sys/syscall.h> # include <sys/syscall.h>
#endif #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) # define QSE_OPEN(path,flags,mode) syscall(SYS_open,path,flags,mode)
#else #else
# define QSE_OPEN(path,flags,mode) open(path,flags,mode) # define QSE_OPEN(path,flags,mode) open(path,flags,mode)
#endif #endif
#if defined(SYS_close) #if defined(SYS_close) && defined(QSE_USE_SYSCALL)
# define QSE_CLOSE(handle) syscall(SYS_close,handle) # define QSE_CLOSE(handle) syscall(SYS_close,handle)
#else #else
# define QSE_CLOSE(handle) close(handle) # define QSE_CLOSE(handle) close(handle)
#endif #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) # define QSE_READ(handle,buf,size) syscall(SYS_read,handle,buf,size)
#else #else
# define QSE_READ(handle,buf,size) read(handle,buf,size) # define QSE_READ(handle,buf,size) read(handle,buf,size)
#endif #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) # define QSE_WRITE(handle,buf,size) syscall(SYS_write,handle,buf,size)
#else #else
# define QSE_WRITE(handle,buf,size) write(handle,buf,size) # define QSE_WRITE(handle,buf,size) write(handle,buf,size)
#endif #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) # 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) # define QSE_LLSEEK(handle,hoffset,loffset,out,whence) _llseek(handle,hoffset,loffset,out,whence)
#endif #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) # 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) # define QSE_LSEEK(handle,offset,whence) syscall(SYS_lseek,handle,offset,whence)
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSEEK64) #elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSEEK64)
# define QSE_LSEEK(handle,offset,whence) lseek64(handle,offset,whence) # define QSE_LSEEK(handle,offset,whence) lseek64(handle,offset,whence)
@ -104,10 +104,10 @@
# define QSE_LSEEK(handle,offset,whence) lseek(handle,offset,whence) # define QSE_LSEEK(handle,offset,whence) lseek(handle,offset,whence)
#endif #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) # define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat64,handle,stbuf)
typedef struct stat64 qse_fstat_t; 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) # define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat,handle,stbuf)
typedef struct stat qse_fstat_t; typedef struct stat qse_fstat_t;
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTAT64) #elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTAT64)
@ -118,9 +118,9 @@
typedef struct stat qse_fstat_t; typedef struct stat qse_fstat_t;
#endif #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) # 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) # define QSE_FTRUNCATE(handle,size) syscall(SYS_ftruncate,handle,size)
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FTRUNCATE64) #elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FTRUNCATE64)
# define QSE_FTRUNCATE(handle,size) ftruncate64(handle,size) # define QSE_FTRUNCATE(handle,size) ftruncate64(handle,size)
@ -128,127 +128,127 @@
# define QSE_FTRUNCATE(handle,size) ftruncate(handle,size) # define QSE_FTRUNCATE(handle,size) ftruncate(handle,size)
#endif #endif
#if defined(SYS_fchmod) #if defined(SYS_fchmod) && defined(QSE_USE_SYSCALL)
# define QSE_FCHMOD(handle,mode) syscall(SYS_fchmod,handle,mode) # define QSE_FCHMOD(handle,mode) syscall(SYS_fchmod,handle,mode)
#else #else
# define QSE_FCHMOD(handle,mode) fchmod(handle,mode) # define QSE_FCHMOD(handle,mode) fchmod(handle,mode)
#endif #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) # define QSE_FCHOWN(handle,owner,group) syscall(SYS_fchown,handle,owner,group)
#else #else
# define QSE_FCHOWN(handle,owner,group) fchown(handle,owner,group) # define QSE_FCHOWN(handle,owner,group) fchown(handle,owner,group)
#endif #endif
#if defined(SYS_fsync) #if defined(SYS_fsync) && defined(QSE_USE_SYSCALL)
# define QSE_FSYNC(handle) syscall(SYS_fsync,handle) # define QSE_FSYNC(handle) syscall(SYS_fsync,handle)
#else #else
# define QSE_FSYNC(handle) fsync(handle) # define QSE_FSYNC(handle) fsync(handle)
#endif #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) # define QSE_FCNTL(handle,cmd,arg) syscall(SYS_fcntl,handle,cmd,arg)
#else #else
# define QSE_FCNTL(handle,cmd,arg) fcntl(handle,cmd,arg) # define QSE_FCNTL(handle,cmd,arg) fcntl(handle,cmd,arg)
#endif #endif
#if defined(SYS_dup2) #if defined(SYS_dup2) && defined(QSE_USE_SYSCALL)
# define QSE_DUP2(ofd,nfd) syscall(SYS_dup2,ofd,nfd) # define QSE_DUP2(ofd,nfd) syscall(SYS_dup2,ofd,nfd)
#else #else
# define QSE_DUP2(ofd,nfd) dup2(ofd,nfd) # define QSE_DUP2(ofd,nfd) dup2(ofd,nfd)
#endif #endif
#if defined(SYS_pipe) #if defined(SYS_pipe) && defined(QSE_USE_SYSCALL)
# define QSE_PIPE(pfds) syscall(SYS_pipe,pfds) # define QSE_PIPE(pfds) syscall(SYS_pipe,pfds)
#else #else
# define QSE_PIPE(pfds) pipe(pfds) # define QSE_PIPE(pfds) pipe(pfds)
#endif #endif
#if defined(SYS_exit) #if defined(SYS_exit) && defined(QSE_USE_SYSCALL)
# define QSE_EXIT(code) syscall(SYS_exit,code) # define QSE_EXIT(code) syscall(SYS_exit,code)
#else #else
# define QSE_EXIT(code) _exit(code) # define QSE_EXIT(code) _exit(code)
#endif #endif
#if defined(SYS_fork) #if defined(SYS_fork) && defined(QSE_USE_SYSCALL)
# define QSE_FORK() syscall(SYS_fork) # define QSE_FORK() syscall(SYS_fork)
#else #else
# define QSE_FORK() fork() # define QSE_FORK() fork()
#endif #endif
#if defined(SYS_vfork) #if defined(SYS_vfork) && defined(QSE_USE_SYSCALL)
# define QSE_VFORK() syscall(SYS_vfork) # define QSE_VFORK() syscall(SYS_vfork)
#else #else
# define QSE_VFORK() vfork() # define QSE_VFORK() vfork()
#endif #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) # define QSE_EXECVE(path,argv,envp) syscall(SYS_execve,path,argv,envp)
#else #else
# define QSE_EXECVE(path,argv,envp) execve(path,argv,envp) # define QSE_EXECVE(path,argv,envp) execve(path,argv,envp)
#endif #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) # define QSE_WAITPID(pid,status,options) syscall(SYS_waitpid,pid,status,options)
#else #else
# define QSE_WAITPID(pid,status,options) waitpid(pid,status,options) # define QSE_WAITPID(pid,status,options) waitpid(pid,status,options)
#endif #endif
#if defined(SYS_kill) #if defined(SYS_kill) && defined(QSE_USE_SYSCALL)
# define QSE_KILL(pid,sig) syscall(SYS_kill,pid,sig) # define QSE_KILL(pid,sig) syscall(SYS_kill,pid,sig)
#else #else
# define QSE_KILL(pid,sig) kill(pid,sig) # define QSE_KILL(pid,sig) kill(pid,sig)
#endif #endif
#if defined(SYS_getpid) #if defined(SYS_getpid) && defined(QSE_USE_SYSCALL)
# define QSE_GETPID() syscall(SYS_getpid) # define QSE_GETPID() syscall(SYS_getpid)
#else #else
# define QSE_GETPID() getpid() # define QSE_GETPID() getpid()
#endif #endif
#if defined(SYS_getuid) #if defined(SYS_getuid) && defined(QSE_USE_SYSCALL)
# define QSE_GETUID() syscall(SYS_getuid) # define QSE_GETUID() syscall(SYS_getuid)
#else #else
# define QSE_GETUID() getuid() # define QSE_GETUID() getuid()
#endif #endif
#if defined(SYS_geteuid) #if defined(SYS_geteuid) && defined(QSE_USE_SYSCALL)
# define QSE_GETEUID() syscall(SYS_geteuid) # define QSE_GETEUID() syscall(SYS_geteuid)
#else #else
# define QSE_GETEUID() geteuid() # define QSE_GETEUID() geteuid()
#endif #endif
#if defined(SYS_getgid) #if defined(SYS_getgid) && defined(QSE_USE_SYSCALL)
# define QSE_GETGID() syscall(SYS_getgid) # define QSE_GETGID() syscall(SYS_getgid)
#else #else
# define QSE_GETGID() getgid() # define QSE_GETGID() getgid()
#endif #endif
#if defined(SYS_getegid) #if defined(SYS_getegid) && defined(QSE_USE_SYSCALL)
# define QSE_GETEGID() syscall(SYS_getegid) # define QSE_GETEGID() syscall(SYS_getegid)
#else #else
# define QSE_GETEGID() getegid() # define QSE_GETEGID() getegid()
#endif #endif
#if defined(SYS_gettimeofday) #if defined(SYS_gettimeofday) && defined(QSE_USE_SYSCALL)
# define QSE_GETTIMEOFDAY(tv,tz) syscall(SYS_gettimeofday,tv,tz) # define QSE_GETTIMEOFDAY(tv,tz) syscall(SYS_gettimeofday,tv,tz)
#else #else
# define QSE_GETTIMEOFDAY(tv,tz) gettimeofday(tv,tz) # define QSE_GETTIMEOFDAY(tv,tz) gettimeofday(tv,tz)
#endif #endif
#if defined(SYS_settimeofday) #if defined(SYS_settimeofday) && defined(QSE_USE_SYSCALL)
# define QSE_SETTIMEOFDAY(tv,tz) syscall(SYS_settimeofday,tv,tz) # define QSE_SETTIMEOFDAY(tv,tz) syscall(SYS_settimeofday,tv,tz)
#else #else
# define QSE_SETTIMEOFDAY(tv,tz) settimeofday(tv,tz) # define QSE_SETTIMEOFDAY(tv,tz) settimeofday(tv,tz)
#endif #endif
#if defined(SYS_getrlimit) #if defined(SYS_getrlimit) && defined(QSE_USE_SYSCALL)
# define QSE_GETRLIMIT(res,lim) syscall(SYS_getrlimit,res,lim) # define QSE_GETRLIMIT(res,lim) syscall(SYS_getrlimit,res,lim)
#else #else
# define QSE_GETRLIMIT(res,lim) getrlimit(res,lim) # define QSE_GETRLIMIT(res,lim) getrlimit(res,lim)
#endif #endif
#if defined(SYS_setrlimit) #if defined(SYS_setrlimit) && defined(QSE_USE_SYSCALL)
# define QSE_SETRLIMIT(res,lim) syscall(SYS_setrlimit,res,lim) # define QSE_SETRLIMIT(res,lim) syscall(SYS_setrlimit,res,lim)
#else #else
# define QSE_SETRLIMIT(res,lim) setrlimit(res,lim) # define QSE_SETRLIMIT(res,lim) setrlimit(res,lim)
@ -257,40 +257,40 @@
/* ===== FILE SYSTEM CALLS ===== */ /* ===== 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) # define QSE_CHMOD(path,mode) syscall(SYS_chmod,path,mode)
#else #else
# define QSE_CHMOD(path,mode) chmod(path,mode) # define QSE_CHMOD(path,mode) chmod(path,mode)
#endif #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) # define QSE_CHOWN(path,owner,group) syscall(SYS_chown,path,owner,group)
#else #else
# define QSE_CHOWN(path,owner,group) chown(path,owner,group) # define QSE_CHOWN(path,owner,group) chown(path,owner,group)
#endif #endif
#if defined(SYS_chroot) #if defined(SYS_chroot) && defined(QSE_USE_SYSCALL)
# define QSE_CHROOT(path) syscall(SYS_chroot,path) # define QSE_CHROOT(path) syscall(SYS_chroot,path)
#else #else
# define QSE_CHROOT(path) chroot(path) # define QSE_CHROOT(path) chroot(path)
#endif #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) # define QSE_LCHOWN(path,owner,group) syscall(SYS_lchown,path,owner,group)
#else #else
# define QSE_LCHOWN(path,owner,group) lchown(path,owner,group) # define QSE_LCHOWN(path,owner,group) lchown(path,owner,group)
#endif #endif
#if defined(SYS_link) #if defined(SYS_link) && defined(QSE_USE_SYSCALL)
# define QSE_LINK(oldpath,newpath) syscall(SYS_link,oldpath,newpath) # define QSE_LINK(oldpath,newpath) syscall(SYS_link,oldpath,newpath)
#else #else
# define QSE_LINK(oldpath,newpath) link(oldpath,newpath) # define QSE_LINK(oldpath,newpath) link(oldpath,newpath)
#endif #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) # define QSE_LSTAT(path,stbuf) syscall(SYS_lstat,path,stbuf)
typedef struct stat64 qse_lstat_t; 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) # define QSE_LSTAT(path,stbuf) syscall(SYS_lstat,path,stbuf)
typedef struct stat qse_lstat_t; typedef struct stat qse_lstat_t;
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSTAT64) #elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_LSTAT64)
@ -301,29 +301,29 @@
typedef struct stat qse_lstat_t; typedef struct stat qse_lstat_t;
#endif #endif
#if defined(SYS_access) #if defined(SYS_access) && defined(QSE_USE_SYSCALL)
# define QSE_ACCESS(path,mode) syscall(SYS_access,path,mode) # define QSE_ACCESS(path,mode) syscall(SYS_access,path,mode)
#else #else
# define QSE_ACCESS(path,mode) access(path,mode) # define QSE_ACCESS(path,mode) access(path,mode)
#endif #endif
#if defined(SYS_rename) #if defined(SYS_rename) && defined(QSE_USE_SYSCALL)
# define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath) # define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath)
#else #else
int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */ int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath) # define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
#endif #endif
#if defined(SYS_rmdir) #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
# define QSE_RMDIR(path) rmdir(path) # define QSE_RMDIR(path) rmdir(path)
#endif #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) # define QSE_STAT(path,stbuf) syscall(SYS_stat64,path,stbuf)
typedef struct stat64 qse_stat_t; 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) # define QSE_STAT(path,stbuf) syscall(SYS_stat,path,stbuf)
typedef struct stat qse_stat_t; typedef struct stat qse_stat_t;
#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_STAT64) #elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_STAT64)
@ -334,25 +334,25 @@
typedef struct stat qse_stat_t; typedef struct stat qse_stat_t;
#endif #endif
#if defined(SYS_symlink) #if defined(SYS_symlink) && defined(QSE_USE_SYSCALL)
# define QSE_SYMLINK(oldpath,newpath) syscall(SYS_symlink,oldpath,newpath) # define QSE_SYMLINK(oldpath,newpath) syscall(SYS_symlink,oldpath,newpath)
#else #else
# define QSE_SYMLINK(oldpath,newpath) symlink(oldpath,newpath) # define QSE_SYMLINK(oldpath,newpath) symlink(oldpath,newpath)
#endif #endif
#if defined(SYS_unlink) #if defined(SYS_unlink) && defined(QSE_USE_SYSCALL)
# define QSE_UNLINK(path) syscall(SYS_unlink,path) # define QSE_UNLINK(path) syscall(SYS_unlink,path)
#else #else
# define QSE_UNLINK(path) unlink(path) # define QSE_UNLINK(path) unlink(path)
#endif #endif
#if defined(SYS_utime) #if defined(SYS_utime) && defined(QSE_USE_SYSCALL)
# define QSE_UTIME(path,t) syscall(SYS_utime,path,t) # define QSE_UTIME(path,t) syscall(SYS_utime,path,t)
#else #else
# define QSE_UTIME(path,t) utime(path,t) # define QSE_UTIME(path,t) utime(path,t)
#endif #endif
#if defined(SYS_utimes) #if defined(SYS_utimes) && defined(QSE_USE_SYSCALL)
# define QSE_UTIMES(path,t) syscall(SYS_utimes,path,t) # define QSE_UTIMES(path,t) syscall(SYS_utimes,path,t)
#else #else
# define QSE_UTIMES(path,t) utimes(path,t) # define QSE_UTIMES(path,t) utimes(path,t)

View File

@ -18,11 +18,6 @@
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>. 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 "httpd.h"
#include "../cmn/mem.h" #include "../cmn/mem.h"
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
@ -34,9 +29,11 @@
typedef struct task_cgi_arg_t task_cgi_arg_t; typedef struct task_cgi_arg_t task_cgi_arg_t;
struct task_cgi_arg_t struct task_cgi_arg_t
{ {
const qse_mchar_t* path; qse_mcstr_t path;
qse_htre_t* req; qse_mcstr_t script;
qse_mcstr_t suffix;
int nph; int nph;
qse_htre_t* req;
}; };
typedef struct task_cgi_t task_cgi_t; typedef struct task_cgi_t task_cgi_t;
@ -46,6 +43,8 @@ struct task_cgi_t
qse_httpd_t* httpd; qse_httpd_t* httpd;
const qse_mchar_t* path; const qse_mchar_t* path;
const qse_mchar_t* script;
const qse_mchar_t* suffix;
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;
@ -407,8 +406,13 @@ static qse_htrd_recbs_t cgi_script_htrd_cbs =
static int cgi_add_env ( static int cgi_add_env (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_env_t* env, qse_htre_t* req, const qse_env_t* env, qse_htre_t* req,
qse_mchar_t* path, qse_size_t length, int chunked) 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 */ /* TODO: error check */
cgi_client_req_hdr_ctx_t ctx; 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); 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("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??? */ /* 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("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_METHOD"), qse_htre_getqmethodname(req));
qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req)); qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req));
if (qparam) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), qparam); 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); 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")); 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); qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf);
#if 0 #if 0
//qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), QSE_MT("/"));
qse_env_insertmbs (env, "SERVER_NAME", qse_env_insertmbs (env, "SERVER_NAME",
qse_env_insertmbs (env, "SERVER_ROOT", qse_env_insertmbs (env, "SERVER_ROOT",
qse_env_insertmbs (env, "DOCUMENT_ROOT", qse_env_insertmbs (env, "DOCUMENT_ROOT",
@ -680,6 +684,7 @@ static int task_init_cgi (
qse_size_t content_length; qse_size_t content_length;
qse_size_t len; qse_size_t len;
const qse_mchar_t* ptr; const qse_mchar_t* ptr;
const qse_htre_hdrval_t* tmp;
cgi = (task_cgi_t*)qse_httpd_gettaskxtn (httpd, task); cgi = (task_cgi_t*)qse_httpd_gettaskxtn (httpd, task);
arg = (task_cgi_arg_t*)task->ctx; arg = (task_cgi_arg_t*)task->ctx;
@ -692,8 +697,13 @@ static int task_init_cgi (
QSE_MEMSET (cgi, 0, QSE_SIZEOF(*cgi)); QSE_MEMSET (cgi, 0, QSE_SIZEOF(*cgi));
cgi->httpd = httpd; cgi->httpd = httpd;
qse_mbscpy ((qse_mchar_t*)(cgi + 1), arg->path);
cgi->path = (qse_mchar_t*)(cgi + 1); 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->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;
@ -826,8 +836,14 @@ done:
goto oops; 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 ( 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) (cgi->reqflags & CGI_REQ_FWDCHUNKED)) <= -1)
{ {
goto oops; goto oops;
@ -1434,15 +1450,28 @@ oops:
* non-blocking pio read ... * non-blocking pio read ...
*/ */
static QSE_INLINE qse_httpd_task_t* entask_cgi ( qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd,
qse_httpd_task_t* pred, const qse_mchar_t* path, qse_httpd_client_t* client,
qse_htre_t* req, int nph) 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; qse_httpd_task_t task;
task_cgi_arg_t arg; 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.req = req;
arg.nph = nph; arg.nph = nph;
@ -1454,22 +1483,10 @@ static QSE_INLINE qse_httpd_task_t* entask_cgi (
return qse_httpd_entask ( return qse_httpd_entask (
httpd, client, pred, &task, 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

View File

@ -27,11 +27,14 @@
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
#include <qse/cmn/stdio.h> /* TODO: remove this */ #include <qse/cmn/stdio.h> /* TODO: remove this */
#define ETAG_LEN_MAX 127
typedef struct task_file_t task_file_t; typedef struct task_file_t task_file_t;
struct task_file_t struct task_file_t
{ {
const qse_mchar_t* path; const qse_mchar_t* path;
qse_http_range_t range; qse_http_range_t range;
qse_mchar_t if_none_match[ETAG_LEN_MAX + 1];
qse_ntime_t if_modified_since; qse_ntime_t if_modified_since;
qse_http_version_t version; qse_http_version_t version;
int keepalive; int keepalive;
@ -178,6 +181,8 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
if (file->range.type != QSE_HTTP_RANGE_NONE) if (file->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_size_t etag_len;
if (file->range.type == QSE_HTTP_RANGE_SUFFIX) 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[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); 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 ( x = qse_httpd_entaskformat (
httpd, client, x, 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, file->version.major, file->version.minor,
qse_httpd_getname (httpd), qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), 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? QSE_MT("Content-Type: "): QSE_MT("")),
(st.mime? st.mime: QSE_MT("")), (st.mime? st.mime: QSE_MT("")),
(st.mime? QSE_MT("\r\n"): 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) if (x)
{ {
@ -226,13 +239,24 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
else else
{ {
qse_mchar_t b_fsize[64]; 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 && etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag) - etag_len, st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL);
QSE_MSEC_TO_SEC(st.mtime) <= QSE_MSEC_TO_SEC(file->if_modified_since)) 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 * 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_entaskformat ( x = qse_httpd_entaskformat (
httpd, client, x, 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"), 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 ( x = qse_httpd_entaskformat (
httpd, client, x, 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, file->version.major, file->version.minor,
qse_httpd_getname (httpd), qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), 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? st.mime: QSE_MT("")),
(st.mime? QSE_MT("\r\n"): QSE_MT("")), (st.mime? QSE_MT("\r\n"): QSE_MT("")),
b_fsize, 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); if (x) x = entask_file_segment (httpd, client, x, handle, 0, st.size);
} }
@ -305,8 +330,24 @@ qse_httpd_task_t* qse_httpd_entaskfile (
data.range.type = QSE_HTTP_RANGE_NONE; data.range.type = QSE_HTTP_RANGE_NONE;
} }
/* TODO: support Etag and If-None-Match */ tmp = qse_htre_getheaderval(req, QSE_MT("If-None-Match"));
data.if_modified_since = 0; /* 0 should be old enough */ 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")); tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
if (tmp) if (tmp)
{ {
@ -314,6 +355,7 @@ qse_httpd_task_t* qse_httpd_entaskfile (
if (qse_parsehttptime (tmp->ptr, &data.if_modified_since) <= -1) if (qse_parsehttptime (tmp->ptr, &data.if_modified_since) <= -1)
data.if_modified_since = 0; data.if_modified_since = 0;
} }
}
QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_file; task.init = task_init_file;

View File

@ -155,6 +155,13 @@ static qse_httpd_errnum_t syserr_to_errnum (int e)
return QSE_HTTPD_EACCES; return QSE_HTTPD_EACCES;
case ENOENT: 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; return QSE_HTTPD_ENOENT;
case EEXIST: case EEXIST:
@ -328,6 +335,7 @@ static int init_xtn_ssl (
/* TODO: CRYPTO_set_id_callback (); /* TODO: CRYPTO_set_id_callback ();
TODO: CRYPTO_set_locking_callback ();*/ TODO: CRYPTO_set_locking_callback ();*/
SSL_CTX_set_read_ahead (ctx, 0);
xtn->ssl_ctx = ctx; xtn->ssl_ctx = ctx;
return 0; return 0;
} }
@ -987,6 +995,8 @@ static int file_stat (
QSE_MEMSET (hst, 0, QSE_SIZEOF(*hst)); QSE_MEMSET (hst, 0, QSE_SIZEOF(*hst));
hst->dev = st.st_dev;
hst->ino = st.st_ino;
hst->size = st.st_size; hst->size = st.st_size;
#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) #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); 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 else
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); 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; return ret;
#else #else
return -1; return -1;
@ -1209,6 +1225,8 @@ qse_fflush (QSE_STDOUT);
* will free it */ * will free it */
return -1; return -1;
} }
SSL_set_read_ahead (ssl, 0);
} }
ret = SSL_accept (ssl); ret = SSL_accept (ssl);
@ -1224,7 +1242,10 @@ qse_fflush (QSE_STDOUT);
/* SSL_free (ssl); */ /* SSL_free (ssl); */
return -1; return -1;
} }
qse_printf (QSE_T("SSL ACCEPTED %d\n"), client->handle.i);
qse_fflush (QSE_STDOUT);
#else #else
qse_fprintf (QSE_STDERR, QSE_T("Error: NO SSL SUPPORT\n"));
return -1; return -1;
#endif #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; 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 ( static int process_request (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
qse_htre_t* req, int peek) qse_htre_t* req, int peek)
@ -1332,66 +1525,25 @@ if (qse_htre_getcontentlen(req) > 0)
} }
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) 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 */ target_t target;
#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
/*if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))*/ if (resolve_target (httpd, req, &target) <= -1)
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; qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskerror ( task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req);
httpd, client, QSE_NULL, 411, req);
/* 411 can't keep alive */
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
} }
else else
{ {
task = qse_httpd_entaskcgi ( task = entask_target (httpd, client, req, &target);
httpd, client, QSE_NULL, qpath, req); dispose_target (httpd, &target);
}
if (task == QSE_NULL) goto oops; if (task == QSE_NULL) goto oops;
} }
}
#if 0 #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) if (peek)
{ {
const qse_htre_hdrval_t* auth; const qse_htre_hdrval_t* auth;
@ -1419,31 +1571,15 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
} }
if (task == QSE_NULL) goto oops; if (task == QSE_NULL) goto oops;
} }
return 0; #endif
} }
else 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 (peek)
{ {
qse_httpd_discardcontent (httpd, req); qse_httpd_discardcontent (httpd, req);
task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, req);
if (task == QSE_NULL) goto oops;
}
#endif
}
} }
else else
{
if (!peek)
{ {
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req); task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req);
if (task == QSE_NULL) goto oops; if (task == QSE_NULL) goto oops;

View File

@ -446,6 +446,7 @@ qse_httpd_task_t* qse_httpd_entaskauth (
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entaskpath ( qse_httpd_task_t* qse_httpd_entaskpath (
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* name, qse_htre_t* req) 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_stat_t st;
qse_httpd_task_t* task; 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); task = qse_httpd_entaskdir (httpd, client, pred, name, req);
else else
task = qse_httpd_entaskfile (httpd, client, pred, name, req); task = qse_httpd_entaskfile (httpd, client, pred, name, req);
return task; return task;
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if 0 #if 0

View File

@ -758,6 +758,25 @@ qse_printf (QSE_T("]\n"));
return -1; 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; return 0;
} }
@ -771,6 +790,7 @@ static int invoke_client_task (
int n, trigger_fired, client_handle_writable; int n, trigger_fired, client_handle_writable;
/* TODO: handle comparison callback ... */ /* 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 (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */
{ {
if (!(client->status & CLIENT_MUTE) && 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 /* the code here is pretty fragile. there is a high chance
* that something can go wrong if the task handler plays * 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++) for (i = 0; i < QSE_COUNTOF(task->trigger); i++)

View File

@ -74,12 +74,13 @@ struct qse_httpd_t
#define CLIENT_BAD (1 << 0) #define CLIENT_BAD (1 << 0)
#define CLIENT_READY (1 << 1) #define CLIENT_READY (1 << 1)
#define CLIENT_SECURE (1 << 2) #define CLIENT_SECURE (1 << 2)
#define CLIENT_MUTE (1 << 3) #define CLIENT_PENDING (1 << 3)
#define CLIENT_MUTE_DELETED (1 << 4) #define CLIENT_MUTE (1 << 4)
#define CLIENT_HANDLE_READ_IN_MUX (1 << 5) #define CLIENT_MUTE_DELETED (1 << 5)
#define CLIENT_HANDLE_WRITE_IN_MUX (1 << 6) #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_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 #ifdef __cplusplus
extern "C" { extern "C" {

View File

@ -111,7 +111,7 @@ if (qse_htre_getqparam(req))
else else
{ {
task = qse_httpd_entaskcgi ( 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; if (task == QSE_NULL) goto oops;
} }
} }