BUG/MEDIUM: h2: Only report early HTX EOM for tunneled streams

For regular H2 messages, the HTX EOM flag is synonymous the end of input. So
SE_FL_EOI flag must also be set on the stream-endpoint descriptor. However,
there is an exception. For tunneled streams, the end of message is reported
on the HTX message just after the headers. But in that case, no end of input
is reported on the SE.

But here, there is a bug. The "early" EOM is also report on the HTX messages
when there is no payload (for instance a content-length set to 0). If there
is no ES flag on the H2 HEADERS frame, it is an unexpected case. Because for
the applicative stream and most probably for the opposite endpoint, the
message is considered as finihsed. It is switched in its DONE state (or the
equivalent on the endpoint). But, if an extra H2 frame with the ES flag is
received, a TRAILERS frame or an emtpy DATA frame, an extra EOT HTX block is
pushed to carry the HTX EOM flag. So an extra HTX block is emitted for a
regular HTX message. It is totally invalid, it must never happen.

Because it is an undefined behavior, it is difficult to predict the result.
But it definitly prevent the applicative stream to properly handle aborts
and errors because data remain blocked in the channel buffer. Indeed, the
end of the message was seen, so no more data are forwarded.

It seems to be an issue for 2.8 and upper. Harder to evaluate for older
versions.

This patch must be backported as far as 2.4.

(cherry picked from commit 6743e128f34fba297f2cac836a4f11b84acd503a)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit cac1e39e86fb997b1958265d77d8258a0a03fbd5)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 26a1fdd9e8e099260484f929c733a21cd50dfd23)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/h2.c b/src/h2.c
index 67a4436..d2eb0b3 100644
--- a/src/h2.c
+++ b/src/h2.c
@@ -451,7 +451,8 @@
 	    (*msgf & H2_MSGF_BODY_TUNNEL)) {
 		/* Request without body or tunnel requested */
 		sl_flags |= HTX_SL_F_BODYLESS;
-		htx->flags |= HTX_FL_EOM;
+		if (*msgf & H2_MSGF_BODY_TUNNEL)
+		    htx->flags |= HTX_FL_EOM;
 	}
 
 	if (*msgf & H2_MSGF_EXT_CONNECT) {
@@ -718,7 +719,8 @@
 	    (*msgf & H2_MSGF_BODY_TUNNEL)) {
 		/* Response without body or tunnel successfully established */
 		sl_flags |= HTX_SL_F_BODYLESS;
-		htx->flags |= HTX_FL_EOM;
+		if (*msgf & H2_MSGF_BODY_TUNNEL)
+		    htx->flags |= HTX_FL_EOM;
 	}
 
 	/* update the start line with last detected header info */