MINOR: quic: handle CONNECTION_CLOSE frame

On receiving CONNECTION_CLOSE frame, the mux is flagged for immediate
connection close. A stream is closed even if there is data not ACKed
left if CONNECTION_CLOSE has been received.
diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h
index 7cf9afd..09e0585 100644
--- a/include/haproxy/mux_quic-t.h
+++ b/include/haproxy/mux_quic-t.h
@@ -77,6 +77,8 @@
 /* other flags */
 #define QC_CF_IS_BACK           0x00008000  // this is an outgoing connection
 
+#define QC_CF_CC_RECV           0x00010000  // CONNECTION_CLOSE received
+
 extern struct pool_head *pool_head_qcs;
 
 /* Stream types */
diff --git a/src/mux_quic.c b/src/mux_quic.c
index 4794a50..d60df2b 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -1498,14 +1498,18 @@
 	struct qcc *qcc = qcs->qcc;
 
 	TRACE_ENTER(QC_EV_STRM_END, qcs ? qcs->qcc->conn : NULL, qcs);
-	if (b_data(&qcs->tx.buf) || b_data(&qcs->tx.xprt_buf)) {
+	if (b_data(&qcs->tx.buf) ||
+	    (b_data(&qcs->tx.xprt_buf) && !(qcc->flags & QC_CF_CC_RECV))) {
 		qcs->flags |= QC_SF_DETACH;
 		goto out;
 	}
 
 	qcs_destroy(qcs);
-	if (qcc_is_dead(qcc))
+	if (qcc_is_dead(qcc)) {
 		qc_release(qcc);
+		TRACE_LEAVE(QC_EV_STRM_END, NULL);
+		return;
+	}
 
  out:
 	TRACE_LEAVE(QC_EV_STRM_END, qcs ? qcs->qcc->conn : NULL);
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 70bcea8..eed8b2f 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -2040,6 +2040,7 @@
 			break;
 		case QUIC_FT_CONNECTION_CLOSE:
 		case QUIC_FT_CONNECTION_CLOSE_APP:
+			conn->qcc->flags |= QC_CF_CC_RECV;
 			break;
 		case QUIC_FT_HANDSHAKE_DONE:
 			if (objt_listener(ctx->conn->target))