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.
*/
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 (

View File

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

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

View File

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

View File

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

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 */
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;

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 (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)
{
@ -1002,9 +1014,13 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
/* 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
}
}
}

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

View File

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