added system call macros for x86 and x86_64 for implementing pio based on vfork
This commit is contained in:
parent
7c224230f2
commit
5a0bd73990
9
qse/configure
vendored
9
qse/configure
vendored
@ -16179,12 +16179,13 @@ _ACEOF
|
||||
fi
|
||||
done
|
||||
|
||||
for ac_func in posix_spawn
|
||||
for ac_func in fork vfork posix_spawn
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
|
||||
if test "x$ac_cv_func_posix_spawn" = xyes; then :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_POSIX_SPAWN 1
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
@ -106,7 +106,7 @@ AC_CHECK_FUNCS([utime utimes])
|
||||
AC_CHECK_FUNCS([sysconf])
|
||||
AC_CHECK_FUNCS([backtrace backtrace_symbols])
|
||||
AC_CHECK_FUNCS([fdopendir])
|
||||
AC_CHECK_FUNCS([posix_spawn])
|
||||
AC_CHECK_FUNCS([fork vfork posix_spawn])
|
||||
|
||||
OLDLIBS="$LIBS"
|
||||
LIBS="$LIBM $LIBS"
|
||||
|
@ -94,6 +94,9 @@
|
||||
/* Define to 1 if you have the `fmodl' function. */
|
||||
#undef HAVE_FMODL
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `fstat64' function. */
|
||||
#undef HAVE_FSTAT64
|
||||
|
||||
@ -321,6 +324,9 @@
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
|
@ -1453,25 +1453,25 @@ void* qse_awk_rtx_getxtnstd (qse_awk_rtx_t* rtx)
|
||||
return (void*)((rxtn_t*)QSE_XTN(rtx) + 1);
|
||||
}
|
||||
|
||||
static int fnc_rand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
|
||||
static int fnc_rand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
|
||||
{
|
||||
qse_awk_val_t* r;
|
||||
|
||||
/*
|
||||
rxtn_t* rxtn;
|
||||
rxtn = (rxtn_t*) QSE_XTN (run);
|
||||
rxtn = (rxtn_t*) QSE_XTN (rtx);
|
||||
r = qse_awk_rtx_makefltval (
|
||||
run, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX );
|
||||
rtx, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX );
|
||||
*/
|
||||
r = qse_awk_rtx_makefltval (
|
||||
run, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX);
|
||||
rtx, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX);
|
||||
if (r == QSE_NULL) return -1;
|
||||
|
||||
qse_awk_rtx_setretval (run, r);
|
||||
qse_awk_rtx_setretval (rtx, r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
|
||||
static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
|
||||
{
|
||||
qse_size_t nargs;
|
||||
qse_awk_val_t* a0;
|
||||
@ -1481,16 +1481,16 @@ static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
|
||||
unsigned int prev;
|
||||
rxtn_t* rxtn;
|
||||
|
||||
rxtn = (rxtn_t*) QSE_XTN (run);
|
||||
nargs = qse_awk_rtx_getnargs (run);
|
||||
rxtn = (rxtn_t*) QSE_XTN (rtx);
|
||||
nargs = qse_awk_rtx_getnargs (rtx);
|
||||
QSE_ASSERT (nargs == 0 || nargs == 1);
|
||||
|
||||
prev = rxtn->seed;
|
||||
|
||||
if (nargs == 1)
|
||||
{
|
||||
a0 = qse_awk_rtx_getarg (run, 0);
|
||||
n = qse_awk_rtx_valtolong (run, a0, &lv);
|
||||
a0 = qse_awk_rtx_getarg (rtx, 0);
|
||||
n = qse_awk_rtx_valtolong (rtx, a0, &lv);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
rxtn->seed = lv;
|
||||
@ -1504,10 +1504,10 @@ static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
|
||||
|
||||
srand (rxtn->seed);
|
||||
|
||||
r = qse_awk_rtx_makeintval (run, prev);
|
||||
r = qse_awk_rtx_makeintval (rtx, prev);
|
||||
if (r == QSE_NULL) return -1;
|
||||
|
||||
qse_awk_rtx_setretval (run, r);
|
||||
qse_awk_rtx_setretval (rtx, r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1572,6 +1572,20 @@ skip_system:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fnc_time (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
|
||||
{
|
||||
qse_awk_val_t* r;
|
||||
qse_ntime_t now;
|
||||
|
||||
if (qse_gettime (&now) <= -1) now = 0;
|
||||
|
||||
r = qse_awk_rtx_makeintval (rtx, now);
|
||||
if (r == QSE_NULL) return -1;
|
||||
|
||||
qse_awk_rtx_setretval (rtx, r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(QSE_CHAR_IS_WCHAR)
|
||||
static qse_cmgr_t* getcmgr_from_cmgrtab (
|
||||
qse_awk_rtx_t* rtx, const qse_char_t* ioname)
|
||||
@ -1707,6 +1721,7 @@ static int add_functions (qse_awk_t* awk)
|
||||
ADDFNC (awk, QSE_T("rand"), 0, 0, fnc_rand, 0);
|
||||
ADDFNC (awk, QSE_T("srand"), 0, 1, fnc_srand, 0);
|
||||
ADDFNC (awk, QSE_T("system"), 1, 1, fnc_system, 0);
|
||||
ADDFNC (awk, QSE_T("time"), 0, 0, fnc_time, 0);
|
||||
#if defined(QSE_CHAR_IS_WCHAR)
|
||||
ADDFNC (awk, QSE_T("setenc"), 2, 2, fnc_setenc, QSE_AWK_RIO);
|
||||
ADDFNC (awk, QSE_T("unsetenc"), 1, 1, fnc_unsetenc, QSE_AWK_RIO);
|
||||
|
@ -550,13 +550,23 @@ int qse_pio_init (
|
||||
|
||||
/* DOS not multi-processed. can't support pio */
|
||||
|
||||
#elif defined(HAVE_POSIX_SPAWN)
|
||||
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
|
||||
posix_spawn_file_actions_t fa;
|
||||
int fa_inited = 0;
|
||||
int pserr;
|
||||
#if defined(__linux)
|
||||
posix_spawnattr_t psattr;
|
||||
#endif
|
||||
qse_pio_pid_t pid;
|
||||
param_t param;
|
||||
extern char** environ;
|
||||
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
|
||||
qse_pio_pid_t pid;
|
||||
param_t param;
|
||||
extern char** environ;
|
||||
char** envarr;
|
||||
int highest_fd;
|
||||
int dummy;
|
||||
#else
|
||||
qse_pio_pid_t pid;
|
||||
param_t param;
|
||||
@ -1178,7 +1188,7 @@ create_process:
|
||||
pio->errnum = QSE_PIO_ENOIMPL;
|
||||
return -1;
|
||||
|
||||
#elif defined(HAVE_POSIX_SPAWN)
|
||||
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
|
||||
if (flags & QSE_PIO_WRITEIN)
|
||||
{
|
||||
if (QSE_PIPE(&handle[0]) <= -1)
|
||||
@ -1379,9 +1389,22 @@ create_process:
|
||||
goto oops;
|
||||
}
|
||||
|
||||
#if defined(__linux)
|
||||
posix_spawnattr_init (&psattr);
|
||||
#if !defined(POSIX_SPAWN_USEVFORK)
|
||||
# define POSIX_SPAWN_USEVFORK 0x40
|
||||
#endif
|
||||
posix_spawnattr_setflags (&psattr, POSIX_SPAWN_USEVFORK);
|
||||
#endif
|
||||
|
||||
pserr = posix_spawn(
|
||||
&pid, param.argv[0], &fa, QSE_NULL, param.argv,
|
||||
&pid, param.argv[0], &fa, &psattr, param.argv,
|
||||
(env? qse_env_getarr(env): environ));
|
||||
|
||||
#if defined(__linux)
|
||||
posix_spawnattr_destroy (&psattr);
|
||||
#endif
|
||||
|
||||
free_param (pio, ¶m);
|
||||
if (fa_inited)
|
||||
{
|
||||
@ -1411,6 +1434,210 @@ create_process:
|
||||
handle[5] = QSE_PIO_HND_NIL;
|
||||
}
|
||||
|
||||
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
|
||||
if (flags & QSE_PIO_WRITEIN)
|
||||
{
|
||||
if (QSE_PIPE(&handle[0]) <= -1)
|
||||
{
|
||||
pio->errnum = syserr_to_errnum (errno);
|
||||
goto oops;
|
||||
}
|
||||
minidx = 0; maxidx = 1;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READOUT)
|
||||
{
|
||||
if (QSE_PIPE(&handle[2]) <= -1)
|
||||
{
|
||||
pio->errnum = syserr_to_errnum (errno);
|
||||
goto oops;
|
||||
}
|
||||
if (minidx == -1) minidx = 2;
|
||||
maxidx = 3;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READERR)
|
||||
{
|
||||
if (QSE_PIPE(&handle[4]) <= -1)
|
||||
{
|
||||
pio->errnum = syserr_to_errnum (errno);
|
||||
goto oops;
|
||||
}
|
||||
if (minidx == -1) minidx = 4;
|
||||
maxidx = 5;
|
||||
}
|
||||
|
||||
if (maxidx == -1)
|
||||
{
|
||||
pio->errnum = QSE_PIO_EINVAL;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (make_param (pio, cmd, flags, ¶m) <= -1) goto oops;
|
||||
|
||||
/* check if the command(the command requested or /bin/sh) is
|
||||
* exectuable to return an error without trying to execute it
|
||||
* though this check alone isn't sufficient */
|
||||
if (assert_executable (pio, param.argv[0]) <= -1)
|
||||
{
|
||||
free_param (pio, ¶m);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (!(flags & QSE_PIO_NOCLOEXEC))
|
||||
highest_fd = get_highest_fd ();
|
||||
envarr = env? qse_env_getarr(env): environ;
|
||||
|
||||
QSE_SYSCALL0 (pid, SYS_vfork);
|
||||
if (pid <= -1)
|
||||
{
|
||||
pio->errnum = QSE_PIO_EINVAL;
|
||||
free_param (pio, ¶m);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
/* child */
|
||||
qse_pio_hnd_t devnull = -1;
|
||||
|
||||
if (!(flags & QSE_PIO_NOCLOEXEC))
|
||||
{
|
||||
int fd = highest_fd;
|
||||
|
||||
/* close all other unknown open handles except
|
||||
* stdin/out/err and the pipes. */
|
||||
while (--fd > 2)
|
||||
{
|
||||
if (fd != handle[0] && fd != handle[1] &&
|
||||
fd != handle[2] && fd != handle[3] &&
|
||||
fd != handle[4] && fd != handle[5])
|
||||
{
|
||||
QSE_SYSCALL1 (dummy, SYS_close, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_WRITEIN)
|
||||
{
|
||||
/* child should read */
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[1]);
|
||||
/*handle[1] = QSE_PIO_HND_NIL;*/
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, handle[0], 0);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[0]);
|
||||
/*handle[0] = QSE_PIO_HND_NIL;*/
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READOUT)
|
||||
{
|
||||
/* child should write */
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[2]);
|
||||
/*handle[2] = QSE_PIO_HND_NIL;*/
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, handle[3], 1);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
|
||||
if (flags & QSE_PIO_ERRTOOUT)
|
||||
{
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, handle[3], 2);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
}
|
||||
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[3]);
|
||||
/*handle[3] = QSE_PIO_HND_NIL;*/
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READERR)
|
||||
{
|
||||
/* child should write */
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[4]);
|
||||
/*handle[4] = QSE_PIO_HND_NIL;*/
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, handle[5], 2);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
|
||||
if (flags & QSE_PIO_OUTTOERR)
|
||||
{
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, handle[5], 1);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
}
|
||||
|
||||
QSE_SYSCALL1 (dummy, SYS_close, handle[5]);
|
||||
/*handle[5] = QSE_PIO_HND_NIL;*/
|
||||
}
|
||||
|
||||
if ((flags & QSE_PIO_INTONUL) ||
|
||||
(flags & QSE_PIO_OUTTONUL) ||
|
||||
(flags & QSE_PIO_ERRTONUL))
|
||||
{
|
||||
#if defined(O_LARGEFILE)
|
||||
QSE_SYSCALL3 (devnull, SYS_open, QSE_MT("/dev/null"), O_RDWR|O_LARGEFILE, 0);
|
||||
#else
|
||||
QSE_SYSCALL3 (devnull, SYS_open, QSE_MT("/dev/null"), O_RDWR, 0);
|
||||
#endif
|
||||
if (devnull <= -1) goto child_oops;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_INTONUL)
|
||||
{
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 0);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
}
|
||||
if (flags & QSE_PIO_OUTTONUL)
|
||||
{
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 1);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
}
|
||||
if (flags & QSE_PIO_ERRTONUL)
|
||||
{
|
||||
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 2);
|
||||
if (dummy <= -1) goto child_oops;
|
||||
}
|
||||
|
||||
if ((flags & QSE_PIO_INTONUL) ||
|
||||
(flags & QSE_PIO_OUTTONUL) ||
|
||||
(flags & QSE_PIO_ERRTONUL))
|
||||
{
|
||||
QSE_SYSCALL1 (dummy, SYS_close, devnull);
|
||||
devnull = -1;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_DROPIN) QSE_SYSCALL1 (dummy, SYS_close, 0);
|
||||
if (flags & QSE_PIO_DROPOUT) QSE_SYSCALL1 (dummy, SYS_close, 1);
|
||||
if (flags & QSE_PIO_DROPERR) QSE_SYSCALL1 (dummy, SYS_close, 2);
|
||||
|
||||
QSE_SYSCALL3 (dummy, SYS_execve, param.argv[0], param.argv, envarr);
|
||||
if (dummy == -1)
|
||||
{
|
||||
printf ("hello\n");
|
||||
}
|
||||
/*free_param (pio, ¶m); */
|
||||
|
||||
child_oops:
|
||||
if (devnull >= 0) QSE_SYSCALL1 (dummy, SYS_close, devnull);
|
||||
QSE_SYSCALL1 (dummy, SYS_exit, 128);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
free_param (pio, ¶m);
|
||||
pio->child = pid;
|
||||
|
||||
if (flags & QSE_PIO_WRITEIN)
|
||||
{
|
||||
QSE_CLOSE (handle[0]);
|
||||
handle[0] = QSE_PIO_HND_NIL;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READOUT)
|
||||
{
|
||||
QSE_CLOSE (handle[3]);
|
||||
handle[3] = QSE_PIO_HND_NIL;
|
||||
}
|
||||
|
||||
if (flags & QSE_PIO_READERR)
|
||||
{
|
||||
QSE_CLOSE (handle[5]);
|
||||
handle[5] = QSE_PIO_HND_NIL;
|
||||
}
|
||||
#else
|
||||
|
||||
if (flags & QSE_PIO_WRITEIN)
|
||||
@ -1485,7 +1712,10 @@ create_process:
|
||||
{
|
||||
if (fd != handle[0] && fd != handle[1] &&
|
||||
fd != handle[2] && fd != handle[3] &&
|
||||
fd != handle[4] && fd != handle[5]) QSE_CLOSE (fd);
|
||||
fd != handle[4] && fd != handle[5])
|
||||
{
|
||||
QSE_CLOSE (fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1703,7 +1933,7 @@ oops:
|
||||
#elif defined(__DOS__)
|
||||
|
||||
/* DOS not multi-processed. can't support pio */
|
||||
#elif defined(HAVE_POSIX_SPAWN)
|
||||
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
|
||||
if (fa_inited)
|
||||
{
|
||||
posix_spawn_file_actions_destroy (&fa);
|
||||
@ -1713,6 +1943,11 @@ oops:
|
||||
{
|
||||
if (handle[i] != QSE_PIO_HND_NIL) QSE_CLOSE (handle[i]);
|
||||
}
|
||||
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
|
||||
for (i = minidx; i < maxidx; i++)
|
||||
{
|
||||
if (handle[i] != QSE_PIO_HND_NIL) QSE_CLOSE (handle[i]);
|
||||
}
|
||||
#else
|
||||
for (i = minidx; i < maxidx; i++)
|
||||
{
|
||||
|
@ -173,6 +173,12 @@
|
||||
# define QSE_FORK() fork()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_vfork)
|
||||
# define QSE_VFORK() syscall(SYS_vfork)
|
||||
#else
|
||||
# define QSE_VFORK() vfork()
|
||||
#endif
|
||||
|
||||
#if defined(SYS_execve)
|
||||
# define QSE_EXECVE(path,argv,envp) syscall(SYS_execve,path,argv,envp)
|
||||
#else
|
||||
@ -349,4 +355,110 @@
|
||||
# define QSE_UTIMES(path,t) utimes(path,t)
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if defined(__linux) && defined(__GNUC__) && defined(__x86_64)
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
/*
|
||||
#define QSE_SYSCALL0(ret,num) \
|
||||
__asm__ volatile ( \
|
||||
"movq %1, %%rax\n\t" \
|
||||
"syscall\n": \
|
||||
"=&a"(ret): \
|
||||
"g"((qse_uint64_t)num): \
|
||||
"%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL1(ret,num,arg1) \
|
||||
__asm__ volatile ( \
|
||||
"movq %1, %%rax\n\t" \
|
||||
"movq %2, %%rdi\n\t" \
|
||||
"syscall\n": \
|
||||
"=&a"(ret): \
|
||||
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1): \
|
||||
"%rdi", "%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
|
||||
__asm__ volatile ( \
|
||||
"movq %1, %%rax\n\t" \
|
||||
"movq %2, %%rdi\n\t" \
|
||||
"movq %3, %%rsi\n\t" \
|
||||
"syscall\n": \
|
||||
"=&a"(ret): \
|
||||
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1), "g"((qse_uint64_t)arg2): \
|
||||
"%rdi", "%rsi", "%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
|
||||
__asm__ volatile ( \
|
||||
"movq %1, %%rax\n\t" \
|
||||
"movq %2, %%rdi\n\t" \
|
||||
"movq %3, %%rsi\n\t" \
|
||||
"movq %4, %%rdx\n\t" \
|
||||
"syscall\n": \
|
||||
"=&a"(ret): \
|
||||
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1), "g"((qse_uint64_t)arg2), "g"((qse_uint64_t)arg3): \
|
||||
"%rdi", "%rsi", "%rdx", "%rcx", "%r11")
|
||||
*/
|
||||
|
||||
#define QSE_SYSCALL0(ret,num) \
|
||||
__asm__ volatile ( \
|
||||
"syscall\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint64_t)num) : \
|
||||
"%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL1(ret,num,arg1) \
|
||||
__asm__ volatile ( \
|
||||
"syscall\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1): \
|
||||
"%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
|
||||
__asm__ volatile ( \
|
||||
"syscall\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1), "S"((qse_uint64_t)arg2): \
|
||||
"%rcx", "%r11")
|
||||
|
||||
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
|
||||
__asm__ volatile ( \
|
||||
"syscall\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1), "S"((qse_uint64_t)arg2), "d"((qse_uint64_t)arg3): \
|
||||
"%rcx", "%r11")
|
||||
|
||||
#elif defined(__linux) && defined(__GNUC__) && defined(__i386)
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define QSE_SYSCALL0(ret,num) \
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint32_t)num))
|
||||
|
||||
#define QSE_SYSCALL1(ret,num,arg1) \
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1))
|
||||
|
||||
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2))
|
||||
|
||||
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n": \
|
||||
"=a"(ret): \
|
||||
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2), "d"((qse_uint32_t)arg3))
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#endif
|
||||
|
@ -1572,8 +1572,8 @@ static int cgi_snatch_content (
|
||||
task = (qse_httpd_task_t*)ctx;
|
||||
cgi = (task_cgi_t*)task->ctx;
|
||||
|
||||
if (ptr) qse_printf (QSE_T("!!!SNATCHING [%.*hs]\n"), len, ptr);
|
||||
else qse_printf (QSE_T("!!!SNATCHING DONE\n"));
|
||||
if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr);
|
||||
else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
|
||||
|
||||
if (ptr == QSE_NULL)
|
||||
{
|
||||
@ -1614,7 +1614,7 @@ else qse_printf (QSE_T("!!!SNATCHING DONE\n"));
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
qse_printf (QSE_T("!!!SNATCHED [%.*hs]\n"), len, ptr);
|
||||
qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1800,8 +1800,10 @@ done:
|
||||
cgi->env = makecgienv (httpd, client, arg->req, arg->path, content_length);
|
||||
if (cgi->env == QSE_NULL) goto oops;
|
||||
|
||||
/* i don't set triggers yet. triggers will be set task_main_cgi().
|
||||
* this way, task_main_cgi() is called regardless of data availability */
|
||||
/* no triggers yet since the main loop doesn't allow me to set
|
||||
* triggers in the task initializer. however the main task handler
|
||||
* will be invoked so long as the client handle is writable by
|
||||
* the main loop. */
|
||||
|
||||
task->ctx = cgi;
|
||||
return 0;
|
||||
@ -2349,10 +2351,278 @@ qse_httpd_task_t* qse_httpd_entasknph (
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
typedef struct task_proxy_arg_t task_proxy_arg_t;
|
||||
struct task_proxy_arg_t
|
||||
{
|
||||
const qse_mchar_t* host;
|
||||
qse_htre_t* req;
|
||||
int nph;
|
||||
};
|
||||
|
||||
typedef struct task_proxy_t task_proxy_t;
|
||||
struct task_proxy_t
|
||||
{
|
||||
int init_failed;
|
||||
|
||||
const qse_mchar_t* host;
|
||||
qse_http_version_t version;
|
||||
int keepalive; /* taken from the request */
|
||||
|
||||
qse_htrd_t* htrd;
|
||||
|
||||
qse_htre_t* req; /* original request associated with this */
|
||||
qse_mbs_t* reqfwdbuf; /* content from the request */
|
||||
int reqfwderr;
|
||||
|
||||
qse_mbs_t* res;
|
||||
qse_mchar_t* res_ptr;
|
||||
qse_size_t res_left;
|
||||
};
|
||||
|
||||
typedef struct proxy_htrd_xtn_t proxy_htrd_xtn_t;
|
||||
struct proxy_htrd_xtn_t
|
||||
{
|
||||
task_proxy_t* proxy;
|
||||
};
|
||||
|
||||
static int proxy_snatch_content (
|
||||
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
|
||||
{
|
||||
qse_httpd_task_t* task;
|
||||
task_proxy_t* proxy;
|
||||
|
||||
task = (qse_httpd_task_t*)ctx;
|
||||
proxy = (task_proxy_t*)task->ctx;
|
||||
|
||||
if (ptr) qse_printf (QSE_T("!!!PROXY SNATCHING [%.*hs]\n"), len, ptr);
|
||||
else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
|
||||
|
||||
if (ptr == QSE_NULL)
|
||||
{
|
||||
/*
|
||||
* this callback is called with ptr of QSE_NULL
|
||||
* when the request is completed or discarded.
|
||||
* and this indicates that there's nothing more to read
|
||||
* from the client side. this can happen when the end of
|
||||
* a request is seen or when an error occurs
|
||||
*/
|
||||
QSE_ASSERT (len == 0);
|
||||
|
||||
/* mark the there's nothing to read form the client side */
|
||||
proxy->req = QSE_NULL;
|
||||
|
||||
/* since there is no more to read from the client side.
|
||||
* the relay trigger is not needed any more. */
|
||||
task->trigger[2].mask = 0;
|
||||
|
||||
#if 0
|
||||
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0 && proxy->pio_inited &&
|
||||
!(task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITE))
|
||||
{
|
||||
/* there's nothing more to read from the client side.
|
||||
* there's something to forward in the forwarding buffer.
|
||||
* but no write trigger is set. add the write trigger
|
||||
* for task invocation. */
|
||||
task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
task->trigger[1].handle = qse_pio_gethandleasubi (&proxy->pio, QSE_PIO_IN);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (!proxy->reqfwderr)
|
||||
{
|
||||
/* we can write to the child process if a forwarding error
|
||||
* didn't occur previously. we store data from the client side
|
||||
* to the forwaring buffer only if there's no such previous
|
||||
* error. if an error occurred, we simply drop the data. */
|
||||
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proxy_htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static qse_htrd_recbs_t proxy_htrd_cbs =
|
||||
{
|
||||
proxy_htrd_peek_request,
|
||||
QSE_NULL /* not needed for proxy */
|
||||
};
|
||||
|
||||
static int task_init_proxy (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_proxy_t* proxy;
|
||||
task_proxy_arg_t* arg;
|
||||
qse_size_t content_length;
|
||||
qse_size_t len;
|
||||
const qse_mchar_t* ptr;
|
||||
|
||||
proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task);
|
||||
arg = (task_proxy_arg_t*)task->ctx;
|
||||
|
||||
/* TODO: can content length be a different type???
|
||||
* maybe qse_uintmax_t.... it thinks the data size can be larger than the max pointer size
|
||||
* qse_htre_t and qse_htrd_t also needs changes to support it
|
||||
*/
|
||||
|
||||
QSE_MEMSET (proxy, 0, QSE_SIZEOF(*proxy));
|
||||
qse_mbscpy ((qse_mchar_t*)(proxy + 1), arg->host);
|
||||
proxy->host = (qse_mchar_t*)(proxy + 1);
|
||||
proxy->version = *qse_htre_getversion(arg->req);
|
||||
proxy->keepalive = arg->req->attr.keepalive;
|
||||
|
||||
if (arg->req->state & QSE_HTRE_DISCARDED)
|
||||
{
|
||||
qse_printf (QSE_T("XXXXXXXXXXXXXXXXX\n"));
|
||||
content_length = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
len = qse_htre_getcontentlen(arg->req);
|
||||
if ((arg->req->state & QSE_HTRE_COMPLETED) && len <= 0)
|
||||
{
|
||||
qse_printf (QSE_T("YYYYYYYYYYYYYYYYy\n"));
|
||||
/* the content part is completed and no content
|
||||
* in the content buffer. there is nothing to forward */
|
||||
content_length = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(arg->req->state & QSE_HTRE_COMPLETED) &&
|
||||
!arg->req->attr.content_length_set)
|
||||
{
|
||||
qse_printf (QSE_T("ZZZZZZZZZZZZZZZ\n"));
|
||||
/* if the request is not completed and doesn't have
|
||||
* content-length set, it's not really possible to
|
||||
* pass the content. this function, however, allows
|
||||
* such a request to entask a proxy script dropping the
|
||||
* content */
|
||||
qse_htre_discardcontent (arg->req);
|
||||
content_length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create a buffer to hold request content from the client
|
||||
* and copy content received already */
|
||||
proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
|
||||
if (proxy->reqfwdbuf == QSE_NULL) goto oops;
|
||||
|
||||
ptr = qse_htre_getcontentptr(arg->req);
|
||||
if (qse_mbs_ncpy (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
|
||||
{
|
||||
qse_mbs_close (proxy->reqfwdbuf);
|
||||
proxy->reqfwdbuf = QSE_NULL;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (arg->req->state & QSE_HTRE_COMPLETED)
|
||||
{
|
||||
/* no furthur forwarding is needed.
|
||||
* even a chunked request entaksed when completed
|
||||
* should reach here. if content-length is set
|
||||
* the length should match len. */
|
||||
QSE_ASSERT (len > 0);
|
||||
QSE_ASSERT (!arg->req->attr.content_length_set ||
|
||||
(arg->req->attr.content_length_set && arg->req->attr.content_length == len));
|
||||
qse_printf (QSE_T("HHHHHHHHHHHHHHHHhh %d\n"), (int)len);
|
||||
content_length = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CGI entasking is invoked probably from the peek handler
|
||||
* that was triggered after the request header is received.
|
||||
* you can know this because the request is not completed.
|
||||
* In this case, arrange to forward content
|
||||
* bypassing the buffer in the request object itself. */
|
||||
|
||||
/* TODO: callback chain instead of a single pointer???
|
||||
if the request is already set up with a callback, something will go wrong.
|
||||
*/
|
||||
/* set up a callback to be called when the request content
|
||||
* is fed to the htrd reader. qse_htre_addcontent() that
|
||||
* htrd calls invokes this callback. */
|
||||
proxy->req = arg->req;
|
||||
qse_htre_setconcb (proxy->req, proxy_snatch_content, task);
|
||||
|
||||
QSE_ASSERT (arg->req->attr.content_length_set);
|
||||
content_length = arg->req->attr.content_length;
|
||||
qse_printf (QSE_T("TTTTTTTTTTTTTTTTTTTT %d\n"), (int)content_length);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* no triggers yet since the main loop doesn't allow me to set
|
||||
* triggers in the task initializer. however the main task handler
|
||||
* will be invoked so long as the client handle is writable by
|
||||
* the main loop. */
|
||||
|
||||
task->ctx = proxy;
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
/* since a new task can't be added in the initializer,
|
||||
* i mark that initialization failed and let task_main_proxy()
|
||||
* add an error task */
|
||||
proxy->init_failed = 1;
|
||||
task->ctx = proxy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_fini_proxy (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
}
|
||||
|
||||
static int task_main_proxy (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
|
||||
proxy_htrd_xtn_t* xtn;
|
||||
int http_errnum = 500;
|
||||
|
||||
if (proxy->init_failed) goto oops;
|
||||
|
||||
proxy->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(proxy_htrd_xtn_t));
|
||||
if (proxy->htrd == QSE_NULL) goto oops;
|
||||
xtn = (proxy_htrd_xtn_t*) qse_htrd_getxtn (proxy->htrd);
|
||||
xtn->proxy = proxy;
|
||||
qse_htrd_setrecbs (proxy->htrd, &proxy_htrd_cbs);
|
||||
qse_htrd_setoption (
|
||||
proxy->htrd,
|
||||
QSE_HTRD_SKIPINITIALLINE |
|
||||
QSE_HTRD_PEEKONLY |
|
||||
QSE_HTRD_REQUEST
|
||||
);
|
||||
|
||||
proxy->res = qse_mbs_open (httpd->mmgr, 0, 256);
|
||||
if (proxy->res == QSE_NULL) goto oops;
|
||||
|
||||
///////////////////////
|
||||
|
||||
return 1;
|
||||
|
||||
oops:
|
||||
if (proxy->res)
|
||||
{
|
||||
qse_mbs_close (proxy->res);
|
||||
proxy->res = QSE_NULL;
|
||||
}
|
||||
if (proxy->htrd)
|
||||
{
|
||||
qse_htrd_close (proxy->htrd);
|
||||
proxy->htrd = QSE_NULL;
|
||||
}
|
||||
|
||||
return (entask_error (
|
||||
httpd, client, task, http_errnum,
|
||||
&proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskproxy (
|
||||
@ -2362,9 +2632,23 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
|
||||
const qse_mchar_t* host,
|
||||
const qse_htre_t* req)
|
||||
{
|
||||
|
||||
qse_httpd_task_t task;
|
||||
task_proxy_arg_t arg;
|
||||
|
||||
arg.host = host;
|
||||
arg.req = req;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_proxy;
|
||||
task.fini = task_fini_proxy;
|
||||
task.main = task_main_proxy;
|
||||
task.ctx = &arg;
|
||||
|
||||
return qse_httpd_entask (
|
||||
httpd, client, pred, &task,
|
||||
QSE_SIZEOF(task_proxy_t) + ((qse_mbslen(host) + 1) * QSE_SIZEOF(*host))
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -775,10 +775,6 @@ static int invoke_client_task (
|
||||
}
|
||||
}
|
||||
|
||||
/* locate an active client to the tail of the client list */
|
||||
qse_gettime (&client->last_active); /* TODO: error check??? */
|
||||
move_client_to_tail (httpd, client);
|
||||
|
||||
n = task->main (httpd, client, task);
|
||||
qse_printf (QSE_T("task returend %d\n"), n);
|
||||
if (n <= -1) return -1;
|
||||
@ -943,6 +939,10 @@ static int perform_client_task (
|
||||
}
|
||||
else
|
||||
{
|
||||
/* locate an active client to the tail of the client list */
|
||||
qse_gettime (&client->last_active); /* TODO: error check??? */
|
||||
move_client_to_tail (httpd, client);
|
||||
|
||||
if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops;
|
||||
}
|
||||
|
||||
|
@ -430,10 +430,6 @@ struct mux_t
|
||||
struct mux_ev_t* ptr;
|
||||
qse_size_t capa;
|
||||
} mev;
|
||||
|
||||
#if 0
|
||||
qse_fma_t* fma;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MUX_EV_ALIGN 64
|
||||
@ -455,13 +451,6 @@ static void* mux_open (qse_httpd_t* httpd)
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
mux->fma = qse_fma_open (qse_getmmgr(httpd), QSE_NULL);
|
||||
if (mux->fma == QSE_NULL)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
return mux;
|
||||
}
|
||||
|
||||
@ -486,28 +475,22 @@ static int mux_addhnd (
|
||||
if (mask & QSE_HTTPD_MUX_READ) ev.events |= EPOLLIN;
|
||||
if (mask & QSE_HTTPD_MUX_WRITE) ev.events |= EPOLLOUT;
|
||||
|
||||
if (ev.events == 0)
|
||||
if (ev.events == 0 || handle.i <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
mev = qse_httpd_allocmem (httpd, QSE_SIZEOF(*mev));
|
||||
if (mev == QSE_NULL) return -1;
|
||||
#endif
|
||||
|
||||
if (handle.i >= mux->mev.capa)
|
||||
{
|
||||
struct mux_ev_t* tmp;
|
||||
qse_size_t tmpcapa;
|
||||
|
||||
tmpcapa = (((handle.i + MUX_EV_ALIGN - 1) / MUX_EV_ALIGN) * MUX_EV_ALIGN) + 1;
|
||||
|
||||
tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN);
|
||||
|
||||
/* TODO: allocate this from fma ... */
|
||||
tmp = qse_httpd_reallocmem (
|
||||
httpd, mux->mev.ptr,
|
||||
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa); /* TODO: round up handle.i ... */
|
||||
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa);
|
||||
if (tmp == QSE_NULL) return -1;
|
||||
|
||||
mux->mev.ptr = tmp;
|
||||
@ -521,11 +504,7 @@ static int mux_addhnd (
|
||||
tmp = qse_httpd_reallocmem (
|
||||
httpd, mux->ee.ptr,
|
||||
QSE_SIZEOF(*mux->ee.ptr) * (mux->ee.capa + 1) * 2);
|
||||
if (tmp == QSE_NULL)
|
||||
{
|
||||
/*qse_httpd_freemem (httpd, mev);*/
|
||||
return -1;
|
||||
}
|
||||
if (tmp == QSE_NULL) return -1;
|
||||
|
||||
mux->ee.ptr = tmp;
|
||||
mux->ee.capa = (mux->ee.capa + 1) * 2;
|
||||
@ -544,7 +523,6 @@ static int mux_addhnd (
|
||||
{
|
||||
/* don't rollback ee.ptr */
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
/*qse_httpd_freemem (httpd, mev);*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -556,8 +534,6 @@ static int mux_delhnd (qse_httpd_t* httpd, void* vmux, qse_ubi_t handle)
|
||||
{
|
||||
struct mux_t* mux = (struct mux_t*)vmux;
|
||||
|
||||
/* TODO: delete mev associated with handle.i */
|
||||
|
||||
if (epoll_ctl (mux->fd, EPOLL_CTL_DEL, handle.i, QSE_NULL) <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
@ -597,8 +573,6 @@ static int mux_poll (qse_httpd_t* httpd, void* vmux, qse_ntime_t timeout)
|
||||
}
|
||||
|
||||
mev->cbfun (httpd, mux, mev->handle, mask, mev->cbarg);
|
||||
|
||||
//if (cbfun fails and the client is deleted???) other pending events should also be dropped???
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -971,7 +945,6 @@ if (qse_htre_getcontentlen(req) > 0)
|
||||
qse_printf (QSE_T("CONTENT after discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
|
||||
}
|
||||
|
||||
|
||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||
{
|
||||
const qse_mchar_t* qpath = qse_htre_getqpathptr(req);
|
||||
@ -1089,6 +1062,80 @@ oops:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int proxy_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek)
|
||||
{
|
||||
const qse_mchar_t* qpath;
|
||||
|
||||
qpath = qse_htre_qpathptr (eq);
|
||||
if (qpath[0] == QSE_MT('/'))
|
||||
{
|
||||
host = qse_htre_getheaderval (req, QSE_MT("Host"));
|
||||
if (host == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("Host not included....\n"));
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const qse_mchar_t* host;
|
||||
qse_parseuri ();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
if (peek)
|
||||
{
|
||||
if (req->attr.expect &&
|
||||
(req->version.major > 1 ||
|
||||
(req->version.major == 1 && req->version.minor >= 1)) &&
|
||||
!content_received)
|
||||
{
|
||||
/* TODO: check method.... */
|
||||
/* "expect" in the header, version 1.1 or higher,
|
||||
* and no content received yet */
|
||||
|
||||
if (qse_mbscasecmp(req->attr.expect, QSE_MT("100-continue")) != 0)
|
||||
{
|
||||
if (qse_httpd_entaskerror (
|
||||
httpd, client, QSE_NULL, 417, req) == QSE_NULL) return -1;
|
||||
if (qse_httpd_entaskdisconnect (
|
||||
httpd, client, QSE_NULL) == QSE_NULL) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: determine if to return 100-continue or other errors */
|
||||
if (qse_httpd_entaskcontinue (
|
||||
httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (qse_htre_getqparamlen(req) > 0) qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparamptr(req));
|
||||
|
||||
|
||||
task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
|
||||
if (!req->attr.keepalive)
|
||||
{
|
||||
if (!peek)
|
||||
{
|
||||
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int peek_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user