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_htb_t* gvm; /* global variable map */
qse_char_t* fs; /* field separator */ qse_char_t* fs; /* field separator */
qse_char_t* call; /* function to call */ qse_char_t* call; /* function to call */
qse_cmgr_t* script_cmgr;
qse_cmgr_t* console_cmgr;
int opton; int opton;
int optoff; 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(" -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(" -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")); 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) #if defined(QSE_BUILD_DEBUG)
qse_fprintf (out, QSE_T(" -X number fail the number'th memory allocation\n")); qse_fprintf (out, QSE_T(" -X number fail the number'th memory allocation\n"));
#endif #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(":assign"), QSE_T('v') },
{ QSE_T(":memory-limit"), QSE_T('m') }, { 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_T("help"), QSE_T('h') },
{ QSE_NULL, QSE_T('\0') } { 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 */ /* a long option with no corresponding short option */
qse_size_t i; 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) 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; 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; break;
} }
@ -874,14 +904,14 @@ static int awk_main (int argc, qse_char_t* argv[])
else else
{ {
psin.u.file.path = arg.isp.files[0]; 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) if (arg.osf != QSE_NULL)
{ {
psout.type = QSE_AWK_PARSESTD_FILE; psout.type = QSE_AWK_PARSESTD_FILE;
psout.u.file.path = arg.osf; psout.u.file.path = arg.osf;
psout.u.file.cmgr = QSE_NULL; psout.u.file.cmgr = arg.script_cmgr;
} }
#if defined(QSE_BUILD_DEBUG) #if defined(QSE_BUILD_DEBUG)
@ -954,7 +984,7 @@ static int awk_main (int argc, qse_char_t* argv[])
rtx = qse_awk_rtx_openstd ( rtx = qse_awk_rtx_openstd (
awk, 0, QSE_T("qseawk"), 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) if (rtx == QSE_NULL)
{ {
print_awkerr (awk); print_awkerr (awk);

11
qse/configure vendored
View File

@ -15518,6 +15518,17 @@ _ACEOF
fi fi
done 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" OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS" LIBS="$LIBM $LIBS"

View File

@ -100,6 +100,7 @@ AC_CHECK_FUNCS([timegm timelocal])
AC_CHECK_FUNCS([utime utimes]) 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])
OLDLIBS="$LIBS" OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS" LIBS="$LIBM $LIBS"

View File

@ -84,9 +84,13 @@ enum qse_tre_cflag_t
enum qse_tre_eflag_t enum qse_tre_eflag_t
{ {
QSE_TRE_NOTBOL = (1 << 0), QSE_TRE_BACKTRACKING = (1 << 0),
QSE_TRE_NOTEOL = (1 << 1),
QSE_TRE_BACKTRACKING = (1 << 2) /* 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; 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. */ /* Define to 1 if you have the `expl' function. */
#undef HAVE_EXPL #undef HAVE_EXPL
/* Define to 1 if you have the `fdopendir' function. */
#undef HAVE_FDOPENDIR
/* Define to 1 if you have the `fmod' function. */ /* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD #undef HAVE_FMOD

View File

@ -44,7 +44,7 @@ struct qse_htre_t
int chunked; int chunked;
int content_length_set; int content_length_set;
qse_size_t content_length; qse_size_t content_length;
int connection_close; int keepalive;
int expect_continue; int expect_continue;
/* indicates if the content has been filled */ /* 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; typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
struct 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) ( int (*handle_request) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
int (*handle_expect_continue) ( int (*handle_expect_continue) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); 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; 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, qse_httpd_t* httpd,
const qse_char_t* uri const qse_char_t* uri
); );
@ -200,13 +194,21 @@ qse_httpd_task_t* qse_httpd_entaskfile (
qse_foff_t size 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_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, const qse_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
const qse_http_range_t* range, 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 ( qse_httpd_task_t* qse_httpd_entaskcgi (

View File

@ -1089,7 +1089,7 @@ int qse_awk_matchrex (
x = qse_matchrex ( x = qse_matchrex (
awk->mmgr, awk->rex.depth.max.match, awk->mmgr, awk->rex.depth.max.match,
code, option, str, substr, match, &err); code, option, str, substr, match, &err);
if (x < 0) *errnum = QSE_AWK_REXERRTOERR(err); if (x <= -1) *errnum = QSE_AWK_REXERRTOERR(err);
return x; 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 (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr); if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
riod->handle = sio; riod->handle = sio;
rxtn->c.in.count++; rxtn->c.in.count++;
return 1; return 1;
@ -1114,6 +1115,8 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
return -1; return -1;
} }
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
if (qse_awk_rtx_setfilename ( if (qse_awk_rtx_setfilename (
rtx, file, qse_strlen(file)) <= -1) 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 (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
riod->handle = sio; riod->handle = sio;
rxtn->c.out.count++; rxtn->c.out.count++;
return 1; 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); QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR);
if (sio == QSE_NULL) return -1; if (sio == QSE_NULL) return -1;
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
if (qse_awk_rtx_setofilename ( if (qse_awk_rtx_setofilename (
rtx, file, qse_strlen(file)) <= -1) 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]); 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) qse_cmgr_t* qse_getcmgrbyname (const qse_char_t* name)
{ {
if (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("")) == 0) return dfl_cmgr;
if (qse_strcmp(name, QSE_T("utf8")) == 0) return qse_utf8cmgr; if (qse_strcmp(name, QSE_T("utf8")) == 0) return qse_utf8cmgr;
if (qse_strcmp(name, QSE_T("slmb")) == 0) return qse_slmbcmgr; 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; return QSE_NULL;
} }

View File

@ -132,28 +132,22 @@ typedef struct tre_backtrack_struct
s = tre_bt_mem_alloc(mem, sizeof(*s)); \ s = tre_bt_mem_alloc(mem, sizeof(*s)); \
if (!s) \ if (!s) \
{ \ { \
tre_bt_mem_destroy(mem); \ tre_bt_mem_destroy(mem); \
if (tags) \ if (tags) xfree(_mmgr,tags); \
xfree(_mmgr,tags); \ if (pmatch) xfree(_mmgr,pmatch); \
if (pmatch) \ if (states_seen) xfree(_mmgr,states_seen); \
xfree(_mmgr,pmatch); \
if (states_seen) \
xfree(_mmgr,states_seen); \
return REG_ESPACE; \ return REG_ESPACE; \
} \ } \
s->prev = stack; \ s->prev = stack; \
s->next = NULL; \ s->next = NULL; \
s->item.tags = tre_bt_mem_alloc(mem, \ s->item.tags = tre_bt_mem_alloc(mem, \
sizeof(*tags) * tnfa->num_tags); \ sizeof(*tags) * tnfa->num_tags); \
if (!s->item.tags) \ if (!s->item.tags) \
{ \ { \
tre_bt_mem_destroy(mem); \ tre_bt_mem_destroy(mem); \
if (tags) \ if (tags) xfree(_mmgr,tags); \
xfree(_mmgr,tags); \ if (pmatch) xfree(_mmgr,pmatch); \
if (pmatch) \ if (states_seen) xfree(_mmgr,states_seen); \
xfree(_mmgr,pmatch); \
if (states_seen) \
xfree(_mmgr,states_seen); \
return REG_ESPACE; \ return REG_ESPACE; \
} \ } \
stack->next = s; \ 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->code_min, trans_i->code_max, trans_i->code_min, trans_i->code_max,
trans_i->assertions, trans_i->state_id)); trans_i->assertions, trans_i->state_id));
if (trans_i->code_min <= (tre_cint_t)prev_c if (trans_i->code_min <= (tre_cint_t)prev_c &&
&& trans_i->code_max >= (tre_cint_t)prev_c) trans_i->code_max >= (tre_cint_t)prev_c)
{ {
if (trans_i->assertions if (trans_i->assertions
&& (CHECK_ASSERTIONS(trans_i->assertions) && (CHECK_ASSERTIONS(trans_i->assertions)

View File

@ -409,7 +409,7 @@ tre_tnfa_run_parallel(qse_mmgr_t* mmgr, const tre_tnfa_t *tnfa, const void *stri
{ {
/* Does this transition match the input symbol? */ /* Does this transition match the input symbol? */
if (trans_i->code_min <= (tre_cint_t)prev_c && if (trans_i->code_min <= (tre_cint_t)prev_c &&
trans_i->code_max >= (tre_cint_t)prev_c) trans_i->code_max >= (tre_cint_t)prev_c)
{ {
if (trans_i->assertions if (trans_i->assertions
&& (CHECK_ASSERTIONS(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; if (qse_htre_setsmessagefromcstr (&htrd->re, &tmp) <= -1) goto outofmem;
/* adjust Connection: close for HTTP 1.0 or eariler */ /* adjust Connection: Keep-Alive for HTTP 1.1 or later */
if (htrd->re.version.major < 1 || if (htrd->re.version.major > 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor == 0)) (htrd->re.version.major == 1 && htrd->re.version.minor >= 1))
{ {
htrd->re.attr.connection_close = 1; htrd->re.attr.keepalive = 1;
} }
} }
else else
@ -379,11 +379,11 @@ static qse_mchar_t* parse_initial_line (
/* skip trailing spaces on the line */ /* skip trailing spaces on the line */
while (is_space_octet(*p)) p++; while (is_space_octet(*p)) p++;
/* adjust Connection: close for HTTP 1.0 or eariler */ /* adjust Connection: Keep-Alive for HTTP 1.1 or later */
if (htrd->re.version.major < 1 || if (htrd->re.version.major > 1 ||
(htrd->re.version.major == 1 && htrd->re.version.minor == 0)) (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; htrd->recbs = recbs;
} }
#define octet_tolower(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) | 0x20) : (c)) static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair)
#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)
{ {
int n; 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) if (n == 0)
{ {
htrd->re.attr.connection_close = 1; htrd->re.attr.keepalive = 0;
return 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) if (n == 0)
{ {
htrd->re.attr.connection_close = 0; htrd->re.attr.keepalive = 1;
return 0; 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; return 0;
} }
static QSE_INLINE int capture_content_length ( static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair)
qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
qse_size_t len = 0, off = 0, tmp; qse_size_t len = 0, off = 0, tmp;
const qse_mchar_t* ptr = QSE_HTB_VPTR(pair); const qse_mchar_t* ptr = QSE_HTB_VPTR(pair);
@ -525,12 +513,12 @@ static QSE_INLINE int capture_content_length (
return 0; return 0;
} }
static QSE_INLINE int capture_expect ( static int capture_expect (qse_htrd_t* htrd, qse_htb_pair_t* pair)
qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
int n; 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) if (n == 0)
{ {
@ -542,12 +530,12 @@ static QSE_INLINE int capture_expect (
return 0; return 0;
} }
static QSE_INLINE int capture_transfer_encoding ( static int capture_transfer_encoding (qse_htrd_t* htrd, qse_htb_pair_t* pair)
qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
int n; 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 (n == 0)
{ {
/* if (htrd->re.attr.content_length > 0) */ /* if (htrd->re.attr.content_length > 0) */
@ -591,7 +579,7 @@ static QSE_INLINE int capture_key_header (
{ {
mid = base + count / 2; mid = base + count / 2;
n = compare_octets ( n = qse_mbsxncasecmp (
QSE_HTB_KPTR(pair), QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), QSE_HTB_KLEN(pair),
hdrtab[mid].ptr, hdrtab[mid].len hdrtab[mid].ptr, hdrtab[mid].len
); );

View File

@ -27,6 +27,7 @@
#include "../cmn/mem.h" #include "../cmn/mem.h"
#include <qse/cmn/chr.h> #include <qse/cmn/chr.h>
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.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]); purge_tasks_locked (httpd, &array->data[fd]);
#if defined(HAVE_PTHREAD) #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 #endif
qse_htrd_close (array->data[fd].htrd); 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 ( static int make_fd_set_from_client_array (
qse_httpd_t* httpd, fd_set* r, fd_set* w) qse_httpd_t* httpd, fd_set* r, fd_set* w)
{ {
@ -955,136 +956,123 @@ static void free_listener_list (qse_httpd_t* httpd, listener_t* l)
} }
} }
static listener_t* parse_listener_string ( static listener_t* parse_listener_uri (
qse_httpd_t* httpd, const qse_char_t* str, listener_t** ltail) qse_httpd_t* httpd, const qse_char_t* uri)
{ {
const qse_char_t* p = str; const qse_char_t* p = uri;
listener_t* lhead = QSE_NULL, * ltmp = QSE_NULL, * lend = QSE_NULL; listener_t* ltmp = QSE_NULL;
qse_cstr_t tmp;
qse_mchar_t* host;
int x;
do ltmp = qse_httpd_allocmem (httpd, QSE_SIZEOF(*ltmp));
if (ltmp == QSE_NULL) goto oops; /* alloc set error number. so goto oops */
QSE_MEMSET (ltmp, 0, QSE_SIZEOF(*ltmp));
ltmp->handle = -1;
/* check the protocol part */
tmp.ptr = p;
while (*p != QSE_T(':'))
{ {
qse_cstr_t tmp; if (*p == QSE_T('\0')) goto oops_einval;
qse_mchar_t* host; p++;
int x; }
tmp.len = p - tmp.ptr;
if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0)
{
ltmp->secure = 0;
ltmp->port = DEFAULT_PORT;
}
else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0)
{
ltmp->secure = 1;
ltmp->port = DEFAULT_SECURE_PORT;
}
else goto oops;
/* skip spaces */ p++; /* skip : */
while (QSE_ISSPACE(*p)) p++; if (*p != QSE_T('/')) goto oops_einval;
p++; /* skip / */
if (*p != QSE_T('/')) goto oops_einval;
p++; /* skip / */
ltmp = qse_httpd_allocmem (httpd, QSE_SIZEOF(*ltmp)); #ifdef AF_INET6
if (ltmp == QSE_NULL) goto oops; /* alloc set error number. so goto oops */ if (*p == QSE_T('['))
{
/* IPv6 address */
p++; /* skip [ */
QSE_MEMSET (ltmp, 0, QSE_SIZEOF(*ltmp)); for (tmp.ptr = p; *p != QSE_T(']'); p++)
ltmp->handle = -1;
/* check the protocol part */
tmp.ptr = p;
while (*p != QSE_T(':'))
{ {
if (*p == QSE_T('\0')) goto oops_einval; if (*p == QSE_T('\0')) goto oops_einval;
p++; }
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 */
for (tmp.ptr = p; ; p++)
{
if (*p == QSE_T(':') || *p == QSE_T('\0')) break;
} }
tmp.len = p - tmp.ptr; tmp.len = p - tmp.ptr;
if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0) ltmp->family = AF_INET;
{
ltmp->secure = 0;
ltmp->port = DEFAULT_PORT;
}
else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0)
{
ltmp->secure = 1;
ltmp->port = DEFAULT_SECURE_PORT;
}
else goto oops;
p++; /* skip : */
if (*p != QSE_T('/')) goto oops_einval;
p++; /* skip / */
if (*p != QSE_T('/')) goto oops_einval;
p++; /* skip / */
#ifdef AF_INET6 #ifdef AF_INET6
if (*p == QSE_T('['))
{
/* IPv6 address */
p++; /* skip [ */
tmp.ptr = p;
while (*p != QSE_T(']'))
{
if (*p == QSE_T('\0')) goto oops_einval;
p++;
}
tmp.len = p - tmp.ptr;
ltmp->family = AF_INET6;
p++; /* skip ] */
}
else
{
#endif
/* host name or IPv4 address */
tmp.ptr = p;
while (!QSE_ISSPACE(*p) &&
*p != QSE_T(':') &&
*p != QSE_T('\0')) p++;
tmp.len = p - tmp.ptr;
ltmp->family = AF_INET;
#ifdef AF_INET6
}
#endif
ltmp->host = qse_strxdup (tmp.ptr, tmp.len, httpd->mmgr);
if (ltmp->host == QSE_NULL) goto oops_enomem;
#ifdef QSE_CHAR_IS_WCHAR
host = qse_wcstombsdup (ltmp->host, httpd->mmgr);
if (host == QSE_NULL) goto oops_enomem;
#else
host = ltmp->host;
#endif
x = inet_pton (ltmp->family, host, &ltmp->addr);
#ifdef QSE_CHAR_IS_WCHAR
qse_httpd_freemem (httpd, host);
#endif
if (x != 1)
{
/* TODO: need to support host names???
if (getaddrinfo... )....
or CALL a user callback for name resolution?
if (httpd->cbs.resolve_hostname (httpd, ltmp->host) <= -1) must call this with host before freeing it up????
*/
goto oops_einval;
}
if (*p == QSE_T(':'))
{
unsigned int port = 0;
/* port number */
p++;
tmp.ptr = p;
while (QSE_ISDIGIT(*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;
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')); #endif
if (ltail) *ltail = lend; ltmp->host = qse_strxdup (tmp.ptr, tmp.len, httpd->mmgr);
return lhead; if (ltmp->host == QSE_NULL) goto oops_enomem;
#ifdef QSE_CHAR_IS_WCHAR
host = qse_wcstombsdup (ltmp->host, httpd->mmgr);
if (host == QSE_NULL) goto oops_enomem;
#else
host = ltmp->host;
#endif
x = inet_pton (ltmp->family, host, &ltmp->addr);
#ifdef QSE_CHAR_IS_WCHAR
qse_httpd_freemem (httpd, host);
#endif
if (x != 1)
{
/* TODO: need to support host names???
if (getaddrinfo... )....
or CALL a user callback for name resolution?
if (httpd->cbs.resolve_hostname (httpd, ltmp->host) <= -1) must call this with host before freeing it up????
*/
goto oops_einval;
}
if (*p == QSE_T(':'))
{
unsigned int port = 0;
/* port number */
p++;
for (tmp.ptr = p; QSE_ISDIGIT(*p); p++)
port = port * 10 + (*p - QSE_T('0'));
tmp.len = p - tmp.ptr;
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++;
return ltmp;
oops_einval: oops_einval:
httpd->errnum = QSE_HTTPD_EINVAL; httpd->errnum = QSE_HTTPD_EINVAL;
@ -1096,19 +1084,18 @@ oops_enomem:
oops: oops:
if (ltmp) free_listener (httpd, ltmp); if (ltmp) free_listener (httpd, ltmp);
if (lhead) free_listener_list (httpd, lhead);
return QSE_NULL; 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); lsn = parse_listener_uri (httpd, uri);
if (lh == QSE_NULL) return -1; if (lsn == QSE_NULL) return -1;
lt->next = httpd->listener.list; lsn->next = httpd->listener.list;
httpd->listener.list = lh; httpd->listener.list = lsn;
/* /*
TODO: mutex protection... TODO: mutex protection...
if in the activated state... 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; 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; if (lh == QSE_NULL) return -1;
for (li = lh; li; li = li->next) 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 #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) #if defined(HAVE_PTHREAD)
int n; int n;
pthread_mutex_lock (&httpd->listener.mutex); pthread_mutex_lock (&httpd->listener.mutex);
n = add_listeners (httpd, uri); n = add_listener (httpd, uri);
pthread_mutex_unlock (&httpd->listener.mutex); pthread_mutex_unlock (&httpd->listener.mutex);
return n; return n;
#else #else
return add_listeners (httpd, uri); return add_listener (httpd, uri);
#endif #endif
} }
#if 0 #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; int n;
pthread_mutex_lock (&httpd->listener.mutex); pthread_mutex_lock (&httpd->listener.mutex);

View File

@ -33,6 +33,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <dirent.h>
#define MAX_SEND_SIZE 4096 #define MAX_SEND_SIZE 4096
@ -112,7 +113,6 @@ static qse_ssize_t xsendfile (
} }
#endif #endif
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
static int task_main_disconnect ( 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)); 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> #include <unistd.h>
@ -508,6 +627,7 @@ struct task_path_t
const qse_mchar_t* name; const qse_mchar_t* name;
qse_http_range_t range; qse_http_range_t range;
qse_http_version_t version; qse_http_version_t version;
int keepalive;
}; };
static int task_init_path ( static int task_init_path (
@ -521,6 +641,46 @@ static int task_init_path (
return 0; 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 ( static int task_main_path (
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)
{ {
@ -529,45 +689,48 @@ static int task_main_path (
struct stat st; struct stat st;
qse_httpd_task_t* x = task; 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); handle.i = open (data->name, O_RDONLY);
if (handle.i <= -1) 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 = entask_path_error (httpd, client, x, 404);
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
);
goto no_file_send; goto no_file_send;
} }
fcntl (handle.i, F_SETFD, FD_CLOEXEC); fcntl (handle.i, F_SETFD, FD_CLOEXEC);
if (fstat (handle.i, &st) <= -1) 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 = entask_path_error (httpd, client, x, 404);
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
);
goto no_file_send; goto no_file_send;
} }
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
{ {
/* TODO: directory listing */ qse_ubi_t dir;
const qse_mchar_t* msg = QSE_MT("<html><head><title>Directory Listing</title></head><body><li>file1<li>file2<li>file3</body></html>");
x = qse_httpd_entaskformat ( /*#if defined(HAVE_FDOPENDIR)
httpd, client, x, dir.ptr = fdopendir (handle.i);
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"), #else */
data->version.major, data->version.minor, dir.ptr = opendir (data->name);
(int)qse_mbslen(msg) + 4, msg /*#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\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,
(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; 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) if (data->range.from >= st.st_size)
{ {
const qse_mchar_t* msg; x = entask_path_error (httpd, client, x, 416);
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
);
goto no_file_send; goto no_file_send;
} }
if (data->range.to >= st.st_size) data->range.to = st.st_size - 1; 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; 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... */ /*TODO: how to handle an error... */
} }
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat ( x = qse_httpd_entaskformat (
httpd, client, x, 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.major,
data->version.minor, data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")), (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")), (mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): 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 #else
x = qse_httpd_entaskformat ( x = qse_httpd_entaskformat (
httpd, client, x, 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.major,
data->version.minor, data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")), (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")), (mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): QSE_MT("")), (mime_type? QSE_MT("\r\n"): QSE_MT("")),
@ -642,10 +799,10 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
if (x) if (x)
{ {
x = qse_httpd_entaskfile ( x = qse_httpd_entaskfile (
httpd, client, x, httpd, client, x,
handle, handle,
data->range.from, data->range.from,
(data->range.to - data->range.from + 1) (data->range.to - data->range.from + 1)
); );
} }
} }
@ -654,19 +811,22 @@ qse_printf (QSE_T("opending file %hs\n"), data->name);
/* TODO: int64 format.... don't hard code it llu */ /* TODO: int64 format.... don't hard code it llu */
const qse_mchar_t* mime_type = QSE_NULL; const qse_mchar_t* mime_type = QSE_NULL;
if (httpd->cbs->file.getmimetype) if (httpd->cbs->getmimetype)
{ {
httpd->errnum = QSE_HTTPD_ENOERR; 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... */ /*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) #if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat ( x = qse_httpd_entaskformat (
httpd, client, x, 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"), 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.major, data->version.minor,
data->version.minor, (data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")), (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")), (mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): 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 #else
x = qse_httpd_entaskformat ( x = qse_httpd_entaskformat (
httpd, client, x, 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.major,
data->version.minor, data->version.minor,
(data->keepalive? QSE_MT("Keep-Alive"): QSE_MT("Close")),
(mime_type? QSE_MT("Content-Type: "): QSE_MT("")), (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
(mime_type? mime_type: QSE_MT("")), (mime_type? mime_type: QSE_MT("")),
(mime_type? QSE_MT("\r\n"): 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_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
const qse_http_range_t* range, 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; qse_httpd_task_t task;
task_path_t data; task_path_t data;
@ -716,6 +878,7 @@ qse_httpd_task_t* qse_httpd_entaskpath (
if (range) data.range = *range; if (range) data.range = *range;
else data.range.type = QSE_HTTP_RANGE_NONE; else data.range.type = QSE_HTTP_RANGE_NONE;
data.version = *verison; data.version = *verison;
data.keepalive = keepalive;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_path; task.init = task_init_path;

View File

@ -30,8 +30,9 @@
#else #else
# if defined(QSE_CHAR_IS_MCHAR) && defined(USE_REGEX) # if defined(QSE_CHAR_IS_MCHAR) && defined(USE_REGEX)
# include <regex.h> # include <regex.h>
# else
# include <qse/cmn/tre.h>
# endif # endif
# include <qse/cmn/tre.h>
#endif #endif
QSE_IMPLEMENT_COMMON_FUNCTIONS (sed) 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, httpd, client, QSE_NULL,
qse_htre_getqpathptr(req), qse_htre_getqpathptr(req),
(rangestr? &range: QSE_NULL), (rangestr? &range: QSE_NULL),
qse_htre_getversion(req) qse_htre_getversion(req),
req->attr.keepalive
); );
if (x == QSE_NULL) goto oops; 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: done:
if (req->attr.connection_close) if (!req->attr.keepalive)
{ {
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
if (x == QSE_NULL) goto oops; 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; return QSE_NULL;
} }
int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path)
{
return 404;
}
static qse_httpd_t* httpd = NULL; static qse_httpd_t* httpd = NULL;
static void sigint (int sig) static void sigint (int sig)
@ -158,9 +164,10 @@ static void sigint (int sig)
static qse_httpd_cbs_t httpd_cbs = static qse_httpd_cbs_t httpd_cbs =
{ {
{ get_mime_type, QSE_NULL, },
handle_request, handle_request,
handle_expect_continue handle_expect_continue,
get_mime_type,
list_directory
}; };
int httpd_main (int argc, qse_char_t* argv[]) int httpd_main (int argc, qse_char_t* argv[])
@ -168,9 +175,9 @@ int httpd_main (int argc, qse_char_t* argv[])
int n; int n;
httpd_xtn_t* xtn; 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; return -1;
} }
@ -184,11 +191,15 @@ int httpd_main (int argc, qse_char_t* argv[])
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
xtn->orgcbs = qse_httpd_getcbs (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_httpd_close (httpd); {
return -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); qse_httpd_setcbs (httpd, &httpd_cbs);