added a state field to htrd for determining if it's waiting for more feeds.
enhanced how it can determine client's half-close changed how to compose cgi environment variables fixed a few bugs for various edge cases.
This commit is contained in:
parent
3e104c1ec8
commit
05e0476f97
@ -97,6 +97,7 @@ struct qse_htrd_t
|
||||
} fed;
|
||||
|
||||
qse_htre_t re;
|
||||
int clean;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -59,7 +59,8 @@ typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
|
||||
enum qse_httpd_option_t
|
||||
{
|
||||
QSE_HTTPD_CGIERRTONUL = (1 << 0),
|
||||
QSE_HTTPD_CGINOCLOEXEC = (1 << 1)
|
||||
QSE_HTTPD_CGINOCLOEXEC = (1 << 1),
|
||||
QSE_HTTPD_CGINOCHUNKED = (1 << 2)
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_stat_t qse_httpd_stat_t;
|
||||
|
@ -98,6 +98,8 @@ static QSE_INLINE int push_to_buffer (
|
||||
static QSE_INLINE int push_content (
|
||||
qse_htrd_t* htrd, const qse_mchar_t* ptr, qse_size_t len)
|
||||
{
|
||||
QSE_ASSERT (len > 0);
|
||||
|
||||
if (qse_htre_addcontent (&htrd->re, ptr, len) <= -1)
|
||||
{
|
||||
htrd->errnum = QSE_HTRD_ENOMEM;
|
||||
@ -109,15 +111,11 @@ static QSE_INLINE int push_content (
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hdr_cmb_t
|
||||
{
|
||||
struct hdr_cmb_t* next;
|
||||
};
|
||||
|
||||
static QSE_INLINE void clear_feed (qse_htrd_t* htrd)
|
||||
{
|
||||
/* clear necessary part of the request/response before
|
||||
* reading the next request/response */
|
||||
htrd->clean = 1;
|
||||
qse_htre_clear (&htrd->re);
|
||||
|
||||
qse_mbs_clear (&htrd->fed.b.tra);
|
||||
@ -126,10 +124,6 @@ static QSE_INLINE void clear_feed (qse_htrd_t* htrd)
|
||||
QSE_MEMSET (&htrd->fed.s, 0, QSE_SIZEOF(htrd->fed.s));
|
||||
}
|
||||
|
||||
#define QSE_HTRD_STATE_REQ 1
|
||||
#define QSE_HTRD_STATE_HDR 2
|
||||
#define QSE_HTRD_STATE_POST 3
|
||||
|
||||
qse_htrd_t* qse_htrd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||
{
|
||||
qse_htrd_t* htrd;
|
||||
@ -176,6 +170,7 @@ int qse_htrd_init (qse_htrd_t* htrd, qse_mmgr_t* mmgr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
htrd->clean = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -849,9 +844,11 @@ static QSE_INLINE int parse_initial_line_and_headers (
|
||||
|
||||
p = QSE_MBS_PTR(&htrd->fed.b.raw);
|
||||
|
||||
#if 0
|
||||
if (htrd->option & QSE_HTRD_SKIPEMPTYLINES)
|
||||
while (is_whspace_octet(*p)) p++;
|
||||
else
|
||||
#endif
|
||||
while (is_space_octet(*p)) p++;
|
||||
|
||||
QSE_ASSERT (*p != '\0');
|
||||
@ -895,7 +892,6 @@ static const qse_mchar_t* getchunklen (qse_htrd_t* htrd, const qse_mchar_t* ptr,
|
||||
/* this function must be called in the GET_CHUNK_LEN context */
|
||||
QSE_ASSERT (htrd->fed.s.chunk.phase == GET_CHUNK_LEN);
|
||||
|
||||
/*qse_printf (QSE_T("CALLING getchunklen [%hs]\n"), ptr);*/
|
||||
if (htrd->fed.s.chunk.count <= 0)
|
||||
{
|
||||
/* skip leading spaces if the first character of
|
||||
@ -925,7 +921,6 @@ static const qse_mchar_t* getchunklen (qse_htrd_t* htrd, const qse_mchar_t* ptr,
|
||||
if (htrd->fed.s.chunk.count <= 0)
|
||||
{
|
||||
/* empty line - no more chunk */
|
||||
/*qse_printf (QSE_T("empty line chunk done....\n"));*/
|
||||
htrd->fed.s.chunk.phase = GET_CHUNK_DONE;
|
||||
}
|
||||
else if (htrd->fed.s.chunk.len <= 0)
|
||||
@ -933,13 +928,11 @@ static const qse_mchar_t* getchunklen (qse_htrd_t* htrd, const qse_mchar_t* ptr,
|
||||
/* length explicity specified to 0
|
||||
get trailing headers .... */
|
||||
htrd->fed.s.chunk.phase = GET_CHUNK_TRAILERS;
|
||||
/*qse_printf (QSE_T("SWITCH TO GET_CHUNK_TRAILERS....\n"));*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ready to read the chunk data... */
|
||||
htrd->fed.s.chunk.phase = GET_CHUNK_DATA;
|
||||
/*qse_printf (QSE_T("SWITCH TO GET_CHUNK_DATA....\n"));*/
|
||||
}
|
||||
|
||||
htrd->fed.s.need = htrd->fed.s.chunk.len;
|
||||
@ -947,7 +940,6 @@ static const qse_mchar_t* getchunklen (qse_htrd_t* htrd, const qse_mchar_t* ptr,
|
||||
}
|
||||
else
|
||||
{
|
||||
/*qse_printf (QSE_T("XXXXXXXXXXXXXXXXXxxx [%c]\n"), *ptr);*/
|
||||
htrd->errnum = QSE_HTRD_EBADRE;
|
||||
return QSE_NULL;
|
||||
}
|
||||
@ -964,7 +956,6 @@ static const qse_mchar_t* get_trailing_headers (
|
||||
while (ptr < end)
|
||||
{
|
||||
register qse_mchar_t b = *ptr++;
|
||||
/*qse_printf (QSE_T("[%hc], %d\n"), b, htrd->fed.s.crlf);*/
|
||||
switch (b)
|
||||
{
|
||||
case '\0':
|
||||
@ -1043,6 +1034,8 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||
int header_completed_during_this_feed = 0;
|
||||
qse_size_t avail;
|
||||
|
||||
QSE_ASSERT (len > 0);
|
||||
|
||||
/* does this goto drop code maintainability? */
|
||||
if (htrd->fed.s.need > 0)
|
||||
{
|
||||
@ -1069,10 +1062,13 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||
goto dechunk_get_trailers;
|
||||
}
|
||||
|
||||
htrd->clean = 0; /* mark that the htrd is in need of some data */
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
register qse_mchar_t b = *ptr++;
|
||||
|
||||
#if 0
|
||||
if (htrd->option & QSE_HTRD_SKIPEMPTYLINES &&
|
||||
htrd->fed.s.plen <= 0 && is_whspace_octet(b))
|
||||
{
|
||||
@ -1081,6 +1077,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||
req++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (b)
|
||||
{
|
||||
@ -1142,16 +1139,17 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||
* reading CGI outputs. So it comes with
|
||||
* awkwardity described above.
|
||||
*/
|
||||
if (push_content (htrd, ptr, end - ptr) <= -1) return -1;
|
||||
/* this jump is only to invoke the peek
|
||||
* callback. this function should not be fed
|
||||
* more. */
|
||||
if (ptr < end && push_content (htrd, ptr, end - ptr) <= -1) return -1;
|
||||
|
||||
/* i don't really know if it is really completed
|
||||
* with content. QSE_HTRD_PEEKONLY is not compatible
|
||||
* with the completed state. anyway, let me complete
|
||||
* it. */
|
||||
qse_htre_completecontent (&htrd->re);
|
||||
|
||||
/* this jump is only to invoke the peek
|
||||
* callback. this function should not be fed
|
||||
* more. */
|
||||
goto feedme_more;
|
||||
}
|
||||
|
||||
@ -1235,8 +1233,17 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
|
||||
* specified */
|
||||
content_resume:
|
||||
avail = end - ptr;
|
||||
if (avail <= 0)
|
||||
{
|
||||
/* we didn't get a complete content yet */
|
||||
|
||||
if (avail < htrd->fed.s.need)
|
||||
/* avail can be 0 if data fed ends with
|
||||
* a chunk length withtout actual data.
|
||||
* so i check if avail is greater than 0
|
||||
* in order not to push empty content. */
|
||||
goto feedme_more;
|
||||
}
|
||||
else if (avail < htrd->fed.s.need)
|
||||
{
|
||||
/* the data is not as large as needed */
|
||||
if (push_content (htrd, ptr, avail) <= -1) return -1;
|
||||
@ -1355,10 +1362,17 @@ qse_printf (QSE_T("CONTENT_LENGTH %d, RAW HEADER LENGTH %d\n"),
|
||||
#endif
|
||||
|
||||
clear_feed (htrd);
|
||||
if (ptr >= end) return 0; /* no more feeds to handle */
|
||||
|
||||
/* let ptr point to the next character to LF or
|
||||
* the optional contents */
|
||||
req = ptr;
|
||||
|
||||
/* since there are more to handle, i mark that
|
||||
* htrd is in need of some data. this may
|
||||
* not be really compatible with SKIPEMPTYLINES.
|
||||
* SHOULD I simply remove the option? */
|
||||
htrd->clean = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1266,6 +1266,7 @@ struct task_cgi_t
|
||||
#define CGI_REQ_GOTALL (1 << 0)
|
||||
#define CGI_REQ_FWDALL (1 << 1)
|
||||
#define CGI_REQ_FWDERR (1 << 2)
|
||||
#define CGI_REQ_FWDCHUNKED (1 << 3)
|
||||
int reqflags;
|
||||
qse_htre_t* req; /* original request associated with this */
|
||||
qse_mbs_t* reqfwdbuf; /* content from the request */
|
||||
@ -1306,12 +1307,16 @@ static int cgi_capture_client_header (
|
||||
qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
|
||||
{
|
||||
cgi_client_req_hdr_ctx_t* hdrctx;
|
||||
qse_mchar_t* http_key;
|
||||
int ret;
|
||||
|
||||
hdrctx = (cgi_client_req_hdr_ctx_t*)ctx;
|
||||
|
||||
/* convert value to uppercase, change - to _ */
|
||||
if (qse_mbscasecmp (key, QSE_MT("Connection")) != 0 &&
|
||||
qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0 &&
|
||||
qse_mbscasecmp (key, QSE_MT("Content-Length")) != 0)
|
||||
{
|
||||
qse_mchar_t* http_key, * ptr;
|
||||
int ret;
|
||||
|
||||
http_key = qse_mbsdup2 (QSE_MT("HTTP_"), key, req->mmgr);
|
||||
if (http_key == QSE_NULL)
|
||||
{
|
||||
@ -1319,18 +1324,65 @@ static int cgi_capture_client_header (
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO EXCLUDE VARIOUS FIELDS like transfer-encoding or should i let cgi handle transfer-encoding: chunked??? */
|
||||
/* TODO: special handling for Cookie??? */
|
||||
for (ptr = http_key; *ptr; ptr++)
|
||||
{
|
||||
*ptr = QSE_TOMUPPER((unsigned)*ptr);
|
||||
if (*ptr == QSE_MT('-')) *ptr = '_';
|
||||
}
|
||||
|
||||
/* insert the last value only */
|
||||
while (val->next) val = val->next;
|
||||
ret = qse_env_insertmbs (hdrctx->env, http_key, val->ptr);
|
||||
if (ret <= -1)
|
||||
{
|
||||
QSE_MMGR_FREE (req->mmgr, http_key);
|
||||
hdrctx->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSE_MMGR_FREE (req->mmgr, http_key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cgi_add_header_to_buffer (
|
||||
task_cgi_t* cgi, qse_mbs_t* buf, const qse_mchar_t* key, const qse_htre_hdrval_t* val)
|
||||
{
|
||||
QSE_ASSERT (val != QSE_NULL);
|
||||
|
||||
do
|
||||
{
|
||||
ret = qse_env_insertmbs (hdrctx->env, http_key, val->ptr);
|
||||
if (ret <= -1) break;
|
||||
if (qse_mbs_cat (buf, key) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (buf, QSE_MT(": ")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (buf, val->ptr) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (buf, QSE_MT("\r\n")) == (qse_size_t)-1)
|
||||
{
|
||||
/* multiple items with the same keys are also
|
||||
* copied back to the response buffer */
|
||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
val = val->next;
|
||||
}
|
||||
while (val);
|
||||
|
||||
QSE_MMGR_FREE (req->mmgr, http_key);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cgi_capture_client_trailer (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
|
||||
{
|
||||
task_cgi_t* cgi = (task_cgi_t*)ctx;
|
||||
|
||||
if (qse_mbscasecmp (key, QSE_MT("Content-Length")) != 0 &&
|
||||
qse_mbscasecmp (key, QSE_MT("Connection")) != 0 &&
|
||||
qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0)
|
||||
{
|
||||
return cgi_add_header_to_buffer (cgi, cgi->reqfwdbuf, key, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
|
||||
@ -1342,22 +1394,7 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c
|
||||
qse_mbscasecmp (key, QSE_MT("Connection")) != 0 &&
|
||||
qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0)
|
||||
{
|
||||
/* multiple items with the same keys are also
|
||||
* copied back to the response buffer */
|
||||
do
|
||||
{
|
||||
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->res, val->ptr) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1)
|
||||
{
|
||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
val = val->next;
|
||||
}
|
||||
while (val);
|
||||
return cgi_add_header_to_buffer (cgi, cgi->res, key, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1553,15 +1590,19 @@ static qse_htrd_recbs_t cgi_script_htrd_cbs =
|
||||
QSE_NULL /* not needed for CGI */
|
||||
};
|
||||
|
||||
static qse_env_t* makecgienv (
|
||||
static int cgi_add_env (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
const qse_htre_t* req, const qse_mchar_t* path, qse_size_t content_length)
|
||||
qse_env_t* env, qse_htre_t* req, const
|
||||
qse_mchar_t* path, qse_size_t length, int chunked)
|
||||
{
|
||||
/* TODO: error check */
|
||||
qse_env_t* env;
|
||||
cgi_client_req_hdr_ctx_t ctx;
|
||||
qse_mchar_t buf[128];
|
||||
const qse_http_version_t* v;
|
||||
const qse_mchar_t* qparam;
|
||||
|
||||
env = qse_env_open (httpd->mmgr, 0, 0);
|
||||
if (env == QSE_NULL) goto oops;
|
||||
v = qse_htre_getversion(req);
|
||||
qparam = qse_htre_getqparam(req);
|
||||
|
||||
#ifdef _WIN32
|
||||
qse_env_insert (env, QSE_T("PATH"), QSE_NULL);
|
||||
@ -1571,6 +1612,8 @@ static qse_env_t* makecgienv (
|
||||
#endif
|
||||
|
||||
qse_env_insertmbs (env, QSE_MT("GATEWAY_INTERFACE"), QSE_MT("CGI/1.1"));
|
||||
snprintf (buf, QSE_COUNTOF(buf), QSE_MT("HTTP/%d.%d"), (int)v->major, (int)v->minor);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), buf);
|
||||
|
||||
{
|
||||
/* TODO: corrent all these name??? */
|
||||
@ -1582,110 +1625,38 @@ static qse_env_t* makecgienv (
|
||||
|
||||
|
||||
//qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path);
|
||||
qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req));
|
||||
qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req));
|
||||
if (qparam) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), qparam);
|
||||
|
||||
{
|
||||
const qse_mchar_t* tmp = qse_htre_getqparam(req);
|
||||
if (tmp) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), tmp);
|
||||
}
|
||||
qse_fmtuintmaxtombs (buf, QSE_COUNTOF(buf), length, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), buf);
|
||||
|
||||
qse_env_insertmbs (
|
||||
env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req));
|
||||
if (chunked) qse_env_insertmbs (env, QSE_MT("TRANSFER_ENCODING"), QSE_MT("chunked"));
|
||||
|
||||
{
|
||||
qse_mchar_t tmp[64];
|
||||
qse_fmtuintmaxtombs (
|
||||
tmp, QSE_COUNTOF(tmp), content_length,
|
||||
10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp);
|
||||
}
|
||||
|
||||
{
|
||||
qse_mchar_t addr[128];
|
||||
qse_nwadtombs (&client->local_addr,
|
||||
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), addr);
|
||||
qse_nwadtombs (&client->local_addr,
|
||||
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), addr);
|
||||
qse_nwadtombs (&client->remote_addr,
|
||||
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT);
|
||||
qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), addr);
|
||||
qse_nwadtombs (&client->remote_addr,
|
||||
addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR);
|
||||
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), addr);
|
||||
}
|
||||
|
||||
{
|
||||
qse_mchar_t proto[32];
|
||||
const qse_http_version_t* v = qse_htre_getversion(req);
|
||||
snprintf (proto, QSE_COUNTOF(proto),
|
||||
QSE_MT("HTTP/%d.%d"), (int)v->major, (int)v->minor);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), proto);
|
||||
}
|
||||
// TODO: HTTP_ headers.
|
||||
// TODO: REMOTE_USER ...
|
||||
qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), buf);
|
||||
qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR);
|
||||
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), buf);
|
||||
qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT);
|
||||
qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), buf);
|
||||
qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR);
|
||||
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf);
|
||||
|
||||
#if 0
|
||||
qse_env_insertmbs (env, "SERVER_NAME",
|
||||
qse_env_insertmbs (env, "SERVER_ROOT",
|
||||
qse_env_insertmbs (env, "DOCUMENT_ROOT",
|
||||
qse_env_insertmbs (env, "REMOTE_PORT",
|
||||
qse_env_insertmbs (env, "REQUEST_URI",
|
||||
qse_env_insertmbs (env, "REMOTE_USER",
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
ctx.httpd = httpd;
|
||||
ctx.env = env;
|
||||
if (qse_htre_walkheaders (req, cgi_capture_client_header, &ctx) <= -1) return -1;
|
||||
#endif
|
||||
if (qse_htre_walktrailers (req, cgi_capture_client_header, &ctx) <= -1) return -1;
|
||||
|
||||
/* TODO: memory error check */
|
||||
{
|
||||
const qse_htre_hdrval_t* tmp;
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Content-Type"));
|
||||
if (tmp)
|
||||
{
|
||||
while (tmp->next) tmp = tmp->next;
|
||||
qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), tmp->ptr);
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Cookie"));
|
||||
if (tmp)
|
||||
{
|
||||
/* TODO: should cookie be combined into 1??? */
|
||||
while (tmp->next) tmp = tmp->next;
|
||||
qse_env_insertmbs (env, QSE_MT("HTTP_COOKIE"), tmp->ptr);
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Host"));
|
||||
if (tmp)
|
||||
{
|
||||
while (tmp->next) tmp = tmp->next;
|
||||
qse_env_insertmbs (env, QSE_MT("HTTP_HOST"), tmp->ptr);
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Referer"));
|
||||
if (tmp)
|
||||
{
|
||||
while (tmp->next) tmp = tmp->next;
|
||||
qse_env_insertmbs (env, QSE_MT("HTTP_REFERER"), tmp->ptr);
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("User-Agent"));
|
||||
if (tmp)
|
||||
{
|
||||
while (tmp->next) tmp = tmp->next;
|
||||
qse_env_insertmbs (env, QSE_MT("HTTP_USER_AGENT"), tmp->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return env;
|
||||
|
||||
oops:
|
||||
if (env) qse_env_close (env);
|
||||
return QSE_NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cgi_snatch_client_input (
|
||||
@ -1714,6 +1685,18 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
|
||||
*/
|
||||
QSE_ASSERT (len == 0);
|
||||
|
||||
if (cgi->reqflags & CGI_REQ_FWDCHUNKED)
|
||||
{
|
||||
/* add the 0-sized chunk and trailers */
|
||||
if (qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("0\r\n")) == (qse_size_t)-1 ||
|
||||
qse_htre_walktrailers (req, cgi_capture_client_trailer, cgi) <= -1 ||
|
||||
qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1)
|
||||
{
|
||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark the there's nothing to read form the client side */
|
||||
cgi->reqflags |= CGI_REQ_GOTALL;
|
||||
|
||||
@ -1743,11 +1726,34 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
|
||||
* didn't occur previously. we store data from the client side
|
||||
* to the forwaring buffer only if there's no such previous
|
||||
* error. if an error occurred, we simply drop the data. */
|
||||
if (cgi->reqflags & CGI_REQ_FWDCHUNKED)
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
qse_fmtuintmaxtombs (
|
||||
buf, QSE_COUNTOF(buf), len,
|
||||
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
|
||||
-1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
if (qse_mbs_cat (cgi->reqfwdbuf, buf) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
|
||||
qse_mbs_ncat (cgi->reqfwdbuf, ptr, len) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1)
|
||||
{
|
||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qse_mbs_ncat (cgi->reqfwdbuf, ptr, len) == (qse_size_t)-1)
|
||||
{
|
||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* output pipe to child */
|
||||
task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr);
|
||||
}
|
||||
|
||||
@ -1798,6 +1804,11 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
|
||||
/* TODO: improve performance.. instead of copying the remaing part
|
||||
to the head all the time.. grow the buffer to a certain limit. */
|
||||
qse_mbs_del (cgi->reqfwdbuf, 0, n);
|
||||
if (QSE_MBS_LEN(cgi->reqfwdbuf) <= 0)
|
||||
{
|
||||
if (cgi->reqflags & CGI_REQ_GOTALL) goto done;
|
||||
else task->trigger[1].mask = 0; /* pipe output to child */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1821,17 +1832,26 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@WRITE TO CGI FAILED\n"));
|
||||
QSE_ASSERT (!cgi->req);
|
||||
QSE_ASSERT (cgi->reqflags & CGI_REQ_GOTALL);
|
||||
}
|
||||
|
||||
/* mark the end of input to the child explicitly. */
|
||||
qse_pio_end (&cgi->pio, QSE_PIO_IN);
|
||||
task->trigger[1].mask = 0; /* pipe output to child */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cgi->reqflags & CGI_REQ_GOTALL)
|
||||
{
|
||||
done:
|
||||
/* there is nothing to read from the client side and
|
||||
* there is nothing more to forward in the forwarding buffer.
|
||||
* clear the relay and write triggers for the time being.
|
||||
*/
|
||||
qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n"));
|
||||
QSE_ASSERT (cgi->req == QSE_NULL);
|
||||
|
||||
/* mark the end of input to the child explicitly. */
|
||||
qse_pio_end (&cgi->pio, QSE_PIO_IN);
|
||||
|
||||
task->trigger[1].mask = 0; /* pipe output to child */
|
||||
task->trigger[2].mask = 0; /* client-side */
|
||||
}
|
||||
@ -1864,11 +1884,8 @@ static int task_init_cgi (
|
||||
cgi->nph = arg->nph;
|
||||
cgi->req = QSE_NULL;
|
||||
|
||||
if (arg->req->state & QSE_HTRE_DISCARDED)
|
||||
{
|
||||
content_length = 0;
|
||||
goto done;
|
||||
}
|
||||
if (arg->req->state & QSE_HTRE_DISCARDED) goto done;
|
||||
|
||||
len = qse_htre_getcontentlen(arg->req);
|
||||
if ((arg->req->state & QSE_HTRE_COMPLETED) && len <= 0)
|
||||
@ -1876,7 +1893,6 @@ static int task_init_cgi (
|
||||
/* the content part is completed and no content
|
||||
* in the content buffer. there is nothing to forward */
|
||||
cgi->reqflags |= CGI_REQ_GOTALL;
|
||||
content_length = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1888,22 +1904,63 @@ static int task_init_cgi (
|
||||
* pass the content. this function, however, allows
|
||||
* such a request to entask a cgi script dropping the
|
||||
* content */
|
||||
|
||||
if (httpd->option & QSE_HTTPD_CGINOCHUNKED)
|
||||
{
|
||||
qse_htre_discardcontent (arg->req);
|
||||
cgi->reqflags |= CGI_REQ_GOTALL;
|
||||
content_length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do chunking to cgi */
|
||||
cgi->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
|
||||
if (cgi->reqfwdbuf == QSE_NULL)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
|
||||
qse_fmtuintmaxtombs (
|
||||
buf, QSE_COUNTOF(buf), len,
|
||||
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
|
||||
-1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
ptr = qse_htre_getcontentptr(arg->req);
|
||||
if (qse_mbs_cat (cgi->reqfwdbuf, buf) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
|
||||
qse_mbs_ncat (cgi->reqfwdbuf, ptr, len) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (cgi->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cgi->reqflags |= CGI_REQ_FWDCHUNKED;
|
||||
cgi->req = arg->req;
|
||||
qse_htre_setconcb (cgi->req, cgi_snatch_client_input, task);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create a buffer to hold request content from the client
|
||||
* and copy content received already */
|
||||
cgi->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
|
||||
if (cgi->reqfwdbuf == QSE_NULL) goto oops;
|
||||
if (cgi->reqfwdbuf == QSE_NULL)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
ptr = qse_htre_getcontentptr(arg->req);
|
||||
if (qse_mbs_ncpy (cgi->reqfwdbuf, ptr, len) == (qse_size_t)-1)
|
||||
{
|
||||
qse_mbs_close (cgi->reqfwdbuf);
|
||||
cgi->reqfwdbuf = QSE_NULL;
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
@ -1947,8 +2004,19 @@ static int task_init_cgi (
|
||||
}
|
||||
|
||||
done:
|
||||
cgi->env = makecgienv (httpd, client, arg->req, arg->path, content_length);
|
||||
if (cgi->env == QSE_NULL) goto oops;
|
||||
cgi->env = qse_env_open (httpd->mmgr, 0, 0);
|
||||
if (cgi->env == QSE_NULL)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (cgi_add_env (
|
||||
httpd, client, cgi->env, arg->req, arg->path, content_length,
|
||||
(cgi->reqflags & CGI_REQ_FWDCHUNKED)) <= -1)
|
||||
{
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* no triggers yet since the main loop doesn't allow me to set
|
||||
* triggers in the task initializer. however the main task handler
|
||||
@ -1964,6 +2032,18 @@ oops:
|
||||
* add an error task */
|
||||
cgi->init_failed = 1;
|
||||
task->ctx = cgi;
|
||||
|
||||
if (cgi->env)
|
||||
{
|
||||
qse_env_close (cgi->env);
|
||||
cgi->env = QSE_NULL;
|
||||
}
|
||||
if (cgi->reqfwdbuf)
|
||||
{
|
||||
qse_mbs_close (cgi->reqfwdbuf);
|
||||
cgi->reqfwdbuf = QSE_NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2245,6 +2325,8 @@ static int task_main_cgi_3 (
|
||||
|
||||
QSE_ASSERT (!cgi->nph);
|
||||
|
||||
qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
|
||||
{
|
||||
cgi_forward_client_input_to_script (httpd, task, 0);
|
||||
@ -2324,11 +2406,9 @@ static int task_main_cgi_2 (
|
||||
QSE_ASSERT (!cgi->nph);
|
||||
QSE_ASSERT (cgi->pio_inited);
|
||||
|
||||
{
|
||||
qse_ntime_t now;
|
||||
qse_gettime(&now);
|
||||
qse_printf (QSE_T("[cgi_2 at %lld]\n"), now);
|
||||
}
|
||||
qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
|
||||
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
|
||||
{
|
||||
qse_printf (QSE_T("[cgi_2 write]\n"));
|
||||
@ -2604,11 +2684,11 @@ struct task_proxy_t
|
||||
#define PROXY_PEER_CONNECTED (1 << 1)
|
||||
int peer_status;
|
||||
|
||||
#define PROXY_REQ_CHUNKED (1 << 0)
|
||||
#define PROXY_REQ_FWDERR (1 << 0)
|
||||
#define PROXY_REQ_FWDCHUNKED (1 << 1)
|
||||
int reqflags;
|
||||
qse_htre_t* req; /* original client request associated with this */
|
||||
qse_mbs_t* reqfwdbuf; /* content from the request */
|
||||
int reqfwderr;
|
||||
|
||||
qse_mbs_t* res;
|
||||
qse_size_t res_consumed;
|
||||
@ -2748,7 +2828,7 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
|
||||
*/
|
||||
QSE_ASSERT (len == 0);
|
||||
|
||||
if (proxy->reqflags & PROXY_REQ_CHUNKED)
|
||||
if (proxy->reqflags & PROXY_REQ_FWDCHUNKED)
|
||||
{
|
||||
/* add the 0-sized chunk and trailers */
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("0\r\n")) == (qse_size_t)-1 ||
|
||||
@ -2778,15 +2858,14 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
|
||||
* for task invocation. */
|
||||
task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
}
|
||||
|
||||
}
|
||||
else if (!proxy->reqfwderr)
|
||||
else if (!(proxy->reqflags & PROXY_REQ_FWDERR))
|
||||
{
|
||||
/* we can write to the peer if a forwarding error
|
||||
* didn't occur previously. we store data from the client side
|
||||
* to the forwaring buffer only if there's no such previous
|
||||
* error. if an error occurred, we simply drop the data. */
|
||||
if (proxy->reqflags & PROXY_REQ_CHUNKED)
|
||||
if (proxy->reqflags & PROXY_REQ_FWDCHUNKED)
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
qse_fmtuintmaxtombs (
|
||||
@ -2811,6 +2890,8 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr);
|
||||
}
|
||||
|
||||
@ -2897,7 +2978,6 @@ static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res)
|
||||
/* this peek handler is being called again.
|
||||
* this can happen if qse_htrd_feed() is fed with
|
||||
* multiple responses in task_main_proxy_2 (). */
|
||||
qse_printf (QSE_T("XXXXXXXXXXXXXXXXXXXXXXxx\n"));
|
||||
proxy->httpd->errnum = QSE_HTTPD_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -3142,7 +3222,7 @@ static void proxy_forward_client_input_to_peer (
|
||||
{
|
||||
/* there is something to forward in the forwarding buffer. */
|
||||
|
||||
if (proxy->reqfwderr)
|
||||
if (proxy->reqflags & PROXY_REQ_FWDERR)
|
||||
{
|
||||
/* a forwarding error has occurred previously.
|
||||
* clear the forwarding buffer */
|
||||
@ -3173,14 +3253,22 @@ qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
|
||||
|
||||
/* TODO: improve performance.. instead of copying the remaing part
|
||||
to the head all the time.. grow the buffer to a certain limit. */
|
||||
if (n > 0) qse_mbs_del (proxy->reqfwdbuf, 0, n);
|
||||
if (n > 0)
|
||||
{
|
||||
qse_mbs_del (proxy->reqfwdbuf, 0, n);
|
||||
if (QSE_MBS_LEN(proxy->reqfwdbuf) <= 0)
|
||||
{
|
||||
if (proxy->req == QSE_NULL) goto done;
|
||||
else task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@WRITE TO PROXY FAILED\n"));
|
||||
/* TODO: logging ... */
|
||||
proxy->reqfwderr = 1;
|
||||
proxy->reqflags |= PROXY_REQ_FWDERR;
|
||||
qse_mbs_clear (proxy->reqfwdbuf);
|
||||
if (proxy->req)
|
||||
{
|
||||
@ -3189,17 +3277,21 @@ qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@WRITE TO PROXY FAILED\n"));
|
||||
* in proxy_snatch_client_input() triggered by
|
||||
* qse_htre_discardcontent() */
|
||||
}
|
||||
|
||||
task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (proxy->req == QSE_NULL)
|
||||
{
|
||||
done:
|
||||
/* there is nothing to read from the client side and
|
||||
* there is nothing more to forward in the forwarding buffer.
|
||||
* clear the relay and write triggers.
|
||||
* clear the read and write triggers.
|
||||
*/
|
||||
qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO PROXY\n"));
|
||||
task->trigger[2].mask = 0;
|
||||
task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */
|
||||
task->trigger[2].mask = 0; /* client-side */
|
||||
}
|
||||
}
|
||||
|
||||
@ -3233,19 +3325,19 @@ len = 1024;
|
||||
proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
|
||||
if (proxy->reqfwdbuf == QSE_NULL) goto oops;
|
||||
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqmethodname(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqpath(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqmethodname(arg->req)) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqpath(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
|
||||
if (qse_htre_getqparam(arg->req))
|
||||
{
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("?")) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqparam(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("?")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqparam(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
}
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1) goto oops;
|
||||
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
|
||||
if (qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
|
||||
qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
|
||||
|
||||
proxy->resflags |= PROXY_RES_AWAIT_RESHDR;
|
||||
if ((arg->req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
|
||||
@ -3259,20 +3351,20 @@ len = 1024;
|
||||
if (arg->req->state & QSE_HTRE_DISCARDED)
|
||||
{
|
||||
/* no content to add */
|
||||
/*if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: 0\r\n")) == (qse_size_t)-1) goto oops;*/
|
||||
|
||||
/* i don't also add chunk traiers if the
|
||||
if ((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) ||
|
||||
(arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
/* i don't add chunk traiers if the
|
||||
* request content has been discarded */
|
||||
|
||||
/* end of header */
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: 0\r\n\r\n")) == (qse_size_t)-1) goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
|
||||
}
|
||||
}
|
||||
else if (arg->req->state & QSE_HTRE_COMPLETED)
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
|
||||
len = qse_htre_getcontentlen(arg->req);
|
||||
|
||||
if (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
|
||||
{
|
||||
/* add trailers if any */
|
||||
@ -3280,6 +3372,12 @@ len = 1024;
|
||||
arg->req, proxy_capture_client_trailer, proxy) <= -1) goto oops;
|
||||
}
|
||||
|
||||
len = qse_htre_getcontentlen(arg->req);
|
||||
if (len > 0 || (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) ||
|
||||
(arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
|
||||
qse_fmtuintmaxtombs (
|
||||
buf, QSE_COUNTOF(buf), len,
|
||||
10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
@ -3297,6 +3395,11 @@ len = 1024;
|
||||
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
|
||||
}
|
||||
}
|
||||
else if (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
@ -3321,9 +3424,12 @@ len = 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if this request is not chunked nor not length based,
|
||||
* the state should be QSE_HTRE_COMPLETED. so only a
|
||||
* chunked request should reach here */
|
||||
QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
|
||||
|
||||
proxy->reqflags |= PROXY_REQ_CHUNKED;
|
||||
proxy->reqflags |= PROXY_REQ_FWDCHUNKED;
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 /* end of header */) goto oops;
|
||||
|
||||
@ -3332,12 +3438,13 @@ len = 1024;
|
||||
{
|
||||
qse_mchar_t buf[64];
|
||||
|
||||
ptr = qse_htre_getcontentptr(arg->req);
|
||||
qse_fmtuintmaxtombs (
|
||||
buf, QSE_COUNTOF(buf), len,
|
||||
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
|
||||
-1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
ptr = qse_htre_getcontentptr(arg->req);
|
||||
|
||||
/* chunk length and chunk content */
|
||||
if (qse_mbs_cat (proxy->reqfwdbuf, buf) == (qse_size_t)-1 ||
|
||||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
|
||||
@ -3402,17 +3509,20 @@ static int task_main_proxy_5 (
|
||||
qse_ssize_t n;
|
||||
|
||||
//QSE_ASSERT (proxy->pio_inited);
|
||||
qse_printf (QSE_T("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
|
||||
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
|
||||
{
|
||||
/* if the client side is readable */
|
||||
proxy_forward_client_input_to_peer (httpd, task, 0);
|
||||
}
|
||||
else if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)
|
||||
{
|
||||
/* if the peer side is writable */
|
||||
proxy_forward_client_input_to_peer (httpd, task, 1);
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("task_main_proxy_5\n"));
|
||||
if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||
|
||||
(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
|
||||
{
|
||||
@ -3621,7 +3731,9 @@ static int task_main_proxy_2 (
|
||||
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
|
||||
int http_errnum = 0;
|
||||
|
||||
qse_printf (QSE_T("task_main_proxy_2....\n"));
|
||||
qse_printf (QSE_T("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"),
|
||||
task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
|
||||
|
||||
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
|
||||
{
|
||||
proxy_forward_client_input_to_peer (httpd, task, 0);
|
||||
@ -3740,7 +3852,13 @@ qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n"));
|
||||
|
||||
proxy->buflen += n;
|
||||
|
||||
qse_printf (QSE_T("#####PROXY FEEDING %d [%.*hs]\n"), (int)proxy->buflen, (int)proxy->buflen, proxy->buf);
|
||||
qse_printf (QSE_T("#####PROXY FEEDING %d [\n"), (int)proxy->buflen);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < proxy->buflen; i++) qse_printf (QSE_T("%hc"), proxy->buf[i]);
|
||||
}
|
||||
qse_printf (QSE_T("]\n"));
|
||||
|
||||
if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1)
|
||||
{
|
||||
/* TODO: logging */
|
||||
@ -3829,6 +3947,7 @@ qse_printf (QSE_T("task_main_proxy_1.... ERROR \n"));
|
||||
if (n >= 1)
|
||||
{
|
||||
proxy->peer_status |= PROXY_PEER_CONNECTED;
|
||||
qse_printf (QSE_T("FINALLY connected to peer ...............................\n"));
|
||||
|
||||
if (proxy->req)
|
||||
{
|
||||
@ -3838,13 +3957,16 @@ qse_printf (QSE_T("task_main_proxy_1.... ERROR \n"));
|
||||
task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
|
||||
{
|
||||
/* forward the initial part of the input to the peer */
|
||||
proxy_forward_client_input_to_peer (httpd, task, 0);
|
||||
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
|
||||
{
|
||||
/* there are still more to forward in the buffer
|
||||
* request the task invocation when the peer
|
||||
* is writable */
|
||||
task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
|
||||
}
|
||||
}
|
||||
qse_printf (QSE_T("FINALLY connected to peer ...............................\n"));
|
||||
task->main = task_main_proxy_2;
|
||||
}
|
||||
}
|
||||
@ -3969,4 +4091,16 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
qse_httpd_task_t* qse_httpd_entaskconnect (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_nwad_t* nwad,
|
||||
qse_htre_t* req)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -46,6 +46,7 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd)
|
||||
#define DEFAULT_PORT 80
|
||||
#define DEFAULT_SECURE_PORT 443
|
||||
|
||||
/* client->status */
|
||||
#define CLIENT_BAD (1 << 0)
|
||||
#define CLIENT_READY (1 << 1)
|
||||
#define CLIENT_SECURE (1 << 2)
|
||||
@ -531,7 +532,9 @@ static int activate_servers (qse_httpd_t* httpd)
|
||||
{
|
||||
if (httpd->cbs->server.open (httpd, server) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("FAILED TO ACTIVATE SERVER....\n"));
|
||||
qse_char_t buf[64];
|
||||
qse_nwadtostr (&server->nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL);
|
||||
qse_printf (QSE_T("FAILED TO ACTIVATE SERVER....[%s]\n"), buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -690,9 +693,10 @@ qse_printf (QSE_T("Error: failed to read from a client %d\n"), client->handle.i)
|
||||
else if (m == 0)
|
||||
{
|
||||
qse_printf (QSE_T("Debug: connection closed %d - errno %d\n"), client->handle.i, errno);
|
||||
if (client->task.head)
|
||||
if (client->task.head && client->htrd->clean)
|
||||
{
|
||||
/* there is still more tasks to finish */
|
||||
/* there is still more tasks to finish and
|
||||
* http reader is not waiting for any more feeds. */
|
||||
client->status |= CLIENT_MUTE;
|
||||
return 0;
|
||||
}
|
||||
|
@ -335,7 +335,20 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
||||
/* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the
|
||||
* address size for AF_INET. */
|
||||
/*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/
|
||||
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)
|
||||
{
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (errno == EADDRINUSE && addr.ss_family == AF_INET6)
|
||||
{
|
||||
int on = 1;
|
||||
setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
|
||||
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1) goto oops;
|
||||
}
|
||||
else goto oops;
|
||||
#else
|
||||
goto oops;
|
||||
#endif
|
||||
}
|
||||
if (listen (fd, 10) <= -1) goto oops;
|
||||
|
||||
flag = fcntl (fd, F_GETFL);
|
||||
@ -1084,6 +1097,7 @@ if (qse_htre_getcontentlen(req) > 0)
|
||||
if (peek)
|
||||
{
|
||||
/* cgi */
|
||||
#if 0
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
|
||||
{
|
||||
qse_printf (QSE_T("chunked cgi... delaying until contents are received\n"));
|
||||
@ -1095,7 +1109,13 @@ qse_printf (QSE_T("chunked cgi... delaying until contents are received\n"));
|
||||
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
#endif
|
||||
}
|
||||
else if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))
|
||||
else
|
||||
#endif
|
||||
|
||||
/*if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))*/
|
||||
if (method == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
task = qse_httpd_entaskerror (
|
||||
@ -1110,6 +1130,7 @@ qse_printf (QSE_T("chunked cgi... delaying until contents are received\n"));
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
/* to support the chunked request,
|
||||
@ -1122,6 +1143,7 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if (dot && qse_mbscmp (dot, QSE_MT(".nph")) == 0)
|
||||
@ -1285,16 +1307,28 @@ oops:
|
||||
static int peek_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
//return process_request (httpd, client, req, 1);
|
||||
if (memcmp (&client->local_addr, &client->orgdst_addr, sizeof(client->orgdst_addr)) == 0)
|
||||
{
|
||||
return process_request (httpd, client, req, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return proxy_request (httpd, client, req, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
||||
{
|
||||
//return process_request (httpd, client, req, 0);
|
||||
if (memcmp (&client->local_addr, &client->orgdst_addr, sizeof(client->orgdst_addr)) == 0)
|
||||
{
|
||||
return process_request (httpd, client, req, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return proxy_request (httpd, client, req, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user