1 #pragma once 2 3 #include "bmcweb_config.h" 4 5 #include "app.hpp" 6 #include "async_resp.hpp" 7 #include "error_messages.hpp" 8 #include "http_request.hpp" 9 #include "http_response.hpp" 10 #include "logging.hpp" 11 #include "utils/query_param.hpp" 12 13 #include <boost/beast/http/verb.hpp> 14 #include <boost/url/params_view.hpp> 15 #include <boost/url/url_view.hpp> 16 17 #include <functional> 18 #include <memory> 19 #include <new> 20 #include <optional> 21 #include <string> 22 #include <string_view> 23 #include <type_traits> 24 #include <utility> 25 26 // IWYU pragma: no_forward_declare crow::App 27 // IWYU pragma: no_include <boost/url/impl/params_view.hpp> 28 // IWYU pragma: no_include <boost/url/impl/url_view.hpp> 29 30 #include <redfish_aggregator.hpp> 31 32 namespace redfish 33 { 34 35 // Sets up the Redfish Route and delegates some of the query parameter 36 // processing. |queryCapabilities| stores which query parameters will be 37 // handled by redfish-core/lib codes, then default query parameter handler won't 38 // process these parameters. 39 [[nodiscard]] inline bool setUpRedfishRouteWithDelegation( 40 crow::App& app, const crow::Request& req, 41 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42 query_param::Query& delegated, 43 const query_param::QueryCapabilities& queryCapabilities) 44 { 45 BMCWEB_LOG_DEBUG << "setup redfish route"; 46 47 // Section 7.4 of the redfish spec "Redfish Services shall process the 48 // [OData-Version header] in the following table as defined by the HTTP 1.1 49 // specification..." 50 // Required to pass redfish-protocol-validator REQ_HEADERS_ODATA_VERSION 51 std::string_view odataHeader = req.getHeaderValue("OData-Version"); 52 if (!odataHeader.empty() && odataHeader != "4.0") 53 { 54 messages::preconditionFailed(asyncResp->res); 55 return false; 56 } 57 58 asyncResp->res.addHeader("OData-Version", "4.0"); 59 60 std::optional<query_param::Query> queryOpt = 61 query_param::parseParameters(req.urlView.params(), asyncResp->res); 62 if (queryOpt == std::nullopt) 63 { 64 return false; 65 } 66 67 bool needToCallHandlers = true; 68 69 #ifdef BMCWEB_ENABLE_REDFISH_AGGREGATION 70 needToCallHandlers = RedfishAggregator::getInstance().beginAggregation( 71 req, asyncResp) == Result::LocalHandle; 72 73 // If the request should be forwarded to a satellite BMC then we don't want 74 // to write anything to the asyncResp since it will get overwritten later. 75 #endif 76 77 // If this isn't a get, no need to do anything with parameters 78 if (req.method() != boost::beast::http::verb::get) 79 { 80 return needToCallHandlers; 81 } 82 83 delegated = query_param::delegate(queryCapabilities, *queryOpt); 84 std::function<void(crow::Response&)> handler = 85 asyncResp->res.releaseCompleteRequestHandler(); 86 87 asyncResp->res.setCompleteRequestHandler( 88 [&app, handler(std::move(handler)), 89 query{std::move(*queryOpt)}](crow::Response& resIn) mutable { 90 processAllParams(app, query, handler, resIn); 91 }); 92 93 return needToCallHandlers; 94 } 95 96 // Sets up the Redfish Route. All parameters are handled by the default handler. 97 [[nodiscard]] inline bool 98 setUpRedfishRoute(crow::App& app, const crow::Request& req, 99 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 100 { 101 // This route |delegated| is never used 102 query_param::Query delegated; 103 return setUpRedfishRouteWithDelegation(app, req, asyncResp, delegated, 104 query_param::QueryCapabilities{}); 105 } 106 } // namespace redfish 107