enhanced qse_http_t

This commit is contained in:
hyung-hwan 2011-06-23 10:17:35 +00:00
parent 37318f12db
commit 325a9d8b2b
4 changed files with 863 additions and 382 deletions

View File

@ -11,20 +11,23 @@
typedef struct qse_http_t qse_http_t; typedef struct qse_http_t qse_http_t;
/*typedef qse_byte_t qse_http_oct_t;*/
typedef qse_mchar_t qse_http_oct_t;
typedef struct qse_http_octb_t qse_http_octb_t; typedef struct qse_http_octb_t qse_http_octb_t;
struct qse_http_octb_t struct qse_http_octb_t
{ {
qse_size_t capa; qse_size_t capa;
qse_size_t size; qse_size_t size;
qse_byte_t* data; qse_http_oct_t* data;
}; };
enum qse_http_errnum_t enum qse_http_errnum_t
{ {
QSE_HTTP_ENOERR, QSE_HTTP_ENOERR,
QSE_HTTP_ENOMEM, QSE_HTTP_ENOMEM,
QSE_HTTP_EBADREQ, QSE_HTTP_EBADRE,
QSE_HTTP_EBADHDR, QSE_HTTP_EBADHDR,
QSE_HTTP_EREQCBS QSE_HTTP_EREQCBS
}; };
@ -39,40 +42,12 @@ enum qse_http_option_t
typedef enum qse_http_option_t qse_http_option_t; typedef enum qse_http_option_t qse_http_option_t;
typedef struct qse_http_req_t qse_http_req_t; typedef struct qse_http_req_t qse_http_req_t;
typedef struct qse_http_res_t qse_http_res_t;
typedef struct qse_http_rhc_t qse_http_rhc_t;
struct qse_http_req_t /* header and contents of request/response */
struct qse_http_rhc_t
{ {
enum
{
QSE_HTTP_REQ_GET,
QSE_HTTP_REQ_HEAD,
QSE_HTTP_REQ_POST
} method;
struct
{
qse_byte_t* ptr;
qse_size_t len;
} host;
struct
{
qse_byte_t* ptr;
qse_size_t len;
} path;
struct
{
qse_byte_t* ptr;
qse_size_t len;
} args;
struct
{
short major;
short minor;
} version;
/* header table */ /* header table */
qse_htb_t hdrtab; qse_htb_t hdrtab;
@ -82,31 +57,89 @@ struct qse_http_req_t
int chunked; int chunked;
int content_length; int content_length;
int connection_close; int connection_close;
struct
{
qse_http_oct_t* ptr;
qse_size_t len;
} content_type;
struct
{
qse_http_oct_t* ptr;
qse_size_t len;
} host;
int expect_continue;
} attr; } attr;
qse_http_octb_t con; qse_http_octb_t con;
/* if set, the rest of the contents are discarded */
int discard;
}; };
struct qse_http_req_t
{
enum
{
QSE_HTTP_REQ_GET,
QSE_HTTP_REQ_HEAD,
QSE_HTTP_REQ_POST,
QSE_HTTP_REQ_PUT,
QSE_HTTP_REQ_DELETE,
QSE_HTTP_REQ_TRACE,
QSE_HTTP_REQ_OPTIONS,
QSE_HTTP_REQ_CONNECT
} method;
struct
{
qse_http_oct_t* ptr;
qse_size_t len;
} path;
#if 0 #if 0
struct qse_http_rep_node_t struct
{ {
int type; /* TEXT, RESOURCE */ qse_http_oct_t* ptr;
qse_http_req_node_t* next; qse_size_t len;
}; } args;
typedef struct qse_http_rep_t qse_http_rep_t;
struct qse_http_rep_t
{
};
#endif #endif
typedef struct qse_http_reqcbs_t qse_http_reqcbs_t; struct
{
short major;
short minor;
} version;
qse_http_rhc_t* rhc;
};
struct qse_http_reqcbs_t struct qse_http_res_t
{
struct
{
short major;
short minor;
} version;
int code;
struct
{
qse_http_oct_t* ptr;
qse_size_t len;
} message;
qse_http_rhc_t* rhc;
};
typedef struct qse_http_recbs_t qse_http_recbs_t;
struct qse_http_recbs_t
{ {
int (*request) (qse_http_t* http, qse_http_req_t* req); int (*request) (qse_http_t* http, qse_http_req_t* req);
int (*response) (qse_http_t* http, qse_http_res_t* rep);
int (*expect_continue) (qse_http_t* http, qse_http_req_t* req);
}; };
struct qse_http_t struct qse_http_t
@ -115,7 +148,7 @@ struct qse_http_t
qse_http_errnum_t errnum; qse_http_errnum_t errnum;
int option; int option;
const qse_http_reqcbs_t* reqcbs; qse_http_recbs_t recbs;
struct struct
{ {
@ -144,9 +177,22 @@ struct qse_http_t
/* points to the head of the combined header list */ /* points to the head of the combined header list */
void* chl; void* chl;
} reqx; } fed;
qse_http_req_t req;
enum
{
QSE_HTTP_RETYPE_Q,
QSE_HTTP_RETYPE_S
} retype;
union
{
qse_http_req_t q;
qse_http_res_t s;
} re;
qse_http_rhc_t rhc;
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -192,13 +238,13 @@ void qse_http_setoption (
int opts int opts
); );
const qse_http_reqcbs_t* qse_http_getreqcbs ( const qse_http_recbs_t* qse_http_getrecbs (
qse_http_t* http qse_http_t* http
); );
void qse_http_setreqcbs ( void qse_http_setrecbs (
qse_http_t* http, qse_http_t* http,
const qse_http_reqcbs_t* reqcbs const qse_http_recbs_t* recbs
); );
/** /**
@ -207,7 +253,7 @@ void qse_http_setreqcbs (
*/ */
int qse_http_feed ( int qse_http_feed (
qse_http_t* http, /**< http */ qse_http_t* http, /**< http */
const qse_byte_t* req, /**< request octets */ const qse_http_oct_t* req, /**< request octets */
qse_size_t len /**< number of octets */ qse_size_t len /**< number of octets */
); );

