Replies: 3 comments 2 replies
This is the correct behaviour. When |
|
After poking my harness to look at the delta between 747223f and what WLED is carrying, I think the actual issue may be that the old path counts bytes accepted into AsyncTCP's internal queue rather than bytes that have made it into the lwIP send buffer. On slow links those can diverge enough that the response lifecycle concludes while data is still in transit through AsyncTCP's internals. Your rewrite closes that gap. Would that match your understanding of the bug? |
|
Following up — the truncation turned out to be |
Uh oh!
There was an error while loading. Please reload this page.
AsyncAbstractResponse: chunked responses close connection before ACKs in RESPONSE_WAIT_ACK
In
AsyncAbstractResponse::_ack()(WebResponses.cpp), theRESPONSE_WAIT_ACKexit condition is:On the chunked path,
sendChunked()sets_chunked=trueand_sendContentLength=false. The!_sendContentLengthterm is unconditionally true, soRESPONSE_WAIT_ACKexits immediately on the next_ack()call regardless of_ackedLength >= _writtenLength.close()fires as soon as the final zero-length chunk is written to the lwIP send buffer — not when it is ACKed.On fast WiFi the write-to-ACK gap is short enough that this doesn't matter in practice. On slow transports (PPP/UART, congested WiFi with retransmissions) the gap is large enough that the connection closes before the tail of the payload drains, truncating the response on the client.
Your fork addressed this in
747223f02f8eby dropping the ACK wait entirely and relying onAsyncWebServerRequest::_onAckfor graceful close. This issue documents the root cause for the benefit of other forks still carrying the buggy condition, and to ask whether a minimal targeted fix might be worth upstreaming to me-no-dev as well.State across active forks (as of August 2026)
AsyncAbstractResponseWAIT_ACK conditionAsyncAbstractResponse!_sendContentLength || _ackedLength >= _writtenLengthAsyncBasicResponselines 320-323_ackedLength >= _writtenLengthAsyncAbstractResponse!_sendContentLength || _ackedLength >= _writtenLengthac44e32(WLED fork)!_sendContentLength || _ackedLength >= _writtenLength747223f02f8e_state = RESPONSE_ENDMinimal fix (for forks not adopting the ESP32Async lifecycle refactor)
Match
AsyncBasicResponse— remove the!_sendContentLengthshortcut:Context
Discovered while investigating truncated
/json/fxdataresponses on PPP/UART and congested WiFi in wled/WLED#5808. That PR works around it at the application level by switching fromsendChunked()torequest->send()with a pre-computedContent-Length(_sendContentLength=true), which gatesRESPONSE_WAIT_ACKcorrectly. The workaround is unaffected by whether this is fixed in the library.All reactions