summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2021-10-05 03:02:43 +0300
committerEd Tanous <ed@tanous.net>2022-04-05 21:50:46 +0300
commitf4c99e70dad320abf84fd25a32ad5fce2bf16f4a (patch)
treeabd2889eeab39f5b0b0dc0772260b3d29d16b58f /redfish-core
parentfa0b217fc0d4ec246d79055c463c1e7f573fd4c8 (diff)
downloadbmcweb-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.hpp36
-rw-r--r--redfish-core/include/utils/query_param.hpp127
-rw-r--r--redfish-core/lib/service_root.hpp4
-rw-r--r--redfish-core/lib/systems.hpp9
-rw-r--r--redfish-core/lib/ut/service_root_test.cpp3
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"]);