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