Skip to content

Commit 5c17d4e

Browse files
lws-teamclaude
andcommitted
h3: C-035: do not refuse a POST body because the ah is already detached
639cf4778 gated DATA on the stream still holding its ah, to stop a DATA frame arriving after the body completed (stream back in ESTABLISHED, ah detached) from reaching lws_read_h1()'s header parser with a NULL ah. But the ah being gone does not mean the body phase is over: the POLLOUT handler detaches it as soon as lws_http_action() returns, while a POST stream is still legitimately in LRS_BODY waiting for its body. So every h3 POST body was refused with "DATA outside body phase", and the http-client-multi-post-stag / -stag-h1 ctests timed out. Keep refusing DATA before the header block, and DATA on an ESTABLISHED stream whose ah is gone (the body-completed case the original fix was for), but let the body states through: there lws_read_h1() goes straight to the body path and needs no ah. The ESTABLISHED-with-ah -> LRS_BODY mirror of h2 is unchanged. Bisected with http-client-multi-post-stag; all eight http-client-multi-post ctests pass again with this. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 3c6a860 commit 5c17d4e

1 file changed

Lines changed: 36 additions & 16 deletions

File tree

lib/roles/h3/ops-h3.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,26 +1484,46 @@ lws_h3_rx_stream_data(struct lws *wsi, const uint8_t *buf, size_t len)
14841484
/*
14851485
* DATA is only meaningful as
14861486
* body after a complete header
1487-
* block and before the body was
1488-
* completed: once the body is
1489-
* done the ah is detached and
1490-
* lws_read_h1() would try to
1491-
* parse into it (NULL); before
1492-
* the headers it is
1493-
* H3_FRAME_UNEXPECTED. Mirror
1494-
* h2: a stream still in
1487+
* block: before it, DATA is
1488+
* H3_FRAME_UNEXPECTED. And a
1489+
* stream back in ESTABLISHED
1490+
* with its ah detached has
1491+
* finished its body: a further
1492+
* DATA frame would go into
1493+
* lws_read_h1()'s header parser
1494+
* with a NULL ah. Refuse both.
1495+
*
1496+
* But the ah being gone is not
1497+
* by itself "outside the body
1498+
* phase": the POLLOUT handler
1499+
* detaches it as soon as
1500+
* lws_http_action() returned,
1501+
* while a POST stream is still
1502+
* legitimately in LRS_BODY
1503+
* waiting for its body, and in
1504+
* the body states lws_read_h1()
1505+
* goes straight to the body
1506+
* path and needs no ah. Gating
1507+
* on the ah alone refused every
1508+
* h3 POST body.
1509+
*
1510+
* Mirror h2: a stream still in
14951511
* ESTABLISHED with its ah moves
14961512
* to LRS_BODY here.
14971513
*/
1498-
if (lwsi_role_http(wsi) &&
1499-
(!wsi->hdr_parsing_completed ||
1500-
!wsi->http.ah)) {
1501-
lwsl_wsi_notice(wsi, "DATA outside body phase");
1502-
return 1;
1514+
if (lwsi_role_http(wsi)) {
1515+
if (!wsi->hdr_parsing_completed) {
1516+
lwsl_wsi_notice(wsi, "DATA before header block");
1517+
return 1;
1518+
}
1519+
if (lwsi_state(wsi) == LRS_ESTABLISHED) {
1520+
if (!wsi->http.ah) {
1521+
lwsl_wsi_notice(wsi, "DATA after body completed");
1522+
return 1;
1523+
}
1524+
lwsi_set_state(wsi, LRS_BODY);
1525+
}
15031526
}
1504-
if (lwsi_role_http(wsi) &&
1505-
lwsi_state(wsi) == LRS_ESTABLISHED)
1506-
lwsi_set_state(wsi, LRS_BODY);
15071527

15081528
wsi->outer_will_close = 1;
15091529
n = lws_read_h1(wsi, (unsigned char *)buf, chunk);

0 commit comments

Comments
 (0)