diff --git a/Server/Source/core_impl.hpp b/Server/Source/core_impl.hpp index 396b195ea..75acea715 100644 --- a/Server/Source/core_impl.hpp +++ b/Server/Source/core_impl.hpp @@ -320,15 +320,15 @@ class Config final : public IEarlyConfig std::map defaults; - String expandEnvironmentVariables(const String& value) const + String expandEnvironmentVariablesInRawJSON(const String& jsonText) const { String result; - result.reserve(value.length()); + result.reserve(jsonText.length()); size_t i = 0; - while (i < value.length()) + while (i < jsonText.length()) { - const char ch = value[i]; + const char ch = jsonText[i]; if (ch != '$') { @@ -337,14 +337,14 @@ class Config final : public IEarlyConfig continue; } - if (i + 1 < value.length() && value[i + 1] == '$') + if (i + 1 < jsonText.length() && jsonText[i + 1] == '$') { result.push_back('$'); i += 2; continue; } - if (i + 1 >= value.length() || value[i + 1] != '{') + if (i + 1 >= jsonText.length() || jsonText[i + 1] != '{') { result.push_back(ch); ++i; @@ -352,31 +352,28 @@ class Config final : public IEarlyConfig } const size_t varStart = i + 2; - const size_t end = value.find('}', varStart); + const size_t end = jsonText.find('}', varStart); if (end == String::npos) { - result.append(value.substr(i)); + result.append(jsonText.substr(i)); break; } - const String fullVar = value.substr(varStart, end - varStart); + const String fullVar = jsonText.substr(varStart, end - varStart); const size_t defaultPos = fullVar.find(":-"); const String varName = (defaultPos != String::npos) ? fullVar.substr(0, defaultPos) : fullVar; + const String defaultValue = (defaultPos != String::npos) ? fullVar.substr(defaultPos + 2) : ""; const char* envValue = std::getenv(varName.c_str()); - if (envValue) + if (envValue && envValue[0] != '\0') { result.append(envValue); } - else if (defaultPos != String::npos) + else if (!defaultValue.empty()) { - result.append(fullVar.substr(defaultPos + 2)); - } - else - { - result.append(value.substr(i, end - i + 1)); + result.append(defaultValue); } i = end + 1; @@ -405,8 +402,7 @@ class Config final : public IEarlyConfig } else if (v.is_string()) { - String strValue = v.get(); - processed[key].emplace(expandEnvironmentVariables(strValue)); + processed[key].emplace(v.get()); } else if (v.is_array()) { @@ -416,8 +412,7 @@ class Config final : public IEarlyConfig { if (arrVal.is_string()) { - String strValue = arrVal.get(); - vec.emplace_back(expandEnvironmentVariables(strValue)); + vec.emplace_back(arrVal.get()); } } } @@ -445,7 +440,10 @@ class Config final : public IEarlyConfig nlohmann::json props; try { - props = nlohmann::json::parse(ifs, nullptr, true /* allow_exceptions */, true /* ignore_comments */); + String fileContent((std::istreambuf_iterator(ifs)), + std::istreambuf_iterator()); + String expandedContent = expandEnvironmentVariablesInRawJSON(fileContent); + props = nlohmann::json::parse(expandedContent, nullptr, true /* allow_exceptions */, true /* ignore_comments */); } catch (nlohmann::json::exception const& e) { @@ -475,6 +473,8 @@ class Config final : public IEarlyConfig // Fill any values missing in config with defaults. // Fill default value if invalid type is provided. + // if the user provided a string but expected type is different + // attempt to parse string to the expected type. for (const auto& kv : Defaults) { auto itr = processed.find(kv.first); @@ -482,7 +482,67 @@ class Config final : public IEarlyConfig { if (itr->second.index() != kv.second.index()) { - itr->second = kv.second; + // check if we can convert from string + bool converted = false; + if (itr->second.index() == 1) // User value is String + { + const String& strVal = std::get(itr->second); + switch (kv.second.index()) + { + case 0: // Expected int + { + try + { + size_t pos = 0; + int intVal = std::stoi(strVal, &pos); + if (pos == strVal.length()) + { + itr->second = intVal; + converted = true; + } + } + catch (...) + { + } + break; + } + case 2: // Expected float + { + try + { + size_t pos = 0; + float floatVal = std::stof(strVal, &pos); + if (pos == strVal.length()) + { + itr->second = floatVal; + converted = true; + } + } + catch (...) + { + } + break; + } + case 4: // Expected bool + { + if (strVal == "true" || strVal == "1") + { + itr->second = true; + converted = true; + } + else if (strVal == "false" || strVal == "0") + { + itr->second = false; + converted = true; + } + break; + } + } + } + if (!converted) + { + itr->second = kv.second; + } } continue; }