added qse_httpd_entasknph()
enhanced qse_pio_t with posix_spawn()
This commit is contained in:
parent
7a7127b89f
commit
a782229fa2
26
qse/configure
vendored
26
qse/configure
vendored
@ -16000,7 +16000,20 @@ fi
|
|||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
for ac_header in time.h sys/time.h utime.h sys/resource.h sys/syscall.h sys/sendfile.h
|
for ac_header in time.h sys/time.h utime.h spawn.h
|
||||||
|
do :
|
||||||
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
|
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||||
|
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
for ac_header in sys/resource.h sys/syscall.h sys/sendfile.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||||
@ -16164,6 +16177,17 @@ _ACEOF
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for ac_func in 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 :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_POSIX_SPAWN 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
OLDLIBS="$LIBS"
|
OLDLIBS="$LIBS"
|
||||||
LIBS="$LIBM $LIBS"
|
LIBS="$LIBM $LIBS"
|
||||||
|
@ -79,7 +79,8 @@ AC_SUBST(LIBM, $LIBM)
|
|||||||
dnl check header files.
|
dnl check header files.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h])
|
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h])
|
||||||
AC_CHECK_HEADERS([time.h sys/time.h utime.h sys/resource.h sys/syscall.h sys/sendfile.h])
|
AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h])
|
||||||
|
AC_CHECK_HEADERS([sys/resource.h sys/syscall.h sys/sendfile.h])
|
||||||
AC_CHECK_HEADERS([execinfo.h])
|
AC_CHECK_HEADERS([execinfo.h])
|
||||||
|
|
||||||
dnl check data types
|
dnl check data types
|
||||||
@ -101,6 +102,7 @@ AC_CHECK_FUNCS([utime utimes])
|
|||||||
AC_CHECK_FUNCS([sysconf])
|
AC_CHECK_FUNCS([sysconf])
|
||||||
AC_CHECK_FUNCS([backtrace backtrace_symbols])
|
AC_CHECK_FUNCS([backtrace backtrace_symbols])
|
||||||
AC_CHECK_FUNCS([fdopendir])
|
AC_CHECK_FUNCS([fdopendir])
|
||||||
|
AC_CHECK_FUNCS([posix_spawn])
|
||||||
|
|
||||||
OLDLIBS="$LIBS"
|
OLDLIBS="$LIBS"
|
||||||
LIBS="$LIBM $LIBS"
|
LIBS="$LIBM $LIBS"
|
||||||
|
@ -154,6 +154,9 @@
|
|||||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||||
#undef HAVE_NDIR_H
|
#undef HAVE_NDIR_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `posix_spawn' function. */
|
||||||
|
#undef HAVE_POSIX_SPAWN
|
||||||
|
|
||||||
/* Define to 1 if you have the `pow' function. */
|
/* Define to 1 if you have the `pow' function. */
|
||||||
#undef HAVE_POW
|
#undef HAVE_POW
|
||||||
|
|
||||||
@ -205,6 +208,9 @@
|
|||||||
/* Define it socklen_t typedef is in sys/socket.h. */
|
/* Define it socklen_t typedef is in sys/socket.h. */
|
||||||
#undef HAVE_SOCKLEN_T
|
#undef HAVE_SOCKLEN_T
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <spawn.h> header file. */
|
||||||
|
#undef HAVE_SPAWN_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `sqrt' function. */
|
/* Define to 1 if you have the `sqrt' function. */
|
||||||
#undef HAVE_SQRT
|
#undef HAVE_SQRT
|
||||||
|
|
||||||
|
@ -232,6 +232,14 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
|
|||||||
const qse_htre_t* req
|
const qse_htre_t* req
|
||||||
);
|
);
|
||||||
|
|
||||||
|
qse_httpd_task_t* qse_httpd_entasknph (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
const qse_httpd_task_t* pred,
|
||||||
|
const qse_mchar_t* path,
|
||||||
|
const qse_htre_t* req
|
||||||
|
);
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
void* qse_httpd_allocmem (
|
void* qse_httpd_allocmem (
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
# include "syscall.h"
|
# include "syscall.h"
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
|
# if defined(HAVE_SPAWN_H)
|
||||||
|
# include <spawn.h>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (pio)
|
QSE_IMPLEMENT_COMMON_FUNCTIONS (pio)
|
||||||
@ -67,6 +70,254 @@ void qse_pio_close (qse_pio_t* pio)
|
|||||||
QSE_MMGR_FREE (pio->mmgr, pio);
|
QSE_MMGR_FREE (pio->mmgr, pio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__)
|
||||||
|
struct param_t
|
||||||
|
{
|
||||||
|
qse_mchar_t* mcmd;
|
||||||
|
qse_mchar_t* fixed_argv[4];
|
||||||
|
qse_mchar_t** argv;
|
||||||
|
|
||||||
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
|
/* nothign extra */
|
||||||
|
#else
|
||||||
|
qse_mchar_t fixed_mbuf[64];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
typedef struct param_t param_t;
|
||||||
|
|
||||||
|
static void free_param (qse_pio_t* pio, param_t* param)
|
||||||
|
{
|
||||||
|
if (param->argv && param->argv != param->fixed_argv)
|
||||||
|
QSE_MMGR_FREE (pio->mmgr, param->argv);
|
||||||
|
if (param->mcmd) QSE_MMGR_FREE (pio->mmgr, param->mcmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_param (
|
||||||
|
qse_pio_t* pio, const qse_char_t* cmd, int flags, param_t* param)
|
||||||
|
{
|
||||||
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
|
qse_mchar_t* mcmd = QSE_NULL;
|
||||||
|
#else
|
||||||
|
qse_mchar_t* mcmd = QSE_NULL;
|
||||||
|
qse_char_t* wcmd = QSE_NULL;
|
||||||
|
#endif
|
||||||
|
int fcnt = 0;
|
||||||
|
|
||||||
|
QSE_MEMSET (param, 0, QSE_SIZEOF(*param));
|
||||||
|
|
||||||
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
|
if (flags & QSE_PIO_SHELL) mcmd = (qse_char_t*)cmd;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mcmd = qse_strdup (cmd, pio->mmgr);
|
||||||
|
if (mcmd == QSE_NULL)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_ENOMEM;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcnt = qse_strspl (mcmd, QSE_T(""),
|
||||||
|
QSE_T('\"'), QSE_T('\"'), QSE_T('\\'));
|
||||||
|
if (fcnt <= 0)
|
||||||
|
{
|
||||||
|
/* no field or an error */
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (flags & QSE_PIO_MBSCMD)
|
||||||
|
{
|
||||||
|
/* the cmd is flagged to be of qse_mchar_t
|
||||||
|
* while the default character type is qse_wchar_t. */
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_SHELL) mcmd = (qse_mchar_t*)cmd;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mcmd = qse_mbsdup ((const qse_mchar_t*)cmd, pio->mmgr);
|
||||||
|
if (mcmd == QSE_NULL)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_ENOMEM;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcnt = qse_mbsspl (mcmd, QSE_MT(""),
|
||||||
|
QSE_MT('\"'), QSE_MT('\"'), QSE_MT('\\'));
|
||||||
|
if (fcnt <= 0)
|
||||||
|
{
|
||||||
|
/* no field or an error */
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qse_size_t n, mn, wl;
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_SHELL)
|
||||||
|
{
|
||||||
|
if (qse_wcstombs (cmd, &wl, QSE_NULL, &mn) <= -1)
|
||||||
|
{
|
||||||
|
/* cmd has illegal sequence */
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wcmd = qse_strdup (cmd, pio->mmgr);
|
||||||
|
if (wcmd == QSE_NULL)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_ENOMEM;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcnt = qse_strspl (wcmd, QSE_T(""),
|
||||||
|
QSE_T('\"'), QSE_T('\"'), QSE_T('\\'));
|
||||||
|
if (fcnt <= 0)
|
||||||
|
{
|
||||||
|
/* no field or an error */
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate the length of the string after splitting */
|
||||||
|
for (wl = 0, n = fcnt; n > 0; )
|
||||||
|
{
|
||||||
|
if (wcmd[wl++] == QSE_T('\0')) n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qse_wcsntombsn (wcmd, &wl, QSE_NULL, &mn) <= -1)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare to reserve 1 more slot for the terminating '\0'
|
||||||
|
* by incrementing mn by 1. */
|
||||||
|
mn = mn + 1;
|
||||||
|
|
||||||
|
if (mn <= QSE_COUNTOF(param->fixed_mbuf))
|
||||||
|
{
|
||||||
|
mcmd = param->fixed_mbuf;
|
||||||
|
mn = QSE_COUNTOF(param->fixed_mbuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mcmd = QSE_MMGR_ALLOC (pio->mmgr, mn * QSE_SIZEOF(*mcmd));
|
||||||
|
if (mcmd == QSE_NULL)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_ENOMEM;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_SHELL)
|
||||||
|
{
|
||||||
|
QSE_ASSERT (wcmd == QSE_NULL);
|
||||||
|
/* qse_wcstombs() should succeed as
|
||||||
|
* it was successful above */
|
||||||
|
qse_wcstombs (cmd, &wl, mcmd, &mn);
|
||||||
|
/* qse_wcstombs() null-terminate mcmd */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QSE_ASSERT (wcmd != QSE_NULL);
|
||||||
|
/* qse_wcsntombsn() should succeed as
|
||||||
|
* it was was successful above */
|
||||||
|
qse_wcsntombsn (wcmd, &wl, mcmd, &mn);
|
||||||
|
/* qse_wcsntombsn() doesn't null-terminate mcmd */
|
||||||
|
mcmd[mn] = QSE_MT('\0');
|
||||||
|
|
||||||
|
QSE_MMGR_FREE (pio->mmgr, wcmd);
|
||||||
|
wcmd = QSE_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_SHELL)
|
||||||
|
{
|
||||||
|
param->argv = param->fixed_argv;
|
||||||
|
param->argv[0] = QSE_MT("/bin/sh");
|
||||||
|
param->argv[1] = QSE_MT("-c");
|
||||||
|
param->argv[2] = mcmd;
|
||||||
|
param->argv[3] = QSE_NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
qse_mchar_t** argv;
|
||||||
|
qse_mchar_t* mcmdptr;
|
||||||
|
|
||||||
|
param->argv = QSE_MMGR_ALLOC (
|
||||||
|
pio->mmgr, (fcnt + 1) * QSE_SIZEOF(argv[0]));
|
||||||
|
if (param->argv == QSE_NULL)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_ENOMEM;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
mcmdptr = mcmd;
|
||||||
|
for (i = 0; i < fcnt; i++)
|
||||||
|
{
|
||||||
|
param->argv[i] = mcmdptr;
|
||||||
|
while (*mcmdptr != QSE_MT('\0')) mcmdptr++;
|
||||||
|
mcmdptr++;
|
||||||
|
}
|
||||||
|
param->argv[i] = QSE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
|
if (mcmd && mcmd != cmd) param->mcmd = mcmd;
|
||||||
|
#else
|
||||||
|
if (mcmd && mcmd != cmd && mcmd != param->fixed_mbuf) param->mcmd = mcmd;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
oops:
|
||||||
|
#if defined(QSE_CHAR_IS_MCHAR)
|
||||||
|
if (mcmd && mcmd != cmd) QSE_MMGR_FREE (pio->mmgr, mcmd);
|
||||||
|
#else
|
||||||
|
if (mcmd && mcmd != cmd && mcmd != param->fixed_mbuf) QSE_MMGR_FREE (pio->mmgr, mcmd);
|
||||||
|
if (wcmd) QSE_MMGR_FREE (pio->mmgr, wcmd);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QSE_INLINE int is_fd_valid (int fd)
|
||||||
|
{
|
||||||
|
return fcntl (fd, F_GETFL) != -1 || errno != EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_highest_fd (void)
|
||||||
|
{
|
||||||
|
/* TODO: consider if reading from /proc/self/fd is
|
||||||
|
* a better idea. */
|
||||||
|
struct rlimit rlim;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
#if defined(F_MAXFD)
|
||||||
|
fd = fcntl (0, F_MAXFD);
|
||||||
|
#endif
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) <= -1 ||
|
||||||
|
rlim.rlim_max == RLIM_INFINITY)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_SYSCONF)
|
||||||
|
fd = sysconf (_SC_OPEN_MAX);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else fd = rlim.rlim_max;
|
||||||
|
}
|
||||||
|
if (fd == -1) fd = 1024; /* fallback */
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int qse_pio_init (
|
int qse_pio_init (
|
||||||
qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd,
|
qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd,
|
||||||
qse_env_t* env, int flags)
|
qse_env_t* env, int flags)
|
||||||
@ -113,8 +364,17 @@ int qse_pio_init (
|
|||||||
|
|
||||||
/* DOS not multi-processed. can't support pio */
|
/* DOS not multi-processed. can't support pio */
|
||||||
|
|
||||||
|
#elif defined(HAVE_POSIX_SPAWN)
|
||||||
|
posix_spawn_file_actions_t fa;
|
||||||
|
int fa_inited = 0;
|
||||||
|
int spawn_ret;
|
||||||
|
qse_pio_pid_t pid;
|
||||||
|
param_t param;
|
||||||
|
extern char** environ;
|
||||||
#else
|
#else
|
||||||
qse_pio_pid_t pid;
|
qse_pio_pid_t pid;
|
||||||
|
param_t param;
|
||||||
|
extern char** environ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QSE_MEMSET (pio, 0, QSE_SIZEOF(*pio));
|
QSE_MEMSET (pio, 0, QSE_SIZEOF(*pio));
|
||||||
@ -618,6 +878,137 @@ int qse_pio_init (
|
|||||||
/* DOS not multi-processed. can't support pio */
|
/* DOS not multi-processed. can't support pio */
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#elif defined(HAVE_POSIX_SPAWN)
|
||||||
|
if (flags & QSE_PIO_WRITEIN)
|
||||||
|
{
|
||||||
|
if (QSE_PIPE(&handle[0]) <= -1) goto oops;
|
||||||
|
minidx = 0; maxidx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_READOUT)
|
||||||
|
{
|
||||||
|
if (QSE_PIPE(&handle[2]) <= -1) goto oops;
|
||||||
|
if (minidx == -1) minidx = 2;
|
||||||
|
maxidx = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_READERR)
|
||||||
|
{
|
||||||
|
if (QSE_PIPE(&handle[4]) <= -1) goto oops;
|
||||||
|
if (minidx == -1) minidx = 4;
|
||||||
|
maxidx = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxidx == -1)
|
||||||
|
{
|
||||||
|
pio->errnum = QSE_PIO_EINVAL;
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posix_spawn_file_actions_init (&fa) != 0) goto oops;
|
||||||
|
fa_inited = 1;
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_WRITEIN)
|
||||||
|
{
|
||||||
|
/* child should read */
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[1]) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_adddup2 (&fa, handle[0], 0) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[0]) != 0) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_READOUT)
|
||||||
|
{
|
||||||
|
/* child should write */
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[2]) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_adddup2 (&fa, handle[3], 1) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_ERRTOOUT) &&
|
||||||
|
posix_spawn_file_actions_adddup2 (&fa, handle[3], 2) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[3]) != 0) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & QSE_PIO_READERR)
|
||||||
|
{
|
||||||
|
/* child should write */
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[4]) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_adddup2 (&fa, handle[5], 2) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_OUTTOERR) &&
|
||||||
|
posix_spawn_file_actions_adddup2 (&fa, handle[5], 1) != 0) goto oops;
|
||||||
|
if (posix_spawn_file_actions_addclose (&fa, handle[5]) != 0) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int oflags = O_RDWR;
|
||||||
|
#if defined(O_LARGEFILE)
|
||||||
|
oflags |= O_LARGEFILE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((flags & QSE_PIO_INTONUL) &&
|
||||||
|
posix_spawn_file_actions_addopen (&fa, 0, QSE_MT("/dev/null"), oflags, 0) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_OUTTONUL) &&
|
||||||
|
posix_spawn_file_actions_addopen (&fa, 1, QSE_MT("/dev/null"), oflags, 0) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_ERRTONUL) &&
|
||||||
|
posix_spawn_file_actions_addopen (&fa, 2, QSE_MT("/dev/null"), oflags, 0) != 0) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* there remains the chance of race condition that
|
||||||
|
* 0, 1, 2 can be closed between addclose() and posix_spawn().
|
||||||
|
* so checking the file descriptors with is_fd_valid() is
|
||||||
|
* just on the best-effort basis.
|
||||||
|
*/
|
||||||
|
if ((flags & QSE_PIO_DROPIN) && is_fd_valid(0) &&
|
||||||
|
posix_spawn_file_actions_addclose (&fa, 0) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_DROPOUT) && is_fd_valid(1) &&
|
||||||
|
posix_spawn_file_actions_addclose (&fa, 1) != 0) goto oops;
|
||||||
|
if ((flags & QSE_PIO_DROPERR) && is_fd_valid(2) &&
|
||||||
|
posix_spawn_file_actions_addclose (&fa, 2) != 0) goto oops;
|
||||||
|
|
||||||
|
{
|
||||||
|
int fd = get_highest_fd ();
|
||||||
|
while (--fd > 2)
|
||||||
|
{
|
||||||
|
if (fd != handle[0] &&
|
||||||
|
fd != handle[1] &&
|
||||||
|
fd != handle[2] &&
|
||||||
|
fd != handle[3] &&
|
||||||
|
fd != handle[4] &&
|
||||||
|
fd != handle[5])
|
||||||
|
{
|
||||||
|
/* closing attempt on a best-effort basis */
|
||||||
|
if (is_fd_valid(fd) &&
|
||||||
|
posix_spawn_file_actions_addclose (&fa, fd) != 0) goto oops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (make_param (pio, cmd, flags, ¶m) <= -1) goto oops;
|
||||||
|
spawn_ret = posix_spawn(
|
||||||
|
&pid, param.argv[0], &fa, QSE_NULL, param.argv,
|
||||||
|
(env? qse_env_getarr(env): environ));
|
||||||
|
free_param (pio, ¶m);
|
||||||
|
if (fa_inited)
|
||||||
|
{
|
||||||
|
posix_spawn_file_actions_destroy (&fa);
|
||||||
|
fa_inited = 0;
|
||||||
|
}
|
||||||
|
if (spawn_ret != 0) goto oops;
|
||||||
|
|
||||||
|
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
|
#else
|
||||||
|
|
||||||
if (flags & QSE_PIO_WRITEIN)
|
if (flags & QSE_PIO_WRITEIN)
|
||||||
@ -652,31 +1043,10 @@ int qse_pio_init (
|
|||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
{
|
{
|
||||||
/* child */
|
/* child */
|
||||||
|
qse_pio_hnd_t devnull = -1;
|
||||||
|
int fd = get_highest_fd ();
|
||||||
|
|
||||||
qse_pio_hnd_t devnull;
|
/* don't close stdin/out/err and the pipes */
|
||||||
qse_mchar_t* mcmd;
|
|
||||||
int fcnt = 0;
|
|
||||||
#ifndef QSE_CHAR_IS_MCHAR
|
|
||||||
qse_mchar_t buf[64];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TODO: consider if reading from /proc/self/fd is
|
|
||||||
* a better idea. */
|
|
||||||
|
|
||||||
struct rlimit rlim;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) <= -1 ||
|
|
||||||
rlim.rlim_max == RLIM_INFINITY)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_SYSCONF
|
|
||||||
fd = sysconf (_SC_OPEN_MAX);
|
|
||||||
if (fd <= 0)
|
|
||||||
#endif
|
|
||||||
fd = 1024;
|
|
||||||
}
|
|
||||||
else fd = rlim.rlim_max;
|
|
||||||
|
|
||||||
while (--fd > 2)
|
while (--fd > 2)
|
||||||
{
|
{
|
||||||
if (fd != handle[0] &&
|
if (fd != handle[0] &&
|
||||||
@ -733,7 +1103,7 @@ int qse_pio_init (
|
|||||||
(flags & QSE_PIO_OUTTONUL) ||
|
(flags & QSE_PIO_OUTTONUL) ||
|
||||||
(flags & QSE_PIO_ERRTONUL))
|
(flags & QSE_PIO_ERRTONUL))
|
||||||
{
|
{
|
||||||
#ifdef O_LARGEFILE
|
#if defined(O_LARGEFILE)
|
||||||
devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR|O_LARGEFILE, 0);
|
devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR|O_LARGEFILE, 0);
|
||||||
#else
|
#else
|
||||||
devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR, 0);
|
devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR, 0);
|
||||||
@ -750,162 +1120,22 @@ int qse_pio_init (
|
|||||||
|
|
||||||
if ((flags & QSE_PIO_INTONUL) ||
|
if ((flags & QSE_PIO_INTONUL) ||
|
||||||
(flags & QSE_PIO_OUTTONUL) ||
|
(flags & QSE_PIO_OUTTONUL) ||
|
||||||
(flags & QSE_PIO_ERRTONUL)) QSE_CLOSE (devnull);
|
(flags & QSE_PIO_ERRTONUL))
|
||||||
|
{
|
||||||
|
QSE_CLOSE (devnull);
|
||||||
|
devnull = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & QSE_PIO_DROPIN) QSE_CLOSE(0);
|
if (flags & QSE_PIO_DROPIN) QSE_CLOSE(0);
|
||||||
if (flags & QSE_PIO_DROPOUT) QSE_CLOSE(1);
|
if (flags & QSE_PIO_DROPOUT) QSE_CLOSE(1);
|
||||||
if (flags & QSE_PIO_DROPERR) QSE_CLOSE(2);
|
if (flags & QSE_PIO_DROPERR) QSE_CLOSE(2);
|
||||||
|
|
||||||
#ifdef QSE_CHAR_IS_MCHAR
|
if (make_param (pio, cmd, flags, ¶m) <= -1) goto child_oops;
|
||||||
if (flags & QSE_PIO_SHELL) mcmd = (qse_char_t*)cmd;
|
QSE_EXECVE (param.argv[0], param.argv, (env? qse_env_getarr(env): environ));
|
||||||
else
|
free_param (pio, ¶m);
|
||||||
{
|
|
||||||
mcmd = qse_strdup (cmd, pio->mmgr);
|
|
||||||
if (mcmd == QSE_NULL) goto child_oops;
|
|
||||||
|
|
||||||
fcnt = qse_strspl (mcmd, QSE_T(""),
|
|
||||||
QSE_T('\"'), QSE_T('\"'), QSE_T('\\'));
|
|
||||||
if (fcnt <= 0)
|
|
||||||
{
|
|
||||||
/* no field or an error */
|
|
||||||
goto child_oops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (flags & QSE_PIO_MBSCMD)
|
|
||||||
{
|
|
||||||
/* the cmd is flagged to be of qse_mchar_t
|
|
||||||
* while the default character type is qse_wchar_t. */
|
|
||||||
|
|
||||||
if (flags & QSE_PIO_SHELL) mcmd = (qse_mchar_t*)cmd;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mcmd = qse_mbsdup ((const qse_mchar_t*)cmd, pio->mmgr);
|
|
||||||
if (mcmd == QSE_NULL) goto child_oops;
|
|
||||||
|
|
||||||
fcnt = qse_mbsspl (mcmd, QSE_MT(""),
|
|
||||||
QSE_MT('\"'), QSE_MT('\"'), QSE_MT('\\'));
|
|
||||||
if (fcnt <= 0)
|
|
||||||
{
|
|
||||||
/* no field or an error */
|
|
||||||
goto child_oops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qse_size_t n, mn, wl;
|
|
||||||
qse_char_t* wcmd = QSE_NULL;
|
|
||||||
|
|
||||||
if (flags & QSE_PIO_SHELL)
|
|
||||||
{
|
|
||||||
if (qse_wcstombs (cmd, &wl, QSE_NULL, &mn) <= -1)
|
|
||||||
{
|
|
||||||
/* cmd has illegal sequence */
|
|
||||||
goto child_oops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wcmd = qse_strdup (cmd, pio->mmgr);
|
|
||||||
if (wcmd == QSE_NULL) goto child_oops;
|
|
||||||
|
|
||||||
fcnt = qse_strspl (wcmd, QSE_T(""),
|
|
||||||
QSE_T('\"'), QSE_T('\"'), QSE_T('\\'));
|
|
||||||
if (fcnt <= 0)
|
|
||||||
{
|
|
||||||
/* no field or an error */
|
|
||||||
goto child_oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate the length of the string after splitting */
|
|
||||||
for (wl = 0, n = fcnt; n > 0; )
|
|
||||||
{
|
|
||||||
if (wcmd[wl++] == QSE_T('\0')) n--;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
n = qse_wcsntombsnlen (wcmd, wl, &mn);
|
|
||||||
if (n != wl) goto child_oops;
|
|
||||||
#endif
|
|
||||||
if (qse_wcsntombsn (wcmd, &wl, QSE_NULL, &mn) <= -1) goto child_oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare to reserve 1 more slot for the terminating '\0'
|
|
||||||
* by incrementing mn by 1. */
|
|
||||||
mn = mn + 1;
|
|
||||||
|
|
||||||
if (mn <= QSE_COUNTOF(buf))
|
|
||||||
{
|
|
||||||
mcmd = buf;
|
|
||||||
mn = QSE_COUNTOF(buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mcmd = QSE_MMGR_ALLOC (
|
|
||||||
pio->mmgr, mn*QSE_SIZEOF(*mcmd));
|
|
||||||
if (mcmd == QSE_NULL) goto child_oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & QSE_PIO_SHELL)
|
|
||||||
{
|
|
||||||
/* qse_wcstombs() should succeed as
|
|
||||||
* it was successful above */
|
|
||||||
qse_wcstombs (cmd, &wl, mcmd, &mn);
|
|
||||||
/* qse_wcstombs() null-terminate mcmd */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QSE_ASSERT (wcmd != QSE_NULL);
|
|
||||||
/* qse_wcsntombsn() should succeed as
|
|
||||||
* it was was successful above */
|
|
||||||
qse_wcsntombsn (wcmd, &wl, mcmd, &mn);
|
|
||||||
/* qse_wcsntombsn() doesn't null-terminate mcmd */
|
|
||||||
mcmd[mn] = QSE_MT('\0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (flags & QSE_PIO_SHELL)
|
|
||||||
{
|
|
||||||
const qse_mchar_t* argv[4];
|
|
||||||
extern char** environ;
|
|
||||||
|
|
||||||
argv[0] = QSE_MT("/bin/sh");
|
|
||||||
argv[1] = QSE_MT("-c");
|
|
||||||
argv[2] = mcmd;
|
|
||||||
argv[3] = QSE_NULL;
|
|
||||||
|
|
||||||
QSE_EXECVE (
|
|
||||||
QSE_MT("/bin/sh"),
|
|
||||||
(qse_mchar_t*const*)argv,
|
|
||||||
(env? qse_env_getarr(env): environ)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
qse_mchar_t** argv;
|
|
||||||
extern char** environ;
|
|
||||||
|
|
||||||
argv = QSE_MMGR_ALLOC (pio->mmgr, (fcnt+1)*QSE_SIZEOF(argv[0]));
|
|
||||||
if (argv == QSE_NULL) goto child_oops;
|
|
||||||
|
|
||||||
for (i = 0; i < fcnt; i++)
|
|
||||||
{
|
|
||||||
argv[i] = mcmd;
|
|
||||||
while (*mcmd != QSE_MT('\0')) mcmd++;
|
|
||||||
mcmd++;
|
|
||||||
}
|
|
||||||
argv[i] = QSE_NULL;
|
|
||||||
|
|
||||||
QSE_EXECVE (argv[0], argv, (env? qse_env_getarr(env): environ));
|
|
||||||
|
|
||||||
/* this won't be reached if execve succeeds */
|
|
||||||
QSE_MMGR_FREE (pio->mmgr, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
child_oops:
|
child_oops:
|
||||||
|
if (devnull >= 0) QSE_CLOSE (devnull);
|
||||||
QSE_EXIT (128);
|
QSE_EXIT (128);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,8 +1225,7 @@ int qse_pio_init (
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
if (pio->errnum == QSE_PIO_ENOERR)
|
if (pio->errnum == QSE_PIO_ENOERR) pio->errnum = QSE_PIO_ESUBSYS;
|
||||||
pio->errnum = QSE_PIO_ESUBSYS;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if (windevnul != INVALID_HANDLE_VALUE) CloseHandle (windevnul);
|
if (windevnul != INVALID_HANDLE_VALUE) CloseHandle (windevnul);
|
||||||
@ -1036,7 +1265,16 @@ oops:
|
|||||||
#elif defined(__DOS__)
|
#elif defined(__DOS__)
|
||||||
|
|
||||||
/* DOS not multi-processed. can't support pio */
|
/* DOS not multi-processed. can't support pio */
|
||||||
|
#elif defined(HAVE_POSIX_SPAWN)
|
||||||
|
if (fa_inited)
|
||||||
|
{
|
||||||
|
posix_spawn_file_actions_destroy (&fa);
|
||||||
|
fa_inited = 0;
|
||||||
|
}
|
||||||
|
for (i = minidx; i < maxidx; i++)
|
||||||
|
{
|
||||||
|
if (handle[i] != QSE_PIO_HND_NIL) QSE_CLOSE (handle[i]);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
for (i = minidx; i < maxidx; i++)
|
for (i = minidx; i < maxidx; i++)
|
||||||
{
|
{
|
||||||
|
@ -1210,6 +1210,7 @@ struct task_cgi_arg_t
|
|||||||
{
|
{
|
||||||
const qse_mchar_t* path;
|
const qse_mchar_t* path;
|
||||||
const qse_htre_t* req;
|
const qse_htre_t* req;
|
||||||
|
int nph;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct task_cgi_t task_cgi_t;
|
typedef struct task_cgi_t task_cgi_t;
|
||||||
@ -1220,6 +1221,7 @@ struct task_cgi_t
|
|||||||
const qse_mchar_t* path;
|
const qse_mchar_t* path;
|
||||||
qse_http_version_t version;
|
qse_http_version_t version;
|
||||||
int keepalive; /* taken from the request */
|
int keepalive; /* taken from the request */
|
||||||
|
int nph;
|
||||||
|
|
||||||
qse_env_t* env;
|
qse_env_t* env;
|
||||||
qse_pio_t* pio;
|
qse_pio_t* pio;
|
||||||
@ -1254,7 +1256,7 @@ int walk_cgi_headers (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t
|
|||||||
{
|
{
|
||||||
task_cgi_t* cgi = (task_cgi_t*)ctx;
|
task_cgi_t* cgi = (task_cgi_t*)ctx;
|
||||||
|
|
||||||
if (qse_mbscmp (key, "Status") != 0)
|
if (qse_mbscmp (key, QSE_MT("Status")) != 0)
|
||||||
{
|
{
|
||||||
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1) return -1;
|
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1) return -1;
|
||||||
if (qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1) return -1;
|
if (qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1) return -1;
|
||||||
@ -1275,6 +1277,7 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
|||||||
QSE_ASSERT (req->attr.hurried);
|
QSE_ASSERT (req->attr.hurried);
|
||||||
|
|
||||||
status = qse_htre_getheaderval (req, QSE_MT("Status"));
|
status = qse_htre_getheaderval (req, QSE_MT("Status"));
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
qse_mchar_t buf[128];
|
qse_mchar_t buf[128];
|
||||||
@ -1282,8 +1285,7 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
|||||||
qse_mchar_t* endptr;
|
qse_mchar_t* endptr;
|
||||||
|
|
||||||
/* TODO: check the syntax of status value??? */
|
/* TODO: check the syntax of status value??? */
|
||||||
|
QSE_MSTRTONUM (nstatus, status, &endptr, 10);
|
||||||
QSE_MSTRTONUM (nstatus,status,&endptr,10);
|
|
||||||
|
|
||||||
snprintf (buf, QSE_COUNTOF(buf),
|
snprintf (buf, QSE_COUNTOF(buf),
|
||||||
QSE_MT("HTTP/%d.%d %d "),
|
QSE_MT("HTTP/%d.%d %d "),
|
||||||
@ -1304,13 +1306,30 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
qse_mchar_t* location;
|
||||||
qse_mchar_t buf[128];
|
qse_mchar_t buf[128];
|
||||||
|
|
||||||
|
location = qse_htre_getheaderval (req, QSE_MT("Location"));
|
||||||
|
if (location)
|
||||||
|
{
|
||||||
|
snprintf (buf, QSE_COUNTOF(buf),
|
||||||
|
QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\n"),
|
||||||
|
cgi->version.major, cgi->version.minor
|
||||||
|
);
|
||||||
|
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1;
|
||||||
|
|
||||||
|
/* the actual Location hearer is added by
|
||||||
|
* qse_htre_walkheaders() below */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
snprintf (buf, QSE_COUNTOF(buf),
|
snprintf (buf, QSE_COUNTOF(buf),
|
||||||
QSE_MT("HTTP/%d.%d 200 OK\r\n"),
|
QSE_MT("HTTP/%d.%d 200 OK\r\n"),
|
||||||
cgi->version.major, cgi->version.minor
|
cgi->version.major, cgi->version.minor
|
||||||
);
|
);
|
||||||
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1;
|
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (req->attr.content_length_set)
|
if (req->attr.content_length_set)
|
||||||
{
|
{
|
||||||
@ -1319,20 +1338,29 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no Content-Length returned by CGI */
|
/* no Content-Length returned by CGI. */
|
||||||
if (qse_comparehttpversions (&cgi->version, &v11) >= 0)
|
if (qse_comparehttpversions (&cgi->version, &v11) >= 0)
|
||||||
|
{
|
||||||
cgi->content_chunked = 1;
|
cgi->content_chunked = 1;
|
||||||
else cgi->disconnect = 1;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If CGI doesn't specify Content-Length, i can't
|
||||||
|
* honor cgi->keepalive in HTTP/1.0 or earlier.
|
||||||
|
* Closing the connection is the only way to
|
||||||
|
* specify how long the content is */
|
||||||
|
cgi->disconnect = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cgi->content_chunked)
|
if (cgi->content_chunked &&
|
||||||
{
|
qse_mbs_cat (cgi->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) return -1;
|
||||||
if (qse_mbs_cat (cgi->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qse_htre_walkheaders (req, walk_cgi_headers, cgi) <= -1) return -1;
|
if (qse_htre_walkheaders (req, walk_cgi_headers, cgi) <= -1) return -1;
|
||||||
if (qse_mbs_ncat (cgi->res, QSE_MT("\r\n"), 2) == (qse_size_t)-1) return -1;
|
/* end of header */
|
||||||
|
if (qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1;
|
||||||
|
|
||||||
|
/* content body begins here */
|
||||||
cgi->content_received = qse_htre_getcontentlen(req);
|
cgi->content_received = qse_htre_getcontentlen(req);
|
||||||
if (cgi->content_length_set &&
|
if (cgi->content_length_set &&
|
||||||
cgi->content_received > cgi->content_length)
|
cgi->content_received > cgi->content_length)
|
||||||
@ -1379,6 +1407,14 @@ static qse_env_t* makecgienv (
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
qse_env_insertsys (env, QSE_T("PATH"));
|
qse_env_insertsys (env, QSE_T("PATH"));
|
||||||
|
|
||||||
|
{
|
||||||
|
qse_char_t proto[32];
|
||||||
|
qse_http_version_t* v = qse_htre_getversion(req);
|
||||||
|
snprintf (proto, QSE_COUNTOF(proto),
|
||||||
|
QSE_T("HTTP/%d.%d"), (int)v->major, (int)v->minor);
|
||||||
|
qse_env_insert (env, QSE_T("SERVER_PROTOCOL"), proto);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
qse_env_insertsysm (env, QSE_MT("LANG"));
|
qse_env_insertsysm (env, QSE_MT("LANG"));
|
||||||
qse_env_insertsysm (env, QSE_MT("PATH"));
|
qse_env_insertsysm (env, QSE_MT("PATH"));
|
||||||
@ -1387,9 +1423,17 @@ static qse_env_t* makecgienv (
|
|||||||
{
|
{
|
||||||
qse_mchar_t port[16];
|
qse_mchar_t port[16];
|
||||||
snprintf (port, QSE_COUNTOF(port),
|
snprintf (port, QSE_COUNTOF(port),
|
||||||
"%d", (int)ntohs(client->addr.in4.sin_port));
|
QSE_MT("%d"), (int)ntohs(client->addr.in4.sin_port));
|
||||||
qse_env_insertm (env, QSE_MT("REMOTE_PORT"), port);
|
qse_env_insertm (env, QSE_MT("REMOTE_PORT"), port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
qse_mchar_t proto[32];
|
||||||
|
qse_http_version_t* v = qse_htre_getversion(req);
|
||||||
|
snprintf (proto, QSE_COUNTOF(proto),
|
||||||
|
QSE_MT("HTTP/%d.%d"), (int)v->major, (int)v->minor);
|
||||||
|
qse_env_insertm (env, QSE_MT("SERVER_PROTOCOL"), proto);
|
||||||
|
}
|
||||||
//qse_env_insertm (env, QSE_MT("REMOTE_ADDR"), QSE_MT("what the hell"));
|
//qse_env_insertm (env, QSE_MT("REMOTE_ADDR"), QSE_MT("what the hell"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1418,6 +1462,7 @@ static int task_init_cgi (
|
|||||||
xtn->path = (qse_mchar_t*)(xtn + 1);
|
xtn->path = (qse_mchar_t*)(xtn + 1);
|
||||||
xtn->version = *qse_htre_getversion(arg->req);
|
xtn->version = *qse_htre_getversion(arg->req);
|
||||||
xtn->keepalive = arg->req->attr.keepalive;
|
xtn->keepalive = arg->req->attr.keepalive;
|
||||||
|
xtn->nph = arg->nph;
|
||||||
|
|
||||||
xtn->env = makecgienv (httpd, client, arg->req);
|
xtn->env = makecgienv (httpd, client, arg->req);
|
||||||
if (xtn->env == QSE_NULL) xtn->init_failed = 1;
|
if (xtn->env == QSE_NULL) xtn->init_failed = 1;
|
||||||
@ -1678,10 +1723,20 @@ static int task_main_cgi (
|
|||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
{
|
{
|
||||||
task_cgi_t* cgi = (task_cgi_t*)task->ctx;
|
task_cgi_t* cgi = (task_cgi_t*)task->ctx;
|
||||||
cgi_htrd_xtn_t* xtn;
|
|
||||||
|
|
||||||
if (cgi->init_failed) goto oops;
|
if (cgi->init_failed) goto oops;
|
||||||
|
|
||||||
|
if (cgi->nph)
|
||||||
|
{
|
||||||
|
/* i cannot know how long the content will be
|
||||||
|
* since i don't parse the header. so i have to close
|
||||||
|
* the connection regardless of content-length or transfer-encoding
|
||||||
|
* in the actual header. */
|
||||||
|
if (qse_httpd_entaskdisconnect (httpd, client, task) == QSE_NULL) return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cgi_htrd_xtn_t* xtn;
|
||||||
cgi->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(cgi_htrd_xtn_t));
|
cgi->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(cgi_htrd_xtn_t));
|
||||||
if (cgi->htrd == QSE_NULL) goto oops;
|
if (cgi->htrd == QSE_NULL) goto oops;
|
||||||
xtn = (cgi_htrd_xtn_t*) qse_htrd_getxtn (cgi->htrd);
|
xtn = (cgi_htrd_xtn_t*) qse_htrd_getxtn (cgi->htrd);
|
||||||
@ -1696,6 +1751,7 @@ static int task_main_cgi (
|
|||||||
|
|
||||||
cgi->res = qse_mbs_open (httpd->mmgr, 0, 256);
|
cgi->res = qse_mbs_open (httpd->mmgr, 0, 256);
|
||||||
if (cgi->res == QSE_NULL) goto oops;
|
if (cgi->res == QSE_NULL) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
cgi->pio = qse_pio_open (
|
cgi->pio = qse_pio_open (
|
||||||
httpd->mmgr, 0, (const qse_char_t*)cgi->path, cgi->env,
|
httpd->mmgr, 0, (const qse_char_t*)cgi->path, cgi->env,
|
||||||
@ -1703,8 +1759,17 @@ static int task_main_cgi (
|
|||||||
);
|
);
|
||||||
if (cgi->pio == QSE_NULL) goto oops;
|
if (cgi->pio == QSE_NULL) goto oops;
|
||||||
|
|
||||||
|
if (cgi->nph)
|
||||||
|
{
|
||||||
|
/* skip various header processing */
|
||||||
|
task->main = task_main_cgi_4;
|
||||||
|
return task_main_cgi_4 (httpd, client, task);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
task->main = task_main_cgi_2; /* cause this function to be called subsequently */
|
task->main = task_main_cgi_2; /* cause this function to be called subsequently */
|
||||||
return task_main_cgi_2 (httpd, client, task); /* let me call it here once */
|
return task_main_cgi_2 (httpd, client, task); /* let me call it here once */
|
||||||
|
}
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
if (cgi->res)
|
if (cgi->res)
|
||||||
@ -1721,6 +1786,10 @@ oops:
|
|||||||
return (entask_error (httpd, client, task, 500, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
return (entask_error (httpd, client, task, 500, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: global option or individual paramter for max cgi lifetime
|
||||||
|
* non-blocking pio read ...
|
||||||
|
*/
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entaskcgi (
|
qse_httpd_task_t* qse_httpd_entaskcgi (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
@ -1733,6 +1802,33 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
|
|||||||
|
|
||||||
arg.path = path;
|
arg.path = path;
|
||||||
arg.req = req;
|
arg.req = req;
|
||||||
|
arg.nph = 0;
|
||||||
|
|
||||||
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
|
task.init = task_init_cgi;
|
||||||
|
task.fini = task_fini_cgi;
|
||||||
|
task.main = task_main_cgi;
|
||||||
|
task.ctx = &arg;
|
||||||
|
|
||||||
|
return qse_httpd_entask (
|
||||||
|
httpd, client, pred, &task,
|
||||||
|
QSE_SIZEOF(task_cgi_t) + ((qse_mbslen(path) + 1) * QSE_SIZEOF(*path))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
qse_httpd_task_t* qse_httpd_entasknph (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
const qse_httpd_task_t* pred,
|
||||||
|
const qse_mchar_t* path,
|
||||||
|
const qse_htre_t* req)
|
||||||
|
{
|
||||||
|
qse_httpd_task_t task;
|
||||||
|
task_cgi_arg_t arg;
|
||||||
|
|
||||||
|
arg.path = path;
|
||||||
|
arg.req = req;
|
||||||
|
arg.nph = 1;
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
task.init = task_init_cgi;
|
task.init = task_init_cgi;
|
||||||
|
@ -69,12 +69,13 @@ qse_printf (QSE_T("content = [%.*S]\n"),
|
|||||||
x = qse_httpd_entaskcgi (
|
x = qse_httpd_entaskcgi (
|
||||||
httpd, client, QSE_NULL, qpath, req);
|
httpd, client, QSE_NULL, qpath, req);
|
||||||
if (x == QSE_NULL) goto oops;
|
if (x == QSE_NULL) goto oops;
|
||||||
|
}
|
||||||
#if 0
|
else if (dot && qse_mbscmp (dot, QSE_MT(".nph")) == 0)
|
||||||
x = qse_httpd_entasknphcgi (
|
{
|
||||||
|
/* nph-cgi */
|
||||||
|
x = qse_httpd_entasknph (
|
||||||
httpd, client, QSE_NULL, qpath, req);
|
httpd, client, QSE_NULL, qpath, req);
|
||||||
if (x == QSE_NULL) goto oops;
|
if (x == QSE_NULL) goto oops;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user