Web server hangs up
Hello everyone, I have written a Rest API for an OTA update. Basically, this works great, but as soon as I execute the request#send method during the upload process (several times), the web server hangs and no new requests are accepted and existing ones. If I remove all request#send calls, nothing hangs anymore. How can I make the web server report the upload status to the client but not hang up? Unfortunately, I have not found an explanation for this in the sample code.
#include "RestApi.h"
#include <Update.h>
#include <ArduinoJson.h>
#define U_PART U_SPIFFS
const size_t MAX_FIRMWARE_SIZE = 1048576; // 1 MB (ota partition size)
const size_t MAX_SPIFFS_SIZE = 786432; // 0.78 mb (spiffs partition size)
AsyncWebServerRequest* updateRequest = nullptr;
bool endsWith(const String& str, const String& suffix) {
if (str.length() >= suffix.length()) {
return str.substring(str.length() - suffix.length()) == suffix;
} else {
return false;
}
}
void handleFirmwareUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final, bool updateUi) {
if (updateRequest == nullptr || updateRequest == request) {
size_t firmwareSize = request->contentLength();
size_t allowedFirmwareSize = updateUi ? MAX_SPIFFS_SIZE : MAX_FIRMWARE_SIZE;
if (!endsWith(filename, ".bin") || firmwareSize > allowedFirmwareSize) {
request->send(400, "application/json", "{\"message\":\"Invalid file or file size too large.\"}");
return;
}
if (!index) {
updateRequest = request;
Serial.println("Processing firmware update...");
size_t content_len = request->contentLength();
int cmd = updateUi ? U_PART : U_FLASH;
if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) {
String errorMsg = "Update begin error: " + String(Update.errorString());
Serial.println(errorMsg);
request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
updateRequest = nullptr;
Update.end();
return;
}
}
if (Update.write(data, len) != len) {
String errorMsg = "Update write error: " + String(Update.errorString());
Serial.println(errorMsg);
request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
updateRequest = nullptr;
Update.end();
return;
}
if (final) {
if (Update.end(true)) {
Serial.println("Firmware update complete.");
request->send(200, "application/json", "{\"message\":\"Firmware update complete.\"}");
} else {
String errorMsg = "Update end error: " + String(Update.errorString());
Serial.println(errorMsg);
request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
}
updateRequest = nullptr;
}
} else {
request->send(400, "application/json", "{\"message\":\"Another update is in progress.\"}");
}
}
void setupRestApi(AsyncWebServer &server) {
server.on("/api/v1/firmware/update", HTTP_POST, [](AsyncWebServerRequest *request) {},
[](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
handleFirmwareUpload(request, filename, index, data, len, final, false);
});
server.on("/api/v1/ui/update", HTTP_POST, [](AsyncWebServerRequest *request) {},
[](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
handleFirmwareUpload(request, filename, index, data, len, final, true);
});
}
Look at the Update class, there is an opportunity to put a callback on &onProgress(THandlerFunction_Progress fn); with it, you can track the file upload process and save data to the global area. Then use the web server to return the data to the user.