BUG/MINOR: mux-h2: use a safe list_for_each_entry in h2_send()

h2_send() uses list_for_each_entry() to scan paused streams and resume
them, but happily deletes any leftover from a previous failed unsubscribe,
which is obviously not safe and would corrupt the list. In practice this
is a proof that this doesn't happen, but it's not the best way to prove it.
In order to fix this and reduce the maintenance burden caused by code
duplication (this list walk exists at 3 places), let's introduce a new
function h2_resume_each_sending_h2s() doing exactly this and use it at
all 3 places.

This bug was introduced as a side effect of fix 998410a41b ("BUG/MEDIUM:
h2: Revamp the way send subscriptions works.") so it should be backported
as far as 1.9.

(cherry picked from commit 989539b048bef502a474553a8e330a3d318edb6c)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 449f28322fb45688dacc80bead89fe75f3dd75db)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 74fffbf..d72ca70 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -2720,13 +2720,37 @@
 	h2c_restart_reading(h2c, 0);
 }
 
+/* resume each h2s eligible for sending in list head <head> */
+static void h2_resume_each_sending_h2s(struct h2c *h2c, struct list *head)
+{
+	struct h2s *h2s, *h2s_back;
+
+	list_for_each_entry_safe(h2s, h2s_back, head, list) {
+		if (h2c->mws <= 0 ||
+		    h2c->flags & H2_CF_MUX_BLOCK_ANY ||
+		    h2c->st0 >= H2_CS_ERROR)
+			break;
+
+		h2s->flags &= ~H2_SF_BLK_ANY;
+		/* For some reason, the upper layer failed to subscribe again,
+		 * so remove it from the send_list
+		 */
+		if (!h2s->send_wait) {
+			LIST_DEL_INIT(&h2s->list);
+			continue;
+		}
+
+		h2s->send_wait->events &= ~SUB_RETRY_SEND;
+		LIST_ADDQ(&h2c->sending_list, &h2s->sending_list);
+		tasklet_wakeup(h2s->send_wait->tasklet);
+	}
+}
+
 /* process Tx frames from streams to be multiplexed. Returns > 0 if it reached
  * the end.
  */
 static int h2_process_mux(struct h2c *h2c)
 {
-	struct h2s *h2s, *h2s_back;
-
 	if (unlikely(h2c->st0 < H2_CS_FRAME_H)) {
 		if (unlikely(h2c->st0 == H2_CS_PREFACE && (h2c->flags & H2_CF_IS_BACK))) {
 			if (unlikely(h2c_bck_send_preface(h2c) <= 0)) {
@@ -2757,47 +2781,8 @@
 	 * waiting there were already elected for immediate emission but were
 	 * blocked just on this.
 	 */
-
-	list_for_each_entry_safe(h2s, h2s_back, &h2c->fctl_list, list) {
-		if (h2c->mws <= 0 || h2c->flags & H2_CF_MUX_BLOCK_ANY ||
-		    h2c->st0 >= H2_CS_ERROR)
-			break;
-
-		if (LIST_ADDED(&h2s->sending_list))
-			continue;
-
-		h2s->flags &= ~H2_SF_BLK_ANY;
-		/* For some reason, the upper layer failed to subsribe again,
-		 * so remove it from the send_list
-		 */
-		if (!h2s->send_wait) {
-			LIST_DEL_INIT(&h2s->list);
-			continue;
-		}
-		h2s->send_wait->events &= ~SUB_RETRY_SEND;
-		LIST_ADDQ(&h2c->sending_list, &h2s->sending_list);
-		tasklet_wakeup(h2s->send_wait->tasklet);
-	}
-
-	list_for_each_entry_safe(h2s, h2s_back, &h2c->send_list, list) {
-		if (h2c->st0 >= H2_CS_ERROR || h2c->flags & H2_CF_MUX_BLOCK_ANY)
-			break;
-
-		if (LIST_ADDED(&h2s->sending_list))
-			continue;
-
-		/* For some reason, the upper layer failed to subsribe again,
-		 * so remove it from the send_list
-		 */
-		if (!h2s->send_wait) {
-			LIST_DEL_INIT(&h2s->list);
-			continue;
-		}
-		h2s->flags &= ~H2_SF_BLK_ANY;
-		h2s->send_wait->events &= ~SUB_RETRY_SEND;
-		LIST_ADDQ(&h2c->sending_list, &h2s->sending_list);
-		tasklet_wakeup(h2s->send_wait->tasklet);
-	}
+	h2_resume_each_sending_h2s(h2c, &h2c->fctl_list);
+	h2_resume_each_sending_h2s(h2c, &h2c->send_list);
 
  fail:
 	if (unlikely(h2c->st0 >= H2_CS_ERROR)) {
@@ -2963,29 +2948,9 @@
 	/* We're not full anymore, so we can wake any task that are waiting
 	 * for us.
 	 */
-	if (!(h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MROOM)) && h2c->st0 >= H2_CS_FRAME_H) {
-		struct h2s *h2s;
-
-		list_for_each_entry(h2s, &h2c->send_list, list) {
-			if (h2c->st0 >= H2_CS_ERROR || h2c->flags & H2_CF_MUX_BLOCK_ANY)
-				break;
+	if (!(h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MROOM)) && h2c->st0 >= H2_CS_FRAME_H)
+		h2_resume_each_sending_h2s(h2c, &h2c->send_list);
 
-			if (LIST_ADDED(&h2s->sending_list))
-				continue;
-
-			/* For some reason, the upper layer failed to subsribe again,
-			 * so remove it from the send_list
-			 */
-			if (!h2s->send_wait) {
-				LIST_DEL_INIT(&h2s->list);
-				continue;
-			}
-			h2s->flags &= ~H2_SF_BLK_ANY;
-			h2s->send_wait->events &= ~SUB_RETRY_SEND;
-			tasklet_wakeup(h2s->send_wait->tasklet);
-			LIST_ADDQ(&h2c->sending_list, &h2s->sending_list);
-		}
-	}
 	/* We're done, no more to send */
 	if (!br_data(h2c->mbuf))
 		return sent;