177dd8813SKowalski, Kamil /* 2*6be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 3*6be832e2SEd Tanous 4*6be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 5*6be832e2SEd Tanous you may not use this file except in compliance with the License. 6*6be832e2SEd Tanous You may obtain a copy of the License at 7*6be832e2SEd Tanous 8*6be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 9*6be832e2SEd Tanous 10*6be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 11*6be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 12*6be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6be832e2SEd Tanous See the License for the specific language governing permissions and 14*6be832e2SEd Tanous limitations under the License. 1577dd8813SKowalski, Kamil */ 1677dd8813SKowalski, Kamil #pragma once 179712f8acSEd Tanous 18d5c80ad9SNan Zhou #include "error_messages.hpp" 198a7c4b47SNan Zhou #include "http_connection.hpp" 20d5c80ad9SNan Zhou #include "http_request.hpp" 21d5c80ad9SNan Zhou #include "http_response.hpp" 22185444b1SNan Zhou #include "human_sort.hpp" 23d5c80ad9SNan Zhou #include "logging.hpp" 24faf100f9SEd Tanous 25faf100f9SEd Tanous #include <nlohmann/json.hpp> 260627a2c7SEd Tanous 27185444b1SNan Zhou #include <algorithm> 28d5c80ad9SNan Zhou #include <array> 29d5c80ad9SNan Zhou #include <cmath> 30d5c80ad9SNan Zhou #include <cstddef> 31d5c80ad9SNan Zhou #include <cstdint> 32d5c80ad9SNan Zhou #include <limits> 33d5c80ad9SNan Zhou #include <map> 34d5c80ad9SNan Zhou #include <optional> 353544d2a7SEd Tanous #include <ranges> 36ea2e6eecSWilly Tu #include <span> 37d5c80ad9SNan Zhou #include <string> 38d5c80ad9SNan Zhou #include <string_view> 39d5c80ad9SNan Zhou #include <type_traits> 40d5c80ad9SNan Zhou #include <utility> 41d5c80ad9SNan Zhou #include <variant> 42d5c80ad9SNan Zhou #include <vector> 43d5c80ad9SNan Zhou 441e75e1ddSNan Zhou // IWYU pragma: no_forward_declare crow::Request 451214b7e7SGunnar Mills 461abe55efSEd Tanous namespace redfish 471abe55efSEd Tanous { 481abe55efSEd Tanous 491abe55efSEd Tanous namespace json_util 501abe55efSEd Tanous { 5177dd8813SKowalski, Kamil 5277dd8813SKowalski, Kamil /** 5377dd8813SKowalski, Kamil * @brief Processes request to extract JSON from its body. If it fails, adds 5477dd8813SKowalski, Kamil * MalformedJSON message to response and ends it. 5577dd8813SKowalski, Kamil * 5677dd8813SKowalski, Kamil * @param[io] res Response object 5777dd8813SKowalski, Kamil * @param[in] req Request object 5877dd8813SKowalski, Kamil * @param[out] reqJson JSON object extracted from request's body 5977dd8813SKowalski, Kamil * 6077dd8813SKowalski, Kamil * @return true if JSON is valid, false when JSON is invalid and response has 6177dd8813SKowalski, Kamil * been filled with message and ended. 6277dd8813SKowalski, Kamil */ 6355c7b7a2SEd Tanous bool processJsonFromRequest(crow::Response& res, const crow::Request& req, 6477dd8813SKowalski, Kamil nlohmann::json& reqJson); 659712f8acSEd Tanous namespace details 669712f8acSEd Tanous { 67771cfa0fSJason M. Bills 681214b7e7SGunnar Mills template <typename Type> 692c70f800SEd Tanous struct IsOptional : std::false_type 701214b7e7SGunnar Mills {}; 719712f8acSEd Tanous 72771cfa0fSJason M. Bills template <typename Type> 732c70f800SEd Tanous struct IsOptional<std::optional<Type>> : std::true_type 741214b7e7SGunnar Mills {}; 759712f8acSEd Tanous 76771cfa0fSJason M. Bills template <typename Type> 772c70f800SEd Tanous struct IsVector : std::false_type 781214b7e7SGunnar Mills {}; 79b1556427SEd Tanous 801214b7e7SGunnar Mills template <typename Type> 812c70f800SEd Tanous struct IsVector<std::vector<Type>> : std::true_type 821214b7e7SGunnar Mills {}; 83b1556427SEd Tanous 841214b7e7SGunnar Mills template <typename Type> 852c70f800SEd Tanous struct IsStdArray : std::false_type 861214b7e7SGunnar Mills {}; 87318226c2SJames Feist 88318226c2SJames Feist template <typename Type, std::size_t size> 892c70f800SEd Tanous struct IsStdArray<std::array<Type, size>> : std::true_type 901214b7e7SGunnar Mills {}; 91318226c2SJames Feist 928099c517SEd Tanous template <typename Type> 938099c517SEd Tanous struct IsVariant : std::false_type 948099c517SEd Tanous {}; 958099c517SEd Tanous 968099c517SEd Tanous template <typename... Types> 978099c517SEd Tanous struct IsVariant<std::variant<Types...>> : std::true_type 988099c517SEd Tanous {}; 998099c517SEd Tanous 100471a5eb8SAppaRao Puli enum class UnpackErrorCode 101471a5eb8SAppaRao Puli { 102471a5eb8SAppaRao Puli success, 103471a5eb8SAppaRao Puli invalidType, 104471a5eb8SAppaRao Puli outOfRange 105471a5eb8SAppaRao Puli }; 106471a5eb8SAppaRao Puli 107a6acbb31SJames Feist template <typename ToType, typename FromType> 108c09966bdSEd Tanous bool checkRange(const FromType& from [[maybe_unused]], 109c09966bdSEd Tanous std::string_view key [[maybe_unused]]) 110a6acbb31SJames Feist { 111a6acbb31SJames Feist if constexpr (std::is_floating_point_v<ToType>) 112a6acbb31SJames Feist { 113ee344e0fSEd Tanous if (std::isnan(from)) 114a6acbb31SJames Feist { 11562598e31SEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was NAN", key); 116a6acbb31SJames Feist return false; 117a6acbb31SJames Feist } 118a6acbb31SJames Feist } 119c09966bdSEd Tanous if constexpr (std::numeric_limits<ToType>::max() < 120c09966bdSEd Tanous std::numeric_limits<FromType>::max()) 121c09966bdSEd Tanous { 122c09966bdSEd Tanous if (from > std::numeric_limits<ToType>::max()) 123c09966bdSEd Tanous { 124c09966bdSEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was greater than max {}", key, 125c09966bdSEd Tanous std::numeric_limits<FromType>::max()); 126c09966bdSEd Tanous return false; 127c09966bdSEd Tanous } 128c09966bdSEd Tanous } 129c09966bdSEd Tanous if constexpr (std::numeric_limits<ToType>::lowest() > 130c09966bdSEd Tanous std::numeric_limits<FromType>::lowest()) 131c09966bdSEd Tanous { 132c09966bdSEd Tanous if (from < std::numeric_limits<ToType>::lowest()) 133c09966bdSEd Tanous { 134c09966bdSEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was less than min {}", key, 135c09966bdSEd Tanous std::numeric_limits<FromType>::lowest()); 136c09966bdSEd Tanous return false; 137c09966bdSEd Tanous } 138c09966bdSEd Tanous } 139a6acbb31SJames Feist 140a6acbb31SJames Feist return true; 141a6acbb31SJames Feist } 142a6acbb31SJames Feist 143771cfa0fSJason M. Bills template <typename Type> 144471a5eb8SAppaRao Puli UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, 1458099c517SEd Tanous std::string_view key, Type& value); 1468099c517SEd Tanous 1478099c517SEd Tanous template <std::size_t Index = 0, typename... Args> 1488099c517SEd Tanous UnpackErrorCode unpackValueVariant(nlohmann::json& j, std::string_view key, 1498099c517SEd Tanous std::variant<Args...>& v) 1508099c517SEd Tanous { 1518099c517SEd Tanous if constexpr (Index < std::variant_size_v<std::variant<Args...>>) 1528099c517SEd Tanous { 153ed4de7a8SEd Tanous std::variant_alternative_t<Index, std::variant<Args...>> type{}; 1548099c517SEd Tanous UnpackErrorCode unpack = unpackValueWithErrorCode(j, key, type); 1558099c517SEd Tanous if (unpack == UnpackErrorCode::success) 1568099c517SEd Tanous { 1578099c517SEd Tanous v = std::move(type); 1588099c517SEd Tanous return unpack; 1598099c517SEd Tanous } 1608099c517SEd Tanous 1618099c517SEd Tanous return unpackValueVariant<Index + 1, Args...>(j, key, v); 1628099c517SEd Tanous } 1638099c517SEd Tanous return UnpackErrorCode::invalidType; 1648099c517SEd Tanous } 1658099c517SEd Tanous 1668099c517SEd Tanous template <typename Type> 1678099c517SEd Tanous UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, 168ea2e6eecSWilly Tu std::string_view key, Type& value) 169771cfa0fSJason M. Bills { 170471a5eb8SAppaRao Puli UnpackErrorCode ret = UnpackErrorCode::success; 17141352c24SSantosh Puranik 172a6acbb31SJames Feist if constexpr (std::is_floating_point_v<Type>) 173771cfa0fSJason M. Bills { 174a6acbb31SJames Feist double helper = 0; 175a6acbb31SJames Feist double* jsonPtr = jsonValue.get_ptr<double*>(); 176771cfa0fSJason M. Bills 177771cfa0fSJason M. Bills if (jsonPtr == nullptr) 178771cfa0fSJason M. Bills { 179a6acbb31SJames Feist int64_t* intPtr = jsonValue.get_ptr<int64_t*>(); 180a6acbb31SJames Feist if (intPtr != nullptr) 181771cfa0fSJason M. Bills { 182a6acbb31SJames Feist helper = static_cast<double>(*intPtr); 183a6acbb31SJames Feist jsonPtr = &helper; 184771cfa0fSJason M. Bills } 185a6acbb31SJames Feist } 1865eb2bef2SAppaRao Puli if (jsonPtr == nullptr) 1875eb2bef2SAppaRao Puli { 188471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 1895eb2bef2SAppaRao Puli } 190cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 191771cfa0fSJason M. Bills { 192471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 193771cfa0fSJason M. Bills } 194771cfa0fSJason M. Bills value = static_cast<Type>(*jsonPtr); 195771cfa0fSJason M. Bills } 196a6acbb31SJames Feist 197a6acbb31SJames Feist else if constexpr (std::is_signed_v<Type>) 198a6acbb31SJames Feist { 199a6acbb31SJames Feist int64_t* jsonPtr = jsonValue.get_ptr<int64_t*>(); 200271584abSEd Tanous if (jsonPtr == nullptr) 201271584abSEd Tanous { 202471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 203271584abSEd Tanous } 204cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 205a6acbb31SJames Feist { 206471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 207a6acbb31SJames Feist } 208a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 209a6acbb31SJames Feist } 210a6acbb31SJames Feist 211bd79bce8SPatrick Williams else if constexpr ((std::is_unsigned_v<Type>) && 212bd79bce8SPatrick Williams (!std::is_same_v<bool, Type>)) 213a6acbb31SJames Feist { 214a6acbb31SJames Feist uint64_t* jsonPtr = jsonValue.get_ptr<uint64_t*>(); 215271584abSEd Tanous if (jsonPtr == nullptr) 216271584abSEd Tanous { 217471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 218271584abSEd Tanous } 219cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 220a6acbb31SJames Feist { 221471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 222a6acbb31SJames Feist } 223a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 224a6acbb31SJames Feist } 225a6acbb31SJames Feist 2260627a2c7SEd Tanous else if constexpr (std::is_same_v<nlohmann::json, Type>) 2270627a2c7SEd Tanous { 2280627a2c7SEd Tanous value = std::move(jsonValue); 2290627a2c7SEd Tanous } 2308099c517SEd Tanous else if constexpr (std::is_same_v<std::nullptr_t, Type>) 2318099c517SEd Tanous { 2328099c517SEd Tanous if (!jsonValue.is_null()) 2338099c517SEd Tanous { 2348099c517SEd Tanous return UnpackErrorCode::invalidType; 2358099c517SEd Tanous } 2368099c517SEd Tanous } 237ed4de7a8SEd Tanous else if constexpr (IsVector<Type>::value) 238ed4de7a8SEd Tanous { 239ed4de7a8SEd Tanous nlohmann::json::object_t* obj = 240ed4de7a8SEd Tanous jsonValue.get_ptr<nlohmann::json::object_t*>(); 241ed4de7a8SEd Tanous if (obj == nullptr) 242ed4de7a8SEd Tanous { 243ed4de7a8SEd Tanous return UnpackErrorCode::invalidType; 244ed4de7a8SEd Tanous } 245ed4de7a8SEd Tanous 246ed4de7a8SEd Tanous for (const auto& val : *obj) 247ed4de7a8SEd Tanous { 248ed4de7a8SEd Tanous value.emplace_back(); 249ed4de7a8SEd Tanous ret = unpackValueWithErrorCode<typename Type::value_type>( 250ed4de7a8SEd Tanous val, key, value.back()) && 251ed4de7a8SEd Tanous ret; 252ed4de7a8SEd Tanous } 253ed4de7a8SEd Tanous } 254471a5eb8SAppaRao Puli else 255471a5eb8SAppaRao Puli { 256471a5eb8SAppaRao Puli using JsonType = std::add_const_t<std::add_pointer_t<Type>>; 257471a5eb8SAppaRao Puli JsonType jsonPtr = jsonValue.get_ptr<JsonType>(); 258471a5eb8SAppaRao Puli if (jsonPtr == nullptr) 259471a5eb8SAppaRao Puli { 26062598e31SEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was incorrect type: {}", key, 26162598e31SEd Tanous jsonValue.type_name()); 262471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 263471a5eb8SAppaRao Puli } 264471a5eb8SAppaRao Puli value = std::move(*jsonPtr); 265471a5eb8SAppaRao Puli } 266471a5eb8SAppaRao Puli return ret; 267471a5eb8SAppaRao Puli } 268471a5eb8SAppaRao Puli 269471a5eb8SAppaRao Puli template <typename Type> 270ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, 271471a5eb8SAppaRao Puli crow::Response& res, Type& value) 272471a5eb8SAppaRao Puli { 273471a5eb8SAppaRao Puli bool ret = true; 274471a5eb8SAppaRao Puli 2752c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 276471a5eb8SAppaRao Puli { 277471a5eb8SAppaRao Puli value.emplace(); 278471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, res, 279471a5eb8SAppaRao Puli *value) && 280471a5eb8SAppaRao Puli ret; 281471a5eb8SAppaRao Puli } 2822c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 283318226c2SJames Feist { 2840bdda665SEd Tanous nlohmann::json::array_t* arr = 2850bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 2860bdda665SEd Tanous if (arr == nullptr) 287318226c2SJames Feist { 2882e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 28941352c24SSantosh Puranik return false; 290318226c2SJames Feist } 291318226c2SJames Feist if (jsonValue.size() != value.size()) 292318226c2SJames Feist { 2932e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 29441352c24SSantosh Puranik return false; 295318226c2SJames Feist } 296318226c2SJames Feist size_t index = 0; 2970bdda665SEd Tanous for (auto& val : *arr) 298318226c2SJames Feist { 2990bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, res, 30041352c24SSantosh Puranik value[index++]) && 30141352c24SSantosh Puranik ret; 302318226c2SJames Feist } 303318226c2SJames Feist } 3042c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 305b1556427SEd Tanous { 3060bdda665SEd Tanous nlohmann::json::array_t* arr = 3070bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3080bdda665SEd Tanous if (arr == nullptr) 309b1556427SEd Tanous { 3102e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 31141352c24SSantosh Puranik return false; 312b1556427SEd Tanous } 313b1556427SEd Tanous 3140bdda665SEd Tanous for (auto& val : *arr) 315b1556427SEd Tanous { 316b1556427SEd Tanous value.emplace_back(); 3170bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, res, 31841352c24SSantosh Puranik value.back()) && 31941352c24SSantosh Puranik ret; 320b1556427SEd Tanous } 321b1556427SEd Tanous } 3228099c517SEd Tanous else if constexpr (IsVariant<Type>::value) 3238099c517SEd Tanous { 3248099c517SEd Tanous UnpackErrorCode ec = unpackValueVariant(jsonValue, key, value); 3258099c517SEd Tanous if (ec != UnpackErrorCode::success) 3268099c517SEd Tanous { 3278099c517SEd Tanous if (ec == UnpackErrorCode::invalidType) 3288099c517SEd Tanous { 3298099c517SEd Tanous messages::propertyValueTypeError(res, jsonValue, key); 3308099c517SEd Tanous } 3318099c517SEd Tanous else if (ec == UnpackErrorCode::outOfRange) 3328099c517SEd Tanous { 3338099c517SEd Tanous messages::propertyValueNotInList(res, jsonValue, key); 3348099c517SEd Tanous } 3358099c517SEd Tanous return false; 3368099c517SEd Tanous } 3378099c517SEd Tanous } 338771cfa0fSJason M. Bills else 339771cfa0fSJason M. Bills { 340471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 341471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 342771cfa0fSJason M. Bills { 343471a5eb8SAppaRao Puli if (ec == UnpackErrorCode::invalidType) 344471a5eb8SAppaRao Puli { 3452e8c4bdaSEd Tanous messages::propertyValueTypeError(res, jsonValue, key); 346471a5eb8SAppaRao Puli } 347471a5eb8SAppaRao Puli else if (ec == UnpackErrorCode::outOfRange) 348471a5eb8SAppaRao Puli { 349e2616cc5SEd Tanous messages::propertyValueNotInList(res, jsonValue, key); 350471a5eb8SAppaRao Puli } 35141352c24SSantosh Puranik return false; 352771cfa0fSJason M. Bills } 353771cfa0fSJason M. Bills } 354471a5eb8SAppaRao Puli 355471a5eb8SAppaRao Puli return ret; 356471a5eb8SAppaRao Puli } 357471a5eb8SAppaRao Puli 358471a5eb8SAppaRao Puli template <typename Type> 359ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, Type& value) 360471a5eb8SAppaRao Puli { 361471a5eb8SAppaRao Puli bool ret = true; 3622c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 363471a5eb8SAppaRao Puli { 364471a5eb8SAppaRao Puli value.emplace(); 365471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, *value) && 366471a5eb8SAppaRao Puli ret; 367471a5eb8SAppaRao Puli } 3682c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 369471a5eb8SAppaRao Puli { 3700bdda665SEd Tanous nlohmann::json::array_t* arr = 3710bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3720bdda665SEd Tanous if (arr == nullptr) 373471a5eb8SAppaRao Puli { 374471a5eb8SAppaRao Puli return false; 375471a5eb8SAppaRao Puli } 376471a5eb8SAppaRao Puli if (jsonValue.size() != value.size()) 377471a5eb8SAppaRao Puli { 378471a5eb8SAppaRao Puli return false; 379471a5eb8SAppaRao Puli } 380471a5eb8SAppaRao Puli size_t index = 0; 3810bdda665SEd Tanous for (const auto& val : *arr) 382471a5eb8SAppaRao Puli { 3830bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, 384471a5eb8SAppaRao Puli value[index++]) && 385471a5eb8SAppaRao Puli ret; 386471a5eb8SAppaRao Puli } 387471a5eb8SAppaRao Puli } 3882c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 389471a5eb8SAppaRao Puli { 3900bdda665SEd Tanous nlohmann::json::array_t* arr = 3910bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3920bdda665SEd Tanous if (arr == nullptr) 393471a5eb8SAppaRao Puli { 394471a5eb8SAppaRao Puli return false; 395471a5eb8SAppaRao Puli } 396471a5eb8SAppaRao Puli 3970bdda665SEd Tanous for (const auto& val : *arr) 398471a5eb8SAppaRao Puli { 399471a5eb8SAppaRao Puli value.emplace_back(); 4000bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, 401471a5eb8SAppaRao Puli value.back()) && 402471a5eb8SAppaRao Puli ret; 403471a5eb8SAppaRao Puli } 404471a5eb8SAppaRao Puli } 405471a5eb8SAppaRao Puli else 406471a5eb8SAppaRao Puli { 407471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 408471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 409471a5eb8SAppaRao Puli { 410471a5eb8SAppaRao Puli return false; 411471a5eb8SAppaRao Puli } 412471a5eb8SAppaRao Puli } 413471a5eb8SAppaRao Puli 41441352c24SSantosh Puranik return ret; 415771cfa0fSJason M. Bills } 4169712f8acSEd Tanous } // namespace details 4179712f8acSEd Tanous 418ea2e6eecSWilly Tu // clang-format off 419ea2e6eecSWilly Tu using UnpackVariant = std::variant< 420ea2e6eecSWilly Tu uint8_t*, 421ea2e6eecSWilly Tu uint16_t*, 422ea2e6eecSWilly Tu int16_t*, 423ea2e6eecSWilly Tu uint32_t*, 424ea2e6eecSWilly Tu int32_t*, 425ea2e6eecSWilly Tu uint64_t*, 426ea2e6eecSWilly Tu int64_t*, 427ea2e6eecSWilly Tu bool*, 428ea2e6eecSWilly Tu double*, 429ea2e6eecSWilly Tu std::string*, 430b6164cbeSEd Tanous nlohmann::json::object_t*, 4318099c517SEd Tanous std::variant<std::string, std::nullptr_t>*, 4328099c517SEd Tanous std::variant<uint8_t, std::nullptr_t>*, 4338099c517SEd Tanous std::variant<int16_t, std::nullptr_t>*, 4348099c517SEd Tanous std::variant<uint16_t, std::nullptr_t>*, 4358099c517SEd Tanous std::variant<int32_t, std::nullptr_t>*, 4368099c517SEd Tanous std::variant<uint32_t, std::nullptr_t>*, 4378099c517SEd Tanous std::variant<int64_t, std::nullptr_t>*, 4388099c517SEd Tanous std::variant<uint64_t, std::nullptr_t>*, 4398099c517SEd Tanous std::variant<double, std::nullptr_t>*, 4408099c517SEd Tanous std::variant<bool, std::nullptr_t>*, 441ea2e6eecSWilly Tu std::vector<uint8_t>*, 442ea2e6eecSWilly Tu std::vector<uint16_t>*, 443ea2e6eecSWilly Tu std::vector<int16_t>*, 444ea2e6eecSWilly Tu std::vector<uint32_t>*, 445ea2e6eecSWilly Tu std::vector<int32_t>*, 446ea2e6eecSWilly Tu std::vector<uint64_t>*, 447ea2e6eecSWilly Tu std::vector<int64_t>*, 448ea2e6eecSWilly Tu //std::vector<bool>*, 449ea2e6eecSWilly Tu std::vector<double>*, 450ea2e6eecSWilly Tu std::vector<std::string>*, 451b6164cbeSEd Tanous std::vector<nlohmann::json::object_t>*, 452ea2e6eecSWilly Tu std::optional<uint8_t>*, 453ea2e6eecSWilly Tu std::optional<uint16_t>*, 454ea2e6eecSWilly Tu std::optional<int16_t>*, 455ea2e6eecSWilly Tu std::optional<uint32_t>*, 456ea2e6eecSWilly Tu std::optional<int32_t>*, 457ea2e6eecSWilly Tu std::optional<uint64_t>*, 458ea2e6eecSWilly Tu std::optional<int64_t>*, 459ea2e6eecSWilly Tu std::optional<bool>*, 460ea2e6eecSWilly Tu std::optional<double>*, 461ea2e6eecSWilly Tu std::optional<std::string>*, 462b6164cbeSEd Tanous std::optional<nlohmann::json::object_t>*, 463ea2e6eecSWilly Tu std::optional<std::vector<uint8_t>>*, 464ea2e6eecSWilly Tu std::optional<std::vector<uint16_t>>*, 465ea2e6eecSWilly Tu std::optional<std::vector<int16_t>>*, 466ea2e6eecSWilly Tu std::optional<std::vector<uint32_t>>*, 467ea2e6eecSWilly Tu std::optional<std::vector<int32_t>>*, 468ea2e6eecSWilly Tu std::optional<std::vector<uint64_t>>*, 469ea2e6eecSWilly Tu std::optional<std::vector<int64_t>>*, 470ea2e6eecSWilly Tu //std::optional<std::vector<bool>>*, 471ea2e6eecSWilly Tu std::optional<std::vector<double>>*, 472ea2e6eecSWilly Tu std::optional<std::vector<std::string>>*, 4738099c517SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>*, 4748099c517SEd Tanous std::optional<std::variant<std::string, std::nullptr_t>>*, 4758099c517SEd Tanous std::optional<std::variant<uint8_t, std::nullptr_t>>*, 4768099c517SEd Tanous std::optional<std::variant<int16_t, std::nullptr_t>>*, 4778099c517SEd Tanous std::optional<std::variant<uint16_t, std::nullptr_t>>*, 4788099c517SEd Tanous std::optional<std::variant<int32_t, std::nullptr_t>>*, 4798099c517SEd Tanous std::optional<std::variant<uint32_t, std::nullptr_t>>*, 4808099c517SEd Tanous std::optional<std::variant<int64_t, std::nullptr_t>>*, 4818099c517SEd Tanous std::optional<std::variant<uint64_t, std::nullptr_t>>*, 4828099c517SEd Tanous std::optional<std::variant<double, std::nullptr_t>>*, 4838099c517SEd Tanous std::optional<std::variant<bool, std::nullptr_t>>*, 4848099c517SEd Tanous std::optional<std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>*, 485ed4de7a8SEd Tanous std::optional<std::vector<std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>>>*, 486ed4de7a8SEd Tanous 487ed4de7a8SEd Tanous // Note, these types are kept for historical completeness, but should not be used, 488ed4de7a8SEd Tanous // As they do not provide object type safety. Instead, rely on nlohmann::json::object_t 489ed4de7a8SEd Tanous // Will be removed Q2 2025 490ed4de7a8SEd Tanous nlohmann::json*, 491ed4de7a8SEd Tanous std::optional<std::vector<nlohmann::json>>*, 492ed4de7a8SEd Tanous std::vector<nlohmann::json>*, 493ed4de7a8SEd Tanous std::optional<nlohmann::json>* 494ea2e6eecSWilly Tu >; 495ea2e6eecSWilly Tu // clang-format on 496ea2e6eecSWilly Tu 497ea2e6eecSWilly Tu struct PerUnpack 498ea2e6eecSWilly Tu { 499ea2e6eecSWilly Tu std::string_view key; 500ea2e6eecSWilly Tu UnpackVariant value; 501ea2e6eecSWilly Tu bool complete = false; 502ea2e6eecSWilly Tu }; 503ea2e6eecSWilly Tu 504ea2e6eecSWilly Tu inline bool readJsonHelper(nlohmann::json& jsonRequest, crow::Response& res, 505b6164cbeSEd Tanous std::span<PerUnpack> toUnpack); 506b6164cbeSEd Tanous 507b6164cbeSEd Tanous inline bool readJsonHelperObject(nlohmann::json::object_t& obj, 508b6164cbeSEd Tanous crow::Response& res, 509ea2e6eecSWilly Tu std::span<PerUnpack> toUnpack) 5109712f8acSEd Tanous { 51141352c24SSantosh Puranik bool result = true; 512b6164cbeSEd Tanous for (auto& item : obj) 5139712f8acSEd Tanous { 514ea2e6eecSWilly Tu size_t unpackIndex = 0; 515ea2e6eecSWilly Tu for (; unpackIndex < toUnpack.size(); unpackIndex++) 516ea2e6eecSWilly Tu { 517ea2e6eecSWilly Tu PerUnpack& unpackSpec = toUnpack[unpackIndex]; 518ea2e6eecSWilly Tu std::string_view key = unpackSpec.key; 519ea2e6eecSWilly Tu size_t keysplitIndex = key.find('/'); 520ea2e6eecSWilly Tu std::string_view leftover; 521ea2e6eecSWilly Tu if (keysplitIndex != std::string_view::npos) 522ea2e6eecSWilly Tu { 523ea2e6eecSWilly Tu leftover = key.substr(keysplitIndex + 1); 524ea2e6eecSWilly Tu key = key.substr(0, keysplitIndex); 525ea2e6eecSWilly Tu } 526ea2e6eecSWilly Tu 527d91415c4SEd Tanous if (key != item.first || unpackSpec.complete) 528ea2e6eecSWilly Tu { 529ea2e6eecSWilly Tu continue; 530ea2e6eecSWilly Tu } 531ea2e6eecSWilly Tu 532ea2e6eecSWilly Tu // Sublevel key 533ea2e6eecSWilly Tu if (!leftover.empty()) 534ea2e6eecSWilly Tu { 535ea2e6eecSWilly Tu // Include the slash in the key so we can compare later 536ea2e6eecSWilly Tu key = unpackSpec.key.substr(0, keysplitIndex + 1); 537ea2e6eecSWilly Tu nlohmann::json j; 538d91415c4SEd Tanous result = details::unpackValue<nlohmann::json>(item.second, key, 539ea2e6eecSWilly Tu res, j) && 54041352c24SSantosh Puranik result; 54155f79e6fSEd Tanous if (!result) 542ea2e6eecSWilly Tu { 543ea2e6eecSWilly Tu return result; 5449712f8acSEd Tanous } 5459712f8acSEd Tanous 546ea2e6eecSWilly Tu std::vector<PerUnpack> nextLevel; 547ea2e6eecSWilly Tu for (PerUnpack& p : toUnpack) 548ea2e6eecSWilly Tu { 549ea2e6eecSWilly Tu if (!p.key.starts_with(key)) 550ea2e6eecSWilly Tu { 551ea2e6eecSWilly Tu continue; 552ea2e6eecSWilly Tu } 553ea2e6eecSWilly Tu std::string_view thisLeftover = p.key.substr(key.size()); 554ea2e6eecSWilly Tu nextLevel.push_back({thisLeftover, p.value, false}); 555ea2e6eecSWilly Tu p.complete = true; 5569712f8acSEd Tanous } 55777dd8813SKowalski, Kamil 558ea2e6eecSWilly Tu result = readJsonHelper(j, res, nextLevel) && result; 559ea2e6eecSWilly Tu break; 560ea2e6eecSWilly Tu } 561ea2e6eecSWilly Tu 562bd79bce8SPatrick Williams result = 563bd79bce8SPatrick Williams std::visit( 5645ea927bbSEd Tanous [&item, &unpackSpec, &res](auto& val) { 565ea2e6eecSWilly Tu using ContainedT = 566ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 567ea2e6eecSWilly Tu return details::unpackValue<ContainedT>( 568d91415c4SEd Tanous item.second, unpackSpec.key, res, *val); 569ea2e6eecSWilly Tu }, 570ea2e6eecSWilly Tu unpackSpec.value) && 571ea2e6eecSWilly Tu result; 572ea2e6eecSWilly Tu 573ea2e6eecSWilly Tu unpackSpec.complete = true; 574ea2e6eecSWilly Tu break; 575ea2e6eecSWilly Tu } 576ea2e6eecSWilly Tu 577ea2e6eecSWilly Tu if (unpackIndex == toUnpack.size()) 578ea2e6eecSWilly Tu { 579d91415c4SEd Tanous messages::propertyUnknown(res, item.first); 580ea2e6eecSWilly Tu result = false; 581ea2e6eecSWilly Tu } 582ea2e6eecSWilly Tu } 583ea2e6eecSWilly Tu 584ea2e6eecSWilly Tu for (PerUnpack& perUnpack : toUnpack) 585ea2e6eecSWilly Tu { 58655f79e6fSEd Tanous if (!perUnpack.complete) 587ea2e6eecSWilly Tu { 588ea2e6eecSWilly Tu bool isOptional = std::visit( 5895ea927bbSEd Tanous [](auto& val) { 590ea2e6eecSWilly Tu using ContainedType = 591ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 592ea2e6eecSWilly Tu return details::IsOptional<ContainedType>::value; 593ea2e6eecSWilly Tu }, 594ea2e6eecSWilly Tu perUnpack.value); 595ea2e6eecSWilly Tu if (isOptional) 596ea2e6eecSWilly Tu { 597ea2e6eecSWilly Tu continue; 598ea2e6eecSWilly Tu } 599ea2e6eecSWilly Tu messages::propertyMissing(res, perUnpack.key); 600ea2e6eecSWilly Tu result = false; 601ea2e6eecSWilly Tu } 602ea2e6eecSWilly Tu } 603ea2e6eecSWilly Tu return result; 604ea2e6eecSWilly Tu } 605ea2e6eecSWilly Tu 606b6164cbeSEd Tanous inline bool readJsonHelper(nlohmann::json& jsonRequest, crow::Response& res, 607b6164cbeSEd Tanous std::span<PerUnpack> toUnpack) 608b6164cbeSEd Tanous { 609b6164cbeSEd Tanous nlohmann::json::object_t* obj = 610b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 611b6164cbeSEd Tanous if (obj == nullptr) 612b6164cbeSEd Tanous { 613b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is not an object"); 614b6164cbeSEd Tanous messages::unrecognizedRequestBody(res); 615b6164cbeSEd Tanous return false; 616b6164cbeSEd Tanous } 617b6164cbeSEd Tanous return readJsonHelperObject(*obj, res, toUnpack); 618b6164cbeSEd Tanous } 619b6164cbeSEd Tanous 62089492a15SPatrick Williams inline void packVariant(std::span<PerUnpack> /*toPack*/) {} 621ea2e6eecSWilly Tu 622ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 623ea2e6eecSWilly Tu void packVariant(std::span<PerUnpack> toPack, std::string_view key, 6245ea927bbSEd Tanous FirstType&& first, UnpackTypes&&... in) 625ea2e6eecSWilly Tu { 626ea2e6eecSWilly Tu if (toPack.empty()) 627ea2e6eecSWilly Tu { 628ea2e6eecSWilly Tu return; 629ea2e6eecSWilly Tu } 630ea2e6eecSWilly Tu toPack[0].key = key; 631ea2e6eecSWilly Tu toPack[0].value = &first; 632ea2e6eecSWilly Tu // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) 633ea2e6eecSWilly Tu packVariant(toPack.subspan(1), std::forward<UnpackTypes&&>(in)...); 634ea2e6eecSWilly Tu } 635ea2e6eecSWilly Tu 636ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 637b6164cbeSEd Tanous bool readJsonObject(nlohmann::json::object_t& jsonRequest, crow::Response& res, 638b6164cbeSEd Tanous std::string_view key, FirstType&& first, 639b6164cbeSEd Tanous UnpackTypes&&... in) 640ea2e6eecSWilly Tu { 641ea2e6eecSWilly Tu const std::size_t n = sizeof...(UnpackTypes) + 2; 642ea2e6eecSWilly Tu std::array<PerUnpack, n / 2> toUnpack2; 6435ea927bbSEd Tanous packVariant(toUnpack2, key, std::forward<FirstType>(first), 6445ea927bbSEd Tanous std::forward<UnpackTypes&&>(in)...); 645b6164cbeSEd Tanous return readJsonHelperObject(jsonRequest, res, toUnpack2); 646ea2e6eecSWilly Tu } 647ea2e6eecSWilly Tu 648b6164cbeSEd Tanous template <typename FirstType, typename... UnpackTypes> 649b6164cbeSEd Tanous bool readJson(nlohmann::json& jsonRequest, crow::Response& res, 650b6164cbeSEd Tanous std::string_view key, FirstType&& first, UnpackTypes&&... in) 651b6164cbeSEd Tanous { 652b6164cbeSEd Tanous nlohmann::json::object_t* obj = 653b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 654b6164cbeSEd Tanous if (obj == nullptr) 655b6164cbeSEd Tanous { 656b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is not an object"); 657b6164cbeSEd Tanous messages::unrecognizedRequestBody(res); 658b6164cbeSEd Tanous return false; 659b6164cbeSEd Tanous } 6605be2b14aSEd Tanous return readJsonObject(*obj, res, key, std::forward<FirstType>(first), 6615be2b14aSEd Tanous std::forward<UnpackTypes&&>(in)...); 662b6164cbeSEd Tanous } 663b6164cbeSEd Tanous 664b6164cbeSEd Tanous inline std::optional<nlohmann::json::object_t> 665ea2e6eecSWilly Tu readJsonPatchHelper(const crow::Request& req, crow::Response& res) 6660627a2c7SEd Tanous { 6670627a2c7SEd Tanous nlohmann::json jsonRequest; 6680627a2c7SEd Tanous if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 6690627a2c7SEd Tanous { 67062598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value not readable"); 671ea2e6eecSWilly Tu return std::nullopt; 6720627a2c7SEd Tanous } 673357bb8f8SEd Tanous nlohmann::json::object_t* object = 674357bb8f8SEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 675357bb8f8SEd Tanous if (object == nullptr || object->empty()) 67615ed6780SWilly Tu { 67762598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value is empty"); 67815ed6780SWilly Tu messages::emptyJSON(res); 679ea2e6eecSWilly Tu return std::nullopt; 680ea2e6eecSWilly Tu } 681357bb8f8SEd Tanous std::erase_if(*object, 682357bb8f8SEd Tanous [](const std::pair<std::string, nlohmann::json>& item) { 683357bb8f8SEd Tanous return item.first.starts_with("@odata."); 684357bb8f8SEd Tanous }); 685357bb8f8SEd Tanous if (object->empty()) 686357bb8f8SEd Tanous { 687357bb8f8SEd Tanous // If the update request only contains OData annotations, the service 688357bb8f8SEd Tanous // should return the HTTP 400 Bad Request status code with the 689357bb8f8SEd Tanous // NoOperation message from the Base Message Registry, ... 690357bb8f8SEd Tanous messages::noOperation(res); 691357bb8f8SEd Tanous return std::nullopt; 692357bb8f8SEd Tanous } 693357bb8f8SEd Tanous 694b6164cbeSEd Tanous return {std::move(*object)}; 695ea2e6eecSWilly Tu } 696ea2e6eecSWilly Tu 697ea2e6eecSWilly Tu template <typename... UnpackTypes> 698ea2e6eecSWilly Tu bool readJsonPatch(const crow::Request& req, crow::Response& res, 699ea2e6eecSWilly Tu std::string_view key, UnpackTypes&&... in) 700ea2e6eecSWilly Tu { 70176b038f2SEd Tanous std::optional<nlohmann::json::object_t> jsonRequest = 70276b038f2SEd Tanous readJsonPatchHelper(req, res); 703e01d0c36SEd Tanous if (!jsonRequest) 704ea2e6eecSWilly Tu { 70515ed6780SWilly Tu return false; 70615ed6780SWilly Tu } 70776b038f2SEd Tanous if (jsonRequest->empty()) 708b6164cbeSEd Tanous { 709b6164cbeSEd Tanous messages::emptyJSON(res); 710b6164cbeSEd Tanous return false; 711b6164cbeSEd Tanous } 71215ed6780SWilly Tu 71376b038f2SEd Tanous return readJsonObject(*jsonRequest, res, key, 714b6164cbeSEd Tanous std::forward<UnpackTypes&&>(in)...); 71515ed6780SWilly Tu } 71615ed6780SWilly Tu 71715ed6780SWilly Tu template <typename... UnpackTypes> 71815ed6780SWilly Tu bool readJsonAction(const crow::Request& req, crow::Response& res, 719ea2e6eecSWilly Tu const char* key, UnpackTypes&&... in) 72015ed6780SWilly Tu { 72115ed6780SWilly Tu nlohmann::json jsonRequest; 72215ed6780SWilly Tu if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 72315ed6780SWilly Tu { 72462598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value not readable"); 72515ed6780SWilly Tu return false; 72615ed6780SWilly Tu } 727b6164cbeSEd Tanous nlohmann::json::object_t* object = 728b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 729b6164cbeSEd Tanous if (object == nullptr) 730b6164cbeSEd Tanous { 731b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is empty"); 732b6164cbeSEd Tanous messages::emptyJSON(res); 733b6164cbeSEd Tanous return false; 734b6164cbeSEd Tanous } 735b6164cbeSEd Tanous return readJsonObject(*object, res, key, 736b6164cbeSEd Tanous std::forward<UnpackTypes&&>(in)...); 7370627a2c7SEd Tanous } 738185444b1SNan Zhou 739185444b1SNan Zhou // Determines if two json objects are less, based on the presence of the 740185444b1SNan Zhou // @odata.id key 741185444b1SNan Zhou inline int odataObjectCmp(const nlohmann::json& a, const nlohmann::json& b) 742185444b1SNan Zhou { 743185444b1SNan Zhou using object_t = nlohmann::json::object_t; 744185444b1SNan Zhou const object_t* aObj = a.get_ptr<const object_t*>(); 745185444b1SNan Zhou const object_t* bObj = b.get_ptr<const object_t*>(); 746185444b1SNan Zhou 747185444b1SNan Zhou if (aObj == nullptr) 748185444b1SNan Zhou { 749185444b1SNan Zhou if (bObj == nullptr) 750185444b1SNan Zhou { 751185444b1SNan Zhou return 0; 752185444b1SNan Zhou } 753185444b1SNan Zhou return -1; 754185444b1SNan Zhou } 755185444b1SNan Zhou if (bObj == nullptr) 756185444b1SNan Zhou { 757185444b1SNan Zhou return 1; 758185444b1SNan Zhou } 759185444b1SNan Zhou object_t::const_iterator aIt = aObj->find("@odata.id"); 760185444b1SNan Zhou object_t::const_iterator bIt = bObj->find("@odata.id"); 761185444b1SNan Zhou // If either object doesn't have the key, they get "sorted" to the end. 762185444b1SNan Zhou if (aIt == aObj->end()) 763185444b1SNan Zhou { 764185444b1SNan Zhou if (bIt == bObj->end()) 765185444b1SNan Zhou { 766185444b1SNan Zhou return 0; 767185444b1SNan Zhou } 768185444b1SNan Zhou return -1; 769185444b1SNan Zhou } 770185444b1SNan Zhou if (bIt == bObj->end()) 771185444b1SNan Zhou { 772185444b1SNan Zhou return 1; 773185444b1SNan Zhou } 774185444b1SNan Zhou const nlohmann::json::string_t* nameA = 775185444b1SNan Zhou aIt->second.get_ptr<const std::string*>(); 776185444b1SNan Zhou const nlohmann::json::string_t* nameB = 777185444b1SNan Zhou bIt->second.get_ptr<const std::string*>(); 778185444b1SNan Zhou // If either object doesn't have a string as the key, they get "sorted" to 779185444b1SNan Zhou // the end. 780185444b1SNan Zhou if (nameA == nullptr) 781185444b1SNan Zhou { 782185444b1SNan Zhou if (nameB == nullptr) 783185444b1SNan Zhou { 784185444b1SNan Zhou return 0; 785185444b1SNan Zhou } 786185444b1SNan Zhou return -1; 787185444b1SNan Zhou } 788185444b1SNan Zhou if (nameB == nullptr) 789185444b1SNan Zhou { 790185444b1SNan Zhou return 1; 791185444b1SNan Zhou } 792185444b1SNan Zhou boost::urls::url_view aUrl(*nameA); 793185444b1SNan Zhou boost::urls::url_view bUrl(*nameB); 794185444b1SNan Zhou auto segmentsAIt = aUrl.segments().begin(); 795185444b1SNan Zhou auto segmentsBIt = bUrl.segments().begin(); 796185444b1SNan Zhou 797185444b1SNan Zhou while (true) 798185444b1SNan Zhou { 799185444b1SNan Zhou if (segmentsAIt == aUrl.segments().end()) 800185444b1SNan Zhou { 801185444b1SNan Zhou if (segmentsBIt == bUrl.segments().end()) 802185444b1SNan Zhou { 803185444b1SNan Zhou return 0; 804185444b1SNan Zhou } 805185444b1SNan Zhou return -1; 806185444b1SNan Zhou } 807185444b1SNan Zhou if (segmentsBIt == bUrl.segments().end()) 808185444b1SNan Zhou { 809185444b1SNan Zhou return 1; 810185444b1SNan Zhou } 811185444b1SNan Zhou int res = alphanumComp(*segmentsAIt, *segmentsBIt); 812185444b1SNan Zhou if (res != 0) 813185444b1SNan Zhou { 814185444b1SNan Zhou return res; 815185444b1SNan Zhou } 816185444b1SNan Zhou 817185444b1SNan Zhou segmentsAIt++; 818185444b1SNan Zhou segmentsBIt++; 819185444b1SNan Zhou } 820185444b1SNan Zhou }; 821185444b1SNan Zhou 822185444b1SNan Zhou struct ODataObjectLess 823185444b1SNan Zhou { 824185444b1SNan Zhou bool operator()(const nlohmann::json& left, 825185444b1SNan Zhou const nlohmann::json& right) const 826185444b1SNan Zhou { 827185444b1SNan Zhou return odataObjectCmp(left, right) < 0; 828185444b1SNan Zhou } 829185444b1SNan Zhou }; 830185444b1SNan Zhou 831185444b1SNan Zhou // Sort the JSON array by |element[key]|. 832185444b1SNan Zhou // Elements without |key| or type of |element[key]| is not string are smaller 833185444b1SNan Zhou // those whose |element[key]| is string. 834185444b1SNan Zhou inline void sortJsonArrayByOData(nlohmann::json::array_t& array) 835185444b1SNan Zhou { 8363544d2a7SEd Tanous std::ranges::sort(array, ODataObjectLess()); 837185444b1SNan Zhou } 838185444b1SNan Zhou 8398a7c4b47SNan Zhou // Returns the estimated size of the JSON value 8408a7c4b47SNan Zhou // The implementation walks through every key and every value, accumulates the 8418a7c4b47SNan Zhou // total size of keys and values. 8428a7c4b47SNan Zhou // Ideally, we should use a custom allocator that nlohmann JSON supports. 8438a7c4b47SNan Zhou 8448a7c4b47SNan Zhou // Assumption made: 8458a7c4b47SNan Zhou // 1. number: 8 characters 8468a7c4b47SNan Zhou // 2. boolean: 5 characters (False) 8478a7c4b47SNan Zhou // 3. string: len(str) + 2 characters (quote) 8488a7c4b47SNan Zhou // 4. bytes: len(bytes) characters 8498a7c4b47SNan Zhou // 5. null: 4 characters (null) 8508a7c4b47SNan Zhou uint64_t getEstimatedJsonSize(const nlohmann::json& root); 8518a7c4b47SNan Zhou 85277dd8813SKowalski, Kamil } // namespace json_util 85377dd8813SKowalski, Kamil } // namespace redfish 854