View File

@ -1,5 +1,5 @@
/* /*
* $Id: str_dup.c 443 2011-04-25 14:56:05Z hyunghwan.chung $ * $Id: str_dup.c 499 2011-06-22 16:17:35Z hyunghwan.chung $
* *
Copyright 2006-2011 Chung, Hyung-Hwan. Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE. This file is part of QSE.
@ -25,6 +25,8 @@ qse_mchar_t* qse_mbsdup (const qse_mchar_t* str, qse_mmgr_t* mmgr)
{ {
qse_mchar_t* tmp; qse_mchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_mchar_t*) QSE_MMGR_ALLOC ( tmp = (qse_mchar_t*) QSE_MMGR_ALLOC (
mmgr, (qse_mbslen(str)+1)*QSE_SIZEOF(qse_mchar_t)); mmgr, (qse_mbslen(str)+1)*QSE_SIZEOF(qse_mchar_t));
if (tmp == QSE_NULL) return QSE_NULL; if (tmp == QSE_NULL) return QSE_NULL;
@ -59,6 +61,8 @@ qse_mchar_t* qse_mbsxdup2 (
{ {
qse_mchar_t* tmp; qse_mchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_mchar_t*) QSE_MMGR_ALLOC ( tmp = (qse_mchar_t*) QSE_MMGR_ALLOC (
mmgr, (len1+len2+1) * QSE_SIZEOF(qse_mchar_t)); mmgr, (len1+len2+1) * QSE_SIZEOF(qse_mchar_t));
if (tmp == QSE_NULL) return QSE_NULL; if (tmp == QSE_NULL) return QSE_NULL;
@ -72,6 +76,8 @@ qse_wchar_t* qse_wcsdup (const qse_wchar_t* str, qse_mmgr_t* mmgr)
{ {
qse_wchar_t* tmp; qse_wchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC ( tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (qse_wcslen(str)+1)*QSE_SIZEOF(qse_wchar_t)); mmgr, (qse_wcslen(str)+1)*QSE_SIZEOF(qse_wchar_t));
if (tmp == QSE_NULL) return QSE_NULL; if (tmp == QSE_NULL) return QSE_NULL;
@ -92,6 +98,8 @@ qse_wchar_t* qse_wcsxdup (
{ {
qse_wchar_t* tmp; qse_wchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC ( tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (len+1)*QSE_SIZEOF(qse_wchar_t)); mmgr, (len+1)*QSE_SIZEOF(qse_wchar_t));
if (tmp == QSE_NULL) return QSE_NULL; if (tmp == QSE_NULL) return QSE_NULL;
@ -106,6 +114,8 @@ qse_wchar_t* qse_wcsxdup2 (
{ {
qse_wchar_t* tmp; qse_wchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC ( tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (len1+len2+1) * QSE_SIZEOF(qse_wchar_t)); mmgr, (len1+len2+1) * QSE_SIZEOF(qse_wchar_t));
if (tmp == QSE_NULL) return QSE_NULL; if (tmp == QSE_NULL) return QSE_NULL;

File diff suppressed because it is too large Load Diff

View File

@ -30,11 +30,23 @@ struct client_action_t
enum enum
{ {
ACTION_SENDTEXT, ACTION_SENDTEXT,
ACTION_SENDFILE ACTION_SENDTEXTDUP,
ACTION_SENDFILE,
ACTION_DISCONNECT
} type; } type;
union union
{ {
struct
{
const qse_http_oct_t* ptr;
qse_size_t left;
} sendtext;
struct
{
qse_http_oct_t* ptr;
qse_size_t left;
} sendtextdup;
struct struct
{ {
int fd; int fd;
@ -55,7 +67,7 @@ struct client_t
{ {
int offset; int offset;
int count; int count;
client_action_t target[10]; client_action_t target[32];
} action; } action;
}; };
@ -108,9 +120,15 @@ static int enqueue_client_action_locked (client_t* client, const client_action_t
static int dequeue_client_action_unlocked (client_t* client, client_action_t* action) static int dequeue_client_action_unlocked (client_t* client, client_action_t* action)
{ {
client_action_t* actp;
if (client->action.count <= 0) return -1; if (client->action.count <= 0) return -1;
if (action) *action = client->action.target[client->action.offset]; actp = &client->action.target[client->action.offset];
if (actp->type == ACTION_SENDFILE) close (actp->u.sendfile.fd);
else if (actp->type == ACTION_SENDTEXTDUP) free (actp->u.sendtextdup.ptr);
if (action) *action = *actp;
client->action.offset = (client->action.offset + 1) % QSE_COUNTOF(client->action.target); client->action.offset = (client->action.offset + 1) % QSE_COUNTOF(client->action.target);
client->action.count--; client->action.count--;
return 0; return 0;
@ -129,18 +147,81 @@ static void purge_client_actions_locked (client_t* client)
{ {
client_action_t action; client_action_t action;
pthread_mutex_lock (&client->action_mutex); pthread_mutex_lock (&client->action_mutex);
while (dequeue_client_action_unlocked (client, &action) == 0) while (dequeue_client_action_unlocked (client, &action) == 0);
{
if (action.type == ACTION_SENDFILE) close (action.u.sendfile.fd);
}
pthread_mutex_unlock (&client->action_mutex); pthread_mutex_unlock (&client->action_mutex);
} }
static int enqueue_sendtext_locked (client_t* client, const char* text)
{
client_action_t action;
memset (&action, 0, sizeof(action));
action.type = ACTION_SENDTEXT;
action.u.sendtext.ptr = text;
action.u.sendtext.left = strlen(text);
return enqueue_client_action_locked (client, &action);
}
static int enqueue_sendfmt_locked (client_t* client, const char* fmt, ...)
{
return 0;
}
static int enqueue_sendtextdup_locked (client_t* client, const char* text)
{
client_action_t action;
char* textdup;
textdup = strdup (text);
if (textdup == NULL) return -1;
memset (&action, 0, sizeof(action));
action.type = ACTION_SENDTEXTDUP;
action.u.sendtextdup.ptr = textdup;
action.u.sendtextdup.left = strlen(textdup);
if (enqueue_client_action_locked (client, &action) <= -1)
{
free (textdup);
return -1;
}
return 0;
}
static int enqueue_sendfile_locked (client_t* client, int fd)
{
client_action_t action;
struct stat st;
if (fstat (fd, &st) <= -1) return -1;
memset (&action, 0, sizeof(action));
action.type = ACTION_SENDFILE;
action.u.sendfile.fd = fd;
action.u.sendfile.left = st.st_size;;
return enqueue_client_action_locked (client, &action);
}
static int enqueue_disconnect (client_t* client)
{
client_action_t action;
memset (&action, 0, sizeof(action));
action.type = ACTION_DISCONNECT;
return enqueue_client_action_locked (client, &action);
}
static int handle_request (qse_http_t* http, qse_http_req_t* req) static int handle_request (qse_http_t* http, qse_http_req_t* req)
{ {
http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http); http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http);
qse_printf (QSE_T("got a request... %S\n"), req->path.ptr); qse_printf (QSE_T("got a request... %S\n"), req->path.ptr);
if (req->rhc->attr.host.ptr) qse_printf (QSE_T("host %S\n"), req->rhc->attr.host.ptr);
if (req->method == QSE_HTTP_REQ_GET) if (req->method == QSE_HTTP_REQ_GET)
{ {
int fd = open (req->path.ptr, O_RDONLY); int fd = open (req->path.ptr, O_RDONLY);
@ -167,7 +248,7 @@ qse_printf (QSE_T("fstat failure....\n"));
qse_printf (QSE_T("empty file....\n")); qse_printf (QSE_T("empty file....\n"));
#if 0 #if 0
qse_http_req_t* rep = qse_http_newreply (http); qse_http_req_t* res = qse_http_newresponse (http);
if (req == QSE_NULL) if (req == QSE_NULL)
{ {
/* hard failure... can't answer */ /* hard failure... can't answer */
@ -175,7 +256,7 @@ qse_printf (QSE_T("empty file....\n"));
} }
ptr = qse_http_emitreply (http, rep, &len); ptr = qse_http_emitresponse (http, res, &len);
if (ptr == QSE_NULL) if (ptr == QSE_NULL)
{ {
/* hard failure... can't answer */ /* hard failure... can't answer */
@ -190,17 +271,43 @@ qse_printf (QSE_T("empty file....\n"));
else else
{ {
client_t* client = &xtn->array->data[xtn->index]; client_t* client = &xtn->array->data[xtn->index];
client_action_t action;
memset (&action, 0, sizeof(action)); char text[128];
action.type = ACTION_SENDFILE; snprintf (text, sizeof(text),
action.u.sendfile.fd = fd; "HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\n\r\n",
action.u.sendfile.left = st.st_size;; req->version.major,
req->version.minor, (unsigned long long)st.st_size);
if (enqueue_client_action_locked (client, &action) <= -1) #if 0
if (enqueue_sendfmt_locked (client,
"HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\n\r\n",
req->version.major,
req->version.minor,
(unsigned long long)st.st_size) <= -1)
{
}
#endif
if (enqueue_sendtextdup_locked (client, text) <= -1)
{ {
/* TODO: close??? send error page ...*/
qse_printf (QSE_T("failed to push action....\n")); qse_printf (QSE_T("failed to push action....\n"));
return -1;
}
if (enqueue_sendfile_locked (client, fd) <= -1)
{
/* TODO: close??? just close....??? */
qse_printf (QSE_T("failed to push action....\n"));
return -1;
}
if (req->rhc->attr.connection_close)
{
if (enqueue_disconnect (client) <= -1)
{
qse_printf (QSE_T("failed to push action....\n"));
return -1;
}
} }
} }
} }
@ -210,9 +317,63 @@ qse_printf (QSE_T("failed to push action....\n"));
return 0; return 0;
} }
qse_http_reqcbs_t http_reqcbs = static int handle_expect_continue (qse_http_t* http, qse_http_req_t* req)
{ {
handle_request http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http);
client_t* client = &xtn->array->data[xtn->index];
if (req->method == QSE_HTTP_REQ_GET)
{
char text[32];
req->rhc->discard = 1;
snprintf (text, sizeof(text),
"HTTP/%d.%d 404 Not found\r\n\r\n",
req->version.major, req->version.minor);
if (enqueue_sendtextdup_locked (client, text) <= -1)
{
return -1;
}
}
else
{
char text[32];
snprintf (text, sizeof(text),
"HTTP/%d.%d 100 OK\r\n\r\n",
req->version.major, req->version.minor);
if (enqueue_sendtextdup_locked (client, text) <= -1)
{
return -1;
}
}
return 0;
}
static int handle_response (qse_http_t* http, qse_http_res_t* res)
{
#if 0
if (res->code >= 100 && res->code <= 199)
{
/* informational response */
}
#endif
qse_printf (QSE_T("response received... HTTP/%d.%d %d %.*S\n"),
res->version.major, res->version.minor, res->code,
(int)res->message.len, res->message.ptr);
return -1;
}
qse_http_recbs_t http_recbs =
{
handle_request,
handle_response,
handle_expect_continue
}; };
int mkserver (const char* portstr) int mkserver (const char* portstr)
@ -229,7 +390,7 @@ int mkserver (const char* portstr)
memset (&addr, 0, sizeof(addr)); memset (&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port); addr.sin6_port = htons(port);
inet_pton (AF_INET6, "::1", &addr.sin6_addr); //inet_pton (AF_INET6, "::1", &addr.sin6_addr);
if (bind (s, (struct sockaddr*)&addr, sizeof(addr)) <= -1) if (bind (s, (struct sockaddr*)&addr, sizeof(addr)) <= -1)
{ {
@ -321,7 +482,7 @@ static client_t* insert_into_client_array (
xtn->array = array; xtn->array = array;
xtn->index = fd; xtn->index = fd;
qse_http_setreqcbs (array->data[fd].http, &http_reqcbs); qse_http_setrecbs (array->data[fd].http, &http_recbs);
array->size++; array->size++;
return &array->data[fd]; return &array->data[fd];
} }
@ -352,7 +513,7 @@ static int make_fd_set_from_client_array (
} }
if (w && ca->data[fd].action.count > 0) if (w && ca->data[fd].action.count > 0)
{ {
/* add it to the set if it has a reply to send */ /* add it to the set if it has a response to send */
FD_SET (ca->data[fd].fd, w); FD_SET (ca->data[fd].fd, w);
if (ca->data[fd].fd > max) max = ca->data[fd].fd; if (ca->data[fd].fd > max) max = ca->data[fd].fd;
} }
@ -379,6 +540,63 @@ static int take_client_action (client_t* client)
{ {
case ACTION_SENDTEXT: case ACTION_SENDTEXT:
{ {
ssize_t n;
size_t count;
count = MAX_SENDFILE_SIZE;
if (count >= action->u.sendtext.left)
count = action->u.sendtext.left;
n = send (client->fd, action->u.sendtext.ptr, count, 0);
if (n <= -1)
{
qse_printf (QSE_T("send text failure... arrange to close this connection....\n"));
dequeue_client_action_locked (client, NULL);
shutdown (client->fd, SHUT_RDWR);
}
else
{
/* TODO: what if n is 0???? does it mean EOF? */
action->u.sendtext.left -= n;
if (action->u.sendtext.left <= 0)
{
qse_printf (QSE_T("finished sending text ...\n"));
dequeue_client_action_locked (client, NULL);
}
}
break;
}
case ACTION_SENDTEXTDUP:
{
ssize_t n;
size_t count;
count = MAX_SENDFILE_SIZE;
if (count >= action->u.sendtextdup.left)
count = action->u.sendtextdup.left;
n = send (client->fd, action->u.sendtextdup.ptr, count, 0);
if (n <= -1)
{
qse_printf (QSE_T("send text dup failure... arrange to close this connection....\n"));
dequeue_client_action_locked (client, NULL);
shutdown (client->fd, SHUT_RDWR);
}
else
{
/* TODO: what if n is 0???? does it mean EOF? */
action->u.sendtextdup.left -= n;
if (action->u.sendtextdup.left <= 0)
{
qse_printf (QSE_T("finished sending text dup...\n"));
dequeue_client_action_locked (client, NULL);
}
}
break; break;
} }
@ -401,29 +619,35 @@ static int take_client_action (client_t* client)
if (n <= -1) if (n <= -1)
{ {
qse_printf (QSE_T("sendfile failure... arrange to close this connection....\n")); qse_printf (QSE_T("sendfile failure... arrange to close this connection....\n"));
close (action->u.sendfile.fd);
dequeue_client_action_locked (client, NULL); dequeue_client_action_locked (client, NULL);
shutdown (client->fd, SHUT_RDWR);
} }
else else
{ {
/* TODO: what if n is 0???? does it mean EOF? */
action->u.sendfile.left -= n; action->u.sendfile.left -= n;
if (action->u.sendfile.left <= 0) if (action->u.sendfile.left <= 0)
{ {
qse_printf (QSE_T("finished sending...\n")); qse_printf (QSE_T("finished sending...\n"));
close (action->u.sendfile.fd);
dequeue_client_action_locked (client, NULL); dequeue_client_action_locked (client, NULL);
} }
} }
break; break;
} }
case ACTION_DISCONNECT:
{
shutdown (client->fd, SHUT_RDWR);
break;
}
} }
return 0; return 0;
} }
static void* replier_thread (void* arg) static void* response_thread (void* arg)
{ {
appdata_t* appdata = (appdata_t*)arg; appdata_t* appdata = (appdata_t*)arg;
@ -463,8 +687,9 @@ static void* replier_thread (void* arg)
if (n <= -1) if (n <= -1)
{ {
if (errno == EINTR) continue; if (errno == EINTR) continue;
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n")); qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %S\n"), strerror(errno));
break; /* break; */
continue;
} }
if (n == 0) continue; if (n == 0) continue;
@ -489,7 +714,7 @@ static void* replier_thread (void* arg)
int main (int argc, char* argv[]) int main (int argc, char* argv[])
{ {
int s; int s;
pthread_t replier_thread_id; pthread_t response_thread_id;
appdata_t appdata; appdata_t appdata;
if (argc != 2) if (argc != 2)
@ -515,8 +740,8 @@ int main (int argc, char* argv[])
init_client_array (&appdata.ca); init_client_array (&appdata.ca);
pthread_mutex_init (&appdata.camutex, NULL); pthread_mutex_init (&appdata.camutex, NULL);
/* start the reply sender as a thread */ /* start the response sender as a thread */
pthread_create (&replier_thread_id, NULL, replier_thread, &appdata); pthread_create (&response_thread_id, NULL, response_thread, &appdata);
while (!quit) while (!quit)
{ {
@ -533,7 +758,8 @@ int main (int argc, char* argv[])
{ {
if (errno == EINTR) continue; if (errno == EINTR) continue;
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n")); qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
break; /* break; */
continue;
} }
if (n == 0) continue; if (n == 0) continue;
@ -589,7 +815,7 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
{ {
/* got input */ /* got input */
qse_byte_t buf[1024]; qse_http_oct_t buf[1024];
ssize_t m; ssize_t m;
reread: reread:
@ -602,6 +828,7 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
delete_from_client_array (&appdata.ca, fd); delete_from_client_array (&appdata.ca, fd);
pthread_mutex_unlock (&appdata.camutex); pthread_mutex_unlock (&appdata.camutex);
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), fd); qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), fd);
continue;
} }
goto reread; goto reread;
} }
@ -620,9 +847,9 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
n = qse_http_feed (client->http, buf, m); n = qse_http_feed (client->http, buf, m);
if (n <= -1) if (n <= -1)
{ {
if (client->http->errnum == QSE_HTTP_EBADREQ) if (client->http->errnum == QSE_HTTP_EBADRE)
{ {
/* TODO: write a reply to indicate bad request... */ /* TODO: write a response to indicate bad request... */
} }
pthread_mutex_lock (&appdata.camutex); pthread_mutex_lock (&appdata.camutex);
@ -635,7 +862,7 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
} }
} }
pthread_join (replier_thread_id, NULL); pthread_join (response_thread_id, NULL);
fini_client_array (&appdata.ca); fini_client_array (&appdata.ca);
pthread_mutex_destroy (&appdata.camutex); pthread_mutex_destroy (&appdata.camutex);