enhanced qse_http_t
This commit is contained in:
parent
37318f12db
commit
325a9d8b2b
@ -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
|
||||||
{
|
{
|
||||||
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
|
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
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,9 +252,9 @@ void qse_http_setreqcbs (
|
|||||||
* callback function if it has processed a proper http request.
|
* callback function if it has processed a proper http request.
|
||||||
*/
|
*/
|
||||||
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 */
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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.
|
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
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user