fixed of not setting cmgr properly in awk/std.c

added encoding options to the awk command.
added directory functions to httpd
This commit is contained in:
hyung-hwan 2012-01-25 15:39:02 +00:00
parent b903f8ebb5
commit 246dc4f5b7
17 changed files with 481 additions and 274 deletions

View File

@ -75,6 +75,8 @@ struct arg_t
qse_htb_t* gvm; /* global variable map */
qse_char_t* fs; /* field separator */
qse_char_t* call; /* function to call */
qse_cmgr_t* script_cmgr;
qse_cmgr_t* console_cmgr;
int opton;
int optoff;
@ -429,13 +431,19 @@ static void print_usage (QSE_FILE* out, const qse_char_t* argv0)
qse_fprintf (out, QSE_T(" -F/--field-separator string set a field separator(FS)\n"));
qse_fprintf (out, QSE_T(" -v/--assign var=value add a global variable with a value\n"));
qse_fprintf (out, QSE_T(" -m/--memory-limit number limit the memory usage (bytes)\n"));
#if defined(QSE_CHAR_IS_WCHAR)
qse_fprintf (out, QSE_T(" --script-encoding string specify script encoding name\n"));
qse_fprintf (out, QSE_T(" --console-encoding string specify console encoding name\n"));
#endif
#if defined(QSE_BUILD_DEBUG)
qse_fprintf (out, QSE_T(" -X number fail the number'th memory allocation\n"));
#endif
for (j = 0; opttab[j].name != QSE_NULL; j++)
for (j = 0; opttab[j].name; j++)
{
qse_fprintf (out, QSE_T(" --%-18s on/off %s\n"), opttab[j].name, opttab[j].desc);
qse_fprintf (out,
QSE_T(" --%-18s on/off %s\n"),
opttab[j].name, opttab[j].desc);
}
}
@ -468,6 +476,9 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
{ QSE_T(":assign"), QSE_T('v') },
{ QSE_T(":memory-limit"), QSE_T('m') },
{ QSE_T(":script-encoding"), QSE_T('\0') },
{ QSE_T(":console-encoding"), QSE_T('\0') },
{ QSE_T("help"), QSE_T('h') },
{ QSE_NULL, QSE_T('\0') }
};
@ -621,7 +632,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
{
/* a long option with no corresponding short option */
qse_size_t i;
for (i = 0; opttab[i].name != QSE_NULL; i++)
for (i = 0; opttab[i].name; i++)
{
if (qse_strcmp (opt.lngopt, opttab[i].name) == 0)
{
@ -637,6 +648,25 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
break;
}
}
if (qse_strcmp(opt.lngopt, QSE_T("script-encoding")) == 0)
{
arg->script_cmgr = qse_getcmgrbyname (opt.arg);
if (arg->script_cmgr == QSE_NULL)
{
print_err (QSE_T("unknown script encoding - %s\n"), opt.arg);
goto oops;
}
}
else if (qse_strcmp(opt.lngopt, QSE_T("console-encoding")) == 0)
{
arg->console_cmgr = qse_getcmgrbyname (opt.arg);
if (arg->console_cmgr == QSE_NULL)
{
print_err (QSE_T("unknown console encoding - %s\n"), opt.arg);
goto oops;
}
}
break;
}
@ -874,14 +904,14 @@ static int awk_main (int argc, qse_char_t* argv[])
else
{
psin.u.file.path = arg.isp.files[0];
psin.u.file.cmgr = QSE_NULL;
psin.u.file.cmgr = arg.script_cmgr;
}
if (arg.osf != QSE_NULL)
{
psout.type = QSE_AWK_PARSESTD_FILE;
psout.u.file.path = arg.osf;
psout.u.file.cmgr = QSE_NULL;
psout.u.file.cmgr = arg.script_cmgr;
}
#if defined(QSE_BUILD_DEBUG)
@ -954,7 +984,7 @@ static int awk_main (int argc, qse_char_t* argv[])
rtx = qse_awk_rtx_openstd (
awk, 0, QSE_T("qseawk"),
(const qse_char_t*const*)arg.icf, QSE_NULL, QSE_NULL);
(const qse_char_t*const*)arg.icf, QSE_NULL, arg.console_cmgr);
if (rtx == QSE_NULL)
{
print_awkerr (awk);

11
qse/configure vendored
View File

@ -15518,6 +15518,17 @@ _ACEOF
fi
done
for ac_func in fdopendir
do :
ac_fn_c_check_func "$LINENO" "fdopendir" "ac_cv_func_fdopendir"
if test "x$ac_cv_func_fdopendir" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_FDOPENDIR 1
_ACEOF
fi
done
OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS"

View File

@ -100,6 +100,7 @@ AC_CHECK_FUNCS([timegm timelocal])
AC_CHECK_FUNCS([utime utimes])
AC_CHECK_FUNCS([sysconf])
AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([fdopendir])
OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS"

View File

@ -84,9 +84,13 @@ enum qse_tre_cflag_t
enum qse_tre_eflag_t
{
QSE_TRE_NOTBOL = (1 << 0),
QSE_TRE_NOTEOL = (1 << 1),
QSE_TRE_BACKTRACKING = (1 << 2)
QSE_TRE_BACKTRACKING = (1 << 0),
/* you can use QSE_TRE_IGNORECASE for execution */
/*QSE_TRE_IGNORECASE = (1 << 1),*/
QSE_TRE_NOTBOL = (1 << 2),
QSE_TRE_NOTEOL = (1 << 3)
};
typedef struct qse_tre_strsrc_t qse_tre_strsrc_t;

View File

@ -61,6 +61,9 @@
/* Define to 1 if you have the `expl' function. */
#undef HAVE_EXPL
/* Define to 1 if you have the `fdopendir' function. */
#undef HAVE_FDOPENDIR
/* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD

View File

@ -44,7 +44,7 @@ struct qse_htre_t
int chunked;
int content_length_set;
qse_size_t content_length;
int connection_close;
int keepalive;
int expect_continue;
/* indicates if the content has been filled */

View File

@ -46,19 +46,13 @@ typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
struct qse_httpd_cbs_t
{
struct
{
const qse_mchar_t* (*getmimetype) (qse_httpd_t* httpd, const qse_mchar_t* path);
qse_ubi_t (*open) (qse_httpd_t* httpd, const qse_mchar_t* path);
void (*close) (qse_httpd_t* httpd, qse_ubi_t handle);
int (*getsize) (qse_httpd_t* httpd, qse_ubi_t handle, qse_foff_t* size);
} file;
int (*handle_request) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
int (*handle_expect_continue) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
const qse_mchar_t* (*getmimetype) (qse_httpd_t* httpd, const qse_mchar_t* path);
int (*listdir) (qse_httpd_t* httpd, const qse_mchar_t* path);
};
typedef struct qse_httpd_task_t qse_httpd_task_t;
@ -142,7 +136,7 @@ void qse_httpd_stop (
);
int qse_httpd_addlisteners (
int qse_httpd_addlistener (
qse_httpd_t* httpd,
const qse_char_t* uri
);
@ -200,13 +194,21 @@ qse_httpd_task_t* qse_httpd_entaskfile (
qse_foff_t size
);
qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
qse_ubi_t handle
);
qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* name,
const qse_http_range_t* range,
const qse_http_version_t* version
const qse_http_version_t* version,
int keepalive
);
qse_httpd_task_t* qse_httpd_entaskcgi (

View File

@ -1089,7 +1089,7 @@ int qse_awk_matchrex (
x = qse_matchrex (
awk->mmgr, awk->rex.depth.max.match,
code, option, str, substr, match, &err);
if (x < 0) *errnum = QSE_AWK_REXERRTOERR(err);
if (x <= -1) *errnum = QSE_AWK_REXERRTOERR(err);
return x;
}

View File

@ -997,6 +997,7 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
if (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
riod->handle = sio;
rxtn->c.in.count++;
return 1;
@ -1114,6 +1115,8 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
return -1;
}
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
if (qse_awk_rtx_setfilename (
rtx, file, qse_strlen(file)) <= -1)
{
@ -1146,6 +1149,8 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
);
if (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
riod->handle = sio;
rxtn->c.out.count++;
return 1;
@ -1178,6 +1183,8 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR);
if (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
if (qse_awk_rtx_setofilename (
rtx, file, qse_strlen(file)) <= -1)
{

View File

@ -58,6 +58,11 @@ void qse_setdflcmgr (qse_cmgr_t* cmgr)
dfl_cmgr = (cmgr? cmgr: &builtin_cmgr[0]);
}
/* TODO:
qse_addcmgr (const qse_char_t* name, qse_cmgr_t* cmgr);
qse_delcmgr (const qse_char_t* name);
*/
qse_cmgr_t* qse_getcmgrbyname (const qse_char_t* name)
{
if (name)
@ -66,7 +71,7 @@ qse_cmgr_t* qse_getcmgrbyname (const qse_char_t* name)
if (qse_strcmp(name, QSE_T("")) == 0) return dfl_cmgr;
if (qse_strcmp(name, QSE_T("utf8")) == 0) return qse_utf8cmgr;
if (qse_strcmp(name, QSE_T("slmb")) == 0) return qse_slmbcmgr;
/* TODO: add more */
/* TODO: add more - handle those added with qse_addcmgr() */
}
return QSE_NULL;
}

View File

@ -133,12 +133,9 @@ typedef struct tre_backtrack_struct
if (!s) \
{ \
tre_bt_mem_destroy(mem); \
if (tags) \
xfree(_mmgr,tags); \
if (pmatch) \
xfree(_mmgr,pmatch); \
if (states_seen) \
xfree(_mmgr,states_seen); \
if (tags) xfree(_mmgr,tags); \
if (pmatch) xfree(_mmgr,pmatch); \
if (states_seen) xfree(_mmgr,states_seen); \
return REG_ESPACE; \
} \
s->prev = stack; \
@ -148,12 +145,9 @@ typedef struct tre_backtrack_struct
if (!s->item.tags) \
{ \
tre_bt_mem_destroy(mem); \
if (tags) \
xfree(_mmgr,tags); \
if (pmatch) \
xfree(_mmgr,pmatch); \
if (states_seen) \
xfree(_mmgr,states_seen); \
if (tags) xfree(_mmgr,tags); \
if (pmatch) xfree(_mmgr,pmatch); \
if (states_seen) xfree(_mmgr,states_seen); \
return REG_ESPACE; \
} \
stack->next = s; \
@ -539,8 +533,8 @@ retry:
trans_i->code_min, trans_i->code_max,
trans_i->code_min, trans_i->code_max,
trans_i->assertions, trans_i->state_id));
if (trans_i->code_min <= (tre_cint_t)prev_c
&& trans_i->code_max >= (tre_cint_t)prev_c)
if (trans_i->code_min <= (tre_cint_t)prev_c &&
trans_i->code_max >= (tre_cint_t)prev_c)
{
if (trans_i->assertions
&& (CHECK_ASSERTIONS(trans_i->assertions)

View File

@ -275,11 +275,11 @@ static qse_mchar_t* parse_initial_line (
if (qse_htre_setsmessagefromcstr (&htrd->re, &tmp) <= -1) goto outofmem;
/* adjust Connection: close for HTTP 1.0 or eariler */
if (htrd->re.version.major < 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor == 0))
/* adjust Connection: Keep-Alive for HTTP 1.1 or later */
if (htrd->re.version.major > 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor >= 1))
{
htrd->re.attr.connection_close = 1;
htrd->re.attr.keepalive = 1;
}
}
else
@ -379,11 +379,11 @@ static qse_mchar_t* parse_initial_line (
/* skip trailing spaces on the line */
while (is_space_octet(*p)) p++;
/* adjust Connection: close for HTTP 1.0 or eariler */
if (htrd->re.version.major < 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor == 0))
/* adjust Connection: Keep-Alive for HTTP 1.1 or later */
if (htrd->re.version.major > 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor >= 1))
{
htrd->re.attr.connection_close = 1;
htrd->re.attr.keepalive = 1;
}
}
@ -427,58 +427,46 @@ void qse_htrd_setrecbs (qse_htrd_t* htrd, const qse_htrd_recbs_t* recbs)
htrd->recbs = recbs;
}
#define octet_tolower(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) | 0x20) : (c))
#define octet_toupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) & ~0x20) : (c))
static QSE_INLINE int compare_octets (
const qse_mchar_t* s1, qse_size_t len1,
const qse_mchar_t* s2, qse_size_t len2)
{
qse_char_t c1, c2;
const qse_mchar_t* end1 = s1 + len1;
const qse_mchar_t* end2 = s2 + len2;
while (s1 < end1)
{
c1 = octet_toupper (*s1);
if (s2 < end2)
{
c2 = octet_toupper (*s2);
if (c1 > c2) return 1;
if (c1 < c2) return -1;
}
else return 1;
s1++; s2++;
}
return (s2 < end2)? -1: 0;
}
static QSE_INLINE int capture_connection (
qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{
int n;
n = compare_octets (QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "close", 5);
n = qse_mbsxncasecmp (
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair),
"close", 5);
if (n == 0)
{
htrd->re.attr.connection_close = 1;
htrd->re.attr.keepalive = 0;
return 0;
}
n = compare_octets (QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "Keep-Alive", 10);
n = qse_mbsxncasecmp (
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair),
"Keep-Alive", 10);
if (n == 0)
{
htrd->re.attr.connection_close = 0;
htrd->re.attr.keepalive = 1;
return 0;
}
/* don't care about other values */
/* Basically i don't care about other values.
* but for HTTP 1.0, other values will set connection to 'close'.
*
* Other values include even Keep-Alive specified multiple times.
* Connection: Keep-Alive
* Connection: Keep-Alive
* For the second Keep-Alive, this function sees 'Keep-Alive,Keep-Alive'
* That's because values of the same keys are concatenated.
*/
if (htrd->re.version.major < 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor <= 0))
{
htrd->re.attr.keepalive = 0;
}
return 0;
}
static QSE_INLINE int capture_content_length (
qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{
qse_size_t len = 0, off = 0, tmp;
const qse_mchar_t* ptr = QSE_HTB_VPTR(pair);
@ -525,12 +513,12 @@ static QSE_INLINE int capture_content_length (
return 0;
}
static QSE_INLINE int capture_expect (
qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_expect (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{
int n;
n = compare_octets (QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "100-continue", 12);
n = qse_mbsxncasecmp (
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "100-continue", 12);
if (n == 0)
{
@ -542,12 +530,12 @@ static QSE_INLINE int capture_expect (
return 0;
}
static QSE_INLINE int capture_transfer_encoding (
qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_transfer_encoding (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{
int n;
n = compare_octets (QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "chunked", 7);
n = qse_mbsxncasecmp (
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "chunked", 7);
if (n == 0)
{
/* if (htrd->re.attr.content_length > 0) */
@ -591,7 +579,7 @@ static QSE_INLINE int capture_key_header (
{
mid = base + count / 2;
n = compare_octets (
n = qse_mbsxncasecmp (
QSE_HTB_KPTR(pair), QSE_HTB_KLEN(pair),
hdrtab[mid].ptr, hdrtab[mid].len
);

View File

@ -27,6 +27,7 @@
#include "../cmn/mem.h"
#include <qse/cmn/chr.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include <fcntl.h>
#include <unistd.h>
@ -451,7 +452,8 @@ static void delete_from_client_array (qse_httpd_t* httpd, int fd)
{
purge_tasks_locked (httpd, &array->data[fd]);
#if defined(HAVE_PTHREAD)
if (httpd->threaded) pthread_mutex_destroy (&array->data[fd].task.mutex);
if (httpd->threaded)
pthread_mutex_destroy (&array->data[fd].task.mutex);
#endif
qse_htrd_close (array->data[fd].htrd);
@ -610,7 +612,6 @@ httpd->cbs.on_error (httpd, l).... */
}
}
static int make_fd_set_from_client_array (
qse_httpd_t* httpd, fd_set* r, fd_set* w)
{
@ -955,21 +956,15 @@ static void free_listener_list (qse_httpd_t* httpd, listener_t* l)
}
}
static listener_t* parse_listener_string (
qse_httpd_t* httpd, const qse_char_t* str, listener_t** ltail)
static listener_t* parse_listener_uri (
qse_httpd_t* httpd, const qse_char_t* uri)
{
const qse_char_t* p = str;
listener_t* lhead = QSE_NULL, * ltmp = QSE_NULL, * lend = QSE_NULL;
do
{
const qse_char_t* p = uri;
listener_t* ltmp = QSE_NULL;
qse_cstr_t tmp;
qse_mchar_t* host;
int x;
/* skip spaces */
while (QSE_ISSPACE(*p)) p++;
ltmp = qse_httpd_allocmem (httpd, QSE_SIZEOF(*ltmp));
if (ltmp == QSE_NULL) goto oops; /* alloc set error number. so goto oops */
@ -1007,25 +1002,26 @@ static listener_t* parse_listener_string (
{
/* IPv6 address */
p++; /* skip [ */
tmp.ptr = p;
while (*p != QSE_T(']'))
for (tmp.ptr = p; *p != QSE_T(']'); p++)
{
if (*p == QSE_T('\0')) goto oops_einval;
p++;
}
tmp.len = p - tmp.ptr;
tmp.len = p - tmp.ptr;
ltmp->family = AF_INET6;
p++; /* skip ] */
if (*p != QSE_T(':') && *p != QSE_T('\0')) goto oops_einval;
}
else
{
#endif
/* host name or IPv4 address */
tmp.ptr = p;
while (!QSE_ISSPACE(*p) &&
*p != QSE_T(':') &&
*p != QSE_T('\0')) p++;
for (tmp.ptr = p; ; p++)
{
if (*p == QSE_T(':') || *p == QSE_T('\0')) break;
}
tmp.len = p - tmp.ptr;
ltmp->family = AF_INET;
#ifdef AF_INET6
@ -1059,32 +1055,24 @@ or CALL a user callback for name resolution?
if (*p == QSE_T(':'))
{
unsigned int port = 0;
/* port number */
p++;
tmp.ptr = p;
while (QSE_ISDIGIT(*p))
{
for (tmp.ptr = p; QSE_ISDIGIT(*p); p++)
port = port * 10 + (*p - QSE_T('0'));
p++;
}
tmp.len = p - tmp.ptr;
if (tmp.len > 5 || port > QSE_TYPE_MAX(unsigned short)) goto oops_einval;
if (tmp.len <= 0 ||
tmp.len >= 6 ||
port > QSE_TYPE_MAX(unsigned short)) goto oops_einval;
ltmp->port = port;
}
/* skip spaces */
while (QSE_ISSPACE(*p)) p++;
if (lhead == QSE_NULL) lend = ltmp;
ltmp->next = lhead;
lhead = ltmp;
ltmp = QSE_NULL;
}
while (*p != QSE_T('\0'));
if (ltail) *ltail = lend;
return lhead;
return ltmp;
oops_einval:
httpd->errnum = QSE_HTTPD_EINVAL;
@ -1096,19 +1084,18 @@ oops_enomem:
oops:
if (ltmp) free_listener (httpd, ltmp);
if (lhead) free_listener_list (httpd, lhead);
return QSE_NULL;
}
static int add_listeners (qse_httpd_t* httpd, const qse_char_t* uri)
static int add_listener (qse_httpd_t* httpd, const qse_char_t* uri)
{
listener_t* lh, * lt;
listener_t* lsn;
lh = parse_listener_string (httpd, uri, &lt);
if (lh == QSE_NULL) return -1;
lsn = parse_listener_uri (httpd, uri);
if (lsn == QSE_NULL) return -1;
lt->next = httpd->listener.list;
httpd->listener.list = lh;
lsn->next = httpd->listener.list;
httpd->listener.list = lsn;
/*
TODO: mutex protection...
if in the activated state...
@ -1124,7 +1111,7 @@ static int delete_listeners (qse_httpd_t* httpd, const qse_char_t* uri)
{
listener_t* lh, * li, * hl;
lh = parse_listener_string (httpd, uri, QSE_NULL);
lh = parse_listener_uri (httpd, uri, QSE_NULL);
if (lh == QSE_NULL) return -1;
for (li = lh; li; li = li->next)
@ -1142,21 +1129,21 @@ static int delete_listeners (qse_httpd_t* httpd, const qse_char_t* uri)
}
#endif
int qse_httpd_addlisteners (qse_httpd_t* httpd, const qse_char_t* uri)
int qse_httpd_addlistener (qse_httpd_t* httpd, const qse_char_t* uri)
{
#if defined(HAVE_PTHREAD)
int n;
pthread_mutex_lock (&httpd->listener.mutex);
n = add_listeners (httpd, uri);
n = add_listener (httpd, uri);
pthread_mutex_unlock (&httpd->listener.mutex);
return n;
#else
return add_listeners (httpd, uri);
return add_listener (httpd, uri);
#endif
}
#if 0
int qse_httpd_dellisteners (qse_httpd_t* httpd, const qse_char_t* uri)
int qse_httpd_dellistener (qse_httpd_t* httpd, const qse_char_t* uri)
{
int n;
pthread_mutex_lock (&httpd->listener.mutex);

View File

@ -33,6 +33,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <dirent.h>
#define MAX_SEND_SIZE 4096
@ -112,7 +113,6 @@ static qse_ssize_t xsendfile (
}
#endif
/*------------------------------------------------------------------------*/
static int task_main_disconnect (
@ -496,6 +496,125 @@ qse_httpd_task_t* qse_httpd_entaskfile (
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data));
}
/*------------------------------------------------------------------------*/
typedef struct task_dir_t task_dir_t;
struct task_dir_t
{
qse_ubi_t handle;
qse_size_t count;
int eod;
qse_mchar_t buf[4096];
qse_size_t buflen;
qse_size_t bufsent;
};
static int task_init_dir (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_dir_t* xtn = qse_httpd_gettaskxtn (httpd, task);
QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn));
xtn->handle = *(qse_ubi_t*)task->ctx;
qse_printf (QSE_T(">>>> handle %p\n"), xtn->handle.ptr);
task->ctx = xtn;
return 0;
}
static void task_fini_dir (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_dir_t* ctx = (task_file_t*)task->ctx;
closedir (ctx->handle.ptr);
}
static int task_main_dir (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_dir_t* ctx = (task_dir_t*)task->ctx;
qse_ssize_t n;
char buf[100];
if (ctx->bufsent < ctx->buflen) goto send_dirlist;
ctx->buflen = 0;
ctx->bufsent = 0;
if (ctx->count == 0)
{
ctx->buflen += snprintf (
&ctx->buf[ctx->buflen],
QSE_COUNTOF(ctx->buf) - ctx->buflen,
"<html><head><title>Directory Listing</title></head><body>index of xxxx<ul>"
);
}
do
{
struct dirent* ent;
ent = readdir (ctx->handle.ptr);
if (ent == QSE_NULL)
{
// TODO: check if errno has changed from before readdir().
// and return -1 if so.
ctx->eod = 1;
ctx->buflen += snprintf (
&ctx->buf[ctx->buflen],
QSE_COUNTOF(ctx->buf) - ctx->buflen,
"</ul></body></html>");
break;
}
else
{
// TODO: check if snprintf has truncated....
ctx->buflen += snprintf (
&ctx->buf[ctx->buflen],
QSE_COUNTOF(ctx->buf) - ctx->buflen,
"<li><a href='%s%s'>%s%s</a></li>",
ent->d_name,
(ent->d_type == DT_DIR? "/": ""),
ent->d_name,
(ent->d_type == DT_DIR? "/": "")
);
}
ctx->count++;
}
while (1);
send_dirlist:
snprintf (buf, QSE_COUNTOF(buf), "%lX\r\n", (unsigned long)(ctx->buflen - ctx->bufsent));
send (client->handle.i, buf, strlen(buf), 0);
n = send (client->handle.i, ctx->buf, ctx->buflen, 0);
if (n <= -1) return -1;
send (client->handle.i, "0\r\n", 3, 0);
ctx->bufsent += n;
return (ctx->bufsent < ctx->buflen || !ctx->eod)? 1: 0;
}
qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
qse_ubi_t handle)
{
qse_httpd_task_t task;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_dir;
task.main = task_main_dir;
task.fini = task_fini_dir;
task.ctx = &handle;
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(task_dir_t));
}
/*------------------------------------------------------------------------*/
#include <unistd.h>
@ -508,6 +627,7 @@ struct task_path_t
const qse_mchar_t* name;
qse_http_range_t range;
qse_http_version_t version;
int keepalive;
};
static int task_init_path (
@ -521,6 +641,46 @@ static int task_init_path (
return 0;
}
static qse_httpd_task_t* entask_path_error (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task, int code)
{
task_path_t* data = (task_path_t*)task->ctx;
const qse_mchar_t* smsg;
const qse_mchar_t* lmsg;
switch (code)
{
case 403:
smsg = QSE_MT("Forbidden");
lmsg = QSE_MT("<html><head><title>Directory Listing Forbidden</title></head><body><b>DIRECTORY LISTING FORBIDDEN<b></body></html>");
break;
case 404:
smsg = QSE_MT("Not Found");
lmsg = QSE_MT("<html><head><title>Not Found</title></head><body><b>REQUESTED PATH NOT FOUND<b></body></html>");
break;
case 416:
smsg = QSE_MT("Requested Range Not Satisfiable");
lmsg = QSE_MT("<html><head><title>Requested Range Not Satsfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE<b></body></html>");
break;
default:
smsg = QSE_MT("Unknown");
lmsg = QSE_MT("<html><head><title>Unknown Error</title></head><body><b>UNKNOWN ERROR<b></body></html>");
break;
}
return qse_httpd_entaskformat (
httpd, client, task,
QSE_MT("HTTP/%d.%d %d %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor, code, smsg,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(int)qse_mbslen(lmsg) + 4, lmsg
);
}
static int task_main_path (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
@ -529,45 +689,48 @@ static int task_main_path (
struct stat st;
qse_httpd_task_t* x = task;
qse_printf (QSE_T("opending file %hs\n"), data->name);
qse_printf (QSE_T("opening file %hs\n"), data->name);
handle.i = open (data->name, O_RDONLY);
if (handle.i <= -1)
{
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg
);
x = entask_path_error (httpd, client, x, 404);
goto no_file_send;
}
fcntl (handle.i, F_SETFD, FD_CLOEXEC);
if (fstat (handle.i, &st) <= -1)
{
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg
);
x = entask_path_error (httpd, client, x, 404);
goto no_file_send;
}
if (S_ISDIR(st.st_mode))
{
/* TODO: directory listing */
const qse_mchar_t* msg = QSE_MT("<html><head><title>Directory Listing</title></head><body><li>file1<li>file2<li>file3</body></html>");
qse_ubi_t dir;
/*#if defined(HAVE_FDOPENDIR)
dir.ptr = fdopendir (handle.i);
#else */
dir.ptr = opendir (data->name);
/*#endif */
if (dir.ptr)
{
qse_printf (QSE_T(">>>> entask dir handle %p\n"), dir.ptr);
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Location: %s\r\nTransfer-Encoding: chunked\r\n\r\n"),
data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
data->name
);
x = qse_httpd_entaskdir (httpd, client, x, dir);
if (x == QSE_NULL) closedir (dir.ptr);
}
else
{
x = entask_path_error (httpd, client, x, 403);
}
goto no_file_send;
}
@ -587,33 +750,26 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
if (data->range.from >= st.st_size)
{
const qse_mchar_t* msg;
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg
);
x = entask_path_error (httpd, client, x, 416);
goto no_file_send;
}
if (data->range.to >= st.st_size) data->range.to = st.st_size - 1;
if (httpd->cbs->file.getmimetype)
if (httpd->cbs->getmimetype)
{
httpd->errnum = QSE_HTTPD_ENOERR;
mime_type = httpd->cbs->file.getmimetype (httpd, data->name);
mime_type = httpd->cbs->getmimetype (httpd, data->name);
/*TODO: how to handle an error... */
}
#if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%s%sContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
data->version.major,
data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): QSE_MT("")),
@ -626,9 +782,10 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
#else
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%s%sContent-Length: %lu\r\nContent-Location: %s\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"),
QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\nContent-Location: %s\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"),
data->version.major,
data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): QSE_MT("")),
@ -654,19 +811,22 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
/* TODO: int64 format.... don't hard code it llu */
const qse_mchar_t* mime_type = QSE_NULL;
if (httpd->cbs->file.getmimetype)
if (httpd->cbs->getmimetype)
{
httpd->errnum = QSE_HTTPD_ENOERR;
mime_type = httpd->cbs->file.getmimetype (httpd, data->name);
mime_type = httpd->cbs->getmimetype (httpd, data->name);
/*TODO: how to handle an error... */
}
/* wget 1.8.2 set 'Connection: Keep-Alive' in the http 1.0 header.
* if the reply doesn't contain 'Connection: Keep-Alive', it didn't
* close connection.*/
#if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\n%s%s%sContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"),
data->version.major,
data->version.minor,
QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"),
data->version.major, data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): QSE_MT("")),
@ -676,9 +836,10 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
#else
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\n%s%s%sContent-Length: %lu\r\nContent-Location: %s\r\n\r\n"),
QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\nContent-Location: %s\r\n\r\n"),
data->version.major,
data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): QSE_MT("")),
@ -706,7 +867,8 @@ qse_httpd_task_t* qse_httpd_entaskpath (
const qse_httpd_task_t* pred,
const qse_mchar_t* name,
const qse_http_range_t* range,
const qse_http_version_t* verison)
const qse_http_version_t* verison,
int keepalive)
{
qse_httpd_task_t task;
task_path_t data;
@ -716,6 +878,7 @@ qse_httpd_task_t* qse_httpd_entaskpath (
if (range) data.range = *range;
else data.range.type = QSE_HTTP_RANGE_NONE;
data.version = *verison;
data.keepalive = keepalive;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_path;

View File

@ -30,8 +30,9 @@
#else
# if defined(QSE_CHAR_IS_MCHAR) && defined(USE_REGEX)
# include <regex.h>
# endif
# else
# include <qse/cmn/tre.h>
# endif
#endif
QSE_IMPLEMENT_COMMON_FUNCTIONS (sed)

View File

@ -101,7 +101,8 @@ qse_httpd_entaskstatictext (httpd, client, QSE_NULL, QSE_MT("HTTP/1.1 416 Reques
httpd, client, QSE_NULL,
qse_htre_getqpathptr(req),
(rangestr? &range: QSE_NULL),
qse_htre_getversion(req)
qse_htre_getversion(req),
req->attr.keepalive
);
if (x == QSE_NULL) goto oops;
}
@ -120,7 +121,7 @@ qse_httpd_entaskstatictext (httpd, client, QSE_NULL, QSE_MT("HTTP/1.1 416 Reques
}
done:
if (req->attr.connection_close)
if (!req->attr.keepalive)
{
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
if (x == QSE_NULL) goto oops;
@ -149,6 +150,11 @@ const qse_mchar_t* get_mime_type (qse_httpd_t* httpd, const qse_mchar_t* path)
return QSE_NULL;
}
int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path)
{
return 404;
}
static qse_httpd_t* httpd = NULL;
static void sigint (int sig)
@ -158,9 +164,10 @@ static void sigint (int sig)
static qse_httpd_cbs_t httpd_cbs =
{
{ get_mime_type, QSE_NULL, },
handle_request,
handle_expect_continue
handle_expect_continue,
get_mime_type,
list_directory
};
int httpd_main (int argc, qse_char_t* argv[])
@ -168,9 +175,9 @@ int httpd_main (int argc, qse_char_t* argv[])
int n;
httpd_xtn_t* xtn;
if (argc != 2)
if (argc <= 1)
{
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri>\n"), argv[0]);
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri> ...\n"), argv[0]);
return -1;
}
@ -184,12 +191,16 @@ int httpd_main (int argc, qse_char_t* argv[])
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
xtn->orgcbs = qse_httpd_getcbs (httpd);
if (qse_httpd_addlisteners (httpd, argv[1]) <= -1)
for (n = 1; n < argc; n++)
{
qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listeners\n"));
if (qse_httpd_addlistener (httpd, argv[n]) <= -1)
{
qse_fprintf (QSE_STDERR,
QSE_T("Failed to add httpd listener - %s\n"), argv[n]);
qse_httpd_close (httpd);
return -1;
}
}
qse_httpd_setcbs (httpd, &httpd_cbs);