MEDIUM: mux-h2: make h2_snd_buf() HTX-aware

Now h2_snd_buf() will check the proxy's mode to decide whether to use
HTX-specific send functions or legacy functions. In HTX mode, the HTX
blocks of the output buffer will be parsed and the related functions
will be called accordingly based on the block type, and unimplemented
blocks will be skipped. For now all blocks are skipped, this is only
helpful for debugging.
diff --git a/src/mux_h2.c b/src/mux_h2.c
index c07cdd9..898c51a 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -20,6 +20,8 @@
 #include <common/net_helper.h>
 #include <proto/connection.h>
 #include <proto/h1.h>
+#include <proto/http_htx.h>
+#include <proto/htx.h>
 #include <proto/stream.h>
 #include <types/session.h>
 #include <eb32tree.h>
@@ -3652,6 +3654,11 @@
 	struct h2s *h2s = cs->ctx;
 	size_t total = 0;
 	size_t ret;
+	struct htx *htx;
+	struct htx_blk *blk;
+	enum htx_blk_type btype;
+	uint32_t bsize;
+	int32_t idx;
 
 	if (h2s->send_wait) {
 		h2s->send_wait->wait_reason &= ~SUB_CALL_UNSUBSCRIBE;
@@ -3662,9 +3669,31 @@
 	if (h2s->h2c->st0 < H2_CS_FRAME_H)
 		return 0;
 
+	/* htx will be enough to decide if we're using HTX or legacy */
+	htx = (h2s->h2c->proxy->options2 & PR_O2_USE_HTX) ? htx_from_buf(buf) : NULL;
+
 	if (!(h2s->flags & H2_SF_OUTGOING_DATA) && count)
 		h2s->flags |= H2_SF_OUTGOING_DATA;
 
+	if (htx) {
+		while (count && !htx_is_empty(htx)) {
+			idx   = htx_get_head(htx);
+			blk   = htx_get_blk(htx, idx);
+			btype = htx_get_blk_type(blk);
+			bsize = htx_get_blksz(blk);
+
+			switch (btype) {
+			default:
+				htx_remove_blk(htx, blk);
+				total += bsize;
+				count -= bsize;
+				break;
+			}
+		}
+		goto done;
+	}
+
+	/* legacy transfer mode */
 	while (h2s->h1m.state < H1_MSG_DONE && count) {
 		if (h2s->h1m.state <= H1_MSG_LAST_LF) {
 			ret = h2s_frt_make_resp_headers(h2s, buf, total, count);
@@ -3702,6 +3731,7 @@
 			break;
 	}
 
+ done:
 	if (h2s->st >= H2_SS_ERROR) {
 		/* trim any possibly pending data after we close (extra CR-LF,
 		 * unprocessed trailers, abnormal extra data, ...)
@@ -3717,12 +3747,20 @@
 			h2s_close(h2s);
 	}
 
-	b_del(buf, total);
+	if (htx) {
+		if (htx_is_empty(htx)) {
+			htx_reset(htx);
+			b_set_data(buf, 0);
+		}
+	} else {
+		b_del(buf, total);
+	}
 
 	/* The mux is full, cancel the pending tasks */
 	if ((h2s->h2c->flags & H2_CF_MUX_BLOCK_ANY) ||
 	    (h2s->flags & H2_SF_BLK_MBUSY))
 		h2_stop_senders(h2s->h2c);
+
 	if (total > 0) {
 		if (!(h2s->h2c->wait_event.wait_reason & SUB_CAN_SEND))
 			tasklet_wakeup(h2s->h2c->wait_event.task);