[MINOR] http: create new MSG_BODY sub-states

An HTTP message can be decomposed into several sub-states depending
on the transfer-encoding. We'll have to keep these state information
while parsing chunks, so we must extend the values. In order not to
change everything, we'll now consider that anything >= MSG_BODY is
the body, and that the value indicates the precise state. The
MSG_ERROR status which was greater than MSG_BODY was moved for this.
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index 35114a8..93376e5 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -145,8 +145,24 @@
 #define HTTP_MSG_HDR_L2_LWS   24 // checking whether it's a new header or an LWS
 
 #define HTTP_MSG_LAST_LF      25 // parsing last LF
-#define HTTP_MSG_BODY         26 // parsing body at end of headers
-#define HTTP_MSG_ERROR        27 // an error occurred
+
+/* error state : must be before HTTP_MSG_BODY so that (>=BODY) always indicates
+ * that data are being processed.
+ */
+
+#define HTTP_MSG_ERROR        26 // an error occurred
+
+/* Body processing.
+ * The state HTTP_MSG_BODY is a delimiter to know if we're waiting for headers
+ * or body. All the sub-states below also indicate we're processing the body,
+ * with some additional information.
+ */
+#define HTTP_MSG_BODY         27 // parsing body at end of headers
+#define HTTP_MSG_100_SENT     28 // parsing body after a 100-Continue was sent
+#define HTTP_MSG_CHUNK_SIZE   29 // parsing the chunk size (RFC2616 #3.6.1)
+#define HTTP_MSG_DATA         30 // skipping data chunk / content-length data
+#define HTTP_MSG_DATA_CRLF    31 // skipping CRLF after data chunk
+#define HTTP_MSG_TRAILERS     32 // trailers (post-data entity headers)
 
 
 /* various data sources for the responses */
diff --git a/src/proto_http.c b/src/proto_http.c
index b78fc53..3aa8f5a 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1,7 +1,7 @@
 /*
  * HTTP protocol analyzer
  *
- * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -1791,7 +1791,7 @@
 	/* 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))) {
+		     (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
 		char *eol, *sol;
 
 		sol = req->data + msg->som;
@@ -1814,12 +1814,12 @@
 	 * Now we quickly check if we have found a full valid request.
 	 * If not so, we check the FD and buffer states before leaving.
 	 * A full request is indicated by the fact that we have seen
-	 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
+	 * the double LF/CRLF, so the state is >= HTTP_MSG_BODY. Invalid
 	 * requests are checked first.
 	 *
 	 */
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		/*
 		 * First, let's catch bad requests.
 		 */
@@ -2137,7 +2137,7 @@
 	struct redirect_rule *rule;
 	int cur_idx;
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		/* we need more data */
 		buffer_dont_connect(req);
 		return 0;
@@ -2439,7 +2439,7 @@
 	struct http_txn *txn = &s->txn;
 	struct http_msg *msg = &txn->req;
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		/* we need more data */
 		buffer_dont_connect(req);
 		return 0;
@@ -2769,7 +2769,7 @@
 	unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1;
 	long long limit = s->be->url_param_post_limit;
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		/* we need more data */
 		buffer_dont_connect(req);
 		return 0;
@@ -2891,7 +2891,7 @@
 	/* 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))) {
+		     (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
 		char *eol, *sol;
 
 		sol = rep->data + msg->som;
@@ -2913,7 +2913,7 @@
 	 * 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
+	 * 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
@@ -2922,7 +2922,7 @@
 	 * errors somewhere else.
 	 */
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	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
@@ -3217,7 +3217,7 @@
 		rep->l,
 		rep->analysers);
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY))	/* we need more data */
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY))	/* we need more data */
 		return 0;
 
 	rep->analysers &= ~an_bit;
@@ -4885,7 +4885,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	meth = txn->meth;
@@ -4945,7 +4945,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	len = txn->req.sl.rq.v_l;
@@ -4973,7 +4973,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	len = txn->rsp.sl.st.v_l;
@@ -5002,7 +5002,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	len = txn->rsp.sl.st.c_l;
@@ -5023,7 +5023,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5047,7 +5047,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5079,7 +5079,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5137,7 +5137,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5156,7 +5156,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
@@ -5196,7 +5196,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5215,7 +5215,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
@@ -5261,7 +5261,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5280,7 +5280,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
@@ -5329,7 +5329,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5348,7 +5348,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->rsp.msg_state != HTTP_MSG_BODY)
+	if (txn->rsp.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	return acl_fetch_hdr_ip(px, l4, txn, txn->rsp.sol, expr, test);
@@ -5367,7 +5367,7 @@
 	if (!txn)
 		return 0;
 
-	if (txn->req.msg_state != HTTP_MSG_BODY)
+	if (txn->req.msg_state < HTTP_MSG_BODY)
 		return 0;
 
 	if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
@@ -5407,7 +5407,7 @@
 	if (!s || !req)
 		return 0;
 
-	if (unlikely(msg->msg_state == HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state >= HTTP_MSG_BODY)) {
 		/* Already decoded as OK */
 		test->flags |= ACL_TEST_F_SET_RES_PASS;
 		return 1;
@@ -5417,7 +5417,7 @@
 	if (likely(req->lr < req->r))
 		http_msg_analyzer(req, msg, &txn->hdr_idx);
 
-	if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		if ((msg->msg_state == HTTP_MSG_ERROR) || (req->flags & BF_FULL)) {
 			test->flags |= ACL_TEST_F_SET_RES_FAIL;
 			return 1;