1f4c99e70SEd Tanous #pragma once 2f4c99e70SEd Tanous #include "app.hpp" 3f4c99e70SEd Tanous #include "async_resp.hpp" 4f4c99e70SEd Tanous #include "error_messages.hpp" 5f4c99e70SEd Tanous #include "http_request.hpp" 6f4c99e70SEd Tanous #include "routing.hpp" 7f4c99e70SEd Tanous 87cf436c9SEd Tanous #include <charconv> 9f4c99e70SEd Tanous #include <string> 10f4c99e70SEd Tanous #include <string_view> 117cf436c9SEd Tanous #include <utility> 12f4c99e70SEd Tanous #include <vector> 13f4c99e70SEd Tanous 14f4c99e70SEd Tanous namespace redfish 15f4c99e70SEd Tanous { 16f4c99e70SEd Tanous namespace query_param 17f4c99e70SEd Tanous { 18f4c99e70SEd Tanous 197cf436c9SEd Tanous enum class ExpandType : uint8_t 207cf436c9SEd Tanous { 217cf436c9SEd Tanous None, 227cf436c9SEd Tanous Links, 237cf436c9SEd Tanous NotLinks, 247cf436c9SEd Tanous Both, 257cf436c9SEd Tanous }; 267cf436c9SEd Tanous 27*a6b9125fSNan Zhou // The struct stores the parsed query parameters of the default Redfish route. 28f4c99e70SEd Tanous struct Query 29f4c99e70SEd Tanous { 30*a6b9125fSNan Zhou // Only 31f4c99e70SEd Tanous bool isOnly = false; 32*a6b9125fSNan Zhou // Expand 33*a6b9125fSNan Zhou uint8_t expandLevel = 0; 347cf436c9SEd Tanous ExpandType expandType = ExpandType::None; 35f4c99e70SEd Tanous }; 36f4c99e70SEd Tanous 37*a6b9125fSNan Zhou // The struct defines how resource handlers in redfish-core/lib/ can handle 38*a6b9125fSNan Zhou // query parameters themselves, so that the default Redfish route will delegate 39*a6b9125fSNan Zhou // the processing. 40*a6b9125fSNan Zhou struct QueryCapabilities 41*a6b9125fSNan Zhou { 42*a6b9125fSNan Zhou bool canDelegateOnly = false; 43*a6b9125fSNan Zhou uint8_t canDelegateExpandLevel = 0; 44*a6b9125fSNan Zhou }; 45*a6b9125fSNan Zhou 46*a6b9125fSNan Zhou // Delegates query parameters according to the given |queryCapabilities| 47*a6b9125fSNan Zhou // This function doesn't check query parameter conflicts since the parse 48*a6b9125fSNan Zhou // function will take care of it. 49*a6b9125fSNan Zhou // Returns a delegated query object which can be used by individual resource 50*a6b9125fSNan Zhou // handlers so that handlers don't need to query again. 51*a6b9125fSNan Zhou inline Query delegate(const QueryCapabilities& queryCapabilities, Query& query) 52*a6b9125fSNan Zhou { 53*a6b9125fSNan Zhou Query delegated; 54*a6b9125fSNan Zhou // delegate only 55*a6b9125fSNan Zhou if (query.isOnly && queryCapabilities.canDelegateOnly) 56*a6b9125fSNan Zhou { 57*a6b9125fSNan Zhou delegated.isOnly = true; 58*a6b9125fSNan Zhou query.isOnly = false; 59*a6b9125fSNan Zhou } 60*a6b9125fSNan Zhou // delegate expand as much as we can 61*a6b9125fSNan Zhou if (query.expandType != ExpandType::None) 62*a6b9125fSNan Zhou { 63*a6b9125fSNan Zhou delegated.expandType = query.expandType; 64*a6b9125fSNan Zhou if (query.expandLevel <= queryCapabilities.canDelegateExpandLevel) 65*a6b9125fSNan Zhou { 66*a6b9125fSNan Zhou query.expandType = ExpandType::None; 67*a6b9125fSNan Zhou delegated.expandLevel = query.expandLevel; 68*a6b9125fSNan Zhou query.expandLevel = 0; 69*a6b9125fSNan Zhou } 70*a6b9125fSNan Zhou else 71*a6b9125fSNan Zhou { 72*a6b9125fSNan Zhou query.expandLevel -= queryCapabilities.canDelegateExpandLevel; 73*a6b9125fSNan Zhou delegated.expandLevel = queryCapabilities.canDelegateExpandLevel; 74*a6b9125fSNan Zhou } 75*a6b9125fSNan Zhou } 76*a6b9125fSNan Zhou return delegated; 77*a6b9125fSNan Zhou } 78*a6b9125fSNan Zhou 797cf436c9SEd Tanous inline bool getExpandType(std::string_view value, Query& query) 807cf436c9SEd Tanous { 817cf436c9SEd Tanous if (value.empty()) 827cf436c9SEd Tanous { 837cf436c9SEd Tanous return false; 847cf436c9SEd Tanous } 857cf436c9SEd Tanous switch (value[0]) 867cf436c9SEd Tanous { 877cf436c9SEd Tanous case '*': 887cf436c9SEd Tanous query.expandType = ExpandType::Both; 897cf436c9SEd Tanous break; 907cf436c9SEd Tanous case '.': 917cf436c9SEd Tanous query.expandType = ExpandType::NotLinks; 927cf436c9SEd Tanous break; 937cf436c9SEd Tanous case '~': 947cf436c9SEd Tanous query.expandType = ExpandType::Links; 957cf436c9SEd Tanous break; 967cf436c9SEd Tanous default: 977cf436c9SEd Tanous return false; 987cf436c9SEd Tanous 997cf436c9SEd Tanous break; 1007cf436c9SEd Tanous } 1017cf436c9SEd Tanous value.remove_prefix(1); 1027cf436c9SEd Tanous if (value.empty()) 1037cf436c9SEd Tanous { 1047cf436c9SEd Tanous query.expandLevel = 1; 1057cf436c9SEd Tanous return true; 1067cf436c9SEd Tanous } 1077cf436c9SEd Tanous constexpr std::string_view levels = "($levels="; 1087cf436c9SEd Tanous if (!value.starts_with(levels)) 1097cf436c9SEd Tanous { 1107cf436c9SEd Tanous return false; 1117cf436c9SEd Tanous } 1127cf436c9SEd Tanous value.remove_prefix(levels.size()); 1137cf436c9SEd Tanous 1147cf436c9SEd Tanous auto it = std::from_chars(value.data(), value.data() + value.size(), 1157cf436c9SEd Tanous query.expandLevel); 1167cf436c9SEd Tanous if (it.ec != std::errc()) 1177cf436c9SEd Tanous { 1187cf436c9SEd Tanous return false; 1197cf436c9SEd Tanous } 1207cf436c9SEd Tanous value.remove_prefix(static_cast<size_t>(it.ptr - value.data())); 1217cf436c9SEd Tanous return value == ")"; 1227cf436c9SEd Tanous } 1237cf436c9SEd Tanous 124f4c99e70SEd Tanous inline std::optional<Query> 125f4c99e70SEd Tanous parseParameters(const boost::urls::params_view& urlParams, 126f4c99e70SEd Tanous crow::Response& res) 127f4c99e70SEd Tanous { 128f4c99e70SEd Tanous Query ret; 129f4c99e70SEd Tanous for (const boost::urls::params_view::value_type& it : urlParams) 130f4c99e70SEd Tanous { 131f4c99e70SEd Tanous std::string_view key(it.key.data(), it.key.size()); 132f4c99e70SEd Tanous std::string_view value(it.value.data(), it.value.size()); 133f4c99e70SEd Tanous if (key == "only") 134f4c99e70SEd Tanous { 135f4c99e70SEd Tanous if (!it.value.empty()) 136f4c99e70SEd Tanous { 137f4c99e70SEd Tanous messages::queryParameterValueFormatError(res, value, key); 138f4c99e70SEd Tanous return std::nullopt; 139f4c99e70SEd Tanous } 140f4c99e70SEd Tanous ret.isOnly = true; 141f4c99e70SEd Tanous } 1427cf436c9SEd Tanous else if (key == "$expand") 1437cf436c9SEd Tanous { 1447cf436c9SEd Tanous if (!getExpandType(value, ret)) 1457cf436c9SEd Tanous { 1467cf436c9SEd Tanous messages::queryParameterValueFormatError(res, value, key); 1477cf436c9SEd Tanous return std::nullopt; 148f4c99e70SEd Tanous } 1497cf436c9SEd Tanous } 1507cf436c9SEd Tanous else 1517cf436c9SEd Tanous { 1527cf436c9SEd Tanous // Intentionally ignore other errors Redfish spec, 7.3.1 1537cf436c9SEd Tanous if (key.starts_with("$")) 1547cf436c9SEd Tanous { 1557cf436c9SEd Tanous // Services shall return... The HTTP 501 Not Implemented 1567cf436c9SEd Tanous // status code for any unsupported query parameters that 1577cf436c9SEd Tanous // start with $ . 1587cf436c9SEd Tanous messages::queryParameterValueFormatError(res, value, key); 1597cf436c9SEd Tanous res.result(boost::beast::http::status::not_implemented); 1607cf436c9SEd Tanous return std::nullopt; 1617cf436c9SEd Tanous } 1627cf436c9SEd Tanous // "Shall ignore unknown or unsupported query parameters that do 1637cf436c9SEd Tanous // not begin with $ ." 1647cf436c9SEd Tanous } 1657cf436c9SEd Tanous } 1667cf436c9SEd Tanous 167f4c99e70SEd Tanous return ret; 168f4c99e70SEd Tanous } 169f4c99e70SEd Tanous 170f4c99e70SEd Tanous inline bool processOnly(crow::App& app, crow::Response& res, 171f4c99e70SEd Tanous std::function<void(crow::Response&)>& completionHandler) 172f4c99e70SEd Tanous { 173f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Processing only query param"; 174f4c99e70SEd Tanous auto itMembers = res.jsonValue.find("Members"); 175f4c99e70SEd Tanous if (itMembers == res.jsonValue.end()) 176f4c99e70SEd Tanous { 177f4c99e70SEd Tanous messages::queryNotSupportedOnResource(res); 178f4c99e70SEd Tanous completionHandler(res); 179f4c99e70SEd Tanous return false; 180f4c99e70SEd Tanous } 181f4c99e70SEd Tanous auto itMemBegin = itMembers->begin(); 182f4c99e70SEd Tanous if (itMemBegin == itMembers->end() || itMembers->size() != 1) 183f4c99e70SEd Tanous { 184f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Members contains " << itMembers->size() 185f4c99e70SEd Tanous << " element, returning full collection."; 186f4c99e70SEd Tanous completionHandler(res); 187f4c99e70SEd Tanous return false; 188f4c99e70SEd Tanous } 189f4c99e70SEd Tanous 190f4c99e70SEd Tanous auto itUrl = itMemBegin->find("@odata.id"); 191f4c99e70SEd Tanous if (itUrl == itMemBegin->end()) 192f4c99e70SEd Tanous { 193f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "No found odata.id"; 194f4c99e70SEd Tanous messages::internalError(res); 195f4c99e70SEd Tanous completionHandler(res); 196f4c99e70SEd Tanous return false; 197f4c99e70SEd Tanous } 198f4c99e70SEd Tanous const std::string* url = itUrl->get_ptr<const std::string*>(); 199f4c99e70SEd Tanous if (url == nullptr) 200f4c99e70SEd Tanous { 201f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "@odata.id wasn't a string????"; 202f4c99e70SEd Tanous messages::internalError(res); 203f4c99e70SEd Tanous completionHandler(res); 204f4c99e70SEd Tanous return false; 205f4c99e70SEd Tanous } 206f4c99e70SEd Tanous // TODO(Ed) copy request headers? 207f4c99e70SEd Tanous // newReq.session = req.session; 208f4c99e70SEd Tanous std::error_code ec; 209f4c99e70SEd Tanous crow::Request newReq({boost::beast::http::verb::get, *url, 11}, ec); 210f4c99e70SEd Tanous if (ec) 211f4c99e70SEd Tanous { 212f4c99e70SEd Tanous messages::internalError(res); 213f4c99e70SEd Tanous completionHandler(res); 214f4c99e70SEd Tanous return false; 215f4c99e70SEd Tanous } 216f4c99e70SEd Tanous 217f4c99e70SEd Tanous auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 218f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "setting completion handler on " << &asyncResp->res; 219f4c99e70SEd Tanous asyncResp->res.setCompleteRequestHandler(std::move(completionHandler)); 220f4c99e70SEd Tanous asyncResp->res.setIsAliveHelper(res.releaseIsAliveHelper()); 221f4c99e70SEd Tanous app.handle(newReq, asyncResp); 222f4c99e70SEd Tanous return true; 223f4c99e70SEd Tanous } 224f4c99e70SEd Tanous 2257cf436c9SEd Tanous struct ExpandNode 2267cf436c9SEd Tanous { 2277cf436c9SEd Tanous nlohmann::json::json_pointer location; 2287cf436c9SEd Tanous std::string uri; 2297cf436c9SEd Tanous 2307cf436c9SEd Tanous inline bool operator==(const ExpandNode& other) const 2317cf436c9SEd Tanous { 2327cf436c9SEd Tanous return location == other.location && uri == other.uri; 2337cf436c9SEd Tanous } 2347cf436c9SEd Tanous }; 2357cf436c9SEd Tanous 2367cf436c9SEd Tanous // Walks a json object looking for Redfish NavigationReference entries that 2377cf436c9SEd Tanous // might need resolved. It recursively walks the jsonResponse object, looking 2387cf436c9SEd Tanous // for links at every level, and returns a list (out) of locations within the 2397cf436c9SEd Tanous // tree that need to be expanded. The current json pointer location p is passed 2407cf436c9SEd Tanous // in to reference the current node that's being expanded, so it can be combined 2417cf436c9SEd Tanous // with the keys from the jsonResponse object 2427cf436c9SEd Tanous inline void findNavigationReferencesRecursive( 2437cf436c9SEd Tanous ExpandType eType, nlohmann::json& jsonResponse, 2447cf436c9SEd Tanous const nlohmann::json::json_pointer& p, bool inLinks, 2457cf436c9SEd Tanous std::vector<ExpandNode>& out) 2467cf436c9SEd Tanous { 2477cf436c9SEd Tanous // If no expand is needed, return early 2487cf436c9SEd Tanous if (eType == ExpandType::None) 2497cf436c9SEd Tanous { 2507cf436c9SEd Tanous return; 2517cf436c9SEd Tanous } 2527cf436c9SEd Tanous nlohmann::json::array_t* array = 2537cf436c9SEd Tanous jsonResponse.get_ptr<nlohmann::json::array_t*>(); 2547cf436c9SEd Tanous if (array != nullptr) 2557cf436c9SEd Tanous { 2567cf436c9SEd Tanous size_t index = 0; 2577cf436c9SEd Tanous // For arrays, walk every element in the array 2587cf436c9SEd Tanous for (auto& element : *array) 2597cf436c9SEd Tanous { 2607cf436c9SEd Tanous nlohmann::json::json_pointer newPtr = p / index; 2617cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "Traversing response at " << newPtr.to_string(); 2627cf436c9SEd Tanous findNavigationReferencesRecursive(eType, element, newPtr, inLinks, 2637cf436c9SEd Tanous out); 2647cf436c9SEd Tanous index++; 2657cf436c9SEd Tanous } 2667cf436c9SEd Tanous } 2677cf436c9SEd Tanous nlohmann::json::object_t* obj = 2687cf436c9SEd Tanous jsonResponse.get_ptr<nlohmann::json::object_t*>(); 2697cf436c9SEd Tanous if (obj == nullptr) 2707cf436c9SEd Tanous { 2717cf436c9SEd Tanous return; 2727cf436c9SEd Tanous } 2737cf436c9SEd Tanous // Navigation References only ever have a single element 2747cf436c9SEd Tanous if (obj->size() == 1) 2757cf436c9SEd Tanous { 2767cf436c9SEd Tanous if (obj->begin()->first == "@odata.id") 2777cf436c9SEd Tanous { 2787cf436c9SEd Tanous const std::string* uri = 2797cf436c9SEd Tanous obj->begin()->second.get_ptr<const std::string*>(); 2807cf436c9SEd Tanous if (uri != nullptr) 2817cf436c9SEd Tanous { 2827cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "Found element at " << p.to_string(); 2837cf436c9SEd Tanous out.push_back({p, *uri}); 2847cf436c9SEd Tanous } 2857cf436c9SEd Tanous } 2867cf436c9SEd Tanous } 2877cf436c9SEd Tanous // Loop the object and look for links 2887cf436c9SEd Tanous for (auto& element : *obj) 2897cf436c9SEd Tanous { 2907cf436c9SEd Tanous if (!inLinks) 2917cf436c9SEd Tanous { 2927cf436c9SEd Tanous // Check if this is a links node 2937cf436c9SEd Tanous inLinks = element.first == "Links"; 2947cf436c9SEd Tanous } 2957cf436c9SEd Tanous // Only traverse the parts of the tree the user asked for 2967cf436c9SEd Tanous // Per section 7.3 of the redfish specification 2977cf436c9SEd Tanous if (inLinks && eType == ExpandType::NotLinks) 2987cf436c9SEd Tanous { 2997cf436c9SEd Tanous continue; 3007cf436c9SEd Tanous } 3017cf436c9SEd Tanous if (!inLinks && eType == ExpandType::Links) 3027cf436c9SEd Tanous { 3037cf436c9SEd Tanous continue; 3047cf436c9SEd Tanous } 3057cf436c9SEd Tanous nlohmann::json::json_pointer newPtr = p / element.first; 3067cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "Traversing response at " << newPtr; 3077cf436c9SEd Tanous 3087cf436c9SEd Tanous findNavigationReferencesRecursive(eType, element.second, newPtr, 3097cf436c9SEd Tanous inLinks, out); 3107cf436c9SEd Tanous } 3117cf436c9SEd Tanous } 3127cf436c9SEd Tanous 3137cf436c9SEd Tanous inline std::vector<ExpandNode> 3147cf436c9SEd Tanous findNavigationReferences(ExpandType eType, nlohmann::json& jsonResponse, 3157cf436c9SEd Tanous const nlohmann::json::json_pointer& root) 3167cf436c9SEd Tanous { 3177cf436c9SEd Tanous std::vector<ExpandNode> ret; 3187cf436c9SEd Tanous findNavigationReferencesRecursive(eType, jsonResponse, root, false, ret); 3197cf436c9SEd Tanous return ret; 3207cf436c9SEd Tanous } 3217cf436c9SEd Tanous 3227cf436c9SEd Tanous class MultiAsyncResp : public std::enable_shared_from_this<MultiAsyncResp> 3237cf436c9SEd Tanous { 3247cf436c9SEd Tanous public: 3257cf436c9SEd Tanous // This object takes a single asyncResp object as the "final" one, then 3267cf436c9SEd Tanous // allows callers to attach sub-responses within the json tree that need 3277cf436c9SEd Tanous // to be executed and filled into their appropriate locations. This 3287cf436c9SEd Tanous // class manages the final "merge" of the json resources. 3297cf436c9SEd Tanous MultiAsyncResp(crow::App& app, 3307cf436c9SEd Tanous std::shared_ptr<bmcweb::AsyncResp> finalResIn) : 3317cf436c9SEd Tanous app(app), 3327cf436c9SEd Tanous finalRes(std::move(finalResIn)) 3337cf436c9SEd Tanous {} 3347cf436c9SEd Tanous 3357cf436c9SEd Tanous void addAwaitingResponse( 3367cf436c9SEd Tanous Query query, std::shared_ptr<bmcweb::AsyncResp>& res, 3377cf436c9SEd Tanous const nlohmann::json::json_pointer& finalExpandLocation) 3387cf436c9SEd Tanous { 3397cf436c9SEd Tanous res->res.setCompleteRequestHandler(std::bind_front( 3407cf436c9SEd Tanous onEndStatic, shared_from_this(), query, finalExpandLocation)); 3417cf436c9SEd Tanous } 3427cf436c9SEd Tanous 3437cf436c9SEd Tanous void onEnd(Query query, const nlohmann::json::json_pointer& locationToPlace, 3447cf436c9SEd Tanous crow::Response& res) 3457cf436c9SEd Tanous { 3467cf436c9SEd Tanous nlohmann::json& finalObj = finalRes->res.jsonValue[locationToPlace]; 3477cf436c9SEd Tanous finalObj = std::move(res.jsonValue); 3487cf436c9SEd Tanous 3497cf436c9SEd Tanous if (query.expandLevel <= 0) 3507cf436c9SEd Tanous { 3517cf436c9SEd Tanous // Last level to expand, no need to go deeper 3527cf436c9SEd Tanous return; 3537cf436c9SEd Tanous } 3547cf436c9SEd Tanous // Now decrease the depth by one to account for the tree node we 3557cf436c9SEd Tanous // just resolved 3567cf436c9SEd Tanous query.expandLevel--; 3577cf436c9SEd Tanous 3587cf436c9SEd Tanous std::vector<ExpandNode> nodes = findNavigationReferences( 3597cf436c9SEd Tanous query.expandType, finalObj, locationToPlace); 3607cf436c9SEd Tanous BMCWEB_LOG_DEBUG << nodes.size() << " nodes to traverse"; 3617cf436c9SEd Tanous for (const ExpandNode& node : nodes) 3627cf436c9SEd Tanous { 3637cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "Expanding " << locationToPlace; 3647cf436c9SEd Tanous std::error_code ec; 3657cf436c9SEd Tanous crow::Request newReq({boost::beast::http::verb::get, node.uri, 11}, 3667cf436c9SEd Tanous ec); 3677cf436c9SEd Tanous if (ec) 3687cf436c9SEd Tanous { 3697cf436c9SEd Tanous messages::internalError(res); 3707cf436c9SEd Tanous return; 3717cf436c9SEd Tanous } 3727cf436c9SEd Tanous 3737cf436c9SEd Tanous auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 3747cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "setting completion handler on " 3757cf436c9SEd Tanous << &asyncResp->res; 3767cf436c9SEd Tanous addAwaitingResponse(query, asyncResp, node.location); 3777cf436c9SEd Tanous app.handle(newReq, asyncResp); 3787cf436c9SEd Tanous } 3797cf436c9SEd Tanous } 3807cf436c9SEd Tanous 3817cf436c9SEd Tanous private: 3827cf436c9SEd Tanous static void onEndStatic(const std::shared_ptr<MultiAsyncResp>& multi, 3837cf436c9SEd Tanous Query query, 3847cf436c9SEd Tanous const nlohmann::json::json_pointer& locationToPlace, 3857cf436c9SEd Tanous crow::Response& res) 3867cf436c9SEd Tanous { 3877cf436c9SEd Tanous multi->onEnd(query, locationToPlace, res); 3887cf436c9SEd Tanous } 3897cf436c9SEd Tanous 3907cf436c9SEd Tanous crow::App& app; 3917cf436c9SEd Tanous std::shared_ptr<bmcweb::AsyncResp> finalRes; 3927cf436c9SEd Tanous }; 3937cf436c9SEd Tanous 3947cf436c9SEd Tanous inline void 3957cf436c9SEd Tanous processAllParams(crow::App& app, const Query query, 3967cf436c9SEd Tanous 3977cf436c9SEd Tanous std::function<void(crow::Response&)>& completionHandler, 3987cf436c9SEd Tanous crow::Response& intermediateResponse) 399f4c99e70SEd Tanous { 400f4c99e70SEd Tanous if (!completionHandler) 401f4c99e70SEd Tanous { 402f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Function was invalid?"; 403f4c99e70SEd Tanous return; 404f4c99e70SEd Tanous } 405f4c99e70SEd Tanous 406f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Processing query params"; 407f4c99e70SEd Tanous // If the request failed, there's no reason to even try to run query 408f4c99e70SEd Tanous // params. 409f4c99e70SEd Tanous if (intermediateResponse.resultInt() < 200 || 410f4c99e70SEd Tanous intermediateResponse.resultInt() >= 400) 411f4c99e70SEd Tanous { 412f4c99e70SEd Tanous completionHandler(intermediateResponse); 413f4c99e70SEd Tanous return; 414f4c99e70SEd Tanous } 415f4c99e70SEd Tanous if (query.isOnly) 416f4c99e70SEd Tanous { 417f4c99e70SEd Tanous processOnly(app, intermediateResponse, completionHandler); 418f4c99e70SEd Tanous return; 419f4c99e70SEd Tanous } 4207cf436c9SEd Tanous if (query.expandType != ExpandType::None) 4217cf436c9SEd Tanous { 4227cf436c9SEd Tanous BMCWEB_LOG_DEBUG << "Executing expand query"; 4237cf436c9SEd Tanous // TODO(ed) this is a copy of the response object. Admittedly, 4247cf436c9SEd Tanous // we're inherently doing something inefficient, but we shouldn't 4257cf436c9SEd Tanous // have to do a full copy 4267cf436c9SEd Tanous auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 4277cf436c9SEd Tanous asyncResp->res.setCompleteRequestHandler(std::move(completionHandler)); 4287cf436c9SEd Tanous asyncResp->res.jsonValue = std::move(intermediateResponse.jsonValue); 4297cf436c9SEd Tanous auto multi = std::make_shared<MultiAsyncResp>(app, asyncResp); 4307cf436c9SEd Tanous 4317cf436c9SEd Tanous // Start the chain by "ending" the root response 4327cf436c9SEd Tanous multi->onEnd(query, nlohmann::json::json_pointer(""), asyncResp->res); 4337cf436c9SEd Tanous return; 4347cf436c9SEd Tanous } 435f4c99e70SEd Tanous completionHandler(intermediateResponse); 436f4c99e70SEd Tanous } 437f4c99e70SEd Tanous 438f4c99e70SEd Tanous } // namespace query_param 439f4c99e70SEd Tanous } // namespace redfish 440