added QSE_HTTPD_MUTECLIENT

This commit is contained in:
hyung-hwan 2012-04-14 08:21:07 +00:00
parent 05e0476f97
commit 8ccc2698d6
5 changed files with 46 additions and 31 deletions

View File

@ -58,9 +58,10 @@ typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
enum qse_httpd_option_t enum qse_httpd_option_t
{ {
QSE_HTTPD_CGIERRTONUL = (1 << 0), QSE_HTTPD_MUTECLIENT = (1 << 0),
QSE_HTTPD_CGINOCLOEXEC = (1 << 1), QSE_HTTPD_CGIERRTONUL = (1 << 1),
QSE_HTTPD_CGINOCHUNKED = (1 << 2) QSE_HTTPD_CGINOCLOEXEC = (1 << 2),
QSE_HTTPD_CGINOCHUNKED = (1 << 3)
}; };
typedef struct qse_httpd_stat_t qse_httpd_stat_t; typedef struct qse_httpd_stat_t qse_httpd_stat_t;
@ -240,12 +241,9 @@ typedef int (*qse_httpd_task_main_t) (
enum qse_httpd_task_trigger_mask_t enum qse_httpd_task_trigger_mask_t
{ {
QSE_HTTPD_TASK_TRIGGER_READ = (1 << 0), QSE_HTTPD_TASK_TRIGGER_READ = (1 << 0),
QSE_HTTPD_TASK_TRIGGER_RELAY = (1 << 1), QSE_HTTPD_TASK_TRIGGER_WRITE = (1 << 1),
QSE_HTTPD_TASK_TRIGGER_WRITE = (1 << 2), QSE_HTTPD_TASK_TRIGGER_READABLE = (1 << 2),
QSE_HTTPD_TASK_TRIGGER_READABLE = (1 << 3), QSE_HTTPD_TASK_TRIGGER_WRITABLE = (1 << 3)
QSE_HTTPD_TASK_TRIGGER_RELAYABLE = (1 << 4),
QSE_HTTPD_TASK_TRIGGER_WRITABLE = (1 << 5)
}; };
typedef struct qse_httpd_task_trigger_t qse_httpd_task_trigger_t; typedef struct qse_httpd_task_trigger_t qse_httpd_task_trigger_t;

View File

@ -1419,7 +1419,7 @@ feedme_more:
int qse_htrd_halt (qse_htrd_t* htrd) int qse_htrd_halt (qse_htrd_t* htrd)
{ {
if (htrd->fed.s.flags & CONSUME_UNTIL_CLOSE) if (htrd->fed.s.flags & CONSUME_UNTIL_CLOSE || !htrd->clean)
{ {
qse_htre_completecontent (&htrd->re); qse_htre_completecontent (&htrd->re);

View File

@ -2701,6 +2701,7 @@ struct task_proxy_t
#define PROXY_RES_PEER_LENGTH (1 << 5) /* peer's output is set with #define PROXY_RES_PEER_LENGTH (1 << 5) /* peer's output is set with
* the content-length */ * the content-length */
#define PROXY_RES_PEER_LENGTH_FAKE (1 << 6) /* peer_output_length is fake */ #define PROXY_RES_PEER_LENGTH_FAKE (1 << 6) /* peer_output_length is fake */
#define PROXY_RES_EVER_SENTBACK (1 << 7) /* any single byte sent back to a client */
#define PROXY_RES_AWAIT_100 (1 << 10) /* waiting for 100 continue */ #define PROXY_RES_AWAIT_100 (1 << 10) /* waiting for 100 continue */
#define PROXY_RES_AWAIT_RESHDR (1 << 11) /* waiting for response header */ #define PROXY_RES_AWAIT_RESHDR (1 << 11) /* waiting for response header */
#define PROXY_RES_AWAIT_RESCON (1 << 12) /* waiting for response content. #define PROXY_RES_AWAIT_RESCON (1 << 12) /* waiting for response content.
@ -3652,11 +3653,16 @@ qse_printf (QSE_T("task_main_proxy_4 read from PEER...%d\n"), (int)n);
static int task_main_proxy_3 ( static int task_main_proxy_3 (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
/* send the http initial line and headers built using the headers /* let's send up the http initial line and headers before
* returned by peer. it may include some contents as well */ * attempting to read the reset of content. it may already
* include some contents as well received together with
* the header. */
task_proxy_t* proxy = (task_proxy_t*)task->ctx; task_proxy_t* proxy = (task_proxy_t*)task->ctx;
qse_printf (QSE_T("task_main_proxy_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) if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task, 0);
@ -3666,7 +3672,6 @@ static int task_main_proxy_3 (
proxy_forward_client_input_to_peer (httpd, task, 1); proxy_forward_client_input_to_peer (httpd, task, 1);
} }
qse_printf (QSE_T("[PROXY-----3]\n"));
if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || if (!(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||
(task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{ {
@ -3693,6 +3698,7 @@ qse_printf (QSE_T("[proxy-3 send failure....\n"));
return -1; return -1;
} }
proxy->resflags |= PROXY_RES_EVER_SENTBACK;
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
} }
@ -3713,7 +3719,7 @@ qse_printf (QSE_T("SWITINCG TO 55555555555555555555555555 %d %d %d %d\n"),
} }
else else
{ {
qse_printf (QSE_T("SWITINCG TO 4444444444444444444444444444\n")); qse_printf (QSE_T("SWITICHING TO 4444444444444444444444444444\n"));
task->main = task_main_proxy_4; task->main = task_main_proxy_4;
task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
} }
@ -3729,7 +3735,7 @@ static int task_main_proxy_2 (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
task_proxy_t* proxy = (task_proxy_t*)task->ctx; task_proxy_t* proxy = (task_proxy_t*)task->ctx;
int http_errnum = 0; int http_errnum = 500;
qse_printf (QSE_T("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\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); task->trigger[0].mask, task->trigger[1].mask, task->trigger[2].mask);
@ -3782,9 +3788,10 @@ qse_printf (QSE_T("]\n"));
if (n <= -1) if (n <= -1)
{ {
qse_printf (QSE_T("[proxy-2 send failure....\n")); qse_printf (QSE_T("[proxy-2 send failure....\n"));
return -1; goto oops;
} }
proxy->resflags |= PROXY_RES_EVER_SENTBACK;
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
@ -3822,14 +3829,9 @@ qse_printf (QSE_T("[proxy-2 send failure....\n"));
* the proxy script must be crooked. */ * the proxy script must be crooked. */
/* TODO: logging */ /* TODO: logging */
qse_printf (QSE_T("#####PREMATURE EOF FROM PEER\n")); qse_printf (QSE_T("#####PREMATURE EOF FROM PEER\n"));
if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) http_errnum = 502;
{
http_errnum = 502;
goto oops; goto oops;
} }
return -1;
}
else else
{ {
QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK); QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK);
@ -3846,7 +3848,7 @@ qse_printf (QSE_T("#####PREMATURE EOF FROM PEER\n"));
} }
qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n")); qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n"));
return -1; goto oops;
} }
} }
@ -3893,7 +3895,7 @@ qse_printf (QSE_T("#####INVALID HEADER FROM PEER [%.*hs]\n"), (int)proxy->buflen
} }
else else
{ {
qse_printf (QSE_T("TRAILING DATA=[%hs]\n"), QSE_MBS_CPTR(proxy->res,proxy->res_consumed)); qse_printf (QSE_T("TRAILING DATA=%d, [%hs]\n"), (int)QSE_MBS_LEN(proxy->res), QSE_MBS_CPTR(proxy->res,proxy->res_consumed));
/* switch to the next phase */ /* switch to the next phase */
task->main = task_main_proxy_3; task->main = task_main_proxy_3;
task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
@ -3916,6 +3918,7 @@ qse_printf (QSE_T("TRAILING DATA=[%hs]\n"), QSE_MBS_CPTR(proxy->res,proxy->res_c
return 1; return 1;
oops: oops:
if (proxy->resflags & PROXY_RES_EVER_SENTBACK) return -1;
return (entask_error (httpd, client, task, http_errnum, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; return (entask_error (httpd, client, task, http_errnum, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
} }

View File

@ -693,15 +693,25 @@ qse_printf (QSE_T("Error: failed to read from a client %d\n"), client->handle.i)
else if (m == 0) else if (m == 0)
{ {
qse_printf (QSE_T("Debug: connection closed %d - errno %d\n"), client->handle.i, errno); qse_printf (QSE_T("Debug: connection closed %d - errno %d\n"), client->handle.i, errno);
if (client->task.head && client->htrd->clean) /* reading from the client returned 0. this typically
* happens when the client closes the connection or
* shutdown the writing half of the socket. it's
* not really easy to determine one from the other.
* if QSE_HTTPD_MUTECLIENT is on, attempt to handle
* it as a half-close under a certain condition. */
if (httpd->option & QSE_HTTPD_MUTECLIENT &&
client->task.head && client->htrd->clean)
{ {
/* there is still more tasks to finish and /* there is still more tasks to finish and
* http reader is not waiting for any more feeds. */ * http reader is not waiting for any more feeds. */
client->status |= CLIENT_MUTE; client->status |= CLIENT_MUTE;
qse_printf (QSE_T(">>>>> Marking client %d as MUTE\n"), client->handle.i);
return 0; return 0;
} }
else else
{ {
qse_printf (QSE_T(">>>>> Returning failure for client %d\n"), client->handle.i);
httpd->errnum = QSE_HTTPD_EDISCON; httpd->errnum = QSE_HTTPD_EDISCON;
return -1; return -1;
} }
@ -820,7 +830,7 @@ qse_printf (QSE_T("task returend %d\n"), n);
int mux_mask; int mux_mask;
int mux_status; int mux_status;
/* the current task is over. remove remove the task /* the current task is over. remove the task
* from the queue. dequeue_task() clears task triggers * from the queue. dequeue_task() clears task triggers
* from the mux. so i don't clear them explicitly here */ * from the mux. so i don't clear them explicitly here */

View File

@ -699,13 +699,17 @@ static int mux_poll (qse_httpd_t* httpd, void* vmux, qse_ntime_t timeout)
mask = 0; mask = 0;
if (mux->ee.ptr[i].events & EPOLLIN) mask |= QSE_HTTPD_MUX_READ; if (mux->ee.ptr[i].events & EPOLLIN)
if (mux->ee.ptr[i].events & EPOLLOUT) mask |= QSE_HTTPD_MUX_WRITE; mask |= QSE_HTTPD_MUX_READ;
if (mux->ee.ptr[i].events & EPOLLOUT)
mask |= QSE_HTTPD_MUX_WRITE;
if (mux->ee.ptr[i].events & EPOLLHUP) if (mux->ee.ptr[i].events & EPOLLHUP)
{ {
if (mev->reqmask & QSE_HTTPD_MUX_READ) mask |= QSE_HTTPD_MUX_READ; if (mev->reqmask & QSE_HTTPD_MUX_READ)
if (mev->reqmask & QSE_HTTPD_MUX_WRITE) mask |= QSE_HTTPD_MUX_WRITE; mask |= QSE_HTTPD_MUX_READ;
if (mev->reqmask & QSE_HTTPD_MUX_WRITE)
mask |= QSE_HTTPD_MUX_WRITE;
} }
mev->cbfun (httpd, mux, mev->handle, mask, mev->cbarg); mev->cbfun (httpd, mux, mev->handle, mask, mev->cbarg);