added qse_httpd_entaskpath().

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

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

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