[MAJOR] http: create the analyser which waits for a response

The code part which waits for an HTTP response has been extracted
from the old function. We now have two analysers and the second one
may re-enable the first one when an 1xx response is encountered.
This has been tested and works.

The calls to stream_int_return() that were remaining in the wait
analyser have been converted to stream_int_retnclose().
diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
index 5fcbced..832be29 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -66,7 +66,8 @@
 int http_process_request(struct session *t, struct buffer *req, int an_bit);
 int http_process_tarpit(struct session *s, struct buffer *req, int an_bit);
 int http_process_request_body(struct session *s, struct buffer *req, int an_bit);
-int process_response(struct session *t);
+int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit);
+int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, struct proxy *px);
 
 void debug_hdr(const char *dir, struct session *t, const char *start, const char *end);
 void get_srv_from_appsession(struct session *t, const char *begin, int len);
diff --git a/include/types/buffers.h b/include/types/buffers.h
index 8c8ee9b..e8ac641 100644
--- a/include/types/buffers.h
+++ b/include/types/buffers.h
@@ -140,10 +140,16 @@
 #define AN_REQ_HTTP_INNER       0x00000020  /* inner processing of HTTP request */
 #define AN_REQ_HTTP_TARPIT      0x00000040  /* wait for end of HTTP tarpit */
 #define AN_REQ_HTTP_BODY        0x00000080  /* inspect HTTP request body */
-
-#define AN_RTR_HTTP_HDR         0x00000200  /* inspect HTTP response headers */
+/* unused: 0x100, 0x200 */
 #define AN_REQ_PRST_RDP_COOKIE  0x00000400  /* persistence on rdp cookie */
 
+/* response analysers */
+#define AN_RES_INSPECT          0x00010000  /* content inspection */
+#define AN_RES_WAIT_HTTP        0x00020000  /* wait for HTTP response */
+#define AN_RES_HTTP_PROCESS_BE  0x00040000  /* process backend's HTTP part */
+#define AN_RES_HTTP_PROCESS_FE  0x00040000  /* process frontend's HTTP part (same for now) */
+
+
 /* Magic value to forward infinite size (TCP, ...), used with ->to_forward */
 #define BUF_INFINITE_FORWARD    (~0UL)
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index bcadaee..4363796 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -4489,7 +4489,7 @@
 
 			if (curproxy->mode == PR_MODE_HTTP) {
 				curproxy->fe_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE;
-				curproxy->fe_rsp_ana |= AN_RTR_HTTP_HDR;
+				curproxy->fe_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_FE;
 			}
 
 			/* both TCP and HTTP must check switching rules */
@@ -4499,7 +4499,7 @@
 		if (curproxy->cap & PR_CAP_BE) {
 			if (curproxy->mode == PR_MODE_HTTP) {
 				curproxy->be_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_INNER | AN_REQ_HTTP_PROCESS_BE;
-				curproxy->be_rsp_ana |= AN_RTR_HTTP_HDR;
+				curproxy->be_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_BE;
 			}
 
 			/* If the backend does requires RDP cookie persistence, we have to
diff --git a/src/proto_http.c b/src/proto_http.c
index 9460cb7..31a2098 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2840,249 +2840,290 @@
 	}
 }
 
-/* This function performs all the processing enabled for the current response.
- * It normally returns zero, but may return 1 if it absolutely needs to be
- * called again after other functions. It relies on buffers flags, and updates
- * t->rep->analysers. It might make sense to explode it into several other
- * functions. It works like process_request (see indications above).
+/* This stream analyser waits for a complete HTTP response. It returns 1 if the
+ * processing can continue on next analysers, or zero if it either needs more
+ * data or wants to immediately abort the response (eg: timeout, error, ...). It
+ * is tied to AN_RES_WAIT_HTTP and may may remove itself from s->rep->analysers
+ * when it has nothing left to do, and may remove any analyser when it wants to
+ * abort.
  */
-int process_response(struct session *t)
+int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit)
 {
-	struct http_txn *txn = &t->txn;
-	struct buffer *req = t->req;
-	struct buffer *rep = t->rep;
+	struct http_txn *txn = &s->txn;
+	struct http_msg *msg = &txn->rsp;
+	int cur_idx;
 	int n;
 
- next_response:
 	DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
 		now_ms, __FUNCTION__,
-		t,
+		s,
 		rep,
 		rep->rex, rep->wex,
 		rep->flags,
 		rep->l,
 		rep->analysers);
 
