diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index 6f760edf..6b05d60b 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -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 ); diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h index 9acb7625..f40cfe54 100644 --- a/qse/lib/cmn/syscall.h +++ b/qse/lib/cmn/syscall.h @@ -64,39 +64,39 @@ # include #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) diff --git a/qse/lib/net/httpd-cgi.c b/qse/lib/net/httpd-cgi.c index 2f3503d9..7bc975ba 100644 --- a/qse/lib/net/httpd-cgi.c +++ b/qse/lib/net/httpd-cgi.c @@ -18,11 +18,6 @@ License along with QSE. If not, see . */ -#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) -/* UNSUPPORTED YET.. */ -/* TODO: IMPLEMENT THIS */ -#else - #include "httpd.h" #include "../cmn/mem.h" #include @@ -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 diff --git a/qse/lib/net/httpd-file.c b/qse/lib/net/httpd-file.c index fb732698..9490cd6f 100644 --- a/qse/lib/net/httpd-file.c +++ b/qse/lib/net/httpd-file.c @@ -27,11 +27,14 @@ #include #include /* 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)); diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index c1eb2e30..bf2ad22d 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -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; diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index 71b166d8..e684622a 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -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 diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 07f554ad..b8c5ae35 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -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++) diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index 15787a44..23f6f149 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -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" { diff --git a/qse/samples/net/httpd02.c b/qse/samples/net/httpd02.c index c0a81025..50184018 100644 --- a/qse/samples/net/httpd02.c +++ b/qse/samples/net/httpd02.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; } }