[BUG] http: fix computation of message body length after forwarding has started

Till now, the forwarding code was making use of the hdr_content_len member
to hold the size of the last chunk parsed. As such, it was reset after being
scheduled for forwarding. The issue is that this entry was reset before the
data could be viewed by backend.c in order to parse a POST body, so the
"balance url_param check_post" did not work anymore.

In order to fix this, we need two things :
  - the chunk size (reset upon every forward)
  - the total body size (not reset)

hdr_content_len was thus replaced by the former (hence the size of the patch)
as it makes more sense to have it stored that way than the way around.

This patch should be backported to 1.4 with care, considering that it affects
the forwarding code.
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index 2222304..1fdaf0f 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -300,7 +300,8 @@
 			int r, r_l;            /* REASON, length */
 		} st;                          /* status line : field, length */
 	} sl;                                  /* start line */
-	unsigned long long hdr_content_len;    /* cache for parsed header value or for chunk-size if present */
+	unsigned long long chunk_len;          /* cache for last chunk size or content-length header value */
+	unsigned long long body_len;           /* total known length of the body, excluding encoding */
 	char **cap;                            /* array of captured headers (may be NULL) */
 };
 
diff --git a/src/backend.c b/src/backend.c
index 6d1adff..7554923 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -251,7 +251,7 @@
 	struct http_msg *msg  = &txn->req;
 	struct proxy    *px   = s->be;
 	unsigned int     plen = px->url_param_len;
-	unsigned long    len  = msg->hdr_content_len;
+	unsigned long    len  = msg->body_len;
 	const char      *params = req->data + msg->sov;
 	const char      *p    = params;
 
diff --git a/src/proto_http.c b/src/proto_http.c
index 12bb2a3..eb6ba30 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2148,7 +2148,8 @@
 	 */
 	msg->sov += ptr - buf->lr;
 	buf->lr = ptr;
-	msg->hdr_content_len = chunk;
+	msg->chunk_len = chunk;
+	msg->body_len += chunk;
 	msg->msg_state = chunk ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
 	return 1;
  error:
@@ -2809,11 +2810,11 @@
 		if (cl < 0)
 			goto return_bad_req;
 
-		if ((txn->flags & TX_REQ_CNT_LEN) && (msg->hdr_content_len != cl))
+		if ((txn->flags & TX_REQ_CNT_LEN) && (msg->chunk_len != cl))
 			goto return_bad_req; /* already specified, was different */
 
 		txn->flags |= TX_REQ_CNT_LEN | TX_REQ_XFER_LEN;
-		msg->hdr_content_len = cl;
+		msg->body_len = msg->chunk_len = cl;
 	}
 
 	/* bodyless requests have a known length */
@@ -2869,7 +2870,7 @@
 	char *first_param, *cur_param, *next_param, *end_params;
 
 	first_param = req->data + txn->req.eoh + 2;
-	end_params  = first_param + txn->req.hdr_content_len;
+	end_params  = first_param + txn->req.body_len;
 
 	cur_param = next_param = end_params;
 
