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()); }