-
Notifications
You must be signed in to change notification settings - Fork 70
Description
Platform
ESP32
IDE / Tooling
Arduino (IDE/CLI)
What happened?
When sending a 16kb response in three parts, using AsyncCallbackResponse, the middle one sometimes goes missing (so the received data is ~5k shorter than expected - the page finishes but with ~5k fewer bytes than the Content-Length indicated).
This seems to be due to this:
ESPAsyncWebServer/src/WebResponses.cpp
Line 476 in 80af245
| _writtenLength += request->client()->write((const char *)buf, outLen); |
where the code assumes that the whole buffer got written (it frees it after), even if it was only partially sent. Ideally it could signal to the AsyncCallbackResponse that it needs to rewind, but being in the Abstract superclass it can't access _filledLength to decrement it.
AsyncTCP's write(...) allocates memory by default, and this system is very memory constrained, so that is probably why it is not consuming the whole buffer (probably not any of it). It looks like the code above does check space() though, but that doesn't take into account the free memory that the write() might need to allocate.
Maybe this is a situation you don't want to handle - as there's no guarantee there'll ever be enough free RAM? In practice it works if I rewind (eg. by adding a rewind method which the AsyncCallbackResponse can implement to roll back _filledLength).
Thanks!
Stack Trace
N/A
Minimal Reproductible Example (MRE)
This is the essence of it, but could build a full MRE if needed?
String *largeResponseString = new String("16k chars...");
AsyncWebServerResponse *response = request->beginResponse(
"text/html",
largeResponseString->length(),
[](uint8_t *buffer, size_t maxLen, size_t alreadySent) -> size_t {
// Calculate how much we can send in this chunk
size_t remaining = largeResponseString->length() - alreadySent;
size_t toSend = (remaining < maxLen) ? remaining : maxLen;
// Copy the data from the content string to the buffer
memcpy(buffer, largeResponseString->c_str() + alreadySent, toSend);
// Return the number of bytes sent
return toSend;
},
(AwsTemplateProcessor)nullptr // No template processor needed
);
request->send(response);I confirm that:
- I have read the documentation.
- I have searched for similar discussions.
- I have searched for similar issues.
- I have looked at the examples.
- I have upgraded to the lasted version of ESPAsyncWebServer (and AsyncTCP for ESP32).