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 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;
struct qse_http_octb_t
{
qse_size_t capa;
qse_size_t size;
qse_byte_t* data;
qse_http_oct_t* data;
};
enum qse_http_errnum_t
{
QSE_HTTP_ENOERR,
QSE_HTTP_ENOMEM,
QSE_HTTP_EBADREQ,
QSE_HTTP_EBADRE,
QSE_HTTP_EBADHDR,
QSE_HTTP_EREQCBS
};
@ -39,40 +42,12 @@ enum 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_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 */
qse_htb_t hdrtab;
@ -82,31 +57,89 @@ struct qse_http_req_t
int chunked;
int content_length;
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;
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
struct qse_http_rep_node_t
struct
{
int type; /* TEXT, RESOURCE */
qse_http_req_node_t* next;
};
typedef struct qse_http_rep_t qse_http_rep_t;
struct qse_http_rep_t
{
};
qse_http_oct_t* ptr;
qse_size_t len;
} args;
#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 (*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
@ -115,7 +148,7 @@ struct qse_http_t
qse_http_errnum_t errnum;
int option;
const qse_http_reqcbs_t* reqcbs;
qse_http_recbs_t recbs;
struct
{
@ -144,9 +177,22 @@ struct qse_http_t
/* points to the head of the combined header list */
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
@ -192,13 +238,13 @@ void qse_http_setoption (
int opts
);
const qse_http_reqcbs_t* qse_http_getreqcbs (
const qse_http_recbs_t* qse_http_getrecbs (
qse_http_t* http
);
void qse_http_setreqcbs (
void qse_http_setrecbs (
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 (
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 */
);

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.
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_ASSERT (mmgr != QSE_NULL);
tmp = (qse_mchar_t*) QSE_MMGR_ALLOC (
mmgr, (qse_mbslen(str)+1)*QSE_SIZEOF(qse_mchar_t));
if (tmp == QSE_NULL) return QSE_NULL;
@ -59,6 +61,8 @@ qse_mchar_t* qse_mbsxdup2 (
{
qse_mchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_mchar_t*) QSE_MMGR_ALLOC (
mmgr, (len1+len2+1) * QSE_SIZEOF(qse_mchar_t));
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_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (qse_wcslen(str)+1)*QSE_SIZEOF(qse_wchar_t));
if (tmp == QSE_NULL) return QSE_NULL;
@ -92,6 +98,8 @@ qse_wchar_t* qse_wcsxdup (
{
qse_wchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (len+1)*QSE_SIZEOF(qse_wchar_t));
if (tmp == QSE_NULL) return QSE_NULL;
@ -106,6 +114,8 @@ qse_wchar_t* qse_wcsxdup2 (
{
qse_wchar_t* tmp;
QSE_ASSERT (mmgr != QSE_NULL);
tmp = (qse_wchar_t*) QSE_MMGR_ALLOC (
mmgr, (len1+len2+1) * QSE_SIZEOF(qse_wchar_t));
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
{
ACTION_SENDTEXT,
ACTION_SENDFILE
ACTION_SENDTEXTDUP,
ACTION_SENDFILE,
ACTION_DISCONNECT
} type;
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
{
int fd;
@ -55,7 +67,7 @@ struct client_t
{
int offset;
int count;
client_action_t target[10];
client_action_t target[32];
} 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)
{
client_action_t* actp;
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.count--;
return 0;
@ -129,18 +147,81 @@ static void purge_client_actions_locked (client_t* client)
{
client_action_t action;
pthread_mutex_lock (&client->action_mutex);
while (dequeue_client_action_unlocked (client, &action) == 0)
{
if (action.type == ACTION_SENDFILE) close (action.u.sendfile.fd);
}
while (dequeue_client_action_unlocked (client, &action) == 0);
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)
{
http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http);
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)
{
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"));
#if 0
qse_http_req_t* rep = qse_http_newreply (http);
qse_http_req_t* res = qse_http_newresponse (http);
if (req == QSE_NULL)
{
/* 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)
{
/* hard failure... can't answer */
@ -190,17 +271,43 @@ qse_printf (QSE_T("empty file....\n"));
else
{
client_t* client = &xtn->array->data[xtn->index];
client_action_t action;
memset (&action, 0, sizeof(action));
action.type = ACTION_SENDFILE;
action.u.sendfile.fd = fd;
action.u.sendfile.left = st.st_size;;
char text[128];
snprintf (text, sizeof(text),
"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);
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"));
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;
}
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)
@ -229,7 +390,7 @@ int mkserver (const char* portstr)
memset (&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
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)
{
@ -321,7 +482,7 @@ static client_t* insert_into_client_array (
xtn->array = array;
xtn->index = fd;
qse_http_setreqcbs (array->data[fd].http, &http_reqcbs);
qse_http_setrecbs (array->data[fd].http, &http_recbs);
array->size++;
return &array->data[fd];
}
@ -352,7 +513,7 @@ static int make_fd_set_from_client_array (
}
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);
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:
{
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;
}
@ -401,29 +619,35 @@ static int take_client_action (client_t* client)
if (n <= -1)
{
qse_printf (QSE_T("sendfile failure... arrange to close this connection....\n"));
close (action->u.sendfile.fd);
dequeue_client_action_locked (client, NULL);
shutdown (client->fd, SHUT_RDWR);
}
else
{
/* TODO: what if n is 0???? does it mean EOF? */
action->u.sendfile.left -= n;
if (action->u.sendfile.left <= 0)
{
qse_printf (QSE_T("finished sending...\n"));
close (action->u.sendfile.fd);
dequeue_client_action_locked (client, NULL);
}
}
break;
}
case ACTION_DISCONNECT:
{
shutdown (client->fd, SHUT_RDWR);
break;
}
}
return 0;
}
static void* replier_thread (void* arg)
static void* response_thread (void* arg)
{
appdata_t* appdata = (appdata_t*)arg;
@ -463,8 +687,9 @@ static void* replier_thread (void* arg)
if (n <= -1)
{
if (errno == EINTR) continue;
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
break;
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %S\n"), strerror(errno));
/* break; */
continue;
}
if (n == 0) continue;
@ -489,7 +714,7 @@ static void* replier_thread (void* arg)
int main (int argc, char* argv[])
{
int s;
pthread_t replier_thread_id;
pthread_t response_thread_id;
appdata_t appdata;
if (argc != 2)
@ -515,8 +740,8 @@ int main (int argc, char* argv[])
init_client_array (&appdata.ca);
pthread_mutex_init (&appdata.camutex, NULL);
/* start the reply sender as a thread */
pthread_create (&replier_thread_id, NULL, replier_thread, &appdata);
/* start the response sender as a thread */
pthread_create (&response_thread_id, NULL, response_thread, &appdata);
while (!quit)
{
@ -533,7 +758,8 @@ int main (int argc, char* argv[])
{
if (errno == EINTR) continue;
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
break;
/* break; */
continue;
}
if (n == 0) continue;
@ -589,7 +815,7 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
{
/* got input */
qse_byte_t buf[1024];
qse_http_oct_t buf[1024];
ssize_t m;
reread:
@ -602,6 +828,7 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
delete_from_client_array (&appdata.ca, fd);
pthread_mutex_unlock (&appdata.camutex);
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), fd);
continue;
}
goto reread;
}
@ -620,9 +847,9 @@ qse_printf (QSE_T("connection %d accepted\n"), c);
n = qse_http_feed (client->http, buf, m);
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);
@ -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);
pthread_mutex_destroy (&appdata.camutex);