diff options
author | Ed Tanous <edtanous@google.com> | 2021-10-05 03:02:43 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2022-04-05 21:50:46 +0300 |
commit | f4c99e70dad320abf84fd25a32ad5fce2bf16f4a (patch) | |
tree | abd2889eeab39f5b0b0dc0772260b3d29d16b58f /redfish-core | |
parent | fa0b217fc0d4ec246d79055c463c1e7f573fd4c8 (diff) | |
download | bmcweb-f4c99e70dad320abf84fd25a32ad5fce2bf16f4a.tar.xz |
Redfish: Query parameters: Only
Add the query parameter "only" for redfish.
The specification is based on DSP0266_1.8.0.
This commit is inspired by the commit that carries the same title, but
is largely unique, namely, in that it adds the core feature to be able
to recall handle with a new Response object, and make sure the result
gets to the connection. It does this by swapping the handlers and
implementing move semantics on the Response object. It definitely needs
broken up into a few smaller patches, but it does pass the below tests
without any apparent seg faults or ownership issues.
It implements a number of cleanups that deserve their own patches, and
will be split up accordingly, but for the moment, I think this is a good
start to getting filter and expand support in the future.
Tested:
Validator passes (on previous patchset)
~$ curl -i -k -H "X-Auth-Token: $token" -X GET "https://${bmc}/redfish/v1/Systems"
~$ curl -i -k -H "X-Auth-Token: $token" -X GET "https://${bmc}/redfish/v1/Systems?only"
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I123d8ab8bcd88a0b63ff131f6b98548951989755
Diffstat (limited to 'redfish-core')
-rw-r--r-- | redfish-core/include/query.hpp | 36 | ||||
-rw-r--r-- | redfish-core/include/utils/query_param.hpp | 127 | ||||
-rw-r--r-- | redfish-core/lib/service_root.hpp | 4 | ||||
-rw-r--r-- | redfish-core/lib/systems.hpp | 9 | ||||
-rw-r--r-- | redfish-core/lib/ut/service_root_test.cpp | 3 |
5 files changed, 175 insertions, 4 deletions
diff --git a/redfish-core/include/query.hpp b/redfish-core/include/query.hpp new file mode 100644 index 0000000000..44f07ba048 --- /dev/null +++ b/redfish-core/include/query.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "utils/query_param.hpp" + +#include <bmcweb_config.h> + +namespace redfish +{ + +[[nodiscard]] inline bool setUpRedfishRoute(crow::App& app, + const crow::Request& req, + crow::Response& res) +{ + // If query parameters aren't enabled, do nothing. + if constexpr (!bmcwebInsecureEnableQueryParams) + { + return true; + } + std::optional<query_param::Query> queryOpt = + query_param::parseParameters(req.urlView.params(), res); + if (queryOpt == std::nullopt) + { + return false; + } + + std::function<void(crow::Response&)> handler = + res.releaseCompleteRequestHandler(); + + res.setCompleteRequestHandler( + [&app, handler(std::move(handler)), + query{*queryOpt}](crow::Response& res) mutable { + processAllParams(app, query, res, handler); + }); + return true; +} +} // namespace redfish diff --git a/redfish-core/include/utils/query_param.hpp b/redfish-core/include/utils/query_param.hpp new file mode 100644 index 0000000000..d4ff81f5f3 --- /dev/null +++ b/redfish-core/include/utils/query_param.hpp @@ -0,0 +1,127 @@ +#pragma once +#include "app.hpp" +#include "async_resp.hpp" +#include "error_messages.hpp" +#include "http_request.hpp" +#include "routing.hpp" + +#include <string> +#include <string_view> +#include <vector> + +namespace redfish +{ +namespace query_param +{ + +struct Query +{ + bool isOnly = false; +}; + +inline std::optional<Query> + parseParameters(const boost::urls::params_view& urlParams, + crow::Response& res) +{ + Query ret; + for (const boost::urls::params_view::value_type& it : urlParams) + { + std::string_view key(it.key.data(), it.key.size()); + std::string_view value(it.value.data(), it.value.size()); + if (key == "only") + { + if (!it.value.empty()) + { + messages::queryParameterValueFormatError(res, value, key); + return std::nullopt; + } + ret.isOnly = true; + } + } + return ret; +} + +inline bool processOnly(crow::App& app, crow::Response& res, + std::function<void(crow::Response&)>& completionHandler) +{ + BMCWEB_LOG_DEBUG << "Processing only query param"; + auto itMembers = res.jsonValue.find("Members"); + if (itMembers == res.jsonValue.end()) + { + messages::queryNotSupportedOnResource(res); + completionHandler(res); + return false; + } + auto itMemBegin = itMembers->begin(); + if (itMemBegin == itMembers->end() || itMembers->size() != 1) + { + BMCWEB_LOG_DEBUG << "Members contains " << itMembers->size() + << " element, returning full collection."; + completionHandler(res); + return false; + } + + auto itUrl = itMemBegin->find("@odata.id"); + if (itUrl == itMemBegin->end()) + { + BMCWEB_LOG_DEBUG << "No found odata.id"; + messages::internalError(res); + completionHandler(res); + return false; + } + const std::string* url = itUrl->get_ptr<const std::string*>(); + if (url == nullptr) + { + BMCWEB_LOG_DEBUG << "@odata.id wasn't a string????"; + messages::internalError(res); + completionHandler(res); + return false; + } + // TODO(Ed) copy request headers? + // newReq.session = req.session; + std::error_code ec; + crow::Request newReq({boost::beast::http::verb::get, *url, 11}, ec); + if (ec) + { + messages::internalError(res); + completionHandler(res); + return false; + } + + auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); + BMCWEB_LOG_DEBUG << "setting completion handler on " << &asyncResp->res; + asyncResp->res.setCompleteRequestHandler(std::move(completionHandler)); + asyncResp->res.setIsAliveHelper(res.releaseIsAliveHelper()); + app.handle(newReq, asyncResp); + return true; +} + +void processAllParams(crow::App& app, Query query, + crow::Response& intermediateResponse, + std::function<void(crow::Response&)>& completionHandler) +{ + if (!completionHandler) + { + BMCWEB_LOG_DEBUG << "Function was invalid?"; + return; + } + + BMCWEB_LOG_DEBUG << "Processing query params"; + // If the request failed, there's no reason to even try to run query + // params. + if (intermediateResponse.resultInt() < 200 || + intermediateResponse.resultInt() >= 400) + { + completionHandler(intermediateResponse); + return; + } + if (query.isOnly) + { + processOnly(app, intermediateResponse, completionHandler); + return; + } + completionHandler(intermediateResponse); +} + +} // namespace query_param +} // namespace redfish diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp index e2f32bbef9..696d6fd025 100644 --- a/redfish-core/lib/service_root.hpp +++ b/redfish-core/lib/service_root.hpp @@ -15,6 +15,8 @@ */ #pragma once +#include <bmcweb_config.h> + #include <app.hpp> #include <async_resp.hpp> #include <http_request.hpp> @@ -76,7 +78,7 @@ inline void protocolFeatures["ExpandQuery"]["Links"] = false; protocolFeatures["ExpandQuery"]["NoLinks"] = false; protocolFeatures["FilterQuery"] = false; - protocolFeatures["OnlyMemberQuery"] = false; + protocolFeatures["OnlyMemberQuery"] = bmcwebInsecureEnableQueryParams; protocolFeatures["SelectQuery"] = false; protocolFeatures["DeepOperations"]["DeepPOST"] = false; protocolFeatures["DeepOperations"]["DeepPATCH"] = false; diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp index 429e99242c..83f9dadf3e 100644 --- a/redfish-core/lib/systems.hpp +++ b/redfish-core/lib/systems.hpp @@ -19,6 +19,7 @@ #include "health.hpp" #include "led.hpp" #include "pcie.hpp" +#include "query.hpp" #include "redfish_util.hpp" #include <app.hpp> @@ -2652,8 +2653,12 @@ inline void requestRoutesSystemsCollection(App& app) BMCWEB_ROUTE(app, "/redfish/v1/Systems/") .privileges(redfish::privileges::getComputerSystemCollection) .methods(boost::beast::http::verb::get)( - [](const crow::Request& /*req*/, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { + [&app](const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { + if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) + { + return; + } asyncResp->res.jsonValue["@odata.type"] = "#ComputerSystemCollection.ComputerSystemCollection"; asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; diff --git a/redfish-core/lib/ut/service_root_test.cpp b/redfish-core/lib/ut/service_root_test.cpp index 61b0d02f9a..4c05751f09 100644 --- a/redfish-core/lib/ut/service_root_test.cpp +++ b/redfish-core/lib/ut/service_root_test.cpp @@ -73,7 +73,8 @@ static void assertServiceRootGet(crow::Response& res) EXPECT_FALSE(json["ProtocolFeaturesSupported"]["ExpandQuery"]["NoLinks"]); EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"].size(), 4); EXPECT_FALSE(json["ProtocolFeaturesSupported"]["FilterQuery"]); - EXPECT_FALSE(json["ProtocolFeaturesSupported"]["OnlyMemberQuery"]); + EXPECT_EQ(json["ProtocolFeaturesSupported"]["OnlyMemberQuery"], + bmcwebInsecureEnableQueryParams); EXPECT_FALSE(json["ProtocolFeaturesSupported"]["SelectQuery"]); EXPECT_FALSE( json["ProtocolFeaturesSupported"]["DeepOperations"]["DeepPOST"]); |