-	if (rep->analysers & AN_RTR_HTTP_HDR) { /* receiving server headers */
-		/*
-		 * Now parse the partial (or complete) lines.
-		 * We will check the response syntax, and also join multi-line
-		 * headers. An index of all the lines will be elaborated while
-		 * parsing.
-		 *
-		 * For the parsing, we use a 28 states FSM.
-		 *
-		 * Here is the information we currently have :
-		 *   rep->data + rep->som  = beginning of response
-		 *   rep->data + rep->eoh  = end of processed headers / start of current one
-		 *   rep->data + rep->eol  = end of current header or line (LF or CRLF)
-		 *   rep->lr = first non-visited byte
-		 *   rep->r  = end of data
-		 */
+	/*
+	 * Now parse the partial (or complete) lines.
+	 * We will check the response syntax, and also join multi-line
+	 * headers. An index of all the lines will be elaborated while
+	 * parsing.
+	 *
+	 * For the parsing, we use a 28 states FSM.
+	 *
+	 * Here is the information we currently have :
+	 *   rep->data + rep->som  = beginning of response
+	 *   rep->data + rep->eoh  = end of processed headers / start of current one
+	 *   rep->data + rep->eol  = end of current header or line (LF or CRLF)
+	 *   rep->lr = first non-visited byte
+	 *   rep->r  = end of data
+	 */
+
+	if (likely(rep->lr < rep->r))
+		http_msg_analyzer(rep, msg, &txn->hdr_idx);
 
-		int cur_idx;
-		struct http_msg *msg = &txn->rsp;
-		struct proxy *cur_proxy;
+	/* 1: we might have to print this header in debug mode */
+	if (unlikely((global.mode & MODE_DEBUG) &&
+		     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
+		     (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
+		char *eol, *sol;
 
-		if (likely(rep->lr < rep->r))
-			http_msg_analyzer(rep, msg, &txn->hdr_idx);
+		sol = rep->data + msg->som;
+		eol = sol + msg->sl.rq.l;
+		debug_hdr("srvrep", s, sol, eol);
 
-		/* 1: we might have to print this header in debug mode */
-		if (unlikely((global.mode & MODE_DEBUG) &&
-			     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
-			     (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
-			char *eol, *sol;
+		sol += hdr_idx_first_pos(&txn->hdr_idx);
+		cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
 
-			sol = rep->data + msg->som;
-			eol = sol + msg->sl.rq.l;
-			debug_hdr("srvrep", t, sol, eol);
+		while (cur_idx) {
+			eol = sol + txn->hdr_idx.v[cur_idx].len;
+			debug_hdr("srvhdr", s, sol, eol);
+			sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
+			cur_idx = txn->hdr_idx.v[cur_idx].next;
+		}
+	}
 
-			sol += hdr_idx_first_pos(&txn->hdr_idx);
-			cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
+	/*
+	 * Now we quickly check if we have found a full valid response.
+	 * If not so, we check the FD and buffer states before leaving.
+	 * A full response is indicated by the fact that we have seen
+	 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
+	 * responses are checked first.
+	 *
+	 * Depending on whether the client is still there or not, we
+	 * may send an error response back or not. Note that normally
+	 * we should only check for HTTP status there, and check I/O
+	 * errors somewhere else.
+	 */
 
-			while (cur_idx) {
-				eol = sol + txn->hdr_idx.v[cur_idx].len;
-				debug_hdr("srvhdr", t, sol, eol);
-				sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
-				cur_idx = txn->hdr_idx.v[cur_idx].next;
-			}
+	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+		/* Invalid response */
+		if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
+			/* we detected a parsing error. We want to archive this response
+			 * in the dedicated proxy area for later troubleshooting.
+			 */
+		hdr_response_bad:
+			if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
+				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
+
+			s->be->counters.failed_resp++;
+			if (s->srv)
+				s->srv->counters.failed_resp++;
+
+			rep->analysers = 0;
+			txn->status = 502;
+			stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
+
+			if (!(s->flags & SN_ERR_MASK))
+				s->flags |= SN_ERR_PRXCOND;
+			if (!(s->flags & SN_FINST_MASK))
+				s->flags |= SN_FINST_H;
+
+			return 0;
 		}
 
-		/*
-		 * Now we quickly check if we have found a full valid response.
-		 * If not so, we check the FD and buffer states before leaving.
-		 * A full response is indicated by the fact that we have seen
-		 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
-		 * responses are checked first.
-		 *
-		 * Depending on whether the client is still there or not, we
-		 * may send an error response back or not. Note that normally
-		 * we should only check for HTTP status there, and check I/O
-		 * errors somewhere else.
-		 */
+		/* too large response does not fit in buffer. */
+		else if (rep->flags & BF_FULL) {
+			goto hdr_response_bad;
+		}
 
-		if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
-			/* Invalid response */
-			if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
-				/* we detected a parsing error. We want to archive this response
-				 * in the dedicated proxy area for later troubleshooting.
-				 */
-			hdr_response_bad:
-				if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
-					http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
+		/* read error */
+		else if (rep->flags & BF_READ_ERROR) {
+			if (msg->err_pos >= 0)
+				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
 
-				buffer_shutr_now(rep);
-				buffer_shutw_now(req);
-				if (t->srv)
-					t->srv->counters.failed_resp++;
-				t->be->counters.failed_resp++;
-				rep->analysers = 0;
-				txn->status = 502;
-				stream_int_return(rep->cons, error_message(t, HTTP_ERR_502));
-				if (!(t->flags & SN_ERR_MASK))
-					t->flags |= SN_ERR_PRXCOND;
-				if (!(t->flags & SN_FINST_MASK))
-					t->flags |= SN_FINST_H;
+			s->be->counters.failed_resp++;
+			if (s->srv)
+				s->srv->counters.failed_resp++;
 
-				return 0;
-			}
-			/* 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) {
-				if (msg->err_pos >= 0)
-					http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
-				buffer_shutr_now(rep);
-				buffer_shutw_now(req);
-				if (t->srv)
-					t->srv->counters.failed_resp++;
-				t->be->counters.failed_resp++;
-				rep->analysers = 0;
-				txn->status = 502;
-				stream_int_return(rep->cons, 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;
-				return 0;
-			}
-			/* read timeout : return a 504 to the client. */
-			else if (rep->flags & BF_READ_TIMEOUT) {
-				if (msg->err_pos >= 0)
-					http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
-				buffer_shutr_now(rep);
-				buffer_shutw_now(req);
-				if (t->srv)
-					t->srv->counters.failed_resp++;
-				t->be->counters.failed_resp++;
-				rep->analysers = 0;
-				txn->status = 504;
-				stream_int_return(rep->cons, error_message(t, HTTP_ERR_504));
-				if (!(t->flags & SN_ERR_MASK))
-					t->flags |= SN_ERR_SRVTO;
-				if (!(t->flags & SN_FINST_MASK))
-					t->flags |= SN_FINST_H;
-				return 0;
-			}
-			/* close from server */
-			else if (rep->flags & BF_SHUTR) {
-				if (msg->err_pos >= 0)
-					http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
-				buffer_shutw_now(req);
-				if (t->srv)
-					t->srv->counters.failed_resp++;
-				t->be->counters.failed_resp++;
-				rep->analysers = 0;
-				txn->status = 502;
-				stream_int_return(rep->cons, 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;
-				return 0;
-			}
-			/* write error to client (we don't send any message then) */
-			else if (rep->flags & BF_WRITE_ERROR) {
-				if (msg->err_pos >= 0)
-					http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
-				buffer_shutr_now(rep);
-				t->be->counters.failed_resp++;
-				rep->analysers = 0;
-				if (!(t->flags & SN_ERR_MASK))
-					t->flags |= SN_ERR_CLICL;
-				if (!(t->flags & SN_FINST_MASK))
-					t->flags |= SN_FINST_H;
-				return 0;
-			}
+			rep->analysers = 0;
+			txn->status = 502;
+			stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
 
-			buffer_dont_close(rep);
+			if (!(s->flags & SN_ERR_MASK))
+				s->flags |= SN_ERR_SRVCL;
+			if (!(s->flags & SN_FINST_MASK))
+				s->flags |= SN_FINST_H;
 			return 0;
 		}
 
+		/* read timeout : return a 504 to the client. */
+		else if (rep->flags & BF_READ_TIMEOUT) {
+			if (msg->err_pos >= 0)
+				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
 
-		/*****************************************************************
-		 * More interesting part now : we know that we have a complete   *
-		 * response which at least looks like HTTP. We have an indicator *
-		 * of each header's length, so we can parse them quickly.        *
-		 ****************************************************************/
+			s->be->counters.failed_resp++;
+			if (s->srv)
+				s->srv->counters.failed_resp++;
 
-		if (msg->err_pos >= 0)
-			http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
+			rep->analysers = 0;
+			txn->status = 504;
+			stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_504));
 
-		rep->analysers &= ~AN_RTR_HTTP_HDR;
+			if (!(s->flags & SN_ERR_MASK))
+				s->flags |= SN_ERR_SRVTO;
+			if (!(s->flags & SN_FINST_MASK))
+				s->flags |= SN_FINST_H;
+			return 0;
+		}
 
-		/* ensure we keep this pointer to the beginning of the message */
-		msg->sol = rep->data + msg->som;
+		/* close from server */
+		else if (rep->flags & BF_SHUTR) {
+			if (msg->err_pos >= 0)
+				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
 
-		/*
-		 * 1: get the status code and check for cacheability.
-		 */
+			s->be->counters.failed_resp++;
+			if (s->srv)
+				s->srv->counters.failed_resp++;
 
-		t->logs.logwait &= ~LW_RESP;
-		txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
+			rep->analysers = 0;
+			txn->status = 502;
+			stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
 
-		n = rep->data[msg->sl.st.c] - '0';
-		if (n < 1 || n > 5)
-			n = 0;
+			if (!(s->flags & SN_ERR_MASK))
+				s->flags |= SN_ERR_SRVCL;
+			if (!(s->flags & SN_FINST_MASK))
+				s->flags |= SN_FINST_H;
+			return 0;
+		}
 
-		t->srv->counters.p.http.rsp[n]++;
-		t->be->counters.p.http.rsp[n]++;
+		/* write error to client (we don't send any message then) */
+		else if (rep->flags & BF_WRITE_ERROR) {
+			if (msg->err_pos >= 0)
+				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
 
-		switch (txn->status) {
-		case 200:
-		case 203:
-		case 206:
-		case 300:
-		case 301:
-		case 410:
-			/* RFC2616 @13.4:
-			 *   "A response received with a status code of
-			 *    200, 203, 206, 300, 301 or 410 MAY be stored
-			 *    by a cache (...) unless a cache-control
-			 *    directive prohibits caching."
-			 *   
-			 * RFC2616 @9.5: POST method :
-			 *   "Responses to this method are not cacheable,
-			 *    unless the response includes appropriate
-			 *    Cache-Control or Expires header fields."
-			 */
-			if (likely(txn->meth != HTTP_METH_POST) &&
-			    (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
-				txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
-			break;
-		default:
-			break;
+			s->be->counters.failed_resp++;
+			rep->analysers = 0;
+
+			if (!(s->flags & SN_ERR_MASK))
+				s->flags |= SN_ERR_CLICL;
+			if (!(s->flags & SN_FINST_MASK))
+				s->flags |= SN_FINST_H;
+
+			/* process_session() will take care of the error */
+			return 0;
 		}
 
-		/*
-		 * 2: we may need to capture headers
+		buffer_dont_close(rep);
+		return 0;
+	}
+
+	/* More interesting part now : we know that we have a complete
+	 * response which at least looks like HTTP. We have an indicator
+	 * of each header's length, so we can parse them quickly.
+	 */
+
+	if (unlikely(msg->err_pos >= 0))
+		http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
+
+	/* ensure we keep this pointer to the beginning of the message */
+	msg->sol = rep->data + msg->som;
+
+	/*
+	 * 1: get the status code
+	 */
+	n = rep->data[msg->sl.st.c] - '0';
+	if (n < 1 || n > 5)
+		n = 0;
+	s->srv->counters.p.http.rsp[n]++;
+	s->be->counters.p.http.rsp[n]++;
+
+	txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
+
+	/*
+	 * 2: check for cacheability.
+	 */
+
+	switch (txn->status) {
+	case 200:
+	case 203:
+	case 206:
+	case 300:
+	case 301:
+	case 410:
+		/* RFC2616 @13.4:
+		 *   "A response received with a status code of
+		 *    200, 203, 206, 300, 301 or 410 MAY be stored
+		 *    by a cache (...) unless a cache-control
+		 *    directive prohibits caching."
+		 *
+		 * RFC2616 @9.5: POST method :
+		 *   "Responses to this method are not cacheable,
+		 *    unless the response includes appropriate
+		 *    Cache-Control or Expires header fields."
 		 */
-		if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
-			capture_headers(rep->data + msg->som, &txn->hdr_idx,
-					txn->rsp.cap, t->fe->rsp_cap);
+		if (likely(txn->meth != HTTP_METH_POST) &&
+		    (s->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
+			txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
+		break;
+	default:
+		break;
+	}
 
+	/*
+	 * 3: we may need to capture headers
+	 */
+	s->logs.logwait &= ~LW_RESP;
+	if (unlikely((s->logs.logwait & LW_RSPHDR) && s->fe->rsp_cap))
+		capture_headers(rep->data + msg->som, &txn->hdr_idx,
+				txn->rsp.cap, s->fe->rsp_cap);
+
+	/* end of job, return OK */
+	rep->analysers &= ~an_bit;
+	rep->analyse_exp = TICK_ETERNITY;
+	return 1;
+}
+
+/* This function performs all the processing enabled for the current response.
+ * It normally returns zero, but may return 1 if it absolutely needs to be
+ * called again after other functions. It relies on buffers flags, and updates
+ * t->rep->analysers. It might make sense to explode it into several other
+ * functions. It works like process_request (see indications above).
+ */
+int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, struct proxy *px)
+{
+	struct http_txn *txn = &t->txn;
+	struct buffer *req = t->req;
+	struct http_msg *msg = &txn->rsp;
+	struct proxy *cur_proxy;
+	int cur_idx;
+
+	DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
+		now_ms, __FUNCTION__,
+		t,
+		rep,
+		rep->rex, rep->wex,
+		rep->flags,
+		rep->l,
+		rep->analysers);
+
+	if (unlikely(msg->msg_state != HTTP_MSG_BODY))	/* we need more data */
+		return 0;
+
+	rep->analysers &= ~an_bit;
+	rep->analyse_exp = TICK_ETERNITY;
+
+	if (1) {
 		/*
 		 * 3: we will have to evaluate the filters.
 		 * As opposed to version 1.2, now they will be evaluated in the
@@ -3308,8 +3349,8 @@
 			buffer_forward(rep, rep->lr - (rep->data + msg->som));
 			msg->msg_state = HTTP_MSG_RPBEFORE;
 			txn->status = 0;
-			rep->analysers |= AN_RTR_HTTP_HDR;
-			goto next_response;
+			rep->analysers |= AN_RES_WAIT_HTTP | an_bit;
+			return 1;
 		}
 
 		/*************************************************************
@@ -3337,18 +3378,6 @@
 
 		return 0;
 	}
-
-	/* Note: eventhough nobody should set an unknown flag, clearing them right now will
-	 * probably reduce one day's debugging session.
-	 */
-#ifdef DEBUG_DEV
-	if (rep->analysers & ~(AN_RTR_HTTP_HDR)) {
-		fprintf(stderr, "FIXME !!!! unknown analysers flags %s:%d = 0x%08X\n",
-			__FILE__, __LINE__, rep->analysers);
-		ABORT_NOW();
-	}
-#endif
-	rep->analysers &= AN_RTR_HTTP_HDR;
 	return 0;
 }
 
diff --git a/src/session.c b/src/session.c
index fefdc86..b010f59 100644
--- a/src/session.c
+++ b/src/session.c
@@ -894,10 +894,43 @@
 		unsigned int flags = s->rep->flags;
 
 		if (s->rep->prod->state >= SI_ST_EST) {
+			unsigned int last_ana = 0;
+
 			/* it's up to the analysers to reset auto_close */
 			buffer_auto_close(s->rep);
-			if (s->rep->analysers)
-				process_response(s);
+
+			/* We will call all analysers for which a bit is set in
+			 * s->rep->analysers, following the bit order from LSB
+			 * to MSB. The analysers must remove themselves from
+			 * the list when not needed. Any analyser may return 0
+			 * to break out of the loop, either because of missing
+			 * data to take a decision, or because it decides to
+			 * kill the session. We loop at least once through each
+			 * analyser, and we may loop again if other analysers
+			 * are added in the middle.
+			 */
+			while (s->rep->analysers & ~last_ana) {
+				last_ana = s->rep->analysers;
+
+				if (s->rep->analysers & AN_RES_WAIT_HTTP) {
+					last_ana |= AN_RES_WAIT_HTTP;
+					if (!http_wait_for_response(s, s->rep, AN_RES_WAIT_HTTP))
+						break;
+				}
+
+				if (s->rep->analysers & AN_RES_HTTP_PROCESS_BE) {
+					last_ana |= AN_RES_HTTP_PROCESS_BE;
+					if (!http_process_res_common(s, s->rep, AN_RES_HTTP_PROCESS_BE, s->be))
+						break;
+					/* FIXME: we may wait for a second response in case of a status 1xx
+					 * and want to immediately loop back to the top. This is a dirty way
+					 * of doing it, and we should find a cleaner method relying on a
+					 * circular list of function pointers.
+					 */
+					if ((s->rep->analysers & ~last_ana) & AN_RES_WAIT_HTTP)
+						continue;
+				}
+			}
 		}
 
 		if ((s->rep->flags ^ flags) & BF_MASK_STATIC) {