1*f4c99e70SEd Tanous #pragma once 2*f4c99e70SEd Tanous #include "app.hpp" 3*f4c99e70SEd Tanous #include "async_resp.hpp" 4*f4c99e70SEd Tanous #include "error_messages.hpp" 5*f4c99e70SEd Tanous #include "http_request.hpp" 6*f4c99e70SEd Tanous #include "routing.hpp" 7*f4c99e70SEd Tanous 8*f4c99e70SEd Tanous #include <string> 9*f4c99e70SEd Tanous #include <string_view> 10*f4c99e70SEd Tanous #include <vector> 11*f4c99e70SEd Tanous 12*f4c99e70SEd Tanous namespace redfish 13*f4c99e70SEd Tanous { 14*f4c99e70SEd Tanous namespace query_param 15*f4c99e70SEd Tanous { 16*f4c99e70SEd Tanous 17*f4c99e70SEd Tanous struct Query 18*f4c99e70SEd Tanous { 19*f4c99e70SEd Tanous bool isOnly = false; 20*f4c99e70SEd Tanous }; 21*f4c99e70SEd Tanous 22*f4c99e70SEd Tanous inline std::optional<Query> 23*f4c99e70SEd Tanous parseParameters(const boost::urls::params_view& urlParams, 24*f4c99e70SEd Tanous crow::Response& res) 25*f4c99e70SEd Tanous { 26*f4c99e70SEd Tanous Query ret; 27*f4c99e70SEd Tanous for (const boost::urls::params_view::value_type& it : urlParams) 28*f4c99e70SEd Tanous { 29*f4c99e70SEd Tanous std::string_view key(it.key.data(), it.key.size()); 30*f4c99e70SEd Tanous std::string_view value(it.value.data(), it.value.size()); 31*f4c99e70SEd Tanous if (key == "only") 32*f4c99e70SEd Tanous { 33*f4c99e70SEd Tanous if (!it.value.empty()) 34*f4c99e70SEd Tanous { 35*f4c99e70SEd Tanous messages::queryParameterValueFormatError(res, value, key); 36*f4c99e70SEd Tanous return std::nullopt; 37*f4c99e70SEd Tanous } 38*f4c99e70SEd Tanous ret.isOnly = true; 39*f4c99e70SEd Tanous } 40*f4c99e70SEd Tanous } 41*f4c99e70SEd Tanous return ret; 42*f4c99e70SEd Tanous } 43*f4c99e70SEd Tanous 44*f4c99e70SEd Tanous inline bool processOnly(crow::App& app, crow::Response& res, 45*f4c99e70SEd Tanous std::function<void(crow::Response&)>& completionHandler) 46*f4c99e70SEd Tanous { 47*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Processing only query param"; 48*f4c99e70SEd Tanous auto itMembers = res.jsonValue.find("Members"); 49*f4c99e70SEd Tanous if (itMembers == res.jsonValue.end()) 50*f4c99e70SEd Tanous { 51*f4c99e70SEd Tanous messages::queryNotSupportedOnResource(res); 52*f4c99e70SEd Tanous completionHandler(res); 53*f4c99e70SEd Tanous return false; 54*f4c99e70SEd Tanous } 55*f4c99e70SEd Tanous auto itMemBegin = itMembers->begin(); 56*f4c99e70SEd Tanous if (itMemBegin == itMembers->end() || itMembers->size() != 1) 57*f4c99e70SEd Tanous { 58*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Members contains " << itMembers->size() 59*f4c99e70SEd Tanous << " element, returning full collection."; 60*f4c99e70SEd Tanous completionHandler(res); 61*f4c99e70SEd Tanous return false; 62*f4c99e70SEd Tanous } 63*f4c99e70SEd Tanous 64*f4c99e70SEd Tanous auto itUrl = itMemBegin->find("@odata.id"); 65*f4c99e70SEd Tanous if (itUrl == itMemBegin->end()) 66*f4c99e70SEd Tanous { 67*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "No found odata.id"; 68*f4c99e70SEd Tanous messages::internalError(res); 69*f4c99e70SEd Tanous completionHandler(res); 70*f4c99e70SEd Tanous return false; 71*f4c99e70SEd Tanous } 72*f4c99e70SEd Tanous const std::string* url = itUrl->get_ptr<const std::string*>(); 73*f4c99e70SEd Tanous if (url == nullptr) 74*f4c99e70SEd Tanous { 75*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "@odata.id wasn't a string????"; 76*f4c99e70SEd Tanous messages::internalError(res); 77*f4c99e70SEd Tanous completionHandler(res); 78*f4c99e70SEd Tanous return false; 79*f4c99e70SEd Tanous } 80*f4c99e70SEd Tanous // TODO(Ed) copy request headers? 81*f4c99e70SEd Tanous // newReq.session = req.session; 82*f4c99e70SEd Tanous std::error_code ec; 83*f4c99e70SEd Tanous crow::Request newReq({boost::beast::http::verb::get, *url, 11}, ec); 84*f4c99e70SEd Tanous if (ec) 85*f4c99e70SEd Tanous { 86*f4c99e70SEd Tanous messages::internalError(res); 87*f4c99e70SEd Tanous completionHandler(res); 88*f4c99e70SEd Tanous return false; 89*f4c99e70SEd Tanous } 90*f4c99e70SEd Tanous 91*f4c99e70SEd Tanous auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 92*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "setting completion handler on " << &asyncResp->res; 93*f4c99e70SEd Tanous asyncResp->res.setCompleteRequestHandler(std::move(completionHandler)); 94*f4c99e70SEd Tanous asyncResp->res.setIsAliveHelper(res.releaseIsAliveHelper()); 95*f4c99e70SEd Tanous app.handle(newReq, asyncResp); 96*f4c99e70SEd Tanous return true; 97*f4c99e70SEd Tanous } 98*f4c99e70SEd Tanous 99*f4c99e70SEd Tanous void processAllParams(crow::App& app, Query query, 100*f4c99e70SEd Tanous crow::Response& intermediateResponse, 101*f4c99e70SEd Tanous std::function<void(crow::Response&)>& completionHandler) 102*f4c99e70SEd Tanous { 103*f4c99e70SEd Tanous if (!completionHandler) 104*f4c99e70SEd Tanous { 105*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Function was invalid?"; 106*f4c99e70SEd Tanous return; 107*f4c99e70SEd Tanous } 108*f4c99e70SEd Tanous 109*f4c99e70SEd Tanous BMCWEB_LOG_DEBUG << "Processing query params"; 110*f4c99e70SEd Tanous // If the request failed, there's no reason to even try to run query 111*f4c99e70SEd Tanous // params. 112*f4c99e70SEd Tanous if (intermediateResponse.resultInt() < 200 || 113*f4c99e70SEd Tanous intermediateResponse.resultInt() >= 400) 114*f4c99e70SEd Tanous { 115*f4c99e70SEd Tanous completionHandler(intermediateResponse); 116*f4c99e70SEd Tanous return; 117*f4c99e70SEd Tanous } 118*f4c99e70SEd Tanous if (query.isOnly) 119*f4c99e70SEd Tanous { 120*f4c99e70SEd Tanous processOnly(app, intermediateResponse, completionHandler); 121*f4c99e70SEd Tanous return; 122*f4c99e70SEd Tanous } 123*f4c99e70SEd Tanous completionHandler(intermediateResponse); 124*f4c99e70SEd Tanous } 125*f4c99e70SEd Tanous 126*f4c99e70SEd Tanous } // namespace query_param 127*f4c99e70SEd Tanous } // namespace redfish 128