From: Christopher Faulet Date: Wed, 7 Oct 2026 08:34:08 +0000 (+0200) Subject: BUG/MINOR: h1: keep accepting unsafe violations after a parser reset X-Git-Tag: v3.5-dev10~159 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=298bd3d474f8b4606494452765024fbdd095aabf;p=haproxy.git BUG/MINOR: h1: keep accepting unsafe violations after a parser reset The H1 parser relies on h1m->err_pos being preset to -1 instead of -2 to accept some violations ("option accept-unsafe-violations-in-http-request" and "option accept-unsafe-violations-in-http-response"). The H1 mux sets it when the H1 stream is created. However the H1 message is reset in a few places using h1m_init_req() or h1m_init_res(), which set err_pos back to -2: - in h1_process_demux(), when a 1xx interim response was received, to parse the final response; - in h1_postparse_req_hdrs() and h1_postparse_res_hdrs(), when the headers do not fit in the output buffer and the parsing must be restarted later. As a result, the strict mode is silently enforced on the final response following a 1xx interim response (or after an output full condition), and a response accepted otherwise is rejected with a 502. To fix the issue, the lenient mode is restored after these resets: from the proxy's options in the mux, and from the previous err_pos value in the h1_postparse_* functions. This should be backported to all stable versions. --- diff --git a/src/h1_htx.c b/src/h1_htx.c index 60cee11ce..aaaca5ad4 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -178,6 +178,7 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx struct htx_sl *sl; struct ist meth, uri, vsn; unsigned int flags = 0; + int lenient; /* is always defined for a request */ meth = h1sl->rq.m; @@ -268,8 +269,11 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx * corresponding flags must be preserved for the next parsing. */ flags = h1m->flags & (H1_MF_CONN_CLO|H1_MF_CONN_KAL); + lenient = (h1m->err_pos >= -1); h1m_init_req(h1m); h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR|flags); + if (lenient) + h1m->err_pos = -1; /* keep accepting unsafe violations */ return -2; error: h1m->err_pos = h1m->next; @@ -290,6 +294,7 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx struct ist vsn, status, reason; unsigned int flags = 0; uint16_t code = 0; + int lenient; if (h1sl) { /* For HTTP responses, the start-line was parsed */ @@ -393,8 +398,11 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx * corresponding flags must be preserved for the next parsing. */ flags = h1m->flags & (H1_MF_CONN_CLO|H1_MF_CONN_KAL); + lenient = (h1m->err_pos >= -1); h1m_init_res(h1m); h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR|flags); + if (lenient) + h1m->err_pos = -1; /* keep accepting unsafe violations */ return -2; error: h1m->err_pos = h1m->next; diff --git a/src/mux_h1.c b/src/mux_h1.c index 7e6cf2bf2..82b29cb48 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -2230,6 +2230,8 @@ static size_t h1_process_demux(struct h1c *h1c, struct buffer *buf, size_t count h1s->status < 200 && (h1s->status == 100 || h1s->status >= 102)) { h1m_init_res(&h1s->res); h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR); + if (h1c->px->options2 & PR_O2_RSPBUG_OK) + h1m->err_pos = -1; TRACE_STATE("1xx response rcvd", H1_EV_RX_DATA|H1_EV_RX_HDRS, h1c->conn, h1s); } }