From 7d8a5ff433229cb067c229a963406786e89c6698 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 30 Mar 2012 06:12:53 +0000 Subject: [PATCH] added more proxy handling code --- qse/include/qse/net/htrd.h | 6 - qse/include/qse/net/htre.h | 81 +++-- qse/lib/net/htrd.c | 104 ++++--- qse/lib/net/htre.c | 24 +- qse/lib/net/httpd-task.c | 598 +++++++++++++++++++++++-------------- qse/samples/net/http01.c | 21 +- 6 files changed, 502 insertions(+), 332 deletions(-) diff --git a/qse/include/qse/net/htrd.h b/qse/include/qse/net/htrd.h index ff510bf2..09c65583 100644 --- a/qse/include/qse/net/htrd.h +++ b/qse/include/qse/net/htrd.h @@ -97,12 +97,6 @@ struct qse_htrd_t void* chl; } fed; - enum - { - QSE_HTRD_RETYPE_Q, - QSE_HTRD_RETYPE_S - } retype; - qse_htre_t re; }; diff --git a/qse/include/qse/net/htre.h b/qse/include/qse/net/htre.h index 8bd172b1..9b72cfea 100644 --- a/qse/include/qse/net/htre.h +++ b/qse/include/qse/net/htre.h @@ -45,12 +45,38 @@ struct qse_htre_t { qse_mmgr_t* mmgr; + enum + { + QSE_HTRE_Q, + QSE_HTRE_S + } type; + /* version */ qse_http_version_t version; + const qse_mchar_t* verstr; /* version string include HTTP/ */ - int qmethod_or_sstatus; - qse_mbs_t qpath_or_smesg; - qse_mbs_t qparam; + union + { + struct + { + struct + { + qse_http_method_t type; + const qse_mchar_t* name; + } method; + const qse_mchar_t* path; + const qse_mchar_t* param; + } q; + struct + { + struct + { + int val; + const qse_mchar_t* str; + } code; + const qse_mchar_t* mesg; + } s; + } u; /* special attributes derived from the header */ struct @@ -79,31 +105,17 @@ struct qse_htre_t #define qse_htre_getversion(re) (&((re)->version)) #define qse_htre_getmajorversion(re) ((re)->version.major) #define qse_htre_getminorversion(re) ((re)->version.minor) -#define qse_htre_setversion(re,v) QSE_BLOCK((re)->version = *(v);) +#define qse_htre_getverstr(re) ((re)->verstr) -#define qse_htre_getqmethod(re) ((re)->qmethod_or_sstatus) -#define qse_htre_setqmethod(re,v) QSE_BLOCK((re)->qmethod_or_sstatus=(v);) +#define qse_htre_getqmethodtype(re) ((re)->u.q.method.type) +#define qse_htre_getqmethodname(re) ((re)->u.q.method.name) -#define qse_htre_getsstatus(re) ((re)->qmethod_or_sstatus) -#define qse_htre_setsstatus(re,v) QSE_BLOCK((re)->qmethod_or_sstatus=(v);) +#define qse_htre_getqpath(re) ((re)->u.q.path) +#define qse_htre_getqparam(re) ((re)->u.q.param) -#define qse_htre_getqpath(re) (&(re)->qpath_or_smesg) -#define qse_htre_getqpathxstr(re) QSE_MBS_XSTR(&(re)->qpath_or_smesg) -#define qse_htre_getqpathcstr(re) QSE_MBS_CSTR(&(re)->qpath_or_smesg) -#define qse_htre_getqpathptr(re) QSE_MBS_PTR(&(re)->qpath_or_smesg) -#define qse_htre_getqpathlen(re) QSE_MBS_LEN(&(re)->qpath_or_smesg) - -#define qse_htre_getqparam(re) (&(re)->qparam) -#define qse_htre_getqparamxstr(re) QSE_MBS_XSTR(&(re)->qparam) -#define qse_htre_getqparamcstr(re) QSE_MBS_CSTR(&(re)->qparam) -#define qse_htre_getqparamptr(re) QSE_MBS_PTR(&(re)->qparam) -#define qse_htre_getqparamlen(re) QSE_MBS_LEN(&(re)->qparam) - -#define qse_htre_getsmessage(re) (&(re)->qpath_or_smesg) -#define qse_htre_getsmessagexstr(re) QSE_MBS_XSTR(&(re)->qpath_or_smesg) -#define qse_htre_getsmessagecstr(re) QSE_MBS_CSTR(&(re)->qpath_or_smesg) -#define qse_htre_getsmessageptr(re) QSE_MBS_PTR(&(re)->qpath_or_smesg) -#define qse_htre_getsmessagelen(re) QSE_MBS_LEN(&(re)->qpath_or_smesg) +#define qse_htre_getscodeval(re) ((re)->u.s.code.val) +#define qse_htre_getscodestr(re) ((re)->u.s.code.str) +#define qse_htre_getsmesg(re) ((re)->u.s.mesg) #define qse_htre_getcontent(re) (&(re)->content) #define qse_htre_getcontentxstr(re) QSE_MBS_XSTR(&(re)->content) @@ -111,21 +123,6 @@ struct qse_htre_t #define qse_htre_getcontentptr(re) QSE_MBS_PTR(&(re)->content) #define qse_htre_getcontentlen(re) QSE_MBS_LEN(&(re)->content) -#define qse_htre_setqpathfromcstr(re,v) \ - qse_htre_setstrfromcstr((re),qse_htre_getqpath(re),(v)) -#define qse_htre_setqpathfromxstr(re,v) \ - qse_htre_setstrfromxstr((re),qse_htre_getqpath(re),(v)) - -#define qse_htre_setqparamfromcstr(re,v) \ - qse_htre_setstrfromcstr((re),qse_htre_getqparam(re),(v)) -#define qse_htre_setqparamfromxstr(re,v) \ - qse_htre_setstrfromxstr((re),qse_htre_getqparam(re),(v)) - -#define qse_htre_setsmessagefromcstr(re,v) \ - qse_htre_setstrfromcstr((re),qse_htre_getsmessage(re),(v)) -#define qse_htre_setsmessagefromxstr(re,v) \ - qse_htre_setstrfromxstr((re),qse_htre_getsmessage(re),(v)) - typedef int (*qse_htre_header_walker_t) ( qse_htre_t* re, const qse_mchar_t* key, @@ -204,10 +201,6 @@ void qse_htre_setconcb ( void* ctx ); -const qse_mchar_t* qse_htre_getqmethodname ( - const qse_htre_t* re -); - #ifdef __cplusplus } #endif diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index 692a5dc4..4ba6e1c5 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -223,21 +223,28 @@ static qse_mchar_t* parse_initial_line ( do { p++; } while (is_upalpha_octet(*p)); tmp.len = p - tmp.ptr; - htrd->retype = QSE_HTRD_RETYPE_Q; + htrd->re.type = QSE_HTRE_Q; if (htrd->option & QSE_HTRD_REQUEST) { - qse_htre_setqmethod (&htrd->re, qse_mcstrtohttpmethod (&tmp)); + /* method name must be followed by space */ + if (!is_space_octet(*p)) goto badre; + + *p = QSE_MT('\0'); /* null-terminate the method name */ + + htrd->re.u.q.method.type = qse_mcstrtohttpmethod (&tmp); + htrd->re.u.q.method.name = tmp.ptr; } else if ((htrd->option & QSE_HTRD_RESPONSE) && qse_mbsxcmp (tmp.ptr, tmp.len, QSE_MT("HTTP")) == 0) { /* it begins with HTTP. it may be a response */ - htrd->retype = QSE_HTRD_RETYPE_S; + htrd->re.type = QSE_HTRE_S; } else goto badre; - if (htrd->retype == QSE_HTRD_RETYPE_S) + if (htrd->re.type == QSE_HTRE_S) { + /* response */ int n, status; if (*p == QSE_MT('/') && p[1] != QSE_MT('\0') && p[2] == QSE_MT('.')) @@ -254,15 +261,19 @@ static qse_mchar_t* parse_initial_line ( } else goto badre; - /* htrd version must be followed by space */ + /* version must be followed by space */ if (!is_space_octet(*p)) goto badre; + *p = QSE_MT('\0'); /* null-terminate version string */ + htrd->re.verstr = tmp.ptr; + /* skip spaces */ do p++; while (is_space_octet(*p)); n = digit_to_num(*p); if (n <= -1) goto badre; + tmp.ptr = p; status = 0; do { @@ -271,37 +282,39 @@ static qse_mchar_t* parse_initial_line ( } while ((n = digit_to_num(*p)) >= 0); - qse_htre_setsstatus (&htrd->re, status); + if (!is_space_octet(*p)) goto badre; + *p = QSE_MT('\0'); /* null-terminate the status code */ - /* i don't treat the following weird messages as bad message + htrd->re.u.s.code.val = status; + htrd->re.u.s.code.str = tmp.ptr; + + /* i don't treat the following weird messages as bad message: * no status message follows the status code - * no space between the status code and the status message */ /* skip spaces */ - while (is_space_octet(*p)) p++; + do p++; while (is_space_octet(*p)); tmp.ptr = p; - while (*p != QSE_MT('\0') && *p != QSE_MT('\n')) p++; - tmp.len = p - tmp.ptr; - - if (qse_htre_setsmessagefromcstr (&htrd->re, &tmp) <= -1) goto outofmem; - - /* adjust Connection: Keep-Alive for HTTP 1.1 or later */ - if (htrd->re.version.major > 1 || - (htrd->re.version.major == 1 && htrd->re.version.minor >= 1)) + tmp.len = 0; + while (*p != QSE_MT('\0') && *p != QSE_MT('\n')) { - htrd->re.attr.keepalive = 1; + if (!is_space_octet(*p)) tmp.len = p - tmp.ptr + 1; + p++; } + + /* if the line does not end with a new line, it is a bad request */ + if (*p != QSE_T('\n')) goto badre; + + /* null-terminate the message */ + ((qse_mchar_t*)tmp.ptr)[tmp.len] = QSE_MT('\0'); + htrd->re.u.s.mesg = tmp.ptr; } else { qse_mchar_t* out; qse_mcstr_t param; - /* method name must be followed by space */ - if (!is_space_octet(*p)) goto badre; - /* skip spaces */ do p++; while (is_space_octet(*p)); @@ -314,8 +327,8 @@ static qse_mchar_t* parse_initial_line ( { if (*p == QSE_MT('%') && param.ptr == QSE_NULL) { - /* decode percence-encoded charaters in the - * path part. if we're in the parameter string + /* decode percent-encoded charaters in the + * path part. if we're in the parameter string * part, we don't decode them. */ int q = xdigit_to_num(*(p+1)); @@ -339,7 +352,7 @@ static qse_mchar_t* parse_initial_line ( { if (!param.ptr) { - /* ? must be explicit to be a argument instroducer. + /* ? must be explicit to be an argument instroducer. * %3f is just a literal. */ tmp.len = out - tmp.ptr; *out++ = QSE_MT('\0'); /* null-terminate the path part */ @@ -360,15 +373,20 @@ static qse_mchar_t* parse_initial_line ( if (param.ptr) { param.len = out - param.ptr; - if (qse_htre_setqparamfromcstr (&htrd->re, ¶m) <= -1) goto outofmem; + htrd->re.u.q.path = tmp.ptr; + htrd->re.u.q.param = param.ptr; + } + else + { + tmp.len = out - tmp.ptr; + htrd->re.u.q.path = tmp.ptr; + htrd->re.u.q.param = QSE_NULL; } - else tmp.len = out - tmp.ptr; - - if (qse_htre_setqpathfromcstr (&htrd->re, &tmp) <= -1) goto outofmem; /* skip spaces after the url part */ do { p++; } while (is_space_octet(*p)); + tmp.ptr = p; /* check protocol version */ if ((p[0] == 'H' || p[0] == 'h') && (p[1] == 'T' || p[1] == 't') && @@ -388,30 +406,30 @@ static qse_mchar_t* parse_initial_line ( } else goto badre; + tmp.len = p - tmp.ptr; + /* skip trailing spaces on the line */ while (is_space_octet(*p)) p++; - /* adjust Connection: Keep-Alive for HTTP 1.1 or later */ - if (htrd->re.version.major > 1 || - (htrd->re.version.major == 1 && htrd->re.version.minor >= 1)) - { - htrd->re.attr.keepalive = 1; - } + /* if the line does not end with a new line, it is a bad request */ + if (*p != QSE_T('\n')) goto badre; + + ((qse_mchar_t*)tmp.ptr)[tmp.len] = QSE_MT('\0'); + htrd->re.verstr = tmp.ptr; } - /* if the line does not end with a new line, it is a bad request */ - if (*p != QSE_T('\n')) goto badre; - + /* adjust Connection: Keep-Alive for HTTP 1.1 or later */ + if (htrd->re.version.major > 1 || + (htrd->re.version.major == 1 && htrd->re.version.minor >= 1)) + { + htrd->re.attr.keepalive = 1; + } + return ++p; badre: htrd->errnum = QSE_HTRD_EBADRE; return QSE_NULL; - -outofmem: - htrd->errnum = QSE_HTRD_ENOMEM; - return QSE_NULL; - } void qse_htrd_clear (qse_htrd_t* htrd) @@ -1085,7 +1103,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) header_completed_during_this_feed = 1; if (htrd->option & QSE_HTRD_PEEKONLY) { - /* when QSE_HTRD_PEEKONCE is set, + /* when QSE_HTRD_PEEKONLY is set, * the peek callback is invoked once * a complete header is seen. the caller * should not feed more data by calling diff --git a/qse/lib/net/htre.c b/qse/lib/net/htre.c index ad68f0e4..8a989901 100644 --- a/qse/lib/net/htre.c +++ b/qse/lib/net/htre.c @@ -29,16 +29,18 @@ int qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr) if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1; qse_mbs_init (&re->content, mmgr, 0); - qse_mbs_init (&re->qpath_or_smesg, mmgr, 0); - qse_mbs_init (&re->qparam, mmgr, 0); +#if 0 + qse_mbs_init (&re->iniline, mmgr, 0); +#endif return 0; } void qse_htre_fini (qse_htre_t* re) { - qse_mbs_fini (&re->qparam); - qse_mbs_fini (&re->qpath_or_smesg); +#if 0 + qse_mbs_fini (&re->iniline); +#endif qse_mbs_fini (&re->content); qse_htb_fini (&re->hdrtab); } @@ -55,14 +57,17 @@ void qse_htre_clear (qse_htre_t* re) } } + re->state = 0; + QSE_MEMSET (&re->version, 0, QSE_SIZEOF(re->version)); QSE_MEMSET (&re->attr, 0, QSE_SIZEOF(re->attr)); qse_htb_clear (&re->hdrtab); qse_mbs_clear (&re->content); - qse_mbs_clear (&re->qpath_or_smesg); - qse_mbs_clear (&re->qparam); +#if 0 + qse_mbs_clear (&re->iniline); +#endif re->state = 0; } @@ -134,8 +139,7 @@ int qse_htre_addcontent ( else { /* if the callback is not set, the contents goes to the internal buffer */ - if (qse_mbs_ncat (&re->content, ptr, len) == (qse_size_t)-1) - return -1; + if (qse_mbs_ncat (&re->content, ptr, len) == (qse_size_t)-1) return -1; } return 1; /* added successfully */ @@ -203,7 +207,3 @@ void qse_htre_setconcb (qse_htre_t* re, qse_htre_concb_t concb, void* ctx) re->concb_ctx = ctx; } -const qse_mchar_t* qse_htre_getqmethodname (const qse_htre_t* re) -{ - return qse_httpmethodtombs (re->qmethod_or_sstatus); -} diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index d772418a..a318e363 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -1469,20 +1469,18 @@ static qse_env_t* makecgienv ( { /* TODO: corrent all these name??? */ -qse_mchar_t tmp[1024]; -qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), qse_htre_getqpathptr(req), qse_htre_getqpathlen(req)); - //qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), tmp); - //qse_env_insertmbs (env, QSE_MT("PATH_INFO"), tmp); - //qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), tmp); + //qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), qse_htre_getqpath(req)); + //qse_env_insertmbs (env, QSE_MT("PATH_INFO"), qse_htre_getqpath(req)); + //qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), qse_htre_getqpath(req)); //qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), QSE_MT("/")); } //qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path); - qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpathptr(req)); + qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req)); { - qse_mchar_t* tmp = qse_htre_getqparamptr(req); + qse_mchar_t* tmp = qse_htre_getqparam(req); if (tmp) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), tmp); } @@ -1855,21 +1853,24 @@ static int task_main_cgi_5 ( cgi_forward_content (httpd, task, 1); } -qse_printf (QSE_T("task_main_cgi_5\n")); - if (cgi->buflen > 0) + if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) { -/* TODO: check if cgi outputs more than content-length if it is set... */ - httpd->errnum = QSE_HTTPD_ENOERR; - n = httpd->cbs->client.send (httpd, client, cgi->buf, cgi->buflen); - if (n <= -1) +qse_printf (QSE_T("task_main_cgi_5\n")); + if (cgi->buflen > 0) { +/* TODO: check if cgi outputs more than content-length if it is set... */ + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->cbs->client.send (httpd, client, cgi->buf, cgi->buflen); + if (n <= -1) + { /* can't return internal server error any more... */ /* TODO: logging ... */ - return -1; - } + return -1; + } - QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); - cgi->buflen -= n; + QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); + cgi->buflen -= n; + } } /* if forwarding didn't finish, something is not really right... @@ -1901,26 +1902,22 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { - /* this function assumes that the chunk length does not exceeded - * 4 hexadecimal digits. */ - QSE_ASSERT (QSE_SIZEOF(cgi->buf) <= 0xFFFF); - - qse_printf (QSE_T("task_main_cgi_4\n")); +qse_printf (QSE_T("TASK_MAIN_CGI_4\n")); if (cgi->content_chunked) { qse_size_t count, extra; qse_mchar_t chunklen[7]; + + /* this function assumes that the chunk length does not + * exceed 4 hexadecimal digits. */ + QSE_ASSERT (QSE_SIZEOF(cgi->buf) <= 0xFFFF); qse_printf (QSE_T("READING CHUNKED MODE...\n")); extra = (QSE_SIZEOF(chunklen) - 1) + 2; count = QSE_SIZEOF(cgi->buf) - cgi->buflen; if (count > extra) { - - /* TODO: check if cgi outputs more than content-length if it is set... */ - /* <- can i make it non-block?? or use select??? pio_tryread()? */ - n = qse_pio_read ( &cgi->pio, QSE_PIO_OUT, &cgi->buf[cgi->buflen + QSE_SIZEOF(chunklen) - 1], @@ -1935,7 +1932,6 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger if (n == 0) { /* the cgi script closed the output */ - task->trigger[0].mask = 0; cgi->buf[cgi->buflen++] = QSE_MT('0'); cgi->buf[cgi->buflen++] = QSE_MT('\r'); @@ -1944,9 +1940,9 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger cgi->buf[cgi->buflen++] = QSE_MT('\n'); task->main = task_main_cgi_5; - /* ok to chain-call since this task is called - * if the client-side is writable */ - return task_main_cgi_5 (httpd, client, task); + task->trigger[0].mask = 0; + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + return 1; } /* set the chunk length */ @@ -1961,46 +1957,57 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger cgi->buf[cgi->buflen++] = QSE_MT('\n'); cgi->content_received += n; + + if (cgi->content_length_set && + cgi->content_received > cgi->content_length) + { + /* TODO: cgi returning too much data... something is wrong in CGI */ + qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); + return -1; + } } } else { qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n")); - n = qse_pio_read ( - &cgi->pio, QSE_PIO_OUT, - &cgi->buf[cgi->buflen], - QSE_SIZEOF(cgi->buf) - cgi->buflen - ); - if (n <= -1) + if (cgi->buflen < QSE_SIZEOF(cgi->buf)) { - /* can't return internal server error any more... */ + n = qse_pio_read ( + &cgi->pio, QSE_PIO_OUT, + &cgi->buf[cgi->buflen], + QSE_SIZEOF(cgi->buf) - cgi->buflen + ); + if (n <= -1) + { + /* can't return internal server error any more... */ /* TODO: loggig ... */ return -1; - } - if (n == 0) - { - task->trigger[0].mask = 0; - task->main = task_main_cgi_5; - /* ok to chain-call since this task is called - * if the client-side is writable */ - return task_main_cgi_5 (httpd, client, task); - } + } + if (n == 0) + { + task->main = task_main_cgi_5; + task->trigger[0].mask = 0; + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + return 1; + } - cgi->buflen += n; - cgi->content_received += n; - } - - if (cgi->content_length_set && - cgi->content_received > cgi->content_length) - { + cgi->buflen += n; + cgi->content_received += n; + + if (cgi->content_length_set && + cgi->content_received > cgi->content_length) + { /* TODO: cgi returning too much data... something is wrong in CGI */ qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); - return -1; + return -1; + } + } } -#if 0 -qse_printf (QSE_T("CGI_4 SEND [%.*hs]\n"), (int)cgi->buflen, cgi->buf); -#endif + /* the main loop invokes the task function only if the client + * side is writable. it should be safe to write whenever + * this task function is called. */ + httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->cbs->client.send (httpd, client, cgi->buf, cgi->buflen); if (n <= -1) @@ -2013,10 +2020,6 @@ qse_printf (QSE_T("CGI_4 SEND [%.*hs]\n"), (int)cgi->buflen, cgi->buf); QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); cgi->buflen -= n; - -#if 0 -qse_printf (QSE_T("CGI SEND DONE\n")); -#endif } return 1; @@ -2041,7 +2044,9 @@ static int task_main_cgi_3 ( cgi_forward_content (httpd, task, 1); } - if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + /* send the partial reponse received with the initial line and headers + * so long as the client-side handle is writable... */ + if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) { count = MAX_SEND_SIZE; if (count >= cgi->res_left) count = cgi->res_left; @@ -2061,10 +2066,7 @@ qse_printf (QSE_T("[cgi-3 send failure....\n")); { qse_printf (QSE_T("[switching to cgi-4....\n")); task->main = task_main_cgi_4; - /* don't chain-call task_main_cgi_4 since it has another send - * and it has already been sent here. so the writability must - * be checked again in the main loop. - * => return task_main_cgi_4 (httpd, client, task);*/ + task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } @@ -2161,9 +2163,8 @@ qse_printf (QSE_T("#####INVALID HEADER FROM FROM CHILD [%.*hs]\n"), (int)cgi->bu qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res)); task->main = task_main_cgi_3; - /* ok to chain-call since this task is called - * only if the client-side is writable */ - return task_main_cgi_3 (httpd, client, task); + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + return 1; } } @@ -2255,7 +2256,8 @@ static int task_main_cgi ( task->trigger[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; task->trigger[2].handle = client->handle; } - else if (QSE_MBS_LEN(cgi->reqfwdbuf) > 0) + + if (QSE_MBS_LEN(cgi->reqfwdbuf) > 0) { /* there's nothing more to read from the client side but * some contents are already read into the forwarding buffer. @@ -2284,9 +2286,6 @@ qse_printf (QSE_T("FORWARDING INITIAL PART OF CONTENT...\n")); } task->main = cgi->nph? task_main_cgi_4: task_main_cgi_2; - /* no chain call since readability and writability needs - * to be checked in the main loop - return task->main (httpd, client, task); */ return 1; oops: @@ -2379,13 +2378,13 @@ struct task_proxy_t int reqfwderr; qse_mbs_t* res; - qse_mchar_t* res_ptr; - qse_size_t res_left; + qse_size_t res_consumed; + qse_size_t res_pending; + + int expect_100; /* if true, close connection after response is sent out */ int disconnect; - /* if true, the content of response is chunked */ - int content_chunked; /* if true, content_length is set. */ int content_length_set; /* content-length that CGI returned */ @@ -2460,16 +2459,77 @@ qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr); return 0; } +static int add_header_to_proxy_resbuf (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx) +{ + task_proxy_t* proxy = (task_proxy_t*)ctx; + + if (qse_mbs_cat (proxy->res, key) == (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, val) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + + return 0; +} + static int proxy_htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req) { proxy_htrd_xtn_t* xtn = (proxy_htrd_xtn_t*) qse_htrd_getxtn (htrd); task_proxy_t* proxy = xtn->proxy; + const qse_mchar_t* mbsptr; - /* add initial line and headers to proxy->res */ - if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + mbsptr = QSE_MBS_PTR(proxy->res); - /* add any contents received so far to cgi->res */ - if (qse_mbs_ncat (proxy->res, qse_htre_getcontentptr(req), qse_htre_getcontentlen(req)) == (qse_size_t)-1) return -1; + if (proxy->expect_100 > 0 && qse_htre_getscodeval(req) == 100) + { +/* TODO: check if the request contained Expect... */ +qse_printf (QSE_T("10000000000000000000000000000 CONTINUE 10000000000000000000000000000000\n")); + proxy->expect_100 = 0; + + if (qse_mbs_cat (proxy->res, qse_htre_getverstr(req)) == (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(req)) == (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(req)) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->res, QSE_MT("\r\n\r\n")) == (qse_size_t)-1) return -1; + + /* '100 continue' should not include contents. drop them if any */ + qse_htre_discardcontent (req); + } + else + { + /* add initial line and headers to proxy->res */ + proxy->expect_100 = -1; + +qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n")); + if (qse_mbs_cat (proxy->res, qse_htre_getverstr(req)) == (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(req)) == (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(req)) == (qse_size_t)-1) return -1; + + if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + if (qse_htre_walkheaders (req, add_header_to_proxy_resbuf, proxy) <= -1) return -1; + if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + + /* add any contents received so far to cgi->res */ + if (qse_mbs_ncat (proxy->res, qse_htre_getcontentptr(req), qse_htre_getcontentlen(req)) == (qse_size_t)-1) return -1; +qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY [%hs]\n"), QSE_MBS_PTR(proxy->res)); + } + + proxy->res_pending = QSE_MBS_LEN(proxy->res) - proxy->res_consumed; + return 0; +} + +static int proxy_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req) +{ + proxy_htrd_xtn_t* xtn = (proxy_htrd_xtn_t*) qse_htrd_getxtn (htrd); + task_proxy_t* proxy = xtn->proxy; + + if (proxy->expect_100 == 0 || proxy->expect_100 == -2) + { +qse_printf (QSE_T("SETTIG HTRD TO PEEK ONLY >>>>>>>>>>>>>>>>>>>>>>>>.\n")); + qse_htrd_setoption (htrd, qse_htrd_getoption(htrd) | QSE_HTRD_PEEKONLY); + } return 0; } @@ -2477,7 +2537,7 @@ static int proxy_htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req) static qse_htrd_recbs_t proxy_htrd_cbs = { proxy_htrd_peek_request, - QSE_NULL /* not needed for proxy */ + proxy_htrd_handle_request }; static void proxy_forward_content ( @@ -2552,6 +2612,17 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO PROXY\n")); } } +static int add_header_to_proxy_fwdbuf (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx) +{ + task_proxy_t* proxy = (task_proxy_t*)ctx; + + if (qse_mbs_cat (proxy->reqfwdbuf, key) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(": ")) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->reqfwdbuf, val) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; + + return 0; +} static int task_init_proxy ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) @@ -2565,11 +2636,6 @@ static int task_init_proxy ( proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task); arg = (task_proxy_arg_t*)task->ctx; -/* TODO: can content length be a different type??? - * maybe qse_uintmax_t.... it thinks the data size can be larger than the max pointer size - * qse_htre_t and qse_htrd_t also needs changes to support it - */ - QSE_MEMSET (proxy, 0, QSE_SIZEOF(*proxy)); proxy->version = *qse_htre_getversion(arg->req); proxy->keepalive = arg->req->attr.keepalive; @@ -2580,6 +2646,36 @@ static int task_init_proxy ( * TODO: also change the content length check logic below... * -------------------------------------------------------------------- */ +/* TODO: DETERMINE THIS SIZE */ +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_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) 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, add_header_to_proxy_fwdbuf, proxy) <= -1) goto oops; + if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops; + + if (arg->req->attr.expect && + (arg->req->version.major > 1 || + (arg->req->version.major == 1 && arg->req->version.minor >= 1))) + { + if (qse_mbscasecmp(arg->req->attr.expect, QSE_MT("100-continue")) == 0) + { + proxy->expect_100 = 1; + } + } + if (arg->req->state & QSE_HTRE_DISCARDED) { content_length = 0; @@ -2610,17 +2706,8 @@ static int task_init_proxy ( { /* create a buffer to hold request content from the client * and copy content received already */ - proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len)); - if (proxy->reqfwdbuf == QSE_NULL) goto oops; - ptr = qse_htre_getcontentptr(arg->req); - if (qse_mbs_ncpy (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) - { - qse_mbs_close (proxy->reqfwdbuf); - proxy->reqfwdbuf = QSE_NULL; - goto oops; - } - + if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops; if (arg->req->state & QSE_HTRE_COMPLETED) { @@ -2635,7 +2722,7 @@ static int task_init_proxy ( } else { - /* CGI entasking is invoked probably from the peek handler + /* proxy entasking is invoked probably from the peek handler * that was triggered after the request header is received. * you can know this because the request is not completed. * In this case, arrange to forward content @@ -2661,6 +2748,7 @@ done: * will be invoked so long as the client handle is writable by * the main loop. */ +qse_printf (QSE_T("GOING TO PROXY [%hs]\n"), QSE_MBS_PTR(proxy->reqfwdbuf)); task->ctx = proxy; return 0; @@ -2668,6 +2756,11 @@ oops: /* since a new task can't be added in the initializer, * i mark that initialization failed and let task_main_proxy() * add an error task */ + if (proxy->reqfwdbuf) + { + qse_mbs_close (proxy->reqfwdbuf); + proxy->reqfwdbuf = QSE_NULL; + } proxy->init_failed = 1; task->ctx = proxy; return 0; @@ -2704,20 +2797,23 @@ static int task_main_proxy_5 ( } qse_printf (QSE_T("task_main_proxy_5\n")); - if (proxy->buflen > 0) + if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) { -/* TODO: check if proxy outputs more than content-length if it is set... */ - httpd->errnum = QSE_HTTPD_ENOERR; - n = httpd->cbs->client.send (httpd, client, proxy->buf, proxy->buflen); - if (n <= -1) + if (proxy->buflen > 0) { - /* can't return internal server error any more... */ +/* TODO: check if proxy outputs more than content-length if it is set... */ + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->cbs->client.send (httpd, client, proxy->buf, proxy->buflen); + if (n <= -1) + { + /* can't return internal server error any more... */ /* TODO: logging ... */ - return -1; - } + return -1; + } - QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); - proxy->buflen -= n; + QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); + proxy->buflen -= n; + } } /* if forwarding didn't finish, something is not really right... @@ -2747,48 +2843,58 @@ qse_printf (QSE_T("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigg proxy_forward_content (httpd, task, 1); } +qse_printf (QSE_T("task_main_proxy_4 about to read from PEER...\n")); if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { - /* this function assumes that the chunk length does not exceeded - * 4 hexadecimal digits. */ - QSE_ASSERT (QSE_SIZEOF(proxy->buf) <= 0xFFFF); - - qse_printf (QSE_T("task_main_proxy_4\n")); - - n = httpd->cbs->peer.recv ( - httpd, &proxy->peer, - &proxy->buf[proxy->buflen], - QSE_SIZEOF(proxy->buf) - proxy->buflen - ); - if (n <= -1) + if (proxy->buflen < QSE_SIZEOF(proxy->buf)) { - /* can't return internal server error any more... */ +qse_printf (QSE_T("task_main_proxy_4 reading from PEER... %d %d\n"), (int)proxy->content_length, (int)proxy->content_received); + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->cbs->peer.recv ( + httpd, &proxy->peer, + &proxy->buf[proxy->buflen], + QSE_SIZEOF(proxy->buf) - proxy->buflen + ); +qse_printf (QSE_T("task_main_proxy_4 read from PEER...%d\n"), (int)n); + if (n <= -1) + { + /* can't return internal server error any more... */ /* TODO: loggig ... */ - return -1; - } - if (n == 0) - { - task->trigger[0].mask = 0; - task->main = task_main_proxy_5; - /* ok to chain-call since this task is called - * if the client-side is writable */ - return task_main_proxy_5 (httpd, client, task); + return -1; + } + if (n == 0) + { + task->main = task_main_proxy_5; + task->trigger[0].mask = 0; + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + return 1; + } + + proxy->buflen += n; + proxy->content_received += n; + + if (proxy->content_length_set && + proxy->content_received > proxy->content_length) + { + /* TODO: proxy returning too much data... something is wrong in PROXY */ + qse_printf (QSE_T("PROXY FUCKED UP...RETURNING TOO MUCH DATA\n")); + return -1; + } + + if (proxy->content_length_set && + proxy->content_received == proxy->content_length) + { + qse_printf (QSE_T("PROXY DONE READING\n")); + task->main = task_main_proxy_5; + task->trigger[0].mask = 0; + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + return 1; + } } - proxy->buflen += n; - proxy->content_received += n; - - if (proxy->content_length_set && - proxy->content_received > proxy->content_length) - { - /* TODO: proxy returning too much data... something is wrong in CGI */ - qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); - return -1; - } - -#if 0 -qse_printf (QSE_T("CGI_4 SEND [%.*hs]\n"), (int)proxy->buflen, proxy->buf); -#endif + /* the main loop invokes the task function only if the client + * side is writable. it should be safe to write whenever + * this task function is called. */ httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->cbs->client.send (httpd, client, proxy->buf, proxy->buflen); if (n <= -1) @@ -2801,10 +2907,6 @@ qse_printf (QSE_T("CGI_4 SEND [%.*hs]\n"), (int)proxy->buflen, proxy->buf); QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); proxy->buflen -= n; - -#if 0 -qse_printf (QSE_T("CGI SEND DONE\n")); -#endif } return 1; @@ -2817,8 +2919,6 @@ static int task_main_proxy_3 ( * returned by peer. it may include some contents as well */ task_proxy_t* proxy = (task_proxy_t*)task->ctx; - qse_ssize_t n; - qse_size_t count; if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { @@ -2829,34 +2929,42 @@ static int task_main_proxy_3 ( proxy_forward_content (httpd, task, 1); } - if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) +qse_printf (QSE_T("[PROXY-----3]\n")); + if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) { - count = MAX_SEND_SIZE; - if (count >= proxy->res_left) count = proxy->res_left; + qse_ssize_t n; + qse_size_t count; -qse_printf (QSE_T("[proxy_3 sending %d bytes]\n"), (int)count); - httpd->errnum = QSE_HTTPD_ENOERR; - n = httpd->cbs->client.send (httpd, client, proxy->res_ptr, count); +qse_printf (QSE_T("[PROXY-----3 SENDING XXXXX]\n")); + count = proxy->res_pending; + if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; - if (n <= -1) + if (count > 0) { +qse_printf (QSE_T("[proxy_3 sending %d bytes]\n"), (int)count); + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->cbs->client.send ( + httpd, client, + &QSE_MBS_CHAR(proxy->res,proxy->res_consumed), + count + ); + + if (n <= -1) + { qse_printf (QSE_T("[proxy-3 send failure....\n")); - return -1; + return -1; + } + + proxy->res_consumed += n; + proxy->res_pending -= n; } - proxy->res_left -= n; - if (proxy->res_left <= 0) + if (proxy->res_pending <= 0) { -qse_printf (QSE_T("[switching to proxy-4....\n")); task->main = task_main_proxy_4; - /* don't chain-call task_main_proxy_4 since it has another send - * and it has already been sent here. so the writability must - * be checked again in the main loop. - * => return task_main_proxy_4 (httpd, client, task);*/ + task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } - - proxy->res_ptr += n; } return 1; /* more work to do */ @@ -2867,8 +2975,6 @@ static int task_main_proxy_2 ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_proxy_t* proxy = (task_proxy_t*)task->ctx; - qse_ssize_t n; - qse_size_t count; if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { @@ -2879,9 +2985,45 @@ static int task_main_proxy_2 ( proxy_forward_content (httpd, task, 1); } + if (proxy->res_pending > 0) + { + /* the 'if' condition becomes true only if '100 Continue' + * is received without an actual reply in a previous call to + * qse_htrd_feed() below. Since the actual reply is not + * received yet, i just want to read more while realying + * '100 Continue' to the client. this task handler is called + * only if the client side handle is writable. i can safely + * write to the client without a check. */ + + qse_ssize_t n; + qse_size_t count; + + count = proxy->res_pending; + if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; + +qse_printf (QSE_T("[proxy_2 sending %d bytes] [%.*hs]\n"), (int)count, (int)count, &QSE_MBS_CHAR(proxy->res,proxy->res_consumed)); + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->cbs->client.send ( + httpd, client, + &QSE_MBS_CHAR(proxy->res,proxy->res_consumed), + count + ); + if (n <= -1) + { +qse_printf (QSE_T("[proxy-2 send failure....\n")); + return -1; + } + + proxy->res_consumed += n; + proxy->res_pending -= n; + } + if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { + qse_ssize_t n; + /* there is something to read from peer */ + httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->cbs->peer.recv ( httpd, &proxy->peer, &proxy->buf[proxy->buflen], @@ -2904,32 +3046,55 @@ qse_printf (QSE_T("#####PREMATURE EOF FROM PEER\n")); proxy->buflen += n; +qse_printf (QSE_T("#####PROXY FEEDING [%.*hs]\n"), (int)proxy->buflen, proxy->buf); if (qse_htrd_feed (proxy->htrd, proxy->buf, proxy->buflen) <= -1) { /* TODO: logging */ -qse_printf (QSE_T("#####INVALID HEADER FROM FROM PEER [%.*hs]\n"), (int)proxy->buflen, proxy->buf); +qse_printf (QSE_T("#####INVALID HEADER FROM PEER [%.*hs]\n"), (int)proxy->buflen, proxy->buf); goto oops; } proxy->buflen = 0; - if (QSE_MBS_LEN(proxy->res) > 0) { - if (proxy->disconnect && - qse_httpd_entaskdisconnect (httpd, client, task) == QSE_NULL) +qse_printf (QSE_T("proxy->expect_100 %d\n"), proxy->expect_100); + if (proxy->expect_100 == -1) { - goto oops; + /* the peek handler for proxy->htrd sets + * proxy->expect_100 to either -1 or 0. + * it's set to 0 if it's called with + * '100 Continue', -1 with other responses. + * But at this point, the handler could + * be called with both '100 Continue' and + * another response for a single feed. + * if it's already set to -1, proxy->res + * should contains at least the part of + * the actual reply. so i can switch to the + * next phase */ + + if (proxy->disconnect && + qse_httpd_entaskdisconnect (httpd, client, task) == QSE_NULL) + { + goto oops; + } + +qse_printf (QSE_T("TRAILING DATA=[%hs]\n"), &QSE_MBS_CHAR(proxy->res,proxy->res_consumed)); + /* switch to the next phase */ + task->main = task_main_proxy_3; + task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + + return 1; + } + else if (proxy->expect_100 == 0) + { + /* if it's set to 0, it's seen '100 Continue' + * without an actual response. so i need to + * arrange to relay '100 Continue' while + * waiting for at least the header of an + * actual reponse */ + proxy->expect_100 = -2; } - - proxy->res_ptr = QSE_MBS_PTR(proxy->res); - proxy->res_left = QSE_MBS_LEN(proxy->res); - -qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(proxy->res), QSE_MBS_PTR(proxy->res)); - task->main = task_main_proxy_3; - /* ok to chain-call since this task is called - * only if the client-side is writable */ - return task_main_proxy_3 (httpd, client, task); } } @@ -2940,7 +3105,7 @@ oops: return (entask_error (httpd, client, task, 500, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; } -static int task_main_proxy_0 ( +static int task_main_proxy_1 ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_proxy_t* proxy = (task_proxy_t*)task->ctx; @@ -2956,26 +3121,22 @@ static int task_main_proxy_0 ( if (n >= 1) { proxy->peer_status |= PEER_CONNECTED; - task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; - if (proxy->reqfwdbuf) + + if (proxy->req) { - if (proxy->req) + task->trigger[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; + task->trigger[2].handle = client->handle; + } + + task->trigger[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; + if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) + { + proxy_forward_content (httpd, task, 0); + if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) { - task->trigger[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; - task->trigger[2].handle = client->handle; - } - else if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) - { - proxy_forward_content (httpd, task, 0); - if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) - { - task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; - } + task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } } -qse_printf (QSE_T("FINALLY connected to peer ...............................\n")); -qse_printf (QSE_T("FINALLY connected to peer ...............................\n")); -qse_printf (QSE_T("FINALLY connected to peer ...............................\n")); qse_printf (QSE_T("FINALLY connected to peer ...............................\n")); task->main = task_main_proxy_2; } @@ -2999,14 +3160,16 @@ static int task_main_proxy ( xtn = (proxy_htrd_xtn_t*) qse_htrd_getxtn (proxy->htrd); xtn->proxy = proxy; qse_htrd_setrecbs (proxy->htrd, &proxy_htrd_cbs); - qse_htrd_setoption ( - proxy->htrd, - QSE_HTRD_PEEKONLY | - QSE_HTRD_REQUEST - ); + + if (proxy->expect_100 == 1) + qse_htrd_setoption (proxy->htrd, QSE_HTRD_RESPONSE); + else + qse_htrd_setoption (proxy->htrd, QSE_HTRD_PEEKONLY | QSE_HTRD_RESPONSE); proxy->res = qse_mbs_open (httpd->mmgr, 0, 256); if (proxy->res == QSE_NULL) goto oops; + proxy->res_consumed = 0; + proxy->res_pending = 0; httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->cbs->peer.open (httpd, &proxy->peer); @@ -3026,27 +3189,24 @@ static int task_main_proxy ( { /* peer not connected yet */ task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; - task->main = task_main_proxy_0; + task->main = task_main_proxy_1; } else { /* peer connected already */ proxy->peer_status |= PEER_CONNECTED; - if (proxy->reqfwdbuf) + if (proxy->req) { - if (proxy->req) + task->trigger[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; + task->trigger[2].handle = client->handle; + } + + if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) + { + proxy_forward_content (httpd, task, 0); + if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) { - task->trigger[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; - task->trigger[2].handle = client->handle; - } - else if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) - { - proxy_forward_content (httpd, task, 0); - - if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) - { - task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; - } + task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } } task->main = task_main_proxy_2; diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index 55165659..56778fa5 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -967,25 +967,29 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_ } static int process_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_htre_t* req, int peek) { int method; qse_httpd_task_t* task; int content_received; - method = qse_htre_getqmethod(req); + method = qse_htre_getqmethodtype(req); content_received = (qse_htre_getcontentlen(req) > 0); qse_printf (QSE_T("================================\n")); -qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d] method[%hs]\n"), +qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), (unsigned long)time(NULL), (peek? QSE_MT("PEEK"): QSE_MT("HANDLE")), - qse_htre_getqpathptr(req), - qse_htre_getmajorversion(req), - qse_htre_getminorversion(req), + qse_htre_getqpath(req), + qse_htre_getmajorversion(req), + qse_htre_getminorversion(req), + qse_htre_getverstr(req), qse_htre_getqmethodname(req) ); -if (qse_htre_getqparamlen(req) > 0) qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparamptr(req)); +if (qse_htre_getqparam(req)) + qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparam(req)); + qse_htb_walk (&req->hdrtab, walk, QSE_NULL); if (qse_htre_getcontentlen(req) > 0) { @@ -1038,7 +1042,7 @@ if (qse_htre_getcontentlen(req) > 0) if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) { - const qse_mchar_t* qpath = qse_htre_getqpathptr(req); + const qse_mchar_t* qpath = qse_htre_getqpath(req); const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.')); if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0) @@ -1211,6 +1215,7 @@ qse_printf (QSE_T("Host not included....\n")); if (peek) { qse_nwad_t nwad; + //qse_strtonwad (QSE_T("192.168.1.55:9000"), &nwad); qse_strtonwad (QSE_T("192.168.1.3:80"), &nwad); task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &nwad, req); if (task == QSE_NULL) goto oops;