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 namespace redfish
31 {
32 
33 // Sets up the Redfish Route and delegates some of the query parameter
34 // processing. |queryCapabilities| stores which query parameters will be
35 // handled by redfish-core/lib codes, then default query parameter handler won't
36 // process these parameters.
37 [[nodiscard]] inline bool setUpRedfishRouteWithDelegation(
38     crow::App& app, const crow::Request& req,
39     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40     query_param::Query& delegated,
41     const query_param::QueryCapabilities& queryCapabilities)
42 {
43     BMCWEB_LOG_DEBUG << "setup redfish route";
44 
45     // Section 7.4 of the redfish spec "Redfish Services shall process the
46     // [OData-Version header] in the following table as defined by the HTTP 1.1
47     // specification..."
48     // Required to pass redfish-protocol-validator REQ_HEADERS_ODATA_VERSION
49     std::string_view odataHeader = req.getHeaderValue("OData-Version");
50     if (!odataHeader.empty() && odataHeader != "4.0")
51     {
52         messages::preconditionFailed(asyncResp->res);
53         return false;
54     }
55 
56     asyncResp->res.addHeader("OData-Version", "4.0");
57 
58     std::optional<query_param::Query> queryOpt =
59         query_param::parseParameters(req.urlView.params(), asyncResp->res);
60     if (queryOpt == std::nullopt)
61     {
62         return false;
63     }
64 
65     // If this isn't a get, no need to do anything with parameters
66     if (req.method() != boost::beast::http::verb::get)
67     {
68         return true;
69     }
70 
71     delegated = query_param::delegate(queryCapabilities, *queryOpt);
72     std::function<void(crow::Response&)> handler =
73         asyncResp->res.releaseCompleteRequestHandler();
74     asyncResp->res.setCompleteRequestHandler(
75         [&app, handler(std::move(handler)),
76          query{*queryOpt}](crow::Response& resIn) mutable {
77         processAllParams(app, query, handler, resIn);
78     });
79     return true;
80 }
81 
82 // Sets up the Redfish Route. All parameters are handled by the default handler.
83 [[nodiscard]] inline bool
84     setUpRedfishRoute(crow::App& app, const crow::Request& req,
85                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
86 {
87     // This route |delegated| is never used
88     query_param::Query delegated;
89     return setUpRedfishRouteWithDelegation(app, req, asyncResp, delegated,
90                                            query_param::QueryCapabilities{});
91 }
92 } // namespace redfish
93