From 6665b47744695f235c8d60159429a00e9db68d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Fri, 22 Aug 2025 17:02:27 +0200 Subject: [PATCH 1/9] Fix ETag handling for dynamic template responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates AsyncStaticWebHandler::handleRequest to correctly manage caching headers when template processing introduces dynamic content. The previous implementation always set ETag and Last-Modified headers based on the underlying filesystem metadata, which was misleading when templates generated non-static responses (e.g., current time). Issue #237 (https://github.com/ESP32Async/ESPAsyncWebServer/issues/237) The new implementation: - Uses file-based ETag when .gz files or template callback is not present. - Ensures gzip files generate consistent ETag values using _getEtag. - For non-gzip files, generate ETag values ​​using the timestamp or file size. - Returns 304 Not Modified only when If-None-Match matches the valid ETag. - Removed use of Variable Length Array and String, ensuring the same implementation works consistently on all platforms. This prevents browsers from incorrectly reusing cached content when template output is dynamic, ensuring correctness while still allowing efficient caching for static resources. --- src/ESPAsyncWebServer.h | 1 + src/WebHandlers.cpp | 102 +++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 7d5eea17..41c08810 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -204,6 +204,7 @@ class AsyncWebServerRequest { friend class AsyncWebServer; friend class AsyncCallbackWebHandler; friend class AsyncFileResponse; + friend class AsyncStaticWebHandler; private: AsyncClient *_client; diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index 21dba006..d1f7c5bc 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -187,6 +187,15 @@ bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest *request, const St return found; } +/** + * @brief Handles an incoming HTTP request for a static file. + * + * This method processes a request for serving static files asynchronously. + * It determines the correct ETag (entity tag) for caching, checks if the file + * has been modified, and prepares the appropriate response (file response or 304 Not Modified). + * + * @param request Pointer to the incoming AsyncWebServerRequest object. + */ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { // Get the filename from request->_tempObject and free it String filename((char *)request->_tempObject); @@ -198,66 +207,61 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - time_t lw = request->_tempFile.getLastWrite(); // get last file mod time (if supported by FS) - // set etag to lastmod timestamp if available, otherwise to size - String etag; - if (lw) { - setLastModified(lw); -#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) - // time_t == long long int - constexpr size_t len = 1 + 8 * sizeof(time_t); - char buf[len]; - char *ret = lltoa(lw ^ request->_tempFile.size(), buf, len, 10); - etag = ret ? String(ret) : String(request->_tempFile.size()); -#elif defined(LIBRETINY) - long val = lw ^ request->_tempFile.size(); - etag = String(val); -#else - etag = lw ^ request->_tempFile.size(); // etag combines file size and lastmod timestamp -#endif + // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 + char etag[9]; + const char* tempFileName = request->_tempFile.name(); + const size_t lenFilename = strlen(tempFileName); + const size_t gz_len = sizeof(T__gz) - 1; + if (lenFilename > sizeof(T__gz) && memcmp(tempFileName + lenFilename - gz_len, T__gz, gz_len) == 0) { + //File is a gz, get etag from CRC in trailer + if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) { + // File is corrupted or invalid + log_e("File is corrupted or invalid: %s", tempFileName); + request->send(404); + return; + } + request->_tempFile.seek(0); + } else if (_callback == nullptr) { + // We don't have a Template processor + uint32_t etagValue; + time_t lastWrite = request->_tempFile.getLastWrite(); + if (lastWrite > 0) { + // Use timestamp-based ETag + etagValue = static_cast(lastWrite); + } + // Use filesize-based ETag + size_t fileSize = request->_tempFile.size(); + etagValue = static_cast(fileSize); + + snprintf(etag, sizeof(etag), "%08x", etagValue); } else { -#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) || defined(LIBRETINY) - etag = String(request->_tempFile.size()); -#else - etag = request->_tempFile.size(); -#endif - } - - bool not_modified = false; - - // if-none-match has precedence over if-modified-since - if (request->hasHeader(T_INM)) { - not_modified = request->header(T_INM).equals(etag); - } else if (_last_modified.length()) { - not_modified = request->header(T_IMS).equals(_last_modified); + etag[0] = '\0'; } AsyncWebServerResponse *response; - if (not_modified) { + // Check if client already has the file (ETag match) + if (*etag != '\0' && request->header(T_INM).equals(etag)) { request->_tempFile.close(); response = new AsyncBasicResponse(304); // Not modified } else { response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback); - } - - if (!response) { -#ifdef ESP32 - log_e("Failed to allocate"); -#endif - request->abort(); - return; - } - response->addHeader(T_ETag, etag.c_str()); - - if (_last_modified.length()) { - response->addHeader(T_Last_Modified, _last_modified.c_str()); - } - if (_cache_control.length()) { - response->addHeader(T_Cache_Control, _cache_control.c_str()); + if (!response) { + #ifdef ESP32 + log_e("Failed to allocate"); + #endif + request->abort(); + return; + } + if (*etag != '\0') { + response->addHeader(T_ETag, etag, true); + response->addHeader(T_Cache_Control, T_no_cache, true); + } + else if (_cache_control.length()) { + response->addHeader(T_Cache_Control, _cache_control.c_str(), false); + } } - request->send(response); } From a16b756287e2d982442f1e82d86f66c6da14decd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Fri, 22 Aug 2025 19:37:44 +0200 Subject: [PATCH 2/9] Update src/WebHandlers.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/WebHandlers.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index d1f7c5bc..9bf3f9c3 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -232,7 +232,11 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { // Use filesize-based ETag size_t fileSize = request->_tempFile.size(); etagValue = static_cast(fileSize); - + } else { + // Use filesize-based ETag + size_t fileSize = request->_tempFile.size(); + etagValue = static_cast(fileSize); + } snprintf(etag, sizeof(etag), "%08x", etagValue); } else { etag[0] = '\0'; From dcf0491dc73b5ba8cd06ec3d7795d1646dbe2756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Fri, 22 Aug 2025 19:52:24 +0200 Subject: [PATCH 3/9] Update src/WebHandlers.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/WebHandlers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index 9bf3f9c3..76dae3c6 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -220,6 +220,8 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { request->send(404); return; } + // Reset file position to the beginning after reading the gz trailer for ETag, + // so the file can be served from the start. request->_tempFile.seek(0); } else if (_callback == nullptr) { // We don't have a Template processor From d1b08684cfb1c4503e0cf377bbb7ccaac73e82e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Fri, 22 Aug 2025 20:22:10 +0200 Subject: [PATCH 4/9] update mathieucarbou suggestions --- src/WebHandlers.cpp | 11 ++++------- src/literals.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index 76dae3c6..c1b891db 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -211,8 +211,8 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { char etag[9]; const char* tempFileName = request->_tempFile.name(); const size_t lenFilename = strlen(tempFileName); - const size_t gz_len = sizeof(T__gz) - 1; - if (lenFilename > sizeof(T__gz) && memcmp(tempFileName + lenFilename - gz_len, T__gz, gz_len) == 0) { + + if (lenFilename > T__GZ_LEN && memcmp(tempFileName + lenFilename - T__GZ_LEN, T__gz, T__GZ_LEN) == 0) { //File is a gz, get etag from CRC in trailer if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) { // File is corrupted or invalid @@ -220,6 +220,7 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { request->send(404); return; } + // Reset file position to the beginning after reading the gz trailer for ETag, // so the file can be served from the start. request->_tempFile.seek(0); @@ -230,12 +231,8 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { if (lastWrite > 0) { // Use timestamp-based ETag etagValue = static_cast(lastWrite); - } - // Use filesize-based ETag - size_t fileSize = request->_tempFile.size(); - etagValue = static_cast(fileSize); } else { - // Use filesize-based ETag + // No timestamp available, use filesize-based ETag size_t fileSize = request->_tempFile.size(); etagValue = static_cast(fileSize); } diff --git a/src/literals.h b/src/literals.h index fc0fff13..f6995870 100644 --- a/src/literals.h +++ b/src/literals.h @@ -203,5 +203,5 @@ static constexpr const char *T_only_once_headers[] = { T_Transfer_Encoding, T_Content_Location, T_Server, T_WWW_AUTH }; static constexpr size_t T_only_once_headers_len = sizeof(T_only_once_headers) / sizeof(T_only_once_headers[0]); - +static constexpr size_t T__GZ_LEN = sizeof(T__gz) - 1; } // namespace asyncsrv From bc2a00ceb6c513320fdd1ef17fa4d4cddd09075c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Sat, 23 Aug 2025 21:22:15 +0200 Subject: [PATCH 5/9] Add files via upload --- src/literals.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/literals.h b/src/literals.h index d435a496..06579e02 100644 --- a/src/literals.h +++ b/src/literals.h @@ -115,7 +115,6 @@ static constexpr const char *T__jpg = ".jpg"; // JPEG/JPG: Photos. Legacy s static constexpr const char *T__js = ".js"; // JavaScript: Interactive functionality static constexpr const char *T__json = ".json"; // JSON: Data exchange format static constexpr const char *T__mp4 = ".mp4"; // MP4: Proprietary format. Worse compression than WEBM. -static constexpr const char *T__mjs = ".mjs"; // MJS: JavaScript module format static constexpr const char *T__opus = ".opus"; // OPUS: High compression audio format static constexpr const char *T__pdf = ".pdf"; // PDF: Universal document format static constexpr const char *T__png = ".png"; // PNG: Icons, logos, transparency. Legacy support @@ -204,5 +203,5 @@ static constexpr const char *T_only_once_headers[] = { T_Transfer_Encoding, T_Content_Location, T_Server, T_WWW_AUTH }; static constexpr size_t T_only_once_headers_len = sizeof(T_only_once_headers) / sizeof(T_only_once_headers[0]); -static constexpr size_t T__GZ_LEN = sizeof(T__gz) - 1; +static constexpr size_t T__GZ_LEN = strlen(T__gz); } // namespace asyncsrv From d7e91bc1fb6b331f089bdeb26049a01cfdaabcfe Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:48:31 +0000 Subject: [PATCH 6/9] ci(pre-commit): Apply automatic fixes --- src/WebHandlers.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index c1b891db..328bffdb 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -190,9 +190,9 @@ bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest *request, const St /** * @brief Handles an incoming HTTP request for a static file. * - * This method processes a request for serving static files asynchronously. - * It determines the correct ETag (entity tag) for caching, checks if the file - * has been modified, and prepares the appropriate response (file response or 304 Not Modified). + * This method processes a request for serving static files asynchronously. + * It determines the correct ETag (entity tag) for caching, checks if the file + * has been modified, and prepares the appropriate response (file response or 304 Not Modified). * * @param request Pointer to the incoming AsyncWebServerRequest object. */ @@ -207,11 +207,11 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 + // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 char etag[9]; - const char* tempFileName = request->_tempFile.name(); + const char *tempFileName = request->_tempFile.name(); const size_t lenFilename = strlen(tempFileName); - + if (lenFilename > T__GZ_LEN && memcmp(tempFileName + lenFilename - T__GZ_LEN, T__gz, T__GZ_LEN) == 0) { //File is a gz, get etag from CRC in trailer if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) { @@ -221,9 +221,9 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Reset file position to the beginning after reading the gz trailer for ETag, - // so the file can be served from the start. - request->_tempFile.seek(0); + // Reset file position to the beginning after reading the gz trailer for ETag, + // so the file can be served from the start. + request->_tempFile.seek(0); } else if (_callback == nullptr) { // We don't have a Template processor uint32_t etagValue; @@ -251,17 +251,16 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback); if (!response) { - #ifdef ESP32 +#ifdef ESP32 log_e("Failed to allocate"); - #endif +#endif request->abort(); return; } if (*etag != '\0') { response->addHeader(T_ETag, etag, true); response->addHeader(T_Cache_Control, T_no_cache, true); - } - else if (_cache_control.length()) { + } else if (_cache_control.length()) { response->addHeader(T_Cache_Control, _cache_control.c_str(), false); } } From 22cc69d675ec308e57bf40d80d85cccf8a5b5a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Tue, 26 Aug 2025 20:42:05 +0200 Subject: [PATCH 7/9] Add Last-Modified header In funcion void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) add Last-Modified header if no GZ file or have template processor. Sugeestion of @willmmiles --- src/WebHandlers.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index 328bffdb..bbd61de3 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -190,9 +190,9 @@ bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest *request, const St /** * @brief Handles an incoming HTTP request for a static file. * - * This method processes a request for serving static files asynchronously. - * It determines the correct ETag (entity tag) for caching, checks if the file - * has been modified, and prepares the appropriate response (file response or 304 Not Modified). + * This method processes a request for serving static files asynchronously. + * It determines the correct ETag (entity tag) for caching, checks if the file + * has been modified, and prepares the appropriate response (file response or 304 Not Modified). * * @param request Pointer to the incoming AsyncWebServerRequest object. */ @@ -207,11 +207,11 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 + // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 char etag[9]; - const char *tempFileName = request->_tempFile.name(); + const char* tempFileName = request->_tempFile.name(); const size_t lenFilename = strlen(tempFileName); - + if (lenFilename > T__GZ_LEN && memcmp(tempFileName + lenFilename - T__GZ_LEN, T__gz, T__GZ_LEN) == 0) { //File is a gz, get etag from CRC in trailer if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) { @@ -221,9 +221,9 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Reset file position to the beginning after reading the gz trailer for ETag, - // so the file can be served from the start. - request->_tempFile.seek(0); + // Reset file position to the beginning after reading the gz trailer for ETag, + // so the file can be served from the start. + request->_tempFile.seek(0); } else if (_callback == nullptr) { // We don't have a Template processor uint32_t etagValue; @@ -251,17 +251,23 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback); if (!response) { -#ifdef ESP32 + #ifdef ESP32 log_e("Failed to allocate"); -#endif + #endif request->abort(); return; } if (*etag != '\0') { response->addHeader(T_ETag, etag, true); response->addHeader(T_Cache_Control, T_no_cache, true); - } else if (_cache_control.length()) { - response->addHeader(T_Cache_Control, _cache_control.c_str(), false); + } + else { + if (_cache_control.length()) { + response->addHeader(T_Cache_Control, _cache_control.c_str(), false); + } + if (_last_modified.length()) { + response->addHeader(T_Last_Modified, _last_modified.c_str(), true); + } } } request->send(response); From 72ab5215d7fd1431520d8ea0600f79e61c67e7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20M=2E=20Pi=C3=B1eiro?= Date: Tue, 2 Sep 2025 04:52:07 +0200 Subject: [PATCH 8/9] fix handleRequest(AsyncWebServerRequest *request) If the user has defined them, "Last-Modified" and "Cache-Control" are always sent. --- src/WebHandlers.cpp | 55 +++++++++++++++++++++++++++++++-------------- src/literals.h | 1 + 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index bbd61de3..cc10ac7d 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -200,7 +200,7 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { // Get the filename from request->_tempObject and free it String filename((char *)request->_tempObject); free(request->_tempObject); - request->_tempObject = NULL; + request->_tempObject = nullptr; if (request->_tempFile != true) { request->send(404); @@ -221,8 +221,7 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Reset file position to the beginning after reading the gz trailer for ETag, - // so the file can be served from the start. + // Reset file position to the beginning so the file can be served from the start. request->_tempFile.seek(0); } else if (_callback == nullptr) { // We don't have a Template processor @@ -243,33 +242,55 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { AsyncWebServerResponse *response; - // Check if client already has the file (ETag match) - if (*etag != '\0' && request->header(T_INM).equals(etag)) { + // Get raw header pointers to avoid creating temporary String objects + const char* inm = request->header(T_INM).c_str(); // If-None-Match + const char* ims = request->header(T_IMS).c_str(); // If-Modified-Since + + bool notModified = false; + // 1. If the client sent If-None-Match and we have an ETag → compare + if (*etag != '\0' && inm && *inm) { + if (strcmp(inm, etag) == 0) { + notModified = true; + } + } + // 2. Otherwise, if there is no ETag and no Template processor but we have Last-Modified and Last-Modified matches + else if (*etag == '\0' && _callback == nullptr && _last_modified.length() > 0 && ims && *ims && strcmp(ims, _last_modified.c_str()) == 0) { + log_d("_last_modified: %s", _last_modified.c_str()); + log_d("ims: %s", ims); + notModified = true; + } + + if (notModified) { request->_tempFile.close(); response = new AsyncBasicResponse(304); // Not modified } else { response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback); - if (!response) { - #ifdef ESP32 - log_e("Failed to allocate"); - #endif + #ifdef ESP32 + log_e("Failed to allocate"); + #endif request->abort(); return; } + + // Set ETag header if (*etag != '\0') { response->addHeader(T_ETag, etag, true); - response->addHeader(T_Cache_Control, T_no_cache, true); } - else { - if (_cache_control.length()) { - response->addHeader(T_Cache_Control, _cache_control.c_str(), false); - } - if (_last_modified.length()) { - response->addHeader(T_Last_Modified, _last_modified.c_str(), true); - } + // Set Last-Modified header + if (_last_modified.length()) { + response->addHeader(T_Last_Modified, _last_modified.c_str(), true); } } + + // Set cache control + if (_cache_control.length()) { + response->addHeader(T_Cache_Control, _cache_control.c_str(), false); + } + else { + response->addHeader(T_Cache_Control, T_no_cache, false); + } + request->send(response); } diff --git a/src/literals.h b/src/literals.h index 1f7e731a..369bd18e 100644 --- a/src/literals.h +++ b/src/literals.h @@ -115,6 +115,7 @@ static constexpr const char *T__jpg = ".jpg"; // JPEG/JPG: Photos. Legacy s static constexpr const char *T__js = ".js"; // JavaScript: Interactive functionality static constexpr const char *T__json = ".json"; // JSON: Data exchange format static constexpr const char *T__mp4 = ".mp4"; // MP4: Proprietary format. Worse compression than WEBM. +static constexpr const char *T__mjs = ".mjs"; // MJS: JavaScript module format static constexpr const char *T__opus = ".opus"; // OPUS: High compression audio format static constexpr const char *T__pdf = ".pdf"; // PDF: Universal document format static constexpr const char *T__png = ".png"; // PNG: Icons, logos, transparency. Legacy support From 04fd5e5290623dce6ae6f079755e722c05bc03bb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:53:48 +0000 Subject: [PATCH 9/9] ci(pre-commit): Apply automatic fixes --- src/WebHandlers.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index cc10ac7d..6a95d724 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -190,9 +190,9 @@ bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest *request, const St /** * @brief Handles an incoming HTTP request for a static file. * - * This method processes a request for serving static files asynchronously. - * It determines the correct ETag (entity tag) for caching, checks if the file - * has been modified, and prepares the appropriate response (file response or 304 Not Modified). + * This method processes a request for serving static files asynchronously. + * It determines the correct ETag (entity tag) for caching, checks if the file + * has been modified, and prepares the appropriate response (file response or 304 Not Modified). * * @param request Pointer to the incoming AsyncWebServerRequest object. */ @@ -207,11 +207,11 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 + // Get server ETag. If file is not GZ and we have a Template Processor, ETag=0 char etag[9]; - const char* tempFileName = request->_tempFile.name(); + const char *tempFileName = request->_tempFile.name(); const size_t lenFilename = strlen(tempFileName); - + if (lenFilename > T__GZ_LEN && memcmp(tempFileName + lenFilename - T__GZ_LEN, T__gz, T__GZ_LEN) == 0) { //File is a gz, get etag from CRC in trailer if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) { @@ -221,8 +221,8 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { return; } - // Reset file position to the beginning so the file can be served from the start. - request->_tempFile.seek(0); + // Reset file position to the beginning so the file can be served from the start. + request->_tempFile.seek(0); } else if (_callback == nullptr) { // We don't have a Template processor uint32_t etagValue; @@ -243,21 +243,21 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { AsyncWebServerResponse *response; // Get raw header pointers to avoid creating temporary String objects - const char* inm = request->header(T_INM).c_str(); // If-None-Match - const char* ims = request->header(T_IMS).c_str(); // If-Modified-Since + const char *inm = request->header(T_INM).c_str(); // If-None-Match + const char *ims = request->header(T_IMS).c_str(); // If-Modified-Since bool notModified = false; // 1. If the client sent If-None-Match and we have an ETag → compare if (*etag != '\0' && inm && *inm) { - if (strcmp(inm, etag) == 0) { - notModified = true; - } + if (strcmp(inm, etag) == 0) { + notModified = true; + } } // 2. Otherwise, if there is no ETag and no Template processor but we have Last-Modified and Last-Modified matches else if (*etag == '\0' && _callback == nullptr && _last_modified.length() > 0 && ims && *ims && strcmp(ims, _last_modified.c_str()) == 0) { log_d("_last_modified: %s", _last_modified.c_str()); log_d("ims: %s", ims); - notModified = true; + notModified = true; } if (notModified) { @@ -266,9 +266,9 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { } else { response = new AsyncFileResponse(request->_tempFile, filename, emptyString, false, _callback); if (!response) { - #ifdef ESP32 - log_e("Failed to allocate"); - #endif +#ifdef ESP32 + log_e("Failed to allocate"); +#endif request->abort(); return; } @@ -286,8 +286,7 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) { // Set cache control if (_cache_control.length()) { response->addHeader(T_Cache_Control, _cache_control.c_str(), false); - } - else { + } else { response->addHeader(T_Cache_Control, T_no_cache, false); }