- Add new patches (see https://www.haproxy.org/bugs/bugs-1.8.8.html) - Raise patch-level to 02 Signed-off-by: Christian Lachner <gladiac@gmail.com>
147 lines
6 KiB
Diff
147 lines
6 KiB
Diff
commit a8bcc7dd3fe5aa615f21e795375ff9225f004498
|
|
Author: Willy Tarreau <w@1wt.eu>
|
|
Date: Wed Apr 25 18:13:58 2018 +0200
|
|
|
|
MINOR: h2: detect presence of CONNECT and/or content-length
|
|
|
|
We'll need this in order to support uploading chunks. The h2 to h1
|
|
converter checks for the presence of the content-length header field
|
|
as well as the CONNECT method and returns these information to the
|
|
caller. The caller indicates whether or not a body is detected for
|
|
the message (presence of END_STREAM or not). No transfer-encoding
|
|
header is emitted yet.
|
|
|
|
(cherry picked from commit 174b06a572ef141f15d8b7ea64eb6b34ec4c9af1)
|
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
|
|
|
diff --git a/include/common/h2.h b/include/common/h2.h
|
|
index 65c5ab1c..576ed105 100644
|
|
--- a/include/common/h2.h
|
|
+++ b/include/common/h2.h
|
|
@@ -145,9 +145,15 @@ enum h2_err {
|
|
"\x0d\x0a\x53\x4d\x0d\x0a\x0d\x0a"
|
|
|
|
|
|
+/* some flags related to protocol parsing */
|
|
+#define H2_MSGF_BODY 0x0001 // a body is present
|
|
+#define H2_MSGF_BODY_CL 0x0002 // content-length is present
|
|
+#define H2_MSGF_BODY_TUNNEL 0x0004 // a tunnel is in use (CONNECT)
|
|
+
|
|
+
|
|
/* various protocol processing functions */
|
|
|
|
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize);
|
|
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf);
|
|
|
|
/*
|
|
* Some helpful debugging functions.
|
|
diff --git a/src/h2.c b/src/h2.c
|
|
index 43ed7f3c..7d9ddd50 100644
|
|
--- a/src/h2.c
|
|
+++ b/src/h2.c
|
|
@@ -36,9 +36,10 @@
|
|
* stored in <phdr[]>. <fields> indicates what was found so far. This should be
|
|
* called once at the detection of the first general header field or at the end
|
|
* of the request if no general header field was found yet. Returns 0 on success
|
|
- * or a negative error code on failure.
|
|
+ * or a negative error code on failure. Upon success, <msgf> is updated with a
|
|
+ * few H2_MSGF_* flags indicating what was found while parsing.
|
|
*/
|
|
-static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end)
|
|
+static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end, unsigned int *msgf)
|
|
{
|
|
char *out = *ptr;
|
|
int uri_idx = H2_PHDR_IDX_PATH;
|
|
@@ -62,6 +63,7 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr,
|
|
}
|
|
// otherwise OK ; let's use the authority instead of the URI
|
|
uri_idx = H2_PHDR_IDX_AUTH;
|
|
+ *msgf |= H2_MSGF_BODY_TUNNEL;
|
|
}
|
|
else if ((fields & (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) !=
|
|
(H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) {
|
|
@@ -113,6 +115,10 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr,
|
|
* for a max of <osize> bytes, and the amount of bytes emitted is returned. In
|
|
* case of error, a negative error code is returned.
|
|
*
|
|
+ * Upon success, <msgf> is filled with a few H2_MSGF_* flags indicating what
|
|
+ * was found while parsing. The caller must set it to zero in or H2_MSGF_BODY
|
|
+ * if a body is detected (!ES).
|
|
+ *
|
|
* The headers list <list> must be composed of :
|
|
* - n.name != NULL, n.len > 0 : literal header name
|
|
* - n.name == NULL, n.len > 0 : indexed pseudo header name number <n.len>
|
|
@@ -124,7 +130,7 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr,
|
|
* The Cookie header will be reassembled at the end, and for this, the <list>
|
|
* will be used to create a linked list, so its contents may be destroyed.
|
|
*/
|
|
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize)
|
|
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf)
|
|
{
|
|
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
|
|
char *out_end = out + osize;
|
|
@@ -176,7 +182,7 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize)
|
|
/* regular header field in (name,value) */
|
|
if (!(fields & H2_PHDR_FND_NONE)) {
|
|
/* no more pseudo-headers, time to build the request line */
|
|
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end);
|
|
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf);
|
|
if (ret != 0)
|
|
goto leave;
|
|
fields |= H2_PHDR_FND_NONE;
|
|
@@ -185,6 +191,10 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize)
|
|
if (isteq(list[idx].n, ist("host")))
|
|
fields |= H2_PHDR_FND_HOST;
|
|
|
|
+ if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY &&
|
|
+ isteq(list[idx].n, ist("content-length")))
|
|
+ *msgf |= H2_MSGF_BODY_CL;
|
|
+
|
|
/* these ones are forbidden in requests (RFC7540#8.1.2.2) */
|
|
if (isteq(list[idx].n, ist("connection")) ||
|
|
isteq(list[idx].n, ist("proxy-connection")) ||
|
|
@@ -232,7 +242,7 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize)
|
|
|
|
/* Let's dump the request now if not yet emitted. */
|
|
if (!(fields & H2_PHDR_FND_NONE)) {
|
|
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end);
|
|
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf);
|
|
if (ret != 0)
|
|
goto leave;
|
|
}
|
|
diff --git a/src/mux_h2.c b/src/mux_h2.c
|
|
index 4fde7fcc..82dd414a 100644
|
|
--- a/src/mux_h2.c
|
|
+++ b/src/mux_h2.c
|
|
@@ -2626,6 +2626,7 @@ static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count)
|
|
struct chunk *tmp = get_trash_chunk();
|
|
struct http_hdr list[MAX_HTTP_HDR * 2];
|
|
struct chunk *copy = NULL;
|
|
+ unsigned int msgf;
|
|
int flen = h2c->dfl;
|
|
int outlen = 0;
|
|
int wrap;
|
|
@@ -2727,13 +2728,22 @@ static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count)
|
|
}
|
|
|
|
/* OK now we have our header list in <list> */
|
|
- outlen = h2_make_h1_request(list, bi_end(buf), try);
|
|
+ msgf = (h2c->dff & H2_F_DATA_END_STREAM) ? 0 : H2_MSGF_BODY;
|
|
+ outlen = h2_make_h1_request(list, bi_end(buf), try, &msgf);
|
|
|
|
if (outlen < 0) {
|
|
h2c_error(h2c, H2_ERR_COMPRESSION_ERROR);
|
|
goto fail;
|
|
}
|
|
|
|
+ if (msgf & H2_MSGF_BODY) {
|
|
+ /* a payload is present */
|
|
+ if (msgf & H2_MSGF_BODY_CL)
|
|
+ h2s->flags |= H2_SF_DATA_CLEN;
|
|
+ else if (!(msgf & H2_MSGF_BODY_TUNNEL))
|
|
+ h2s->flags |= H2_SF_DATA_CHNK;
|
|
+ }
|
|
+
|
|
/* now consume the input data */
|
|
bi_del(h2c->dbuf, h2c->dfl);
|
|
h2c->st0 = H2_CS_FRAME_H;
|