MAJOR: muxes/htx: Handle inplicit upgrades from h1 to h2

The upgrade is performed when an H2 preface is detected when the first request
on a connection is parsed. The CS is destroyed by setting EOS flag on it. A
special flag is added on the HTX message to warn the HTX analyzers the stream
will be closed because of an upgrade. This way, no error and no log are
emitted. When the mux h1 is released, we create a mux h2, without any CS and
passing the buffer with the unparsed H2 preface.
diff --git a/src/mux_h1.c b/src/mux_h1.c
index ef9dd01..5ea5f3c 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -12,6 +12,7 @@
 #include <common/cfgparse.h>
 #include <common/config.h>
 #include <common/h1.h>
+#include <common/h2.h>
 #include <common/htx.h>
 #include <common/initcall.h>
 
@@ -48,6 +49,7 @@
 #define H1C_F_CS_WAIT_CONN   0x00008000 /* waiting for the connection establishment */
 
 #define H1C_F_WAIT_NEXT_REQ  0x00010000 /*  waiting for the next request to start, use keep-alive timeout */
+#define H1C_F_UPG_H2C        0x00020000 /* set if an upgrade to h2 should be done */
 
 /*
  * H1 Stream flags (32 bits)
@@ -450,6 +452,16 @@
 		conn = NULL;
 
 	if (h1c) {
+		if (h1c->flags & H1C_F_UPG_H2C) {
+			h1c->flags &= ~H1C_F_UPG_H2C;
+			if (conn_upgrade_mux_fe(conn, NULL, &h1c->ibuf, ist("h2"), PROTO_MODE_HTX) != -1) {
+				/* connection successfully upgraded to H2, this
+				 * mux was already released */
+				return;
+			}
+			sess_log(conn->owner); /* Log if the upgrade failed */
+		}
+
 		if (!LIST_ISEMPTY(&h1c->buf_wait.list)) {
 			HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
 			LIST_DEL(&h1c->buf_wait.list);
@@ -908,6 +920,13 @@
 	if (b_head(buf) + b_data(buf) > b_wrap(buf))
 		b_slow_realign(buf, trash.area, 0);
 
+	if (!(h1m->flags & H1_MF_RESP)) {
+		/* Try to match H2 preface before parsing the request headers. */
+		ret = b_isteq(buf, 0, b_data(buf), ist(H2_CONN_PREFACE));
+		if (ret > 0)
+			goto h2c_upgrade;
+	}
+
 	ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_peek(buf, *ofs) + max,
 				     hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, &h1sl);
 	if (ret <= 0) {
@@ -1049,6 +1068,13 @@
 	h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
 	ret = 0;
 	goto end;
+
+  h2c_upgrade:
+	h1s->h1c->flags |= H1C_F_UPG_H2C;
+	h1s->cs->flags |= CS_FL_REOS;
+	htx->flags |= HTX_FL_UPGRADE;
+	ret = 0;
+	goto end;
 }
 
 /*
@@ -2067,7 +2093,7 @@
 	}
 
 	/* We don't want to close right now unless the connection is in error */
-	if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN)) ||
+	if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN|H1C_F_UPG_H2C)) ||
 	    (h1c->conn->flags & CO_FL_ERROR) || !h1c->conn->owner)
 		h1_release(h1c);
 	else {
@@ -2097,7 +2123,7 @@
 	if ((cs->flags & CS_FL_KILL_CONN) || (h1c->conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH)))
 		goto do_shutr;
 
-	if (h1s->flags & H1S_F_WANT_KAL)
+	if ((h1c->flags & H1C_F_UPG_H2C) || (h1s->flags & H1S_F_WANT_KAL))
 		return;
 
   do_shutr:
@@ -2122,7 +2148,8 @@
 	if ((cs->flags & CS_FL_KILL_CONN) || (h1c->conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH)))
 		goto do_shutw;
 
-	if ((h1s->flags & H1S_F_WANT_KAL) && h1s->req.state == H1_MSG_DONE && h1s->res.state == H1_MSG_DONE)
+	if ((h1c->flags & H1C_F_UPG_H2C) ||
+	    ((h1s->flags & H1S_F_WANT_KAL) && h1s->req.state == H1_MSG_DONE && h1s->res.state == H1_MSG_DONE))
 		return;
 
   do_shutw: