From 7cd4126d52d788d8bfc40c4f5e4d7a4d1d2350e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 6 Jan 2024 17:01:34 +0100 Subject: [PATCH] Merge pull request #3648 from willmmiles/json-response-locking Expand JSON buffer lock scope to entire web reply --- wled00/fcn_declare.h | 16 ++++++++++++++++ wled00/json.cpp | 22 +++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index f46c7cce97..ab29dd8d21 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -373,6 +373,22 @@ um_data_t* simulateSound(uint8_t simulationId); CRGB getCRGBForBand(int x, uint8_t *fftResult, int pal); //WLEDMM netmindz ar palette char *cleanUpName(char *in); // to clean up a name that was read from file +// RAII guard class for the JSON Buffer lock +// Modeled after std::lock_guard +class JSONBufferGuard { + bool holding_lock; + public: + inline JSONBufferGuard(uint8_t module=255) : holding_lock(requestJSONBufferLock(module)) {}; + inline ~JSONBufferGuard() { if (holding_lock) releaseJSONBufferLock(); }; + inline JSONBufferGuard(const JSONBufferGuard&) = delete; // Noncopyable + inline JSONBufferGuard& operator=(const JSONBufferGuard&) = delete; + inline JSONBufferGuard(JSONBufferGuard&& r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable + inline JSONBufferGuard& operator=(JSONBufferGuard&& r) { holding_lock |= r.holding_lock; r.holding_lock = false; return *this; }; + inline bool owns_lock() const { return holding_lock; } + explicit inline operator bool() const { return owns_lock(); }; + inline void release() { if (holding_lock) releaseJSONBufferLock(); holding_lock = false; } +}; + #ifdef WLED_ADD_EEPROM_SUPPORT //wled_eeprom.cpp void applyMacro(byte index); diff --git a/wled00/json.cpp b/wled00/json.cpp index b481d7b8f2..212482b012 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -9,6 +9,7 @@ #define JSON_PATH_PALETTES 5 #define JSON_PATH_FXDATA 6 #define JSON_PATH_NETWORKS 7 +#define JSON_PATH_EFFECTS 8 // begin WLEDMM #ifdef ARDUINO_ARCH_ESP32 @@ -1392,6 +1393,17 @@ void serializeModeNames(JsonArray arr) { } } + +// Global buffer locking response helper class +class GlobalBufferAsyncJsonResponse: public JSONBufferGuard, public AsyncJsonResponse { + public: + inline GlobalBufferAsyncJsonResponse(bool isArray) : JSONBufferGuard(17), AsyncJsonResponse(&doc, isArray) {}; + virtual ~GlobalBufferAsyncJsonResponse() {}; + + // Other members are inherited +}; + + void serveJson(AsyncWebServerRequest* request) { byte subJson = 0; @@ -1400,6 +1412,7 @@ void serveJson(AsyncWebServerRequest* request) else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO; else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO; else if (url.indexOf("nodes") > 0) subJson = JSON_PATH_NODES; + else if (url.indexOf("eff") > 0) subJson = JSON_PATH_EFFECTS; else if (url.indexOf("palx") > 0) subJson = JSON_PATH_PALETTES; else if (url.indexOf("fxda") > 0) subJson = JSON_PATH_FXDATA; else if (url.indexOf("net") > 0) subJson = JSON_PATH_NETWORKS; @@ -1435,11 +1448,12 @@ void serveJson(AsyncWebServerRequest* request) return; } - if (!requestJSONBufferLock(17)) { + GlobalBufferAsyncJsonResponse *response = new GlobalBufferAsyncJsonResponse(subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary + if (!response->owns_lock()) { request->send(503, "application/json", F("{\"error\":3}")); + delete response; return; } - AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==6); JsonVariant lDoc = response->getRoot(); @@ -1453,6 +1467,9 @@ void serveJson(AsyncWebServerRequest* request) serializeNodes(lDoc); break; case JSON_PATH_PALETTES: serializePalettes(lDoc, request); break; + //serializePalettes(lDoc, request->hasParam("page") ? request->getParam("page")->value().toInt() : 0); break; + case JSON_PATH_EFFECTS: + serializeModeNames(lDoc); break; case JSON_PATH_FXDATA: serializeModeData(lDoc.as()); break; case JSON_PATH_NETWORKS: @@ -1475,7 +1492,6 @@ void serveJson(AsyncWebServerRequest* request) response->setLength(); request->send(response); - releaseJSONBufferLock(); } #ifdef WLED_ENABLE_JSONLIVE