MEDIUM: h1: make the parser support a pointer to a start line

This will allow the parser to fill some extra fields like the method or
status without having to store them permanently in the HTTP message. At
this point however the parser cannot restart from an interrupted read.
diff --git a/include/proto/h1.h b/include/proto/h1.h
index c82e17a..e6a4204 100644
--- a/include/proto/h1.h
+++ b/include/proto/h1.h
@@ -41,7 +41,7 @@
 int http_forward_trailers(struct http_msg *msg);
 int h1_headers_to_hdr_list(char *start, const char *stop,
                            struct http_hdr *hdr, unsigned int hdr_num,
-                           struct h1m *h1m);
+                           struct h1m *h1m, union h1_sl *slp);
 int h1_measure_trailers(const struct buffer *buf, unsigned int ofs, unsigned int max);
 
 /* Macros used in the HTTP/1 parser, to check for the expected presence of
diff --git a/include/types/h1.h b/include/types/h1.h
index 7edfbd8..c6c97dc 100644
--- a/include/types/h1.h
+++ b/include/types/h1.h
@@ -22,6 +22,8 @@
 #ifndef _TYPES_H1_H
 #define _TYPES_H1_H
 
+#include <common/http.h>
+
 /* Legacy version of the HTTP/1 message state, used by the channels, should
  * ultimately be removed.
  */
@@ -161,4 +163,20 @@
 	int err_state;              // state where the first error was met (H1 or H2)
 };
 
+/* basic H1 start line, describes either the request and the response */
+union h1_sl {                          /* useful start line pointers, relative to ->sol */
+	struct {
+		int m, m_l;            /* METHOD, length */
+		int u, u_l;            /* URI, length */
+		int v, v_l;            /* VERSION, length */
+		enum http_meth_t meth; /* method */
+	} rq;                          /* request line : field, length */
+	struct {
+		int v, v_l;            /* VERSION, length */
+		int c, c_l;            /* CODE, length */
+		int r, r_l;            /* REASON, length */
+		uint16_t status;       /* status code */
+	} st;                          /* status line : field, length */
+};
+
 #endif /* _TYPES_H1_H */
diff --git a/src/h1.c b/src/h1.c
index 20a1493..2fafc35 100644
--- a/src/h1.c
+++ b/src/h1.c
@@ -670,6 +670,9 @@
  * For now it's limited to the response. If the header block is incomplete,
  * 0 is returned, waiting to be called again with more data to try it again.
  *
+ * A pointer to a start line descriptor may be passed in <slp>, in which case
+ * the parser will fill it with whatever it found.
+ *
  * The code derived from the main HTTP/1 parser above but was simplified and
  * optimized to process responses produced or forwarded by haproxy. The caller
  * is responsible for ensuring that the message doesn't wrap, and should ensure
@@ -693,22 +696,21 @@
  */
 int h1_headers_to_hdr_list(char *start, const char *stop,
                            struct http_hdr *hdr, unsigned int hdr_num,
-                           struct h1m *h1m)
+                           struct h1m *h1m, union h1_sl *slp)
 {
 	enum h1m_state state = H1_MSG_RPBEFORE;
 	register char *ptr  = start;
 	register const char *end  = stop;
 	unsigned int hdr_count = 0;
-	unsigned int code = 0; /* status code, ASCII form */
-	unsigned int st_c;     /* beginning of status code, relative to msg_start */
-	unsigned int st_c_l;   /* length of status code */
 	unsigned int sol = 0;  /* start of line */
 	unsigned int col = 0;  /* position of the colon */
 	unsigned int eol = 0;  /* end of line */
 	unsigned int sov = 0;  /* start of value */
 	unsigned int skip = 0; /* number of bytes skipped at the beginning */
+	union h1_sl sl;
 	struct ist n, v;       /* header name and value during parsing */
 
+	sl.st.status = 0;
 	if (unlikely(ptr >= end))
 		goto http_msg_ood;
 
@@ -723,6 +725,7 @@
 			start = ptr;
 
 			sol = 0;
+			sl.st.v = skip;
 			hdr_count = 0;
 			state = H1_MSG_RPVER;
 			goto http_msg_rpver;
@@ -750,7 +753,7 @@
 			EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver, http_msg_ood, state, H1_MSG_RPVER);
 
 		if (likely(HTTP_IS_SPHT(*ptr))) {
-			/* version length = ptr - start */
+			sl.st.v_l = ptr - start;
 			EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver_sp, http_msg_ood, state, H1_MSG_RPVER_SP);
 		}
 		state = H1_MSG_RPVER;
