177dd8813SKowalski, Kamil /* 277dd8813SKowalski, Kamil // Copyright (c) 2018 Intel Corporation 377dd8813SKowalski, Kamil // 477dd8813SKowalski, Kamil // Licensed under the Apache License, Version 2.0 (the "License"); 577dd8813SKowalski, Kamil // you may not use this file except in compliance with the License. 677dd8813SKowalski, Kamil // You may obtain a copy of the License at 777dd8813SKowalski, Kamil // 877dd8813SKowalski, Kamil // http://www.apache.org/licenses/LICENSE-2.0 977dd8813SKowalski, Kamil // 1077dd8813SKowalski, Kamil // Unless required by applicable law or agreed to in writing, software 1177dd8813SKowalski, Kamil // distributed under the License is distributed on an "AS IS" BASIS, 1277dd8813SKowalski, Kamil // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1377dd8813SKowalski, Kamil // See the License for the specific language governing permissions and 1477dd8813SKowalski, Kamil // limitations under the License. 1577dd8813SKowalski, Kamil */ 1677dd8813SKowalski, Kamil #pragma once 179712f8acSEd Tanous 189712f8acSEd Tanous #include <error_messages.hpp> 1904e438cbSEd Tanous #include <http_request.hpp> 2004e438cbSEd Tanous #include <http_response.hpp> 211abe55efSEd Tanous #include <nlohmann/json.hpp> 220627a2c7SEd Tanous 23*ea2e6eecSWilly Tu #include <span> 241214b7e7SGunnar Mills 251abe55efSEd Tanous namespace redfish 261abe55efSEd Tanous { 271abe55efSEd Tanous 281abe55efSEd Tanous namespace json_util 291abe55efSEd Tanous { 3077dd8813SKowalski, Kamil 3177dd8813SKowalski, Kamil /** 3277dd8813SKowalski, Kamil * @brief Processes request to extract JSON from its body. If it fails, adds 3377dd8813SKowalski, Kamil * MalformedJSON message to response and ends it. 3477dd8813SKowalski, Kamil * 3577dd8813SKowalski, Kamil * @param[io] res Response object 3677dd8813SKowalski, Kamil * @param[in] req Request object 3777dd8813SKowalski, Kamil * @param[out] reqJson JSON object extracted from request's body 3877dd8813SKowalski, Kamil * 3977dd8813SKowalski, Kamil * @return true if JSON is valid, false when JSON is invalid and response has 4077dd8813SKowalski, Kamil * been filled with message and ended. 4177dd8813SKowalski, Kamil */ 4255c7b7a2SEd Tanous bool processJsonFromRequest(crow::Response& res, const crow::Request& req, 4377dd8813SKowalski, Kamil nlohmann::json& reqJson); 449712f8acSEd Tanous namespace details 459712f8acSEd Tanous { 46771cfa0fSJason M. Bills 471214b7e7SGunnar Mills template <typename Type> 482c70f800SEd Tanous struct IsOptional : std::false_type 491214b7e7SGunnar Mills {}; 509712f8acSEd Tanous 51771cfa0fSJason M. Bills template <typename Type> 522c70f800SEd Tanous struct IsOptional<std::optional<Type>> : std::true_type 531214b7e7SGunnar Mills {}; 549712f8acSEd Tanous 55771cfa0fSJason M. Bills template <typename Type> 562c70f800SEd Tanous struct IsVector : std::false_type 571214b7e7SGunnar Mills {}; 58b1556427SEd Tanous 591214b7e7SGunnar Mills template <typename Type> 602c70f800SEd Tanous struct IsVector<std::vector<Type>> : std::true_type 611214b7e7SGunnar Mills {}; 62b1556427SEd Tanous 631214b7e7SGunnar Mills template <typename Type> 642c70f800SEd Tanous struct IsStdArray : std::false_type 651214b7e7SGunnar Mills {}; 66318226c2SJames Feist 67318226c2SJames Feist template <typename Type, std::size_t size> 682c70f800SEd Tanous struct IsStdArray<std::array<Type, size>> : std::true_type 691214b7e7SGunnar Mills {}; 70318226c2SJames Feist 71471a5eb8SAppaRao Puli enum class UnpackErrorCode 72471a5eb8SAppaRao Puli { 73471a5eb8SAppaRao Puli success, 74471a5eb8SAppaRao Puli invalidType, 75471a5eb8SAppaRao Puli outOfRange 76471a5eb8SAppaRao Puli }; 77471a5eb8SAppaRao Puli 78a6acbb31SJames Feist template <typename ToType, typename FromType> 79*ea2e6eecSWilly Tu bool checkRange(const FromType& from, std::string_view key) 80a6acbb31SJames Feist { 81ee344e0fSEd Tanous if (from > std::numeric_limits<ToType>::max()) 82a6acbb31SJames Feist { 83a6acbb31SJames Feist BMCWEB_LOG_DEBUG << "Value for key " << key 84a6acbb31SJames Feist << " was greater than max: " << __PRETTY_FUNCTION__; 85a6acbb31SJames Feist return false; 86a6acbb31SJames Feist } 87ee344e0fSEd Tanous if (from < std::numeric_limits<ToType>::lowest()) 88a6acbb31SJames Feist { 89a6acbb31SJames Feist BMCWEB_LOG_DEBUG << "Value for key " << key 90a6acbb31SJames Feist << " was less than min: " << __PRETTY_FUNCTION__; 91a6acbb31SJames Feist return false; 92a6acbb31SJames Feist } 93a6acbb31SJames Feist if constexpr (std::is_floating_point_v<ToType>) 94a6acbb31SJames Feist { 95ee344e0fSEd Tanous if (std::isnan(from)) 96a6acbb31SJames Feist { 97a6acbb31SJames Feist BMCWEB_LOG_DEBUG << "Value for key " << key << " was NAN"; 98a6acbb31SJames Feist return false; 99a6acbb31SJames Feist } 100a6acbb31SJames Feist } 101a6acbb31SJames Feist 102a6acbb31SJames Feist return true; 103a6acbb31SJames Feist } 104a6acbb31SJames Feist 105771cfa0fSJason M. Bills template <typename Type> 106471a5eb8SAppaRao Puli UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, 107*ea2e6eecSWilly Tu std::string_view key, Type& value) 108771cfa0fSJason M. Bills { 109471a5eb8SAppaRao Puli UnpackErrorCode ret = UnpackErrorCode::success; 11041352c24SSantosh Puranik 111a6acbb31SJames Feist if constexpr (std::is_floating_point_v<Type>) 112771cfa0fSJason M. Bills { 113a6acbb31SJames Feist double helper = 0; 114a6acbb31SJames Feist double* jsonPtr = jsonValue.get_ptr<double*>(); 115771cfa0fSJason M. Bills 116771cfa0fSJason M. Bills if (jsonPtr == nullptr) 117771cfa0fSJason M. Bills { 118a6acbb31SJames Feist int64_t* intPtr = jsonValue.get_ptr<int64_t*>(); 119a6acbb31SJames Feist if (intPtr != nullptr) 120771cfa0fSJason M. Bills { 121a6acbb31SJames Feist helper = static_cast<double>(*intPtr); 122a6acbb31SJames Feist jsonPtr = &helper; 123771cfa0fSJason M. Bills } 124a6acbb31SJames Feist } 1255eb2bef2SAppaRao Puli if (jsonPtr == nullptr) 1265eb2bef2SAppaRao Puli { 127471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 1285eb2bef2SAppaRao Puli } 129cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 130771cfa0fSJason M. Bills { 131471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 132771cfa0fSJason M. Bills } 133771cfa0fSJason M. Bills value = static_cast<Type>(*jsonPtr); 134771cfa0fSJason M. Bills } 135a6acbb31SJames Feist 136a6acbb31SJames Feist else if constexpr (std::is_signed_v<Type>) 137a6acbb31SJames Feist { 138a6acbb31SJames Feist int64_t* jsonPtr = jsonValue.get_ptr<int64_t*>(); 139271584abSEd Tanous if (jsonPtr == nullptr) 140271584abSEd Tanous { 141471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 142271584abSEd Tanous } 143cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 144a6acbb31SJames Feist { 145471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 146a6acbb31SJames Feist } 147a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 148a6acbb31SJames Feist } 149a6acbb31SJames Feist 1508102ddbaSAppaRao Puli else if constexpr ((std::is_unsigned_v<Type>)&&( 1518102ddbaSAppaRao Puli !std::is_same_v<bool, Type>)) 152a6acbb31SJames Feist { 153a6acbb31SJames Feist uint64_t* jsonPtr = jsonValue.get_ptr<uint64_t*>(); 154271584abSEd Tanous if (jsonPtr == nullptr) 155271584abSEd Tanous { 156471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 157271584abSEd Tanous } 158cb13a392SEd Tanous if (!checkRange<Type>(*jsonPtr, key)) 159a6acbb31SJames Feist { 160471a5eb8SAppaRao Puli return UnpackErrorCode::outOfRange; 161a6acbb31SJames Feist } 162a6acbb31SJames Feist value = static_cast<Type>(*jsonPtr); 163a6acbb31SJames Feist } 164a6acbb31SJames Feist 1650627a2c7SEd Tanous else if constexpr (std::is_same_v<nlohmann::json, Type>) 1660627a2c7SEd Tanous { 1670627a2c7SEd Tanous // Must be a complex type. Simple types (int string etc) should be 1680627a2c7SEd Tanous // unpacked directly 1698ebc91f6SEd Tanous if (!jsonValue.is_object() && !jsonValue.is_array() && 1708ebc91f6SEd Tanous !jsonValue.is_null()) 1710627a2c7SEd Tanous { 172471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 1730627a2c7SEd Tanous } 1740627a2c7SEd Tanous 1750627a2c7SEd Tanous value = std::move(jsonValue); 1760627a2c7SEd Tanous } 177471a5eb8SAppaRao Puli else 178471a5eb8SAppaRao Puli { 179471a5eb8SAppaRao Puli using JsonType = std::add_const_t<std::add_pointer_t<Type>>; 180471a5eb8SAppaRao Puli JsonType jsonPtr = jsonValue.get_ptr<JsonType>(); 181471a5eb8SAppaRao Puli if (jsonPtr == nullptr) 182471a5eb8SAppaRao Puli { 183471a5eb8SAppaRao Puli BMCWEB_LOG_DEBUG 184471a5eb8SAppaRao Puli << "Value for key " << key 185471a5eb8SAppaRao Puli << " was incorrect type: " << jsonValue.type_name(); 186471a5eb8SAppaRao Puli return UnpackErrorCode::invalidType; 187471a5eb8SAppaRao Puli } 188471a5eb8SAppaRao Puli value = std::move(*jsonPtr); 189471a5eb8SAppaRao Puli } 190471a5eb8SAppaRao Puli return ret; 191471a5eb8SAppaRao Puli } 192471a5eb8SAppaRao Puli 193471a5eb8SAppaRao Puli template <typename Type> 194*ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, 195471a5eb8SAppaRao Puli crow::Response& res, Type& value) 196471a5eb8SAppaRao Puli { 197471a5eb8SAppaRao Puli bool ret = true; 198471a5eb8SAppaRao Puli 1992c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 200471a5eb8SAppaRao Puli { 201471a5eb8SAppaRao Puli value.emplace(); 202471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, res, 203471a5eb8SAppaRao Puli *value) && 204471a5eb8SAppaRao Puli ret; 205471a5eb8SAppaRao Puli } 2062c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 207318226c2SJames Feist { 208318226c2SJames Feist if (!jsonValue.is_array()) 209318226c2SJames Feist { 21071f52d96SEd Tanous messages::propertyValueTypeError( 21171f52d96SEd Tanous res, 21271f52d96SEd Tanous res.jsonValue.dump(2, ' ', true, 21371f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 21471f52d96SEd Tanous key); 21541352c24SSantosh Puranik return false; 216318226c2SJames Feist } 217318226c2SJames Feist if (jsonValue.size() != value.size()) 218318226c2SJames Feist { 21971f52d96SEd Tanous messages::propertyValueTypeError( 22071f52d96SEd Tanous res, 22171f52d96SEd Tanous res.jsonValue.dump(2, ' ', true, 22271f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 22371f52d96SEd Tanous key); 22441352c24SSantosh Puranik return false; 225318226c2SJames Feist } 226318226c2SJames Feist size_t index = 0; 227318226c2SJames Feist for (const auto& val : jsonValue.items()) 228318226c2SJames Feist { 22941352c24SSantosh Puranik ret = unpackValue<typename Type::value_type>(val.value(), key, res, 23041352c24SSantosh Puranik value[index++]) && 23141352c24SSantosh Puranik ret; 232318226c2SJames Feist } 233318226c2SJames Feist } 2342c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 235b1556427SEd Tanous { 236b1556427SEd Tanous if (!jsonValue.is_array()) 237b1556427SEd Tanous { 23871f52d96SEd Tanous messages::propertyValueTypeError( 23971f52d96SEd Tanous res, 24071f52d96SEd Tanous res.jsonValue.dump(2, ' ', true, 24171f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 24271f52d96SEd Tanous key); 24341352c24SSantosh Puranik return false; 244b1556427SEd Tanous } 245b1556427SEd Tanous 246b1556427SEd Tanous for (const auto& val : jsonValue.items()) 247b1556427SEd Tanous { 248b1556427SEd Tanous value.emplace_back(); 24941352c24SSantosh Puranik ret = unpackValue<typename Type::value_type>(val.value(), key, res, 25041352c24SSantosh Puranik value.back()) && 25141352c24SSantosh Puranik ret; 252b1556427SEd Tanous } 253b1556427SEd Tanous } 254771cfa0fSJason M. Bills else 255771cfa0fSJason M. Bills { 256471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 257471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 258771cfa0fSJason M. Bills { 259471a5eb8SAppaRao Puli if (ec == UnpackErrorCode::invalidType) 260471a5eb8SAppaRao Puli { 26171f52d96SEd Tanous messages::propertyValueTypeError( 26271f52d96SEd Tanous res, 26371f52d96SEd Tanous jsonValue.dump(2, ' ', true, 26471f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 26571f52d96SEd Tanous key); 266471a5eb8SAppaRao Puli } 267471a5eb8SAppaRao Puli else if (ec == UnpackErrorCode::outOfRange) 268471a5eb8SAppaRao Puli { 26971f52d96SEd Tanous messages::propertyValueNotInList( 27071f52d96SEd Tanous res, 27171f52d96SEd Tanous jsonValue.dump(2, ' ', true, 27271f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 27371f52d96SEd Tanous key); 274471a5eb8SAppaRao Puli } 27541352c24SSantosh Puranik return false; 276771cfa0fSJason M. Bills } 277771cfa0fSJason M. Bills } 278471a5eb8SAppaRao Puli 279471a5eb8SAppaRao Puli return ret; 280471a5eb8SAppaRao Puli } 281471a5eb8SAppaRao Puli 282471a5eb8SAppaRao Puli template <typename Type> 283*ea2e6eecSWilly Tu bool unpackValue(nlohmann::json& jsonValue, std::string_view key, Type& value) 284471a5eb8SAppaRao Puli { 285471a5eb8SAppaRao Puli bool ret = true; 2862c70f800SEd Tanous if constexpr (IsOptional<Type>::value) 287471a5eb8SAppaRao Puli { 288471a5eb8SAppaRao Puli value.emplace(); 289471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(jsonValue, key, *value) && 290471a5eb8SAppaRao Puli ret; 291471a5eb8SAppaRao Puli } 2922c70f800SEd Tanous else if constexpr (IsStdArray<Type>::value) 293471a5eb8SAppaRao Puli { 294471a5eb8SAppaRao Puli if (!jsonValue.is_array()) 295471a5eb8SAppaRao Puli { 296471a5eb8SAppaRao Puli return false; 297471a5eb8SAppaRao Puli } 298471a5eb8SAppaRao Puli if (jsonValue.size() != value.size()) 299471a5eb8SAppaRao Puli { 300471a5eb8SAppaRao Puli return false; 301471a5eb8SAppaRao Puli } 302471a5eb8SAppaRao Puli size_t index = 0; 303471a5eb8SAppaRao Puli for (const auto& val : jsonValue.items()) 304471a5eb8SAppaRao Puli { 305471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(val.value(), key, 306471a5eb8SAppaRao Puli value[index++]) && 307471a5eb8SAppaRao Puli ret; 308471a5eb8SAppaRao Puli } 309471a5eb8SAppaRao Puli } 3102c70f800SEd Tanous else if constexpr (IsVector<Type>::value) 311471a5eb8SAppaRao Puli { 312471a5eb8SAppaRao Puli if (!jsonValue.is_array()) 313471a5eb8SAppaRao Puli { 314471a5eb8SAppaRao Puli return false; 315471a5eb8SAppaRao Puli } 316471a5eb8SAppaRao Puli 317471a5eb8SAppaRao Puli for (const auto& val : jsonValue.items()) 318471a5eb8SAppaRao Puli { 319471a5eb8SAppaRao Puli value.emplace_back(); 320471a5eb8SAppaRao Puli ret = unpackValue<typename Type::value_type>(val.value(), key, 321471a5eb8SAppaRao Puli value.back()) && 322471a5eb8SAppaRao Puli ret; 323471a5eb8SAppaRao Puli } 324471a5eb8SAppaRao Puli } 325471a5eb8SAppaRao Puli else 326471a5eb8SAppaRao Puli { 327471a5eb8SAppaRao Puli UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); 328471a5eb8SAppaRao Puli if (ec != UnpackErrorCode::success) 329471a5eb8SAppaRao Puli { 330471a5eb8SAppaRao Puli return false; 331471a5eb8SAppaRao Puli } 332471a5eb8SAppaRao Puli } 333471a5eb8SAppaRao Puli 33441352c24SSantosh Puranik return ret; 335771cfa0fSJason M. Bills } 3369712f8acSEd Tanous } // namespace details 3379712f8acSEd Tanous 338*ea2e6eecSWilly Tu // clang-format off 339*ea2e6eecSWilly Tu using UnpackVariant = std::variant< 340*ea2e6eecSWilly Tu uint8_t*, 341*ea2e6eecSWilly Tu uint16_t*, 342*ea2e6eecSWilly Tu int16_t*, 343*ea2e6eecSWilly Tu uint32_t*, 344*ea2e6eecSWilly Tu int32_t*, 345*ea2e6eecSWilly Tu uint64_t*, 346*ea2e6eecSWilly Tu int64_t*, 347*ea2e6eecSWilly Tu bool*, 348*ea2e6eecSWilly Tu double*, 349*ea2e6eecSWilly Tu std::string*, 350*ea2e6eecSWilly Tu nlohmann::json*, 351*ea2e6eecSWilly Tu std::vector<uint8_t>*, 352*ea2e6eecSWilly Tu std::vector<uint16_t>*, 353*ea2e6eecSWilly Tu std::vector<int16_t>*, 354*ea2e6eecSWilly Tu std::vector<uint32_t>*, 355*ea2e6eecSWilly Tu std::vector<int32_t>*, 356*ea2e6eecSWilly Tu std::vector<uint64_t>*, 357*ea2e6eecSWilly Tu std::vector<int64_t>*, 358*ea2e6eecSWilly Tu //std::vector<bool>*, 359*ea2e6eecSWilly Tu std::vector<double>*, 360*ea2e6eecSWilly Tu std::vector<std::string>*, 361*ea2e6eecSWilly Tu std::vector<nlohmann::json>*, 362*ea2e6eecSWilly Tu std::optional<uint8_t>*, 363*ea2e6eecSWilly Tu std::optional<uint16_t>*, 364*ea2e6eecSWilly Tu std::optional<int16_t>*, 365*ea2e6eecSWilly Tu std::optional<uint32_t>*, 366*ea2e6eecSWilly Tu std::optional<int32_t>*, 367*ea2e6eecSWilly Tu std::optional<uint64_t>*, 368*ea2e6eecSWilly Tu std::optional<int64_t>*, 369*ea2e6eecSWilly Tu std::optional<bool>*, 370*ea2e6eecSWilly Tu std::optional<double>*, 371*ea2e6eecSWilly Tu std::optional<std::string>*, 372*ea2e6eecSWilly Tu std::optional<nlohmann::json>*, 373*ea2e6eecSWilly Tu std::optional<std::vector<uint8_t>>*, 374*ea2e6eecSWilly Tu std::optional<std::vector<uint16_t>>*, 375*ea2e6eecSWilly Tu std::optional<std::vector<int16_t>>*, 376*ea2e6eecSWilly Tu std::optional<std::vector<uint32_t>>*, 377*ea2e6eecSWilly Tu std::optional<std::vector<int32_t>>*, 378*ea2e6eecSWilly Tu std::optional<std::vector<uint64_t>>*, 379*ea2e6eecSWilly Tu std::optional<std::vector<int64_t>>*, 380*ea2e6eecSWilly Tu //std::optional<std::vector<bool>>*, 381*ea2e6eecSWilly Tu std::optional<std::vector<double>>*, 382*ea2e6eecSWilly Tu std::optional<std::vector<std::string>>*, 383*ea2e6eecSWilly Tu std::optional<std::vector<nlohmann::json>>* 384*ea2e6eecSWilly Tu >; 385*ea2e6eecSWilly Tu // clang-format on 386*ea2e6eecSWilly Tu 387*ea2e6eecSWilly Tu struct PerUnpack 388*ea2e6eecSWilly Tu { 389*ea2e6eecSWilly Tu std::string_view key; 390*ea2e6eecSWilly Tu UnpackVariant value; 391*ea2e6eecSWilly Tu bool complete = false; 392*ea2e6eecSWilly Tu }; 393*ea2e6eecSWilly Tu 394*ea2e6eecSWilly Tu inline bool readJsonHelper(nlohmann::json& jsonRequest, crow::Response& res, 395*ea2e6eecSWilly Tu std::span<PerUnpack> toUnpack) 3969712f8acSEd Tanous { 39741352c24SSantosh Puranik bool result = true; 3989712f8acSEd Tanous if (!jsonRequest.is_object()) 3999712f8acSEd Tanous { 4009712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Json value is not an object"; 401f12894f8SJason M. Bills messages::unrecognizedRequestBody(res); 4029712f8acSEd Tanous return false; 4039712f8acSEd Tanous } 404*ea2e6eecSWilly Tu for (auto& item : jsonRequest.items()) 4059712f8acSEd Tanous { 406*ea2e6eecSWilly Tu size_t unpackIndex = 0; 407*ea2e6eecSWilly Tu for (; unpackIndex < toUnpack.size(); unpackIndex++) 408*ea2e6eecSWilly Tu { 409*ea2e6eecSWilly Tu PerUnpack& unpackSpec = toUnpack[unpackIndex]; 410*ea2e6eecSWilly Tu std::string_view key = unpackSpec.key; 411*ea2e6eecSWilly Tu size_t keysplitIndex = key.find('/'); 412*ea2e6eecSWilly Tu std::string_view leftover; 413*ea2e6eecSWilly Tu if (keysplitIndex != std::string_view::npos) 414*ea2e6eecSWilly Tu { 415*ea2e6eecSWilly Tu leftover = key.substr(keysplitIndex + 1); 416*ea2e6eecSWilly Tu key = key.substr(0, keysplitIndex); 417*ea2e6eecSWilly Tu } 418*ea2e6eecSWilly Tu 419*ea2e6eecSWilly Tu if (key != item.key() || unpackSpec.complete) 420*ea2e6eecSWilly Tu { 421*ea2e6eecSWilly Tu continue; 422*ea2e6eecSWilly Tu } 423*ea2e6eecSWilly Tu 424*ea2e6eecSWilly Tu // Sublevel key 425*ea2e6eecSWilly Tu if (!leftover.empty()) 426*ea2e6eecSWilly Tu { 427*ea2e6eecSWilly Tu // Include the slash in the key so we can compare later 428*ea2e6eecSWilly Tu key = unpackSpec.key.substr(0, keysplitIndex + 1); 429*ea2e6eecSWilly Tu nlohmann::json j; 430*ea2e6eecSWilly Tu result = details::unpackValue<nlohmann::json>(item.value(), key, 431*ea2e6eecSWilly Tu res, j) && 43241352c24SSantosh Puranik result; 433*ea2e6eecSWilly Tu if (result == false) 434*ea2e6eecSWilly Tu { 435*ea2e6eecSWilly Tu return result; 4369712f8acSEd Tanous } 4379712f8acSEd Tanous 438*ea2e6eecSWilly Tu std::vector<PerUnpack> nextLevel; 439*ea2e6eecSWilly Tu for (PerUnpack& p : toUnpack) 440*ea2e6eecSWilly Tu { 441*ea2e6eecSWilly Tu if (!p.key.starts_with(key)) 442*ea2e6eecSWilly Tu { 443*ea2e6eecSWilly Tu continue; 444*ea2e6eecSWilly Tu } 445*ea2e6eecSWilly Tu std::string_view thisLeftover = p.key.substr(key.size()); 446*ea2e6eecSWilly Tu nextLevel.push_back({thisLeftover, p.value, false}); 447*ea2e6eecSWilly Tu p.complete = true; 4489712f8acSEd Tanous } 44977dd8813SKowalski, Kamil 450*ea2e6eecSWilly Tu result = readJsonHelper(j, res, nextLevel) && result; 451*ea2e6eecSWilly Tu break; 452*ea2e6eecSWilly Tu } 453*ea2e6eecSWilly Tu 454*ea2e6eecSWilly Tu result = 455*ea2e6eecSWilly Tu std::visit( 456*ea2e6eecSWilly Tu [&item, &unpackSpec, &res](auto&& val) { 457*ea2e6eecSWilly Tu using ContainedT = 458*ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 459*ea2e6eecSWilly Tu return details::unpackValue<ContainedT>( 460*ea2e6eecSWilly Tu item.value(), unpackSpec.key, res, *val); 461*ea2e6eecSWilly Tu }, 462*ea2e6eecSWilly Tu unpackSpec.value) && 463*ea2e6eecSWilly Tu result; 464*ea2e6eecSWilly Tu 465*ea2e6eecSWilly Tu unpackSpec.complete = true; 466*ea2e6eecSWilly Tu break; 467*ea2e6eecSWilly Tu } 468*ea2e6eecSWilly Tu 469*ea2e6eecSWilly Tu if (unpackIndex == toUnpack.size()) 470*ea2e6eecSWilly Tu { 471*ea2e6eecSWilly Tu messages::propertyUnknown(res, item.key()); 472*ea2e6eecSWilly Tu result = false; 473*ea2e6eecSWilly Tu } 474*ea2e6eecSWilly Tu } 475*ea2e6eecSWilly Tu 476*ea2e6eecSWilly Tu for (PerUnpack& perUnpack : toUnpack) 477*ea2e6eecSWilly Tu { 478*ea2e6eecSWilly Tu if (perUnpack.complete == false) 479*ea2e6eecSWilly Tu { 480*ea2e6eecSWilly Tu bool isOptional = std::visit( 481*ea2e6eecSWilly Tu [](auto&& val) { 482*ea2e6eecSWilly Tu using ContainedType = 483*ea2e6eecSWilly Tu std::remove_pointer_t<std::decay_t<decltype(val)>>; 484*ea2e6eecSWilly Tu return details::IsOptional<ContainedType>::value; 485*ea2e6eecSWilly Tu }, 486*ea2e6eecSWilly Tu perUnpack.value); 487*ea2e6eecSWilly Tu if (isOptional) 488*ea2e6eecSWilly Tu { 489*ea2e6eecSWilly Tu continue; 490*ea2e6eecSWilly Tu } 491*ea2e6eecSWilly Tu messages::propertyMissing(res, perUnpack.key); 492*ea2e6eecSWilly Tu result = false; 493*ea2e6eecSWilly Tu } 494*ea2e6eecSWilly Tu } 495*ea2e6eecSWilly Tu return result; 496*ea2e6eecSWilly Tu } 497*ea2e6eecSWilly Tu 498*ea2e6eecSWilly Tu inline void packVariant(std::span<PerUnpack> /*toPack*/) 499*ea2e6eecSWilly Tu {} 500*ea2e6eecSWilly Tu 501*ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 502*ea2e6eecSWilly Tu void packVariant(std::span<PerUnpack> toPack, std::string_view key, 503*ea2e6eecSWilly Tu FirstType& first, UnpackTypes&&... in) 504*ea2e6eecSWilly Tu { 505*ea2e6eecSWilly Tu if (toPack.empty()) 506*ea2e6eecSWilly Tu { 507*ea2e6eecSWilly Tu return; 508*ea2e6eecSWilly Tu } 509*ea2e6eecSWilly Tu toPack[0].key = key; 510*ea2e6eecSWilly Tu toPack[0].value = &first; 511*ea2e6eecSWilly Tu // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) 512*ea2e6eecSWilly Tu packVariant(toPack.subspan(1), std::forward<UnpackTypes&&>(in)...); 513*ea2e6eecSWilly Tu } 514*ea2e6eecSWilly Tu 515*ea2e6eecSWilly Tu template <typename FirstType, typename... UnpackTypes> 516*ea2e6eecSWilly Tu bool readJson(nlohmann::json& jsonRequest, crow::Response& res, 517*ea2e6eecSWilly Tu std::string_view key, FirstType&& first, UnpackTypes&&... in) 518*ea2e6eecSWilly Tu { 519*ea2e6eecSWilly Tu const std::size_t n = sizeof...(UnpackTypes) + 2; 520*ea2e6eecSWilly Tu std::array<PerUnpack, n / 2> toUnpack2; 521*ea2e6eecSWilly Tu packVariant(toUnpack2, key, first, std::forward<UnpackTypes&&>(in)...); 522*ea2e6eecSWilly Tu return readJsonHelper(jsonRequest, res, toUnpack2); 523*ea2e6eecSWilly Tu } 524*ea2e6eecSWilly Tu 525*ea2e6eecSWilly Tu inline std::optional<nlohmann::json> 526*ea2e6eecSWilly Tu readJsonPatchHelper(const crow::Request& req, crow::Response& res) 5270627a2c7SEd Tanous { 5280627a2c7SEd Tanous nlohmann::json jsonRequest; 5290627a2c7SEd Tanous if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 5300627a2c7SEd Tanous { 5310627a2c7SEd Tanous BMCWEB_LOG_DEBUG << "Json value not readable"; 532*ea2e6eecSWilly Tu return std::nullopt; 5330627a2c7SEd Tanous } 53415ed6780SWilly Tu 53515ed6780SWilly Tu if (jsonRequest.empty()) 53615ed6780SWilly Tu { 53715ed6780SWilly Tu BMCWEB_LOG_DEBUG << "Json value is empty"; 53815ed6780SWilly Tu messages::emptyJSON(res); 539*ea2e6eecSWilly Tu return std::nullopt; 540*ea2e6eecSWilly Tu } 541*ea2e6eecSWilly Tu return {std::move(jsonRequest)}; 542*ea2e6eecSWilly Tu } 543*ea2e6eecSWilly Tu 544*ea2e6eecSWilly Tu template <typename... UnpackTypes> 545*ea2e6eecSWilly Tu bool readJsonPatch(const crow::Request& req, crow::Response& res, 546*ea2e6eecSWilly Tu std::string_view key, UnpackTypes&&... in) 547*ea2e6eecSWilly Tu { 548*ea2e6eecSWilly Tu std::optional<nlohmann::json> jsonRequest = readJsonPatchHelper(req, res); 549*ea2e6eecSWilly Tu if (jsonRequest == std::nullopt) 550*ea2e6eecSWilly Tu { 55115ed6780SWilly Tu return false; 55215ed6780SWilly Tu } 55315ed6780SWilly Tu 554*ea2e6eecSWilly Tu return readJson(*jsonRequest, res, key, std::forward<UnpackTypes&&>(in)...); 55515ed6780SWilly Tu } 55615ed6780SWilly Tu 55715ed6780SWilly Tu template <typename... UnpackTypes> 55815ed6780SWilly Tu bool readJsonAction(const crow::Request& req, crow::Response& res, 559*ea2e6eecSWilly Tu const char* key, UnpackTypes&&... in) 56015ed6780SWilly Tu { 56115ed6780SWilly Tu nlohmann::json jsonRequest; 56215ed6780SWilly Tu if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 56315ed6780SWilly Tu { 56415ed6780SWilly Tu BMCWEB_LOG_DEBUG << "Json value not readable"; 56515ed6780SWilly Tu return false; 56615ed6780SWilly Tu } 567*ea2e6eecSWilly Tu return readJson(jsonRequest, res, key, std::forward<UnpackTypes&&>(in)...); 5680627a2c7SEd Tanous } 5690627a2c7SEd Tanous 57077dd8813SKowalski, Kamil } // namespace json_util 57177dd8813SKowalski, Kamil } // namespace redfish 572