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.
|
||||
*/
|
||||
int qse_htrd_feed (
|
||||
qse_htrd_t* htrd, /**< htrd */
|
||||
const qse_htoc_t* req, /**< request octets */
|
||||
qse_size_t len /**< number of octets */
|
||||
qse_htrd_t* htrd, /**< htrd */
|
||||
const qse_mchar_t* req, /**< request octets */
|
||||
qse_size_t len /**< number of octets */
|
||||
);
|
||||
|
||||
int qse_htrd_read (
|
||||
|
@ -31,8 +31,6 @@
|
||||
#include <qse/cmn/htb.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
typedef qse_mchar_t qse_htoc_t;
|
||||
|
||||
/* octet buffer */
|
||||
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;
|
||||
#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
|
||||
* 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.
|
||||
* - -500 => last 500 bytes
|
||||
*
|
||||
@ -95,16 +102,17 @@ typedef qse_ulong_t qse_http_range_int_t;
|
||||
* range.to = range.to + range.from - 1;
|
||||
* @endcode
|
||||
*
|
||||
* If suffix is zero, 'from' and 'to' represents a proper range where
|
||||
* the value of 0 indicates the first byte. This doesn't require any adjustment.
|
||||
* If type is #QSE_HTTP_RANGE_PROPER, 'from' and 'to' represents a proper range
|
||||
* where the value of 0 indicates the first byte. This doesn't require any
|
||||
* adjustment.
|
||||
* - 0-999 => first 1000 bytes
|
||||
* - 99- => from the 100th bytes to the end.
|
||||
*/
|
||||
struct qse_http_range_t
|
||||
{
|
||||
int suffix; /**< suffix indicator */
|
||||
qse_http_range_int_t from; /**< starting offset */
|
||||
qse_http_range_int_t to; /**< ending offset */
|
||||
qse_http_range_type_t type; /**< type indicator */
|
||||
qse_http_range_int_t from; /**< starting offset */
|
||||
qse_http_range_int_t to; /**< ending offset */
|
||||
};
|
||||
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" {
|
||||
#endif
|
||||
|
||||
const qse_htoc_t* qse_gethttpmethodname (
|
||||
const qse_mchar_t* qse_gethttpmethodname (
|
||||
qse_http_method_t type
|
||||
);
|
||||
|
||||
int qse_gethttpmethodtype (
|
||||
const qse_htoc_t* name,
|
||||
const qse_mchar_t* name,
|
||||
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;
|
||||
struct qse_httpd_cbs_t
|
||||
{
|
||||
int (*handle_request) (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);
|
||||
int (*handle_request) (
|
||||
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 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
|
||||
{
|
||||
int (*init) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
||||
void (*fini) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
||||
int (*main) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
||||
/* you must not call another entask functions from within initailizer */
|
||||
qse_httpd_task_init_t init;
|
||||
qse_httpd_task_fini_t fini;
|
||||
qse_httpd_task_main_t main;
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
@ -106,6 +128,12 @@ int qse_httpd_addlisteners (
|
||||
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))
|
||||
|
||||
int qse_httpd_entask (
|
||||
@ -115,27 +143,35 @@ int qse_httpd_entask (
|
||||
qse_size_t xtnsize
|
||||
);
|
||||
|
||||
int qse_httpd_entasksendtext (
|
||||
int qse_httpd_entasktext (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
const qse_mchar_t* text
|
||||
);
|
||||
|
||||
int qse_httpd_entasksendfmt (
|
||||
int qse_httpd_entaskformat (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
const qse_mchar_t* fmt,
|
||||
...
|
||||
);
|
||||
|
||||
int qse_httpd_entasksendfile (
|
||||
int qse_httpd_entaskfile (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
int fd,
|
||||
qse_ubi_t handle,
|
||||
qse_foff_t offset,
|
||||
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 (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client
|
||||
|
@ -24,58 +24,58 @@
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
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') ||
|
||||
(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';
|
||||
}
|
||||
|
||||
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') ||
|
||||
(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';
|
||||
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 >= '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 (
|
||||
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)
|
||||
{
|
||||
@ -198,10 +198,10 @@ void qse_htrd_fini (qse_htrd_t* htrd)
|
||||
qse_mbs_fini (&htrd->tmp.qparam);
|
||||
}
|
||||
|
||||
static qse_htoc_t* parse_initial_line (
|
||||
qse_htrd_t* htrd, qse_htoc_t* line)
|
||||
static qse_mchar_t* parse_initial_line (
|
||||
qse_htrd_t* htrd, qse_mchar_t* line)
|
||||
{
|
||||
qse_htoc_t* p = line;
|
||||
qse_mchar_t* p = line;
|
||||
qse_mcstr_t tmp;
|
||||
qse_http_method_t mtype;
|
||||
|
||||
@ -225,7 +225,7 @@ static qse_htoc_t* parse_initial_line (
|
||||
qse_htre_setqmethod (&htrd->re, mtype);
|
||||
}
|
||||
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 */
|
||||
htrd->retype = QSE_HTRD_RETYPE_S;
|
||||
@ -290,7 +290,7 @@ static qse_htoc_t* parse_initial_line (
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_htoc_t* out;
|
||||
qse_mchar_t* out;
|
||||
qse_mcstr_t param;
|
||||
|
||||
/* 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))
|
||||
|
||||
static QSE_INLINE int compare_octets (
|
||||
const qse_htoc_t* s1, qse_size_t len1,
|
||||
const qse_htoc_t* s2, qse_size_t len2)
|
||||
const qse_mchar_t* s1, qse_size_t len1,
|
||||
const qse_mchar_t* s2, qse_size_t len2)
|
||||
{
|
||||
qse_char_t c1, c2;
|
||||
const qse_htoc_t* end1 = s1 + len1;
|
||||
const qse_htoc_t* end2 = s2 + len2;
|
||||
const qse_mchar_t* end1 = s1 + len1;
|
||||
const qse_mchar_t* end2 = s2 + len2;
|
||||
|
||||
while (s1 < end1)
|
||||
{
|
||||
@ -487,7 +487,7 @@ static QSE_INLINE int capture_content_length (
|
||||
qse_htrd_t* htrd, qse_htb_pair_t* pair)
|
||||
{
|
||||
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))
|
||||
{
|
||||
@ -577,7 +577,7 @@ static QSE_INLINE int capture_key_header (
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const qse_htoc_t* ptr;
|
||||
const qse_mchar_t* ptr;
|
||||
qse_size_t len;
|
||||
int (*handler) (qse_htrd_t*, qse_htb_pair_t*);
|
||||
} hdrtab[] =
|
||||
@ -653,7 +653,7 @@ static qse_htb_pair_t* hdr_cbserter (
|
||||
/* the key exists. let's combine values, each separated
|
||||
* by a comma */
|
||||
struct hdr_cmb_t* cmb;
|
||||
qse_htoc_t* ptr;
|
||||
qse_mchar_t* ptr;
|
||||
qse_size_t len;
|
||||
|
||||
/* 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 (
|
||||
tx->htrd->mmgr,
|
||||
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)
|
||||
{
|
||||
@ -680,7 +680,7 @@ static qse_htb_pair_t* hdr_cbserter (
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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
|
||||
{
|
||||
qse_htoc_t* ptr;
|
||||
qse_mchar_t* ptr;
|
||||
qse_size_t len;
|
||||
} name, value;
|
||||
|
||||
@ -767,7 +767,7 @@ qse_htoc_t* parse_header_fields (qse_htrd_t* htrd, qse_htoc_t* line)
|
||||
* the continuation */
|
||||
if (is_purespace_octet (*++p))
|
||||
{
|
||||
qse_htoc_t* cpydst;
|
||||
qse_mchar_t* cpydst;
|
||||
|
||||
cpydst = p - 1;
|
||||
if (*(cpydst-1) == '\r') cpydst--;
|
||||
@ -817,9 +817,9 @@ badhdr:
|
||||
}
|
||||
|
||||
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 */
|
||||
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_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 */
|
||||
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;
|
||||
}
|
||||
|
||||
static const qse_htoc_t* get_trailing_headers (
|
||||
qse_htrd_t* htrd, const qse_htoc_t* req, const qse_htoc_t* end)
|
||||
static const qse_mchar_t* get_trailing_headers (
|
||||
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)
|
||||
{
|
||||
register qse_htoc_t b = *ptr++;
|
||||
register qse_mchar_t b = *ptr++;
|
||||
|
||||
switch (b)
|
||||
{
|
||||
@ -957,7 +957,7 @@ static const qse_htoc_t* get_trailing_headers (
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_htoc_t* p;
|
||||
qse_mchar_t* p;
|
||||
|
||||
QSE_ASSERT (htrd->fed.s.crlf <= 3);
|
||||
htrd->fed.s.crlf = 0;
|
||||
@ -1008,10 +1008,10 @@ done:
|
||||
}
|
||||
|
||||
/* 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_htoc_t* ptr = req;
|
||||
const qse_mchar_t* end = req + len;
|
||||
const qse_mchar_t* ptr = req;
|
||||
|
||||
/* does this goto drop code maintainability? */
|
||||
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)
|
||||
{
|
||||
register qse_htoc_t b = *ptr++;
|
||||
register qse_mchar_t b = *ptr++;
|
||||
|
||||
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES &&
|
||||
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)
|
||||
{
|
||||
qse_mcstr_t key, val;
|
||||
const qse_htoc_t* p, * end;
|
||||
qse_htoc_t* out;
|
||||
const qse_mchar_t* p, * end;
|
||||
qse_mchar_t* out;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
||||
* like bytes=1-20,30-50 */
|
||||
|
||||
qse_http_range_int_t from, to;
|
||||
int suffix = 0;
|
||||
int type = QSE_HTTP_RANGE_PROPER;
|
||||
|
||||
if (str[0] != QSE_MT('b') ||
|
||||
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));
|
||||
}
|
||||
else suffix = 1;
|
||||
else type = QSE_HTTP_RANGE_SUFFIX;
|
||||
|
||||
if (*str != QSE_MT('-')) return -1;
|
||||
str++;
|
||||
@ -182,7 +182,7 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
||||
|
||||
if (from > to) return -1;
|
||||
|
||||
range->suffix = suffix;
|
||||
range->type = type;
|
||||
range->from = from;
|
||||
range->to = to;
|
||||
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 (r)
|
||||
if (r && !ca->data[fd].bad)
|
||||
{
|
||||
FD_SET (ca->data[fd].handle.i, r);
|
||||
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; */
|
||||
continue;
|
||||
}
|
||||
if (n == 0) continue;
|
||||
if (n == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*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)
|
||||
{
|
||||
qse_htoc_t buf[1024];
|
||||
qse_mchar_t buf[1024];
|
||||
qse_ssize_t m;
|
||||
|
||||
reread:
|
||||
@ -974,7 +983,10 @@ int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
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);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -997,14 +1009,18 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
|
||||
if (!client->htrd) continue;
|
||||
|
||||
if (FD_ISSET(client->handle.i, &r))
|
||||
if (FD_ISSET(client->handle.i, &r))
|
||||
{
|
||||
/* got input */
|
||||
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);
|
||||
delete_from_client_array (httpd, fd);
|
||||
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;
|
||||
struct task_sendtext_t
|
||||
typedef struct task_text_t task_text_t;
|
||||
struct task_text_t
|
||||
{
|
||||
const qse_mchar_t* ptr;
|
||||
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)
|
||||
{
|
||||
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 + 1, xtn->ptr, xtn->left);
|
||||
@ -76,12 +76,12 @@ static int httpd_init_sendtext (
|
||||
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)
|
||||
{
|
||||
ssize_t n;
|
||||
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;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
@ -102,19 +102,19 @@ static int httpd_main_sendtext (
|
||||
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_task_t task;
|
||||
task_sendtext_t data;
|
||||
task_text_t data;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.ptr = text;
|
||||
data.left = qse_mbslen(text);
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = httpd_init_sendtext;
|
||||
task.main = httpd_main_sendtext;
|
||||
task.init = task_init_text;
|
||||
task.main = task_main_text;
|
||||
task.ctx = &data;
|
||||
|
||||
return qse_httpd_entask (
|
||||
@ -127,37 +127,37 @@ int qse_httpd_entasksendtext (
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct task_sendfmt_t task_sendfmt_t;
|
||||
struct task_sendfmt_t
|
||||
typedef struct task_format_t task_format_t;
|
||||
struct task_format_t
|
||||
{
|
||||
qse_mchar_t* org;
|
||||
const qse_mchar_t* ptr;
|
||||
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)
|
||||
{
|
||||
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));
|
||||
task->ctx = xtn;
|
||||
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)
|
||||
{
|
||||
task_sendfmt_t* ctx = (task_sendfmt_t*)task->ctx;
|
||||
task_format_t* ctx = (task_format_t*)task->ctx;
|
||||
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)
|
||||
{
|
||||
ssize_t n;
|
||||
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;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
@ -178,11 +178,11 @@ static int httpd_main_sendfmt (
|
||||
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_task_t task;
|
||||
task_sendfmt_t data;
|
||||
task_format_t data;
|
||||
|
||||
va_list ap;
|
||||
qse_mchar_t n[2];
|
||||
@ -259,9 +259,9 @@ int qse_httpd_entasksendfmt (
|
||||
data.left = l;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = httpd_init_sendfmt;
|
||||
task.fini = httpd_fini_sendfmt;
|
||||
task.main = httpd_main_sendfmt;
|
||||
task.init = task_init_format;
|
||||
task.fini = task_fini_format;
|
||||
task.main = task_main_format;
|
||||
task.ctx = &data;
|
||||
|
||||
return qse_httpd_entask (
|
||||
@ -272,53 +272,58 @@ int qse_httpd_entasksendfmt (
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct httpd_task_sendfile_t httpd_task_sendfile_t;
|
||||
struct httpd_task_sendfile_t
|
||||
typedef struct task_file_t task_file_t;
|
||||
struct task_file_t
|
||||
{
|
||||
int fd;
|
||||
qse_ubi_t handle;
|
||||
qse_foff_t left;
|
||||
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)
|
||||
{
|
||||
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));
|
||||
task->ctx = xtn;
|
||||
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)
|
||||
{
|
||||
httpd_task_sendfile_t* ctx = (httpd_task_sendfile_t*)task->ctx;
|
||||
close (ctx->fd);
|
||||
task_file_t* ctx = (task_file_t*)task->ctx;
|
||||
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)
|
||||
{
|
||||
ssize_t n;
|
||||
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;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
/* TODO: more adjustment needed for OS with different sendfile semantics... */
|
||||
n = sendfile (
|
||||
client->handle.i,
|
||||
ctx->fd,
|
||||
ctx->handle.i,
|
||||
&ctx->offset,
|
||||
count
|
||||
);
|
||||
|
||||
if (n <= -1) return -1;
|
||||
if (n <= -1) return -1; /* TODO: any logging */
|
||||
|
||||
if (n == 0 && count > 0)
|
||||
{
|
||||
/* TODO: .... */
|
||||
/* anything to do in this case? can this happen if the file has been truncated during transfer.... */
|
||||
/* The file could be truncated when this condition is set.
|
||||
* 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;
|
||||
@ -327,22 +332,22 @@ static int httpd_main_sendfile (
|
||||
return 1; /* more work to do */
|
||||
}
|
||||
|
||||
int qse_httpd_entasksendfile (
|
||||
int qse_httpd_entaskfile (
|
||||
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;
|
||||
httpd_task_sendfile_t data;
|
||||
task_file_t data;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.fd = fd;
|
||||
data.handle = handle;
|
||||
data.offset = offset;
|
||||
data.left = size;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = httpd_init_sendfile;
|
||||
task.main = httpd_main_sendfile;
|
||||
task.fini = httpd_fini_sendfile;
|
||||
task.init = task_init_file;
|
||||
task.main = task_main_file;
|
||||
task.fini = task_fini_file;
|
||||
task.ctx = &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
|
||||
typedef struct httpd_task_cgi_t httpd_task_cgi_t;
|
||||
struct httpd_task_cgi_t
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.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;
|
||||
}
|
||||
|
||||
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 (
|
||||
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)
|
||||
{
|
||||
int fd;
|
||||
const qse_mchar_t* rangestr;
|
||||
qse_http_range_t range;
|
||||
int x;
|
||||
|
||||
fd = open (qse_htre_getqpathptr(req), O_RDONLY);
|
||||
if (fd <= -1)
|
||||
rangestr = qse_htre_gethdrval (req, "Range");
|
||||
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>");
|
||||
if (qse_httpd_entasksendfmt (httpd, client,
|
||||
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
||||
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"),
|
||||
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);
|
||||
if (qse_httpd_entasksendfmt (httpd, client,
|
||||
QSE_MT("HTTP/%d.%d 404 Not found\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) <= -1) goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
x = qse_httpd_entaskpath (
|
||||
httpd, client,
|
||||
qse_htre_getqpathptr(req),
|
||||
(rangestr? &range: QSE_NULL),
|
||||
qse_htre_getversion(req)
|
||||
);
|
||||
if (x <= -1) goto oops;
|
||||
}
|
||||
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>");
|
||||
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"),
|
||||
req->version.major, req->version.minor,
|
||||
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops;
|
||||
|
Loading…
x
Reference in New Issue
Block a user