177dd8813SKowalski, Kamil /* 26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd 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 { 333*340d74c8SMyung Bae messages::propertyValueOutOfRange(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 { 349*340d74c8SMyung Bae messages::propertyValueOutOfRange(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 7414e196b9aSEd Tanous inline int objectKeyCmp(std::string_view key, const nlohmann::json& a, 7424e196b9aSEd Tanous const nlohmann::json& b) 743185444b1SNan Zhou { 744185444b1SNan Zhou using object_t = nlohmann::json::object_t; 745185444b1SNan Zhou const object_t* aObj = a.get_ptr<const object_t*>(); 746185444b1SNan Zhou const object_t* bObj = b.get_ptr<const object_t*>(); 747185444b1SNan Zhou 748185444b1SNan Zhou if (aObj == nullptr) 749185444b1SNan Zhou { 750185444b1SNan Zhou if (bObj == nullptr) 751185444b1SNan Zhou { 752185444b1SNan Zhou return 0; 753185444b1SNan Zhou } 754185444b1SNan Zhou return -1; 755185444b1SNan Zhou } 756185444b1SNan Zhou if (bObj == nullptr) 757185444b1SNan Zhou { 758185444b1SNan Zhou return 1; 759185444b1SNan Zhou } 7604e196b9aSEd Tanous object_t::const_iterator aIt = aObj->find(key); 7614e196b9aSEd Tanous object_t::const_iterator bIt = bObj->find(key); 7624e196b9aSEd Tanous // If either object doesn't have the key, they get "sorted" to the 7634e196b9aSEd Tanous // beginning. 764185444b1SNan Zhou if (aIt == aObj->end()) 765185444b1SNan Zhou { 766185444b1SNan Zhou if (bIt == bObj->end()) 767185444b1SNan Zhou { 768185444b1SNan Zhou return 0; 769185444b1SNan Zhou } 770185444b1SNan Zhou return -1; 771185444b1SNan Zhou } 772185444b1SNan Zhou if (bIt == bObj->end()) 773185444b1SNan Zhou { 774185444b1SNan Zhou return 1; 775185444b1SNan Zhou } 776185444b1SNan Zhou const nlohmann::json::string_t* nameA = 777185444b1SNan Zhou aIt->second.get_ptr<const std::string*>(); 778185444b1SNan Zhou const nlohmann::json::string_t* nameB = 779185444b1SNan Zhou bIt->second.get_ptr<const std::string*>(); 780185444b1SNan Zhou // If either object doesn't have a string as the key, they get "sorted" to 7814e196b9aSEd Tanous // the beginning. 782185444b1SNan Zhou if (nameA == nullptr) 783185444b1SNan Zhou { 784185444b1SNan Zhou if (nameB == nullptr) 785185444b1SNan Zhou { 786185444b1SNan Zhou return 0; 787185444b1SNan Zhou } 788185444b1SNan Zhou return -1; 789185444b1SNan Zhou } 790185444b1SNan Zhou if (nameB == nullptr) 791185444b1SNan Zhou { 792185444b1SNan Zhou return 1; 793185444b1SNan Zhou } 794185444b1SNan Zhou boost::urls::url_view aUrl(*nameA); 795185444b1SNan Zhou boost::urls::url_view bUrl(*nameB); 796185444b1SNan Zhou auto segmentsAIt = aUrl.segments().begin(); 797185444b1SNan Zhou auto segmentsBIt = bUrl.segments().begin(); 798185444b1SNan Zhou 799185444b1SNan Zhou while (true) 800185444b1SNan Zhou { 801185444b1SNan Zhou if (segmentsAIt == aUrl.segments().end()) 802185444b1SNan Zhou { 803185444b1SNan Zhou if (segmentsBIt == bUrl.segments().end()) 804185444b1SNan Zhou { 805185444b1SNan Zhou return 0; 806185444b1SNan Zhou } 807185444b1SNan Zhou return -1; 808185444b1SNan Zhou } 809185444b1SNan Zhou if (segmentsBIt == bUrl.segments().end()) 810185444b1SNan Zhou { 811185444b1SNan Zhou return 1; 812185444b1SNan Zhou } 813185444b1SNan Zhou int res = alphanumComp(*segmentsAIt, *segmentsBIt); 814185444b1SNan Zhou if (res != 0) 815185444b1SNan Zhou { 816185444b1SNan Zhou return res; 817185444b1SNan Zhou } 818185444b1SNan Zhou 819185444b1SNan Zhou segmentsAIt++; 820185444b1SNan Zhou segmentsBIt++; 821185444b1SNan Zhou } 822185444b1SNan Zhou }; 823185444b1SNan Zhou 8244e196b9aSEd Tanous // kept for backward compatibility 8254e196b9aSEd Tanous inline int odataObjectCmp(const nlohmann::json& left, 8264e196b9aSEd Tanous const nlohmann::json& right) 8274e196b9aSEd Tanous { 8284e196b9aSEd Tanous return objectKeyCmp("@odata.id", left, right); 8294e196b9aSEd Tanous } 8304e196b9aSEd Tanous 831185444b1SNan Zhou struct ODataObjectLess 832185444b1SNan Zhou { 8334e196b9aSEd Tanous std::string_view key; 8344e196b9aSEd Tanous 8354e196b9aSEd Tanous explicit ODataObjectLess(std::string_view keyIn) : key(keyIn) {} 8364e196b9aSEd Tanous 837185444b1SNan Zhou bool operator()(const nlohmann::json& left, 838185444b1SNan Zhou const nlohmann::json& right) const 839185444b1SNan Zhou { 8404e196b9aSEd Tanous return objectKeyCmp(key, left, right) < 0; 841185444b1SNan Zhou } 842185444b1SNan Zhou }; 843185444b1SNan Zhou 844185444b1SNan Zhou // Sort the JSON array by |element[key]|. 845185444b1SNan Zhou // Elements without |key| or type of |element[key]| is not string are smaller 846185444b1SNan Zhou // those whose |element[key]| is string. 8474e196b9aSEd Tanous inline void sortJsonArrayByKey(nlohmann::json::array_t& array, 8484e196b9aSEd Tanous std::string_view key) 8494e196b9aSEd Tanous { 8504e196b9aSEd Tanous std::ranges::sort(array, ODataObjectLess(key)); 8514e196b9aSEd Tanous } 8524e196b9aSEd Tanous 8534e196b9aSEd Tanous // Sort the JSON array by |element[key]|. 8544e196b9aSEd Tanous // Elements without |key| or type of |element[key]| is not string are smaller 8554e196b9aSEd Tanous // those whose |element[key]| is string. 856185444b1SNan Zhou inline void sortJsonArrayByOData(nlohmann::json::array_t& array) 857185444b1SNan Zhou { 8584e196b9aSEd Tanous std::ranges::sort(array, ODataObjectLess("@odata.id")); 859185444b1SNan Zhou } 860185444b1SNan Zhou 8618a7c4b47SNan Zhou // Returns the estimated size of the JSON value 8628a7c4b47SNan Zhou // The implementation walks through every key and every value, accumulates the 8638a7c4b47SNan Zhou // total size of keys and values. 8648a7c4b47SNan Zhou // Ideally, we should use a custom allocator that nlohmann JSON supports. 8658a7c4b47SNan Zhou 8668a7c4b47SNan Zhou // Assumption made: 8678a7c4b47SNan Zhou // 1. number: 8 characters 8688a7c4b47SNan Zhou // 2. boolean: 5 characters (False) 8698a7c4b47SNan Zhou // 3. string: len(str) + 2 characters (quote) 8708a7c4b47SNan Zhou // 4. bytes: len(bytes) characters 8718a7c4b47SNan Zhou // 5. null: 4 characters (null) 8728a7c4b47SNan Zhou uint64_t getEstimatedJsonSize(const nlohmann::json& root); 8738a7c4b47SNan Zhou 87477dd8813SKowalski, Kamil } // namespace json_util 87577dd8813SKowalski, Kamil } // namespace redfish 876