diff options
author | Nan Zhou <nanzhoumails@gmail.com> | 2022-04-04 23:10:40 +0300 |
---|---|---|
committer | Nan Zhou <nanzhoumails@gmail.com> | 2022-04-11 18:42:01 +0300 |
commit | a6b9125ff91500afed34dc923e9bafb90da75ec4 (patch) | |
tree | cd2861d1acf386de01aeaa19866adfb8759eced0 /redfish-core | |
parent | bacb216228c45ca715163f4c81717b1af39889ab (diff) | |
download | bmcweb-a6b9125ff91500afed34dc923e9bafb90da75ec4.tar.xz |
query parameter: add a way to delegate certain parameter
The generic query parameter handlers might not be performant, e.g.,
Expand in the sensor collections. This change adds a way to delegate
query parameter processsing to redfish-core codes:
1. introduced a separate struct in the setUpRedfishRoute function, with
which redfish-core codes can easily set delegation for each parameter;
for example, the children patch of this PR will implement an efficient
handler for sensor collection Expand, top, and skip.
2. introduced a separate Redfish route for delegation; this routes takes
the struct described above and changes the query object so that query
parameters are delegated.
3. in order to avoid copying Query objects and run delegation check
twice, the |setUpRedfishRouteWithDelegation| function sets |delegated|
so that callers can directly use it to determinte if delegation is
needed, and what delegated Queries are
Tested:
1. added unit tests
2. the default redfish route is still working correctly
Signed-off-by: Nan Zhou <nanzhoumails@gmail.com>
Change-Id: I77597ad7e8b40ac179d86dc9be1a35767cc61284
Diffstat (limited to 'redfish-core')
-rw-r--r-- | redfish-core/include/query.hpp | 24 | ||||
-rw-r--r-- | redfish-core/include/utils/query_param.hpp | 47 | ||||
-rw-r--r-- | redfish-core/include/utils/query_param_test.cpp | 61 |
3 files changed, 127 insertions, 5 deletions
diff --git a/redfish-core/include/query.hpp b/redfish-core/include/query.hpp index 7db370d9fb..4dd03c622c 100644 --- a/redfish-core/include/query.hpp +++ b/redfish-core/include/query.hpp @@ -7,9 +7,14 @@ namespace redfish { -[[nodiscard]] inline bool setUpRedfishRoute(crow::App& app, - const crow::Request& req, - crow::Response& res) +// 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]] inline bool setUpRedfishRouteWithDelegation( + crow::App& app, const crow::Request& req, crow::Response& res, + query_param::Query& delegated, + const query_param::QueryCapabilities& queryCapabilities) { BMCWEB_LOG_DEBUG << "setup redfish route"; @@ -42,9 +47,9 @@ namespace redfish return true; } + delegated = query_param::delegate(queryCapabilities, *queryOpt); std::function<void(crow::Response&)> handler = res.releaseCompleteRequestHandler(); - res.setCompleteRequestHandler( [&app, handler(std::move(handler)), query{*queryOpt}](crow::Response& res) mutable { @@ -52,4 +57,15 @@ namespace redfish }); return true; } + +// Sets up the Redfish Route. All parameters are handled by the default handler. +[[nodiscard]] inline bool setUpRedfishRoute(crow::App& app, + const crow::Request& req, + crow::Response& res) +{ + // This route |delegated| is never used + query_param::Query delegated; + return setUpRedfishRouteWithDelegation(app, req, res, delegated, + query_param::QueryCapabilities{}); +} } // namespace redfish diff --git a/redfish-core/include/utils/query_param.hpp b/redfish-core/include/utils/query_param.hpp index 7aef2f0923..60e572fccc 100644 --- a/redfish-core/include/utils/query_param.hpp +++ b/redfish-core/include/utils/query_param.hpp @@ -24,13 +24,58 @@ enum class ExpandType : uint8_t Both, }; +// The struct stores the parsed query parameters of the default Redfish route. struct Query { + // Only bool isOnly = false; - uint8_t expandLevel = 1; + // Expand + uint8_t expandLevel = 0; ExpandType expandType = ExpandType::None; }; +// 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; + uint8_t canDelegateExpandLevel = 0; +}; + +// Delegates query parameters according to the given |queryCapabilities| +// This function doesn't check query parameter conflicts since the parse +// function will take care of it. +// Returns a delegated query object which can be used by individual resource +// handlers so that handlers don't need to query again. +inline Query delegate(const QueryCapabilities& queryCapabilities, Query& query) +{ + Query delegated; + // delegate only + if (query.isOnly && queryCapabilities.canDelegateOnly) + { + delegated.isOnly = true; + query.isOnly = false; + } + // delegate expand as much as we can + if (query.expandType != ExpandType::None) + { + delegated.expandType = query.expandType; + if (query.expandLevel <= queryCapabilities.canDelegateExpandLevel) + { + query.expandType = ExpandType::None; + delegated.expandLevel = query.expandLevel; + query.expandLevel = 0; + } + else + { + query.expandLevel -= queryCapabilities.canDelegateExpandLevel; + delegated.expandLevel = queryCapabilities.canDelegateExpandLevel; + } + } + return delegated; +} + inline bool getExpandType(std::string_view value, Query& query) { if (value.empty()) diff --git a/redfish-core/include/utils/query_param_test.cpp b/redfish-core/include/utils/query_param_test.cpp index 69ed673f6d..7a2da712c2 100644 --- a/redfish-core/include/utils/query_param_test.cpp +++ b/redfish-core/include/utils/query_param_test.cpp @@ -7,6 +7,67 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +namespace redfish::query_param +{ +namespace +{ + +TEST(Delegate, OnlyPositive) +{ + Query query{ + .isOnly = true, + }; + QueryCapabilities capabilities{ + .canDelegateOnly = true, + }; + Query delegated = delegate(capabilities, query); + EXPECT_TRUE(delegated.isOnly); + EXPECT_FALSE(query.isOnly); +} + +TEST(Delegate, ExpandPositive) +{ + Query query{ + .isOnly = false, + .expandLevel = 5, + .expandType = ExpandType::Both, + }; + QueryCapabilities capabilities{ + .canDelegateExpandLevel = 3, + }; + Query delegated = delegate(capabilities, query); + EXPECT_FALSE(delegated.isOnly); + EXPECT_EQ(delegated.expandLevel, capabilities.canDelegateExpandLevel); + EXPECT_EQ(delegated.expandType, ExpandType::Both); + EXPECT_EQ(query.expandLevel, 2); +} + +TEST(Delegate, OnlyNegative) +{ + Query query{ + .isOnly = true, + }; + QueryCapabilities capabilities{ + .canDelegateOnly = false, + }; + Query delegated = delegate(capabilities, query); + EXPECT_FALSE(delegated.isOnly); + EXPECT_EQ(query.isOnly, true); +} + +TEST(Delegate, ExpandNegative) +{ + Query query{ + .isOnly = false, + .expandType = ExpandType::None, + }; + Query delegated = delegate(QueryCapabilities{}, query); + EXPECT_EQ(delegated.expandType, ExpandType::None); +} + +} // namespace +} // namespace redfish::query_param + TEST(QueryParams, ParseParametersOnly) { auto ret = boost::urls::parse_relative_ref("/redfish/v1?only"); |