[MEDIUM] simplify and centralize request timeout cancellation and request forwarding

Instead of playing with req->flags and request timeout everywhere,
tweak them only at precise locations.
diff --git a/src/proto_http.c b/src/proto_http.c
index df037bd..870b025 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -673,6 +673,18 @@
 		s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
 		s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
 
+		/* Trick: if a request is being waiting for the server to respond,
+		 * and if we know the server can timeout, we don't want the timeout
+		 * to expire on the client side first, but we're still interested
+		 * in passing data from the client to the server (eg: POST). Thus,
+		 * we can cancel the client's request timeout if the server's
+		 * request timeout is set and the server has not yet sent a response.
+		 */
+
+		if ((s->rep->flags & (BF_MAY_FORWARD|BF_SHUTR_STATUS)) == 0 &&
+		    (tick_isset(s->req->cex) || tick_isset(s->req->wex) || tick_isset(s->rep->rex)))
+			s->req->rex = TICK_ETERNITY;
+
 		t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
 				       tick_first(s->rep->rex, s->rep->wex));
 		t->expire = tick_first(t->expire, s->req->cex);
@@ -1648,8 +1660,6 @@
 		t->analysis &= ~AN_REQ_INSPECT;
 		if (t->analysis & AN_REQ_HTTP_HDR)
 			t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
-		else
-			req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
 
 		t->inspect_exp = TICK_ETERNITY;
 		return 1;
@@ -2378,23 +2388,19 @@
 		 * could. Let's switch to the DATA state.                    *
 		 ************************************************************/
 
-		if (!(t->analysis & AN_REQ_ANY))
-			req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
-
 		req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
 		t->logs.tv_request = now;
 
-		/* This is a bit tricky. We don't want the client timeout to strike
-		 * while intially waiting for the server to respond. So we rely
-		 * entirely on the server timeout to ensure that we cannot wait
-		 * indefinitely.
-		 */
-		if (t->fe->timeout.client || req->l >= req->rlim - req->data)
-			req->rex = TICK_ETERNITY;
-		else if (t->analysis || !t->be->timeout.server || rep->flags & BF_MAY_FORWARD)
-			req->rex = tick_add(now_ms, t->fe->timeout.client);
-		else
-			req->rex = TICK_ETERNITY;
+		if (req->l >= req->rlim - req->data) {
+			/* 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);
+		}
 
 		/* When a connection is tarpitted, we use the tarpit timeout,
 		 * which may be the same as the connect timeout if unspecified.
@@ -2483,19 +2489,17 @@
 			/* we have enough bytes ! */
 			t->logs.tv_request = now;  /* update the request timer to reflect full request */
 			t->analysis &= ~AN_REQ_HTTP_BODY;
-			req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
 
-			/* This is a bit tricky. We don't want the client timeout to strike
-			 * while intially waiting for the server to respond. So we rely
-			 * entirely on the server timeout to ensure that we cannot wait
-			 * indefinitely.
-			 */
-			if (t->fe->timeout.client || req->l >= req->rlim - req->data)
-				req->rex = TICK_ETERNITY;
-			else if (t->analysis || !t->be->timeout.server || rep->flags & BF_MAY_FORWARD)
-				req->rex = tick_add(now_ms, t->fe->timeout.client);
-			else
-				req->rex = TICK_ETERNITY;
+			if (req->l >= req->rlim - req->data) {
+				/* 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);
+			}
 			return 1;
 		}
 
@@ -2506,29 +2510,29 @@
 			/* The situation will not evolve, so let's give up on the analysis. */
 			t->logs.tv_request = now;  /* update the request timer to reflect full request */
 			t->analysis &= ~AN_REQ_HTTP_BODY;
-			req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
 
-			/* This is a bit tricky. We don't want the client timeout to strike
-			 * while intially waiting for the server to respond. So we rely
-			 * entirely on the server timeout to ensure that we cannot wait
-			 * indefinitely.
-			 */
-			if (t->fe->timeout.client || req->l >= req->rlim - req->data)
-				req->rex = TICK_ETERNITY;
-			else if (t->analysis || !t->be->timeout.server || rep->flags & BF_MAY_FORWARD)
-				req->rex = tick_add(now_ms, t->fe->timeout.client);
-			else
-				req->rex = TICK_ETERNITY;
+			if (req->l >= req->rlim - req->data) {
+				/* 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);
+			}
 			return 1;
 		}
 
-		if (!tick_isset(req->rex)) {
-			EV_FD_COND_S(t->cli_fd, DIR_RD);
-			req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-		}
+		EV_FD_COND_S(t->cli_fd, DIR_RD);
+		req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
 		return 0;
 	}
 
+	/* if no analysis remains, it's time to forward the connection */
+	if (!(t->analysis & AN_REQ_ANY) && !(req->flags & (BF_MAY_CONNECT|BF_MAY_FORWARD)))
+		req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
+
 	if (c == CL_STDATA) {
 		/* FIXME: this error handling is partly buggy because we always report
 		 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
@@ -2558,9 +2562,6 @@
 			EV_FD_CLR(t->cli_fd, DIR_RD);
 			buffer_shutr(req);
 			t->cli_state = CL_STSHUTR;
-			/* we must allow immediate connection if not already done */
-			if (!req->flags & (BF_MAY_CONNECT | BF_MAY_FORWARD))
-				req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
 			return 1;
 		}	
 		/* last server read and buffer empty */
@@ -2624,21 +2625,8 @@
 				req->rex = TICK_ETERNITY;
 			}
 		} else {
-			/* there's still some space in the buffer */
-			if (!tick_isset(req->rex)) {
-				EV_FD_COND_S(t->cli_fd, DIR_RD);
-				/* This is a bit tricky. We don't want the client timeout to strike
-				 * while intially waiting for the server to respond. So we rely
-				 * entirely on the server timeout to ensure that we cannot wait
-				 * indefinitely.
-				 */
-				if (t->fe->timeout.client)
-					req->rex = TICK_ETERNITY;
-				else if (t->analysis || !t->be->timeout.server || rep->flags & BF_MAY_FORWARD)
-					req->rex = tick_add(now_ms, t->fe->timeout.client);
-				else
-					req->rex = TICK_ETERNITY;
-			}
+			EV_FD_COND_S(t->cli_fd, DIR_RD);
+			req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
 		}
 
 		/* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
@@ -2769,21 +2757,13 @@
 		}
 		else if (req->l >= req->rlim - req->data) {
 			/* no room to read more data */
-
-			/* FIXME-20050705: is it possible for a client to maintain a session
-			 * after the timeout by sending more data after it receives a close ?
-			 */
-
 			if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
 				/* stop reading until we get some space */
 				req->rex = TICK_ETERNITY;
 			}
 		} else {
-			/* there's still some space in the buffer */
-			if (!tick_isset(req->rex)) {
-				EV_FD_COND_S(t->cli_fd, DIR_RD);
-				req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-			}
+			EV_FD_COND_S(t->cli_fd, DIR_RD);
+			req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
 		}
 		return 0;
 	}