@@ -3348,7 +3349,7 @@
 
 			if (rule->rdr_len >= 1 && *rule->rdr_str == '/' &&
 			    (txn->flags & TX_REQ_XFER_LEN) &&
-			    !(txn->flags & TX_REQ_TE_CHNK) && !txn->req.hdr_content_len &&
+			    !(txn->flags & TX_REQ_TE_CHNK) && !txn->req.body_len &&
 			    ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
 			     (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
 				/* keep-alive possible */
@@ -3769,7 +3770,7 @@
 	}
 
 	if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
-		/* read the chunk size and assign it to ->hdr_content_len, then
+		/* read the chunk size and assign it to ->chunk_len, then
 		 * set ->sov and ->lr to point to the body and switch to DATA or
 		 * TRAILERS state.
 		 */
@@ -3790,8 +3791,8 @@
 	 * We're waiting for at least <url_param_post_limit> bytes after msg->sov.
 	 */
 
-	if (msg->hdr_content_len < limit)
-		limit = msg->hdr_content_len;
+	if (msg->body_len < limit)
+		limit = msg->body_len;
 
 	if (req->l - (msg->sov - msg->som) >= limit)    /* we have enough bytes now */
 		goto http_end;
@@ -4311,7 +4312,7 @@
  * remaining data and to resync after end of body. It expects the msg_state to
  * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
  * read more data, or 1 once we can go on with next request or end the session.
- * When in MSG_DATA or MSG_TRAILERS, it will automatically forward hdr_content_len
+ * When in MSG_DATA or MSG_TRAILERS, it will automatically forward chunk_len
  * bytes of pending data + the headers if not already done (between som and sov).
  * It eventually adjusts som to match sov after the data in between have been sent.
  */
@@ -4359,12 +4360,12 @@
 	while (1) {
 		http_silent_debug(__LINE__, s);
 		/* we may have some data pending */
-		if (msg->hdr_content_len || msg->som != msg->sov) {
+		if (msg->chunk_len || msg->som != msg->sov) {
 			int bytes = msg->sov - msg->som;
 			if (bytes < 0) /* sov may have wrapped at the end */
 				bytes += req->size;
-			buffer_forward(req, bytes + msg->hdr_content_len);
-			msg->hdr_content_len = 0; /* don't forward that again */
+			buffer_forward(req, bytes + msg->chunk_len);
+			msg->chunk_len = 0; /* don't forward that again */
 			msg->som = msg->sov;
 		}
 
@@ -4380,7 +4381,7 @@
 				msg->msg_state = HTTP_MSG_DONE;
 		}
 		else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
-			/* read the chunk size and assign it to ->hdr_content_len, then
+			/* read the chunk size and assign it to ->chunk_len, then
 			 * set ->sov and ->lr to point to the body and switch to DATA or
 			 * TRAILERS state.
 			 */
@@ -4935,7 +4936,7 @@
 	 */
 
 	/* Skip parsing if no content length is possible. The response flags
-	 * remain 0 as well as the hdr_content_len, which may or may not mirror
+	 * remain 0 as well as the chunk_len, which may or may not mirror
 	 * the real header value, and we note that we know the response's length.
 	 * FIXME: should we parse anyway and return an error on chunked encoding ?
 	 */
@@ -4975,11 +4976,11 @@
 		if (cl < 0)
 			goto hdr_response_bad;
 
-		if ((txn->flags & TX_RES_CNT_LEN) && (msg->hdr_content_len != cl))
+		if ((txn->flags & TX_RES_CNT_LEN) && (msg->chunk_len != cl))
 			goto hdr_response_bad; /* already specified, was different */
 
 		txn->flags |= TX_RES_CNT_LEN | TX_RES_XFER_LEN;
-		msg->hdr_content_len = cl;
+		msg->body_len = msg->chunk_len = cl;
 	}
 
 	/* FIXME: we should also implement the multipart/byterange method.
@@ -5360,7 +5361,7 @@
  * remaining data and to resync after end of body. It expects the msg_state to
  * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
  * read more data, or 1 once we can go on with next request or end the session.
- * When in MSG_DATA or MSG_TRAILERS, it will automatically forward hdr_content_len
+ * When in MSG_DATA or MSG_TRAILERS, it will automatically forward chunk_len
  * bytes of pending data + the headers if not already done (between som and sov).
  * It eventually adjusts som to match sov after the data in between have been sent.
  */
@@ -5403,12 +5404,12 @@
 	while (1) {
 		http_silent_debug(__LINE__, s);
 		/* we may have some data pending */
-		if (msg->hdr_content_len || msg->som != msg->sov) {
+		if (msg->chunk_len || msg->som != msg->sov) {
 			int bytes = msg->sov - msg->som;
 			if (bytes < 0) /* sov may have wrapped at the end */
 				bytes += res->size;
-			buffer_forward(res, bytes + msg->hdr_content_len);
-			msg->hdr_content_len = 0; /* don't forward that again */
+			buffer_forward(res, bytes + msg->chunk_len);
+			msg->chunk_len = 0; /* don't forward that again */
 			msg->som = msg->sov;
 		}
 
@@ -5424,7 +5425,7 @@
 				msg->msg_state = HTTP_MSG_DONE;
 		}
 		else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
-			/* read the chunk size and assign it to ->hdr_content_len, then
+			/* read the chunk size and assign it to ->chunk_len, then
 			 * set ->sov to point to the body and switch to DATA or TRAILERS state.
 			 */
 			int ret = http_parse_chunk_size(res, msg);
@@ -5521,12 +5522,12 @@
 		goto return_bad_res;
 
 	/* forward the chunk size as well as any pending data */
-	if (msg->hdr_content_len || msg->som != msg->sov) {
+	if (msg->chunk_len || msg->som != msg->sov) {
 		int bytes = msg->sov - msg->som;
 		if (bytes < 0) /* sov may have wrapped at the end */
 			bytes += res->size;
-		buffer_forward(res, msg->sov - msg->som + msg->hdr_content_len);
-		msg->hdr_content_len = 0; /* don't forward that again */
+		buffer_forward(res, msg->sov - msg->som + msg->chunk_len);
+		msg->chunk_len = 0; /* don't forward that again */
 		msg->som = msg->sov;
 	}
 
@@ -7455,8 +7456,10 @@
 	txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
 	txn->rsp.sol = txn->rsp.eol = NULL;
 	txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */
-	txn->req.hdr_content_len = 0LL;
-	txn->rsp.hdr_content_len = 0LL;
+	txn->req.chunk_len = 0LL;
+	txn->req.body_len = 0LL;
+	txn->rsp.chunk_len = 0LL;
+	txn->rsp.body_len = 0LL;
 	txn->req.msg_state = HTTP_MSG_RQBEFORE; /* at the very beginning of the request */
 	txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */