touched up code a little
This commit is contained in:
parent
9cdc8206e5
commit
1deaac776d
@ -30,8 +30,6 @@ enum qse_htrd_errnum_t
|
||||
{
|
||||
QSE_HTRD_ENOERR,
|
||||
QSE_HTRD_ENOMEM,
|
||||
|
||||
QSE_HTRD_EDISCON,
|
||||
QSE_HTRD_EBADRE,
|
||||
QSE_HTRD_EBADHDR,
|
||||
QSE_HTRD_ERECBS
|
||||
@ -50,13 +48,9 @@ typedef struct qse_htrd_recbs_t qse_htrd_recbs_t;
|
||||
|
||||
struct qse_htrd_recbs_t
|
||||
{
|
||||
/* octet reader and writer */
|
||||
qse_ssize_t (*reader) (qse_htrd_t* htrd, qse_htoc_t* buf, qse_size_t len);
|
||||
|
||||
int (*request) (qse_htrd_t* htrd, qse_htre_t* req);
|
||||
int (*response) (qse_htrd_t* htrd, qse_htre_t* res);
|
||||
int (*expect_continue) (qse_htrd_t* htrd, qse_htre_t* req);
|
||||
|
||||
int (*response) (qse_htrd_t* htrd, qse_htre_t* res);
|
||||
int (*qparamstr) (qse_htrd_t* htrd, const qse_mcstr_t* key, const qse_mcstr_t* val);
|
||||
};
|
||||
|
||||
@ -110,8 +104,6 @@ struct qse_htrd_t
|
||||
} retype;
|
||||
|
||||
qse_htre_t re;
|
||||
|
||||
qse_htoc_t rbuf[4096];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -23,8 +23,10 @@
|
||||
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
#include <qse/net/htre.h>
|
||||
|
||||
typedef struct qse_httpd_t qse_httpd_t;
|
||||
typedef struct qse_httpd_client_t qse_httpd_client_t;
|
||||
|
||||
enum qse_httpd_errnum_t
|
||||
{
|
||||
@ -34,15 +36,18 @@ enum qse_httpd_errnum_t
|
||||
QSE_HTTPD_EINTERN,
|
||||
QSE_HTTPD_EIOMUX,
|
||||
QSE_HTTPD_ESOCKET,
|
||||
QSE_HTTPD_EDISCON, /* client disconnnected */
|
||||
QSE_HTTPD_EBADREQ, /* bad request */
|
||||
QSE_HTTPD_ECOMCBS
|
||||
};
|
||||
typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
|
||||
|
||||
typedef struct qse_httpd_comcbs_t qse_httpd_comcbs_t;
|
||||
struct qse_httpd_comcbs_t
|
||||
|
||||
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
|
||||
struct qse_httpd_cbs_t
|
||||
{
|
||||
int (*open_listeners) (qse_httpd_t* httpd);
|
||||
int (*close_listeners) (qse_httpd_t* httpd);
|
||||
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);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -66,9 +71,13 @@ void qse_httpd_close (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
void qse_httpd_setcomcbs (
|
||||
const qse_httpd_cbs_t* qse_httpd_getcbs (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
void qse_httpd_setcbs (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_comcbs_t* comcbs
|
||||
qse_httpd_cbs_t* cbs
|
||||
);
|
||||
|
||||
int qse_httpd_loop (
|
||||
|
@ -1304,31 +1304,6 @@ feedme_more:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_htrd_read (qse_htrd_t* http)
|
||||
{
|
||||
qse_ssize_t n;
|
||||
|
||||
QSE_ASSERTX (
|
||||
http->recbs->reader != QSE_NULL,
|
||||
"You must set the octet reader to be able to call qse_htrd_read()"
|
||||
);
|
||||
|
||||
http->errnum = QSE_HTRD_ENOERR;
|
||||
n = http->recbs->reader (http, http->rbuf, QSE_SIZEOF(http->rbuf));
|
||||
if (n <= -1)
|
||||
{
|
||||
if (http->errnum == QSE_HTRD_ENOERR) http->errnum = QSE_HTRD_ERECBS;
|
||||
return -1;
|
||||
}
|
||||
if (n == 0)
|
||||
{
|
||||
http->errnum = QSE_HTRD_EDISCON;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return qse_htrd_feed (http, http->rbuf, n);
|
||||
}
|
||||
|
||||
int qse_htrd_scanqparam (qse_htrd_t* http, const qse_mcstr_t* cstr)
|
||||
{
|
||||
qse_mcstr_t key, val;
|
||||
|
@ -32,6 +32,17 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd)
|
||||
#define DEFAULT_SECURE_PORT 443
|
||||
|
||||
static void free_listener_list (qse_httpd_t* httpd, listener_t* l);
|
||||
int qse_httpd_entask (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task);
|
||||
|
||||
static int handle_request (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
||||
static int handle_expect_continue (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
|
||||
|
||||
static qse_httpd_cbs_t default_cbs =
|
||||
{
|
||||
handle_request,
|
||||
handle_expect_continue
|
||||
};
|
||||
|
||||
|
||||
qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||
{
|
||||
@ -72,6 +83,7 @@ qse_httpd_t* qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr)
|
||||
QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd));
|
||||
httpd->mmgr = mmgr;
|
||||
httpd->listener.max = -1;
|
||||
httpd->cbs = &default_cbs;
|
||||
|
||||
pthread_mutex_init (&httpd->listener.mutex, QSE_NULL);
|
||||
|
||||
@ -91,6 +103,16 @@ void qse_httpd_stop (qse_httpd_t* httpd)
|
||||
httpd->stopreq = 1;
|
||||
}
|
||||
|
||||
const qse_httpd_cbs_t* qse_httpd_getcbs (qse_httpd_t* httpd)
|
||||
{
|
||||
return httpd->cbs;
|
||||
}
|
||||
|
||||
void qse_httpd_setcbs (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs)
|
||||
{
|
||||
httpd->cbs = cbs;
|
||||
}
|
||||
|
||||
static QSE_INLINE void* httpd_alloc (qse_httpd_t* httpd, qse_size_t n)
|
||||
{
|
||||
void* ptr = QSE_MMGR_ALLOC (httpd->mmgr, n);
|
||||
@ -124,16 +146,15 @@ static void httpd_free (qse_httpd_t* httpd, void* ptr)
|
||||
#define MAX_SENDFILE_SIZE 4096
|
||||
//#define MAX_SENDFILE_SIZE 64
|
||||
|
||||
typedef struct http_xtn_t http_xtn_t;
|
||||
typedef struct htrd_xtn_t htrd_xtn_t;
|
||||
|
||||
struct http_xtn_t
|
||||
struct htrd_xtn_t
|
||||
{
|
||||
client_array_t* array;
|
||||
qse_size_t index;
|
||||
qse_size_t client_index;
|
||||
qse_httpd_t* httpd;
|
||||
};
|
||||
|
||||
static int enqueue_task_unlocked (client_t* client, const task_t* task)
|
||||
static int enqueue_task_unlocked (qse_httpd_client_t* client, const qse_httpd_task_t* task)
|
||||
{
|
||||
int index;
|
||||
|
||||
@ -146,7 +167,7 @@ static int enqueue_task_unlocked (client_t* client, const task_t* task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enqueue_task_locked (client_t* client, const task_t* task)
|
||||
static int enqueue_task_locked (qse_httpd_client_t* client, const qse_httpd_task_t* task)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutex_lock (&client->task.mutex);
|
||||
@ -155,9 +176,9 @@ static int enqueue_task_locked (client_t* client, const task_t* task)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dequeue_task_unlocked (client_t* client, task_t* task)
|
||||
static int dequeue_task_unlocked (qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_t* actp;
|
||||
qse_httpd_task_t* actp;
|
||||
|
||||
if (client->task.count <= 0) return -1;
|
||||
|
||||
@ -171,7 +192,7 @@ static int dequeue_task_unlocked (client_t* client, task_t* task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dequeue_task_locked (client_t* client, task_t* task)
|
||||
static int dequeue_task_locked (qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutex_lock (&client->task.mutex);
|
||||
@ -180,17 +201,17 @@ static int dequeue_task_locked (client_t* client, task_t* task)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void purge_tasks_locked (client_t* client)
|
||||
static void purge_tasks_locked (qse_httpd_client_t* client)
|
||||
{
|
||||
task_t task;
|
||||
qse_httpd_task_t task;
|
||||
pthread_mutex_lock (&client->task.mutex);
|
||||
while (dequeue_task_unlocked (client, &task) == 0);
|
||||
pthread_mutex_unlock (&client->task.mutex);
|
||||
}
|
||||
|
||||
static int enqueue_sendtext_locked (client_t* client, const char* text)
|
||||
static int enqueue_sendtext_locked (qse_httpd_client_t* client, const char* text)
|
||||
{
|
||||
task_t task;
|
||||
qse_httpd_task_t task;
|
||||
|
||||
memset (&task, 0, sizeof(task));
|
||||
task.type = TASK_SENDTEXT;
|
||||
@ -266,31 +287,35 @@ static qse_mchar_t* format_textdup (qse_httpd_t* httpd, const char* fmt, ...)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int enqueue_sendtextdup_locked (client_t* client, const char* text)
|
||||
static int enqueue_sendduptext_locked (qse_httpd_t* httpd, qse_httpd_client_t* client, char* text)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
|
||||
memset (&task, 0, sizeof(task));
|
||||
task.type = TASK_SENDTEXTDUP;
|
||||
task.u.sendtextdup.ptr = text;
|
||||
task.u.sendtextdup.left = strlen(text);
|
||||
|
||||
return qse_httpd_entask (httpd, client, &task);
|
||||
}
|
||||
|
||||
static int enqueue_sendtextdup_locked (qse_httpd_t* httpd, qse_httpd_client_t* client, const char* text)
|
||||
{
|
||||
task_t task;
|
||||
char* textdup;
|
||||
int n;
|
||||
|
||||
textdup = strdup (text);
|
||||
if (textdup == NULL) return -1;
|
||||
|
||||
memset (&task, 0, sizeof(task));
|
||||
task.type = TASK_SENDTEXTDUP;
|
||||
task.u.sendtextdup.ptr = textdup;
|
||||
task.u.sendtextdup.left = strlen(textdup);
|
||||
n = enqueue_sendduptext_locked (httpd, client, textdup);
|
||||
if (n <= -1) free (textdup);
|
||||
|
||||
if (enqueue_task_locked (client, &task) <= -1)
|
||||
{
|
||||
free (textdup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int enqueue_sendfile_locked (client_t* client, int fd)
|
||||
static int enqueue_sendfile_locked (qse_httpd_t* httpd, qse_httpd_client_t* client, int fd)
|
||||
{
|
||||
task_t task;
|
||||
qse_httpd_task_t task;
|
||||
struct stat st;
|
||||
|
||||
if (fstat (fd, &st) <= -1) return -1;
|
||||
@ -300,17 +325,17 @@ static int enqueue_sendfile_locked (client_t* client, int fd)
|
||||
task.u.sendfile.fd = fd;
|
||||
task.u.sendfile.left = st.st_size;;
|
||||
|
||||
return enqueue_task_locked (client, &task);
|
||||
return qse_httpd_entask (httpd, client, &task);
|
||||
}
|
||||
|
||||
static int enqueue_disconnect (client_t* client)
|
||||
static int enqueue_disconnect (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
{
|
||||
task_t task;
|
||||
qse_httpd_task_t task;
|
||||
|
||||
memset (&task, 0, sizeof(task));
|
||||
task.type = TASK_DISCONNECT;
|
||||
|
||||
return enqueue_task_locked (client, &task);
|
||||
return qse_httpd_entask (httpd, client, &task);
|
||||
}
|
||||
|
||||
static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
|
||||
@ -325,10 +350,8 @@ qse_printf (QSE_T("PARAM %d[%S] => %d[%S] \n"), (int)key->len, key->ptr, (int)va
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_request (qse_htrd_t* http, qse_htre_t* req)
|
||||
static int handle_request (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http);
|
||||
client_t* client = &xtn->array->data[xtn->index];
|
||||
int method;
|
||||
|
||||
qse_printf (QSE_T("================================\n"));
|
||||
@ -343,12 +366,12 @@ if (qse_htre_getqparamlen(req) > 0)
|
||||
qse_printf (QSE_T("PARAMS ==> [%S]\n"), qse_htre_getqparamptr(req));
|
||||
}
|
||||
|
||||
qse_htb_walk (&http->re.hdrtab, walk, QSE_NULL);
|
||||
if (QSE_MBS_LEN(&http->re.content) > 0)
|
||||
qse_htb_walk (&req->hdrtab, walk, QSE_NULL);
|
||||
if (QSE_MBS_LEN(&req->content) > 0)
|
||||
{
|
||||
qse_printf (QSE_T("content = [%.*S]\n"),
|
||||
(int)QSE_MBS_LEN(&http->re.content),
|
||||
QSE_MBS_PTR(&http->re.content));
|
||||
(int)QSE_MBS_LEN(&req->content),
|
||||
QSE_MBS_PTR(&req->content));
|
||||
}
|
||||
|
||||
method = qse_htre_getqmethod (req);
|
||||
@ -357,6 +380,7 @@ qse_printf (QSE_T("content = [%.*S]\n"),
|
||||
{
|
||||
int fd;
|
||||
|
||||
#if 0
|
||||
/*if (qse_htrd_scanqparam (http, qse_htre_getqparamcstr(req)) <= -1) */
|
||||
if (qse_htrd_scanqparam (http, QSE_NULL) <= -1)
|
||||
{
|
||||
@ -366,7 +390,7 @@ char* text = format_textdup (xtn->httpd,
|
||||
req->version.major,
|
||||
req->version.minor,
|
||||
(int)strlen(msg) + 4, msg);
|
||||
if (text == QSE_NULL || enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
if (text == QSE_NULL || enqueue_sendduptext_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
if (text) httpd_free (xtn->httpd, text);
|
||||
qse_printf (QSE_T("failed to format text push task....\n"));
|
||||
@ -374,31 +398,32 @@ if (text == QSE_NULL || enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (method == QSE_HTTP_POST)
|
||||
{
|
||||
qse_printf (QSE_T("BEGIN FORM FIELDS=============\n"));
|
||||
if (qse_htrd_scanqparam (http, qse_htre_getcontentcstr(req)) <= -1)
|
||||
{
|
||||
}
|
||||
qse_printf (QSE_T("END FORM FIELDS=============\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
fd = open (qse_htre_getqpathptr(req), O_RDONLY);
|
||||
if (fd <= -1)
|
||||
{
|
||||
const char* msg = "<html><head><title>NOT FOUND</title></head><body><b>REQUESTD FILE NOT FOUND</b></body></html>";
|
||||
char* text = format_textdup (
|
||||
xtn->httpd,
|
||||
httpd,
|
||||
"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)strlen(msg) + 4, msg
|
||||
);
|
||||
|
||||
if (text == QSE_NULL || enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
if (text == QSE_NULL || enqueue_sendduptext_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
if (text) httpd_free (xtn->httpd, text);
|
||||
if (text) httpd_free (httpd, text);
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
@ -415,28 +440,7 @@ qse_printf (QSE_T("fstat failure....\n"));
|
||||
else if (st.st_size <= 0)
|
||||
{
|
||||
close (fd);
|
||||
|
||||
qse_printf (QSE_T("empty file....\n"));
|
||||
#if 0
|
||||
qse_htre_t* res = qse_htrd_newresponse (http);
|
||||
if (req == QSE_NULL)
|
||||
{
|
||||
/* hard failure... can't answer */
|
||||
/* arrange to close connection */
|
||||
}
|
||||
|
||||
|
||||
ptr = qse_htrd_emitresponse (http, res, &len);
|
||||
if (ptr == QSE_NULL)
|
||||
{
|
||||
/* hard failure... can't answer */
|
||||
/* arrange to close connection */
|
||||
}
|
||||
|
||||
task.type = TASK_SENDTEXT;
|
||||
task.u.sendtext.ptr = ptr;
|
||||
task.u.sendtext.len = len;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -450,37 +454,19 @@ snprintf (text, sizeof(text),
|
||||
qse_htre_getqpathptr(req)
|
||||
);
|
||||
|
||||
#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)
|
||||
if (enqueue_sendtextdup_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enqueue_sendfile_locked (client, fd) <= -1)
|
||||
if (enqueue_sendfile_locked (httpd, client, fd) <= -1)
|
||||
{
|
||||
/* TODO: close??? just close....??? */
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (req->attr.connection_close)
|
||||
{
|
||||
if (enqueue_disconnect (client) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,47 +479,58 @@ snprintf (text, sizeof(text),
|
||||
qse_htre_getmajorversion(req),
|
||||
qse_htre_getminorversion(req),
|
||||
(int)strlen(msg)+4, msg);
|
||||
if (enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
if (enqueue_sendtextdup_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pthread_cond_signal (&xtn->array->cond);
|
||||
if (req->attr.connection_close)
|
||||
{
|
||||
if (enqueue_disconnect (httpd, client) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("failed to push task....\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_expect_continue (qse_htrd_t* http, qse_htre_t* req)
|
||||
{
|
||||
http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http);
|
||||
client_t* client = &xtn->array->data[xtn->index];
|
||||
|
||||
static int handle_expect_continue (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
/*
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (http);
|
||||
qse_httpd_client_t* client = &xtn->array->data[xtn->index];
|
||||
*/
|
||||
|
||||
/* TODO: change this whole callback */
|
||||
if (qse_htre_getqmethod(req) == QSE_HTTP_POST)
|
||||
{
|
||||
char text[32];
|
||||
qse_mchar_t text[32];
|
||||
|
||||
snprintf (text, sizeof(text),
|
||||
"HTTP/%d.%d 100 OK\r\n\r\n",
|
||||
QSE_MT("HTTP/%d.%d 100 OK\r\n\r\n"),
|
||||
req->version.major, req->version.minor);
|
||||
|
||||
if (enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
if (enqueue_sendtextdup_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char text[32];
|
||||
qse_mchar_t text[32];
|
||||
|
||||
qse_htre_setdiscard (req, 1);
|
||||
|
||||
snprintf (text, sizeof(text),
|
||||
"HTTP/%d.%d 404 Not found\r\n\r\n",
|
||||
QSE_MT("HTTP/%d.%d 404 Not found\r\n\r\n"),
|
||||
req->version.major, req->version.minor);
|
||||
|
||||
if (enqueue_sendtextdup_locked (client, text) <= -1)
|
||||
if (enqueue_sendtextdup_locked (httpd, client, text) <= -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -542,15 +539,28 @@ static int handle_expect_continue (qse_htrd_t* http, qse_htre_t* req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_response (qse_htrd_t* http, qse_htre_t* res)
|
||||
static int htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req)
|
||||
{
|
||||
#if 0
|
||||
if (res->code >= 100 && res->code <= 199)
|
||||
{
|
||||
/* informational response */
|
||||
}
|
||||
#endif
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
||||
qse_httpd_client_t* client = &xtn->httpd->client.array.data[xtn->client_index];
|
||||
return xtn->httpd->cbs->handle_request (xtn->httpd, client, req);
|
||||
}
|
||||
|
||||
static int htrd_handle_expect_continue (qse_htrd_t* htrd, qse_htre_t* req)
|
||||
{
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
||||
qse_httpd_client_t* client = &xtn->httpd->client.array.data[xtn->client_index];
|
||||
return xtn->httpd->cbs->handle_expect_continue (xtn->httpd, client, req);
|
||||
}
|
||||
|
||||
static int htrd_handle_response (qse_htrd_t* htrd, qse_htre_t* res)
|
||||
{
|
||||
/*
|
||||
htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd);
|
||||
qse_httpd_client_t* client = &xtn->httpd->client.array.data[xtn->client_index];
|
||||
*/
|
||||
|
||||
/* directly send some response saying stupid request... */
|
||||
qse_printf (QSE_T("response received... HTTP/%d.%d %d %.*S\n"),
|
||||
qse_htre_getmajorversion(res),
|
||||
qse_htre_getminorversion(res),
|
||||
@ -558,32 +568,18 @@ static int handle_response (qse_htrd_t* http, qse_htre_t* res)
|
||||
(int)qse_htre_getsmessagelen(res),
|
||||
qse_htre_getsmessageptr(res)
|
||||
);
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static qse_ssize_t receive_octets (qse_htrd_t* http, qse_htoc_t* buf, qse_size_t size)
|
||||
static qse_htrd_recbs_t htrd_recbs =
|
||||
{
|
||||
http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http);
|
||||
client_t* client = &xtn->array->data[xtn->index];
|
||||
ssize_t n;
|
||||
|
||||
n = recv (client->fd, buf, size, 0);
|
||||
if (n <= -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||
http->errnum = 99999;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
qse_htrd_recbs_t htrd_recbs =
|
||||
{
|
||||
receive_octets,
|
||||
handle_request,
|
||||
handle_response,
|
||||
handle_expect_continue,
|
||||
htrd_handle_request,
|
||||
htrd_handle_expect_continue,
|
||||
htrd_handle_response,
|
||||
capture_param
|
||||
};
|
||||
|
||||
|
||||
static void deactivate_listener (qse_httpd_t* httpd, listener_t* l)
|
||||
{
|
||||
QSE_ASSERT (l->handle >= 0);
|
||||
@ -710,18 +706,17 @@ static void init_client_array (client_array_t* array)
|
||||
array->capa = 0;
|
||||
array->size = 0;
|
||||
array->data = QSE_NULL;
|
||||
pthread_cond_init (&array->cond, NULL);
|
||||
}
|
||||
|
||||
static void delete_from_client_array (client_array_t* array, int fd)
|
||||
{
|
||||
if (array->data[fd].http)
|
||||
if (array->data[fd].htrd)
|
||||
{
|
||||
purge_tasks_locked (&array->data[fd]);
|
||||
pthread_mutex_destroy (&array->data[fd].task.mutex);
|
||||
|
||||
qse_htrd_close (array->data[fd].http);
|
||||
array->data[fd].http = QSE_NULL;
|
||||
qse_htrd_close (array->data[fd].htrd);
|
||||
array->data[fd].htrd = QSE_NULL;
|
||||
close (array->data[fd].fd);
|
||||
array->size--;
|
||||
}
|
||||
@ -741,44 +736,42 @@ static void fini_client_array (client_array_t* array)
|
||||
array->size = 0;
|
||||
array->data = QSE_NULL;
|
||||
}
|
||||
pthread_cond_destroy (&array->cond);
|
||||
}
|
||||
|
||||
static client_t* insert_into_client_array (qse_httpd_t* httpd, int fd, sockaddr_t* addr)
|
||||
static qse_httpd_client_t* insert_into_client_array (qse_httpd_t* httpd, int fd, sockaddr_t* addr)
|
||||
{
|
||||
http_xtn_t* xtn;
|
||||
client_array_t* array = &httpd->ca;
|
||||
htrd_xtn_t* xtn;
|
||||
client_array_t* array = &httpd->client.array;
|
||||
|
||||
if (fd >= array->capa)
|
||||
{
|
||||
#define ALIGN 512
|
||||
client_t* tmp;
|
||||
qse_httpd_client_t* tmp;
|
||||
qse_size_t capa = ((fd + ALIGN) / ALIGN) * ALIGN;
|
||||
|
||||
tmp = realloc (array->data, capa * QSE_SIZEOF(client_t));
|
||||
tmp = realloc (array->data, capa * QSE_SIZEOF(*tmp));
|
||||
if (tmp == QSE_NULL) return QSE_NULL;
|
||||
|
||||
memset (&tmp[array->capa], 0,
|
||||
QSE_SIZEOF(client_t) * (capa - array->capa));
|
||||
QSE_SIZEOF(*tmp) * (capa - array->capa));
|
||||
|
||||
array->data = tmp;
|
||||
array->capa = capa;
|
||||
}
|
||||
|
||||
QSE_ASSERT (array->data[fd].http == QSE_NULL);
|
||||
QSE_ASSERT (array->data[fd].htrd == QSE_NULL);
|
||||
|
||||
array->data[fd].fd = fd;
|
||||
array->data[fd].addr = *addr;
|
||||
array->data[fd].http = qse_htrd_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(*xtn));
|
||||
if (array->data[fd].http == QSE_NULL) return QSE_NULL;
|
||||
array->data[fd].htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(*xtn));
|
||||
if (array->data[fd].htrd == QSE_NULL) return QSE_NULL;
|
||||
pthread_mutex_init (&array->data[fd].task.mutex, NULL);
|
||||
|
||||
xtn = (http_xtn_t*)qse_htrd_getxtn (array->data[fd].http);
|
||||
xtn->array = array;
|
||||
xtn->index = fd;
|
||||
xtn = (htrd_xtn_t*)qse_htrd_getxtn (array->data[fd].htrd);
|
||||
xtn->client_index = fd;
|
||||
xtn->httpd = httpd;
|
||||
|
||||
qse_htrd_setrecbs (array->data[fd].http, &htrd_recbs);
|
||||
qse_htrd_setrecbs (array->data[fd].htrd, &htrd_recbs);
|
||||
array->size++;
|
||||
return &array->data[fd];
|
||||
}
|
||||
@ -788,7 +781,7 @@ static int accept_client_from_listener (qse_httpd_t* httpd, listener_t* l)
|
||||
int flag, c;
|
||||
sockaddr_t addr;
|
||||
socklen_t addrlen = QSE_SIZEOF(addr);
|
||||
client_t* client;
|
||||
qse_httpd_client_t* client;
|
||||
|
||||
/* TODO:
|
||||
if (l->secure)
|
||||
@ -824,9 +817,9 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
|
||||
if (flag >= 0) fcntl (c, F_SETFL, flag | O_NONBLOCK);
|
||||
fcntl (c, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
pthread_mutex_lock (&httpd->camutex);
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
client = insert_into_client_array (httpd, c, &addr);
|
||||
pthread_mutex_unlock (&httpd->camutex);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
if (client == QSE_NULL)
|
||||
{
|
||||
close (c);
|
||||
@ -860,7 +853,7 @@ httpd->cbs.on_error (httpd, l).... */
|
||||
static int make_fd_set_from_client_array (qse_httpd_t* httpd, fd_set* r, fd_set* w)
|
||||
{
|
||||
int fd, max = -1;
|
||||
client_array_t* ca = &httpd->ca;
|
||||
client_array_t* ca = &httpd->client.array;
|
||||
|
||||
if (r)
|
||||
{
|
||||
@ -874,7 +867,7 @@ static int make_fd_set_from_client_array (qse_httpd_t* httpd, fd_set* r, fd_set*
|
||||
|
||||
for (fd = 0; fd < ca->capa; fd++)
|
||||
{
|
||||
if (ca->data[fd].http)
|
||||
if (ca->data[fd].htrd)
|
||||
{
|
||||
if (r)
|
||||
{
|
||||
@ -893,9 +886,9 @@ static int make_fd_set_from_client_array (qse_httpd_t* httpd, fd_set* r, fd_set*
|
||||
return max;
|
||||
}
|
||||
|
||||
static int perform_task (client_t* client)
|
||||
static int perform_task (qse_httpd_client_t* client)
|
||||
{
|
||||
task_t* task;
|
||||
qse_httpd_task_t* task;
|
||||
|
||||
task = &client->task.array[client->task.offset];
|
||||
|
||||
@ -973,9 +966,6 @@ qse_printf (QSE_T("finished sending text dup dequed...\n"));
|
||||
if (count >= task->u.sendfile.left)
|
||||
count = task->u.sendfile.left;
|
||||
|
||||
//n = qse_htrd_write (client->http, sendfile, joins);
|
||||
|
||||
|
||||
n = sendfile (
|
||||
client->fd,
|
||||
task->u.sendfile.fd,
|
||||
@ -1027,25 +1017,25 @@ static void* response_thread (void* arg)
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
pthread_mutex_lock (&httpd->camutex);
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
max = make_fd_set_from_client_array (httpd, NULL, &w);
|
||||
pthread_mutex_unlock (&httpd->camutex);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
|
||||
while (max == -1 && !httpd->stopreq)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
|
||||
pthread_mutex_lock (&httpd->camutex);
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
|
||||
gettimeofday (&now, NULL);
|
||||
timeout.tv_sec = now.tv_sec + 2;
|
||||
timeout.tv_nsec = now.tv_usec * 1000;
|
||||
|
||||
pthread_cond_timedwait (&httpd->ca.cond, &httpd->camutex, &timeout);
|
||||
pthread_cond_timedwait (&httpd->client.cond, &httpd->client.mutex, &timeout);
|
||||
max = make_fd_set_from_client_array (httpd, NULL, &w);
|
||||
|
||||
pthread_mutex_unlock (&httpd->camutex);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
}
|
||||
|
||||
if (httpd->stopreq) break;
|
||||
@ -1060,11 +1050,11 @@ static void* response_thread (void* arg)
|
||||
}
|
||||
if (n == 0) continue;
|
||||
|
||||
for (fd = 0; fd < httpd->ca.capa; fd++)
|
||||
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
||||
{
|
||||
client_t* client = &httpd->ca.data[fd];
|
||||
qse_httpd_client_t* client = &httpd->client.array.data[fd];
|
||||
|
||||
if (!client->http) continue;
|
||||
if (!client->htrd) continue;
|
||||
|
||||
if (FD_ISSET(client->fd, &w))
|
||||
{
|
||||
@ -1078,13 +1068,57 @@ static void* response_thread (void* arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
{
|
||||
qse_htoc_t buf[1024];
|
||||
qse_ssize_t m;
|
||||
|
||||
reread:
|
||||
m = read (client->fd, buf, sizeof(buf));
|
||||
if (m <= -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ESOCKET;
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), client->fd);
|
||||
return -1;
|
||||
}
|
||||
goto reread;
|
||||
}
|
||||
else if (m == 0)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_EDISCON;
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), client->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* feed may have called the request callback multiple times...
|
||||
* that's because we don't know how many valid requests
|
||||
* are included in 'buf' */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (qse_htrd_feed (client->htrd, buf, m) <= -1)
|
||||
{
|
||||
if (httpd->errnum == QSE_HTTPD_ENOERR)
|
||||
{
|
||||
if (client->htrd->errnum == QSE_HTRD_EBADRE ||
|
||||
client->htrd->errnum == QSE_HTRD_EBADHDR)
|
||||
httpd->errnum = QSE_HTTPD_EBADREQ;
|
||||
else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */
|
||||
}
|
||||
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: http error while processing \n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
{
|
||||
pthread_t response_thread_id;
|
||||
|
||||
httpd->stopreq = 0;
|
||||
|
||||
|
||||
QSE_ASSERTX (httpd->listener.list != QSE_NULL,
|
||||
"Add listeners before calling qse_httpd_loop()"
|
||||
);
|
||||
@ -1102,8 +1136,9 @@ int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
}
|
||||
|
||||
/* data receiver main logic */
|
||||
init_client_array (&httpd->ca);
|
||||
pthread_mutex_init (&httpd->camutex, NULL);
|
||||
pthread_mutex_init (&httpd->client.mutex, NULL);
|
||||
pthread_cond_init (&httpd->client.cond, NULL);
|
||||
init_client_array (&httpd->client.array);
|
||||
|
||||
/* start the response sender as a thread */
|
||||
pthread_create (&response_thread_id, NULL, response_thread, httpd);
|
||||
@ -1135,29 +1170,20 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
accept_client_from_listeners (httpd, &r);
|
||||
|
||||
/* check the client activity */
|
||||
for (fd = 0; fd < httpd->ca.capa; fd++)
|
||||
for (fd = 0; fd < httpd->client.array.capa; fd++)
|
||||
{
|
||||
client_t* client = &httpd->ca.data[fd];
|
||||
qse_httpd_client_t* client = &httpd->client.array.data[fd];
|
||||
|
||||
if (!client->http) continue;
|
||||
if (!client->htrd) continue;
|
||||
|
||||
if (FD_ISSET(client->fd, &r))
|
||||
{
|
||||
/* got input */
|
||||
if (qse_htrd_read (client->http) <= -1)
|
||||
if (read_from_client (httpd, client) <= -1)
|
||||
{
|
||||
int errnum = client->http->errnum;
|
||||
if (errnum != 99999)
|
||||
{
|
||||
pthread_mutex_lock (&httpd->camutex);
|
||||
delete_from_client_array (&httpd->ca, fd);
|
||||
pthread_mutex_unlock (&httpd->camutex);
|
||||
if (errnum == QSE_HTRD_EDISCON)
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), client->fd);
|
||||
else
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read/process a request from a client %d\n"), client->fd);
|
||||
}
|
||||
continue;
|
||||
pthread_mutex_lock (&httpd->client.mutex);
|
||||
delete_from_client_array (&httpd->client.array, fd);
|
||||
pthread_mutex_unlock (&httpd->client.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1165,8 +1191,9 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
|
||||
pthread_join (response_thread_id, NULL);
|
||||
|
||||
fini_client_array (&httpd->ca);
|
||||
pthread_mutex_destroy (&httpd->camutex);
|
||||
fini_client_array (&httpd->client.array);
|
||||
pthread_cond_destroy (&httpd->client.cond);
|
||||
pthread_mutex_destroy (&httpd->client.mutex);
|
||||
|
||||
deactivate_listeners (httpd);
|
||||
return 0;
|
||||
@ -1405,3 +1432,10 @@ void qse_httpd_clearlisteners (qse_httpd_t* httpd)
|
||||
}
|
||||
#endif
|
||||
|
||||
int qse_httpd_entask (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
int ret;
|
||||
ret = enqueue_task_locked (client, task);
|
||||
if (ret >= 0) pthread_cond_signal (&httpd->client.cond);
|
||||
return ret;
|
||||
}
|
||||
|
@ -4,20 +4,43 @@
|
||||
#include <qse/cmn/main.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct httpd_xtn_t httpd_xtn_t;
|
||||
struct httpd_xtn_t
|
||||
{
|
||||
const qse_httpd_cbs_t* orgcbs;
|
||||
};
|
||||
|
||||
qse_httpd_t* httpd = NULL;
|
||||
static int handle_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
|
||||
return xtn->orgcbs->handle_request (httpd, client, req);
|
||||
}
|
||||
|
||||
static int handle_expect_continue (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
|
||||
return xtn->orgcbs->handle_expect_continue (httpd, client, req);
|
||||
}
|
||||
|
||||
static qse_httpd_t* httpd = NULL;
|
||||
|
||||
static void sigint (int sig)
|
||||
{
|
||||
qse_httpd_stop (httpd);
|
||||
}
|
||||
|
||||
static qse_httpd_cbs_t httpd_cbs =
|
||||
{
|
||||
handle_request,
|
||||
handle_expect_continue
|
||||
};
|
||||
|
||||
int httpd_main (int argc, qse_char_t* argv[])
|
||||
{
|
||||
int n;
|
||||
/*
|
||||
httpd_xtn_t* xtn;
|
||||
*/
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
@ -26,17 +49,16 @@ int httpd_main (int argc, qse_char_t* argv[])
|
||||
}
|
||||
|
||||
|
||||
httpd = qse_httpd_open (QSE_NULL, 0);
|
||||
httpd = qse_httpd_open (QSE_NULL, QSE_SIZEOF(httpd_xtn_t));
|
||||
if (httpd == QSE_NULL)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
|
||||
httpd->cfg.port = atoi(argv[1]);
|
||||
*/
|
||||
xtn->orgcbs = qse_httpd_getcbs (httpd);
|
||||
|
||||
if (qse_httpd_addlisteners (httpd, argv[1]) <= -1)
|
||||
{
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listeners\n"));
|
||||
@ -44,6 +66,8 @@ int httpd_main (int argc, qse_char_t* argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_httpd_setcbs (httpd, &httpd_cbs);
|
||||
|
||||
signal (SIGINT, sigint);
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user