MINOR: htx: make htx_add_data() return the transmitted byte count

In order to later allow htx_add_data() to transmit partial blocks and
avoid defragmenting the buffer, we'll need to return the number of bytes
consumed. This first modification makes the function do this and its
callers take this into account. At the moment the function still works
atomically so it returns either the block size or zero. However all
call places have been adapted to consider any value between zero and
the block size.
diff --git a/src/cache.c b/src/cache.c
index 83aacd1..e390b21 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -957,8 +957,7 @@
 		sz = MIN(len, shctx->block_size - offset);
 		data = ist2((const char *)shblk->data + offset, sz);
 		if (type == HTX_BLK_DATA) {
-			if (!htx_add_data(htx, data))
-				break;
+			sz = htx_add_data(htx, data);
 		}
 		else { /* HTX_BLK_TLR */
 			if (!htx_add_trailer(htx, data))
@@ -968,7 +967,7 @@
 		offset += sz;
 		len -= sz;
 		total += sz;
-		if (!len)
+		if (!len || sz < data.len)
 			break;
 		offset = 0;
 	}
diff --git a/src/hlua.c b/src/hlua.c
index 3c9c70a..a3fd57b 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -4568,8 +4568,7 @@
 		max = len - l;
 
 	/* Copy data. */
-	if (!htx_add_data(htx, ist2(data + l, max)))
-		goto snd_yield;
+	max = htx_add_data(htx, ist2(data + l, max));
 	channel_add_input(res, max);
 
 	/* update counters. */
diff --git a/src/http_htx.c b/src/http_htx.c
index b9501be..9892fd3 100644
--- a/src/http_htx.c
+++ b/src/http_htx.c
@@ -657,9 +657,11 @@
 		goto error;
 	sl->info.res.status = h1sl.st.status;
 
-	if (raw.len > ret) {
-		if (!htx_add_data(htx, ist2(raw.ptr + ret, raw.len - ret)))
+	while (raw.len > ret) {
+		int sent = htx_add_data(htx, ist2(raw.ptr + ret, raw.len - ret));
+		if (!sent)
 			goto error;
+		ret += sent;
 	}
 	if (!htx_add_endof(htx, HTX_BLK_EOM))
 		goto error;
diff --git a/src/htx.c b/src/htx.c
index 2aeb077..32e23d1 100644
--- a/src/htx.c
+++ b/src/htx.c
@@ -758,11 +758,18 @@
 
 
 /* Adds an HTX block of type DATA in <htx>. It first tries to append data if
- * possible. It returns the new block on success. Otherwise, it returns NULL.
+ * possible. It returns the number of bytes consumed from <data>, which may be
+ * zero if nothing could be copied.
  */
-struct htx_blk *htx_add_data(struct htx *htx, const struct ist data)
+size_t htx_add_data(struct htx *htx, const struct ist data)
 {
-	return htx_add_data_atonce(htx, data);
+	struct htx_blk *blk;
+
+	blk = htx_add_data_atonce(htx, data);
+	if (blk)
+		return data.len;
+	else
+		return 0;
 }
 
 /* Adds an HTX block of type TLR in <htx>. It returns the new block on
diff --git a/src/mux_h1.c b/src/mux_h1.c
index d1e7c1d..ef622bd 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -1143,6 +1143,8 @@
 				 *   => we can swap the buffers and place an htx header into
 				 *      the target buffer instead
 				 */
+				int32_t try = ret;
+
 				if (unlikely(htx_is_empty(htx) && ret == b_data(buf) &&
 					     !*ofs && b_head_ofs(buf) == sizeof(struct htx))) {
 					void *raw_area = buf->area;
@@ -1162,12 +1164,15 @@
 					 * empty pre-initialized HTX header
 					 */
 				}
-				else if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret)))
-					goto end;
+				else {
+					ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try));
+				}
 				h1m->curr_len -= ret;
 				max -= sizeof(struct htx_blk) + ret;
 				*ofs += ret;
 				total += ret;
+				if (ret < try)
+					goto end;
 			}
 
 			if (!h1m->curr_len) {
@@ -1220,12 +1225,15 @@
 					ret = b_contig_data(buf, *ofs);
 
 				if (ret) {
-					if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret)))
-						goto end;
+					int32_t try = ret;
+
+					ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try));
 					h1m->curr_len -= ret;
 					max -= sizeof(struct htx_blk) + ret;
 					*ofs += ret;
 					total += ret;
+					if (ret < try)
+						goto end;
 				}
 				if (!h1m->curr_len) {
 					h1m->state = H1_MSG_CHUNK_CRLF;
@@ -1291,11 +1299,14 @@
 			ret = b_contig_data(buf, *ofs);
 
 		if (ret) {
-			if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret)))
-				goto end;
+			int32_t try = ret;
+
+			ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try));
 
 			*ofs += ret;
 			total = ret;
+			if (ret < try)
+				goto end;
 		}
 	}
 
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 6bec578..7d29a7d 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -3802,6 +3802,8 @@
 	}
 
 	if (htx) {
+		unsigned int sent;
+
 		block1 = htx_free_data_space(htx);
 		if (!block1) {
 			h2c->flags |= H2_CF_DEM_SFULL;
@@ -3815,10 +3817,7 @@
 		if (flen > block1)
 			flen = block1;
 
-		if (!htx_add_data(htx, ist2(b_head(&h2c->dbuf), flen))) {
-			h2c->flags |= H2_CF_DEM_SFULL;
-			goto fail;
-		}
+		sent = htx_add_data(htx, ist2(b_head(&h2c->dbuf), flen));
 
 		b_del(&h2c->dbuf, flen);
 		h2c->dfl    -= flen;
@@ -3829,6 +3828,12 @@
 			h2s->body_len -= flen;
 			htx->extra = h2s->body_len;
 		}
+
+		if (sent < flen) {
+			h2c->flags |= H2_CF_DEM_SFULL;
+			goto fail;
+		}
+
 		goto try_again;
 	}
 	else if (unlikely(b_space_wraps(csbuf) &&
diff --git a/src/proto_htx.c b/src/proto_htx.c
index 0bb1eb2..27150a8 100644
--- a/src/proto_htx.c
+++ b/src/proto_htx.c
@@ -5502,7 +5502,18 @@
 		goto fail;
 	if (status == 407 && !htx_add_header(htx, ist("Proxy-Authenticate"), ist2(trash.area, trash.data)))
 		goto fail;
-	if (!htx_add_endof(htx, HTX_BLK_EOH) || !htx_add_data(htx, body) || !htx_add_endof(htx, HTX_BLK_EOM))
+	if (!htx_add_endof(htx, HTX_BLK_EOH))
+		goto fail;
+
+	while (body.len) {
+		size_t sent = htx_add_data(htx, body);
+		if (!sent)
+			goto fail;
+		body.ptr += sent;
+		body.len -= sent;
+	}
+
+	if (!htx_add_endof(htx, HTX_BLK_EOM))
 		goto fail;
 
 	data = htx->data - co_data(res);
diff --git a/src/stats.c b/src/stats.c
index 9c3bf7c..4b994b7 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -258,7 +258,7 @@
 	if (htx) {
 		if (chk->data >= channel_htx_recv_max(chn, htx))
 			return 0;
-		if (!htx_add_data(htx, ist2(chk->area, chk->data)))
+		if (!htx_add_data_atonce(htx, ist2(chk->area, chk->data)))
 			return 0;
 		channel_add_input(chn, chk->data);
 		chk->data = 0;