[MAJOR] make the client side use stream_sock_process_data()

The client side now relies on stream_sock_process_data(). One
part has not yet been re-implemented, it concerns the calls
to produce_content().

process_session() has been adjusted to correctly check for
changing bits in order not to call useless functions too many
times.

It already appears that stream_sock_process_data() should be
split so that the timeout computations are only performed at
the exit of process_session().
This commit is contained in:
Willy Tarreau 2008-08-27 23:57:16 +02:00
parent 2d2127989c
commit f9839bdffe
2 changed files with 316 additions and 318 deletions

View File

@ -66,6 +66,12 @@
#define BF_SHUTW_NOW 262144 /* the consumer must shut down for writes ASAP */
#define BF_HIJACK 524288 /* the producer is temporarily replaced */
/* masks which define input bits for stream interfaces and stream analysers */
#define BF_MASK_INTERFACE_I (BF_FULL|BF_HIJACK|BF_READ_NULL|BF_SHUTR|BF_SHUTR_NOW|BF_SHUTW)
#define BF_MASK_INTERFACE_O (BF_EMPTY|BF_HIJACK|BF_MAY_FORWARD|BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)
#define BF_MASK_INTERFACE (BF_MASK_INTF_I | BF_MASK_INTF_O)
#define BF_MASK_ANALYSER (BF_FULL|BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW|BF_SHUTR|BF_READ_NULL)
/* Analysers (buffer->analysers).
* Those bits indicate that there are some processing to do on the buffer

View File

@ -650,98 +650,45 @@ http_get_path(struct http_txn *txn)
* to be woken up, or TICK_ETERNITY. In order not to call all functions for
* nothing too many times, the request and response buffers flags are monitored
* and each function is called only if at least another function has changed at
* least one flag. If one of the functions called returns non-zero, then it
* will be called once again after all other functions. This permits explicit
* external loops which may be useful for complex state machines.
* least one flag it is interested in.
*/
#define PROCESS_CLI 0x1
#define PROCESS_SRV 0x2
#define PROCESS_REQ 0x4
#define PROCESS_RTR 0x8
#define PROCESS_ALL (PROCESS_CLI|PROCESS_SRV|PROCESS_REQ|PROCESS_RTR)
void process_session(struct task *t, int *next)
{
struct session *s = t->context;
unsigned resync = PROCESS_ALL;
unsigned int rqf;
unsigned int rpf;
int resync;
unsigned int rqf_cli, rpf_cli;
unsigned int rqf_srv, rpf_srv;
unsigned int rqf_req, rpf_rep;
/* check timeout expiration only once and adjust buffer flags
* accordingly.
*/
if (unlikely(tick_is_expired(t->expire, now_ms))) {
if (tick_is_expired(s->req->rex, now_ms))
s->req->flags |= BF_READ_TIMEOUT;
//if (tick_is_expired(s->req->wex, now_ms))
// s->req->flags |= BF_WRITE_TIMEOUT;
//
//if (tick_is_expired(s->rep->rex, now_ms))
// s->rep->flags |= BF_READ_TIMEOUT;
if (tick_is_expired(s->rep->wex, now_ms))
s->rep->flags |= BF_WRITE_TIMEOUT;
}
/* force one first pass everywhere */
rqf_cli = rqf_srv = rqf_req = ~s->req->flags;
rpf_cli = rpf_srv = rpf_rep = ~s->rep->flags;
//if (fdtab[s->cli_fd].state == FD_STERROR) {
// fprintf(stderr, "s=%p fd=%d req=%p rep=%p cs=%d ss=%d, term=%08x\n",
// s, s->cli_fd, s->req, s->rep, s->cli_state,
// s->si[1].state, s->term_trace);
// sleep(1);
//}
do {
if (resync & PROCESS_REQ) {
resync &= ~PROCESS_REQ;
rqf = s->req->flags;
rpf = s->rep->flags;
resync = 0;
/* the analysers must block it themselves */
s->req->flags |= BF_MAY_FORWARD;
if (s->req->analysers) {
if (process_request(s))
resync |= PROCESS_REQ;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_REQ;
if (((rqf_cli ^ s->req->flags) & BF_MASK_INTERFACE_I) ||
((rpf_cli ^ s->rep->flags) & BF_MASK_INTERFACE_O)) {
resync = 1;
if (s->rep->cons->state != SI_ST_CLO) {
stream_sock_process_data(s->rep->cons->fd);
if (unlikely((s->rep->cons->state == SI_ST_CLO) &&
(global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
int len;
len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n",
s->uniq_id, s->be->id, (unsigned short)s->rep->cons->fd, (unsigned short)s->req->cons->fd);
write(1, trash, len);
}
}
rqf_cli = s->req->flags;
rpf_cli = s->rep->flags;
}
if (resync & PROCESS_RTR) {
resync &= ~PROCESS_RTR;
rqf = s->req->flags;
rpf = s->rep->flags;
/* the analysers must block it themselves */
s->rep->flags |= BF_MAY_FORWARD;
if (s->rep->analysers) {
if (process_response(s))
resync |= PROCESS_RTR;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_RTR;
}
}
if (resync & PROCESS_CLI) {
rqf = s->req->flags;
rpf = s->rep->flags;
resync &= ~PROCESS_CLI;
if (process_cli(s))
resync |= PROCESS_CLI;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_CLI;
}
if (resync & PROCESS_SRV) {
rqf = s->req->flags;
rpf = s->rep->flags;
resync &= ~PROCESS_SRV;
if (((rpf_srv ^ s->rep->flags) & BF_MASK_INTERFACE_I) ||
((rqf_srv ^ s->req->flags) & BF_MASK_INTERFACE_O)) {
resync = 1;
if (s->req->cons->state != SI_ST_CLO) {
if (s->req->cons->state < SI_ST_EST && s->req->flags & BF_MAY_FORWARD)
process_srv_conn(s);
@ -757,8 +704,7 @@ void process_session(struct task *t, int *next)
buffer_shutw_now(s->req);
}
if (stream_sock_process_data(s->req->cons->fd))
resync |= PROCESS_SRV;
stream_sock_process_data(s->req->cons->fd);
/* Count server-side errors (but not timeouts). */
if (s->req->flags & BF_WRITE_ERROR) {
@ -789,12 +735,34 @@ void process_session(struct task *t, int *next)
write(1, trash, len);
}
}
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_SRV;
rqf_srv = s->req->flags;
rpf_srv = s->rep->flags;
}
if ((rqf_req ^ s->req->flags) & BF_MASK_ANALYSER) {
resync = 1;
/* the analysers must block it themselves */
s->req->flags |= BF_MAY_FORWARD;
if (s->req->analysers) {
process_request(s);
}
rqf_req = s->req->flags;
}
if ((rpf_rep ^ s->rep->flags) & BF_MASK_ANALYSER) {
resync = 1;
/* the analysers must block it themselves */
s->rep->flags |= BF_MAY_FORWARD;
if (s->rep->analysers) {
process_response(s);
}
rpf_rep = s->rep->flags;
}
} while (resync);
if (likely(s->cli_state != CL_STCLOSE ||
if (likely((s->rep->cons->state != SI_ST_CLO) ||
(s->req->cons->state != SI_ST_CLO && s->req->cons->state != SI_ST_INI))) {
if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
@ -1724,7 +1692,7 @@ int process_request(struct session *t)
*/
if (req->flags & BF_READ_ERROR) {
req->analysers = 0;
t->fe->failed_req++;
//t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK))
@ -1879,14 +1847,12 @@ int process_request(struct session *t)
goto return_bad_req;
}
/* 2: have we encountered a close ? */
else if (req->flags & (BF_READ_NULL | BF_SHUTR)) {
txn->status = 400;
client_retnclose(t, error_message(t, HTTP_ERR_400));
/* 2: have we encountered a read error ? */
else if (req->flags & BF_READ_ERROR) {
/* we cannot return any message on error */
msg->msg_state = HTTP_MSG_ERROR;
req->analysers = 0;
t->fe->failed_req++;
//t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK))
@ -1909,12 +1875,14 @@ int process_request(struct session *t)
return 0;
}
/* 4: have we encountered a read error ? */
else if (req->flags & BF_READ_ERROR) {
/* we cannot return any message on error */
/* 4: have we encountered a close ? */
else if (req->flags & (BF_READ_NULL | BF_SHUTR)) {
txn->status = 400;
client_retnclose(t, error_message(t, HTTP_ERR_400));
msg->msg_state = HTTP_MSG_ERROR;
req->analysers = 0;
t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK))
@ -2816,18 +2784,22 @@ int process_response(struct session *t)
return 0;
}
/* write error to client, read error or close from server */
if (rep->flags & (BF_WRITE_ERROR|BF_SHUTW|BF_READ_ERROR|BF_SHUTR|BF_READ_NULL)) {
/* too large response does not fit in buffer. */
else if (rep->flags & BF_FULL) {
goto hdr_response_bad;
}
/* read error */
else if (rep->flags & BF_READ_ERROR) {
buffer_shutr_now(rep);
buffer_shutw_now(req);
//fd_delete(req->cons->fd);
//req->cons->state = SI_ST_CLO;
if (t->srv) {
//if (t->srv) {
//t->srv->cur_sess--;
t->srv->failed_resp++;
//t->srv->failed_resp++;
//sess_change_server(t, NULL);
}
t->be->failed_resp++;
//}
//t->be->failed_resp++;
rep->analysers = 0;
txn->status = 502;
client_return(t, error_message(t, HTTP_ERR_502));
@ -2841,10 +2813,6 @@ int process_response(struct session *t)
return 0;
}
/* too large response does not fit in buffer. */
else if (rep->flags & BF_FULL) {
goto hdr_response_bad;
}
/* read timeout : return a 504 to the client. */
else if (rep->flags & BF_READ_TIMEOUT) {
buffer_shutr_now(rep);
@ -2869,7 +2837,31 @@ int process_response(struct session *t)
// process_srv_queue(t->srv);
return 0;
}
/* write error to client, or close from server */
else if (rep->flags & (BF_WRITE_ERROR|BF_SHUTW|BF_SHUTR|BF_READ_NULL)) {
buffer_shutr_now(rep);
buffer_shutw_now(req);
//fd_delete(req->cons->fd);
//req->cons->state = SI_ST_CLO;
if (t->srv) {
//t->srv->cur_sess--;
t->srv->failed_resp++;
//sess_change_server(t, NULL);
}
t->be->failed_resp++;
rep->analysers = 0;
txn->status = 502;
client_return(t, error_message(t, HTTP_ERR_502));
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVCL;
if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_H;
//if (t->srv && may_dequeue_tasks(t->srv, t->be))
// process_srv_queue(t->srv);
return 0;
}
rep->flags &= ~BF_MAY_FORWARD;
return 0;
}
@ -3192,219 +3184,219 @@ int process_response(struct session *t)
return 0;
}
/*
* Manages the client FSM and its socket. It normally returns zero, but may
* return 1 if it absolutely wants to be called again.
*
* Note: process_cli is the ONLY function allowed to set cli_state to anything
* but CL_STCLOSE.
*/
int process_cli(struct session *t)
{
struct buffer *req = t->req;
struct buffer *rep = t->rep;
DPRINTF(stderr,"[%u] %s: fd=%d[%d] c=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
now_ms, __FUNCTION__,
t->cli_fd, t->cli_fd >= 0 ? fdtab[t->cli_fd].state : 0, /* fd,state*/
cli_stnames[t->cli_state],
t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_RD) : 0,
t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_WR) : 0,
req->rex, rep->wex,
req->flags, rep->flags,
req->l, rep->l);
update_state:
/* FIXME: we still have to check for CL_STSHUTR because client_retnclose
* still set this state (and will do until unix sockets are converted).
*/
if (t->cli_state == CL_STDATA || t->cli_state == CL_STSHUTR) {
/* we can skip most of the tests at once if some conditions are not met */
if (!((fdtab[t->cli_fd].state == FD_STERROR) ||
(req->flags & (BF_READ_TIMEOUT|BF_READ_ERROR|BF_SHUTR_NOW)) ||
(rep->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW_NOW)) ||
(!(req->flags & BF_SHUTR) && req->flags & (BF_READ_NULL|BF_SHUTW)) ||
(!(rep->flags & BF_SHUTW) &&
(rep->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR))))
goto update_timeouts;
/* read or write error */
if (fdtab[t->cli_fd].state == FD_STERROR) {
buffer_shutr(req);
req->flags |= BF_READ_ERROR;
buffer_shutw(rep);
rep->flags |= BF_WRITE_ERROR;
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_1);
if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C;
else
t->flags |= SN_FINST_D;
}
}
goto update_state;
}
/* last read, or end of server write */
else if (!(req->flags & BF_SHUTR) && /* not already done */
req->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) {
buffer_shutr(req);
if (!(rep->flags & BF_SHUTW)) {
EV_FD_CLR(t->cli_fd, DIR_RD);
trace_term(t, TT_HTTP_CLI_2);
} else {
/* output was already closed */
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_3);
}
goto update_state;
}
/* last server read and buffer empty : we only check them when we're
* allowed to forward the data.
*/
else if (!(rep->flags & BF_SHUTW) && /* not already done */
((rep->flags & BF_SHUTW_NOW) ||
(rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD &&
rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)))) {
buffer_shutw(rep);
if (!(req->flags & BF_SHUTR)) {
EV_FD_CLR(t->cli_fd, DIR_WR);
shutdown(t->cli_fd, SHUT_WR);
trace_term(t, TT_HTTP_CLI_4);
} else {
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_5);
}
goto update_state;
}
/* read timeout */
else if ((req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) {
buffer_shutr(req);
if (!(rep->flags & BF_SHUTW)) {
EV_FD_CLR(t->cli_fd, DIR_RD);
trace_term(t, TT_HTTP_CLI_6);
} else {
/* output was already closed */
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_7);
}
if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C;
else
t->flags |= SN_FINST_D;
}
}
goto update_state;
}
/* write timeout */
else if ((rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) {
buffer_shutw(rep);
if (!(req->flags & BF_SHUTR)) {
EV_FD_CLR(t->cli_fd, DIR_WR);
shutdown(t->cli_fd, SHUT_WR);
trace_term(t, TT_HTTP_CLI_8);
} else {
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_9);
}
if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C;
else
t->flags |= SN_FINST_D;
}
}
goto update_state;
}
update_timeouts:
/* manage read timeout */
if (!(req->flags & BF_SHUTR)) {
if (req->flags & BF_FULL) {
/* no room to read more data */
if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
/* stop reading until we get some space */
req->rex = TICK_ETERNITY;
}
} else {
EV_FD_COND_S(t->cli_fd, DIR_RD);
req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
}
}
/* manage write timeout */
if (!(rep->flags & BF_SHUTW)) {
/* first, we may have to produce data (eg: stats).
* right now, this is limited to the SHUTR state.
*/
if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) {
produce_content(t);
if (rep->flags & BF_EMPTY) {
buffer_shutw(rep);
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_10);
goto update_state;
}
}
/* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
if ((rep->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) {
if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
/* stop writing */
rep->wex = TICK_ETERNITY;
}
} else {
/* buffer not empty */
EV_FD_COND_S(t->cli_fd, DIR_WR);
if (!tick_isset(rep->wex)) {
/* restart writing */
rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
if (!(req->flags & BF_SHUTR) && tick_isset(rep->wex) && tick_isset(req->rex)) {
/* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it, except if it was already infinite. */
req->rex = rep->wex;
}
}
}
}
return 0; /* other cases change nothing */
}
else if (t->cli_state == CL_STCLOSE) { /* CL_STCLOSE: nothing to do */
if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len;
len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)req->cons->fd);
write(1, trash, len);
}
return 0;
}
#ifdef DEBUG_DEV
fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->cli_state);
ABORT_NOW();
#endif
return 0;
}
///*
// * Manages the client FSM and its socket. It normally returns zero, but may
// * return 1 if it absolutely wants to be called again.
// *
// * Note: process_cli is the ONLY function allowed to set cli_state to anything
// * but CL_STCLOSE.
// */
//int process_cli(struct session *t)
//{
// struct buffer *req = t->req;
// struct buffer *rep = t->rep;
//
// DPRINTF(stderr,"[%u] %s: fd=%d[%d] c=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
// now_ms, __FUNCTION__,
// t->cli_fd, t->cli_fd >= 0 ? fdtab[t->cli_fd].state : 0, /* fd,state*/
// cli_stnames[t->cli_state],
// t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_RD) : 0,
// t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_WR) : 0,
// req->rex, rep->wex,
// req->flags, rep->flags,
// req->l, rep->l);
//
// update_state:
// /* FIXME: we still have to check for CL_STSHUTR because client_retnclose
// * still set this state (and will do until unix sockets are converted).
// */
// if (t->cli_state == CL_STDATA || t->cli_state == CL_STSHUTR) {
// /* we can skip most of the tests at once if some conditions are not met */
// if (!((fdtab[t->cli_fd].state == FD_STERROR) ||
// (req->flags & (BF_READ_TIMEOUT|BF_READ_ERROR|BF_SHUTR_NOW)) ||
// (rep->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW_NOW)) ||
// (!(req->flags & BF_SHUTR) && req->flags & (BF_READ_NULL|BF_SHUTW)) ||
// (!(rep->flags & BF_SHUTW) &&
// (rep->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR))))
// goto update_timeouts;
//
// /* read or write error */
// if (fdtab[t->cli_fd].state == FD_STERROR) {
// buffer_shutr(req);
// req->flags |= BF_READ_ERROR;
// buffer_shutw(rep);
// rep->flags |= BF_WRITE_ERROR;
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_1);
// if (!req->analysers) {
// if (!(t->flags & SN_ERR_MASK))
// t->flags |= SN_ERR_CLICL;
// if (!(t->flags & SN_FINST_MASK)) {
// if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
// t->flags |= SN_FINST_Q;
// else if (req->cons->err_type <= SI_ET_CONN_OTHER)
// t->flags |= SN_FINST_C;
// else
// t->flags |= SN_FINST_D;
// }
// }
// goto update_state;
// }
// /* last read, or end of server write */
// else if (!(req->flags & BF_SHUTR) && /* not already done */
// req->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) {
// buffer_shutr(req);
// if (!(rep->flags & BF_SHUTW)) {
// EV_FD_CLR(t->cli_fd, DIR_RD);
// trace_term(t, TT_HTTP_CLI_2);
// } else {
// /* output was already closed */
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_3);
// }
// goto update_state;
// }
// /* last server read and buffer empty : we only check them when we're
// * allowed to forward the data.
// */
// else if (!(rep->flags & BF_SHUTW) && /* not already done */
// ((rep->flags & BF_SHUTW_NOW) ||
// (rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD &&
// rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)))) {
// buffer_shutw(rep);
// if (!(req->flags & BF_SHUTR)) {
// EV_FD_CLR(t->cli_fd, DIR_WR);
// shutdown(t->cli_fd, SHUT_WR);
// trace_term(t, TT_HTTP_CLI_4);
// } else {
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_5);
// }
// goto update_state;
// }
// /* read timeout */
// else if ((req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) {
// buffer_shutr(req);
// if (!(rep->flags & BF_SHUTW)) {
// EV_FD_CLR(t->cli_fd, DIR_RD);
// trace_term(t, TT_HTTP_CLI_6);
// } else {
// /* output was already closed */
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_7);
// }
// if (!req->analysers) {
// if (!(t->flags & SN_ERR_MASK))
// t->flags |= SN_ERR_CLITO;
// if (!(t->flags & SN_FINST_MASK)) {
// if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
// t->flags |= SN_FINST_Q;
// else if (req->cons->err_type <= SI_ET_CONN_OTHER)
// t->flags |= SN_FINST_C;
// else
// t->flags |= SN_FINST_D;
// }
// }
// goto update_state;
// }
// /* write timeout */
// else if ((rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) {
// buffer_shutw(rep);
// if (!(req->flags & BF_SHUTR)) {
// EV_FD_CLR(t->cli_fd, DIR_WR);
// shutdown(t->cli_fd, SHUT_WR);
// trace_term(t, TT_HTTP_CLI_8);
// } else {
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_9);
// }
// if (!req->analysers) {
// if (!(t->flags & SN_ERR_MASK))
// t->flags |= SN_ERR_CLITO;
// if (!(t->flags & SN_FINST_MASK)) {
// if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
// t->flags |= SN_FINST_Q;
// else if (req->cons->err_type <= SI_ET_CONN_OTHER)
// t->flags |= SN_FINST_C;
// else
// t->flags |= SN_FINST_D;
// }
// }
// goto update_state;
// }
//
// update_timeouts:
// /* manage read timeout */
// if (!(req->flags & BF_SHUTR)) {
// if (req->flags & BF_FULL) {
// /* no room to read more data */
// if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
// /* stop reading until we get some space */
// req->rex = TICK_ETERNITY;
// }
// } else {
// EV_FD_COND_S(t->cli_fd, DIR_RD);
// req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
// }
// }
//
// /* manage write timeout */
// if (!(rep->flags & BF_SHUTW)) {
// /* first, we may have to produce data (eg: stats).
// * right now, this is limited to the SHUTR state.
// */
// if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) {
// produce_content(t);
// if (rep->flags & BF_EMPTY) {
// buffer_shutw(rep);
// fd_delete(t->cli_fd);
// t->cli_state = CL_STCLOSE;
// trace_term(t, TT_HTTP_CLI_10);
// goto update_state;
// }
// }
//
// /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
// if ((rep->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) {
// if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
// /* stop writing */
// rep->wex = TICK_ETERNITY;
// }
// } else {
// /* buffer not empty */
// EV_FD_COND_S(t->cli_fd, DIR_WR);
// if (!tick_isset(rep->wex)) {
// /* restart writing */
// rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
// if (!(req->flags & BF_SHUTR) && tick_isset(rep->wex) && tick_isset(req->rex)) {
// /* FIXME: to prevent the client from expiring read timeouts during writes,
// * we refresh it, except if it was already infinite. */
// req->rex = rep->wex;
// }
// }
// }
// }
// return 0; /* other cases change nothing */
// }
// else if (t->cli_state == CL_STCLOSE) { /* CL_STCLOSE: nothing to do */
// if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
// int len;
// len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)req->cons->fd);
// write(1, trash, len);
// }
// return 0;
// }
//#ifdef DEBUG_DEV
// fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->cli_state);
// ABORT_NOW();
//#endif
// return 0;
//}
/* Return 1 if the pending connection has failed and should be retried,