| #pragma once |
| |
| #include "app.hpp" |
| #include "app_singleton.hpp" |
| #include "async_resp.hpp" |
| #include "http_request.hpp" |
| #include "http_response.hpp" |
| #include "logging.hpp" |
| |
| #include <boost/beast/http/verb.hpp> |
| #include <boost/url/params_view.hpp> |
| #include <boost/url/url_view.hpp> |
| |
| #include <functional> |
| #include <memory> |
| #include <new> |
| #include <optional> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <utility> |
| |
| // IWYU pragma: no_forward_declare crow::App |
| // IWYU pragma: no_include <boost/url/impl/params_view.hpp> |
| // IWYU pragma: no_include <boost/url/impl/url_view.hpp> |
| |
| namespace redfish |
| { |
| |
| namespace query_param |
| { |
| enum class ExpandType : uint8_t |
| { |
| None, |
| Links, |
| NotLinks, |
| Both, |
| }; |
| |
| // A simple implementation of Trie to help |recursiveSelect|. |
| class SelectTrieNode |
| { |
| public: |
| SelectTrieNode() = default; |
| |
| const SelectTrieNode* find(const std::string& jsonKey) const |
| { |
| auto it = children.find(jsonKey); |
| if (it == children.end()) |
| { |
| return nullptr; |
| } |
| return &it->second; |
| } |
| |
| // Creates a new node if the key doesn't exist, returns the reference to the |
| // newly created node; otherwise, return the reference to the existing node |
| SelectTrieNode* emplace(std::string_view jsonKey) |
| { |
| auto [it, _] = children.emplace(jsonKey, SelectTrieNode{}); |
| return &it->second; |
| } |
| |
| bool empty() const |
| { |
| return children.empty(); |
| } |
| |
| void clear() |
| { |
| children.clear(); |
| } |
| |
| void setToSelected() |
| { |
| selected = true; |
| } |
| |
| bool isSelected() const |
| { |
| return selected; |
| } |
| |
| private: |
| std::map<std::string, SelectTrieNode, std::less<>> children; |
| bool selected = false; |
| }; |
| |
| struct SelectTrie |
| { |
| SelectTrie() = default; |
| |
| // Inserts a $select value; returns false if the nestedProperty is illegal. |
| bool insertNode(std::string_view nestedProperty); |
| |
| SelectTrieNode root; |
| }; |
| |
| // The struct stores the parsed query parameters of the default Redfish route. |
| struct Query |
| { |
| // Only |
| bool isOnly = false; |
| // Expand |
| uint8_t expandLevel = 0; |
| ExpandType expandType = ExpandType::None; |
| |
| // Skip |
| std::optional<size_t> skip = std::nullopt; |
| |
| // Top |
| static constexpr size_t maxTop = 1000; // Max entries a response contain |
| std::optional<size_t> top = std::nullopt; |
| |
| // Select |
| SelectTrie selectTrie = {}; // NOLINT |
| |
| // Filter |
| // We only support delegate filter for now. |
| // Unless explicitly enable canDelegateFilter capability, common queries |
| // won't parse $filter in the query. |
| std::string filter = ""; // NOLINT |
| }; |
| |
| // The struct defines how resource handlers in redfish-core/lib/ can handle |
| // query parameters themselves, so that the default Redfish route will delegate |
| // the processing. |
| struct QueryCapabilities |
| { |
| bool canDelegateOnly = false; |
| bool canDelegateTop = false; |
| bool canDelegateSkip = false; |
| uint8_t canDelegateExpandLevel = 0; |
| bool canDelegateSelect = false; |
| bool canDelegateFilter = false; |
| bool canHandleSubscription = false; |
| }; |
| |
| struct ExpandNode |
| { |
| nlohmann::json::json_pointer location; |
| std::string uri; |
| |
| inline bool operator==(const ExpandNode& other) const |
| { |
| return location == other.location && uri == other.uri; |
| } |
| }; |
| |
| Query delegate(const QueryCapabilities& queryCapabilities, Query& query, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp); |
| std::optional<std::string> formatQueryForExpand(const Query& query); |
| bool isSelectedPropertyAllowed(std::string_view property); |
| bool getSelectParam(std::string_view value, Query& query); |
| void recursiveSelect(nlohmann::json& currRoot, const SelectTrieNode& currNode); |
| unsigned propogateErrorCode(unsigned finalCode, unsigned subResponseCode); |
| void propogateError(crow::Response& finalResponse, crow::Response& subResponse); |
| std::optional<Query> parseParameters(boost::urls::params_view urlParams, |
| crow::Response& res); |
| bool getExpandType(std::string_view value, Query& query); |
| std::vector<ExpandNode> findNavigationReferences(ExpandType eType, int depth, |
| nlohmann::json& jsonResponse); |
| } // namespace query_param |
| |
| // Sets up the Redfish Route and delegates some of the query parameter |
| // processing. |queryCapabilities| stores which query parameters will be |
| // handled by redfish-core/lib codes, then default query parameter handler won't |
| // process these parameters. |
| [[nodiscard]] bool setUpRedfishRouteWithDelegation( |
| crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| query_param::Query& delegated, |
| const query_param::QueryCapabilities& queryCapabilities); |
| |
| // Sets up the Redfish Route. All parameters are handled by the default handler. |
| [[nodiscard]] inline bool |
| setUpRedfishRoute(crow::App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| // This route |delegated| is never used |
| query_param::Query delegated; |
| return setUpRedfishRouteWithDelegation(app, req, asyncResp, delegated, |
| query_param::QueryCapabilities{}); |
| } |
| |
| // See |setUpRedfishRouteWithDelegation| above for documentation. |
| [[nodiscard]] inline bool setUpRedfishRouteWithDelegationOnGlobalApp( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| query_param::Query& delegated, |
| const query_param::QueryCapabilities& queryCapabilities) |
| { |
| return setUpRedfishRouteWithDelegation( |
| *crow::globalBmcWebApp, req, asyncResp, delegated, queryCapabilities); |
| } |
| |
| // See |setUpRedfishRoute| above for documentation. |
| [[nodiscard]] inline bool |
| setUpRedfishRouteOnGlobalApp(const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| return setUpRedfishRoute(*crow::globalBmcWebApp, req, asyncResp); |
| } |
| |
| } // namespace redfish |