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 25*e7bcf475SJayanth Othayoth #include <boost/system/result.hpp> 26*e7bcf475SJayanth Othayoth #include <boost/url/parse.hpp> 27*e7bcf475SJayanth Othayoth #include <boost/url/url_view.hpp> 28faf100f9SEd Tanous #include <nlohmann/json.hpp> 290627a2c7SEd Tanous 30185444b1SNan Zhou #include <algorithm> 31d5c80ad9SNan Zhou #include <array> 32d5c80ad9SNan Zhou #include <cmath> 33d5c80ad9SNan Zhou #include <cstddef> 34d5c80ad9SNan Zhou #include <cstdint> 35d5c80ad9SNan Zhou #include <limits> 36d5c80ad9SNan Zhou #include <map> 37d5c80ad9SNan Zhou #include <optional> 383544d2a7SEd Tanous #include <ranges> 39ea2e6eecSWilly Tu #include <span> 40d5c80ad9SNan Zhou #include <string> 41d5c80ad9SNan Zhou #include <string_view> 42d5c80ad9SNan Zhou #include <type_traits> 43d5c80ad9SNan Zhou #include <utility> 44d5c80ad9SNan Zhou #include <variant> 45d5c80ad9SNan Zhou #include <vector> 46d5c80ad9SNan Zhou 471e75e1ddSNan Zhou // IWYU pragma: no_forward_declare crow::Request 481214b7e7SGunnar Mills 491abe55efSEd Tanous namespace redfish 501abe55efSEd Tanous { 511abe55efSEd Tanous 521abe55efSEd Tanous namespace json_util 531abe55efSEd Tanous { 5477dd8813SKowalski, Kamil 5577dd8813SKowalski, Kamil /** 5677dd8813SKowalski, Kamil * @brief Processes request to extract JSON from its body. If it fails, adds 5777dd8813SKowalski, Kamil * MalformedJSON message to response and ends it. 5877dd8813SKowalski, Kamil * 5977dd8813SKowalski, Kamil * @param[io] res Response object 6077dd8813SKowalski, Kamil * @param[in] req Request object 6177dd8813SKowalski, Kamil * @param[out] reqJson JSON object extracted from request's body 6277dd8813SKowalski, Kamil * 6377dd8813SKowalski, Kamil * @return true if JSON is valid, false when JSON is invalid and response has 6477dd8813SKowalski, Kamil * been filled with message and ended. 6577dd8813SKowalski, Kamil */ 6655c7b7a2SEd Tanous bool processJsonFromRequest(crow::Response& res, const crow::Request& req, 6777dd8813SKowalski, Kamil nlohmann::json& reqJson); 689712f8acSEd Tanous namespace details 699712f8acSEd Tanous { 70771cfa0fSJason M. Bills 711214b7e7SGunnar Mills template <typename Type> 722c70f800SEd Tanous struct IsOptional : std::false_type 731214b7e7SGunnar Mills {}; 749712f8acSEd Tanous 75771cfa0fSJason M. Bills template <typename Type> 762c70f800SEd Tanous struct IsOptional<std::optional<Type>> : std::true_type 771214b7e7SGunnar Mills {}; 789712f8acSEd Tanous 79771cfa0fSJason M. Bills template <typename Type> 802c70f800SEd Tanous struct IsVector : std::false_type 811214b7e7SGunnar Mills {}; 82b1556427SEd Tanous 831214b7e7SGunnar Mills template <typename Type> 842c70f800SEd Tanous struct IsVector<std::vector<Type>> : std::true_type 851214b7e7SGunnar Mills {}; 86b1556427SEd Tanous 871214b7e7SGunnar Mills template <typename Type> 882c70f800SEd Tanous struct IsStdArray : std::false_type 891214b7e7SGunnar Mills {}; 90318226c2SJames Feist 91318226c2SJames Feist template <typename Type, std::size_t size> 922c70f800SEd Tanous struct IsStdArray<std::array<Type, size>> : std::true_type 931214b7e7SGunnar Mills {}; 94318226c2SJames Feist 958099c517SEd Tanous template <typename Type> 968099c517SEd Tanous struct IsVariant : std::false_type 978099c517SEd Tanous {}; 988099c517SEd Tanous 998099c517SEd Tanous template <typename... Types> 1008099c517SEd Tanous struct IsVariant<std::variant<Types...>> : std::true_type 1018099c517SEd Tanous {}; 1028099c517SEd Tanous 103471a5eb8SAppaRao Puli enum class UnpackErrorCode 104471a5eb8SAppaRao Puli { 105471a5eb8SAppaRao Puli success, 106471a5eb8SAppaRao Puli invalidType, 107471a5eb8SAppaRao Puli outOfRange 108471a5eb8SAppaRao Puli }; 109471a5eb8SAppaRao Puli 110a6acbb31SJames Feist template <typename ToType, typename FromType> 111c09966bdSEd Tanous bool checkRange(const FromType& from [[maybe_unused]], 112c09966bdSEd Tanous std::string_view key [[maybe_unused]]) 113a6acbb31SJames Feist { 114a6acbb31SJames Feist if constexpr (std::is_floating_point_v<ToType>) 115a6acbb31SJames Feist { 116ee344e0fSEd Tanous if (std::isnan(from)) 117a6acbb31SJames Feist { 11862598e31SEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was NAN", key); 119a6acbb31SJames Feist return false; 120a6acbb31SJames Feist } 121a6acbb31SJames Feist } 122c09966bdSEd Tanous if constexpr (std::numeric_limits<ToType>::max() < 123c09966bdSEd Tanous std::numeric_limits<FromType>::max()) 124c09966bdSEd Tanous { 125c09966bdSEd Tanous if (from > std::numeric_limits<ToType>::max()) 126c09966bdSEd Tanous { 127c09966bdSEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was greater than max {}", key, 128c09966bdSEd Tanous std::numeric_limits<FromType>::max()); 129c09966bdSEd Tanous return false; 130c09966bdSEd Tanous } 131c09966bdSEd Tanous } 132c09966bdSEd Tanous if constexpr (std::numeric_limits<ToType>::lowest() > 133c09966bdSEd Tanous std::numeric_limits<FromType>::lowest()) 134c09966bdSEd Tanous { 135c09966bdSEd Tanous if (from < std::numeric_limits<ToType>::lowest()) 136c09966bdSEd Tanous { 137c09966bdSEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was less than min {}", key, 138c09966bdSEd Tanous std::numeric_limits<FromType>::lowest()); 139c09966bdSEd Tanous return false; 140c09966bdSEd Tanous } 141c09966bdSEd Tanous } 142a6acbb31SJames Feist 143a6acbb31SJames Feist return true; 144a6acbb31SJames Feist } 145a6acbb31SJames Feist 146771cfa0fSJason M. Bills template <typename Type> 147471a5eb8SAppaRao Puli UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, 1488099c517SEd Tanous std::string_view key, Type& value); 1498099c517SEd Tanous 1508099c517SEd Tanous template <std::size_t Index = 0, typename... Args> 1518099c517SEd Tanous UnpackErrorCode unpackValueVariant(nlohmann::json& j, std::string_view key, 1528099c517SEd Tanous std::variant<Args...>& v) 1538099c517SEd Tanous { 1548099c517SEd Tanous if constexpr (Index < std::variant_size_v<std::variant<Args...>>) 1558099c517SEd Tanous { 156ed4de7a8SEd Tanous std::variant_alternative_t<Index, std::variant<Args...>> type{}; 1578099c517SEd Tanous UnpackErrorCode unpack = unpackValueWithErrorCode(j, key, type); 1588099c517SEd Tanous if (unpack == UnpackErrorCode::success) 1598099c517SEd Tanous { 1608099c517SEd Tanous v = std::move(type); 1618099c517SEd Tanous return unpack; 1628099c517SEd Tanous } 1638099c517SEd Tanous 1648099c517SEd Tanous return unpackValueVariant<Index + 1, Args...>(j, key, v); 1658099c517SEd Tanous } 1668099c517SEd Tanous return UnpackErrorCode::invalidType; 1678099c517SEd Tanous } 1688099c517SEd Tanous 1698099c517SEd Tanous template <typename Type> 1708099c517SEd Tanous UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, 171ea2e6eecSWilly Tu std::string_view key, Type& value) 172771cfa0fSJason M. Bills { 173471a5eb8SAppaRao Puli UnpackErrorCode ret = UnpackErrorCode::success; 17441352c24SSantosh Puranik 175a6acbb31SJames Feist if constexpr (std::is_floating_point_v<Type>) 176771cfa0fSJason M. Bills { 177a6acbb31SJames Feist double helper = 0; 178a6acbb31SJames Feist double* jsonPtr = jsonValue.get_ptr<double*>(); 179771cfa0fSJason M. Bills 180771cfa0fSJason M. Bills if (jsonPtr == nullptr) 181771cfa0fSJason M. Bills { 182a6acbb31SJames Feist int64_t* intPtr = jsonValue.get_ptr<int64_t*>(); 183a6acbb31SJames Feist if (intPtr != nullptr) 184771cfa0fSJason M. Bills { 185a6acbb31SJames Feist helper = static_cast<double>(*intPtr); 186a6acbb31SJames Feist jsonPtr = &helper; 187771cfa0fSJason M. Bills } 188a6acbb31SJames Feist } 1895eb2bef2SAppaRao Puli if (jsonPtr == nullptr) 1905eb2bef2SAppaRao Puli { 191471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 1925eb2bef2SAppaRao Puli } 193cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 194771cfa0fSJason M. Bills { 195471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 196771cfa0fSJason M. Bills } 197771cfa0fSJason M. Bills value = static_cast<Type>(*jsonPtr); 198771cfa0fSJason M. Bills } 199a6acbb31SJames Feist 200a6acbb31SJames Feist else if constexpr (std::is_signed_v<Type>) 201a6acbb31SJames Feist { 202a6acbb31SJames Feist int64_t* jsonPtr = jsonValue.get_ptr<int64_t*>(); 203271584abSEd Tanous if (jsonPtr == nullptr) 204271584abSEd Tanous { 205471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 206271584abSEd Tanous } 207cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 208a6acbb31SJames Feist { 209471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 210a6acbb31SJames Feist } 211a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 212a6acbb31SJames Feist } 213a6acbb31SJames Feist 214bd79bce8SPatrick Williams else if constexpr ((std::is_unsigned_v<Type>) && 215bd79bce8SPatrick Williams (!std::is_same_v<bool, Type>)) 216a6acbb31SJames Feist { 217a6acbb31SJames Feist uint64_t* jsonPtr = jsonValue.get_ptr<uint64_t*>(); 218271584abSEd Tanous if (jsonPtr == nullptr) 219271584abSEd Tanous { 220471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 221271584abSEd Tanous } 222cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 223a6acbb31SJames Feist { 224471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 225a6acbb31SJames Feist } 226a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 227a6acbb31SJames Feist } 228a6acbb31SJames Feist 2290627a2c7SEd Tanous else if constexpr (std::is_same_v<nlohmann::json, Type>) 2300627a2c7SEd Tanous { 2310627a2c7SEd Tanous value = std::move(jsonValue); 2320627a2c7SEd Tanous } 2338099c517SEd Tanous else if constexpr (std::is_same_v<std::nullptr_t, Type>) 2348099c517SEd Tanous { 2358099c517SEd Tanous if (!jsonValue.is_null()) 2368099c517SEd Tanous { 2378099c517SEd Tanous return UnpackErrorCode::invalidType; 2388099c517SEd Tanous } 2398099c517SEd Tanous } 240ed4de7a8SEd Tanous else if constexpr (IsVector<Type>::value) 241ed4de7a8SEd Tanous { 242ed4de7a8SEd Tanous nlohmann::json::object_t* obj = 243ed4de7a8SEd Tanous jsonValue.get_ptr<nlohmann::json::object_t*>(); 244ed4de7a8SEd Tanous if (obj == nullptr) 245ed4de7a8SEd Tanous { 246ed4de7a8SEd Tanous return UnpackErrorCode::invalidType; 247ed4de7a8SEd Tanous } 248ed4de7a8SEd Tanous 249ed4de7a8SEd Tanous for (const auto& val : *obj) 250ed4de7a8SEd Tanous { 251ed4de7a8SEd Tanous value.emplace_back(); 252ed4de7a8SEd Tanous ret = unpackValueWithErrorCode<typename Type::value_type>( 253ed4de7a8SEd Tanous val, key, value.back()) && 254ed4de7a8SEd Tanous ret; 255ed4de7a8SEd Tanous } 256ed4de7a8SEd Tanous } 257471a5eb8SAppaRao Puli else 258471a5eb8SAppaRao Puli { 259471a5eb8SAppaRao Puli using JsonType = std::add_const_t<std::add_pointer_t<Type>>; 260471a5eb8SAppaRao Puli JsonType jsonPtr = jsonValue.get_ptr<JsonType>(); 261471a5eb8SAppaRao Puli if (jsonPtr == nullptr) 262471a5eb8SAppaRao Puli { 26362598e31SEd Tanous BMCWEB_LOG_DEBUG("Value for key {} was incorrect type: {}", key, 26462598e31SEd Tanous jsonValue.type_name()); 265471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 266471a5eb8SAppaRao Puli } 267471a5eb8SAppaRao Puli value = std::move(*jsonPtr); 268471a5eb8SAppaRao Puli } 269471a5eb8SAppaRao Puli return ret; 270471a5eb8SAppaRao Puli } 271471a5eb8SAppaRao Puli 272471a5eb8SAppaRao Puli template <typename Type> 273ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, 274471a5eb8SAppaRao Puli crow::Response& res, Type& value) 275471a5eb8SAppaRao Puli { 276471a5eb8SAppaRao Puli bool ret = true; 277471a5eb8SAppaRao Puli 2782c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 279471a5eb8SAppaRao Puli { 280471a5eb8SAppaRao Puli value.emplace(); 281471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, res, 282471a5eb8SAppaRao Puli *value) && 283471a5eb8SAppaRao Puli ret; 284471a5eb8SAppaRao Puli } 2852c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 286318226c2SJames Feist { 2870bdda665SEd Tanous nlohmann::json::array_t* arr = 2880bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 2890bdda665SEd Tanous if (arr == nullptr) 290318226c2SJames Feist { 2912e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 29241352c24SSantosh Puranik return false; 293318226c2SJames Feist } 294318226c2SJames Feist if (jsonValue.size() != value.size()) 295318226c2SJames Feist { 2962e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 29741352c24SSantosh Puranik return false; 298318226c2SJames Feist } 299318226c2SJames Feist size_t index = 0; 3000bdda665SEd Tanous for (auto& val : *arr) 301318226c2SJames Feist { 3020bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, res, 30341352c24SSantosh Puranik value[index++]) && 30441352c24SSantosh Puranik ret; 305318226c2SJames Feist } 306318226c2SJames Feist } 3072c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 308b1556427SEd Tanous { 3090bdda665SEd Tanous nlohmann::json::array_t* arr = 3100bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3110bdda665SEd Tanous if (arr == nullptr) 312b1556427SEd Tanous { 3132e8c4bdaSEd Tanous messages::propertyValueTypeError(res, res.jsonValue, key); 31441352c24SSantosh Puranik return false; 315b1556427SEd Tanous } 316b1556427SEd Tanous 3170bdda665SEd Tanous for (auto& val : *arr) 318b1556427SEd Tanous { 319b1556427SEd Tanous value.emplace_back(); 3200bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, res, 32141352c24SSantosh Puranik value.back()) && 32241352c24SSantosh Puranik ret; 323b1556427SEd Tanous } 324b1556427SEd Tanous } 3258099c517SEd Tanous else if constexpr (IsVariant<Type>::value) 3268099c517SEd Tanous { 3278099c517SEd Tanous UnpackErrorCode ec = unpackValueVariant(jsonValue, key, value); 3288099c517SEd Tanous if (ec != UnpackErrorCode::success) 3298099c517SEd Tanous { 3308099c517SEd Tanous if (ec == UnpackErrorCode::invalidType) 3318099c517SEd Tanous { 3328099c517SEd Tanous messages::propertyValueTypeError(res, jsonValue, key); 3338099c517SEd Tanous } 3348099c517SEd Tanous else if (ec == UnpackErrorCode::outOfRange) 3358099c517SEd Tanous { 336340d74c8SMyung Bae messages::propertyValueOutOfRange(res, jsonValue, key); 3378099c517SEd Tanous } 3388099c517SEd Tanous return false; 3398099c517SEd Tanous } 3408099c517SEd Tanous } 341771cfa0fSJason M. Bills else 342771cfa0fSJason M. Bills { 343471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 344471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 345771cfa0fSJason M. Bills { 346471a5eb8SAppaRao Puli if (ec == UnpackErrorCode::invalidType) 347471a5eb8SAppaRao Puli { 3482e8c4bdaSEd Tanous messages::propertyValueTypeError(res, jsonValue, key); 349471a5eb8SAppaRao Puli } 350471a5eb8SAppaRao Puli else if (ec == UnpackErrorCode::outOfRange) 351471a5eb8SAppaRao Puli { 352340d74c8SMyung Bae messages::propertyValueOutOfRange(res, jsonValue, key); 353471a5eb8SAppaRao Puli } 35441352c24SSantosh Puranik return false; 355771cfa0fSJason M. Bills } 356771cfa0fSJason M. Bills } 357471a5eb8SAppaRao Puli 358471a5eb8SAppaRao Puli return ret; 359471a5eb8SAppaRao Puli } 360471a5eb8SAppaRao Puli 361471a5eb8SAppaRao Puli template <typename Type> 362ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, Type& value) 363471a5eb8SAppaRao Puli { 364471a5eb8SAppaRao Puli bool ret = true; 3652c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 366471a5eb8SAppaRao Puli { 367471a5eb8SAppaRao Puli value.emplace(); 368471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, *value) && 369471a5eb8SAppaRao Puli ret; 370471a5eb8SAppaRao Puli } 3712c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 372471a5eb8SAppaRao Puli { 3730bdda665SEd Tanous nlohmann::json::array_t* arr = 3740bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3750bdda665SEd Tanous if (arr == nullptr) 376471a5eb8SAppaRao Puli { 377471a5eb8SAppaRao Puli return false; 378471a5eb8SAppaRao Puli } 379471a5eb8SAppaRao Puli if (jsonValue.size() != value.size()) 380471a5eb8SAppaRao Puli { 381471a5eb8SAppaRao Puli return false; 382471a5eb8SAppaRao Puli } 383471a5eb8SAppaRao Puli size_t index = 0; 3840bdda665SEd Tanous for (const auto& val : *arr) 385471a5eb8SAppaRao Puli { 3860bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, 387471a5eb8SAppaRao Puli value[index++]) && 388471a5eb8SAppaRao Puli ret; 389471a5eb8SAppaRao Puli } 390471a5eb8SAppaRao Puli } 3912c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 392471a5eb8SAppaRao Puli { 3930bdda665SEd Tanous nlohmann::json::array_t* arr = 3940bdda665SEd Tanous jsonValue.get_ptr<nlohmann::json::array_t*>(); 3950bdda665SEd Tanous if (arr == nullptr) 396471a5eb8SAppaRao Puli { 397471a5eb8SAppaRao Puli return false; 398471a5eb8SAppaRao Puli } 399471a5eb8SAppaRao Puli 4000bdda665SEd Tanous for (const auto& val : *arr) 401471a5eb8SAppaRao Puli { 402471a5eb8SAppaRao Puli value.emplace_back(); 4030bdda665SEd Tanous ret = unpackValue<typename Type::value_type>(val, key, 404471a5eb8SAppaRao Puli value.back()) && 405471a5eb8SAppaRao Puli ret; 406471a5eb8SAppaRao Puli } 407471a5eb8SAppaRao Puli } 408471a5eb8SAppaRao Puli else 409471a5eb8SAppaRao Puli { 410471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 411471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 412471a5eb8SAppaRao Puli { 413471a5eb8SAppaRao Puli return false; 414471a5eb8SAppaRao Puli } 415471a5eb8SAppaRao Puli } 416471a5eb8SAppaRao Puli 41741352c24SSantosh Puranik return ret; 418771cfa0fSJason M. Bills } 4199712f8acSEd Tanous } // namespace details 4209712f8acSEd Tanous 421ea2e6eecSWilly Tu // clang-format off 422ea2e6eecSWilly Tu using UnpackVariant = std::variant< 423ea2e6eecSWilly Tu uint8_t*, 424ea2e6eecSWilly Tu uint16_t*, 425ea2e6eecSWilly Tu int16_t*, 426ea2e6eecSWilly Tu uint32_t*, 427ea2e6eecSWilly Tu int32_t*, 428ea2e6eecSWilly Tu uint64_t*, 429ea2e6eecSWilly Tu int64_t*, 430ea2e6eecSWilly Tu bool*, 431ea2e6eecSWilly Tu double*, 432ea2e6eecSWilly Tu std::string*, 433b6164cbeSEd Tanous nlohmann::json::object_t*, 4348099c517SEd Tanous std::variant<std::string, std::nullptr_t>*, 4358099c517SEd Tanous std::variant<uint8_t, std::nullptr_t>*, 4368099c517SEd Tanous std::variant<int16_t, std::nullptr_t>*, 4378099c517SEd Tanous std::variant<uint16_t, std::nullptr_t>*, 4388099c517SEd Tanous std::variant<int32_t, std::nullptr_t>*, 4398099c517SEd Tanous std::variant<uint32_t, std::nullptr_t>*, 4408099c517SEd Tanous std::variant<int64_t, std::nullptr_t>*, 4418099c517SEd Tanous std::variant<uint64_t, std::nullptr_t>*, 4428099c517SEd Tanous std::variant<double, std::nullptr_t>*, 4438099c517SEd Tanous std::variant<bool, std::nullptr_t>*, 444ea2e6eecSWilly Tu std::vector<uint8_t>*, 445ea2e6eecSWilly Tu std::vector<uint16_t>*, 446ea2e6eecSWilly Tu std::vector<int16_t>*, 447ea2e6eecSWilly Tu std::vector<uint32_t>*, 448ea2e6eecSWilly Tu std::vector<int32_t>*, 449ea2e6eecSWilly Tu std::vector<uint64_t>*, 450ea2e6eecSWilly Tu std::vector<int64_t>*, 451ea2e6eecSWilly Tu //std::vector<bool>*, 452ea2e6eecSWilly Tu std::vector<double>*, 453ea2e6eecSWilly Tu std::vector<std::string>*, 454b6164cbeSEd Tanous std::vector<nlohmann::json::object_t>*, 455ea2e6eecSWilly Tu std::optional<uint8_t>*, 456ea2e6eecSWilly Tu std::optional<uint16_t>*, 457ea2e6eecSWilly Tu std::optional<int16_t>*, 458ea2e6eecSWilly Tu std::optional<uint32_t>*, 459ea2e6eecSWilly Tu std::optional<int32_t>*, 460ea2e6eecSWilly Tu std::optional<uint64_t>*, 461ea2e6eecSWilly Tu std::optional<int64_t>*, 462ea2e6eecSWilly Tu std::optional<bool>*, 463ea2e6eecSWilly Tu std::optional<double>*, 464ea2e6eecSWilly Tu std::optional<std::string>*, 465b6164cbeSEd Tanous std::optional<nlohmann::json::object_t>*, 466ea2e6eecSWilly Tu std::optional<std::vector<uint8_t>>*, 467ea2e6eecSWilly Tu std::optional<std::vector<uint16_t>>*, 468ea2e6eecSWilly Tu std::optional<std::vector<int16_t>>*, 469ea2e6eecSWilly Tu std::optional<std::vector<uint32_t>>*, 470ea2e6eecSWilly Tu std::optional<std::vector<int32_t>>*, 471ea2e6eecSWilly Tu std::optional<std::vector<uint64_t>>*, 472ea2e6eecSWilly Tu std::optional<std::vector<int64_t>>*, 473ea2e6eecSWilly Tu //std::optional<std::vector<bool>>*, 474ea2e6eecSWilly Tu std::optional<std::vector<double>>*, 475ea2e6eecSWilly Tu std::optional<std::vector<std::string>>*, 4768099c517SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>*, 4778099c517SEd Tanous std::optional<std::variant<std::string, std::nullptr_t>>*, 4788099c517SEd Tanous std::optional<std::variant<uint8_t, std::nullptr_t>>*, 4798099c517SEd Tanous std::optional<std::variant<int16_t, std::nullptr_t>>*, 4808099c517SEd Tanous std::optional<std::variant<uint16_t, std::nullptr_t>>*, 4818099c517SEd Tanous std::optional<std::variant<int32_t, std::nullptr_t>>*, 4828099c517SEd Tanous std::optional<std::variant<uint32_t, std::nullptr_t>>*, 4838099c517SEd Tanous std::optional<std::variant<int64_t, std::nullptr_t>>*, 4848099c517SEd Tanous std::optional<std::variant<uint64_t, std::nullptr_t>>*, 4858099c517SEd Tanous std::optional<std::variant<double, std::nullptr_t>>*, 4868099c517SEd Tanous std::optional<std::variant<bool, std::nullptr_t>>*, 4878099c517SEd Tanous std::optional<std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>*, 488ed4de7a8SEd Tanous std::optional<std::vector<std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>>>*, 489ed4de7a8SEd Tanous 490ed4de7a8SEd Tanous // Note, these types are kept for historical completeness, but should not be used, 491ed4de7a8SEd Tanous // As they do not provide object type safety. Instead, rely on nlohmann::json::object_t 492ed4de7a8SEd Tanous // Will be removed Q2 2025 493ed4de7a8SEd Tanous nlohmann::json*, 494ed4de7a8SEd Tanous std::optional<std::vector<nlohmann::json>>*, 495ed4de7a8SEd Tanous std::vector<nlohmann::json>*, 496ed4de7a8SEd Tanous std::optional<nlohmann::json>* 497ea2e6eecSWilly Tu >; 498ea2e6eecSWilly Tu // clang-format on 499ea2e6eecSWilly Tu 500ea2e6eecSWilly Tu struct PerUnpack 501ea2e6eecSWilly Tu { 502ea2e6eecSWilly Tu std::string_view key; 503ea2e6eecSWilly Tu UnpackVariant value; 504ea2e6eecSWilly Tu bool complete = false; 505ea2e6eecSWilly Tu }; 506ea2e6eecSWilly Tu 507ea2e6eecSWilly Tu inline bool readJsonHelper(nlohmann::json& jsonRequest, crow::Response& res, 508b6164cbeSEd Tanous std::span<PerUnpack> toUnpack); 509b6164cbeSEd Tanous 510b6164cbeSEd Tanous inline bool readJsonHelperObject(nlohmann::json::object_t& obj, 511b6164cbeSEd Tanous crow::Response& res, 512ea2e6eecSWilly Tu std::span<PerUnpack> toUnpack) 5139712f8acSEd Tanous { 51441352c24SSantosh Puranik bool result = true; 515b6164cbeSEd Tanous for (auto& item : obj) 5169712f8acSEd Tanous { 517ea2e6eecSWilly Tu size_t unpackIndex = 0; 518ea2e6eecSWilly Tu for (; unpackIndex < toUnpack.size(); unpackIndex++) 519ea2e6eecSWilly Tu { 520ea2e6eecSWilly Tu PerUnpack& unpackSpec = toUnpack[unpackIndex]; 521ea2e6eecSWilly Tu std::string_view key = unpackSpec.key; 522ea2e6eecSWilly Tu size_t keysplitIndex = key.find('/'); 523ea2e6eecSWilly Tu std::string_view leftover; 524ea2e6eecSWilly Tu if (keysplitIndex != std::string_view::npos) 525ea2e6eecSWilly Tu { 526ea2e6eecSWilly Tu leftover = key.substr(keysplitIndex + 1); 527ea2e6eecSWilly Tu key = key.substr(0, keysplitIndex); 528ea2e6eecSWilly Tu } 529ea2e6eecSWilly Tu 530d91415c4SEd Tanous if (key != item.first || unpackSpec.complete) 531ea2e6eecSWilly Tu { 532ea2e6eecSWilly Tu continue; 533ea2e6eecSWilly Tu } 534ea2e6eecSWilly Tu 535ea2e6eecSWilly Tu // Sublevel key 536ea2e6eecSWilly Tu if (!leftover.empty()) 537ea2e6eecSWilly Tu { 538ea2e6eecSWilly Tu // Include the slash in the key so we can compare later 539ea2e6eecSWilly Tu key = unpackSpec.key.substr(0, keysplitIndex + 1); 540ea2e6eecSWilly Tu nlohmann::json j; 541d91415c4SEd Tanous result = details::unpackValue<nlohmann::json>(item.second, key, 542ea2e6eecSWilly Tu res, j) && 54341352c24SSantosh Puranik result; 54455f79e6fSEd Tanous if (!result) 545ea2e6eecSWilly Tu { 546ea2e6eecSWilly Tu return result; 5479712f8acSEd Tanous } 5489712f8acSEd Tanous 549ea2e6eecSWilly Tu std::vector<PerUnpack> nextLevel; 550ea2e6eecSWilly Tu for (PerUnpack& p : toUnpack) 551ea2e6eecSWilly Tu { 552ea2e6eecSWilly Tu if (!p.key.starts_with(key)) 553ea2e6eecSWilly Tu { 554ea2e6eecSWilly Tu continue; 555ea2e6eecSWilly Tu } 556ea2e6eecSWilly Tu std::string_view thisLeftover = p.key.substr(key.size()); 557ea2e6eecSWilly Tu nextLevel.push_back({thisLeftover, p.value, false}); 558ea2e6eecSWilly Tu p.complete = true; 5599712f8acSEd Tanous } 56077dd8813SKowalski, Kamil 561ea2e6eecSWilly Tu result = readJsonHelper(j, res, nextLevel) && result; 562ea2e6eecSWilly Tu break; 563ea2e6eecSWilly Tu } 564ea2e6eecSWilly Tu 565bd79bce8SPatrick Williams result = 566bd79bce8SPatrick Williams std::visit( 5675ea927bbSEd Tanous [&item, &unpackSpec, &res](auto& val) { 568ea2e6eecSWilly Tu using ContainedT = 569ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 570ea2e6eecSWilly Tu return details::unpackValue<ContainedT>( 571d91415c4SEd Tanous item.second, unpackSpec.key, res, *val); 572ea2e6eecSWilly Tu }, 573ea2e6eecSWilly Tu unpackSpec.value) && 574ea2e6eecSWilly Tu result; 575ea2e6eecSWilly Tu 576ea2e6eecSWilly Tu unpackSpec.complete = true; 577ea2e6eecSWilly Tu break; 578ea2e6eecSWilly Tu } 579ea2e6eecSWilly Tu 580ea2e6eecSWilly Tu if (unpackIndex == toUnpack.size()) 581ea2e6eecSWilly Tu { 582d91415c4SEd Tanous messages::propertyUnknown(res, item.first); 583ea2e6eecSWilly Tu result = false; 584ea2e6eecSWilly Tu } 585ea2e6eecSWilly Tu } 586ea2e6eecSWilly Tu 587ea2e6eecSWilly Tu for (PerUnpack& perUnpack : toUnpack) 588ea2e6eecSWilly Tu { 58955f79e6fSEd Tanous if (!perUnpack.complete) 590ea2e6eecSWilly Tu { 591ea2e6eecSWilly Tu bool isOptional = std::visit( 5925ea927bbSEd Tanous [](auto& val) { 593ea2e6eecSWilly Tu using ContainedType = 594ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 595ea2e6eecSWilly Tu return details::IsOptional<ContainedType>::value; 596ea2e6eecSWilly Tu }, 597ea2e6eecSWilly Tu perUnpack.value); 598ea2e6eecSWilly Tu if (isOptional) 599ea2e6eecSWilly Tu { 600ea2e6eecSWilly Tu continue; 601ea2e6eecSWilly Tu } 602ea2e6eecSWilly Tu messages::propertyMissing(res, perUnpack.key); 603ea2e6eecSWilly Tu result = false; 604ea2e6eecSWilly Tu } 605ea2e6eecSWilly Tu } 606ea2e6eecSWilly Tu return result; 607ea2e6eecSWilly Tu } 608ea2e6eecSWilly Tu 609b6164cbeSEd Tanous inline bool readJsonHelper(nlohmann::json& jsonRequest, crow::Response& res, 610b6164cbeSEd Tanous std::span<PerUnpack> toUnpack) 611b6164cbeSEd Tanous { 612b6164cbeSEd Tanous nlohmann::json::object_t* obj = 613b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 614b6164cbeSEd Tanous if (obj == nullptr) 615b6164cbeSEd Tanous { 616b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is not an object"); 617b6164cbeSEd Tanous messages::unrecognizedRequestBody(res); 618b6164cbeSEd Tanous return false; 619b6164cbeSEd Tanous } 620b6164cbeSEd Tanous return readJsonHelperObject(*obj, res, toUnpack); 621b6164cbeSEd Tanous } 622b6164cbeSEd Tanous 62389492a15SPatrick Williams inline void packVariant(std::span<PerUnpack> /*toPack*/) {} 624ea2e6eecSWilly Tu 625ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 626ea2e6eecSWilly Tu void packVariant(std::span<PerUnpack> toPack, std::string_view key, 6275ea927bbSEd Tanous FirstType&& first, UnpackTypes&&... in) 628ea2e6eecSWilly Tu { 629ea2e6eecSWilly Tu if (toPack.empty()) 630ea2e6eecSWilly Tu { 631ea2e6eecSWilly Tu return; 632ea2e6eecSWilly Tu } 633ea2e6eecSWilly Tu toPack[0].key = key; 634ea2e6eecSWilly Tu toPack[0].value = &first; 635ea2e6eecSWilly Tu // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) 636ea2e6eecSWilly Tu packVariant(toPack.subspan(1), std::forward<UnpackTypes&&>(in)...); 637ea2e6eecSWilly Tu } 638ea2e6eecSWilly Tu 639ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 640b6164cbeSEd Tanous bool readJsonObject(nlohmann::json::object_t& jsonRequest, crow::Response& res, 641b6164cbeSEd Tanous std::string_view key, FirstType&& first, 642b6164cbeSEd Tanous UnpackTypes&&... in) 643ea2e6eecSWilly Tu { 644ea2e6eecSWilly Tu const std::size_t n = sizeof...(UnpackTypes) + 2; 645ea2e6eecSWilly Tu std::array<PerUnpack, n / 2> toUnpack2; 6465ea927bbSEd Tanous packVariant(toUnpack2, key, std::forward<FirstType>(first), 6475ea927bbSEd Tanous std::forward<UnpackTypes&&>(in)...); 648b6164cbeSEd Tanous return readJsonHelperObject(jsonRequest, res, toUnpack2); 649ea2e6eecSWilly Tu } 650ea2e6eecSWilly Tu 651b6164cbeSEd Tanous template <typename FirstType, typename... UnpackTypes> 652b6164cbeSEd Tanous bool readJson(nlohmann::json& jsonRequest, crow::Response& res, 653b6164cbeSEd Tanous std::string_view key, FirstType&& first, UnpackTypes&&... in) 654b6164cbeSEd Tanous { 655b6164cbeSEd Tanous nlohmann::json::object_t* obj = 656b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 657b6164cbeSEd Tanous if (obj == nullptr) 658b6164cbeSEd Tanous { 659b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is not an object"); 660b6164cbeSEd Tanous messages::unrecognizedRequestBody(res); 661b6164cbeSEd Tanous return false; 662b6164cbeSEd Tanous } 6635be2b14aSEd Tanous return readJsonObject(*obj, res, key, std::forward<FirstType>(first), 6645be2b14aSEd Tanous std::forward<UnpackTypes&&>(in)...); 665b6164cbeSEd Tanous } 666b6164cbeSEd Tanous 667b6164cbeSEd Tanous inline std::optional<nlohmann::json::object_t> 668ea2e6eecSWilly Tu readJsonPatchHelper(const crow::Request& req, crow::Response& res) 6690627a2c7SEd Tanous { 6700627a2c7SEd Tanous nlohmann::json jsonRequest; 6710627a2c7SEd Tanous if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 6720627a2c7SEd Tanous { 67362598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value not readable"); 674ea2e6eecSWilly Tu return std::nullopt; 6750627a2c7SEd Tanous } 676357bb8f8SEd Tanous nlohmann::json::object_t* object = 677357bb8f8SEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 678357bb8f8SEd Tanous if (object == nullptr || object->empty()) 67915ed6780SWilly Tu { 68062598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value is empty"); 68115ed6780SWilly Tu messages::emptyJSON(res); 682ea2e6eecSWilly Tu return std::nullopt; 683ea2e6eecSWilly Tu } 684357bb8f8SEd Tanous std::erase_if(*object, 685357bb8f8SEd Tanous [](const std::pair<std::string, nlohmann::json>& item) { 686357bb8f8SEd Tanous return item.first.starts_with("@odata."); 687357bb8f8SEd Tanous }); 688357bb8f8SEd Tanous if (object->empty()) 689357bb8f8SEd Tanous { 690357bb8f8SEd Tanous // If the update request only contains OData annotations, the service 691357bb8f8SEd Tanous // should return the HTTP 400 Bad Request status code with the 692357bb8f8SEd Tanous // NoOperation message from the Base Message Registry, ... 693357bb8f8SEd Tanous messages::noOperation(res); 694357bb8f8SEd Tanous return std::nullopt; 695357bb8f8SEd Tanous } 696357bb8f8SEd Tanous 697b6164cbeSEd Tanous return {std::move(*object)}; 698ea2e6eecSWilly Tu } 699ea2e6eecSWilly Tu 700ea2e6eecSWilly Tu template <typename... UnpackTypes> 701ea2e6eecSWilly Tu bool readJsonPatch(const crow::Request& req, crow::Response& res, 702ea2e6eecSWilly Tu std::string_view key, UnpackTypes&&... in) 703ea2e6eecSWilly Tu { 70476b038f2SEd Tanous std::optional<nlohmann::json::object_t> jsonRequest = 70576b038f2SEd Tanous readJsonPatchHelper(req, res); 706e01d0c36SEd Tanous if (!jsonRequest) 707ea2e6eecSWilly Tu { 70815ed6780SWilly Tu return false; 70915ed6780SWilly Tu } 71076b038f2SEd Tanous if (jsonRequest->empty()) 711b6164cbeSEd Tanous { 712b6164cbeSEd Tanous messages::emptyJSON(res); 713b6164cbeSEd Tanous return false; 714b6164cbeSEd Tanous } 71515ed6780SWilly Tu 71676b038f2SEd Tanous return readJsonObject(*jsonRequest, res, key, 717b6164cbeSEd Tanous std::forward<UnpackTypes&&>(in)...); 71815ed6780SWilly Tu } 71915ed6780SWilly Tu 72015ed6780SWilly Tu template <typename... UnpackTypes> 72115ed6780SWilly Tu bool readJsonAction(const crow::Request& req, crow::Response& res, 722ea2e6eecSWilly Tu const char* key, UnpackTypes&&... in) 72315ed6780SWilly Tu { 72415ed6780SWilly Tu nlohmann::json jsonRequest; 72515ed6780SWilly Tu if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 72615ed6780SWilly Tu { 72762598e31SEd Tanous BMCWEB_LOG_DEBUG("Json value not readable"); 72815ed6780SWilly Tu return false; 72915ed6780SWilly Tu } 730b6164cbeSEd Tanous nlohmann::json::object_t* object = 731b6164cbeSEd Tanous jsonRequest.get_ptr<nlohmann::json::object_t*>(); 732b6164cbeSEd Tanous if (object == nullptr) 733b6164cbeSEd Tanous { 734b6164cbeSEd Tanous BMCWEB_LOG_DEBUG("Json value is empty"); 735b6164cbeSEd Tanous messages::emptyJSON(res); 736b6164cbeSEd Tanous return false; 737b6164cbeSEd Tanous } 738b6164cbeSEd Tanous return readJsonObject(*object, res, key, 739b6164cbeSEd Tanous std::forward<UnpackTypes&&>(in)...); 7400627a2c7SEd Tanous } 741185444b1SNan Zhou 742185444b1SNan Zhou // Determines if two json objects are less, based on the presence of the 743185444b1SNan Zhou // @odata.id key 7444e196b9aSEd Tanous inline int objectKeyCmp(std::string_view key, const nlohmann::json& a, 7454e196b9aSEd Tanous const nlohmann::json& b) 746185444b1SNan Zhou { 747185444b1SNan Zhou using object_t = nlohmann::json::object_t; 748185444b1SNan Zhou const object_t* aObj = a.get_ptr<const object_t*>(); 749185444b1SNan Zhou const object_t* bObj = b.get_ptr<const object_t*>(); 750185444b1SNan Zhou 751185444b1SNan Zhou if (aObj == nullptr) 752185444b1SNan Zhou { 753185444b1SNan Zhou if (bObj == nullptr) 754185444b1SNan Zhou { 755185444b1SNan Zhou return 0; 756185444b1SNan Zhou } 757185444b1SNan Zhou return -1; 758185444b1SNan Zhou } 759185444b1SNan Zhou if (bObj == nullptr) 760185444b1SNan Zhou { 761185444b1SNan Zhou return 1; 762185444b1SNan Zhou } 7634e196b9aSEd Tanous object_t::const_iterator aIt = aObj->find(key); 7644e196b9aSEd Tanous object_t::const_iterator bIt = bObj->find(key); 7654e196b9aSEd Tanous // If either object doesn't have the key, they get "sorted" to the 7664e196b9aSEd Tanous // beginning. 767185444b1SNan Zhou if (aIt == aObj->end()) 768185444b1SNan Zhou { 769185444b1SNan Zhou if (bIt == bObj->end()) 770185444b1SNan Zhou { 771185444b1SNan Zhou return 0; 772185444b1SNan Zhou } 773185444b1SNan Zhou return -1; 774185444b1SNan Zhou } 775185444b1SNan Zhou if (bIt == bObj->end()) 776185444b1SNan Zhou { 777185444b1SNan Zhou return 1; 778185444b1SNan Zhou } 779185444b1SNan Zhou const nlohmann::json::string_t* nameA = 780185444b1SNan Zhou aIt->second.get_ptr<const std::string*>(); 781185444b1SNan Zhou const nlohmann::json::string_t* nameB = 782185444b1SNan Zhou bIt->second.get_ptr<const std::string*>(); 783185444b1SNan Zhou // If either object doesn't have a string as the key, they get "sorted" to 7844e196b9aSEd Tanous // the beginning. 785185444b1SNan Zhou if (nameA == nullptr) 786185444b1SNan Zhou { 787185444b1SNan Zhou if (nameB == nullptr) 788185444b1SNan Zhou { 789185444b1SNan Zhou return 0; 790185444b1SNan Zhou } 791185444b1SNan Zhou return -1; 792185444b1SNan Zhou } 793185444b1SNan Zhou if (nameB == nullptr) 794185444b1SNan Zhou { 795185444b1SNan Zhou return 1; 796185444b1SNan Zhou } 797*e7bcf475SJayanth Othayoth if (key != "@odata.id") 798*e7bcf475SJayanth Othayoth { 799*e7bcf475SJayanth Othayoth return alphanumComp(*nameA, *nameB); 800*e7bcf475SJayanth Othayoth } 801185444b1SNan Zhou 802*e7bcf475SJayanth Othayoth boost::system::result<boost::urls::url_view> aUrl = 803*e7bcf475SJayanth Othayoth boost::urls::parse_relative_ref(*nameA); 804*e7bcf475SJayanth Othayoth boost::system::result<boost::urls::url_view> bUrl = 805*e7bcf475SJayanth Othayoth boost::urls::parse_relative_ref(*nameB); 806*e7bcf475SJayanth Othayoth if (!aUrl) 807185444b1SNan Zhou { 808*e7bcf475SJayanth Othayoth if (!bUrl) 809185444b1SNan Zhou { 810185444b1SNan Zhou return 0; 811185444b1SNan Zhou } 812185444b1SNan Zhou return -1; 813185444b1SNan Zhou } 814*e7bcf475SJayanth Othayoth if (!bUrl) 815*e7bcf475SJayanth Othayoth { 816*e7bcf475SJayanth Othayoth return 1; 817*e7bcf475SJayanth Othayoth } 818*e7bcf475SJayanth Othayoth 819*e7bcf475SJayanth Othayoth auto segmentsAIt = aUrl->segments().begin(); 820*e7bcf475SJayanth Othayoth auto segmentsBIt = bUrl->segments().begin(); 821*e7bcf475SJayanth Othayoth 822*e7bcf475SJayanth Othayoth while (true) 823*e7bcf475SJayanth Othayoth { 824*e7bcf475SJayanth Othayoth if (segmentsAIt == aUrl->segments().end()) 825*e7bcf475SJayanth Othayoth { 826*e7bcf475SJayanth Othayoth if (segmentsBIt == bUrl->segments().end()) 827*e7bcf475SJayanth Othayoth { 828*e7bcf475SJayanth Othayoth return 0; 829*e7bcf475SJayanth Othayoth } 830*e7bcf475SJayanth Othayoth return -1; 831*e7bcf475SJayanth Othayoth } 832*e7bcf475SJayanth Othayoth if (segmentsBIt == bUrl->segments().end()) 833185444b1SNan Zhou { 834185444b1SNan Zhou return 1; 835185444b1SNan Zhou } 836185444b1SNan Zhou int res = alphanumComp(*segmentsAIt, *segmentsBIt); 837185444b1SNan Zhou if (res != 0) 838185444b1SNan Zhou { 839185444b1SNan Zhou return res; 840185444b1SNan Zhou } 841185444b1SNan Zhou 842185444b1SNan Zhou segmentsAIt++; 843185444b1SNan Zhou segmentsBIt++; 844185444b1SNan Zhou } 845*e7bcf475SJayanth Othayoth return 0; 846185444b1SNan Zhou }; 847185444b1SNan Zhou 8484e196b9aSEd Tanous // kept for backward compatibility 8494e196b9aSEd Tanous inline int odataObjectCmp(const nlohmann::json& left, 8504e196b9aSEd Tanous const nlohmann::json& right) 8514e196b9aSEd Tanous { 8524e196b9aSEd Tanous return objectKeyCmp("@odata.id", left, right); 8534e196b9aSEd Tanous } 8544e196b9aSEd Tanous 855185444b1SNan Zhou struct ODataObjectLess 856185444b1SNan Zhou { 8574e196b9aSEd Tanous std::string_view key; 8584e196b9aSEd Tanous 8594e196b9aSEd Tanous explicit ODataObjectLess(std::string_view keyIn) : key(keyIn) {} 8604e196b9aSEd Tanous 861185444b1SNan Zhou bool operator()(const nlohmann::json& left, 862185444b1SNan Zhou const nlohmann::json& right) const 863185444b1SNan Zhou { 8644e196b9aSEd Tanous return objectKeyCmp(key, left, right) < 0; 865185444b1SNan Zhou } 866185444b1SNan Zhou }; 867185444b1SNan Zhou 868185444b1SNan Zhou // Sort the JSON array by |element[key]|. 869185444b1SNan Zhou // Elements without |key| or type of |element[key]| is not string are smaller 870185444b1SNan Zhou // those whose |element[key]| is string. 8714e196b9aSEd Tanous inline void sortJsonArrayByKey(nlohmann::json::array_t& array, 8724e196b9aSEd Tanous std::string_view key) 8734e196b9aSEd Tanous { 8744e196b9aSEd Tanous std::ranges::sort(array, ODataObjectLess(key)); 8754e196b9aSEd Tanous } 8764e196b9aSEd Tanous 8774e196b9aSEd Tanous // Sort the JSON array by |element[key]|. 8784e196b9aSEd Tanous // Elements without |key| or type of |element[key]| is not string are smaller 8794e196b9aSEd Tanous // those whose |element[key]| is string. 880185444b1SNan Zhou inline void sortJsonArrayByOData(nlohmann::json::array_t& array) 881185444b1SNan Zhou { 8824e196b9aSEd Tanous std::ranges::sort(array, ODataObjectLess("@odata.id")); 883185444b1SNan Zhou } 884185444b1SNan Zhou 8858a7c4b47SNan Zhou // Returns the estimated size of the JSON value 8868a7c4b47SNan Zhou // The implementation walks through every key and every value, accumulates the 8878a7c4b47SNan Zhou // total size of keys and values. 8888a7c4b47SNan Zhou // Ideally, we should use a custom allocator that nlohmann JSON supports. 8898a7c4b47SNan Zhou 8908a7c4b47SNan Zhou // Assumption made: 8918a7c4b47SNan Zhou // 1. number: 8 characters 8928a7c4b47SNan Zhou // 2. boolean: 5 characters (False) 8938a7c4b47SNan Zhou // 3. string: len(str) + 2 characters (quote) 8948a7c4b47SNan Zhou // 4. bytes: len(bytes) characters 8958a7c4b47SNan Zhou // 5. null: 4 characters (null) 8968a7c4b47SNan Zhou uint64_t getEstimatedJsonSize(const nlohmann::json& root); 8978a7c4b47SNan Zhou 89877dd8813SKowalski, Kamil } // namespace json_util 89977dd8813SKowalski, Kamil } // namespace redfish 900