From 34d234824d6587543a06769dec6e37d026b5baba Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 3 Jan 2019 17:46:56 +0100 Subject: [PATCH] BUG/MEDIUM: mux-h1: use per-direction flags to indicate transitions The H1 mux needs to store some information regarding the states that were met (EOD, trailers, etc) for each direction but currently uses only one set of flags. This results in failures when both the request and the response use chunked-encoding because some elements are believed to have been met already and a trailing 0 CRLF or just a CRLF may be missing at the end. The solution here consists in splitting these flags per direction, one set for input processing and another set for output processing. Only two flags were affected so this is not a big deal. This needs to be backported to 1.9. --- src/mux_h1.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/mux_h1.c b/src/mux_h1.c index e27aec3f8..7b8240116 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -64,8 +64,10 @@ #define H1S_F_NOT_FIRST 0x00000080 /* The H1 stream is not the first one */ #define H1S_F_BUF_FLUSH 0x00000100 /* Flush input buffer and don't read more data */ #define H1S_F_SPLICED_DATA 0x00000200 /* Set when the kernel splicing is in used */ -#define H1S_F_HAVE_EOD 0x00000400 /* Set during input/output process to know the last empty chunk was processed */ -#define H1S_F_HAVE_TLR 0x00000800 /* Set during input/output process to know the trailers were processed */ +#define H1S_F_HAVE_I_EOD 0x00000400 /* Set during input process to know the last empty chunk was processed */ +#define H1S_F_HAVE_I_TLR 0x00000800 /* Set during input process to know the trailers were processed */ +#define H1S_F_HAVE_O_EOD 0x00001000 /* Set during output process to know the last empty chunk was processed */ +#define H1S_F_HAVE_O_TLR 0x00002000 /* Set during output process to know the trailers were processed */ /* H1 connection descriptor */ struct h1c { @@ -1105,7 +1107,7 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, if (!chksz) { if (!htx_add_endof(htx, HTX_BLK_EOD)) goto end; - h1s->flags |= H1S_F_HAVE_EOD; + h1s->flags |= H1S_F_HAVE_I_EOD; h1m->state = H1_MSG_TRAILERS; } else @@ -1144,7 +1146,7 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, if (h1m->state == H1_MSG_TRAILERS) { /* Trailers were alread parsed, only the EOM * need to be added */ - if (h1s->flags & H1S_F_HAVE_TLR) + if (h1s->flags & H1S_F_HAVE_I_TLR) goto skip_tlr_parsing; ret = h1_measure_trailers(buf, *ofs, *ofs + max); @@ -1165,7 +1167,7 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, if (!htx_add_trailer(htx, ist2(b_peek(buf, *ofs), ret))) goto end; - h1s->flags |= H1S_F_HAVE_TLR; + h1s->flags |= H1S_F_HAVE_I_TLR; max -= ret; *ofs += ret; total += ret; @@ -1548,34 +1550,34 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun case HTX_BLK_EOD: if (!chunk_memcat(tmp, "0\r\n", 3)) goto copy; - h1s->flags |= H1S_F_HAVE_EOD; + h1s->flags |= H1S_F_HAVE_O_EOD; h1m->state = H1_MSG_TRAILERS; break; case HTX_BLK_TLR: - if (!(h1s->flags & H1S_F_HAVE_EOD)) { + if (!(h1s->flags & H1S_F_HAVE_O_EOD)) { if (!chunk_memcat(tmp, "0\r\n", 3)) goto copy; - h1s->flags |= H1S_F_HAVE_EOD; + h1s->flags |= H1S_F_HAVE_O_EOD; } v = htx_get_blk_value(chn_htx, blk); v.len = vlen; if (!htx_trailer_to_h1(v, tmp)) goto copy; - h1s->flags |= H1S_F_HAVE_TLR; + h1s->flags |= H1S_F_HAVE_O_TLR; break; case HTX_BLK_EOM: if ((h1m->flags & H1_MF_CHNK)) { - if (!(h1s->flags & H1S_F_HAVE_EOD)) { + if (!(h1s->flags & H1S_F_HAVE_O_EOD)) { if (!chunk_memcat(tmp, "0\r\n", 3)) goto copy; - h1s->flags |= H1S_F_HAVE_EOD; + h1s->flags |= H1S_F_HAVE_O_EOD; } - if (!(h1s->flags & H1S_F_HAVE_TLR)) { + if (!(h1s->flags & H1S_F_HAVE_O_TLR)) { if (!chunk_memcat(tmp, "\r\n", 2)) goto copy; - h1s->flags |= H1S_F_HAVE_TLR; + h1s->flags |= H1S_F_HAVE_O_TLR; } } h1m->state = H1_MSG_DONE;