added qse_httpd_entaskpath().
renames qse_httpd_entaskXXX() functions to a newer style
This commit is contained in:
		| @ -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; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user