Skip to content

Commit b9cc361

Browse files
committed
BUG/MEDIUM: h1-htx: Properly handle bodyless messages
During h1 parsing, there are some postparsing checks to detect bodyless messages and switch the parsing in DONE state. However, a case was not properly handled. Responses to HEAD requests with a "transfer-encoding" header. The response parser remained blocked waiting for the response body. To fix the issue, the postparsing was sliglty modified. Instead of trying to handle bodyless messages in a common way between the request and the response, it is now performed in the dedicated postparsing functions. It is easier to enumerate all cases, especially because there is already a test for responses to HEAD requests. This patch should fix the issue haproxy#2836. It must be backported as far as 2.9.
1 parent ca773e1 commit b9cc361

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

src/h1_htx.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,19 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
176176
if (h1sl->rq.meth == HTTP_METH_CONNECT) {
177177
h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
178178
h1m->curr_len = h1m->body_len = 0;
179+
h1m->state = H1_MSG_DONE;
180+
htx->flags |= HTX_FL_EOM;
179181
}
180-
else if (h1sl->rq.meth == HTTP_METH_HEAD)
181-
flags |= HTX_SL_F_BODYLESS_RESP;
182+
else {
183+
if (h1sl->rq.meth == HTTP_METH_HEAD)
184+
flags |= HTX_SL_F_BODYLESS_RESP;
182185

186+
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
187+
(h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) {
188+
h1m->state = H1_MSG_DONE;
189+
htx->flags |= HTX_FL_EOM;
190+
}
191+
}
183192

184193
flags |= h1m_htx_sl_flags(h1m);
185194

@@ -295,6 +304,8 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
295304
h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
296305
h1m->flags |= H1_MF_XFER_LEN;
297306
h1m->curr_len = h1m->body_len = 0;
307+
h1m->state = H1_MSG_DONE;
308+
htx->flags |= HTX_FL_EOM;
298309
}
299310
else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
300311
(code == 204) || (code == 304)) {
@@ -303,10 +314,20 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
303314
h1m->curr_len = h1m->body_len = 0;
304315
if (code >= 200)
305316
flags |= HTX_SL_F_BODYLESS_RESP;
317+
h1m->state = H1_MSG_DONE;
318+
htx->flags |= HTX_FL_EOM;
306319
}
307-
else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
308-
/* Responses with a known body length. */
309-
h1m->flags |= H1_MF_XFER_LEN;
320+
else {
321+
if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
322+
/* Responses with a known body length. */
323+
h1m->flags |= H1_MF_XFER_LEN;
324+
}
325+
326+
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
327+
(h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) {
328+
h1m->state = H1_MSG_DONE;
329+
htx->flags |= HTX_FL_EOM;
330+
}
310331
}
311332

312333
flags |= h1m_htx_sl_flags(h1m);
@@ -402,13 +423,6 @@ int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
402423
return ret;
403424
}
404425

405-
/* Switch messages without any payload to DONE state */
406-
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
407-
((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN)) {
408-
h1m->state = H1_MSG_DONE;
409-
dsthtx->flags |= HTX_FL_EOM;
410-
}
411-
412426
end:
413427
return total;
414428
error:

0 commit comments

Comments
 (0)