Merge pull request #223 from jpirnay/fix-wbdavpr1976
fix: Stream WebDAV downloads in chunks to prevent client disconnects (PR1976 by georgebashi)
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "FontInstaller.h"
|
||||
#include "HttpFileStreamer.h"
|
||||
#include "OpdsServerStore.h"
|
||||
#include "SdCardFontGlobals.h"
|
||||
#include "SdCardFontRegistry.h"
|
||||
@@ -681,27 +682,12 @@ void CrossPointWebServer::handleDownload() const {
|
||||
server->send(200, contentType.c_str(), "");
|
||||
|
||||
NetworkClient client = server->client();
|
||||
const size_t chunkSize = 4096;
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool downloadOk = HttpFileStreamer::streamFileToClient(file, client);
|
||||
client.clear();
|
||||
file.close();
|
||||
|
||||
if (!downloadOk) {
|
||||
LOG_DBG("WEB", "Download interrupted while streaming: %s", itemPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnostic counters for upload performance analysis
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <NetworkClient.h>
|
||||
|
||||
namespace HttpFileStreamer {
|
||||
bool streamFileToClient(FsFile& file, NetworkClient& client);
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <Xtc.h>
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
#include "HttpFileStreamer.h"
|
||||
|
||||
namespace {
|
||||
const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"};
|
||||
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(), "");
|
||||
|
||||
NetworkClient client = s.client();
|
||||
client.write(file);
|
||||
file.close();
|
||||
bool downloadOk = HttpFileStreamer::streamFileToClient(file, client);
|
||||
client.clear();
|
||||
|
||||
if (!downloadOk) {
|
||||
LOG_DBG("DAV", "GET interrupted while streaming: %s", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// ── HEAD ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user