diff options
Diffstat (limited to 'redfish-core/include/utils')
-rw-r--r-- | redfish-core/include/utils/json_utils.hpp | 124 |
1 files changed, 122 insertions, 2 deletions
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp index bde81ce72d..3263c739a8 100644 --- a/redfish-core/include/utils/json_utils.hpp +++ b/redfish-core/include/utils/json_utils.hpp @@ -14,11 +14,13 @@ // limitations under the License. */ #pragma once + #include <crow/http_request.h> #include <crow/http_response.h> +#include <bitset> +#include <error_messages.hpp> #include <nlohmann/json.hpp> - namespace redfish { @@ -296,7 +298,125 @@ Result getDouble(const char* fieldName, const nlohmann::json& json, */ bool processJsonFromRequest(crow::Response& res, const crow::Request& req, nlohmann::json& reqJson); +namespace details +{ +template <typename Type> struct unpackValue +{ + using isRequired = std::true_type; + using JsonType = std::add_const_t<std::add_pointer_t<Type>>; +}; -} // namespace json_util +template <typename OptionalType> +struct unpackValue<boost::optional<OptionalType>> +{ + using isRequired = std::false_type; + using JsonType = std::add_const_t<std::add_pointer_t<OptionalType>>; +}; + +template <size_t Count, size_t Index> +void readJsonValues(const std::string& key, nlohmann::json& jsonValue, + crow::Response& res, std::bitset<Count>& handled) +{ + BMCWEB_LOG_DEBUG << "Unable to find variable for key" << key; + messages::addMessageToErrorJson(res.jsonValue, + messages::propertyUnknown(key)); + res.result(boost::beast::http::status::bad_request); +} + +template <size_t Count, size_t Index, typename ValueType, + typename... UnpackTypes> +void readJsonValues(const std::string& key, nlohmann::json& jsonValue, + crow::Response& res, std::bitset<Count>& handled, + const char* keyToCheck, ValueType& valueToFill, + UnpackTypes&... in) +{ + if (key != keyToCheck) + { + readJsonValues<Count, Index + 1>(key, jsonValue, res, handled, in...); + return; + } + + handled.set(Index); + + using UnpackType = typename unpackValue<ValueType>::JsonType; + UnpackType value = jsonValue.get_ptr<UnpackType>(); + if (value == nullptr) + { + BMCWEB_LOG_DEBUG << "Value for key " << key + << " was incorrect type: " << jsonValue.type_name(); + messages::addMessageToErrorJson( + res.jsonValue, + messages::propertyValueTypeError(jsonValue.dump(), key)); + res.result(boost::beast::http::status::bad_request); + return; + } + + valueToFill = *value; +} + +template <size_t Index = 0, size_t Count> +void handleMissing(std::bitset<Count>& handled, crow::Response& res) +{ +} + +template <size_t Index = 0, size_t Count, typename ValueType, + typename... UnpackTypes> +void handleMissing(std::bitset<Count>& handled, crow::Response& res, + const char* key, ValueType& unused, UnpackTypes&... in) +{ + if (!handled.test(Index) && unpackValue<ValueType>::isRequired::value) + { + messages::addMessageToErrorJson(res.jsonValue, + messages::propertyMissing(key)); + res.result(boost::beast::http::status::bad_request); + } + details::handleMissing<Index + 1, Count>(handled, res, in...); +} +} // namespace details + +template <typename... UnpackTypes> +bool readJson(const crow::Request& req, crow::Response& res, const char* key, + UnpackTypes&... in) +{ + nlohmann::json jsonRequest; + if (!json_util::processJsonFromRequest(res, req, jsonRequest)) + { + BMCWEB_LOG_DEBUG << "Json value not readable"; + return false; + } + if (!jsonRequest.is_object()) + { + BMCWEB_LOG_DEBUG << "Json value is not an object"; + messages::addMessageToErrorJson(res.jsonValue, + messages::unrecognizedRequestBody()); + res.result(boost::beast::http::status::bad_request); + return false; + } + + if (jsonRequest.empty()) + { + BMCWEB_LOG_DEBUG << "Json value is empty"; + messages::addMessageToErrorJson(res.jsonValue, messages::emptyJSON()); + res.result(boost::beast::http::status::bad_request); + return false; + } + + std::bitset<(sizeof...(in) + 1) / 2> handled(0); + for (const auto& item : jsonRequest.items()) + { + details::readJsonValues<(sizeof...(in) + 1) / 2, 0, UnpackTypes...>( + item.key(), item.value(), res, handled, key, in...); + } + + if (!handled.all()) + { + details::handleMissing(handled, res, key, in...); + + return false; + } + return res.result() == boost::beast::http::status::ok; +} + +} // namespace json_util } // namespace redfish |