added qse_httpd_entaskpath().

renames qse_httpd_entaskXXX() functions to a newer style
This commit is contained in:
hyung-hwan 2011-07-28 08:35:28 +00:00
parent 79370202bc
commit f4ad3e3b66
9 changed files with 357 additions and 232 deletions

View File

@ -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 (

View File

@ -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
); );

View File

@ -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

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;

View File

@ -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
} }
} }
} }

View File

@ -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

View File

@ -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;