enhanced httpd a bit
This commit is contained in:
parent
b9a0863fff
commit
adb9f387f9
@ -70,34 +70,34 @@ const qse_wchar_t* qse_wcsbasename (
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_isabspath() function determines if a path name is absolute.
|
||||
* The qse_ismbsabspath() function determines if a path name is absolute.
|
||||
* A path name beginning with a segment separator is absolute.
|
||||
* On Win32/OS2/DOS, it also returns 1 if a path name begins with a drive
|
||||
* letter followed by a colon.
|
||||
* @return 1 if absolute, 0 if not.
|
||||
*/
|
||||
int qse_isabspath (
|
||||
const qse_char_t* path
|
||||
int qse_ismbsabspath (
|
||||
const qse_mchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_isdrivepath() function determines if a path name begins with
|
||||
* The qse_ismbsdrivepath() function determines if a path name begins with
|
||||
* a drive letter followed by a colon like A:.
|
||||
*/
|
||||
int qse_isdrivepath (
|
||||
const qse_char_t* path
|
||||
int qse_ismbsdrivepath (
|
||||
const qse_mchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_isdrivecurpath() function determines if a path name is in the form
|
||||
* The qse_ismbsdrivecurpath() function determines if a path name is in the form
|
||||
* of a drive letter followed by a colon like A:, without any trailing path.
|
||||
*/
|
||||
int qse_isdrivecurpath (
|
||||
const qse_char_t* path
|
||||
int qse_ismbsdrivecurpath (
|
||||
const qse_mchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_canonpath() function canonicalizes a path name @a path by deleting
|
||||
* The qse_canonmbspath() function canonicalizes a path name @a path by deleting
|
||||
* unnecessary path segments from it and stores the result to a memory buffer
|
||||
* pointed to by @a canon. Canonicalization is purely performed on the path
|
||||
* name without refering to actual file systems. It null-terminates the
|
||||
@ -105,9 +105,9 @@ int qse_isdrivecurpath (
|
||||
* the terminating null.
|
||||
*
|
||||
* @code
|
||||
* qse_char_t buf[64];
|
||||
* qse_canonpath ("/usr/local/../bin/sh", buf);
|
||||
* qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh
|
||||
* qse_mchar_t buf[64];
|
||||
* qse_canonmbspath (QSE_MT("/usr/local/../bin/sh"), buf);
|
||||
* qse_printf (QSE_T("%hs\n")); // prints /usr/bin/sh
|
||||
* @endcode
|
||||
*
|
||||
* If #QSE_CANONPATH_EMPTYSINGLEDOT is clear in the @a flags, a single dot
|
||||
@ -129,12 +129,90 @@ int qse_isdrivecurpath (
|
||||
* @return number of characters in the resulting canonical path excluding
|
||||
* the terminating null.
|
||||
*/
|
||||
qse_size_t qse_canonpath (
|
||||
const qse_char_t* path,
|
||||
qse_char_t* canon,
|
||||
qse_size_t qse_canonmbspath (
|
||||
const qse_mchar_t* path,
|
||||
qse_mchar_t* canon,
|
||||
int flags
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_iswcsabspath() function determines if a path name is absolute.
|
||||
* A path name beginning with a segment separator is absolute.
|
||||
* On Win32/OS2/DOS, it also returns 1 if a path name begins with a drive
|
||||
* letter followed by a colon.
|
||||
* @return 1 if absolute, 0 if not.
|
||||
*/
|
||||
int qse_iswcsabspath (
|
||||
const qse_wchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_iswcsdrivepath() function determines if a path name begins with
|
||||
* a drive letter followed by a colon like A:.
|
||||
*/
|
||||
int qse_iswcsdrivepath (
|
||||
const qse_wchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_iswcsdrivecurpath() function determines if a path name is in the form
|
||||
* of a drive letter followed by a colon like A:, without any trailing path.
|
||||
*/
|
||||
int qse_iswcsdrivecurpath (
|
||||
const qse_wchar_t* path
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_canonwcspath() function canonicalizes a path name @a path by deleting
|
||||
* unnecessary path segments from it and stores the result to a memory buffer
|
||||
* pointed to by @a canon. Canonicalization is purely performed on the path
|
||||
* name without refering to actual file systems. It null-terminates the
|
||||
* canonical path in @a canon and returns the number of characters excluding
|
||||
* the terminating null.
|
||||
*
|
||||
* @code
|
||||
* qse_wchar_t buf[64];
|
||||
* qse_canonwcspath (QSE_WT("/usr/local/../bin/sh"), buf);
|
||||
* qse_printf (QSE_T("%ls\n")); // prints /usr/bin/sh
|
||||
* @endcode
|
||||
*
|
||||
* If #QSE_CANONPATH_EMPTYSINGLEDOT is clear in the @a flags, a single dot
|
||||
* is produced if the input @path resolves to the current directory logically.
|
||||
* For example, dir/.. is canonicalized to a single period; If it is set,
|
||||
* an empty string is produced. Even a single period as an input produces
|
||||
* an empty string if it is set.
|
||||
*
|
||||
* The output is empty returning 0 regardless of @a flags if the input
|
||||
* @a path is empty.
|
||||
*
|
||||
* The caller must ensure that it is large enough to hold the resulting
|
||||
* canonical path before calling because this function does not check the
|
||||
* size of the memory buffer. Since the canonical path cannot be larger
|
||||
* than the original path, you can simply ensure this by providing a memory
|
||||
* buffer as long as the number of characters and a terminating null in
|
||||
* the original path.
|
||||
*
|
||||
* @return number of characters in the resulting canonical path excluding
|
||||
* the terminating null.
|
||||
*/
|
||||
qse_size_t qse_canonwcspath (
|
||||
const qse_wchar_t* path,
|
||||
qse_wchar_t* canon,
|
||||
int flags
|
||||
);
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
# define qse_isabspath(p) qse_ismbsabspath(p)
|
||||
# define qse_isdrivepath(p) qse_ismbsdrivepath(p)
|
||||
# define qse_isdrivecurpath(p) qse_ismbsdrivecurpath(p)
|
||||
# define qse_canonpath(p,c,f) qse_canonmbspath(p,c,f)
|
||||
#else
|
||||
# define qse_isabspath(p) qse_iswcsabspath(p)
|
||||
# define qse_isdrivepath(p) qse_iswcsdrivepath(p)
|
||||
# define qse_isdrivecurpath(p) qse_iswcsdrivecurpath(p)
|
||||
# define qse_canonpath(p,c,f) qse_canonwcspath(p,c,f)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -51,11 +51,12 @@ enum qse_htrd_option_t
|
||||
{
|
||||
QSE_HTRD_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */
|
||||
QSE_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an initial line */
|
||||
QSE_HTRD_PEEKONLY = (1 << 2), /**< trigger a peek callback after headers without processing contents */
|
||||
QSE_HTRD_REQUEST = (1 << 3), /**< parse input as a request */
|
||||
QSE_HTRD_RESPONSE = (1 << 4), /**< parse input as a response */
|
||||
QSE_HTRD_TRAILERS = (1 << 5), /**< store trailers in a separate table */
|
||||
QSE_HTRD_STRICT = (1 << 6) /**< be more picky */
|
||||
QSE_HTRD_CANONQPATH = (1 << 2), /**< canonicalize the query path */
|
||||
QSE_HTRD_PEEKONLY = (1 << 3), /**< trigger a peek callback after headers without processing contents */
|
||||
QSE_HTRD_REQUEST = (1 << 4), /**< parse input as a request */
|
||||
QSE_HTRD_RESPONSE = (1 << 5), /**< parse input as a response */
|
||||
QSE_HTRD_TRAILERS = (1 << 6), /**< store trailers in a separate table */
|
||||
QSE_HTRD_STRICT = (1 << 7) /**< be more picky */
|
||||
};
|
||||
|
||||
typedef enum qse_htrd_option_t qse_htrd_option_t;
|
||||
|
@ -187,11 +187,24 @@ int qse_parsehttpdatetime (
|
||||
);
|
||||
*/
|
||||
|
||||
/* percent-decode a string */
|
||||
qse_size_t qse_perdechttpstr (
|
||||
const qse_mchar_t* str,
|
||||
qse_mchar_t* buf
|
||||
);
|
||||
|
||||
|
||||
/* percent-encode a string */
|
||||
qse_size_t qse_perenchttpstr (
|
||||
const qse_mchar_t* str,
|
||||
qse_mchar_t* buf
|
||||
);
|
||||
|
||||
qse_mchar_t* qse_perenchttpstrdup (
|
||||
const qse_mchar_t* str,
|
||||
qse_mmgr_t* mmgr
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -104,14 +104,8 @@ typedef int (*qse_httpd_muxcb_t) (
|
||||
void* cbarg
|
||||
);
|
||||
|
||||
typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
|
||||
struct qse_httpd_dirent_t
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
||||
struct qse_httpd_cbs_t
|
||||
typedef struct qse_httpd_scb_t qse_httpd_scb_t;
|
||||
struct qse_httpd_scb_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
@ -212,7 +206,11 @@ struct qse_httpd_cbs_t
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client); /* optional */
|
||||
} client;
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_rcb_t qse_httpd_rcb_t;
|
||||
struct qse_httpd_rcb_t
|
||||
{
|
||||
int (*peek_request) (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
||||
int (*handle_request) (
|
||||
@ -335,6 +333,7 @@ struct qse_httpd_ecb_t
|
||||
qse_httpd_ecb_t* next;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -396,7 +395,8 @@ void qse_httpd_pushecb (
|
||||
*/
|
||||
int qse_httpd_loop (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_cbs_t* cbs,
|
||||
qse_httpd_scb_t* scb,
|
||||
qse_httpd_rcb_t* rcb,
|
||||
qse_ntime_t timeout
|
||||
);
|
||||
|
||||
@ -506,7 +506,7 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
||||
qse_htre_t* req
|
||||
);
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskdir (
|
||||
qse_httpd_task_t* qse_httpd_entaskpath (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
@ -574,6 +574,7 @@ void* qse_httpd_getxtnstd (
|
||||
|
||||
int qse_httpd_loopstd (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_rcb_t* rcb,
|
||||
qse_ntime_t timeout
|
||||
);
|
||||
|
||||
|
@ -20,63 +20,67 @@
|
||||
|
||||
#include <qse/cmn/path.h>
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* MBS IMPLEMENTATION */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
# define IS_SEP(c) ((c) == QSE_T('/') || (c) == QSE_T('\\'))
|
||||
# define IS_MSEP(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\'))
|
||||
#else
|
||||
# define IS_SEP(c) ((c) == QSE_T('/'))
|
||||
# define IS_MSEP(c) ((c) == QSE_MT('/'))
|
||||
#endif
|
||||
|
||||
#define IS_NIL(c) ((c) == QSE_T('\0'))
|
||||
#define IS_SEP_OR_NIL(c) (IS_SEP(c) || IS_NIL(c))
|
||||
#define IS_MNIL(c) ((c) == QSE_MT('\0'))
|
||||
#define IS_MSEP_OR_MNIL(c) (IS_MSEP(c) || IS_MNIL(c))
|
||||
|
||||
#define ISDRIVE(s) \
|
||||
(((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \
|
||||
(s[0] >= QSE_T('a') && s[0] <= QSE_T('z'))) && \
|
||||
s[1] == QSE_T(':'))
|
||||
#define IS_MDRIVE(s) \
|
||||
(((s[0] >= QSE_MT('A') && s[0] <= QSE_MT('Z')) || \
|
||||
(s[0] >= QSE_MT('a') && s[0] <= QSE_MT('z'))) && \
|
||||
s[1] == QSE_MT(':'))
|
||||
|
||||
int qse_isabspath (const qse_char_t* path)
|
||||
int qse_ismbsabspath (const qse_mchar_t* path)
|
||||
{
|
||||
if (IS_SEP(path[0])) return 1;
|
||||
if (IS_MSEP(path[0])) return 1;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
/* a drive like c:tmp is absolute in positioning the drive.
|
||||
* but the path within the drive is kind of relative */
|
||||
if (ISDRIVE(path)) return 1;
|
||||
if (IS_MDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int qse_isdrivepath (const qse_char_t* path)
|
||||
int qse_ismbsdrivepath (const qse_mchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(path)) return 1;
|
||||
if (IS_MDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_isdrivecurpath (const qse_char_t* path)
|
||||
int qse_ismbsdrivecurpath (const qse_mchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(path) && path[2] == QSE_T('\0')) return 1;
|
||||
if (IS_MDRIVE(path) && path[2] == QSE_MT('\0')) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
qse_size_t qse_canonmbspath (const qse_mchar_t* path, qse_mchar_t* canon, int flags)
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
qse_char_t* dst;
|
||||
qse_char_t* non_root_start;
|
||||
const qse_mchar_t* ptr;
|
||||
qse_mchar_t* dst;
|
||||
qse_mchar_t* non_root_start;
|
||||
int has_root = 0;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
int is_drive = 0;
|
||||
#endif
|
||||
qse_size_t canon_len;
|
||||
|
||||
if (path[0] == QSE_T('\0'))
|
||||
if (path[0] == QSE_MT('\0'))
|
||||
{
|
||||
/* if the source is empty, no translation is needed */
|
||||
canon[0] = QSE_T('\0');
|
||||
canon[0] = QSE_MT('\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -84,31 +88,31 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
dst = canon;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(ptr))
|
||||
if (IS_MDRIVE(ptr))
|
||||
{
|
||||
/* handle drive letter */
|
||||
*dst++ = *ptr++; /* drive letter */
|
||||
*dst++ = *ptr++; /* colon */
|
||||
|
||||
is_drive = 1;
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
}
|
||||
else if (IS_SEP(*ptr))
|
||||
else if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* handle UNC path for Windows */
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++;
|
||||
|
||||
if (IS_SEP_OR_NIL(*ptr))
|
||||
if (IS_MSEP_OR_MNIL(*ptr))
|
||||
{
|
||||
/* if there is another separator after \\,
|
||||
* it's not an UNC path. */
|
||||
@ -117,14 +121,14 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
else
|
||||
{
|
||||
/* if it starts with \\, process host name */
|
||||
do { *dst++ = *ptr++; } while (!IS_SEP_OR_NIL(*ptr));
|
||||
if (IS_SEP(*ptr)) *dst++ = *ptr++;
|
||||
do { *dst++ = *ptr++; } while (!IS_MSEP_OR_MNIL(*ptr));
|
||||
if (IS_MSEP(*ptr)) *dst++ = *ptr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
@ -137,30 +141,30 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
|
||||
do
|
||||
{
|
||||
const qse_char_t* seg;
|
||||
const qse_mchar_t* seg;
|
||||
qse_size_t seglen;
|
||||
|
||||
/* skip duplicate separators */
|
||||
while (IS_SEP(*ptr)) ptr++;
|
||||
while (IS_MSEP(*ptr)) ptr++;
|
||||
|
||||
/* end of path reached */
|
||||
if (*ptr == QSE_T('\0')) break;
|
||||
if (*ptr == QSE_MT('\0')) break;
|
||||
|
||||
/* find the next segment */
|
||||
seg = ptr;
|
||||
while (!IS_SEP_OR_NIL(*ptr)) ptr++;
|
||||
while (!IS_MSEP_OR_MNIL(*ptr)) ptr++;
|
||||
seglen = ptr - seg;
|
||||
|
||||
/* handle the segment */
|
||||
if (seglen == 1 && seg[0] == QSE_T('.'))
|
||||
if (seglen == 1 && seg[0] == QSE_MT('.'))
|
||||
{
|
||||
/* eat up . */
|
||||
}
|
||||
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
|
||||
seglen == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
|
||||
seglen == 2 && seg[0] == QSE_MT('.') && seg[1] == QSE_MT('.'))
|
||||
{
|
||||
/* eat up the previous segment */
|
||||
qse_char_t* tmp;
|
||||
qse_mchar_t* tmp;
|
||||
|
||||
tmp = dst;
|
||||
if (tmp > non_root_start)
|
||||
@ -173,7 +177,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
while (tmp > non_root_start)
|
||||
{
|
||||
tmp--;
|
||||
if (IS_SEP(*tmp))
|
||||
if (IS_MSEP(*tmp))
|
||||
{
|
||||
tmp++; /* position it next to the separator */
|
||||
break;
|
||||
@ -212,7 +216,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
goto normal;
|
||||
}
|
||||
|
||||
if (prevlen == 3 && tmp[0] == QSE_T('.') && tmp[1] == QSE_T('.'))
|
||||
if (prevlen == 3 && tmp[0] == QSE_MT('.') && tmp[1] == QSE_MT('.'))
|
||||
{
|
||||
/* nothing to eat away because the previous segment is ../
|
||||
*
|
||||
@ -234,7 +238,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
{
|
||||
normal:
|
||||
while (seg < ptr) *dst++ = *seg++;
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
/* this segment ended with a separator */
|
||||
*dst++ = *seg++; /* copy the separator */
|
||||
@ -244,8 +248,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
}
|
||||
while (1);
|
||||
|
||||
if (dst > non_root_start && IS_SEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_SEP(ptr[-1])))
|
||||
if (dst > non_root_start && IS_MSEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_MSEP(ptr[-1])))
|
||||
{
|
||||
/* if the canoncal path composed so far ends with a separator
|
||||
* and the original path didn't end with the separator, delete
|
||||
@ -255,18 +259,18 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
* dst > non_root_start:
|
||||
* there is at least 1 character after the root directory
|
||||
* part.
|
||||
* IS_SEP(dst[-1]):
|
||||
* IS_MSEP(dst[-1]):
|
||||
* the canonical path ends with a separator.
|
||||
* IS_SEP(ptr[-1]):
|
||||
* IS_MSEP(ptr[-1]):
|
||||
* the origial path ends with a separator.
|
||||
*/
|
||||
dst[-1] = QSE_T('\0');
|
||||
dst[-1] = QSE_MT('\0');
|
||||
canon_len = dst - canon - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just null-terminate the canonical path normally */
|
||||
dst[0] = QSE_T('\0');
|
||||
dst[0] = QSE_MT('\0');
|
||||
canon_len = dst - canon;
|
||||
}
|
||||
|
||||
@ -276,8 +280,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
{
|
||||
/* when resolving to a single dot, a trailing separator is not
|
||||
* retained though the orignal path name contains it. */
|
||||
canon[0] = QSE_T('.');
|
||||
canon[1] = QSE_T('\0');
|
||||
canon[0] = QSE_MT('.');
|
||||
canon[1] = QSE_MT('\0');
|
||||
canon_len = 1;
|
||||
}
|
||||
}
|
||||
@ -302,21 +306,328 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
/* i don't have to retain a trailing separator
|
||||
* if the last segment is double slashes because
|
||||
* the double slahses indicate a directory obviously */
|
||||
if (canon[canon_len-3] == QSE_T('.') &&
|
||||
canon[canon_len-2] == QSE_T('.') &&
|
||||
IS_SEP(canon[canon_len-1]))
|
||||
if (canon[canon_len-3] == QSE_MT('.') &&
|
||||
canon[canon_len-2] == QSE_MT('.') &&
|
||||
IS_MSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_T('\0');
|
||||
canon[--canon_len] = QSE_MT('\0');
|
||||
}
|
||||
}
|
||||
else if (canon_len > adj_base_len)
|
||||
{
|
||||
if (IS_SEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_T('.') &&
|
||||
canon[canon_len-2] == QSE_T('.') &&
|
||||
IS_SEP(canon[canon_len-1]))
|
||||
if (IS_MSEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_MT('.') &&
|
||||
canon[canon_len-2] == QSE_MT('.') &&
|
||||
IS_MSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_T('\0');
|
||||
canon[--canon_len] = QSE_MT('\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canon_len;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* WCS IMPLEMENTATION */
|
||||
/* ------------------------------------------------------------------ */
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
# define IS_WSEP(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\'))
|
||||
#else
|
||||
# define IS_WSEP(c) ((c) == QSE_WT('/'))
|
||||
#endif
|
||||
|
||||
#define IS_WNIL(c) ((c) == QSE_WT('\0'))
|
||||
#define IS_WSEP_OR_WNIL(c) (IS_WSEP(c) || IS_WNIL(c))
|
||||
|
||||
#define IS_WDRIVE(s) \
|
||||
(((s[0] >= QSE_WT('A') && s[0] <= QSE_WT('Z')) || \
|
||||
(s[0] >= QSE_WT('a') && s[0] <= QSE_WT('z'))) && \
|
||||
s[1] == QSE_WT(':'))
|
||||
|
||||
int qse_iswcsabspath (const qse_wchar_t* path)
|
||||
{
|
||||
if (IS_WSEP(path[0])) return 1;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
/* a drive like c:tmp is absolute in positioning the drive.
|
||||
* but the path within the drive is kind of relative */
|
||||
if (IS_WDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_iswcsdrivepath (const qse_wchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_iswcsdrivecurpath (const qse_wchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(path) && path[2] == QSE_WT('\0')) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_size_t qse_canonwcspath (const qse_wchar_t* path, qse_wchar_t* canon, int flags)
|
||||
{
|
||||
const qse_wchar_t* ptr;
|
||||
qse_wchar_t* dst;
|
||||
qse_wchar_t* non_root_start;
|
||||
int has_root = 0;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
int is_drive = 0;
|
||||
#endif
|
||||
qse_size_t canon_len;
|
||||
|
||||
if (path[0] == QSE_WT('\0'))
|
||||
{
|
||||
/* if the source is empty, no translation is needed */
|
||||
canon[0] = QSE_WT('\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = path;
|
||||
dst = canon;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(ptr))
|
||||
{
|
||||
/* handle drive letter */
|
||||
*dst++ = *ptr++; /* drive letter */
|
||||
*dst++ = *ptr++; /* colon */
|
||||
|
||||
is_drive = 1;
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
}
|
||||
else if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* handle UNC path for Windows */
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++;
|
||||
|
||||
if (IS_WSEP_OR_WNIL(*ptr))
|
||||
{
|
||||
/* if there is another separator after \\,
|
||||
* it's not an UNC path. */
|
||||
dst--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if it starts with \\, process host name */
|
||||
do { *dst++ = *ptr++; } while (!IS_WSEP_OR_WNIL(*ptr));
|
||||
if (IS_WSEP(*ptr)) *dst++ = *ptr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* non_root_start points to the beginning of the canonicalized
|
||||
* path excluding the root directory part. */
|
||||
non_root_start = dst;
|
||||
|
||||
do
|
||||
{
|
||||
const qse_wchar_t* seg;
|
||||
qse_size_t seglen;
|
||||
|
||||
/* skip duplicate separators */
|
||||
while (IS_WSEP(*ptr)) ptr++;
|
||||
|
||||
/* end of path reached */
|
||||
if (*ptr == QSE_WT('\0')) break;
|
||||
|
||||
/* find the next segment */
|
||||
seg = ptr;
|
||||
while (!IS_WSEP_OR_WNIL(*ptr)) ptr++;
|
||||
seglen = ptr - seg;
|
||||
|
||||
/* handle the segment */
|
||||
if (seglen == 1 && seg[0] == QSE_WT('.'))
|
||||
{
|
||||
/* eat up . */
|
||||
}
|
||||
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
|
||||
seglen == 2 && seg[0] == QSE_WT('.') && seg[1] == QSE_WT('.'))
|
||||
{
|
||||
/* eat up the previous segment */
|
||||
qse_wchar_t* tmp;
|
||||
|
||||
tmp = dst;
|
||||
if (tmp > non_root_start)
|
||||
{
|
||||
/* there is a previous segment. */
|
||||
|
||||
tmp--; /* skip the separator just before .. */
|
||||
|
||||
/* find the beginning of the previous segment */
|
||||
while (tmp > non_root_start)
|
||||
{
|
||||
tmp--;
|
||||
if (IS_WSEP(*tmp))
|
||||
{
|
||||
tmp++; /* position it next to the separator */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_root)
|
||||
{
|
||||
/*
|
||||
* Eat up the previous segment if it exists.
|
||||
*
|
||||
* If it doesn't exist, tmp == dst so dst = tmp
|
||||
* keeps dst unchanged. If it exists,
|
||||
* tmp != dst. so dst = tmp changes dst.
|
||||
*
|
||||
* path /abc/def/..
|
||||
* ^ ^
|
||||
* seg ptr
|
||||
*
|
||||
* canon /abc/def/
|
||||
* ^ ^
|
||||
* tmp dst
|
||||
*/
|
||||
dst = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_size_t prevlen;
|
||||
|
||||
prevlen = dst - tmp;
|
||||
|
||||
if (/*tmp == non_root_start &&*/ prevlen == 0)
|
||||
{
|
||||
/* there is no previous segment */
|
||||
goto normal;
|
||||
}
|
||||
|
||||
if (prevlen == 3 && tmp[0] == QSE_WT('.') && tmp[1] == QSE_WT('.'))
|
||||
{
|
||||
/* nothing to eat away because the previous segment is ../
|
||||
*
|
||||
* path ../../
|
||||
* ^ ^
|
||||
* seg ptr
|
||||
*
|
||||
* canon ../
|
||||
* ^ ^
|
||||
* tmp dst
|
||||
*/
|
||||
goto normal;
|
||||
}
|
||||
|
||||
dst = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
normal:
|
||||
while (seg < ptr) *dst++ = *seg++;
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
/* this segment ended with a separator */
|
||||
*dst++ = *seg++; /* copy the separator */
|
||||
ptr++; /* move forward the pointer */
|
||||
}
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
|
||||
if (dst > non_root_start && IS_WSEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_WSEP(ptr[-1])))
|
||||
{
|
||||
/* if the canoncal path composed so far ends with a separator
|
||||
* and the original path didn't end with the separator, delete
|
||||
* the ending separator.
|
||||
* also delete it if QSE_CANONPATH_DROPTRAILINGSEP is set.
|
||||
*
|
||||
* dst > non_root_start:
|
||||
* there is at least 1 character after the root directory
|
||||
* part.
|
||||
* IS_WSEP(dst[-1]):
|
||||
* the canonical path ends with a separator.
|
||||
* IS_WSEP(ptr[-1]):
|
||||
* the origial path ends with a separator.
|
||||
*/
|
||||
dst[-1] = QSE_WT('\0');
|
||||
canon_len = dst - canon - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just null-terminate the canonical path normally */
|
||||
dst[0] = QSE_WT('\0');
|
||||
canon_len = dst - canon;
|
||||
}
|
||||
|
||||
if (canon_len <= 0)
|
||||
{
|
||||
if (!(flags & QSE_CANONPATH_EMPTYSINGLEDOT))
|
||||
{
|
||||
/* when resolving to a single dot, a trailing separator is not
|
||||
* retained though the orignal path name contains it. */
|
||||
canon[0] = QSE_WT('.');
|
||||
canon[1] = QSE_WT('\0');
|
||||
canon_len = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop a traling separator if the last segment is
|
||||
* double slashes */
|
||||
|
||||
int adj_base_len = 3;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (is_drive && !has_root)
|
||||
{
|
||||
/* A path like A:..\\\ need some adjustment for
|
||||
* finalization below. */
|
||||
adj_base_len += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (canon_len == adj_base_len)
|
||||
{
|
||||
/* i don't have to retain a trailing separator
|
||||
* if the last segment is double slashes because
|
||||
* the double slahses indicate a directory obviously */
|
||||
if (canon[canon_len-3] == QSE_WT('.') &&
|
||||
canon[canon_len-2] == QSE_WT('.') &&
|
||||
IS_WSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_WT('\0');
|
||||
}
|
||||
}
|
||||
else if (canon_len > adj_base_len)
|
||||
{
|
||||
if (IS_WSEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_WT('.') &&
|
||||
canon[canon_len-2] == QSE_WT('.') &&
|
||||
IS_WSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_WT('\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,6 +390,9 @@ static qse_mchar_t* parse_initial_line (
|
||||
}
|
||||
#endif
|
||||
|
||||
if (htrd->option & QSE_HTRD_CANONQPATH)
|
||||
qse_canonmbspath (htrd->re.u.q.path, htrd->re.u.q.path, 0);
|
||||
|
||||
/* skip spaces after the url part */
|
||||
do { p++; } while (is_space_octet(*p));
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/chr.h>
|
||||
#include <qse/cmn/htb.h>
|
||||
#include "../cmn/mem.h"
|
||||
|
||||
int qse_comparehttpversions (
|
||||
const qse_http_version_t* v1,
|
||||
@ -224,3 +225,57 @@ qse_size_t qse_perdechttpstr (const qse_mchar_t* str, qse_mchar_t* buf)
|
||||
*out = QSE_MT('\0');
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
#define IS_UNRESERVED(c) \
|
||||
(((c) >= QSE_MT('A') && (c) <= QSE_MT('Z')) || \
|
||||
((c) >= QSE_MT('a') && (c) <= QSE_MT('z')) || \
|
||||
(c) == QSE_MT('-') || (c) == QSE_T('_') || \
|
||||
(c) == QSE_MT('.') || (c) == QSE_T('~'))
|
||||
|
||||
#define TO_HEX(v) (QSE_MT("0123456789ABCDEF")[(v) & 15])
|
||||
|
||||
qse_size_t qse_perenchttpstr (const qse_mchar_t* str, qse_mchar_t* buf)
|
||||
{
|
||||
const qse_mchar_t* p = str;
|
||||
qse_mchar_t* out = buf;
|
||||
|
||||
while (*p != QSE_T('\0'))
|
||||
{
|
||||
if (IS_UNRESERVED(*p)) *out++ = *p;
|
||||
else
|
||||
{
|
||||
*out++ = QSE_MT('%');
|
||||
*out++ = TO_HEX (*p >> 4);
|
||||
*out++ = TO_HEX (*p & 15);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
*out = QSE_MT('\0');
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
qse_mchar_t* qse_perenchttpstrdup (const qse_mchar_t* str, qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_mchar_t* buf;
|
||||
qse_size_t len = 0;
|
||||
qse_size_t count = 0;
|
||||
|
||||
/* count the number of characters that should be encoded */
|
||||
for (len = 0; str[len] != QSE_T('\0'); len++)
|
||||
{
|
||||
if (!IS_UNRESERVED(str[len])) count++;
|
||||
}
|
||||
|
||||
/* if there are no characters to escape, just return the original string */
|
||||
if (count <= 0) return (qse_mchar_t*)str;
|
||||
|
||||
/* allocate a buffer of an optimal size for escaping, otherwise */
|
||||
buf = QSE_MMGR_ALLOC (mmgr, (len + (count * 2) + 1) * QSE_SIZEOF(*buf));
|
||||
if (buf == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* perform actual escaping */
|
||||
qse_perenchttpstr (str, buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -577,7 +577,7 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
|
||||
|
||||
if (writable) goto forward;
|
||||
|
||||
n = httpd->cbs->mux.writable (
|
||||
n = httpd->scb->mux.writable (
|
||||
httpd, qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN), 0);
|
||||
if (n >= 1)
|
||||
{
|
||||
@ -886,7 +886,7 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client (
|
||||
qse_ssize_t n;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (httpd, client, cgi->buf, cgi->buflen);
|
||||
n = httpd->scb->client.send (httpd, client, cgi->buf, cgi->buflen);
|
||||
if (n > 0)
|
||||
{
|
||||
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
|
||||
@ -1140,7 +1140,7 @@ qse_printf (QSE_T("[cgi_3 sending %d bytes]\n"), (int)count);
|
||||
if (count > 0)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (httpd, client, cgi->res_ptr, count);
|
||||
n = httpd->scb->client.send (httpd, client, cgi->res_ptr, count);
|
||||
|
||||
if (n <= -1)
|
||||
{
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "../cmn/mem.h"
|
||||
#include "../cmn/syscall.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||
|
||||
typedef struct task_dir_t task_dir_t;
|
||||
@ -35,15 +36,24 @@ struct task_dir_t
|
||||
typedef struct task_dseg_t task_dseg_t;
|
||||
struct task_dseg_t
|
||||
{
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int chunked;
|
||||
|
||||
const qse_mchar_t* path;
|
||||
qse_dir_t* handle;
|
||||
qse_dirent_t* dent;
|
||||
|
||||
int header_added;
|
||||
int footer_pending;
|
||||
#define HEADER_ADDED (1 << 0)
|
||||
#define FOOTER_ADDED (1 << 1)
|
||||
#define FOOTER_PENDING (1 << 2)
|
||||
#define DIRENT_PENDING (1 << 3)
|
||||
int state;
|
||||
|
||||
/*qse_mchar_t buf[4096];*/
|
||||
qse_mchar_t buf[512]; /* TOOD: increate size */
|
||||
qse_size_t tcount; /* total directory entries */
|
||||
qse_size_t dcount; /* the number of items in the buffer */
|
||||
|
||||
qse_mchar_t buf[4096];
|
||||
qse_size_t bufpos;
|
||||
qse_size_t buflen;
|
||||
qse_size_t bufrem;
|
||||
@ -70,14 +80,88 @@ static void task_fini_dseg (
|
||||
QSE_CLOSEDIR (ctx->handle);
|
||||
}
|
||||
|
||||
static int task_main_dseg_chunked (
|
||||
#define SIZE_CHLEN 4 /* the space size to hold the hexadecimal chunk length */
|
||||
#define SIZE_CHLENCRLF 2 /* the space size to hold CRLF after the chunk length */
|
||||
#define SIZE_CHENDCRLF 2 /* the sapce size to hold CRLF after the chunk data */
|
||||
|
||||
static QSE_INLINE void close_chunk_data (task_dseg_t* ctx, qse_size_t len)
|
||||
{
|
||||
ctx->chunklen = len;
|
||||
|
||||
/* CHENDCRLF - there is always space for these two.
|
||||
* reserved with SIZE_CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
}
|
||||
|
||||
static void fill_chunk_length (task_dseg_t* ctx)
|
||||
{
|
||||
int x;
|
||||
|
||||
/* right alignment with space padding on the left */
|
||||
/* TODO: change snprintf to qse_fmtuintmaxtombs() */
|
||||
x = snprintf (
|
||||
ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1,
|
||||
QSE_MT("%*lX"), (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2),
|
||||
(unsigned long)(ctx->chunklen - (SIZE_CHLEN + SIZE_CHLENCRLF)));
|
||||
|
||||
/* i don't check the error of snprintf because i've secured the
|
||||
* suffient space for the chunk length at the beginning of the buffer */
|
||||
|
||||
/* CHLENCRLF */
|
||||
ctx->buf[x] = QSE_MT('\r');
|
||||
ctx->buf[x+1] = QSE_MT('\n');
|
||||
|
||||
/* skip leading space padding */
|
||||
QSE_ASSERT (ctx->bufpos == 0);
|
||||
while (ctx->buf[ctx->bufpos] == QSE_MT(' ')) ctx->bufpos++;
|
||||
}
|
||||
|
||||
static int add_footer (task_dseg_t* ctx)
|
||||
{
|
||||
int x;
|
||||
|
||||
if (ctx->chunked)
|
||||
{
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||
QSE_MT("</ul>Total %lu entries</body></html>\r\n0\r\n"), (unsigned long)ctx->tcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||
QSE_MT("</ul>Total %lu entries</body></html>"), (unsigned long)ctx->tcount);
|
||||
}
|
||||
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the
|
||||
* trailing footer. you need to increate the buffer size */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
|
||||
/* -5 for \r\n0\r\n added above */
|
||||
if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int task_main_dseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||
qse_ssize_t n;
|
||||
int x;
|
||||
|
||||
if (ctx->bufpos < ctx->buflen) goto send_dirlist;
|
||||
if (ctx->bufpos < ctx->buflen)
|
||||
{
|
||||
/* buffer contents not fully sent yet */
|
||||
goto send_dirlist;
|
||||
}
|
||||
|
||||
/* the buffer size is fixed to QSE_COUNTOF(ctx->buf).
|
||||
* the number of digits need to hold the the size converted to
|
||||
@ -103,122 +187,149 @@ static int task_main_dseg_chunked (
|
||||
* the size of the buffer arrray, you should check this size.
|
||||
*/
|
||||
|
||||
#define SIZE_CHLEN 4
|
||||
#define SIZE_CHLENCRLF 2
|
||||
#define SIZE_CHENDCRLF 2
|
||||
|
||||
/* initialize buffer */
|
||||
ctx->dcount = 0; /* reset the entry counter */
|
||||
ctx->bufpos = 0;
|
||||
if (ctx->chunked)
|
||||
{
|
||||
/* reserve space to fill with the chunk length
|
||||
* 4 for the actual chunk length and +2 for \r\n */
|
||||
ctx->buflen = SIZE_CHLEN + SIZE_CHLENCRLF;
|
||||
|
||||
/* free space remaing in the buffer for the chunk data */
|
||||
ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - SIZE_CHENDCRLF;
|
||||
|
||||
if (ctx->footer_pending)
|
||||
}
|
||||
else
|
||||
{
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
QSE_MT("</ul></body></html>\r\n0\r\n"));
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
ctx->buflen = 0;
|
||||
ctx->bufrem = QSE_COUNTOF(ctx->buf);
|
||||
}
|
||||
|
||||
if (ctx->state & FOOTER_PENDING)
|
||||
{
|
||||
/* only footers yet to be sent */
|
||||
if (add_footer (ctx) <= -1)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the
|
||||
* trailing footer. you need to increate the buffer size */
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->chunklen = ctx->buflen - 5; /* -5 for \r\n0\r\n added above */
|
||||
ctx->state &= ~FOOTER_PENDING;
|
||||
ctx->state |= FOOTER_ADDED;
|
||||
|
||||
/* CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
|
||||
goto set_chunklen;
|
||||
if (ctx->chunked) fill_chunk_length (ctx);
|
||||
goto send_dirlist;
|
||||
}
|
||||
|
||||
if (!ctx->header_added)
|
||||
if (!(ctx->state & HEADER_ADDED))
|
||||
{
|
||||
/* compose the header since this is the first time. */
|
||||
int is_root;
|
||||
|
||||
is_root = (qse_mbscmp (ctx->path, QSE_MT("/")) == 0);
|
||||
|
||||
/* compose the header since this is the first time. */
|
||||
/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
QSE_MT("<html><head><title>Directory Listing</title></head><body><b>%s</b><ul><li><a href='../'>..</a></li>"),
|
||||
ctx->path
|
||||
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||
QSE_MT("<html><head></head><body><b>%s</b><ul>%s"),
|
||||
ctx->path, (is_root? QSE_MT(""): QSE_MT("<li><a href='../'>..</a></li>"))
|
||||
);
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the header.
|
||||
* you need to increate the buffer size */
|
||||
* you need to increate the buffer size. or i have make the buffer
|
||||
* dynamic. */
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
|
||||
ctx->header_added = 1;
|
||||
ctx->state |= HEADER_ADDED;
|
||||
ctx->dcount++;
|
||||
}
|
||||
|
||||
if (!ctx->dent)
|
||||
/*if (!ctx->dent) ctx->dent = QSE_READDIR (ctx->handle); */
|
||||
if (ctx->state & DIRENT_PENDING)
|
||||
ctx->state &= ~DIRENT_PENDING;
|
||||
else
|
||||
ctx->dent = QSE_READDIR (ctx->handle);
|
||||
|
||||
do
|
||||
{
|
||||
if (!ctx->dent)
|
||||
{
|
||||
// TODO: check if errno has changed from before QSE_READDIR().
|
||||
// and return -1 if so.
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
QSE_MT("</ul></body></html>\r\n0\r\n"));
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
/* TODO: check if errno has changed from before QSE_READDIR().
|
||||
and return -1 if so. */
|
||||
if (add_footer (ctx) <= -1)
|
||||
{
|
||||
ctx->footer_pending = 1;
|
||||
ctx->chunklen = ctx->buflen;
|
||||
|
||||
/* CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
}
|
||||
else
|
||||
/* failed to add the footer part */
|
||||
if (ctx->chunked)
|
||||
{
|
||||
ctx->buflen += x;
|
||||
ctx->chunklen = ctx->buflen - 5;
|
||||
|
||||
/* CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
close_chunk_data (ctx, ctx->buflen);
|
||||
fill_chunk_length (ctx);
|
||||
}
|
||||
ctx->state |= FOOTER_PENDING;
|
||||
}
|
||||
else if (ctx->chunked) fill_chunk_length (ctx);
|
||||
break;
|
||||
}
|
||||
else if (qse_mbscmp (ctx->dent->d_name, QSE_MT(".")) != 0 &&
|
||||
qse_mbscmp (ctx->dent->d_name, QSE_MT("..")) != 0)
|
||||
{
|
||||
qse_mchar_t* encname;
|
||||
|
||||
/* TODO: better buffer management in case there are
|
||||
* a lot of file names to escape. */
|
||||
encname = qse_perenchttpstrdup (ctx->dent->d_name, httpd->mmgr);
|
||||
if (encname == QSE_NULL)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
QSE_MT("<li><a href='%s%s'>%s%s</a></li>"),
|
||||
ctx->dent->d_name,
|
||||
encname,
|
||||
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT("")),
|
||||
ctx->dent->d_name,
|
||||
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT(""))
|
||||
);
|
||||
|
||||
if (encname != ctx->dent->d_name) QSE_MMGR_FREE (httpd->mmgr, encname);
|
||||
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* buffer not large enough to hold this entry */
|
||||
ctx->chunklen = ctx->buflen;
|
||||
if (ctx->dcount <= 0)
|
||||
{
|
||||
/* neither directory entry nor the header
|
||||
* has been added to the buffer so far. and
|
||||
* this attempt has failed. the buffer size must
|
||||
* be too small. you must increase it */
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
if (ctx->chunked)
|
||||
{
|
||||
close_chunk_data (ctx, ctx->buflen);
|
||||
fill_chunk_length (ctx);
|
||||
}
|
||||
|
||||
ctx->state |= DIRENT_PENDING;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
ctx->dcount++;
|
||||
ctx->tcount++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,167 +337,41 @@ static int task_main_dseg_chunked (
|
||||
}
|
||||
while (1);
|
||||
|
||||
set_chunklen:
|
||||
/* right alignment with space padding on the left */
|
||||
/* TODO: change snprintf to qse_fmtuintmaxtombs() */
|
||||
x = snprintf (
|
||||
ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1,
|
||||
QSE_MT("%*lX"), (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2),
|
||||
(unsigned long)(ctx->chunklen - (SIZE_CHLEN + SIZE_CHLENCRLF)));
|
||||
|
||||
/* CHLENCRLF */
|
||||
ctx->buf[x] = QSE_MT('\r');
|
||||
ctx->buf[x+1] = QSE_MT('\n');
|
||||
|
||||
/* skip leading space padding */
|
||||
for (x = 0; ctx->buf[x] == QSE_MT(' '); x++) ctx->buflen--;
|
||||
ctx->bufpos = x;
|
||||
|
||||
send_dirlist:
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (
|
||||
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen);
|
||||
n = httpd->scb->client.send (
|
||||
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen - ctx->bufpos);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
/* NOTE if (n == 0), it will enter an infinite loop */
|
||||
|
||||
ctx->bufpos += n;
|
||||
ctx->buflen -= n;
|
||||
return (ctx->bufpos < ctx->buflen || ctx->footer_pending || ctx->dent)? 1: 0;
|
||||
}
|
||||
|
||||
static int task_main_dseg_nochunk (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||
qse_ssize_t n;
|
||||
int x;
|
||||
|
||||
if (ctx->bufpos < ctx->buflen) goto send_dirlist;
|
||||
|
||||
ctx->bufpos = 0;
|
||||
ctx->buflen = 0;
|
||||
ctx->bufrem = QSE_COUNTOF(ctx->buf);
|
||||
|
||||
if (ctx->footer_pending)
|
||||
{
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
"</ul></body></html>");
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the
|
||||
* trailing footer. you need to increate the buffer size */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buflen += x;
|
||||
goto send_dirlist;
|
||||
}
|
||||
|
||||
if (!ctx->header_added)
|
||||
{
|
||||
/* compose the header since this is the first time. */
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
QSE_MT("<html><head><title>Directory Listing</title></head><body><b>%s</b><ul><li><a href='../'>..</a></li>"),
|
||||
ctx->path
|
||||
);
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the header.
|
||||
* you need to increate the buffer size */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
ctx->header_added = 1;
|
||||
}
|
||||
|
||||
if (ctx->dent == QSE_NULL)
|
||||
ctx->dent = QSE_READDIR (ctx->handle);
|
||||
|
||||
do
|
||||
{
|
||||
if (ctx->dent == QSE_NULL)
|
||||
{
|
||||
// TODO: check if errno has changed from before QSE_READDIR().
|
||||
// and return -1 if so.
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
"</ul></body></html>");
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
ctx->footer_pending = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->buflen += x;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (qse_mbscmp (ctx->dent->d_name, QSE_MT(".")) != 0 &&
|
||||
qse_mbscmp (ctx->dent->d_name, QSE_MT("..")) != 0)
|
||||
{
|
||||
x = snprintf (
|
||||
&ctx->buf[ctx->buflen],
|
||||
ctx->bufrem,
|
||||
"<li><a href='%s%s'>%s%s</a></li>",
|
||||
ctx->dent->d_name,
|
||||
(ctx->dent->d_type == DT_DIR? "/": ""),
|
||||
ctx->dent->d_name,
|
||||
(ctx->dent->d_type == DT_DIR? "/": "")
|
||||
);
|
||||
if (x == -1 || x >= ctx->bufrem)
|
||||
{
|
||||
/* buffer not large enough to hold this entry */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->dent = QSE_READDIR (ctx->handle);
|
||||
}
|
||||
while (1);
|
||||
|
||||
send_dirlist:
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (
|
||||
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
ctx->bufpos += n;
|
||||
ctx->buflen -= n;
|
||||
return (ctx->bufpos < ctx->buflen || ctx->footer_pending || ctx->dent)? 1: 0;
|
||||
return (ctx->bufpos < ctx->buflen || (ctx->state & FOOTER_PENDING) || ctx->dent)? 1: 0;
|
||||
}
|
||||
|
||||
static qse_httpd_task_t* entask_directory_segment (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, qse_dir_t* handle, const qse_mchar_t* path, int keepalive)
|
||||
qse_httpd_task_t* pred, qse_dir_t* handle, task_dir_t* dir)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_dseg_t data;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.handle = handle;
|
||||
data.path = path;
|
||||
data.version = dir->version;
|
||||
data.keepalive = dir->keepalive;
|
||||
data.chunked = dir->keepalive;
|
||||
data.path = dir->path;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_dseg;
|
||||
task.main = (keepalive)? task_main_dseg_chunked: task_main_dseg_nochunk;
|
||||
task.main = task_main_dseg;
|
||||
task.fini = task_fini_dseg;
|
||||
task.ctx = &data;
|
||||
|
||||
qse_printf (QSE_T("Debug: entasking directory segment (%d)\n"), client->handle.i);
|
||||
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + qse_mbslen(path) + 1);
|
||||
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + qse_mbslen(data.path) + 1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -398,6 +383,7 @@ static int task_init_dir (
|
||||
|
||||
/* deep-copy the context data to the extension area */
|
||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||
|
||||
qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path);
|
||||
xtn->path = (qse_mchar_t*)(xtn + 1);
|
||||
|
||||
@ -429,7 +415,7 @@ static QSE_INLINE int task_main_dir (
|
||||
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
(dir->keepalive? QSE_MT("Transfer-Encoding: chunked\r\n"): QSE_MT(""))
|
||||
);
|
||||
if (x) x = entask_directory_segment (httpd, client, x, handle, dir->path, dir->keepalive);
|
||||
if (x) x = entask_directory_segment (httpd, client, x, handle, dir);
|
||||
if (x) return 0;
|
||||
|
||||
QSE_CLOSEDIR (handle);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "../cmn/mem.h"
|
||||
#include "../cmn/syscall.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||
|
||||
typedef struct task_file_t task_file_t;
|
||||
@ -54,7 +55,7 @@ static void task_fini_fseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_fseg_t* ctx = (task_fseg_t*)task->ctx;
|
||||
httpd->cbs->file.close (httpd, ctx->handle);
|
||||
httpd->scb->file.close (httpd, ctx->handle);
|
||||
}
|
||||
|
||||
static int task_main_fseg (
|
||||
@ -68,7 +69,7 @@ static int task_main_fseg (
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
/* TODO: more adjustment needed for OS with different sendfile semantics... */
|
||||
n = httpd->cbs->client.sendfile (
|
||||
n = httpd->scb->client.sendfile (
|
||||
httpd, client, ctx->handle, &ctx->offset, count);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -147,7 +148,7 @@ static QSE_INLINE int task_main_file (
|
||||
qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->cbs->file.stat (httpd, file->path, &st) <= -1)
|
||||
if (httpd->scb->file.stat (httpd, file->path, &st) <= -1)
|
||||
{
|
||||
int http_errnum;
|
||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
@ -159,7 +160,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
}
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->cbs->file.ropen (httpd, file->path, &handle) <= -1)
|
||||
if (httpd->scb->file.ropen (httpd, file->path, &handle) <= -1)
|
||||
{
|
||||
int http_errnum;
|
||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
@ -266,11 +267,11 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||
}
|
||||
|
||||
if (x) return 0;
|
||||
httpd->cbs->file.close (httpd, handle);
|
||||
httpd->scb->file.close (httpd, handle);
|
||||
return -1;
|
||||
|
||||
no_file_send:
|
||||
if (fileopen) httpd->cbs->file.close (httpd, handle);
|
||||
if (fileopen) httpd->scb->file.close (httpd, handle);
|
||||
return (x == QSE_NULL)? -1: 0;
|
||||
}
|
||||
|
||||
|
@ -608,7 +608,7 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
|
||||
|
||||
if (writable) goto forward;
|
||||
|
||||
n = httpd->cbs->mux.writable (httpd, proxy->peer.handle, 0);
|
||||
n = httpd->scb->mux.writable (httpd, proxy->peer.handle, 0);
|
||||
if (n == 0) qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@NOT WRITABLE\n"));
|
||||
if (n >= 1)
|
||||
{
|
||||
@ -617,7 +617,7 @@ if (n == 0) qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@NOT WRITABLE\n"));
|
||||
qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
|
||||
(int)QSE_MBS_LEN(proxy->reqfwdbuf),
|
||||
QSE_MBS_PTR(proxy->reqfwdbuf));
|
||||
n = httpd->cbs->peer.send (
|
||||
n = httpd->scb->peer.send (
|
||||
httpd, &proxy->peer,
|
||||
QSE_MBS_PTR(proxy->reqfwdbuf),
|
||||
QSE_MBS_LEN(proxy->reqfwdbuf)
|
||||
@ -866,7 +866,7 @@ static void task_fini_proxy (
|
||||
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
|
||||
|
||||
if (proxy->peer_status & PROXY_PEER_OPEN)
|
||||
httpd->cbs->peer.close (httpd, &proxy->peer);
|
||||
httpd->scb->peer.close (httpd, &proxy->peer);
|
||||
|
||||
if (proxy->res) qse_mbs_close (proxy->res);
|
||||
if (proxy->peer_htrd) qse_htrd_close (proxy->peer_htrd);
|
||||
@ -902,7 +902,7 @@ qse_printf (QSE_T("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigg
|
||||
{
|
||||
/* TODO: check if proxy outputs more than content-length if it is set... */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (httpd, client, proxy->buf, proxy->buflen);
|
||||
n = httpd->scb->client.send (httpd, client, proxy->buf, proxy->buflen);
|
||||
if (n <= -1)
|
||||
{
|
||||
/* can't return internal server error any more... */
|
||||
@ -950,7 +950,7 @@ qse_printf (QSE_T("task_main_proxy_4 about to read from PEER...\n"));
|
||||
{
|
||||
qse_printf (QSE_T("task_main_proxy_4 reading from PEER... %d %d\n"), (int)proxy->peer_output_length, (int)proxy->peer_output_received);
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->peer.recv (
|
||||
n = httpd->scb->peer.recv (
|
||||
httpd, &proxy->peer,
|
||||
&proxy->buf[proxy->buflen],
|
||||
QSE_SIZEOF(proxy->buf) - proxy->buflen
|
||||
@ -1005,7 +1005,7 @@ qse_printf (QSE_T("task_main_proxy_4 read from PEER...%d\n"), (int)n);
|
||||
* side is writable. it should be safe to write whenever
|
||||
* this task function is called. */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (httpd, client, proxy->buf, proxy->buflen);
|
||||
n = httpd->scb->client.send (httpd, client, proxy->buf, proxy->buflen);
|
||||
if (n <= -1)
|
||||
{
|
||||
/* can't return internal server error any more... */
|
||||
@ -1057,7 +1057,7 @@ qse_printf (QSE_T("[PROXY-----3 SENDING XXXXX]\n"));
|
||||
{
|
||||
qse_printf (QSE_T("[proxy_3 sending %d bytes]\n"), (int)count);
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (
|
||||
n = httpd->scb->client.send (
|
||||
httpd, client,
|
||||
&QSE_MBS_CHAR(proxy->res,proxy->res_consumed),
|
||||
count
|
||||
@ -1150,7 +1150,7 @@ for (i = 0; i < count; i++) qse_printf (QSE_T("%hc"), QSE_MBS_CHAR(proxy->res,pr
|
||||
qse_printf (QSE_T("]\n"));
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->client.send (
|
||||
n = httpd->scb->client.send (
|
||||
httpd, client,
|
||||
QSE_MBS_CPTR(proxy->res,proxy->res_consumed),
|
||||
count
|
||||
@ -1181,7 +1181,7 @@ qse_printf (QSE_T("[proxy-2 send failure....\n"));
|
||||
|
||||
/* there is something to read from peer */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->peer.recv (
|
||||
n = httpd->scb->peer.recv (
|
||||
httpd, &proxy->peer,
|
||||
&proxy->buf[proxy->buflen],
|
||||
QSE_SIZEOF(proxy->buf) - proxy->buflen
|
||||
@ -1307,7 +1307,7 @@ qse_printf (QSE_T("task_main_proxy_1....\n"));
|
||||
int n;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->peer.connected (httpd, &proxy->peer);
|
||||
n = httpd->scb->peer.connected (httpd, &proxy->peer);
|
||||
if (n <= -1)
|
||||
{
|
||||
/* improve error conversion */
|
||||
@ -1378,7 +1378,7 @@ qse_printf (QSE_T("task_main_proxy....\n"));
|
||||
proxy->res_pending = 0;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->cbs->peer.open (httpd, &proxy->peer);
|
||||
n = httpd->scb->peer.open (httpd, &proxy->peer);
|
||||
if (n <= -1)
|
||||
{
|
||||
/* TODO: translate error code to http error... */
|
||||
|
@ -34,8 +34,6 @@
|
||||
|
||||
#else
|
||||
# include "../cmn/syscall.h"
|
||||
# include <errno.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# if defined(HAVE_SYS_SENDFILE_H)
|
||||
@ -49,8 +47,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
@ -543,13 +539,13 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
|
||||
oops:
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
if (fd >= 0) close (fd);
|
||||
if (fd >= 0) QSE_CLOSE (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
close (server->handle.i);
|
||||
QSE_CLOSE (server->handle.i);
|
||||
}
|
||||
|
||||
static int server_accept (
|
||||
@ -578,7 +574,7 @@ static int server_accept (
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
||||
/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/
|
||||
close (fd);
|
||||
QSE_CLOSE (fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
@ -659,13 +655,13 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
||||
|
||||
oops:
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
if (fd >= 0) close (fd);
|
||||
if (fd >= 0) QSE_CLOSE (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
||||
{
|
||||
close (peer->handle.i);
|
||||
QSE_CLOSE (peer->handle.i);
|
||||
}
|
||||
|
||||
static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
||||
@ -782,7 +778,7 @@ static void mux_close (qse_httpd_t* httpd, void* vmux)
|
||||
if (mux->mev.ptr[i]) qse_httpd_freemem (httpd, mux->mev.ptr[i]);
|
||||
qse_httpd_freemem (httpd, mux->mev.ptr);
|
||||
}
|
||||
close (mux->fd);
|
||||
QSE_CLOSE (mux->fd);
|
||||
qse_httpd_freemem (httpd, mux);
|
||||
}
|
||||
|
||||
@ -998,7 +994,10 @@ static int file_stat (
|
||||
qse_mbsend (path, QSE_MT(".txt"))? QSE_MT("text/plain"):
|
||||
qse_mbsend (path, QSE_MT(".jpg"))? QSE_MT("image/jpeg"):
|
||||
qse_mbsend (path, QSE_MT(".mp4"))? QSE_MT("video/mp4"):
|
||||
qse_mbsend (path, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"): QSE_NULL;
|
||||
qse_mbsend (path, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"):
|
||||
qse_mbsend (path, QSE_MT(".c"))? QSE_MT("text/plain"):
|
||||
qse_mbsend (path, QSE_MT(".h"))? QSE_MT("text/plain"):
|
||||
QSE_NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1014,7 +1013,7 @@ static int file_ropen (
|
||||
#endif
|
||||
|
||||
qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
|
||||
fd = open (path, flags, 0);
|
||||
fd = QSE_OPEN (path, flags, 0);
|
||||
if (fd <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
@ -1042,7 +1041,7 @@ static int file_wopen (
|
||||
#endif
|
||||
|
||||
qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
||||
fd = open (path, flags, 0644);
|
||||
fd = QSE_OPEN (path, flags, 0644);
|
||||
if (fd <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
@ -1056,28 +1055,28 @@ qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
||||
static void file_close (qse_httpd_t* httpd, qse_ubi_t handle)
|
||||
{
|
||||
qse_printf (QSE_T("closing file %d\n"), handle.i);
|
||||
close (handle.i);
|
||||
QSE_CLOSE (handle.i);
|
||||
}
|
||||
|
||||
static qse_ssize_t file_read (
|
||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||
qse_mchar_t* buf, qse_size_t len)
|
||||
{
|
||||
return read (handle.i, buf, len);
|
||||
return QSE_READ (handle.i, buf, len);
|
||||
}
|
||||
|
||||
static qse_ssize_t file_write (
|
||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||
const qse_mchar_t* buf, qse_size_t len)
|
||||
{
|
||||
return write (handle.i, buf, len);
|
||||
return QSE_WRITE (handle.i, buf, len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
static void client_close (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
{
|
||||
close (client->handle.i);
|
||||
QSE_CLOSE (client->handle.i);
|
||||
}
|
||||
|
||||
static void client_shutdown (
|
||||
@ -1264,8 +1263,10 @@ static int process_request (
|
||||
|
||||
/* percent-decode the query path to the original buffer
|
||||
* since i'm not gonna need it in the original form
|
||||
* any more */
|
||||
qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
||||
* any more. once it's decoded in the peek mode,
|
||||
* the decoded query path is made available in the
|
||||
* non-peek mode as well */
|
||||
if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
||||
|
||||
qse_printf (QSE_T("================================\n"));
|
||||
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
|
||||
@ -1423,14 +1424,8 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
|
||||
#else
|
||||
if (peek)
|
||||
{
|
||||
qse_stat_t st;
|
||||
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
|
||||
if (QSE_LSTAT (qpath, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
task = qse_httpd_entaskdir (httpd, client, QSE_NULL, qpath, req);
|
||||
else
|
||||
task = qse_httpd_entaskfile (httpd, client, QSE_NULL, qpath, req);
|
||||
task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
#endif
|
||||
@ -1578,7 +1573,7 @@ static int handle_request (
|
||||
}
|
||||
}
|
||||
|
||||
static qse_httpd_cbs_t httpd_standard_callbacks =
|
||||
static qse_httpd_scb_t httpd_system_callbacks =
|
||||
{
|
||||
/* server */
|
||||
{ server_open, server_close, server_accept },
|
||||
@ -1617,14 +1612,17 @@ static qse_httpd_cbs_t httpd_standard_callbacks =
|
||||
client_send,
|
||||
client_sendfile,
|
||||
client_accepted,
|
||||
client_closed },
|
||||
|
||||
/* http request */
|
||||
peek_request,
|
||||
handle_request,
|
||||
client_closed }
|
||||
};
|
||||
|
||||
int qse_httpd_loopstd (qse_httpd_t* httpd, qse_ntime_t timeout)
|
||||
static qse_httpd_rcb_t httpd_request_callbacks =
|
||||
{
|
||||
return qse_httpd_loop (httpd, &httpd_standard_callbacks, timeout);
|
||||
peek_request,
|
||||
handle_request
|
||||
};
|
||||
|
||||
int qse_httpd_loopstd (qse_httpd_t* httpd, qse_httpd_rcb_t* rcb, qse_ntime_t timeout)
|
||||
{
|
||||
if (rcb == QSE_NULL) rcb = &httpd_request_callbacks;
|
||||
return qse_httpd_loop (httpd, &httpd_system_callbacks, rcb, timeout);
|
||||
}
|
||||
|
@ -18,20 +18,24 @@
|
||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
|
||||
/* UNSUPPORTED YET.. */
|
||||
/* TODO: IMPLEMENT THIS */
|
||||
#else
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/fmt.h>
|
||||
|
||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||
#if defined(_WIN32)
|
||||
/* TODO */
|
||||
#elif defined(__DOS__)
|
||||
/* TODO */
|
||||
#elif defined(__OS2__)
|
||||
/* TODO */
|
||||
#else
|
||||
# include "../cmn/syscall.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||
|
||||
|
||||
/* TODO:
|
||||
* many functions in this file use qse_size_t.
|
||||
@ -43,7 +47,7 @@
|
||||
static int task_main_disconnect (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
httpd->cbs->client.shutdown (httpd, client);
|
||||
httpd->scb->client.shutdown (httpd, client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -75,7 +79,7 @@ static int task_main_statictext (
|
||||
}
|
||||
|
||||
/* TODO: do i need to add code to skip this send if count is 0? */
|
||||
n = httpd->cbs->client.send (httpd, client, task->ctx, count);
|
||||
n = httpd->scb->client.send (httpd, client, task->ctx, count);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
ptr = (const qse_mchar_t*)task->ctx + n;
|
||||
@ -133,7 +137,7 @@ static int task_main_text (
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
/* TODO: do i need to add code to skip this send if count is 0? */
|
||||
n = httpd->cbs->client.send (httpd, client, ctx->ptr, count);
|
||||
n = httpd->scb->client.send (httpd, client, ctx->ptr, count);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
ctx->left -= n;
|
||||
@ -206,7 +210,7 @@ static int task_main_format (
|
||||
count = MAX_SEND_SIZE;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
n = httpd->cbs->client.send (httpd, client, ctx->ptr, count);
|
||||
n = httpd->scb->client.send (httpd, client, ctx->ptr, count);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
ctx->left -= n;
|
||||
@ -437,6 +441,21 @@ qse_httpd_task_t* qse_httpd_entaskauth (
|
||||
realm, (unsigned long)qse_mbslen(lmsg) + 4, lmsg);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
qse_httpd_task_t* qse_httpd_entaskpath (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* name, qse_htre_t* req)
|
||||
{
|
||||
qse_stat_t st;
|
||||
qse_httpd_task_t* task;
|
||||
|
||||
if (QSE_LSTAT (name, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
task = qse_httpd_entaskdir (httpd, client, pred, name, req);
|
||||
else
|
||||
task = qse_httpd_entaskfile (httpd, client, pred, name, req);
|
||||
|
||||
return task;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
@ -451,4 +470,3 @@ qse_httpd_task_t* qse_httpd_entaskconnect (
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -245,7 +245,7 @@ static QSE_INLINE int dequeue_task (
|
||||
{
|
||||
if (client->status & CLIENT_TASK_TRIGGER_IN_MUX(i))
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, task->trigger[i].handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, task->trigger[i].handle);
|
||||
client->status &= ~CLIENT_TASK_TRIGGER_IN_MUX(i);
|
||||
}
|
||||
}
|
||||
@ -281,13 +281,13 @@ static QSE_INLINE void purge_tasks (
|
||||
static int htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||
{
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
||||
return xtn->httpd->cbs->peek_request (xtn->httpd, xtn->client, req);
|
||||
return xtn->httpd->rcb->peek_request (xtn->httpd, xtn->client, req);
|
||||
}
|
||||
|
||||
static int htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||
{
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
||||
return xtn->httpd->cbs->handle_request (xtn->httpd, xtn->client, req);
|
||||
return xtn->httpd->rcb->handle_request (xtn->httpd, xtn->client, req);
|
||||
}
|
||||
|
||||
static qse_htrd_recbs_t htrd_recbs =
|
||||
@ -317,9 +317,9 @@ static qse_httpd_client_t* new_client (
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
qse_htrd_setoption (client->htrd, QSE_HTRD_REQUEST | QSE_HTRD_TRAILERS);
|
||||
qse_htrd_setoption (client->htrd, QSE_HTRD_REQUEST | QSE_HTRD_TRAILERS | QSE_HTRD_CANONQPATH);
|
||||
|
||||
if (httpd->cbs->client.accepted == QSE_NULL)
|
||||
if (httpd->scb->client.accepted == QSE_NULL)
|
||||
client->status |= CLIENT_READY;
|
||||
|
||||
client->status = tmpl->status;
|
||||
@ -351,16 +351,16 @@ qse_printf (QSE_T("Debug: CLOSING SOCKET %d\n"), client->handle.i);
|
||||
|
||||
if (client->status & CLIENT_HANDLE_IN_MUX)
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||
}
|
||||
|
||||
/* note that client.closed is not a counterpart to client.accepted.
|
||||
* so it is called even if client.close() failed. */
|
||||
if (httpd->cbs->client.closed)
|
||||
httpd->cbs->client.closed (httpd, client);
|
||||
if (httpd->scb->client.closed)
|
||||
httpd->scb->client.closed (httpd, client);
|
||||
|
||||
httpd->cbs->client.close (httpd, client);
|
||||
httpd->scb->client.close (httpd, client);
|
||||
|
||||
qse_httpd_freemem (httpd, client);
|
||||
}
|
||||
@ -434,7 +434,7 @@ static int accept_client (
|
||||
|
||||
QSE_MEMSET (&clibuf, 0, QSE_SIZEOF(clibuf));
|
||||
|
||||
if (httpd->cbs->server.accept (httpd, server, &clibuf) <= -1)
|
||||
if (httpd->scb->server.accept (httpd, server, &clibuf) <= -1)
|
||||
{
|
||||
/* TODO: proper logging */
|
||||
qse_char_t tmp[128];
|
||||
@ -451,12 +451,12 @@ qse_printf (QSE_T("failed to accept from server %s\n"), tmp);
|
||||
client = new_client (httpd, &clibuf);
|
||||
if (client == QSE_NULL)
|
||||
{
|
||||
httpd->cbs->client.close (httpd, &clibuf);
|
||||
httpd->scb->client.close (httpd, &clibuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i);
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, mux, client->handle, QSE_HTTPD_MUX_READ,
|
||||
perform_client_task, client) <= -1)
|
||||
{
|
||||
@ -540,8 +540,8 @@ static void deactivate_servers (qse_httpd_t* httpd)
|
||||
{
|
||||
if (server->active)
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, server->handle);
|
||||
httpd->cbs->server.close (httpd, server);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, server->handle);
|
||||
httpd->scb->server.close (httpd, server);
|
||||
server->active = 0;
|
||||
httpd->server.nactive--;
|
||||
}
|
||||
@ -554,7 +554,7 @@ static int activate_servers (qse_httpd_t* httpd)
|
||||
|
||||
for (server = httpd->server.list; server; server = server->next)
|
||||
{
|
||||
if (httpd->cbs->server.open (httpd, server) <= -1)
|
||||
if (httpd->scb->server.open (httpd, server) <= -1)
|
||||
{
|
||||
qse_char_t buf[64];
|
||||
qse_nwadtostr (&server->nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL);
|
||||
@ -563,12 +563,12 @@ qse_printf (QSE_T("FAILED TO ACTIVATE SERVER....[%s]\n"), buf);
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("MUX ADDHND SERVER %d\n"), server->handle.i);
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, httpd->mux, server->handle, QSE_HTTPD_MUX_READ,
|
||||
accept_client, server) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("FAILED TO ADD SERVER HANDLE TO MUX....\n"));
|
||||
httpd->cbs->server.close (httpd, server);
|
||||
httpd->scb->server.close (httpd, server);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -585,7 +585,7 @@ static void free_server_list (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
{
|
||||
qse_httpd_server_t* next = server->next;
|
||||
|
||||
httpd->cbs->server.close (httpd, server);
|
||||
httpd->scb->server.close (httpd, server);
|
||||
qse_httpd_freemem (httpd, server);
|
||||
httpd->server.navail--;
|
||||
|
||||
@ -689,11 +689,11 @@ static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
qse_mchar_t buf[4096]; /* TODO: adjust this buffer size */
|
||||
qse_ssize_t m;
|
||||
|
||||
QSE_ASSERT (httpd->cbs->client.recv != QSE_NULL);
|
||||
QSE_ASSERT (httpd->scb->client.recv != QSE_NULL);
|
||||
|
||||
reread:
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
m = httpd->cbs->client.recv (httpd, client, buf, QSE_SIZEOF(buf));
|
||||
m = httpd->scb->client.recv (httpd, client, buf, QSE_SIZEOF(buf));
|
||||
if (m <= -1)
|
||||
{
|
||||
if (httpd->errnum == QSE_HTTPD_EAGAIN)
|
||||
@ -840,7 +840,7 @@ qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int)
|
||||
{
|
||||
/* the task is invoked for triggers.
|
||||
* check if the client handle is writable */
|
||||
if (httpd->cbs->mux.writable (httpd, client->handle, 0) <= 0)
|
||||
if (httpd->scb->mux.writable (httpd, client->handle, 0) <= 0)
|
||||
{
|
||||
/* it is not writable yet. so just skip
|
||||
* performing the actual task */
|
||||
@ -891,12 +891,12 @@ qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
|
||||
if ((client->status & CLIENT_HANDLE_IN_MUX) !=
|
||||
(mux_status & CLIENT_HANDLE_IN_MUX))
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||
|
||||
if (mux_status)
|
||||
{
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, httpd->mux, client->handle,
|
||||
mux_mask, perform_client_task, client) <= -1)
|
||||
{
|
||||
@ -937,7 +937,7 @@ qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
|
||||
{
|
||||
if (client->status & CLIENT_TASK_TRIGGER_IN_MUX(i))
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->trigger[i].handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, client->trigger[i].handle);
|
||||
client->status &= ~CLIENT_TASK_TRIGGER_IN_MUX(i);
|
||||
}
|
||||
}
|
||||
@ -983,7 +983,7 @@ qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, httpd->mux, task->trigger[i].handle,
|
||||
trigger_mux_mask, perform_client_task, client) <= -1)
|
||||
{
|
||||
@ -1012,12 +1012,12 @@ qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
|
||||
if ((client->status & CLIENT_HANDLE_IN_MUX) !=
|
||||
(client_handle_mux_status & CLIENT_HANDLE_IN_MUX))
|
||||
{
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||
|
||||
if (client_handle_mux_mask)
|
||||
{
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, httpd->mux, client->handle,
|
||||
client_handle_mux_mask, perform_client_task, client) <= -1)
|
||||
{
|
||||
@ -1045,7 +1045,7 @@ static int perform_client_task (
|
||||
if (!(client->status & CLIENT_READY))
|
||||
{
|
||||
int x;
|
||||
x = httpd->cbs->client.accepted (httpd, client);
|
||||
x = httpd->scb->client.accepted (httpd, client);
|
||||
if (x <= -1) goto oops;
|
||||
if (x >= 1)
|
||||
{
|
||||
@ -1139,11 +1139,11 @@ qse_httpd_task_t* qse_httpd_entask (
|
||||
/* arrange to invokde this task so long as
|
||||
* the client-side handle is writable. */
|
||||
QSE_ASSERT (client->status & CLIENT_HANDLE_IN_MUX);
|
||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
httpd->scb->mux.delhnd (httpd, httpd->mux, client->handle);
|
||||
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||
|
||||
qse_printf (QSE_T("MUX ADDHND CLIENT RW(ENTASK) %d\n"), client->handle.i);
|
||||
if (httpd->cbs->mux.addhnd (
|
||||
if (httpd->scb->mux.addhnd (
|
||||
httpd, httpd->mux, client->handle,
|
||||
QSE_HTTPD_MUX_READ | QSE_HTTPD_MUX_WRITE,
|
||||
perform_client_task, client) <= -1)
|
||||
@ -1158,30 +1158,28 @@ qse_printf (QSE_T("MUX ADDHND CLIENT RW(ENTASK) %d\n"), client->handle.i);
|
||||
return new_task;
|
||||
}
|
||||
|
||||
int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs, qse_ntime_t timeout)
|
||||
int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_scb_t* scb, qse_httpd_rcb_t* rcb, qse_ntime_t timeout)
|
||||
{
|
||||
httpd->stopreq = 0;
|
||||
httpd->cbs = cbs;
|
||||
|
||||
QSE_ASSERTX (httpd->server.list != QSE_NULL,
|
||||
"Add listeners before calling qse_httpd_loop()");
|
||||
|
||||
QSE_ASSERTX (httpd->client.list.head == QSE_NULL,
|
||||
"No client should exist when this loop is started");
|
||||
|
||||
QSE_ASSERTX (httpd->cbs != QSE_NULL,
|
||||
"Set httpd callbacks before calling qse_httpd_loop()");
|
||||
|
||||
if (httpd->server.list == QSE_NULL)
|
||||
if (scb == QSE_NULL || rcb == QSE_NULL ||
|
||||
httpd->server.list == QSE_NULL)
|
||||
{
|
||||
/* no listener specified */
|
||||
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
httpd->stopreq = 0;
|
||||
httpd->scb = scb;
|
||||
httpd->rcb = rcb;
|
||||
|
||||
QSE_ASSERT (httpd->server.navail > 0);
|
||||
|
||||
httpd->mux = httpd->cbs->mux.open (httpd);
|
||||
httpd->mux = httpd->scb->mux.open (httpd);
|
||||
if (httpd->mux == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("can't open mux....\n"));
|
||||
@ -1190,13 +1188,13 @@ qse_printf (QSE_T("can't open mux....\n"));
|
||||
|
||||
if (activate_servers (httpd) <= -1)
|
||||
{
|
||||
httpd->cbs->mux.close (httpd, httpd->mux);
|
||||
httpd->scb->mux.close (httpd, httpd->mux);
|
||||
return -1;
|
||||
}
|
||||
if (httpd->server.nactive <= 0)
|
||||
{
|
||||
qse_printf (QSE_T("no servers are active....\n"));
|
||||
httpd->cbs->mux.close (httpd, httpd->mux);
|
||||
httpd->scb->mux.close (httpd, httpd->mux);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1204,7 +1202,7 @@ qse_printf (QSE_T("no servers are active....\n"));
|
||||
{
|
||||
int count;
|
||||
|
||||
count = httpd->cbs->mux.poll (httpd, httpd->mux, timeout);
|
||||
count = httpd->scb->mux.poll (httpd, httpd->mux, timeout);
|
||||
if (count <= -1)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_EIOMUX;
|
||||
@ -1220,7 +1218,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: mux returned failure\n"));
|
||||
|
||||
purge_client_list (httpd);
|
||||
deactivate_servers (httpd);
|
||||
httpd->cbs->mux.close (httpd, httpd->mux);
|
||||
httpd->scb->mux.close (httpd, httpd->mux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,8 @@ struct qse_httpd_t
|
||||
QSE_DEFINE_COMMON_FIELDS (httpd)
|
||||
qse_httpd_errnum_t errnum;
|
||||
qse_httpd_ecb_t* ecb; /* event callbacks */
|
||||
qse_httpd_cbs_t* cbs;
|
||||
qse_httpd_scb_t* scb; /* system callbacks */
|
||||
qse_httpd_rcb_t* rcb; /* request callbacks */
|
||||
|
||||
int option;
|
||||
int stopreq;
|
||||
|
@ -5,7 +5,7 @@ AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(includedir)
|
||||
|
||||
bin_PROGRAMS = http01 upxd01
|
||||
bin_PROGRAMS = httpd01 httpd02 upxd01
|
||||
|
||||
LDFLAGS += -L../../lib/cmn -L../../lib/net
|
||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS)
|
||||
@ -16,7 +16,9 @@ LDADD += $(UNICOWS_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
http01_SOURCES = http01.c
|
||||
httpd01_SOURCES = httpd01.c
|
||||
httpd02_SOURCES = httpd02.c
|
||||
upxd01_SOURCES = upxd01.c
|
||||
|
||||
http01_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
httpd01_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
httpd02_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
|
@ -34,7 +34,7 @@ PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
bin_PROGRAMS = http01$(EXEEXT) upxd01$(EXEEXT)
|
||||
bin_PROGRAMS = httpd01$(EXEEXT) httpd02$(EXEEXT) upxd01$(EXEEXT)
|
||||
@WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
||||
subdir = samples/net
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
@ -52,13 +52,16 @@ CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
PROGRAMS = $(bin_PROGRAMS)
|
||||
am_http01_OBJECTS = http01.$(OBJEXT)
|
||||
http01_OBJECTS = $(am_http01_OBJECTS)
|
||||
am_httpd01_OBJECTS = httpd01.$(OBJEXT)
|
||||
httpd01_OBJECTS = $(am_httpd01_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
@WCHAR_TRUE@@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
||||
am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
|
||||
http01_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
|
||||
httpd01_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
|
||||
am_httpd02_OBJECTS = httpd02.$(OBJEXT)
|
||||
httpd02_OBJECTS = $(am_httpd02_OBJECTS)
|
||||
httpd02_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
|
||||
am_upxd01_OBJECTS = upxd01.$(OBJEXT)
|
||||
upxd01_OBJECTS = $(am_upxd01_OBJECTS)
|
||||
upxd01_LDADD = $(LDADD)
|
||||
@ -77,8 +80,8 @@ CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
||||
DIST_SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
||||
SOURCES = $(httpd01_SOURCES) $(httpd02_SOURCES) $(upxd01_SOURCES)
|
||||
DIST_SOURCES = $(httpd01_SOURCES) $(httpd02_SOURCES) $(upxd01_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
@ -243,9 +246,11 @@ AM_CPPFLAGS = \
|
||||
|
||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
|
||||
$(SENDFILE_LIBS) $(am__append_1)
|
||||
http01_SOURCES = http01.c
|
||||
httpd01_SOURCES = httpd01.c
|
||||
httpd02_SOURCES = httpd02.c
|
||||
upxd01_SOURCES = upxd01.c
|
||||
http01_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
httpd01_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
httpd02_LDADD = $(LDADD) $(SSL_LIBS)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
@ -323,9 +328,12 @@ clean-binPROGRAMS:
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
http01$(EXEEXT): $(http01_OBJECTS) $(http01_DEPENDENCIES) $(EXTRA_http01_DEPENDENCIES)
|
||||
@rm -f http01$(EXEEXT)
|
||||
$(LINK) $(http01_OBJECTS) $(http01_LDADD) $(LIBS)
|
||||
httpd01$(EXEEXT): $(httpd01_OBJECTS) $(httpd01_DEPENDENCIES) $(EXTRA_httpd01_DEPENDENCIES)
|
||||
@rm -f httpd01$(EXEEXT)
|
||||
$(LINK) $(httpd01_OBJECTS) $(httpd01_LDADD) $(LIBS)
|
||||
httpd02$(EXEEXT): $(httpd02_OBJECTS) $(httpd02_DEPENDENCIES) $(EXTRA_httpd02_DEPENDENCIES)
|
||||
@rm -f httpd02$(EXEEXT)
|
||||
$(LINK) $(httpd02_OBJECTS) $(httpd02_LDADD) $(LIBS)
|
||||
upxd01$(EXEEXT): $(upxd01_OBJECTS) $(upxd01_DEPENDENCIES) $(EXTRA_upxd01_DEPENDENCIES)
|
||||
@rm -f upxd01$(EXEEXT)
|
||||
$(LINK) $(upxd01_OBJECTS) $(upxd01_LDADD) $(LIBS)
|
||||
@ -336,7 +344,8 @@ mostlyclean-compile:
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd02.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd01.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
|
@ -33,7 +33,7 @@ static void sigint (int sig)
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
int httpd_main (int argc, qse_char_t* argv[])
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
int ret = -1, i;
|
||||
@ -66,7 +66,7 @@ int httpd_main (int argc, qse_char_t* argv[])
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
|
||||
ret = qse_httpd_loopstd (httpd, 10000);
|
||||
ret = qse_httpd_loopstd (httpd, QSE_NULL, 10000);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
signal (SIGPIPE, SIG_DFL);
|
249
qse/samples/net/httpd02.c
Normal file
249
qse/samples/net/httpd02.c
Normal file
@ -0,0 +1,249 @@
|
||||
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <process.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSEXCEPTIONS
|
||||
# define INCL_ERRORS
|
||||
# include <os2.h>
|
||||
#elif defined(__DOS__)
|
||||
# include <dos.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
typedef struct xtn_t xtn_t;
|
||||
struct xtn_t
|
||||
{
|
||||
qse_mchar_t basedir[4096];
|
||||
};
|
||||
|
||||
static int process_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_htre_t* req, int peek)
|
||||
{
|
||||
int method;
|
||||
qse_httpd_task_t* task;
|
||||
int content_received;
|
||||
xtn_t* xtn;
|
||||
|
||||
method = qse_htre_getqmethodtype(req);
|
||||
content_received = (qse_htre_getcontentlen(req) > 0);
|
||||
|
||||
xtn = (xtn_t*) qse_httpd_getxtn (httpd);
|
||||
|
||||
if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
||||
|
||||
qse_printf (QSE_T("================================\n"));
|
||||
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
|
||||
(unsigned long)time(NULL),
|
||||
(peek? QSE_MT("PEEK"): QSE_MT("HANDLE")),
|
||||
qse_htre_getqpath(req),
|
||||
qse_htre_getmajorversion(req),
|
||||
qse_htre_getminorversion(req),
|
||||
qse_htre_getverstr(req),
|
||||
qse_htre_getqmethodname(req)
|
||||
);
|
||||
if (qse_htre_getqparam(req))
|
||||
qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparam(req));
|
||||
|
||||
if (peek)
|
||||
{
|
||||
if (method != QSE_HTTP_POST && method != QSE_HTTP_PUT)
|
||||
{
|
||||
/* i'll discard request contents if the method is none of
|
||||
* post and put */
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
}
|
||||
|
||||
if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
|
||||
(req->version.major > 1 ||
|
||||
(req->version.major == 1 && req->version.minor >= 1)) &&
|
||||
!content_received)
|
||||
{
|
||||
/* TODO: check method.... */
|
||||
/* "expect" in the header, version 1.1 or higher,
|
||||
* and no content received yet */
|
||||
|
||||
/* TODO: determine if to return 100-continue or other errors */
|
||||
if (qse_httpd_entaskcontinue (
|
||||
httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||
{
|
||||
const qse_mchar_t* qpath = qse_htre_getqpath(req);
|
||||
const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.'));
|
||||
|
||||
if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0)
|
||||
{
|
||||
if (peek)
|
||||
{
|
||||
/* cgi */
|
||||
if (method == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
task = qse_httpd_entaskerror (
|
||||
httpd, client, QSE_NULL, 411, req);
|
||||
/* 411 can't keep alive */
|
||||
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskcgi (
|
||||
httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (peek)
|
||||
{
|
||||
/* TODO: combine qpath with xtn->basedir */
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!peek)
|
||||
{
|
||||
task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE))
|
||||
{
|
||||
if (!peek)
|
||||
{
|
||||
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
/*qse_httpd_markbadclient (httpd, client);*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int peek_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
return process_request (httpd, client, req, 1);
|
||||
}
|
||||
|
||||
static int handle_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
return process_request (httpd, client, req, 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static qse_httpd_t* g_httpd = QSE_NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
static int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
qse_httpd_t* httpd = QSE_NULL;
|
||||
int ret = -1, i;
|
||||
static qse_httpd_rcb_t rcb = { peek_request, handle_request };
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri> ...\n"), argv[0]);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
httpd = qse_httpd_openstd (QSE_SIZEOF(xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (qse_httpd_addserver (httpd, argv[i]) <= -1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR,
|
||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
g_httpd = httpd;
|
||||
signal (SIGINT, sigint);
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
|
||||
ret = qse_httpd_loopstd (httpd, &rcb, 10000);
|
||||
|
||||
signal (SIGINT, SIG_DFL);
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
g_httpd = QSE_NULL;
|
||||
|
||||
if (ret <= -1) qse_fprintf (QSE_STDERR, QSE_T("Httpd error\n"));
|
||||
|
||||
oops:
|
||||
if (httpd) qse_httpd_close (httpd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_main (int argc, qse_achar_t* argv[])
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char locale[100];
|
||||
UINT codepage = GetConsoleOutputCP();
|
||||
if (codepage == CP_UTF8)
|
||||
{
|
||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||
qse_setdflcmgr (qse_utf8cmgr);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||
setlocale (LC_ALL, locale);
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
}
|
||||
#else
|
||||
setlocale (LC_ALL, "");
|
||||
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
|
||||
#endif
|
||||
|
||||
return qse_runmain (argc, argv, httpd_main);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user