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 1877dd8813SKowalski, Kamil #include <crow/http_request.h> 1977dd8813SKowalski, Kamil #include <crow/http_response.h> 2077dd8813SKowalski, Kamil 219712f8acSEd Tanous #include <bitset> 229712f8acSEd Tanous #include <error_messages.hpp> 231abe55efSEd Tanous #include <nlohmann/json.hpp> 241abe55efSEd Tanous namespace redfish 251abe55efSEd Tanous { 261abe55efSEd Tanous 271abe55efSEd Tanous namespace json_util 281abe55efSEd Tanous { 2977dd8813SKowalski, Kamil 3077dd8813SKowalski, Kamil /** 3177dd8813SKowalski, Kamil * @brief Processes request to extract JSON from its body. If it fails, adds 3277dd8813SKowalski, Kamil * MalformedJSON message to response and ends it. 3377dd8813SKowalski, Kamil * 3477dd8813SKowalski, Kamil * @param[io] res Response object 3577dd8813SKowalski, Kamil * @param[in] req Request object 3677dd8813SKowalski, Kamil * @param[out] reqJson JSON object extracted from request's body 3777dd8813SKowalski, Kamil * 3877dd8813SKowalski, Kamil * @return true if JSON is valid, false when JSON is invalid and response has 3977dd8813SKowalski, Kamil * been filled with message and ended. 4077dd8813SKowalski, Kamil */ 4155c7b7a2SEd Tanous bool processJsonFromRequest(crow::Response& res, const crow::Request& req, 4277dd8813SKowalski, Kamil nlohmann::json& reqJson); 439712f8acSEd Tanous namespace details 449712f8acSEd Tanous { 459712f8acSEd Tanous template <typename Type> struct unpackValue 469712f8acSEd Tanous { 479712f8acSEd Tanous using isRequired = std::true_type; 489712f8acSEd Tanous using JsonType = std::add_const_t<std::add_pointer_t<Type>>; 499712f8acSEd Tanous }; 509712f8acSEd Tanous 519712f8acSEd Tanous template <typename OptionalType> 529712f8acSEd Tanous struct unpackValue<boost::optional<OptionalType>> 539712f8acSEd Tanous { 549712f8acSEd Tanous using isRequired = std::false_type; 559712f8acSEd Tanous using JsonType = std::add_const_t<std::add_pointer_t<OptionalType>>; 569712f8acSEd Tanous }; 579712f8acSEd Tanous 589712f8acSEd Tanous template <size_t Count, size_t Index> 599712f8acSEd Tanous void readJsonValues(const std::string& key, nlohmann::json& jsonValue, 609712f8acSEd Tanous crow::Response& res, std::bitset<Count>& handled) 619712f8acSEd Tanous { 629712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Unable to find variable for key" << key; 63*a08b46ccSJason M. Bills messages::propertyUnknown(res, key); 649712f8acSEd Tanous } 659712f8acSEd Tanous 669712f8acSEd Tanous template <size_t Count, size_t Index, typename ValueType, 679712f8acSEd Tanous typename... UnpackTypes> 689712f8acSEd Tanous void readJsonValues(const std::string& key, nlohmann::json& jsonValue, 699712f8acSEd Tanous crow::Response& res, std::bitset<Count>& handled, 709712f8acSEd Tanous const char* keyToCheck, ValueType& valueToFill, 719712f8acSEd Tanous UnpackTypes&... in) 729712f8acSEd Tanous { 739712f8acSEd Tanous if (key != keyToCheck) 749712f8acSEd Tanous { 759712f8acSEd Tanous readJsonValues<Count, Index + 1>(key, jsonValue, res, handled, in...); 769712f8acSEd Tanous return; 779712f8acSEd Tanous } 789712f8acSEd Tanous 799712f8acSEd Tanous handled.set(Index); 809712f8acSEd Tanous 819712f8acSEd Tanous using UnpackType = typename unpackValue<ValueType>::JsonType; 829712f8acSEd Tanous UnpackType value = jsonValue.get_ptr<UnpackType>(); 839712f8acSEd Tanous if (value == nullptr) 849712f8acSEd Tanous { 859712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Value for key " << key 869712f8acSEd Tanous << " was incorrect type: " << jsonValue.type_name(); 87*a08b46ccSJason M. Bills messages::propertyValueTypeError(res, jsonValue.dump(), key); 889712f8acSEd Tanous return; 899712f8acSEd Tanous } 909712f8acSEd Tanous 919712f8acSEd Tanous valueToFill = *value; 929712f8acSEd Tanous } 939712f8acSEd Tanous 949712f8acSEd Tanous template <size_t Index = 0, size_t Count> 959712f8acSEd Tanous void handleMissing(std::bitset<Count>& handled, crow::Response& res) 969712f8acSEd Tanous { 979712f8acSEd Tanous } 989712f8acSEd Tanous 999712f8acSEd Tanous template <size_t Index = 0, size_t Count, typename ValueType, 1009712f8acSEd Tanous typename... UnpackTypes> 1019712f8acSEd Tanous void handleMissing(std::bitset<Count>& handled, crow::Response& res, 1029712f8acSEd Tanous const char* key, ValueType& unused, UnpackTypes&... in) 1039712f8acSEd Tanous { 1049712f8acSEd Tanous if (!handled.test(Index) && unpackValue<ValueType>::isRequired::value) 1059712f8acSEd Tanous { 106*a08b46ccSJason M. Bills messages::propertyMissing(res, key); 1079712f8acSEd Tanous } 1089712f8acSEd Tanous details::handleMissing<Index + 1, Count>(handled, res, in...); 1099712f8acSEd Tanous } 1109712f8acSEd Tanous } // namespace details 1119712f8acSEd Tanous 1129712f8acSEd Tanous template <typename... UnpackTypes> 1139712f8acSEd Tanous bool readJson(const crow::Request& req, crow::Response& res, const char* key, 1149712f8acSEd Tanous UnpackTypes&... in) 1159712f8acSEd Tanous { 1169712f8acSEd Tanous nlohmann::json jsonRequest; 1179712f8acSEd Tanous if (!json_util::processJsonFromRequest(res, req, jsonRequest)) 1189712f8acSEd Tanous { 1199712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Json value not readable"; 1209712f8acSEd Tanous return false; 1219712f8acSEd Tanous } 1229712f8acSEd Tanous if (!jsonRequest.is_object()) 1239712f8acSEd Tanous { 1249712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Json value is not an object"; 125f12894f8SJason M. Bills messages::unrecognizedRequestBody(res); 1269712f8acSEd Tanous return false; 1279712f8acSEd Tanous } 1289712f8acSEd Tanous 1299712f8acSEd Tanous if (jsonRequest.empty()) 1309712f8acSEd Tanous { 1319712f8acSEd Tanous BMCWEB_LOG_DEBUG << "Json value is empty"; 132f12894f8SJason M. Bills messages::emptyJSON(res); 1339712f8acSEd Tanous return false; 1349712f8acSEd Tanous } 1359712f8acSEd Tanous 1369712f8acSEd Tanous std::bitset<(sizeof...(in) + 1) / 2> handled(0); 1379712f8acSEd Tanous for (const auto& item : jsonRequest.items()) 1389712f8acSEd Tanous { 1399712f8acSEd Tanous details::readJsonValues<(sizeof...(in) + 1) / 2, 0, UnpackTypes...>( 1409712f8acSEd Tanous item.key(), item.value(), res, handled, key, in...); 1419712f8acSEd Tanous } 1429712f8acSEd Tanous 1439712f8acSEd Tanous details::handleMissing(handled, res, key, in...); 1449712f8acSEd Tanous 1459712f8acSEd Tanous return res.result() == boost::beast::http::status::ok; 1469712f8acSEd Tanous } 14777dd8813SKowalski, Kamil 14877dd8813SKowalski, Kamil } // namespace json_util 14977dd8813SKowalski, Kamil } // namespace redfish 150