enhanced qse_http_t
This commit is contained in:
		@ -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_size_t      capa;
 | 
			
		||||
	qse_size_t      size;
 | 
			
		||||
	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
 | 
			
		||||
{
 | 
			
		||||
	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
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		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
 | 
			
		||||
{
 | 
			
		||||
	int (*request) (qse_http_t* http, qse_http_req_t* req);
 | 
			
		||||
	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 (
 | 
			
		||||
	qse_http_t*              http,
 | 
			
		||||
	const qse_http_reqcbs_t* reqcbs
 | 
			
		||||
void qse_http_setrecbs (
 | 
			
		||||
	qse_http_t*             http,
 | 
			
		||||
	const qse_http_recbs_t* recbs
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -206,9 +252,9 @@ void qse_http_setreqcbs (
 | 
			
		||||
 * callback function if it has processed a proper http request. 
 | 
			
		||||
 */
 | 
			
		||||
int qse_http_feed (
 | 
			
		||||
	qse_http_t*       http, /**< http */
 | 
			
		||||
	const qse_byte_t* req,  /**< request octets */
 | 
			
		||||
	qse_size_t        len   /**< number of octets */
 | 
			
		||||
	qse_http_t*           http, /**< http */
 | 
			
		||||
	const qse_http_oct_t* req,  /**< request octets */
 | 
			
		||||
	qse_size_t            len   /**< number of octets */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 | 
			
		||||
@ -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
											
										
									
								
							@ -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);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user