Compare commits

...

7 Commits

Author SHA1 Message Date
Frank f5adaaa44e Merge branch 'main' into json_error_handling 2026-04-08 21:29:57 +02:00
Frank 121250c0a0 Merge branch 'main' into json_error_handling 2026-04-08 21:21:17 +02:00
Frank 252007d37f shorter 2026-04-07 15:43:22 +02:00
Frank 6e76a69417 preserve legacy behaviour 2026-04-07 15:34:20 +02:00
Frank 24e2e3c195 prevent excessive resize - part 2
overlooked this one
2026-04-07 15:30:17 +02:00
Frank Möhle f1c58ee75f fix indentation 2026-04-07 15:11:10 +02:00
Frank c8fc1c89b6 improve robustness against broken / malformed JSON
* malformed / too big wsec.json and cfg.json are treated as read error
* debug_print JSON parse errors
2026-04-07 15:05:15 +02:00
2 changed files with 16 additions and 9 deletions
+8 -6
View File
@@ -84,7 +84,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray nw_ins = nw["ins"];
if (!nw_ins.isNull()) {
// as password are stored separately in wsec.json when reading configuration vector resize happens there, but for dynamic config we need to resize if necessary
if (nw_ins.size() > 1 && nw_ins.size() > multiWiFi.size()) multiWiFi.resize(nw_ins.size()); // resize constructs objects while resizing
size_t newSize = min((size_t)WLED_MAX_WIFI_COUNT, nw_ins.size()); // cap at WLED_MAX_WIFI_COUNT (prevent oversizing when too many Wi-Fi entries)
if (nw_ins.size() > 1 && newSize > multiWiFi.size()) multiWiFi.resize(newSize); // resize constructs objects while resizing
for (JsonObject wifi : nw_ins) {
JsonArray ip = wifi["ip"];
JsonArray gw = wifi["gw"];
@@ -790,14 +791,14 @@ void resetConfig() {
}
bool deserializeConfigFromFS() {
[[maybe_unused]] bool success = deserializeConfigSec();
(void) deserializeConfigSec(); // success/failure is ignored intentionally. We need to read cfg.json even when wsec.json has errors.
if (!requestJSONBufferLock(JSON_LOCK_CFG_DES)) return false;
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
success = readObjectFromFile(s_cfg_json, nullptr, pDoc);
bool success = readObjectFromFile(s_cfg_json, nullptr, pDoc);
if (!success || (pDoc->overflowed())) pDoc->clear(); // corrupted/too-large → same as missing: seed defaults
// NOTE: This routine deserializes *and* applies the configuration
// Therefore, must also initialize ethernet from this function
JsonObject root = pDoc->as<JsonObject>();
@@ -1263,7 +1264,7 @@ bool deserializeConfigSec() {
if (!requestJSONBufferLock(JSON_LOCK_CFG_SEC_DES)) return false;
bool success = readObjectFromFile(s_wsec_json, nullptr, pDoc);
if (!success) {
if (!success || pDoc->overflowed() || pDoc->size() < 1) { // reject if overflowed (noMemory) or empty
releaseJSONBufferLock();
return false;
}
@@ -1273,7 +1274,8 @@ bool deserializeConfigSec() {
size_t n = 0;
JsonArray nw_ins = root["nw"]["ins"];
if (!nw_ins.isNull()) {
if (nw_ins.size() > 1 && nw_ins.size() > multiWiFi.size()) multiWiFi.resize(nw_ins.size()); // resize constructs objects while resizing
size_t newSize = min((size_t)WLED_MAX_WIFI_COUNT, nw_ins.size()); // cap at WLED_MAX_WIFI_COUNT (prevent oversizing when too many Wi-Fi entries)
if (nw_ins.size() > 1 && newSize > multiWiFi.size()) multiWiFi.resize(newSize); // resize constructs objects while resizing
for (JsonObject wifi : nw_ins) {
char pw[65] = "";
getStringFromJson(pw, wifi["psk"], 65);
+8 -3
View File
@@ -355,12 +355,17 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, c
return false;
}
if (filter) deserializeJson(*dest, f, DeserializationOption::Filter(*filter));
else deserializeJson(*dest, f);
DeserializationError jsonErr = DeserializationError::Ok;
if (filter) jsonErr = deserializeJson(*dest, f, DeserializationOption::Filter(*filter));
else jsonErr = deserializeJson(*dest, f);
f.close();
DEBUGFS_PRINTF("Read, took %lu ms\n", millis() - s);
return true;
if (jsonErr) { // EmptyInput, IncompleteInput, InvalidInput, NoMemory, TooDeep
DEBUG_PRINTF_P(PSTR("readObjectFromFile(%s): JSON %s !\n"), fileName, jsonErr.c_str());
return jsonErr == DeserializationError::NoMemory || jsonErr == DeserializationError::EmptyInput; // NoMemory => data is partial but usable; empty => handled by caller
} else return true;
}
void updateFSInfo() {