added qse_httpd_entaskpath().
renames qse_httpd_entaskXXX() functions to a newer style
This commit is contained in:
parent
79370202bc
commit
f4ad3e3b66
@ -165,9 +165,9 @@ void qse_htrd_setrecbs (
|
|||||||
* callback function if it has processed a proper htrd request.
|
* callback function if it has processed a proper htrd request.
|
||||||
*/
|
*/
|
||||||
int qse_htrd_feed (
|
int qse_htrd_feed (
|
||||||
qse_htrd_t* htrd, /**< htrd */
|
qse_htrd_t* htrd, /**< htrd */
|
||||||
const qse_htoc_t* req, /**< request octets */
|
const qse_mchar_t* req, /**< request octets */
|
||||||
qse_size_t len /**< number of octets */
|
qse_size_t len /**< number of octets */
|
||||||
);
|
);
|
||||||
|
|
||||||
int qse_htrd_read (
|
int qse_htrd_read (
|
||||||
|
@ -31,8 +31,6 @@
|
|||||||
#include <qse/cmn/htb.h>
|
#include <qse/cmn/htb.h>
|
||||||
#include <qse/cmn/time.h>
|
#include <qse/cmn/time.h>
|
||||||
|
|
||||||
typedef qse_mchar_t qse_htoc_t;
|
|
||||||
|
|
||||||
/* octet buffer */
|
/* octet buffer */
|
||||||
typedef qse_mbs_t qse_htob_t;
|
typedef qse_mbs_t qse_htob_t;
|
||||||
|
|
||||||
@ -80,11 +78,20 @@ typedef qse_foff_t qse_http_range_int_t;
|
|||||||
typedef qse_ulong_t qse_http_range_int_t;
|
typedef qse_ulong_t qse_http_range_int_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum qse_http_range_type_t
|
||||||
|
{
|
||||||
|
QSE_HTTP_RANGE_NONE,
|
||||||
|
QSE_HTTP_RANGE_PROPER,
|
||||||
|
QSE_HTTP_RANGE_SUFFIX
|
||||||
|
};
|
||||||
|
typedef enum qse_http_range_type_t qse_http_range_type_t;
|
||||||
/**
|
/**
|
||||||
* The qse_http_range_t type defines a structure that can represent
|
* The qse_http_range_t type defines a structure that can represent
|
||||||
* a value for the @b Range: http header.
|
* a value for the @b Range: http header.
|
||||||
*
|
*
|
||||||
* If suffix is non-zero, 'from' is meaningleass and 'to' indicates
|
* If type is #QSE_HTTP_RANGE_NONE, this range is not valid.
|
||||||
|
*
|
||||||
|
* If type is #QSE_HTTP_RANGE_SUFFIX, 'from' is meaningleass and 'to' indicates
|
||||||
* the number of bytes from the back.
|
* the number of bytes from the back.
|
||||||
* - -500 => last 500 bytes
|
* - -500 => last 500 bytes
|
||||||
*
|
*
|
||||||
@ -95,16 +102,17 @@ typedef qse_ulong_t qse_http_range_int_t;
|
|||||||
* range.to = range.to + range.from - 1;
|
* range.to = range.to + range.from - 1;
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* If suffix is zero, 'from' and 'to' represents a proper range where
|
* If type is #QSE_HTTP_RANGE_PROPER, 'from' and 'to' represents a proper range
|
||||||
* the value of 0 indicates the first byte. This doesn't require any adjustment.
|
* where the value of 0 indicates the first byte. This doesn't require any
|
||||||
|
* adjustment.
|
||||||
* - 0-999 => first 1000 bytes
|
* - 0-999 => first 1000 bytes
|
||||||
* - 99- => from the 100th bytes to the end.
|
* - 99- => from the 100th bytes to the end.
|
||||||
*/
|
*/
|
||||||
struct qse_http_range_t
|
struct qse_http_range_t
|
||||||
{
|
{
|
||||||
int suffix; /**< suffix indicator */
|
qse_http_range_type_t type; /**< type indicator */
|
||||||
qse_http_range_int_t from; /**< starting offset */
|
qse_http_range_int_t from; /**< starting offset */
|
||||||
qse_http_range_int_t to; /**< ending offset */
|
qse_http_range_int_t to; /**< ending offset */
|
||||||
};
|
};
|
||||||
typedef struct qse_http_range_t qse_http_range_t;
|
typedef struct qse_http_range_t qse_http_range_t;
|
||||||
|
|
||||||
@ -112,12 +120,12 @@ typedef struct qse_http_range_t qse_http_range_t;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const qse_htoc_t* qse_gethttpmethodname (
|
const qse_mchar_t* qse_gethttpmethodname (
|
||||||
qse_http_method_t type
|
qse_http_method_t type
|
||||||
);
|
);
|
||||||
|
|
||||||
int qse_gethttpmethodtype (
|
int qse_gethttpmethodtype (
|
||||||
const qse_htoc_t* name,
|
const qse_mchar_t* name,
|
||||||
qse_http_method_t* method
|
qse_http_method_t* method
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -46,16 +46,38 @@ typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
|
|||||||
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
||||||
struct qse_httpd_cbs_t
|
struct qse_httpd_cbs_t
|
||||||
{
|
{
|
||||||
int (*handle_request) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
int (*handle_request) (
|
||||||
int (*handle_expect_continue) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
||||||
|
int (*handle_expect_continue) (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct qse_httpd_task_t qse_httpd_task_t;
|
typedef struct qse_httpd_task_t qse_httpd_task_t;
|
||||||
|
|
||||||
|
typedef int (*qse_httpd_task_init_t) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
qse_httpd_task_t* task
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef void (*qse_httpd_task_fini_t) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
qse_httpd_task_t* task
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef int (*qse_httpd_task_main_t) (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
qse_httpd_task_t* task
|
||||||
|
);
|
||||||
|
|
||||||
struct qse_httpd_task_t
|
struct qse_httpd_task_t
|
||||||
{
|
{
|
||||||
int (*init) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
/* you must not call another entask functions from within initailizer */
|
||||||
void (*fini) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
qse_httpd_task_init_t init;
|
||||||
int (*main) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
qse_httpd_task_fini_t fini;
|
||||||
|
qse_httpd_task_main_t main;
|
||||||
void* ctx;
|
void* ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -106,6 +128,12 @@ int qse_httpd_addlisteners (
|
|||||||
const qse_char_t* uri
|
const qse_char_t* uri
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
void qse_httpd_markclientbad (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client
|
||||||
|
);
|
||||||
|
|
||||||
#define qse_httpd_gettaskxtn(httpd,task) ((void*)(task+1))
|
#define qse_httpd_gettaskxtn(httpd,task) ((void*)(task+1))
|
||||||
|
|
||||||
int qse_httpd_entask (
|
int qse_httpd_entask (
|
||||||
@ -115,27 +143,35 @@ int qse_httpd_entask (
|
|||||||
qse_size_t xtnsize
|
qse_size_t xtnsize
|
||||||
);
|
);
|
||||||
|
|
||||||
int qse_httpd_entasksendtext (
|
int qse_httpd_entasktext (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
const qse_mchar_t* text
|
const qse_mchar_t* text
|
||||||
);
|
);
|
||||||
|
|
||||||
int qse_httpd_entasksendfmt (
|
int qse_httpd_entaskformat (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
const qse_mchar_t* fmt,
|
const qse_mchar_t* fmt,
|
||||||
...
|
...
|
||||||
);
|
);
|
||||||
|
|
||||||
int qse_httpd_entasksendfile (
|
int qse_httpd_entaskfile (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
int fd,
|
qse_ubi_t handle,
|
||||||
qse_foff_t offset,
|
qse_foff_t offset,
|
||||||
qse_foff_t size
|
qse_foff_t size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
int qse_httpd_entaskpath (
|
||||||
|
qse_httpd_t* httpd,
|
||||||
|
qse_httpd_client_t* client,
|
||||||
|
const qse_mchar_t* name,
|
||||||
|
const qse_http_range_t* range,
|
||||||
|
const qse_http_version_t* version
|
||||||
|
);
|
||||||
|
|
||||||
int qse_httpd_entaskdisconnect (
|
int qse_httpd_entaskdisconnect (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client
|
qse_httpd_client_t* client
|
||||||
|
@ -24,58 +24,58 @@
|
|||||||
|
|
||||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd)
|
QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd)
|
||||||
|
|
||||||
static const qse_htoc_t NUL = '\0';
|
static const qse_mchar_t NUL = QSE_MT('\0');
|
||||||
|
|
||||||
static QSE_INLINE int is_whspace_octet (qse_htoc_t c)
|
static QSE_INLINE int is_whspace_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
return c == QSE_MT(' ') || c == QSE_MT('\t') || c == QSE_MT('\r') || c == QSE_MT('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_space_octet (qse_htoc_t c)
|
static QSE_INLINE int is_space_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\r';
|
return c == ' ' || c == '\t' || c == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_purespace_octet (qse_htoc_t c)
|
static QSE_INLINE int is_purespace_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_upalpha_octet (qse_htoc_t c)
|
static QSE_INLINE int is_upalpha_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c >= 'A' && c <= 'Z';
|
return c >= 'A' && c <= 'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_loalpha_octet (qse_htoc_t c)
|
static QSE_INLINE int is_loalpha_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c >= 'a' && c <= 'z';
|
return c >= 'a' && c <= 'z';
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_alpha_octet (qse_htoc_t c)
|
static QSE_INLINE int is_alpha_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return (c >= 'A' && c <= 'Z') ||
|
return (c >= 'A' && c <= 'Z') ||
|
||||||
(c >= 'a' && c <= 'z');
|
(c >= 'a' && c <= 'z');
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_digit_octet (qse_htoc_t c)
|
static QSE_INLINE int is_digit_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int is_xdigit_octet (qse_htoc_t c)
|
static QSE_INLINE int is_xdigit_octet (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
return (c >= '0' && c <= '9') ||
|
return (c >= '0' && c <= '9') ||
|
||||||
(c >= 'A' && c <= 'F') ||
|
(c >= 'A' && c <= 'F') ||
|
||||||
(c >= 'a' && c <= 'f');
|
(c >= 'a' && c <= 'f');
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int digit_to_num (qse_htoc_t c)
|
static QSE_INLINE int digit_to_num (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9') return c - '0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int xdigit_to_num (qse_htoc_t c)
|
static QSE_INLINE int xdigit_to_num (qse_mchar_t c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9') return c - '0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
|
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
|
||||||
@ -85,7 +85,7 @@ static QSE_INLINE int xdigit_to_num (qse_htoc_t c)
|
|||||||
|
|
||||||
static QSE_INLINE int push_to_buffer (
|
static QSE_INLINE int push_to_buffer (
|
||||||
qse_htrd_t* htrd, qse_htob_t* octb,
|
qse_htrd_t* htrd, qse_htob_t* octb,
|
||||||
const qse_htoc_t* ptr, qse_size_t len)
|
const qse_mchar_t* ptr, qse_size_t len)
|
||||||
{
|
{
|
||||||
if (qse_mbs_ncat (octb, ptr, len) == (qse_size_t)-1)
|
if (qse_mbs_ncat (octb, ptr, len) == (qse_size_t)-1)
|
||||||
{
|
{
|
||||||
@ -198,10 +198,10 @@ void qse_htrd_fini (qse_htrd_t* htrd)
|
|||||||
qse_mbs_fini (&htrd->tmp.qparam);
|
qse_mbs_fini (&htrd->tmp.qparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_htoc_t* parse_initial_line (
|
static qse_mchar_t* parse_initial_line (
|
||||||
qse_htrd_t* htrd, qse_htoc_t* line)
|
qse_htrd_t* htrd, qse_mchar_t* line)
|
||||||
{
|
{
|
||||||
qse_htoc_t* p = line;
|
qse_mchar_t* p = line;
|
||||||
qse_mcstr_t tmp;
|
qse_mcstr_t tmp;
|
||||||
qse_http_method_t mtype;
|
qse_http_method_t mtype;
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ static qse_htoc_t* parse_initial_line (
|
|||||||
qse_htre_setqmethod (&htrd->re, mtype);
|
qse_htre_setqmethod (&htrd->re, mtype);
|
||||||
}
|
}
|
||||||
else if ((htrd->option & QSE_HTRD_RESPONSE) &&
|
else if ((htrd->option & QSE_HTRD_RESPONSE) &&
|
||||||
qse_mbsxcmp (tmp.ptr, tmp.len, "HTTP") == 0)
|
qse_mbsxcmp (tmp.ptr, tmp.len, QSE_MT("HTTP")) == 0)
|
||||||
{
|
{
|
||||||
/* it begins with HTTP. it may be a response */
|
/* it begins with HTTP. it may be a response */
|
||||||
htrd->retype = QSE_HTRD_RETYPE_S;
|
htrd->retype = QSE_HTRD_RETYPE_S;
|
||||||
@ -290,7 +290,7 @@ static qse_htoc_t* parse_initial_line (
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_htoc_t* out;
|
qse_mchar_t* out;
|
||||||
qse_mcstr_t param;
|
qse_mcstr_t param;
|
||||||
|
|
||||||
/* method name must be followed by space */
|
/* method name must be followed by space */
|
||||||
@ -437,12 +437,12 @@ void qse_htrd_setrecbs (qse_htrd_t* htrd, const qse_htrd_recbs_t* recbs)
|
|||||||
#define octet_toupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) & ~0x20) : (c))
|
#define octet_toupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) & ~0x20) : (c))
|
||||||
|
|
||||||
static QSE_INLINE int compare_octets (
|
static QSE_INLINE int compare_octets (
|
||||||
const qse_htoc_t* s1, qse_size_t len1,
|
const qse_mchar_t* s1, qse_size_t len1,
|
||||||
const qse_htoc_t* s2, qse_size_t len2)
|
const qse_mchar_t* s2, qse_size_t len2)
|
||||||
{
|
{
|
||||||
qse_char_t c1, c2;
|
qse_char_t c1, c2;
|
||||||
const qse_htoc_t* end1 = s1 + len1;
|
const qse_mchar_t* end1 = s1 + len1;
|
||||||
const qse_htoc_t* end2 = s2 + len2;
|
const qse_mchar_t* end2 = s2 + len2;
|
||||||
|
|
||||||
while (s1 < end1)
|
while (s1 < end1)
|
||||||
{
|
{
|
||||||
@ -487,7 +487,7 @@ static QSE_INLINE int capture_content_length (
|
|||||||
qse_htrd_t* htrd, qse_htb_pair_t* pair)
|
qse_htrd_t* htrd, qse_htb_pair_t* pair)
|
||||||
{
|
{
|
||||||
qse_size_t len = 0, off = 0, tmp;
|
qse_size_t len = 0, off = 0, tmp;
|
||||||
const qse_htoc_t* ptr = QSE_HTB_VPTR(pair);
|
const qse_mchar_t* ptr = QSE_HTB_VPTR(pair);
|
||||||
|
|
||||||
while (off < QSE_HTB_VLEN(pair))
|
while (off < QSE_HTB_VLEN(pair))
|
||||||
{
|
{
|
||||||
@ -577,7 +577,7 @@ static QSE_INLINE int capture_key_header (
|
|||||||
{
|
{
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
const qse_htoc_t* ptr;
|
const qse_mchar_t* ptr;
|
||||||
qse_size_t len;
|
qse_size_t len;
|
||||||
int (*handler) (qse_htrd_t*, qse_htb_pair_t*);
|
int (*handler) (qse_htrd_t*, qse_htb_pair_t*);
|
||||||
} hdrtab[] =
|
} hdrtab[] =
|
||||||
@ -653,7 +653,7 @@ static qse_htb_pair_t* hdr_cbserter (
|
|||||||
/* the key exists. let's combine values, each separated
|
/* the key exists. let's combine values, each separated
|
||||||
* by a comma */
|
* by a comma */
|
||||||
struct hdr_cmb_t* cmb;
|
struct hdr_cmb_t* cmb;
|
||||||
qse_htoc_t* ptr;
|
qse_mchar_t* ptr;
|
||||||
qse_size_t len;
|
qse_size_t len;
|
||||||
|
|
||||||
/* TODO: reduce waste in case the same key appears again.
|
/* TODO: reduce waste in case the same key appears again.
|
||||||
@ -671,7 +671,7 @@ static qse_htb_pair_t* hdr_cbserter (
|
|||||||
cmb = (struct hdr_cmb_t*) QSE_MMGR_ALLOC (
|
cmb = (struct hdr_cmb_t*) QSE_MMGR_ALLOC (
|
||||||
tx->htrd->mmgr,
|
tx->htrd->mmgr,
|
||||||
QSE_SIZEOF(*cmb) +
|
QSE_SIZEOF(*cmb) +
|
||||||
QSE_SIZEOF(qse_htoc_t) * (QSE_HTB_VLEN(pair) + 1 + tx->vlen + 1)
|
QSE_SIZEOF(qse_mchar_t) * (QSE_HTB_VLEN(pair) + 1 + tx->vlen + 1)
|
||||||
);
|
);
|
||||||
if (cmb == QSE_NULL)
|
if (cmb == QSE_NULL)
|
||||||
{
|
{
|
||||||
@ -680,7 +680,7 @@ static qse_htb_pair_t* hdr_cbserter (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* let 'ptr' point to the actual space for the combined value */
|
/* let 'ptr' point to the actual space for the combined value */
|
||||||
ptr = (qse_htoc_t*)(cmb + 1);
|
ptr = (qse_mchar_t*)(cmb + 1);
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
/* fill the space with the value */
|
/* fill the space with the value */
|
||||||
@ -724,12 +724,12 @@ Change it to doubly linked for this?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_htoc_t* parse_header_fields (qse_htrd_t* htrd, qse_htoc_t* line)
|
qse_mchar_t* parse_header_fields (qse_htrd_t* htrd, qse_mchar_t* line)
|
||||||
{
|
{
|
||||||
qse_htoc_t* p = line, * last;
|
qse_mchar_t* p = line, * last;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_htoc_t* ptr;
|
qse_mchar_t* ptr;
|
||||||
qse_size_t len;
|
qse_size_t len;
|
||||||
} name, value;
|
} name, value;
|
||||||
|
|
||||||
@ -767,7 +767,7 @@ qse_htoc_t* parse_header_fields (qse_htrd_t* htrd, qse_htoc_t* line)
|
|||||||
* the continuation */
|
* the continuation */
|
||||||
if (is_purespace_octet (*++p))
|
if (is_purespace_octet (*++p))
|
||||||
{
|
{
|
||||||
qse_htoc_t* cpydst;
|
qse_mchar_t* cpydst;
|
||||||
|
|
||||||
cpydst = p - 1;
|
cpydst = p - 1;
|
||||||
if (*(cpydst-1) == '\r') cpydst--;
|
if (*(cpydst-1) == '\r') cpydst--;
|
||||||
@ -817,9 +817,9 @@ badhdr:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE int parse_initial_line_and_headers (
|
static QSE_INLINE int parse_initial_line_and_headers (
|
||||||
qse_htrd_t* htrd, const qse_htoc_t* req, qse_size_t rlen)
|
qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t rlen)
|
||||||
{
|
{
|
||||||
qse_htoc_t* p;
|
qse_mchar_t* p;
|
||||||
|
|
||||||
/* add the actual request */
|
/* add the actual request */
|
||||||
if (push_to_buffer (htrd, &htrd->fed.b.raw, req, rlen) <= -1) return -1;
|
if (push_to_buffer (htrd, &htrd->fed.b.raw, req, rlen) <= -1) return -1;
|
||||||
@ -864,9 +864,9 @@ static QSE_INLINE int parse_initial_line_and_headers (
|
|||||||
#define GET_CHUNK_CRLF 3
|
#define GET_CHUNK_CRLF 3
|
||||||
#define GET_CHUNK_TRAILERS 4
|
#define GET_CHUNK_TRAILERS 4
|
||||||
|
|
||||||
static const qse_htoc_t* getchunklen (qse_htrd_t* htrd, const qse_htoc_t* ptr, qse_size_t len)
|
static const qse_mchar_t* getchunklen (qse_htrd_t* htrd, const qse_mchar_t* ptr, qse_size_t len)
|
||||||
{
|
{
|
||||||
const qse_htoc_t* end = ptr + len;
|
const qse_mchar_t* end = ptr + len;
|
||||||
|
|
||||||
/* this function must be called in the GET_CHUNK_LEN context */
|
/* this function must be called in the GET_CHUNK_LEN context */
|
||||||
QSE_ASSERT (htrd->fed.s.chunk.phase == GET_CHUNK_LEN);
|
QSE_ASSERT (htrd->fed.s.chunk.phase == GET_CHUNK_LEN);
|
||||||
@ -932,14 +932,14 @@ static const qse_htoc_t* getchunklen (qse_htrd_t* htrd, const qse_htoc_t* ptr, q
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const qse_htoc_t* get_trailing_headers (
|
static const qse_mchar_t* get_trailing_headers (
|
||||||
qse_htrd_t* htrd, const qse_htoc_t* req, const qse_htoc_t* end)
|
qse_htrd_t* htrd, const qse_mchar_t* req, const qse_mchar_t* end)
|
||||||
{
|
{
|
||||||
const qse_htoc_t* ptr = req;
|
const qse_mchar_t* ptr = req;
|
||||||
|
|
||||||
while (ptr < end)
|
while (ptr < end)
|
||||||
{
|
{
|
||||||
register qse_htoc_t b = *ptr++;
|
register qse_mchar_t b = *ptr++;
|
||||||
|
|
||||||
switch (b)
|
switch (b)
|
||||||
{
|
{
|
||||||
@ -957,7 +957,7 @@ static const qse_htoc_t* get_trailing_headers (
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_htoc_t* p;
|
qse_mchar_t* p;
|
||||||
|
|
||||||
QSE_ASSERT (htrd->fed.s.crlf <= 3);
|
QSE_ASSERT (htrd->fed.s.crlf <= 3);
|
||||||
htrd->fed.s.crlf = 0;
|
htrd->fed.s.crlf = 0;
|
||||||
@ -1008,10 +1008,10 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* feed the percent encoded string */
|
/* feed the percent encoded string */
|
||||||
int qse_htrd_feed (qse_htrd_t* htrd, const qse_htoc_t* req, qse_size_t len)
|
int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||||
{
|
{
|
||||||
const qse_htoc_t* end = req + len;
|
const qse_mchar_t* end = req + len;
|
||||||
const qse_htoc_t* ptr = req;
|
const qse_mchar_t* ptr = req;
|
||||||
|
|
||||||
/* does this goto drop code maintainability? */
|
/* does this goto drop code maintainability? */
|
||||||
if (htrd->fed.s.need > 0)
|
if (htrd->fed.s.need > 0)
|
||||||
@ -1041,7 +1041,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_htoc_t* req, qse_size_t len)
|
|||||||
|
|
||||||
while (ptr < end)
|
while (ptr < end)
|
||||||
{
|
{
|
||||||
register qse_htoc_t b = *ptr++;
|
register qse_mchar_t b = *ptr++;
|
||||||
|
|
||||||
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES &&
|
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES &&
|
||||||
htrd->fed.s.plen <= 0 && is_whspace_octet(b))
|
htrd->fed.s.plen <= 0 && is_whspace_octet(b))
|
||||||
@ -1310,8 +1310,8 @@ feedme_more:
|
|||||||
int qse_htrd_scanqparam (qse_htrd_t* htrd, const qse_mcstr_t* cstr)
|
int qse_htrd_scanqparam (qse_htrd_t* htrd, const qse_mcstr_t* cstr)
|
||||||
{
|
{
|
||||||
qse_mcstr_t key, val;
|
qse_mcstr_t key, val;
|
||||||
const qse_htoc_t* p, * end;
|
const qse_mchar_t* p, * end;
|
||||||
qse_htoc_t* out;
|
qse_mchar_t* out;
|
||||||
|
|
||||||
if (cstr == QSE_NULL) cstr = qse_htre_getqparamcstr(&htrd->re);
|
if (cstr == QSE_NULL) cstr = qse_htre_getqparamcstr(&htrd->re);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ const qse_mchar_t* qse_htre_gethdrval (
|
|||||||
{
|
{
|
||||||
qse_htb_pair_t* pair;
|
qse_htb_pair_t* pair;
|
||||||
pair = qse_htb_search (&re->hdrtab, name, qse_mbslen(name));
|
pair = qse_htb_search (&re->hdrtab, name, qse_mbslen(name));
|
||||||
if (pair == QSE_NULL) return pair;
|
if (pair == QSE_NULL) return QSE_NULL;
|
||||||
return QSE_HTB_VPTR(pair);
|
return QSE_HTB_VPTR(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
|||||||
* like bytes=1-20,30-50 */
|
* like bytes=1-20,30-50 */
|
||||||
|
|
||||||
qse_http_range_int_t from, to;
|
qse_http_range_int_t from, to;
|
||||||
int suffix = 0;
|
int type = QSE_HTTP_RANGE_PROPER;
|
||||||
|
|
||||||
if (str[0] != QSE_MT('b') ||
|
if (str[0] != QSE_MT('b') ||
|
||||||
str[1] != QSE_MT('y') ||
|
str[1] != QSE_MT('y') ||
|
||||||
@ -163,7 +163,7 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
|||||||
}
|
}
|
||||||
while (QSE_ISDIGIT(*str));
|
while (QSE_ISDIGIT(*str));
|
||||||
}
|
}
|
||||||
else suffix = 1;
|
else type = QSE_HTTP_RANGE_SUFFIX;
|
||||||
|
|
||||||
if (*str != QSE_MT('-')) return -1;
|
if (*str != QSE_MT('-')) return -1;
|
||||||
str++;
|
str++;
|
||||||
@ -182,7 +182,7 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
|||||||
|
|
||||||
if (from > to) return -1;
|
if (from > to) return -1;
|
||||||
|
|
||||||
range->suffix = suffix;
|
range->type = type;
|
||||||
range->from = from;
|
range->from = from;
|
||||||
range->to = to;
|
range->to = to;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -778,7 +778,7 @@ static int make_fd_set_from_client_array (qse_httpd_t* httpd, fd_set* r, fd_set*
|
|||||||
{
|
{
|
||||||
if (ca->data[fd].htrd)
|
if (ca->data[fd].htrd)
|
||||||
{
|
{
|
||||||
if (r)
|
if (r && !ca->data[fd].bad)
|
||||||
{
|
{
|
||||||
FD_SET (ca->data[fd].handle.i, r);
|
FD_SET (ca->data[fd].handle.i, r);
|
||||||
if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
|
if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
|
||||||
@ -860,7 +860,10 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %S\n"), strerro
|
|||||||
/* break; */
|
/* break; */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (n == 0) continue;
|
if (n == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
||||||
{
|
{
|
||||||
@ -873,9 +876,15 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %S\n"), strerro
|
|||||||
if (client->bad)
|
if (client->bad)
|
||||||
{
|
{
|
||||||
/*send (client->handle, i, "INTERNAL SERVER ERROR..", ...);*/
|
/*send (client->handle, i, "INTERNAL SERVER ERROR..", ...);*/
|
||||||
shutdown (client->handle.i, 0);
|
/*shutdown (client->handle.i, 0);*/
|
||||||
|
pthread_mutex_lock (&httpd->client.mutex);
|
||||||
|
delete_from_client_array (httpd, fd);
|
||||||
|
pthread_mutex_unlock (&httpd->client.mutex);
|
||||||
|
}
|
||||||
|
else if (client->task.queue.count > 0)
|
||||||
|
{
|
||||||
|
perform_task (httpd, client);
|
||||||
}
|
}
|
||||||
else if (client->task.queue.count > 0) perform_task (httpd, client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -887,7 +896,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %S\n"), strerro
|
|||||||
|
|
||||||
static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||||
{
|
{
|
||||||
qse_htoc_t buf[1024];
|
qse_mchar_t buf[1024];
|
||||||
qse_ssize_t m;
|
qse_ssize_t m;
|
||||||
|
|
||||||
reread:
|
reread:
|
||||||
@ -974,7 +983,10 @@ int qse_httpd_loop (qse_httpd_t* httpd)
|
|||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock (&httpd->client.mutex);
|
||||||
max = make_fd_set_from_client_array (httpd, &r, QSE_NULL);
|
max = make_fd_set_from_client_array (httpd, &r, QSE_NULL);
|
||||||
|
pthread_mutex_unlock (&httpd->client.mutex);
|
||||||
|
|
||||||
n = select (max + 1, &r, NULL, NULL, &tv);
|
n = select (max + 1, &r, NULL, NULL, &tv);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
@ -1002,9 +1014,13 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
|||||||
/* got input */
|
/* got input */
|
||||||
if (read_from_client (httpd, client) <= -1)
|
if (read_from_client (httpd, client) <= -1)
|
||||||
{
|
{
|
||||||
|
qse_httpd_markclientbad (httpd, client);
|
||||||
|
shutdown (client->handle.i, 0);
|
||||||
|
#if 0
|
||||||
pthread_mutex_lock (&httpd->client.mutex);
|
pthread_mutex_lock (&httpd->client.mutex);
|
||||||
delete_from_client_array (httpd, fd);
|
delete_from_client_array (httpd, fd);
|
||||||
pthread_mutex_unlock (&httpd->client.mutex);
|
pthread_mutex_unlock (&httpd->client.mutex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,17 +56,17 @@ int qse_httpd_entaskdisconnect (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef struct task_sendtext_t task_sendtext_t;
|
typedef struct task_text_t task_text_t;
|
||||||
struct task_sendtext_t
|
struct task_text_t
|
||||||
{
|
{
|
||||||
const qse_mchar_t* ptr;
|
const qse_mchar_t* ptr;
|
||||||
qse_size_t left;
|
qse_size_t left;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int httpd_init_sendtext (
|
static int task_init_text (
|
||||||
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_sendtext_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
task_text_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||||
|
|
||||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||||
QSE_MEMCPY (xtn + 1, xtn->ptr, xtn->left);
|
QSE_MEMCPY (xtn + 1, xtn->ptr, xtn->left);
|
||||||
@ -76,12 +76,12 @@ static int httpd_init_sendtext (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int httpd_main_sendtext (
|
static int task_main_text (
|
||||||
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)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
size_t count;
|
size_t count;
|
||||||
task_sendtext_t* ctx = (task_sendtext_t*)task->ctx;
|
task_text_t* ctx = (task_text_t*)task->ctx;
|
||||||
|
|
||||||
count = MAX_SENDFILE_SIZE;
|
count = MAX_SENDFILE_SIZE;
|
||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
@ -102,19 +102,19 @@ static int httpd_main_sendtext (
|
|||||||
return 1; /* more work to do */
|
return 1; /* more work to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
int qse_httpd_entasksendtext (
|
int qse_httpd_entasktext (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text)
|
||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
task_sendtext_t data;
|
task_text_t data;
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
data.ptr = text;
|
data.ptr = text;
|
||||||
data.left = qse_mbslen(text);
|
data.left = qse_mbslen(text);
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
task.init = httpd_init_sendtext;
|
task.init = task_init_text;
|
||||||
task.main = httpd_main_sendtext;
|
task.main = task_main_text;
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (
|
return qse_httpd_entask (
|
||||||
@ -127,37 +127,37 @@ int qse_httpd_entasksendtext (
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef struct task_sendfmt_t task_sendfmt_t;
|
typedef struct task_format_t task_format_t;
|
||||||
struct task_sendfmt_t
|
struct task_format_t
|
||||||
{
|
{
|
||||||
qse_mchar_t* org;
|
qse_mchar_t* org;
|
||||||
const qse_mchar_t* ptr;
|
const qse_mchar_t* ptr;
|
||||||
qse_size_t left;
|
qse_size_t left;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int httpd_init_sendfmt (
|
static int task_init_format (
|
||||||
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_sendfmt_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
task_format_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||||
|
|
||||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||||
task->ctx = xtn;
|
task->ctx = xtn;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void httpd_fini_sendfmt (
|
static void task_fini_format (
|
||||||
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_sendfmt_t* ctx = (task_sendfmt_t*)task->ctx;
|
task_format_t* ctx = (task_format_t*)task->ctx;
|
||||||
qse_httpd_freemem (httpd, ctx->org);
|
qse_httpd_freemem (httpd, ctx->org);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int httpd_main_sendfmt (
|
static int task_main_format (
|
||||||
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)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
size_t count;
|
size_t count;
|
||||||
task_sendfmt_t* ctx = (task_sendfmt_t*)task->ctx;
|
task_format_t* ctx = (task_format_t*)task->ctx;
|
||||||
|
|
||||||
count = MAX_SENDFILE_SIZE;
|
count = MAX_SENDFILE_SIZE;
|
||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
@ -178,11 +178,11 @@ static int httpd_main_sendfmt (
|
|||||||
return 1; /* more work to do */
|
return 1; /* more work to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
int qse_httpd_entasksendfmt (
|
int qse_httpd_entaskformat (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* fmt, ...)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* fmt, ...)
|
||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
task_sendfmt_t data;
|
task_format_t data;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
qse_mchar_t n[2];
|
qse_mchar_t n[2];
|
||||||
@ -259,9 +259,9 @@ int qse_httpd_entasksendfmt (
|
|||||||
data.left = l;
|
data.left = l;
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
task.init = httpd_init_sendfmt;
|
task.init = task_init_format;
|
||||||
task.fini = httpd_fini_sendfmt;
|
task.fini = task_fini_format;
|
||||||
task.main = httpd_main_sendfmt;
|
task.main = task_main_format;
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (
|
return qse_httpd_entask (
|
||||||
@ -272,53 +272,58 @@ int qse_httpd_entasksendfmt (
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef struct httpd_task_sendfile_t httpd_task_sendfile_t;
|
typedef struct task_file_t task_file_t;
|
||||||
struct httpd_task_sendfile_t
|
struct task_file_t
|
||||||
{
|
{
|
||||||
int fd;
|
qse_ubi_t handle;
|
||||||
qse_foff_t left;
|
qse_foff_t left;
|
||||||
qse_foff_t offset;
|
qse_foff_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int httpd_init_sendfile (
|
static int task_init_file (
|
||||||
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_task_sendfile_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
task_file_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||||
task->ctx = xtn;
|
task->ctx = xtn;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void httpd_fini_sendfile (
|
static void task_fini_file (
|
||||||
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_task_sendfile_t* ctx = (httpd_task_sendfile_t*)task->ctx;
|
task_file_t* ctx = (task_file_t*)task->ctx;
|
||||||
close (ctx->fd);
|
close (ctx->handle.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int httpd_main_sendfile (
|
static int task_main_file (
|
||||||
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)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
size_t count;
|
size_t count;
|
||||||
httpd_task_sendfile_t* ctx = (httpd_task_sendfile_t*)task->ctx;
|
task_file_t* ctx = (task_file_t*)task->ctx;
|
||||||
|
|
||||||
count = MAX_SENDFILE_SIZE;
|
count = MAX_SENDFILE_SIZE;
|
||||||
if (count >= ctx->left) count = ctx->left;
|
if (count >= ctx->left) count = ctx->left;
|
||||||
|
|
||||||
|
/* TODO: more adjustment needed for OS with different sendfile semantics... */
|
||||||
n = sendfile (
|
n = sendfile (
|
||||||
client->handle.i,
|
client->handle.i,
|
||||||
ctx->fd,
|
ctx->handle.i,
|
||||||
&ctx->offset,
|
&ctx->offset,
|
||||||
count
|
count
|
||||||
);
|
);
|
||||||
|
|
||||||
if (n <= -1) return -1;
|
if (n <= -1) return -1; /* TODO: any logging */
|
||||||
|
|
||||||
if (n == 0 && count > 0)
|
if (n == 0 && count > 0)
|
||||||
{
|
{
|
||||||
/* TODO: .... */
|
/* The file could be truncated when this condition is set.
|
||||||
/* anything to do in this case? can this happen if the file has been truncated during transfer.... */
|
* The content-length sent in the header can't be fulfilled.
|
||||||
|
* So let's return an error here so that the main loop abort
|
||||||
|
* the connection. */
|
||||||
|
/* TODO: any logging....??? */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->left -= n;
|
ctx->left -= n;
|
||||||
@ -327,22 +332,22 @@ static int httpd_main_sendfile (
|
|||||||
return 1; /* more work to do */
|
return 1; /* more work to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
int qse_httpd_entasksendfile (
|
int qse_httpd_entaskfile (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
int fd, qse_foff_t offset, qse_foff_t size)
|
qse_ubi_t handle, qse_foff_t offset, qse_foff_t size)
|
||||||
{
|
{
|
||||||
qse_httpd_task_t task;
|
qse_httpd_task_t task;
|
||||||
httpd_task_sendfile_t data;
|
task_file_t data;
|
||||||
|
|
||||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
data.fd = fd;
|
data.handle = handle;
|
||||||
data.offset = offset;
|
data.offset = offset;
|
||||||
data.left = size;
|
data.left = size;
|
||||||
|
|
||||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
task.init = httpd_init_sendfile;
|
task.init = task_init_file;
|
||||||
task.main = httpd_main_sendfile;
|
task.main = task_main_file;
|
||||||
task.fini = httpd_fini_sendfile;
|
task.fini = task_fini_file;
|
||||||
task.ctx = &data;
|
task.ctx = &data;
|
||||||
|
|
||||||
return qse_httpd_entask (httpd, client, &task, QSE_SIZEOF(data));
|
return qse_httpd_entask (httpd, client, &task, QSE_SIZEOF(data));
|
||||||
@ -350,6 +355,156 @@ int qse_httpd_entasksendfile (
|
|||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
typedef struct task_path_t task_path_t;
|
||||||
|
struct task_path_t
|
||||||
|
{
|
||||||
|
const qse_mchar_t* name;
|
||||||
|
qse_http_range_t range;
|
||||||
|
qse_http_version_t version;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int task_init_path (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
|
{
|
||||||
|
task_path_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||||
|
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||||
|
qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->name);
|
||||||
|
xtn->name = (qse_mchar_t*)(xtn + 1);
|
||||||
|
task->ctx = xtn;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int task_main_path (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||||
|
{
|
||||||
|
task_path_t* data = (task_path_t*)task->ctx;
|
||||||
|
qse_ubi_t handle;
|
||||||
|
struct stat st;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
handle.i = open (data->name, O_RDONLY);
|
||||||
|
if (handle.i <= -1)
|
||||||
|
{
|
||||||
|
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
|
||||||
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||||
|
data->version.major, data->version.minor,
|
||||||
|
(int)qse_mbslen(msg) + 4, msg
|
||||||
|
);
|
||||||
|
if (x <= -1) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat (handle.i, &st) <= -1)
|
||||||
|
{
|
||||||
|
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
|
||||||
|
|
||||||
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||||
|
data->version.major, data->version.minor,
|
||||||
|
(int)qse_mbslen(msg) + 4, msg
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.st_size < 0) st.st_size = 0; /* can this happen? */
|
||||||
|
|
||||||
|
if (data->range.type != QSE_HTTP_RANGE_NONE)
|
||||||
|
{
|
||||||
|
if (data->range.type == QSE_HTTP_RANGE_SUFFIX)
|
||||||
|
{
|
||||||
|
if (data->range.to > st.st_size) data->range.to = st.st_size;
|
||||||
|
data->range.from = st.st_size - data->range.to;
|
||||||
|
data->range.to = data->range.to + data->range.from;
|
||||||
|
if (st.st_size > 0) data->range.to--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->range.from >= st.st_size)
|
||||||
|
{
|
||||||
|
const qse_mchar_t* msg;
|
||||||
|
|
||||||
|
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
|
||||||
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||||
|
data->version.major, data->version.minor,
|
||||||
|
(int)qse_mbslen(msg) + 4, msg
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->range.to >= st.st_size) data->range.to = st.st_size - 1;
|
||||||
|
|
||||||
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 206 Partial content\r\nContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
|
||||||
|
data->version.major,
|
||||||
|
data->version.minor,
|
||||||
|
(unsigned long long)(data->range.to - data->range.from + 1),
|
||||||
|
data->name,
|
||||||
|
(unsigned long long)data->range.from,
|
||||||
|
(unsigned long long)data->range.to,
|
||||||
|
st.st_size
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
|
||||||
|
x = qse_httpd_entaskfile (
|
||||||
|
httpd, client, handle,
|
||||||
|
data->range.from,
|
||||||
|
(data->range.to - data->range.from + 1)
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: int64 format.... don't hard code it llu */
|
||||||
|
|
||||||
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"),
|
||||||
|
data->version.major,
|
||||||
|
data->version.minor,
|
||||||
|
(unsigned long long)st.st_size,
|
||||||
|
data->name
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
|
||||||
|
x = qse_httpd_entaskfile (httpd, client, handle, 0, st.st_size);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
oops:
|
||||||
|
close (handle.i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qse_httpd_entaskpath (
|
||||||
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
|
const qse_mchar_t* name, const qse_http_range_t* range,
|
||||||
|
const qse_http_version_t* verison)
|
||||||
|
{
|
||||||
|
qse_httpd_task_t task;
|
||||||
|
task_path_t data;
|
||||||
|
|
||||||
|
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||||
|
data.name = name;
|
||||||
|
if (range) data.range = *range;
|
||||||
|
else data.range.type = QSE_HTTP_RANGE_NONE;
|
||||||
|
data.version = *verison;
|
||||||
|
|
||||||
|
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||||
|
task.init = task_init_path;
|
||||||
|
task.main = task_main_path;
|
||||||
|
task.ctx = &data;
|
||||||
|
|
||||||
|
return qse_httpd_entask (httpd, client, &task,
|
||||||
|
QSE_SIZEOF(task_path_t) + qse_mbslen(name) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
typedef struct httpd_task_cgi_t httpd_task_cgi_t;
|
typedef struct httpd_task_cgi_t httpd_task_cgi_t;
|
||||||
struct httpd_task_cgi_t
|
struct httpd_task_cgi_t
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -23,18 +22,6 @@ qse_printf (QSE_T("HEADER OK %d[%S] %d[%S]\n"), (int)QSE_HTB_KLEN(pair), QSE_HT
|
|||||||
return QSE_HTB_WALK_FORWARD;
|
return QSE_HTB_WALK_FORWARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int range_not_satisfiable (qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_htre_t* req)
|
|
||||||
{
|
|
||||||
const qse_mchar_t* msg;
|
|
||||||
|
|
||||||
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
|
|
||||||
return qse_httpd_entasksendfmt (httpd, client,
|
|
||||||
QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
|
||||||
req->version.major, req->version.minor,
|
|
||||||
(int)qse_mbslen(msg) + 4, msg
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_request (
|
static int handle_request (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||||
{
|
{
|
||||||
@ -69,112 +56,35 @@ qse_printf (QSE_T("content = [%.*S]\n"),
|
|||||||
|
|
||||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||||
{
|
{
|
||||||
int fd;
|
const qse_mchar_t* rangestr;
|
||||||
|
qse_http_range_t range;
|
||||||
|
int x;
|
||||||
|
|
||||||
fd = open (qse_htre_getqpathptr(req), O_RDONLY);
|
rangestr = qse_htre_gethdrval (req, "Range");
|
||||||
if (fd <= -1)
|
if (rangestr && qse_parsehttprange (rangestr, &range) <= -1)
|
||||||
{
|
{
|
||||||
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
|
const qse_mchar_t* msg;
|
||||||
if (qse_httpd_entasksendfmt (httpd, client,
|
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
|
||||||
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
x = qse_httpd_entaskformat (httpd, client,
|
||||||
|
QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||||
req->version.major, req->version.minor,
|
req->version.major, req->version.minor,
|
||||||
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops;
|
(int)qse_mbslen(msg) + 4, msg
|
||||||
|
);
|
||||||
|
if (x <= -1) goto oops;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
if (fstat (fd, &st) <= -1)
|
|
||||||
{
|
|
||||||
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
|
|
||||||
|
|
||||||
close (fd);
|
x = qse_httpd_entaskpath (
|
||||||
if (qse_httpd_entasksendfmt (httpd, client,
|
httpd, client,
|
||||||
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
qse_htre_getqpathptr(req),
|
||||||
req->version.major, req->version.minor,
|
(rangestr? &range: QSE_NULL),
|
||||||
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops;
|
qse_htre_getversion(req)
|
||||||
}
|
);
|
||||||
else
|
if (x <= -1) goto oops;
|
||||||
{
|
|
||||||
const qse_mchar_t* rangestr;
|
|
||||||
qse_http_range_t range;
|
|
||||||
if (st.st_size <= 0) st.st_size = 0;
|
|
||||||
|
|
||||||
rangestr = qse_htre_gethdrval (req, "Range");
|
|
||||||
if (rangestr)
|
|
||||||
{
|
|
||||||
if (qse_parsehttprange (rangestr, &range) <= -1)
|
|
||||||
{
|
|
||||||
if (range_not_satisfiable (httpd, client, req) <= -1) goto oops;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (range.suffix)
|
|
||||||
{
|
|
||||||
if (range.to > st.st_size) range.to = st.st_size;
|
|
||||||
range.from = st.st_size - range.to;
|
|
||||||
range.to = range.to + range.from;
|
|
||||||
if (st.st_size > 0) range.to--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (range.from >= st.st_size)
|
|
||||||
{
|
|
||||||
if (range_not_satisfiable (httpd, client, req) <= -1) goto oops;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (range.to >= st.st_size) range.to = st.st_size - 1;
|
|
||||||
|
|
||||||
if (qse_httpd_entasksendfmt (httpd, client,
|
|
||||||
QSE_MT("HTTP/%d.%d 206 Partial content\r\nContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
|
|
||||||
qse_htre_getmajorversion(req),
|
|
||||||
qse_htre_getminorversion(req),
|
|
||||||
(unsigned long long)(range.to - range.from + 1),
|
|
||||||
qse_htre_getqpathptr(req),
|
|
||||||
(unsigned long long)range.from,
|
|
||||||
(unsigned long long)range.to,
|
|
||||||
st.st_size) <= -1)
|
|
||||||
{
|
|
||||||
close (fd);
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qse_httpd_entasksendfile (httpd, client, fd, range.from, (range.to - range.from + 1)) <= -1)
|
|
||||||
{
|
|
||||||
close (fd);
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* TODO: int64 format.... don't hard code it llu */
|
|
||||||
if (qse_httpd_entasksendfmt (httpd, client,
|
|
||||||
QSE_MT("HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"),
|
|
||||||
qse_htre_getmajorversion(req),
|
|
||||||
qse_htre_getminorversion(req),
|
|
||||||
(unsigned long long)st.st_size,
|
|
||||||
qse_htre_getqpathptr(req)) <= -1)
|
|
||||||
{
|
|
||||||
close (fd);
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qse_httpd_entasksendfile (httpd, client, fd, 0, st.st_size) <= -1)
|
|
||||||
{
|
|
||||||
close (fd);
|
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const qse_mchar_t* msg = QSE_MT("<html><head><title>Method not allowed</title></head><body><b>REQUEST METHOD NOT ALLOWED</b></body></html>");
|
const qse_mchar_t* msg = QSE_MT("<html><head><title>Method not allowed</title></head><body><b>REQUEST METHOD NOT ALLOWED</b></body></html>");
|
||||||
if (qse_httpd_entasksendfmt (httpd, client,
|
if (qse_httpd_entaskformat (httpd, client,
|
||||||
QSE_MT("HTTP/%d.%d 405 Method not allowed\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
QSE_MT("HTTP/%d.%d 405 Method not allowed\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||||
req->version.major, req->version.minor,
|
req->version.major, req->version.minor,
|
||||||
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops;
|
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user