diff --git a/qse/include/qse/net/htrd.h b/qse/include/qse/net/htrd.h index 2bd316bf..dadb70c0 100644 --- a/qse/include/qse/net/htrd.h +++ b/qse/include/qse/net/htrd.h @@ -74,6 +74,8 @@ struct qse_htrd_t { struct { + int flags; + int crlf; /* crlf status */ qse_size_t plen; /* raw request length excluding crlf */ qse_size_t need; /* number of octets needed for contents */ @@ -86,8 +88,7 @@ struct qse_htrd_t } chunk; } s; /* state */ - - /* buffers needed to for processing a request */ + /* buffers needed for processing a request */ struct { qse_htob_t raw; /* buffer to hold raw octets */ @@ -163,8 +164,13 @@ int qse_htrd_feed ( qse_size_t len /**< number of octets */ ); -int qse_htrd_read ( - qse_htrd_t* htrd /**< htrd */ +/** + * The qse_htrd_halt() function indicates the end of feeeding + * if the current response should be processed until the + * connection is closed. + */ +int qse_htrd_halt ( + qse_htrd_t* htrd ); int qse_htrd_scanqparam ( diff --git a/qse/include/qse/net/htre.h b/qse/include/qse/net/htre.h index e801b114..07460c1b 100644 --- a/qse/include/qse/net/htre.h +++ b/qse/include/qse/net/htre.h @@ -81,10 +81,11 @@ struct qse_htre_t /* special attributes derived from the header */ struct { - int chunked; - int content_length_set; +#define QSE_HTRE_ATTR_CHUNKED (1 << 0) +#define QSE_HTRE_ATTR_LENGTH (1 << 1) +#define QSE_HTRE_ATTR_KEEPALIVE (1 << 2) + int flags; qse_size_t content_length; - int keepalive; const qse_mchar_t* expect; const qse_mchar_t* status; } attr; diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index 247ec259..b75eb93f 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -26,6 +26,8 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd) static const qse_mchar_t NUL = QSE_MT('\0'); +#define CONSUME_UNTIL_CLOSE (1 << 0) + static QSE_INLINE int is_whspace_octet (qse_mchar_t c) { return c == QSE_MT(' ') || c == QSE_MT('\t') || c == QSE_MT('\r') || c == QSE_MT('\n'); @@ -425,7 +427,7 @@ static qse_mchar_t* parse_initial_line ( if (htrd->re.version.major > 1 || (htrd->re.version.major == 1 && htrd->re.version.minor >= 1)) { - htrd->re.attr.keepalive = 1; + htrd->re.attr.flags |= QSE_HTRE_ATTR_KEEPALIVE; } return ++p; @@ -469,7 +471,7 @@ static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair) "close", 5); if (n == 0) { - htrd->re.attr.keepalive = 0; + htrd->re.attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; return 0; } @@ -478,7 +480,7 @@ static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair) "keep-alive", 10); if (n == 0) { - htrd->re.attr.keepalive = 1; + htrd->re.attr.flags |= QSE_HTRE_ATTR_KEEPALIVE; return 0; } @@ -494,7 +496,7 @@ static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair) if (htrd->re.version.major < 1 || (htrd->re.version.major == 1 && htrd->re.version.minor <= 0)) { - htrd->re.attr.keepalive = 0; + htrd->re.attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; } return 0; } @@ -533,7 +535,7 @@ static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair) return -1; } - if (htrd->re.attr.chunked && len > 0) + if ((htrd->re.attr.flags & QSE_HTRE_ATTR_CHUNKED) && len > 0) { /* content-length is greater than 0 * while transfer-encoding: chunked is specified. */ @@ -541,8 +543,8 @@ static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair) return -1; } + htrd->re.attr.flags |= QSE_HTRE_ATTR_LENGTH; htrd->re.attr.content_length = len; - htrd->re.attr.content_length_set = 1; return 0; } @@ -567,13 +569,13 @@ static int capture_transfer_encoding (qse_htrd_t* htrd, qse_htb_pair_t* pair) if (n == 0) { /* if (htrd->re.attr.content_length > 0) */ - if (htrd->re.attr.content_length_set) + if (htrd->re.attr.flags & QSE_HTRE_ATTR_LENGTH) { /* both content-length and 'transfer-encoding: chunked' are specified. */ goto badre; } - htrd->re.attr.chunked = 1; + htrd->re.attr.flags |= QSE_HTRE_ATTR_CHUNKED; return 0; } @@ -1111,8 +1113,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) /* reset the raw request length */ htrd->fed.s.plen = 0; - if (parse_initial_line_and_headers (htrd, req, ptr - req) <= -1) - return -1; + if (parse_initial_line_and_headers (htrd, req, ptr - req) <= -1) return -1; /* compelete request header is received */ header_completed_during_this_feed = 1; @@ -1149,10 +1150,10 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) } /* carry on processing content body fed together with the header */ - if (htrd->re.attr.chunked) + if (htrd->re.attr.flags & QSE_HTRE_ATTR_CHUNKED) { /* transfer-encoding: chunked */ - QSE_ASSERT (!htrd->re.attr.content_length_set); + QSE_ASSERT (!(htrd->re.attr.flags & QSE_HTRE_ATTR_LENGTH)); dechunk_start: htrd->fed.s.chunk.phase = GET_CHUNK_LEN; @@ -1195,7 +1196,31 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) { /* we need to read as many octets as * Content-Length */ - htrd->fed.s.need = htrd->re.attr.content_length; + if ((htrd->option & QSE_HTRD_RESPONSE) && + !(htrd->re.attr.flags & QSE_HTRE_ATTR_LENGTH) && + !(htrd->re.attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) + { + /* for a response, no content-length and + * no chunk are specified and 'connection' + * is to close. i must read until the + * connection is closed. however, there isn't + * any good way to know when to stop from + * within this function. so the caller + * can call qse_htrd_halt() for this. */ + + /* set this to the maximum in a type safe way + * assuming it's unsigned. the problem of + * the current implementation is that + * it can't receive more than */ + htrd->fed.s.need = 0; + htrd->fed.s.need = ~htrd->fed.s.need; + htrd->fed.s.flags |= CONSUME_UNTIL_CLOSE; + } + else + { + htrd->fed.s.need = htrd->re.attr.content_length; + } + } if (htrd->fed.s.need > 0) @@ -1209,7 +1234,17 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) { /* the data is not as large as needed */ if (push_content (htrd, ptr, avail) <= -1) return -1; - htrd->fed.s.need -= avail; + + if (!(htrd->fed.s.flags & CONSUME_UNTIL_CLOSE)) + { + /* i don't decrement htrd->fed.s.need + * if i should read until connection is closed. + * well, unless set your own callback, + * push_content() above will fail + * if too much has been received already */ + htrd->fed.s.need -= avail; + } + /* we didn't get a complete content yet */ goto feedme_more; } @@ -1218,7 +1253,8 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) /* we got all or more than needed */ if (push_content (htrd, ptr, htrd->fed.s.need) <= -1) return -1; ptr += htrd->fed.s.need; - htrd->fed.s.need = 0; + if (!(htrd->fed.s.flags & CONSUME_UNTIL_CLOSE)) + htrd->fed.s.need = 0; } } @@ -1361,6 +1397,33 @@ feedme_more: return 0; } +int qse_htrd_halt (qse_htrd_t* htrd) +{ + if (htrd->fed.s.flags & CONSUME_UNTIL_CLOSE) + { + qse_htre_completecontent (&htrd->re); + + if (htrd->recbs->handle) + { + int n; + htrd->errnum = QSE_HTRD_ENOERR; + n = htrd->recbs->handle (htrd, &htrd->re); + if (n <= -1) + { + if (htrd->errnum == QSE_HTRD_ENOERR) + htrd->errnum = QSE_HTRD_ERECBS; + /* need to clear request on error? + clear_feed (htrd); */ + return -1; + } + } + + clear_feed (htrd); + } + + return 0; +} + #if 0 int qse_htrd_scanqparam (qse_htrd_t* htrd, const qse_mcstr_t* cstr) { diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index e8742952..73f6e7ee 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -36,6 +36,11 @@ #define MAX_SEND_SIZE 4096 +/* TODO: + * many functions in this file use qse_size_t. + * so the size data transfers is limited by this type. + * break this barrier... */ + static qse_http_version_t http_v11 = { 1, 1 }; /*------------------------------------------------------------------------*/ @@ -400,7 +405,8 @@ qse_httpd_task_t* qse_httpd_entaskerror ( { return entask_error ( httpd, client, pred, code, - qse_htre_getversion(req), req->attr.keepalive); + qse_htre_getversion(req), + (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); } /*------------------------------------------------------------------------*/ @@ -431,7 +437,7 @@ qse_httpd_task_t* qse_httpd_entaskauth ( httpd, client, pred, QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nConnection: %s\r\nWWW-Authenticate: Basic realm=\"%s\"\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"), version->major, version->minor, - (req->attr.keepalive? QSE_MT("keep-alive"): QSE_MT("close")), + ((req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")), realm, (unsigned long)qse_mbslen(lmsg) + 4, lmsg); } @@ -1196,7 +1202,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); data.path = path; data.version = *qse_htre_getversion(req); - data.keepalive = req->attr.keepalive; + data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); tmp = qse_htre_getheaderval(req, QSE_MT("Range")); if (tmp) @@ -1414,7 +1420,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) } keepalive = cgi->keepalive; - if (req->attr.content_length_set) + if (req->attr.flags & QSE_HTRE_ATTR_LENGTH) { cgi->resflags |= CGI_RES_SCRIPT_LENGTH; cgi->script_output_length = req->attr.content_length; @@ -1805,7 +1811,7 @@ static int task_init_cgi ( qse_mbscpy ((qse_mchar_t*)(cgi + 1), arg->path); cgi->path = (qse_mchar_t*)(cgi + 1); cgi->version = *qse_htre_getversion(arg->req); - cgi->keepalive = arg->req->attr.keepalive; + cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); cgi->nph = arg->nph; cgi->req = QSE_NULL; @@ -1826,7 +1832,7 @@ static int task_init_cgi ( } if (!(arg->req->state & QSE_HTRE_COMPLETED) && - !arg->req->attr.content_length_set) + !(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)) { /* if the request is not completed and doesn't have * content-length set, it's not really possible to @@ -1859,8 +1865,9 @@ static int task_init_cgi ( * should reach here. if content-length is set * the length should match len. */ QSE_ASSERT (len > 0); - QSE_ASSERT (!arg->req->attr.content_length_set || - (arg->req->attr.content_length_set && arg->req->attr.content_length == len)); + QSE_ASSERT (!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || + ((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) && + arg->req->attr.content_length == len)); cgi->reqflags |= CGI_REQ_GOTALL; content_length = len; } @@ -1885,7 +1892,7 @@ static int task_init_cgi ( cgi->req = arg->req; qse_htre_setconcb (cgi->req, cgi_snatch_client_input, task); - QSE_ASSERT (arg->req->attr.content_length_set); + QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH); content_length = arg->req->attr.content_length; } } @@ -2663,7 +2670,6 @@ static int proxy_snatch_peer_output ( * the client should be chunked */ QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK); - /* TODO: better condition for compaction??? */ if (proxy->res_pending > 0 && proxy->res_consumed > 0) { @@ -2740,6 +2746,7 @@ 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; } @@ -2772,17 +2779,9 @@ qse_printf (QSE_T("10000000000000000000000000000 CONTINUE 1000000000000000000000 proxy->resflags |= PROXY_RES_RECEIVED_RESHDR; qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n")); - /* begin initial line */ - if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1) return -1; - if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1;; - if (qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1) return -1; - if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1; - if (qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1) return -1; - if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; - /* end initial line */ keepalive = proxy->keepalive; - if (res->attr.content_length_set) + if (res->attr.flags & QSE_HTRE_ATTR_LENGTH) { /* the response from the peer is length based */ proxy->resflags |= PROXY_RES_PEER_LENGTH; @@ -2797,13 +2796,7 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n")); /* chunk response when writing back to client */ proxy->resflags |= PROXY_RES_CLIENT_CHUNK; - if (qse_mbs_cat (proxy->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) - { - proxy->httpd->errnum = QSE_HTTPD_ENOMEM; - return -1; - } - - if (res->attr.chunked) + if (res->attr.flags & QSE_HTRE_ATTR_CHUNKED) { /* mark the peer output is chunked */ proxy->resflags |= PROXY_RES_PEER_CHUNK; @@ -2822,13 +2815,42 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n")); proxy->resflags |= PROXY_RES_CLIENT_DISCON; if (qse_httpd_entaskdisconnect (proxy->httpd, xtn->client, xtn->task) == QSE_NULL) return -1; - if (res->attr.chunked) + if (res->attr.flags & QSE_HTRE_ATTR_CHUNKED) proxy->resflags |= PROXY_RES_PEER_CHUNK; else proxy->resflags |= PROXY_RES_PEER_CLOSE; } } + /* begin initial line */ + if (proxy->resflags & PROXY_RES_CLIENT_CHUNK && + qse_comparehttpversions (&res->version, &http_v11) < 0) + { + qse_mchar_t vbuf[64]; + snprintf (vbuf, QSE_COUNTOF(vbuf), QSE_MT("HTTP/%d.%d"), + (int)proxy->version.major, (int)proxy->version.minor); + if (qse_mbs_cat (proxy->res, vbuf) == (qse_size_t)-1) return -1; + } + else + { + if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1) return -1; + } + if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1;; + if (qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + /* end initial line */ + + if (proxy->resflags & PROXY_RES_CLIENT_CHUNK) + { + if (qse_mbs_cat (proxy->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) + { + proxy->httpd->errnum = QSE_HTTPD_ENOMEM; + return -1; + } + } + if (qse_mbs_cat (proxy->res, (keepalive? QSE_MT("Connection: keep-alive\r\n"): QSE_MT("Connection: close\r\n"))) == (qse_size_t)-1) { proxy->httpd->errnum = QSE_HTTPD_ENOMEM; @@ -2883,6 +2905,7 @@ qse_printf (QSE_T("PROXY PEER FUCKED - RETURNING TOO MUCH...\n")); /* arrange to store further contents received to proxy->res */ qse_htre_setconcb (res, proxy_snatch_peer_output, xtn->task); } +qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY OK\n")); } proxy->res_pending = QSE_MBS_LEN(proxy->res) - proxy->res_consumed; @@ -3000,7 +3023,7 @@ static int task_init_proxy ( proxy->httpd = httpd; proxy->version = *qse_htre_getversion(arg->req); - proxy->keepalive = arg->req->attr.keepalive; + proxy->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); proxy->peer.nwad = arg->peer_nwad; proxy->req = QSE_NULL; @@ -3051,7 +3074,7 @@ len = 1024; } if (!(arg->req->state & QSE_HTRE_COMPLETED) && - !arg->req->attr.content_length_set) + !(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)) { /* if the request is not completed and doesn't have * content-length set, it's not really possible to @@ -3074,8 +3097,9 @@ len = 1024; * should reach here. if content-length is set * the length should match len. */ QSE_ASSERT (len > 0); - QSE_ASSERT (!arg->req->attr.content_length_set || - (arg->req->attr.content_length_set && arg->req->attr.content_length == len)); + QSE_ASSERT (!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || + ((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) && + arg->req->attr.content_length == len)); } else { @@ -3093,7 +3117,7 @@ len = 1024; * htrd calls invokes this callback. */ proxy->req = arg->req; qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task); - QSE_ASSERT (arg->req->attr.content_length_set); + QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH); } } @@ -3449,20 +3473,20 @@ qse_printf (QSE_T("#####PREMATURE EOF FROM PEER\n")); } else { -qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n")); QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK); if (proxy->resflags & PROXY_RES_PEER_CLOSE) { - /* i should compelte the content manually - * since the end of content is indicated by - * close in this case. */ - qse_htre_completecontent (&proxy->peer_htrd->re); + /* i should stop the reader manually since the + * end of content is indicated by close in this + * case. call qse_htrd_halt() for this. */ + qse_htrd_halt (proxy->peer_htrd); task->main = task_main_proxy_3; task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } +qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n")); return -1; } } @@ -3550,6 +3574,7 @@ static int task_main_proxy_1 ( /* improve error conversion */ if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; else if (httpd->errnum == QSE_HTTPD_EACCES) http_errnum = 403; +qse_printf (QSE_T("task_main_proxy_1.... ERROR \n")); goto oops; } @@ -3589,11 +3614,13 @@ static int task_main_proxy ( proxy_peer_htrd_xtn_t* xtn; int http_errnum = 500; int n; +qse_printf (QSE_T("task_main_proxy....\n")); if (proxy->init_failed) goto oops; /* set up a http reader to read a response from the peer */ - proxy->peer_htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t)); + proxy->peer_htrd = qse_htrd_open ( + httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t)); if (proxy->peer_htrd == QSE_NULL) goto oops; xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd); xtn->proxy = proxy; @@ -3614,6 +3641,7 @@ static int task_main_proxy ( /* TODO: translate error code to http error... */ if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; else if (httpd->errnum == QSE_HTTPD_EACCES) http_errnum = 403; +qse_printf (QSE_T("caanot open peer....\n")); goto oops; } diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 3696eac2..4ac6a2c1 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -302,8 +302,9 @@ static qse_httpd_client_t* new_client ( client->status = tmpl->status; client->handle = tmpl->handle; client->handle2 = tmpl->handle2; - client->local_addr = tmpl->local_addr; client->remote_addr = tmpl->remote_addr; + client->local_addr = tmpl->local_addr; + client->orgdst_addr = tmpl->orgdst_addr; xtn = (htrd_xtn_t*)qse_htrd_getxtn (client->htrd); xtn->httpd = httpd; @@ -458,10 +459,11 @@ qse_printf (QSE_T("MUX ADDHND CLIENT READ %d\n"), client->handle.i); { /* TODO: proper logging */ -qse_char_t tmp[128], tmp2[128]; +qse_char_t tmp[128], tmp2[128], tmp3[128]; qse_nwadtostr (&client->local_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOSTR_ALL); -qse_nwadtostr (&client->remote_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); -qse_printf (QSE_T("connection %d accepted %s from %s\n"), client->handle.i, tmp, tmp2); +qse_nwadtostr (&client->orgdst_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOSTR_ALL); +qse_nwadtostr (&client->remote_addr, tmp3, QSE_COUNTOF(tmp3), QSE_NWADTOSTR_ALL); +qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, tmp, tmp2, tmp3); } } return 0; diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index daf45e78..e74ffdc3 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -141,6 +141,7 @@ static qse_httpd_errnum_t syserr_to_errnum (int e) return QSE_HTTPD_EINVAL; case EACCES: + case ECONNREFUSED: return QSE_HTTPD_EACCES; case ENOENT: @@ -414,12 +415,6 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); } #endif -{ -qse_char_t buf[100]; -qse_nwadtostr (&client->orgdst_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); -qse_printf (QSE_T("ORGDST address : (%s)\n"), buf); -} - client->handle.i = fd; return 0; } @@ -487,7 +482,11 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) if (getsockopt (peer->handle.i, SOL_SOCKET, SO_ERROR, &ret, &len) <= -1) return -1; if (ret == EINPROGRESS) return 0; - if (ret != 0) return -1; + if (ret != 0) + { + qse_httpd_seterrnum (httpd, syserr_to_errnum (ret)); + return -1; + } return 1; /* connection completed */ } @@ -533,8 +532,8 @@ struct mux_t struct { - struct mux_ev_t* ptr; - qse_size_t capa; + struct mux_ev_t** ptr; + qse_size_t capa; } mev; }; @@ -564,7 +563,13 @@ static void mux_close (qse_httpd_t* httpd, void* vmux) { struct mux_t* mux = (struct mux_t*)vmux; if (mux->ee.ptr) qse_httpd_freemem (httpd, mux->ee.ptr); - if (mux->mev.ptr) qse_httpd_freemem (httpd, mux->mev.ptr); + if (mux->mev.ptr) + { + qse_size_t i; + for (i = 0; i < mux->mev.capa; i++) + if (mux->mev.ptr[i]) qse_httpd_freemem (httpd, mux->mev.ptr[i]); + qse_httpd_freemem (httpd, mux->mev.ptr); + } close (mux->fd); qse_httpd_freemem (httpd, mux); } @@ -589,20 +594,33 @@ static int mux_addhnd ( if (handle.i >= mux->mev.capa) { - struct mux_ev_t* tmp; - qse_size_t tmpcapa; + struct mux_ev_t** tmp; + qse_size_t tmpcapa, i; tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN); - tmp = qse_httpd_reallocmem ( + tmp = (struct mux_ev_t**) qse_httpd_reallocmem ( httpd, mux->mev.ptr, QSE_SIZEOF(*mux->mev.ptr) * tmpcapa); if (tmp == QSE_NULL) return -1; + for (i = mux->mev.capa; i < tmpcapa; i++) tmp[i] = QSE_NULL; mux->mev.ptr = tmp; mux->mev.capa = tmpcapa; } + if (mux->mev.ptr[handle.i] == QSE_NULL) + { + /* the location of the data passed to epoll_ctl() + * must not change unless i update the info with epoll() + * whenever there is reallocation. so i simply + * make mux-mev.ptr reallocatable but auctual + * data fixed once allocated. */ + mux->mev.ptr[handle.i] = qse_httpd_allocmem ( + httpd, QSE_SIZEOF(*mux->mev.ptr[handle.i])); + if (mux->mev.ptr[handle.i] == QSE_NULL) return -1; + } + if (mux->ee.len >= mux->ee.capa) { struct epoll_event* tmp; @@ -616,8 +634,7 @@ static int mux_addhnd ( mux->ee.capa = (mux->ee.capa + 1) * 2; } - mev = &mux->mev.ptr[handle.i]; - + mev = mux->mev.ptr[handle.i]; mev->handle = handle; mev->reqmask = mask; mev->cbfun = cbfun; @@ -1070,7 +1087,7 @@ if (qse_htre_getcontentlen(req) > 0) if (peek) { /* cgi */ - if (req->attr.chunked) + if (req->attr.flags & QSE_HTRE_ATTR_CHUNKED) { qse_printf (QSE_T("chunked cgi... delaying until contents are received\n")); #if 0 @@ -1081,10 +1098,9 @@ 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.content_length_set) + else if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH)) { - req->attr.keepalive = 0; + req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; task = qse_httpd_entaskerror ( httpd, client, QSE_NULL, 411, req); /* 411 can't keep alive */ @@ -1101,7 +1117,7 @@ qse_printf (QSE_T("chunked cgi... delaying until contents are received\n")); { /* to support the chunked request, * i need to wait until it's completed and invoke cgi */ - if (req->attr.chunked) + if (req->attr.flags & QSE_HTRE_ATTR_CHUNKED) { qse_printf (QSE_T("Entasking chunked CGI...\n")); task = qse_httpd_entaskcgi ( @@ -1161,7 +1177,7 @@ qse_printf (QSE_T("Entasking chunked CGI...\n")); } } - if (!req->attr.keepalive) + if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) { if (!peek) { @@ -1236,6 +1252,7 @@ qse_printf (QSE_T("Host not included....\n")); { qse_nwad_t nwad; +#if 0 if (qse_nwadequal (&client->local_addr, &client->orgdst_addr)) { //qse_strtonwad (QSE_T("192.168.1.55:9000"), &nwad); @@ -1243,13 +1260,16 @@ qse_printf (QSE_T("Host not included....\n")); } else { +#endif nwad = client->orgdst_addr; +#if 0 } +#endif task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &nwad, req); if (task == QSE_NULL) goto oops; } - if (!req->attr.keepalive) + if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) { if (!peek) {