stream WebDAV downloads in chunks to prevent client disconnects

This commit is contained in:
jpirnay
2026-05-15 14:23:19 +02:00
parent 684a96f108
commit f1b8b75002
4 changed files with 66 additions and 22 deletions
+6 -20
View File
@@ -15,6 +15,7 @@
#include "CrossPointSettings.h" #include "CrossPointSettings.h"
#include "FontInstaller.h" #include "FontInstaller.h"
#include "HttpFileStreamer.h"
#include "OpdsServerStore.h" #include "OpdsServerStore.h"
#include "SdCardFontGlobals.h" #include "SdCardFontGlobals.h"
#include "SdCardFontRegistry.h" #include "SdCardFontRegistry.h"
@@ -681,27 +682,12 @@ void CrossPointWebServer::handleDownload() const {
server->send(200, contentType.c_str(), ""); server->send(200, contentType.c_str(), "");
NetworkClient client = server->client(); NetworkClient client = server->client();
const size_t chunkSize = 4096; bool downloadOk = HttpFileStreamer::streamFileToClient(file, client);
uint8_t buffer[chunkSize];
bool downloadOk = true;
while (downloadOk && file.available()) {
int result = file.read(buffer, chunkSize);
if (result <= 0) break;
size_t bytesRead = static_cast<size_t>(result);
size_t totalWritten = 0;
while (totalWritten < bytesRead) {
esp_task_wdt_reset();
size_t wrote = client.write(buffer + totalWritten, bytesRead - totalWritten);
if (wrote == 0) {
downloadOk = false;
break;
}
totalWritten += wrote;
}
}
client.clear(); client.clear();
file.close();
if (!downloadOk) {
LOG_DBG("WEB", "Download interrupted while streaming: %s", itemPath.c_str());
}
} }
// Diagnostic counters for upload performance analysis // Diagnostic counters for upload performance analysis
+44
View File
@@ -0,0 +1,44 @@
#include "HttpFileStreamer.h"
#include <Logging.h>
#include <esp_task_wdt.h>
namespace {
constexpr size_t DOWNLOAD_CHUNK_SIZE = 4096;
}
namespace HttpFileStreamer {
bool streamFileToClient(FsFile& file, NetworkClient& client) {
auto* buffer = static_cast<uint8_t*>(malloc(DOWNLOAD_CHUNK_SIZE));
if (!buffer) {
LOG_ERR("HTTP", "malloc failed: %zu bytes", DOWNLOAD_CHUNK_SIZE);
return false;
}
bool ok = true;
while (ok) {
esp_task_wdt_reset();
int result = file.read(buffer, DOWNLOAD_CHUNK_SIZE);
if (result < 0) {
ok = false;
break;
}
if (result == 0) break;
size_t bytesRead = static_cast<size_t>(result);
size_t totalWritten = 0;
while (totalWritten < bytesRead) {
esp_task_wdt_reset();
size_t wrote = client.write(buffer + totalWritten, bytesRead - totalWritten);
if (wrote == 0) {
ok = false;
break;
}
totalWritten += wrote;
}
}
free(buffer);
return ok;
}
} // namespace HttpFileStreamer
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <HalStorage.h>
#include <NetworkClient.h>
namespace HttpFileStreamer {
bool streamFileToClient(FsFile& file, NetworkClient& client);
}
+8 -2
View File
@@ -8,6 +8,8 @@
#include <Xtc.h> #include <Xtc.h>
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
#include "HttpFileStreamer.h"
namespace { namespace {
const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"};
constexpr size_t HIDDEN_ITEMS_COUNT = sizeof(HIDDEN_ITEMS) / sizeof(HIDDEN_ITEMS[0]); constexpr size_t HIDDEN_ITEMS_COUNT = sizeof(HIDDEN_ITEMS) / sizeof(HIDDEN_ITEMS[0]);
@@ -330,8 +332,12 @@ void WebDAVHandler::handleGet(WebServer& s) {
s.send(200, contentType.c_str(), ""); s.send(200, contentType.c_str(), "");
NetworkClient client = s.client(); NetworkClient client = s.client();
client.write(file); bool downloadOk = HttpFileStreamer::streamFileToClient(file, client);
file.close(); client.clear();
if (!downloadOk) {
LOG_DBG("DAV", "GET interrupted while streaming: %s", path.c_str());
}
} }
// ── HEAD ───────────────────────────────────────────────────────────────────── // ── HEAD ─────────────────────────────────────────────────────────────────────