From b5b7d4a53225898245a3fff615e33b2143d4cc66 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 12 Sep 2018 18:51:18 +0200 Subject: [PATCH] BUG/MAJOR: h2: reset the parser's state on mux buffer full The h2 parser has this specificity that if it cannot send the headers frame resulting from the headers it just parsed, it needs to drop it and parse it again later. Since commit 8852850 ("MEDIUM: h1: let the caller pass the initial parser's state"), when this happens the parser remains in the data state and the headers are not parsed again next time, resulting in a parse error. Let's reset the parser on exit there. No backport is needed. --- src/mux_h2.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/mux_h2.c b/src/mux_h2.c index 53364356b..8d63ccde1 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -3123,8 +3123,6 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu * block does not wrap and we can safely read it this way without * having to realign the buffer. */ - h1m->state = H1_MSG_RPBEFORE; - h1m->next = 0; ret = h1_headers_to_hdr_list(b_peek(buf, ofs), b_peek(buf, ofs) + max, list, sizeof(list)/sizeof(list[0]), h1m, &sl); if (ret <= 0) { @@ -3155,12 +3153,8 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu b_slow_realign(&h2c->mbuf, trash.area, b_data(&h2c->mbuf)); } - if (outbuf.size < 9) { - h2c->flags |= H2_CF_MUX_MFULL; - h2s->flags |= H2_SF_BLK_MROOM; - ret = 0; - goto end; - } + if (outbuf.size < 9) + goto full; /* len: 0x000000 (fill later), type: 1(HEADERS), flags: ENDH=4 */ memcpy(outbuf.area, "\x00\x00\x00\x01\x04", 5); @@ -3189,11 +3183,7 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu else { if (b_space_wraps(&h2c->mbuf)) goto realign_again; - - h2c->flags |= H2_CF_MUX_MFULL; - h2s->flags |= H2_SF_BLK_MROOM; - ret = 0; - goto end; + goto full; } /* encode all headers, stop at empty name */ @@ -3213,11 +3203,7 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu /* output full */ if (b_space_wraps(&h2c->mbuf)) goto realign_again; - - h2c->flags |= H2_CF_MUX_MFULL; - h2s->flags |= H2_SF_BLK_MROOM; - ret = 0; - goto end; + goto full; } } @@ -3265,6 +3251,13 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu end: //fprintf(stderr, "[%d] sent simple H2 response (sid=%d) = %d bytes (%d in, ep=%u, es=%s)\n", h2c->st0, h2s->id, outbuf.len, ret, h1m->err_pos, h1_msg_state_str(h1m->err_state)); return ret; + full: + h1m_init_res(h1m); + h1m->err_pos = -1; // don't care about errors on the response path + h2c->flags |= H2_CF_MUX_MFULL; + h2s->flags |= H2_SF_BLK_MROOM; + ret = 0; + goto end; } /* Try to send a DATA frame matching HTTP/1 response present at offset