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.
|
* 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
|
* On Win32/OS2/DOS, it also returns 1 if a path name begins with a drive
|
||||||
* letter followed by a colon.
|
* letter followed by a colon.
|
||||||
* @return 1 if absolute, 0 if not.
|
* @return 1 if absolute, 0 if not.
|
||||||
*/
|
*/
|
||||||
int qse_isabspath (
|
int qse_ismbsabspath (
|
||||||
const qse_char_t* path
|
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:.
|
* a drive letter followed by a colon like A:.
|
||||||
*/
|
*/
|
||||||
int qse_isdrivepath (
|
int qse_ismbsdrivepath (
|
||||||
const qse_char_t* path
|
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.
|
* of a drive letter followed by a colon like A:, without any trailing path.
|
||||||
*/
|
*/
|
||||||
int qse_isdrivecurpath (
|
int qse_ismbsdrivecurpath (
|
||||||
const qse_char_t* path
|
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
|
* 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
|
* pointed to by @a canon. Canonicalization is purely performed on the path
|
||||||
* name without refering to actual file systems. It null-terminates the
|
* name without refering to actual file systems. It null-terminates the
|
||||||
@ -105,9 +105,9 @@ int qse_isdrivecurpath (
|
|||||||
* the terminating null.
|
* the terminating null.
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* qse_char_t buf[64];
|
* qse_mchar_t buf[64];
|
||||||
* qse_canonpath ("/usr/local/../bin/sh", buf);
|
* qse_canonmbspath (QSE_MT("/usr/local/../bin/sh"), buf);
|
||||||
* qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh
|
* qse_printf (QSE_T("%hs\n")); // prints /usr/bin/sh
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* If #QSE_CANONPATH_EMPTYSINGLEDOT is clear in the @a flags, a single dot
|
* 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
|
* @return number of characters in the resulting canonical path excluding
|
||||||
* the terminating null.
|
* the terminating null.
|
||||||
*/
|
*/
|
||||||
qse_size_t qse_canonpath (
|
qse_size_t qse_canonmbspath (
|
||||||
const qse_char_t* path,
|
const qse_mchar_t* path,
|
||||||
qse_char_t* canon,
|
qse_mchar_t* canon,
|
||||||
int flags
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */
|
||||||
QSE_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an 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_CANONQPATH = (1 << 2), /**< canonicalize the query path */
|
||||||
QSE_HTRD_REQUEST = (1 << 3), /**< parse input as a request */
|
QSE_HTRD_PEEKONLY = (1 << 3), /**< trigger a peek callback after headers without processing contents */
|
||||||
QSE_HTRD_RESPONSE = (1 << 4), /**< parse input as a response */
|
QSE_HTRD_REQUEST = (1 << 4), /**< parse input as a request */
|
||||||
QSE_HTRD_TRAILERS = (1 << 5), /**< store trailers in a separate table */
|
QSE_HTRD_RESPONSE = (1 << 5), /**< parse input as a response */
|
||||||
QSE_HTRD_STRICT = (1 << 6) /**< be more picky */
|
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;
|
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 (
|
qse_size_t qse_perdechttpstr (
|
||||||
const qse_mchar_t* str,
|
const qse_mchar_t* str,
|
||||||
qse_mchar_t* buf
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -104,14 +104,8 @@ typedef int (*qse_httpd_muxcb_t) (
|
|||||||
void* cbarg
|
void* cbarg
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
|
typedef struct qse_httpd_scb_t qse_httpd_scb_t;
|
||||||
struct qse_httpd_dirent_t
|
struct qse_httpd_scb_t
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
|
||||||
struct qse_httpd_cbs_t
|
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -212,7 +206,11 @@ struct qse_httpd_cbs_t
|
|||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client); /* optional */
|
qse_httpd_client_t* client); /* optional */
|
||||||
} client;
|
} client;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct qse_httpd_rcb_t qse_httpd_rcb_t;
|
||||||
|
struct qse_httpd_rcb_t
|
||||||
|
{
|
||||||
int (*peek_request) (
|
int (*peek_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_request) (
|
int (*handle_request) (
|
||||||
@ -335,6 +333,7 @@ struct qse_httpd_ecb_t
|
|||||||
qse_httpd_ecb_t* next;
|
qse_httpd_ecb_t* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -396,7 +395,8 @@ void qse_httpd_pushecb (
|
|||||||
*/
|
*/
|
||||||
int qse_httpd_loop (
|
int qse_httpd_loop (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_cbs_t* cbs,
|
qse_httpd_scb_t* scb,
|
||||||
|
qse_httpd_rcb_t* rcb,
|
||||||
qse_ntime_t timeout
|
qse_ntime_t timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -506,7 +506,7 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
|||||||
qse_htre_t* req
|
qse_htre_t* req
|
||||||
);
|
);
|
||||||
|
|
||||||
qse_httpd_task_t* qse_httpd_entaskdir (
|
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,
|
||||||
qse_httpd_task_t* pred,
|
qse_httpd_task_t* pred,
|
||||||
@ -574,6 +574,7 @@ void* qse_httpd_getxtnstd (
|
|||||||
|
|
||||||
int qse_httpd_loopstd (
|
int qse_httpd_loopstd (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_rcb_t* rcb,
|
||||||
qse_ntime_t timeout
|
qse_ntime_t timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -20,63 +20,67 @@
|
|||||||
|
|
||||||
#include <qse/cmn/path.h>
|
#include <qse/cmn/path.h>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* MBS IMPLEMENTATION */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
#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
|
#else
|
||||||
# define IS_SEP(c) ((c) == QSE_T('/'))
|
# define IS_MSEP(c) ((c) == QSE_MT('/'))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IS_NIL(c) ((c) == QSE_T('\0'))
|
#define IS_MNIL(c) ((c) == QSE_MT('\0'))
|
||||||
#define IS_SEP_OR_NIL(c) (IS_SEP(c) || IS_NIL(c))
|
#define IS_MSEP_OR_MNIL(c) (IS_MSEP(c) || IS_MNIL(c))
|
||||||
|
|
||||||
#define ISDRIVE(s) \
|
#define IS_MDRIVE(s) \
|
||||||
(((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \
|
(((s[0] >= QSE_MT('A') && s[0] <= QSE_MT('Z')) || \
|
||||||
(s[0] >= QSE_T('a') && s[0] <= QSE_T('z'))) && \
|
(s[0] >= QSE_MT('a') && s[0] <= QSE_MT('z'))) && \
|
||||||
s[1] == QSE_T(':'))
|
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__)
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
/* a drive like c:tmp is absolute in positioning the drive.
|
/* a drive like c:tmp is absolute in positioning the drive.
|
||||||
* but the path within the drive is kind of relative */
|
* but the path within the drive is kind of relative */
|
||||||
if (ISDRIVE(path)) return 1;
|
if (IS_MDRIVE(path)) return 1;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
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 defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
if (ISDRIVE(path)) return 1;
|
if (IS_MDRIVE(path)) return 1;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
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 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
|
#endif
|
||||||
return 0;
|
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;
|
const qse_mchar_t* ptr;
|
||||||
qse_char_t* dst;
|
qse_mchar_t* dst;
|
||||||
qse_char_t* non_root_start;
|
qse_mchar_t* non_root_start;
|
||||||
int has_root = 0;
|
int has_root = 0;
|
||||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
int is_drive = 0;
|
int is_drive = 0;
|
||||||
#endif
|
#endif
|
||||||
qse_size_t canon_len;
|
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 */
|
/* if the source is empty, no translation is needed */
|
||||||
canon[0] = QSE_T('\0');
|
canon[0] = QSE_MT('\0');
|
||||||
return 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;
|
dst = canon;
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
if (ISDRIVE(ptr))
|
if (IS_MDRIVE(ptr))
|
||||||
{
|
{
|
||||||
/* handle drive letter */
|
/* handle drive letter */
|
||||||
*dst++ = *ptr++; /* drive letter */
|
*dst++ = *ptr++; /* drive letter */
|
||||||
*dst++ = *ptr++; /* colon */
|
*dst++ = *ptr++; /* colon */
|
||||||
|
|
||||||
is_drive = 1;
|
is_drive = 1;
|
||||||
if (IS_SEP(*ptr))
|
if (IS_MSEP(*ptr))
|
||||||
{
|
{
|
||||||
*dst++ = *ptr++; /* root directory */
|
*dst++ = *ptr++; /* root directory */
|
||||||
has_root = 1;
|
has_root = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IS_SEP(*ptr))
|
else if (IS_MSEP(*ptr))
|
||||||
{
|
{
|
||||||
*dst++ = *ptr++; /* root directory */
|
*dst++ = *ptr++; /* root directory */
|
||||||
has_root = 1;
|
has_root = 1;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
/* handle UNC path for Windows */
|
/* handle UNC path for Windows */
|
||||||
if (IS_SEP(*ptr))
|
if (IS_MSEP(*ptr))
|
||||||
{
|
{
|
||||||
*dst++ = *ptr++;
|
*dst++ = *ptr++;
|
||||||
|
|
||||||
if (IS_SEP_OR_NIL(*ptr))
|
if (IS_MSEP_OR_MNIL(*ptr))
|
||||||
{
|
{
|
||||||
/* if there is another separator after \\,
|
/* if there is another separator after \\,
|
||||||
* it's not an UNC path. */
|
* 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
|
else
|
||||||
{
|
{
|
||||||
/* if it starts with \\, process host name */
|
/* if it starts with \\, process host name */
|
||||||
do { *dst++ = *ptr++; } while (!IS_SEP_OR_NIL(*ptr));
|
do { *dst++ = *ptr++; } while (!IS_MSEP_OR_MNIL(*ptr));
|
||||||
if (IS_SEP(*ptr)) *dst++ = *ptr++;
|
if (IS_MSEP(*ptr)) *dst++ = *ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (IS_SEP(*ptr))
|
if (IS_MSEP(*ptr))
|
||||||
{
|
{
|
||||||
*dst++ = *ptr++; /* root directory */
|
*dst++ = *ptr++; /* root directory */
|
||||||
has_root = 1;
|
has_root = 1;
|
||||||
@ -137,30 +141,30 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const qse_char_t* seg;
|
const qse_mchar_t* seg;
|
||||||
qse_size_t seglen;
|
qse_size_t seglen;
|
||||||
|
|
||||||
/* skip duplicate separators */
|
/* skip duplicate separators */
|
||||||
while (IS_SEP(*ptr)) ptr++;
|
while (IS_MSEP(*ptr)) ptr++;
|
||||||
|
|
||||||
/* end of path reached */
|
/* end of path reached */
|
||||||
if (*ptr == QSE_T('\0')) break;
|
if (*ptr == QSE_MT('\0')) break;
|
||||||
|
|
||||||
/* find the next segment */
|
/* find the next segment */
|
||||||
seg = ptr;
|
seg = ptr;
|
||||||
while (!IS_SEP_OR_NIL(*ptr)) ptr++;
|
while (!IS_MSEP_OR_MNIL(*ptr)) ptr++;
|
||||||
seglen = ptr - seg;
|
seglen = ptr - seg;
|
||||||
|
|
||||||
/* handle the segment */
|
/* handle the segment */
|
||||||
if (seglen == 1 && seg[0] == QSE_T('.'))
|
if (seglen == 1 && seg[0] == QSE_MT('.'))
|
||||||
{
|
{
|
||||||
/* eat up . */
|
/* eat up . */
|
||||||
}
|
}
|
||||||
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
|
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 */
|
/* eat up the previous segment */
|
||||||
qse_char_t* tmp;
|
qse_mchar_t* tmp;
|
||||||
|
|
||||||
tmp = dst;
|
tmp = dst;
|
||||||
if (tmp > non_root_start)
|
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)
|
while (tmp > non_root_start)
|
||||||
{
|
{
|
||||||
tmp--;
|
tmp--;
|
||||||
if (IS_SEP(*tmp))
|
if (IS_MSEP(*tmp))
|
||||||
{
|
{
|
||||||
tmp++; /* position it next to the separator */
|
tmp++; /* position it next to the separator */
|
||||||
break;
|
break;
|
||||||
@ -212,7 +216,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
|||||||
goto normal;
|
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 ../
|
/* 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:
|
normal:
|
||||||
while (seg < ptr) *dst++ = *seg++;
|
while (seg < ptr) *dst++ = *seg++;
|
||||||
if (IS_SEP(*ptr))
|
if (IS_MSEP(*ptr))
|
||||||
{
|
{
|
||||||
/* this segment ended with a separator */
|
/* this segment ended with a separator */
|
||||||
*dst++ = *seg++; /* copy the 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);
|
while (1);
|
||||||
|
|
||||||
if (dst > non_root_start && IS_SEP(dst[-1]) &&
|
if (dst > non_root_start && IS_MSEP(dst[-1]) &&
|
||||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_SEP(ptr[-1])))
|
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_MSEP(ptr[-1])))
|
||||||
{
|
{
|
||||||
/* if the canoncal path composed so far ends with a separator
|
/* if the canoncal path composed so far ends with a separator
|
||||||
* and the original path didn't end with the separator, delete
|
* 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:
|
* dst > non_root_start:
|
||||||
* there is at least 1 character after the root directory
|
* there is at least 1 character after the root directory
|
||||||
* part.
|
* part.
|
||||||
* IS_SEP(dst[-1]):
|
* IS_MSEP(dst[-1]):
|
||||||
* the canonical path ends with a separator.
|
* the canonical path ends with a separator.
|
||||||
* IS_SEP(ptr[-1]):
|
* IS_MSEP(ptr[-1]):
|
||||||
* the origial path ends with a separator.
|
* the origial path ends with a separator.
|
||||||
*/
|
*/
|
||||||
dst[-1] = QSE_T('\0');
|
dst[-1] = QSE_MT('\0');
|
||||||
canon_len = dst - canon - 1;
|
canon_len = dst - canon - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* just null-terminate the canonical path normally */
|
/* just null-terminate the canonical path normally */
|
||||||
dst[0] = QSE_T('\0');
|
dst[0] = QSE_MT('\0');
|
||||||
canon_len = dst - canon;
|
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
|
/* when resolving to a single dot, a trailing separator is not
|
||||||
* retained though the orignal path name contains it. */
|
* retained though the orignal path name contains it. */
|
||||||
canon[0] = QSE_T('.');
|
canon[0] = QSE_MT('.');
|
||||||
canon[1] = QSE_T('\0');
|
canon[1] = QSE_MT('\0');
|
||||||
canon_len = 1;
|
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
|
/* i don't have to retain a trailing separator
|
||||||
* if the last segment is double slashes because
|
* if the last segment is double slashes because
|
||||||
* the double slahses indicate a directory obviously */
|
* the double slahses indicate a directory obviously */
|
||||||
if (canon[canon_len-3] == QSE_T('.') &&
|
if (canon[canon_len-3] == QSE_MT('.') &&
|
||||||
canon[canon_len-2] == QSE_T('.') &&
|
canon[canon_len-2] == QSE_MT('.') &&
|
||||||
IS_SEP(canon[canon_len-1]))
|
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)
|
else if (canon_len > adj_base_len)
|
||||||
{
|
{
|
||||||
if (IS_SEP(canon[canon_len-4]) &&
|
if (IS_MSEP(canon[canon_len-4]) &&
|
||||||
canon[canon_len-3] == QSE_T('.') &&
|
canon[canon_len-3] == QSE_MT('.') &&
|
||||||
canon[canon_len-2] == QSE_T('.') &&
|
canon[canon_len-2] == QSE_MT('.') &&
|
||||||
IS_SEP(canon[canon_len-1]))
|
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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,6 +389,9 @@ static qse_mchar_t* parse_initial_line (
|
|||||||
htrd->re.u.q.param = QSE_NULL;
|
htrd->re.u.q.param = QSE_NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/* skip spaces after the url part */
|
||||||
do { p++; } while (is_space_octet(*p));
|
do { p++; } while (is_space_octet(*p));
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <qse/cmn/str.h>
|
#include <qse/cmn/str.h>
|
||||||
#include <qse/cmn/chr.h>
|
#include <qse/cmn/chr.h>
|
||||||
#include <qse/cmn/htb.h>
|
#include <qse/cmn/htb.h>
|
||||||
|
#include "../cmn/mem.h"
|
||||||
|
|
||||||
int qse_comparehttpversions (
|
int qse_comparehttpversions (
|
||||||
const qse_http_version_t* v1,
|
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');
|
*out = QSE_MT('\0');
|
||||||
return out - buf;
|
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;
|
if (writable) goto forward;
|
||||||
|
|
||||||
n = httpd->cbs->mux.writable (
|
n = httpd->scb->mux.writable (
|
||||||
httpd, qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN), 0);
|
httpd, qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN), 0);
|
||||||
if (n >= 1)
|
if (n >= 1)
|
||||||
{
|
{
|
||||||
@ -886,7 +886,7 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client (
|
|||||||
qse_ssize_t n;
|
qse_ssize_t n;
|
||||||
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
|
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)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "../cmn/mem.h"
|
#include "../cmn/mem.h"
|
||||||
#include "../cmn/syscall.h"
|
#include "../cmn/syscall.h"
|
||||||
#include <qse/cmn/str.h>
|
#include <qse/cmn/str.h>
|
||||||
|
#include <qse/cmn/path.h>
|
||||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||||
|
|
||||||
typedef struct task_dir_t task_dir_t;
|
typedef struct task_dir_t task_dir_t;
|
||||||
@ -35,15 +36,24 @@ struct task_dir_t
|
|||||||
typedef struct task_dseg_t task_dseg_t;
|
typedef struct task_dseg_t task_dseg_t;
|
||||||
struct task_dseg_t
|
struct task_dseg_t
|
||||||
{
|
{
|
||||||
|
qse_http_version_t version;
|
||||||
|
int keepalive;
|
||||||
|
int chunked;
|
||||||
|
|
||||||
const qse_mchar_t* path;
|
const qse_mchar_t* path;
|
||||||
qse_dir_t* handle;
|
qse_dir_t* handle;
|
||||||
qse_dirent_t* dent;
|
qse_dirent_t* dent;
|
||||||
|
|
||||||
int header_added;
|
#define HEADER_ADDED (1 << 0)
|
||||||
int footer_pending;
|
#define FOOTER_ADDED (1 << 1)
|
||||||
|
#define FOOTER_PENDING (1 << 2)
|
||||||
|
#define DIRENT_PENDING (1 << 3)
|
||||||
|
int state;
|
||||||
|
|
||||||
/*qse_mchar_t buf[4096];*/
|
qse_size_t tcount; /* total directory entries */
|
||||||
qse_mchar_t buf[512]; /* TOOD: increate size */
|
qse_size_t dcount; /* the number of items in the buffer */
|
||||||
|
|
||||||
|
qse_mchar_t buf[4096];
|
||||||
qse_size_t bufpos;
|
qse_size_t bufpos;
|
||||||
qse_size_t buflen;
|
qse_size_t buflen;
|
||||||
qse_size_t bufrem;
|
qse_size_t bufrem;
|
||||||
@ -70,14 +80,88 @@ static void task_fini_dseg (
|
|||||||
QSE_CLOSEDIR (ctx->handle);
|
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)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
{
|
{
|
||||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||||
qse_ssize_t n;
|
qse_ssize_t n;
|
||||||
int x;
|
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 buffer size is fixed to QSE_COUNTOF(ctx->buf).
|
||||||
* the number of digits need to hold the the size converted to
|
* 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.
|
* the size of the buffer arrray, you should check this size.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SIZE_CHLEN 4
|
/* initialize buffer */
|
||||||
#define SIZE_CHLENCRLF 2
|
ctx->dcount = 0; /* reset the entry counter */
|
||||||
#define SIZE_CHENDCRLF 2
|
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)
|
|
||||||
{
|
{
|
||||||
x = snprintf (
|
/* reserve space to fill with the chunk length
|
||||||
&ctx->buf[ctx->buflen],
|
* 4 for the actual chunk length and +2 for \r\n */
|
||||||
ctx->bufrem,
|
ctx->buflen = SIZE_CHLEN + SIZE_CHLENCRLF;
|
||||||
QSE_MT("</ul></body></html>\r\n0\r\n"));
|
/* free space remaing in the buffer for the chunk data */
|
||||||
if (x == -1 || x >= ctx->bufrem)
|
ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - SIZE_CHENDCRLF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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
|
/* return an error if the buffer is too small to hold the
|
||||||
* trailing footer. you need to increate the buffer size */
|
* trailing footer. you need to increate the buffer size */
|
||||||
|
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->buflen += x;
|
ctx->state &= ~FOOTER_PENDING;
|
||||||
ctx->chunklen = ctx->buflen - 5; /* -5 for \r\n0\r\n added above */
|
ctx->state |= FOOTER_ADDED;
|
||||||
|
|
||||||
/* CHENDCRLF */
|
if (ctx->chunked) fill_chunk_length (ctx);
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
goto send_dirlist;
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
|
||||||
|
|
||||||
goto set_chunklen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen],
|
&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||||
ctx->bufrem,
|
QSE_MT("<html><head></head><body><b>%s</b><ul>%s"),
|
||||||
QSE_MT("<html><head><title>Directory Listing</title></head><body><b>%s</b><ul><li><a href='../'>..</a></li>"),
|
ctx->path, (is_root? QSE_MT(""): QSE_MT("<li><a href='../'>..</a></li>"))
|
||||||
ctx->path
|
|
||||||
);
|
);
|
||||||
if (x == -1 || x >= ctx->bufrem)
|
if (x == -1 || x >= ctx->bufrem)
|
||||||
{
|
{
|
||||||
/* return an error if the buffer is too small to hold the header.
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->buflen += x;
|
ctx->buflen += x;
|
||||||
ctx->bufrem -= 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);
|
ctx->dent = QSE_READDIR (ctx->handle);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!ctx->dent)
|
if (!ctx->dent)
|
||||||
{
|
{
|
||||||
// TODO: check if errno has changed from before QSE_READDIR().
|
/* TODO: check if errno has changed from before QSE_READDIR().
|
||||||
// and return -1 if so.
|
and return -1 if so. */
|
||||||
x = snprintf (
|
if (add_footer (ctx) <= -1)
|
||||||
&ctx->buf[ctx->buflen],
|
|
||||||
ctx->bufrem,
|
|
||||||
QSE_MT("</ul></body></html>\r\n0\r\n"));
|
|
||||||
if (x == -1 || x >= ctx->bufrem)
|
|
||||||
{
|
{
|
||||||
ctx->footer_pending = 1;
|
/* failed to add the footer part */
|
||||||
ctx->chunklen = ctx->buflen;
|
if (ctx->chunked)
|
||||||
|
{
|
||||||
/* CHENDCRLF */
|
close_chunk_data (ctx, ctx->buflen);
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
fill_chunk_length (ctx);
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
}
|
||||||
}
|
ctx->state |= FOOTER_PENDING;
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx->buflen += x;
|
|
||||||
ctx->chunklen = ctx->buflen - 5;
|
|
||||||
|
|
||||||
/* CHENDCRLF */
|
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
|
||||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
|
||||||
}
|
}
|
||||||
|
else if (ctx->chunked) fill_chunk_length (ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (qse_mbscmp (ctx->dent->d_name, QSE_MT(".")) != 0 &&
|
else if (qse_mbscmp (ctx->dent->d_name, QSE_MT(".")) != 0 &&
|
||||||
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 (
|
x = snprintf (
|
||||||
&ctx->buf[ctx->buflen],
|
&ctx->buf[ctx->buflen],
|
||||||
ctx->bufrem,
|
ctx->bufrem,
|
||||||
QSE_MT("<li><a href='%s%s'>%s%s</a></li>"),
|
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_type == DT_DIR? QSE_MT("/"): QSE_MT("")),
|
||||||
ctx->dent->d_name,
|
ctx->dent->d_name,
|
||||||
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT(""))
|
(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)
|
if (x == -1 || x >= ctx->bufrem)
|
||||||
{
|
{
|
||||||
/* buffer not large enough to hold this entry */
|
/* 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 */
|
if (ctx->chunked)
|
||||||
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 |= DIRENT_PENDING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ctx->buflen += x;
|
ctx->buflen += x;
|
||||||
ctx->bufrem -= x;
|
ctx->bufrem -= x;
|
||||||
|
ctx->dcount++;
|
||||||
|
ctx->tcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,167 +337,41 @@ static int task_main_dseg_chunked (
|
|||||||
}
|
}
|
||||||
while (1);
|
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:
|
send_dirlist:
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->client.send (
|
n = httpd->scb->client.send (
|
||||||
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen);
|
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen - ctx->bufpos);
|
||||||
if (n <= -1) return -1;
|
if (n <= -1) return -1;
|
||||||
|
|
||||||
/* NOTE if (n == 0), it will enter an infinite loop */
|
/* NOTE if (n == 0), it will enter an infinite loop */
|
||||||
|
|
||||||
ctx->bufpos += n;
|
ctx->bufpos += n;
|
||||||
ctx->buflen -= n;
|
return (ctx->bufpos < ctx->buflen || (ctx->state & FOOTER_PENDING) || ctx->dent)? 1: 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_httpd_task_t* entask_directory_segment (
|
static qse_httpd_task_t* entask_directory_segment (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
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;
|
qse_httpd_task_t task;
|
||||||
task_dseg_t data;
|
task_dseg_t data;
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
data.handle = handle;
|
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));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
task.init = task_init_dseg;
|
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.fini = task_fini_dseg;
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
qse_printf (QSE_T("Debug: entasking directory segment (%d)\n"), client->handle.i);
|
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 */
|
/* deep-copy the context data to the extension area */
|
||||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||||
|
|
||||||
qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path);
|
qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path);
|
||||||
xtn->path = (qse_mchar_t*)(xtn + 1);
|
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("keep-alive"): QSE_MT("close")),
|
||||||
(dir->keepalive? QSE_MT("Transfer-Encoding: chunked\r\n"): QSE_MT(""))
|
(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;
|
if (x) return 0;
|
||||||
|
|
||||||
QSE_CLOSEDIR (handle);
|
QSE_CLOSEDIR (handle);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "../cmn/mem.h"
|
#include "../cmn/mem.h"
|
||||||
#include "../cmn/syscall.h"
|
#include "../cmn/syscall.h"
|
||||||
#include <qse/cmn/str.h>
|
#include <qse/cmn/str.h>
|
||||||
|
#include <qse/cmn/path.h>
|
||||||
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||||
|
|
||||||
typedef struct task_file_t task_file_t;
|
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)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
{
|
{
|
||||||
task_fseg_t* ctx = (task_fseg_t*)task->ctx;
|
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 (
|
static int task_main_fseg (
|
||||||
@ -68,7 +69,7 @@ static int task_main_fseg (
|
|||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
|
|
||||||
/* TODO: more adjustment needed for OS with different sendfile semantics... */
|
/* 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);
|
httpd, client, ctx->handle, &ctx->offset, count);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
@ -147,7 +148,7 @@ static QSE_INLINE int task_main_file (
|
|||||||
qse_printf (QSE_T("opening file %hs\n"), file->path);
|
qse_printf (QSE_T("opening file %hs\n"), file->path);
|
||||||
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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;
|
int http_errnum;
|
||||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
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;
|
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;
|
int http_errnum;
|
||||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
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;
|
if (x) return 0;
|
||||||
httpd->cbs->file.close (httpd, handle);
|
httpd->scb->file.close (httpd, handle);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
no_file_send:
|
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;
|
return (x == QSE_NULL)? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n"));
|
|||||||
|
|
||||||
if (writable) goto forward;
|
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 == 0) qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@NOT WRITABLE\n"));
|
||||||
if (n >= 1)
|
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"),
|
qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
|
||||||
(int)QSE_MBS_LEN(proxy->reqfwdbuf),
|
(int)QSE_MBS_LEN(proxy->reqfwdbuf),
|
||||||
QSE_MBS_PTR(proxy->reqfwdbuf));
|
QSE_MBS_PTR(proxy->reqfwdbuf));
|
||||||
n = httpd->cbs->peer.send (
|
n = httpd->scb->peer.send (
|
||||||
httpd, &proxy->peer,
|
httpd, &proxy->peer,
|
||||||
QSE_MBS_PTR(proxy->reqfwdbuf),
|
QSE_MBS_PTR(proxy->reqfwdbuf),
|
||||||
QSE_MBS_LEN(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;
|
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
|
||||||
|
|
||||||
if (proxy->peer_status & PROXY_PEER_OPEN)
|
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->res) qse_mbs_close (proxy->res);
|
||||||
if (proxy->peer_htrd) qse_htrd_close (proxy->peer_htrd);
|
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... */
|
/* TODO: check if proxy outputs more than content-length if it is set... */
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
/* can't return internal server error any more... */
|
/* 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);
|
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;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->peer.recv (
|
n = httpd->scb->peer.recv (
|
||||||
httpd, &proxy->peer,
|
httpd, &proxy->peer,
|
||||||
&proxy->buf[proxy->buflen],
|
&proxy->buf[proxy->buflen],
|
||||||
QSE_SIZEOF(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
|
* side is writable. it should be safe to write whenever
|
||||||
* this task function is called. */
|
* this task function is called. */
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
/* can't return internal server error any more... */
|
/* 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);
|
qse_printf (QSE_T("[proxy_3 sending %d bytes]\n"), (int)count);
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->client.send (
|
n = httpd->scb->client.send (
|
||||||
httpd, client,
|
httpd, client,
|
||||||
&QSE_MBS_CHAR(proxy->res,proxy->res_consumed),
|
&QSE_MBS_CHAR(proxy->res,proxy->res_consumed),
|
||||||
count
|
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"));
|
qse_printf (QSE_T("]\n"));
|
||||||
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->client.send (
|
n = httpd->scb->client.send (
|
||||||
httpd, client,
|
httpd, client,
|
||||||
QSE_MBS_CPTR(proxy->res,proxy->res_consumed),
|
QSE_MBS_CPTR(proxy->res,proxy->res_consumed),
|
||||||
count
|
count
|
||||||
@ -1181,7 +1181,7 @@ qse_printf (QSE_T("[proxy-2 send failure....\n"));
|
|||||||
|
|
||||||
/* there is something to read from peer */
|
/* there is something to read from peer */
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->peer.recv (
|
n = httpd->scb->peer.recv (
|
||||||
httpd, &proxy->peer,
|
httpd, &proxy->peer,
|
||||||
&proxy->buf[proxy->buflen],
|
&proxy->buf[proxy->buflen],
|
||||||
QSE_SIZEOF(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;
|
int n;
|
||||||
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->peer.connected (httpd, &proxy->peer);
|
n = httpd->scb->peer.connected (httpd, &proxy->peer);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
/* improve error conversion */
|
/* improve error conversion */
|
||||||
@ -1378,7 +1378,7 @@ qse_printf (QSE_T("task_main_proxy....\n"));
|
|||||||
proxy->res_pending = 0;
|
proxy->res_pending = 0;
|
||||||
|
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||||
n = httpd->cbs->peer.open (httpd, &proxy->peer);
|
n = httpd->scb->peer.open (httpd, &proxy->peer);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
/* TODO: translate error code to http error... */
|
/* TODO: translate error code to http error... */
|
||||||
|
@ -34,8 +34,6 @@
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
# include "../cmn/syscall.h"
|
# include "../cmn/syscall.h"
|
||||||
# include <errno.h>
|
|
||||||
# include <sys/stat.h>
|
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
# include <netinet/in.h>
|
# include <netinet/in.h>
|
||||||
# if defined(HAVE_SYS_SENDFILE_H)
|
# if defined(HAVE_SYS_SENDFILE_H)
|
||||||
@ -49,8 +47,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_SSL)
|
#if defined(HAVE_SSL)
|
||||||
# include <openssl/ssl.h>
|
# include <openssl/ssl.h>
|
||||||
# include <openssl/err.h>
|
# include <openssl/err.h>
|
||||||
@ -543,13 +539,13 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
|||||||
|
|
||||||
oops:
|
oops:
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
if (fd >= 0) close (fd);
|
if (fd >= 0) QSE_CLOSE (fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
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 (
|
static int server_accept (
|
||||||
@ -578,7 +574,7 @@ static int server_accept (
|
|||||||
{
|
{
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
||||||
/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/
|
/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/
|
||||||
close (fd);
|
QSE_CLOSE (fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -659,13 +655,13 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
|||||||
|
|
||||||
oops:
|
oops:
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
if (fd >= 0) close (fd);
|
if (fd >= 0) QSE_CLOSE (fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
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)
|
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]);
|
if (mux->mev.ptr[i]) qse_httpd_freemem (httpd, mux->mev.ptr[i]);
|
||||||
qse_httpd_freemem (httpd, mux->mev.ptr);
|
qse_httpd_freemem (httpd, mux->mev.ptr);
|
||||||
}
|
}
|
||||||
close (mux->fd);
|
QSE_CLOSE (mux->fd);
|
||||||
qse_httpd_freemem (httpd, mux);
|
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(".txt"))? QSE_MT("text/plain"):
|
||||||
qse_mbsend (path, QSE_MT(".jpg"))? QSE_MT("image/jpeg"):
|
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(".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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,7 +1013,7 @@ static int file_ropen (
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
|
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)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
@ -1042,7 +1041,7 @@ static int file_wopen (
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
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)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
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)
|
static void file_close (qse_httpd_t* httpd, qse_ubi_t handle)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("closing file %d\n"), handle.i);
|
qse_printf (QSE_T("closing file %d\n"), handle.i);
|
||||||
close (handle.i);
|
QSE_CLOSE (handle.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_ssize_t file_read (
|
static qse_ssize_t file_read (
|
||||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||||
qse_mchar_t* buf, qse_size_t len)
|
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 (
|
static qse_ssize_t file_write (
|
||||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||||
const qse_mchar_t* buf, qse_size_t len)
|
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 (
|
static void client_close (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||||
{
|
{
|
||||||
close (client->handle.i);
|
QSE_CLOSE (client->handle.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_shutdown (
|
static void client_shutdown (
|
||||||
@ -1264,8 +1263,10 @@ static int process_request (
|
|||||||
|
|
||||||
/* percent-decode the query path to the original buffer
|
/* percent-decode the query path to the original buffer
|
||||||
* since i'm not gonna need it in the original form
|
* since i'm not gonna need it in the original form
|
||||||
* any more */
|
* any more. once it's decoded in the peek mode,
|
||||||
qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
* 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("================================\n"));
|
||||||
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\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
|
#else
|
||||||
if (peek)
|
if (peek)
|
||||||
{
|
{
|
||||||
qse_stat_t st;
|
|
||||||
|
|
||||||
qse_httpd_discardcontent (httpd, req);
|
qse_httpd_discardcontent (httpd, req);
|
||||||
|
task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, 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);
|
|
||||||
if (task == QSE_NULL) goto oops;
|
if (task == QSE_NULL) goto oops;
|
||||||
}
|
}
|
||||||
#endif
|
#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 */
|
||||||
{ server_open, server_close, server_accept },
|
{ server_open, server_close, server_accept },
|
||||||
@ -1617,14 +1612,17 @@ static qse_httpd_cbs_t httpd_standard_callbacks =
|
|||||||
client_send,
|
client_send,
|
||||||
client_sendfile,
|
client_sendfile,
|
||||||
client_accepted,
|
client_accepted,
|
||||||
client_closed },
|
client_closed }
|
||||||
|
|
||||||
/* http request */
|
|
||||||
peek_request,
|
|
||||||
handle_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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/>.
|
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 "httpd.h"
|
||||||
#include "../cmn/mem.h"
|
#include "../cmn/mem.h"
|
||||||
#include <qse/cmn/str.h>
|
#include <qse/cmn/str.h>
|
||||||
#include <qse/cmn/fmt.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 <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <qse/cmn/stdio.h> /* TODO: remove this */
|
||||||
|
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* many functions in this file use qse_size_t.
|
* many functions in this file use qse_size_t.
|
||||||
@ -43,7 +47,7 @@
|
|||||||
static int task_main_disconnect (
|
static int task_main_disconnect (
|
||||||
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)
|
||||||
{
|
{
|
||||||
httpd->cbs->client.shutdown (httpd, client);
|
httpd->scb->client.shutdown (httpd, client);
|
||||||
return 0;
|
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? */
|
/* 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;
|
if (n <= -1) return -1;
|
||||||
|
|
||||||
ptr = (const qse_mchar_t*)task->ctx + n;
|
ptr = (const qse_mchar_t*)task->ctx + n;
|
||||||
@ -133,7 +137,7 @@ static int task_main_text (
|
|||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
|
|
||||||
/* TODO: do i need to add code to skip this send if count is 0? */
|
/* 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;
|
if (n <= -1) return -1;
|
||||||
|
|
||||||
ctx->left -= n;
|
ctx->left -= n;
|
||||||
@ -206,7 +210,7 @@ static int task_main_format (
|
|||||||
count = MAX_SEND_SIZE;
|
count = MAX_SEND_SIZE;
|
||||||
if (count >= ctx->left) count = ctx->left;
|
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;
|
if (n <= -1) return -1;
|
||||||
|
|
||||||
ctx->left -= n;
|
ctx->left -= n;
|
||||||
@ -437,6 +441,21 @@ qse_httpd_task_t* qse_httpd_entaskauth (
|
|||||||
realm, (unsigned long)qse_mbslen(lmsg) + 4, lmsg);
|
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
|
#if 0
|
||||||
@ -451,4 +470,3 @@ qse_httpd_task_t* qse_httpd_entaskconnect (
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -245,7 +245,7 @@ static QSE_INLINE int dequeue_task (
|
|||||||
{
|
{
|
||||||
if (client->status & CLIENT_TASK_TRIGGER_IN_MUX(i))
|
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);
|
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)
|
static int htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||||
{
|
{
|
||||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
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)
|
static int htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||||
{
|
{
|
||||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
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 =
|
static qse_htrd_recbs_t htrd_recbs =
|
||||||
@ -317,9 +317,9 @@ static qse_httpd_client_t* new_client (
|
|||||||
return QSE_NULL;
|
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 |= CLIENT_READY;
|
||||||
|
|
||||||
client->status = tmpl->status;
|
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)
|
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;
|
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note that client.closed is not a counterpart to client.accepted.
|
/* note that client.closed is not a counterpart to client.accepted.
|
||||||
* so it is called even if client.close() failed. */
|
* so it is called even if client.close() failed. */
|
||||||
if (httpd->cbs->client.closed)
|
if (httpd->scb->client.closed)
|
||||||
httpd->cbs->client.closed (httpd, client);
|
httpd->scb->client.closed (httpd, client);
|
||||||
|
|
||||||
httpd->cbs->client.close (httpd, client);
|
httpd->scb->client.close (httpd, client);
|
||||||
|
|
||||||
qse_httpd_freemem (httpd, client);
|
qse_httpd_freemem (httpd, client);
|
||||||
}
|
}
|
||||||
@ -434,7 +434,7 @@ static int accept_client (
|
|||||||
|
|
||||||
QSE_MEMSET (&clibuf, 0, QSE_SIZEOF(clibuf));
|
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 */
|
/* TODO: proper logging */
|
||||||
qse_char_t tmp[128];
|
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);
|
client = new_client (httpd, &clibuf);
|
||||||
if (client == QSE_NULL)
|
if (client == QSE_NULL)
|
||||||
{
|
{
|
||||||
httpd->cbs->client.close (httpd, &clibuf);
|
httpd->scb->client.close (httpd, &clibuf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i);
|
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,
|
httpd, mux, client->handle, QSE_HTTPD_MUX_READ,
|
||||||
perform_client_task, client) <= -1)
|
perform_client_task, client) <= -1)
|
||||||
{
|
{
|
||||||
@ -540,8 +540,8 @@ static void deactivate_servers (qse_httpd_t* httpd)
|
|||||||
{
|
{
|
||||||
if (server->active)
|
if (server->active)
|
||||||
{
|
{
|
||||||
httpd->cbs->mux.delhnd (httpd, httpd->mux, server->handle);
|
httpd->scb->mux.delhnd (httpd, httpd->mux, server->handle);
|
||||||
httpd->cbs->server.close (httpd, server);
|
httpd->scb->server.close (httpd, server);
|
||||||
server->active = 0;
|
server->active = 0;
|
||||||
httpd->server.nactive--;
|
httpd->server.nactive--;
|
||||||
}
|
}
|
||||||
@ -554,7 +554,7 @@ static int activate_servers (qse_httpd_t* httpd)
|
|||||||
|
|
||||||
for (server = httpd->server.list; server; server = server->next)
|
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_char_t buf[64];
|
||||||
qse_nwadtostr (&server->nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL);
|
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);
|
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,
|
httpd, httpd->mux, server->handle, QSE_HTTPD_MUX_READ,
|
||||||
accept_client, server) <= -1)
|
accept_client, server) <= -1)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("FAILED TO ADD SERVER HANDLE TO MUX....\n"));
|
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;
|
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;
|
qse_httpd_server_t* next = server->next;
|
||||||
|
|
||||||
httpd->cbs->server.close (httpd, server);
|
httpd->scb->server.close (httpd, server);
|
||||||
qse_httpd_freemem (httpd, server);
|
qse_httpd_freemem (httpd, server);
|
||||||
httpd->server.navail--;
|
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_mchar_t buf[4096]; /* TODO: adjust this buffer size */
|
||||||
qse_ssize_t m;
|
qse_ssize_t m;
|
||||||
|
|
||||||
QSE_ASSERT (httpd->cbs->client.recv != QSE_NULL);
|
QSE_ASSERT (httpd->scb->client.recv != QSE_NULL);
|
||||||
|
|
||||||
reread:
|
reread:
|
||||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
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 (m <= -1)
|
||||||
{
|
{
|
||||||
if (httpd->errnum == QSE_HTTPD_EAGAIN)
|
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.
|
/* the task is invoked for triggers.
|
||||||
* check if the client handle is writable */
|
* 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
|
/* it is not writable yet. so just skip
|
||||||
* performing the actual task */
|
* 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) !=
|
if ((client->status & CLIENT_HANDLE_IN_MUX) !=
|
||||||
(mux_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;
|
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||||
|
|
||||||
if (mux_status)
|
if (mux_status)
|
||||||
{
|
{
|
||||||
if (httpd->cbs->mux.addhnd (
|
if (httpd->scb->mux.addhnd (
|
||||||
httpd, httpd->mux, client->handle,
|
httpd, httpd->mux, client->handle,
|
||||||
mux_mask, perform_client_task, client) <= -1)
|
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))
|
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
if (httpd->cbs->mux.addhnd (
|
if (httpd->scb->mux.addhnd (
|
||||||
httpd, httpd->mux, task->trigger[i].handle,
|
httpd, httpd->mux, task->trigger[i].handle,
|
||||||
trigger_mux_mask, perform_client_task, client) <= -1)
|
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) !=
|
if ((client->status & CLIENT_HANDLE_IN_MUX) !=
|
||||||
(client_handle_mux_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;
|
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||||
|
|
||||||
if (client_handle_mux_mask)
|
if (client_handle_mux_mask)
|
||||||
{
|
{
|
||||||
if (httpd->cbs->mux.addhnd (
|
if (httpd->scb->mux.addhnd (
|
||||||
httpd, httpd->mux, client->handle,
|
httpd, httpd->mux, client->handle,
|
||||||
client_handle_mux_mask, perform_client_task, client) <= -1)
|
client_handle_mux_mask, perform_client_task, client) <= -1)
|
||||||
{
|
{
|
||||||
@ -1045,7 +1045,7 @@ static int perform_client_task (
|
|||||||
if (!(client->status & CLIENT_READY))
|
if (!(client->status & CLIENT_READY))
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
x = httpd->cbs->client.accepted (httpd, client);
|
x = httpd->scb->client.accepted (httpd, client);
|
||||||
if (x <= -1) goto oops;
|
if (x <= -1) goto oops;
|
||||||
if (x >= 1)
|
if (x >= 1)
|
||||||
{
|
{
|
||||||
@ -1139,11 +1139,11 @@ qse_httpd_task_t* qse_httpd_entask (
|
|||||||
/* arrange to invokde this task so long as
|
/* arrange to invokde this task so long as
|
||||||
* the client-side handle is writable. */
|
* the client-side handle is writable. */
|
||||||
QSE_ASSERT (client->status & CLIENT_HANDLE_IN_MUX);
|
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;
|
client->status &= ~CLIENT_HANDLE_IN_MUX;
|
||||||
|
|
||||||
qse_printf (QSE_T("MUX ADDHND CLIENT RW(ENTASK) %d\n"), client->handle.i);
|
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,
|
httpd, httpd->mux, client->handle,
|
||||||
QSE_HTTPD_MUX_READ | QSE_HTTPD_MUX_WRITE,
|
QSE_HTTPD_MUX_READ | QSE_HTTPD_MUX_WRITE,
|
||||||
perform_client_task, client) <= -1)
|
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;
|
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,
|
QSE_ASSERTX (httpd->server.list != QSE_NULL,
|
||||||
"Add listeners before calling qse_httpd_loop()");
|
"Add listeners before calling qse_httpd_loop()");
|
||||||
|
|
||||||
QSE_ASSERTX (httpd->client.list.head == QSE_NULL,
|
QSE_ASSERTX (httpd->client.list.head == QSE_NULL,
|
||||||
"No client should exist when this loop is started");
|
"No client should exist when this loop is started");
|
||||||
|
|
||||||
QSE_ASSERTX (httpd->cbs != QSE_NULL,
|
if (scb == QSE_NULL || rcb == QSE_NULL ||
|
||||||
"Set httpd callbacks before calling qse_httpd_loop()");
|
httpd->server.list == QSE_NULL)
|
||||||
|
|
||||||
if (httpd->server.list == QSE_NULL)
|
|
||||||
{
|
{
|
||||||
/* no listener specified */
|
|
||||||
httpd->errnum = QSE_HTTPD_EINVAL;
|
httpd->errnum = QSE_HTTPD_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpd->stopreq = 0;
|
||||||
|
httpd->scb = scb;
|
||||||
|
httpd->rcb = rcb;
|
||||||
|
|
||||||
QSE_ASSERT (httpd->server.navail > 0);
|
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)
|
if (httpd->mux == QSE_NULL)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("can't open mux....\n"));
|
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)
|
if (activate_servers (httpd) <= -1)
|
||||||
{
|
{
|
||||||
httpd->cbs->mux.close (httpd, httpd->mux);
|
httpd->scb->mux.close (httpd, httpd->mux);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (httpd->server.nactive <= 0)
|
if (httpd->server.nactive <= 0)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("no servers are active....\n"));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,7 +1202,7 @@ qse_printf (QSE_T("no servers are active....\n"));
|
|||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
count = httpd->cbs->mux.poll (httpd, httpd->mux, timeout);
|
count = httpd->scb->mux.poll (httpd, httpd->mux, timeout);
|
||||||
if (count <= -1)
|
if (count <= -1)
|
||||||
{
|
{
|
||||||
httpd->errnum = QSE_HTTPD_EIOMUX;
|
httpd->errnum = QSE_HTTPD_EIOMUX;
|
||||||
@ -1220,7 +1218,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: mux returned failure\n"));
|
|||||||
|
|
||||||
purge_client_list (httpd);
|
purge_client_list (httpd);
|
||||||
deactivate_servers (httpd);
|
deactivate_servers (httpd);
|
||||||
httpd->cbs->mux.close (httpd, httpd->mux);
|
httpd->scb->mux.close (httpd, httpd->mux);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ struct qse_httpd_t
|
|||||||
QSE_DEFINE_COMMON_FIELDS (httpd)
|
QSE_DEFINE_COMMON_FIELDS (httpd)
|
||||||
qse_httpd_errnum_t errnum;
|
qse_httpd_errnum_t errnum;
|
||||||
qse_httpd_ecb_t* ecb; /* event callbacks */
|
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 option;
|
||||||
int stopreq;
|
int stopreq;
|
||||||
|
@ -5,7 +5,7 @@ AM_CPPFLAGS = \
|
|||||||
-I$(top_srcdir)/include \
|
-I$(top_srcdir)/include \
|
||||||
-I$(includedir)
|
-I$(includedir)
|
||||||
|
|
||||||
bin_PROGRAMS = http01 upxd01
|
bin_PROGRAMS = httpd01 httpd02 upxd01
|
||||||
|
|
||||||
LDFLAGS += -L../../lib/cmn -L../../lib/net
|
LDFLAGS += -L../../lib/cmn -L../../lib/net
|
||||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS)
|
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS)
|
||||||
@ -16,7 +16,9 @@ LDADD += $(UNICOWS_LIBS)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
http01_SOURCES = http01.c
|
httpd01_SOURCES = httpd01.c
|
||||||
|
httpd02_SOURCES = httpd02.c
|
||||||
upxd01_SOURCES = upxd01.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 = :
|
POST_UNINSTALL = :
|
||||||
build_triplet = @build@
|
build_triplet = @build@
|
||||||
host_triplet = @host@
|
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)
|
@WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
||||||
subdir = samples/net
|
subdir = samples/net
|
||||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||||
@ -52,13 +52,16 @@ CONFIG_CLEAN_FILES =
|
|||||||
CONFIG_CLEAN_VPATH_FILES =
|
CONFIG_CLEAN_VPATH_FILES =
|
||||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||||
PROGRAMS = $(bin_PROGRAMS)
|
PROGRAMS = $(bin_PROGRAMS)
|
||||||
am_http01_OBJECTS = http01.$(OBJEXT)
|
am_httpd01_OBJECTS = httpd01.$(OBJEXT)
|
||||||
http01_OBJECTS = $(am_http01_OBJECTS)
|
httpd01_OBJECTS = $(am_httpd01_OBJECTS)
|
||||||
am__DEPENDENCIES_1 =
|
am__DEPENDENCIES_1 =
|
||||||
@WCHAR_TRUE@@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
@WCHAR_TRUE@@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
||||||
am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
|
$(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)
|
am_upxd01_OBJECTS = upxd01.$(OBJEXT)
|
||||||
upxd01_OBJECTS = $(am_upxd01_OBJECTS)
|
upxd01_OBJECTS = $(am_upxd01_OBJECTS)
|
||||||
upxd01_LDADD = $(LDADD)
|
upxd01_LDADD = $(LDADD)
|
||||||
@ -77,8 +80,8 @@ CCLD = $(CC)
|
|||||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||||
$(LDFLAGS) -o $@
|
$(LDFLAGS) -o $@
|
||||||
SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
SOURCES = $(httpd01_SOURCES) $(httpd02_SOURCES) $(upxd01_SOURCES)
|
||||||
DIST_SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
DIST_SOURCES = $(httpd01_SOURCES) $(httpd02_SOURCES) $(upxd01_SOURCES)
|
||||||
ETAGS = etags
|
ETAGS = etags
|
||||||
CTAGS = ctags
|
CTAGS = ctags
|
||||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||||
@ -243,9 +246,11 @@ AM_CPPFLAGS = \
|
|||||||
|
|
||||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
|
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
|
||||||
$(SENDFILE_LIBS) $(am__append_1)
|
$(SENDFILE_LIBS) $(am__append_1)
|
||||||
http01_SOURCES = http01.c
|
httpd01_SOURCES = httpd01.c
|
||||||
|
httpd02_SOURCES = httpd02.c
|
||||||
upxd01_SOURCES = upxd01.c
|
upxd01_SOURCES = upxd01.c
|
||||||
http01_LDADD = $(LDADD) $(SSL_LIBS)
|
httpd01_LDADD = $(LDADD) $(SSL_LIBS)
|
||||||
|
httpd02_LDADD = $(LDADD) $(SSL_LIBS)
|
||||||
all: all-am
|
all: all-am
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
@ -323,9 +328,12 @@ clean-binPROGRAMS:
|
|||||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||||
echo " rm -f" $$list; \
|
echo " rm -f" $$list; \
|
||||||
rm -f $$list
|
rm -f $$list
|
||||||
http01$(EXEEXT): $(http01_OBJECTS) $(http01_DEPENDENCIES) $(EXTRA_http01_DEPENDENCIES)
|
httpd01$(EXEEXT): $(httpd01_OBJECTS) $(httpd01_DEPENDENCIES) $(EXTRA_httpd01_DEPENDENCIES)
|
||||||
@rm -f http01$(EXEEXT)
|
@rm -f httpd01$(EXEEXT)
|
||||||
$(LINK) $(http01_OBJECTS) $(http01_LDADD) $(LIBS)
|
$(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)
|
upxd01$(EXEEXT): $(upxd01_OBJECTS) $(upxd01_DEPENDENCIES) $(EXTRA_upxd01_DEPENDENCIES)
|
||||||
@rm -f upxd01$(EXEEXT)
|
@rm -f upxd01$(EXEEXT)
|
||||||
$(LINK) $(upxd01_OBJECTS) $(upxd01_LDADD) $(LIBS)
|
$(LINK) $(upxd01_OBJECTS) $(upxd01_LDADD) $(LIBS)
|
||||||
@ -336,7 +344,8 @@ mostlyclean-compile:
|
|||||||
distclean-compile:
|
distclean-compile:
|
||||||
-rm -f *.tab.c
|
-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@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd01.Po@am__quote@
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
@ -33,7 +33,7 @@ static void sigint (int sig)
|
|||||||
if (g_httpd) qse_httpd_stop (g_httpd);
|
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;
|
qse_httpd_t* httpd = QSE_NULL;
|
||||||
int ret = -1, i;
|
int ret = -1, i;
|
||||||
@ -66,7 +66,7 @@ int httpd_main (int argc, qse_char_t* argv[])
|
|||||||
signal (SIGPIPE, SIG_IGN);
|
signal (SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
|
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 (SIGINT, SIG_DFL);
|
||||||
signal (SIGPIPE, 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