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