diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp
index e9cb5e9c1b..7f9fbc4057 100644
--- a/src/mesh/http/ContentHandler.cpp
+++ b/src/mesh/http/ContentHandler.cpp
@@ -352,11 +352,14 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET");
- concurrency::LockGuard g(spiLock);
- std::string fileList = htmlListDir("/static", 10);
-
- uint64_t total = FSCom.totalBytes();
- uint64_t used = FSCom.usedBytes();
+ std::string fileList;
+ uint64_t total, used;
+ {
+ concurrency::LockGuard g(spiLock);
+ fileList = htmlListDir("/static", 10);
+ total = FSCom.totalBytes();
+ used = FSCom.usedBytes();
+ }
// Key order matches the previous std::map-based emission (alphabetical).
std::string out;
@@ -385,11 +388,14 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
if (params->getQueryParameter("delete", paramValDelete)) {
std::string pathDelete = "/" + paramValDelete;
- concurrency::LockGuard g(spiLock);
- const char *status = FSCom.remove(pathDelete.c_str()) ? "ok" : "Error";
+ bool removed;
+ {
+ concurrency::LockGuard g(spiLock);
+ removed = FSCom.remove(pathDelete.c_str());
+ }
LOG_INFO("%s", pathDelete.c_str());
std::string out = "{\"status\":";
- out += jsonEscape(status);
+ out += jsonEscape(removed ? "ok" : "Error");
out += "}";
writeAll(res, out);
return;
@@ -421,38 +427,43 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
filenameGzip = "/static/index.html.gz";
}
- concurrency::LockGuard g(spiLock);
+ // spiLock covers filesystem calls only: a socket write or a syslog line can need the lock itself on a
+ // shared-bus Ethernet board, and the lock is not recursive.
+ bool exists;
+ bool gzipExists = false;
+ bool available;
+ size_t size;
+ {
+ concurrency::LockGuard g(spiLock);
+ exists = FSCom.exists(filename.c_str());
+ if (!exists) {
+ gzipExists = FSCom.exists(filenameGzip.c_str());
+ if (!gzipExists)
+ filenameGzip = "/static/index.html.gz";
+ }
+ file = FSCom.open(exists ? filename.c_str() : filenameGzip.c_str());
+ available = file.available();
+ size = file.size();
+ if (!available && !exists && !gzipExists)
+ file.close();
+ }
- if (FSCom.exists(filename.c_str())) {
- file = FSCom.open(filename.c_str());
- if (!file.available()) {
- LOG_WARN("File not available - %s", filename.c_str());
- }
- } else if (FSCom.exists(filenameGzip.c_str())) {
- file = FSCom.open(filenameGzip.c_str());
- res->setHeader("Content-Encoding", "gzip");
- if (!file.available()) {
- LOG_WARN("File not available - %s", filenameGzip.c_str());
- }
- } else {
+ if (!available)
+ LOG_WARN("File not available - %s", exists ? filename.c_str() : filenameGzip.c_str());
+ if (!exists && !gzipExists) {
has_set_content_type = true;
- filenameGzip = "/static/index.html.gz";
- file = FSCom.open(filenameGzip.c_str());
res->setHeader("Content-Type", "text/html");
- if (!file.available()) {
-
- LOG_WARN("File not available - %s", filenameGzip.c_str());
+ if (!available) {
res->println("Web server is running.
The content you are looking for can't be found. Please see: FAQ.
admin");
-
return;
- } else {
- res->setHeader("Content-Encoding", "gzip");
}
}
+ if (!exists)
+ res->setHeader("Content-Encoding", "gzip");
- res->setHeader("Content-Length", httpsserver::intToString(file.size()));
+ res->setHeader("Content-Length", httpsserver::intToString(size));
// Content-Type is guessed using the definition of the contentTypes-table defined above
int cTypeIdx = 0;
@@ -473,13 +484,18 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
// Read the file and write it to the HTTP response body
size_t length = 0;
do {
- char buffer[256];
- length = file.read((uint8_t *)buffer, 256);
- std::string bufferString(buffer, length);
- res->write((uint8_t *)bufferString.c_str(), bufferString.size());
+ uint8_t buffer[256];
+ {
+ concurrency::LockGuard g(spiLock);
+ length = file.read(buffer, sizeof(buffer));
+ }
+ res->write(buffer, length);
} while (length > 0);
- file.close();
+ {
+ concurrency::LockGuard g(spiLock);
+ file.close();
+ }
return;
} else {
@@ -566,9 +582,16 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
// concepts of the body parser functionality easier to understand.
std::string pathname = "/static/" + filename;
- concurrency::LockGuard g(spiLock);
- // Create a new file to stream the data into
- File file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
+ // spiLock covers filesystem calls only: the body is read from a socket, and on a shared-bus Ethernet board
+ // the receive path needs the lock. Free space is taken once, as nothing else writes while this runs.
+ File file;
+ size_t freeBytes;
+ {
+ concurrency::LockGuard g(spiLock);
+ // Create a new file to stream the data into
+ file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
+ freeBytes = FSCom.totalBytes() - FSCom.usedBytes();
+ }
size_t fileLength = 0;
didwrite = true;
@@ -579,29 +602,32 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
byte buf[512];
size_t readLength = parser->read(buf, 512);
- // LOG_DEBUG("readLength - %i", readLength);
-
- // Abort the transfer if there is less than 50k space left on the filesystem.
- if (FSCom.totalBytes() - FSCom.usedBytes() < 51200) {
- file.flush();
- file.close();
- res->println("
Write aborted! Reserving 50k on filesystem.
"); - - // enableLoopWDT(); + // Abort the transfer if there is less than 50k space left on the filesystem, or a write comes up short. + const bool full = fileLength + readLength + 51200 > freeBytes; + size_t written = 0; + if (!full) { + concurrency::LockGuard g(spiLock); + written = file.write(buf, readLength); + } + if (full || written != readLength) { + { + concurrency::LockGuard g(spiLock); + file.flush(); + file.close(); + } + res->println(full ? "Write aborted! Reserving 50k on filesystem.
" : "Write failed.
"); return; } - - // if (readLength) { - file.write(buf, readLength); fileLength += readLength; LOG_DEBUG("File Length %i", fileLength); - //} } - // enableLoopWDT(); - file.flush(); - file.close(); + { + concurrency::LockGuard g(spiLock); + file.flush(); + file.close(); + } res->printf("Saved %d bytes to %s
", (int)fileLength, pathname.c_str()); }