]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: h1: make the parser support a pointer to a start line
authorWilly Tarreau <w@1wt.eu>
Tue, 11 Sep 2018 13:34:50 +0000 (15:34 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 12 Sep 2018 15:38:25 +0000 (17:38 +0200)
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.

include/proto/h1.h
include/types/h1.h
src/h1.c
src/mux_h2.c

index c82e17ad55bcf04fd21057902979dad343b5b5d5..e6a4204ff30fe4a9b16908b42e9b2f1b87e151ac 100644 (file)
@@ -41,7 +41,7 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx);
 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
index 7edfbd89e77c5a5ec3d316e04a5daf9a03d65684..c6c97dcbdc78d17d60fe6a830dee0033933f2f77 100644 (file)
@@ -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 @@ struct h1m {
        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 */
index 20a14934d0a6ba1bb5955be90ba8270625e6c6f8..2fafc358c2796847134d29a1bcc56d8a40d67f70 100644 (file)
--- a/src/h1.c
+++ b/src/h1.c
@@ -670,6 +670,9 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx)
  * 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 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx)
  */
 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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                        start = ptr;
 
                        sol = 0;
+                       sl.st.v = skip;
                        hdr_count = 0;
                        state = H1_MSG_RPVER;
                        goto http_msg_rpver;
@@ -750,7 +753,7 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                        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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
        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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
        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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                }
 
                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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
        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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                        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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
        /* 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 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                h1m->err_state = state;
                h1m->err_pos = ptr - start + skip;
        }
+
+       if (slp)
+               *slp = sl;
+
        return -1;
 
  http_output_full:
@@ -1065,6 +1078,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
                h1m->err_state = state;
                h1m->err_pos = ptr - start + skip;
        }
+
+       if (slp)
+               *slp = sl;
+
        return -2;
 }
 
index 546debb8d004f64d7812d5d41e6edbabfbc4a32d..4d9a7bcd2931eb7b67c0ca59a9a1055f5275f3d5 100644 (file)
@@ -3104,7 +3104,7 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu
         * 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