MEDIUM: http: restrict the HTTP version token to 1 digit as per RFC7230

While RFC2616 used to allow an undeterminate amount of digits for the
major and minor components of the HTTP version, RFC7230 has reduced
that to a single digit for each.

If a server can't properly parse the version string and falls back to 0.9,
it could then send a head-less response whose payload would be taken for
headers, which could confuse downstream agents.

Since there's no more reason for supporting a version scheme that was
never used, let's upgrade to the updated version of the standard. It is
still possible to enforce support for the old behaviour using options
accept-invalid-http-request and accept-invalid-http-response.

(cherry picked from commit 91852eb4280e5fbe63dcd9ea32c168d7516c6667)
diff --git a/src/proto_http.c b/src/proto_http.c
index d6e37ed..33aaf67 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2853,6 +2853,25 @@
 	if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
 		goto return_bad_req;
 
+	/* RFC7230#2.6 has enforced the format of the HTTP version string to be
+	 * exactly one digit "." one digit. This check may be disabled using
+	 * option accept-invalid-http-request.
+	 */
+	if (!(s->fe->options2 & PR_O2_REQBUG_OK)) {
+		if (msg->sl.rq.v_l != 8) {
+			msg->err_pos = msg->sl.rq.v;
+			goto return_bad_req;
+		}
+
+		if (req->buf->p[msg->sl.rq.v + 4] != '/' ||
+		    !isdigit((unsigned char)req->buf->p[msg->sl.rq.v + 5]) ||
+		    req->buf->p[msg->sl.rq.v + 6] != '.' ||
+		    !isdigit((unsigned char)req->buf->p[msg->sl.rq.v + 7])) {
+			msg->err_pos = msg->sl.rq.v + 4;
+			goto return_bad_req;
+		}
+	}
+
 	/* ... and check if the request is HTTP/1.1 or above */
 	if ((msg->sl.rq.v_l == 8) &&
 	    ((req->buf->p[msg->sl.rq.v + 5] > '1') ||
@@ -5870,6 +5889,25 @@
 	if (objt_server(s->target))
 		objt_server(s->target)->counters.p.http.rsp[n]++;
 
+	/* RFC7230#2.6 has enforced the format of the HTTP version string to be
+	 * exactly one digit "." one digit. This check may be disabled using
+	 * option accept-invalid-http-response.
+	 */
+	if (!(s->be->options2 & PR_O2_RSPBUG_OK)) {
+		if (msg->sl.st.v_l != 8) {
+			msg->err_pos = 0;
+			goto hdr_response_bad;
+		}
+
+		if (rep->buf->p[4] != '/' ||
+		    !isdigit((unsigned char)rep->buf->p[5]) ||
+		    rep->buf->p[6] != '.' ||
+		    !isdigit((unsigned char)rep->buf->p[7])) {
+			msg->err_pos = 4;
+			goto hdr_response_bad;
+		}
+	}
+
 	/* check if the response is HTTP/1.1 or above */
 	if ((msg->sl.st.v_l == 8) &&
 	    ((rep->buf->p[5] > '1') ||