@@ -759,8 +762,8 @@
 	case H1_MSG_RPVER_SP:
 	http_msg_rpver_sp:
 		if (likely(!HTTP_IS_LWS(*ptr))) {
-			code = 0;
-			st_c = ptr - start;
+			sl.st.status = 0;
+			sl.st.c = ptr - start + skip;
 			goto http_msg_rpcode;
 		}
 		if (likely(HTTP_IS_SPHT(*ptr)))
@@ -772,7 +775,7 @@
 	case H1_MSG_RPCODE:
 	http_msg_rpcode:
 		if (likely(HTTP_IS_DIGIT(*ptr))) {
-			code = code * 10 + *ptr - '0';
+			sl.st.status = sl.st.status * 10 + *ptr - '0';
 			EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE);
 		}
 
@@ -782,22 +785,22 @@
 		}
 
 		if (likely(HTTP_IS_SPHT(*ptr))) {
-			st_c_l = ptr - start - st_c;
+			sl.st.c_l = ptr - start + skip - sl.st.c;
 			EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, H1_MSG_RPCODE_SP);
 		}
 
 		/* so it's a CR/LF, so there is no reason phrase */
-		st_c_l = ptr - start - st_c;
+		sl.st.c_l = ptr - start + skip - sl.st.c;
 
 	http_msg_rsp_reason:
-		/* reason = ptr - start; */
-		/* reason length = 0 */
+		sl.st.r = ptr - start + skip;
+		sl.st.r_l = 0;
 		goto http_msg_rpline_eol;
 
 	case H1_MSG_RPCODE_SP:
 	http_msg_rpcode_sp:
 		if (likely(!HTTP_IS_LWS(*ptr))) {
-			/* reason = ptr - start */
+			sl.st.r = ptr - start + skip;
 			goto http_msg_rpreason;
 		}
 		if (likely(HTTP_IS_SPHT(*ptr)))
@@ -809,7 +812,7 @@
 	http_msg_rpreason:
 		if (likely(!HTTP_IS_CRLF(*ptr)))
 			EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpreason, http_msg_ood, state, H1_MSG_RPREASON);
-		/* reason length = ptr - start - reason */
+		sl.st.r_l = ptr - start + skip - sl.st.r;
 	http_msg_rpline_eol:
 		/* We have seen the end of line. Note that we do not
 		 * necessarily have the \n yet, but at least we know that we
@@ -822,9 +825,9 @@
 			state = H1_MSG_RPREASON;
 			goto http_output_full;
 		}
-		http_set_hdr(&hdr[hdr_count++], ist(":status"), ist2(start + st_c, st_c_l));
+		http_set_hdr(&hdr[hdr_count++], ist(":status"), ist2(start + sl.st.c, sl.st.c_l));
 		if (h1m)
-			h1m->status = code;
+			h1m->status = sl.st.status;
 
 		sol = ptr - start;
 		if (likely(*ptr == '\r'))
@@ -1045,10 +1048,16 @@
 	/* reaching here, we've parsed the whole message and the state is
 	 * H1_MSG_BODY.
 	 */
+	if (slp)
+		*slp = sl;
+
 	return ptr - start + skip;
 
  http_msg_ood:
 	/* out of data at <ptr> during state <state> */
+	if (slp)
+		*slp = sl;
+
 	return 0;
 
  http_msg_invalid:
@@ -1057,6 +1066,10 @@
 		h1m->err_state = state;
 		h1m->err_pos = ptr - start + skip;
 	}
+
+	if (slp)
+		*slp = sl;
+
 	return -1;
 
  http_output_full:
@@ -1065,6 +1078,10 @@
 		h1m->err_state = state;
 		h1m->err_pos = ptr - start + skip;
 	}
+
+	if (slp)
+		*slp = sl;
+
 	return -2;
 }
 
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 546debb..4d9a7bc 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -3104,7 +3104,7 @@
 	 * having to realign the buffer.
 	 */
 	ret = h1_headers_to_hdr_list(b_peek(buf, ofs), b_peek(buf, ofs) + max,
-	                             list, sizeof(list)/sizeof(list[0]), h1m);
+	                             list, sizeof(list)/sizeof(list[0]), h1m, NULL);
 	if (ret <= 0) {
 		/* incomplete or invalid response, this is abnormal coming from
 		 * haproxy and may only result in a bad errorfile or bad Lua code