summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2022-04-05 20:26:56 +0300
committerEd Tanous <ed@tanous.net>2022-05-10 19:08:25 +0300
commit2a68dc80d62482bfa886e78e536e223b84094ad3 (patch)
tree2b0618b7cfa94ead72eb0d3d02338cdfd7cc03d3
parent550a6bf85f81c1725b6c320a5ee419335cff2cf6 (diff)
downloadbmcweb-2a68dc80d62482bfa886e78e536e223b84094ad3.tar.xz
Implement $top and $skip
$top and $skip are parameters for controlling the responses of collections, to limit their size, per the Redfish specification section 7.4. $skip=integer "Applies to resource collections. Returns a subset of the members in a resource collection, or an empty set of members if the $skip value is greater than or equal to the member count. This paging query parameter defines the number of members in the resource collection to skip." $top=<integer> "Applies to resource collections. Defines the number of members to show in the response. Minimum value is 0 , though a value of 0 returns an empty set of members." This commit implements them within the resource query. Tested: curl --insecure --user root:0penBmc https://localhost:18080/redfish/v1/Registries\?\$top\=1 Returns 1 value. Walking through values of 1-5 (there are 4 registries currently) returns the appropriate sizes of collection (with 5 returning 4 entries). curl --insecure --user root:0penBmc https://localhost:18080/redfish/v1/Registries\?\$skip\=0 Returns the collection. $skip values of 0-5 return descending number of results. Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ied8a8f8338f119173509fb4b7ba2bd4a6c49cae8
-rw-r--r--redfish-core/include/utils/query_param.hpp48
-rw-r--r--redfish-core/include/utils/query_param_test.cpp67
2 files changed, 114 insertions, 1 deletions
diff --git a/redfish-core/include/utils/query_param.hpp b/redfish-core/include/utils/query_param.hpp
index b4a18a3ec2..5c43255de9 100644
--- a/redfish-core/include/utils/query_param.hpp
+++ b/redfish-core/include/utils/query_param.hpp
@@ -494,9 +494,49 @@ class MultiAsyncResp : public std::enable_shared_from_this<MultiAsyncResp>
std::shared_ptr<bmcweb::AsyncResp> finalRes;
};
+inline void processTopAndSkip(const Query& query, crow::Response& res)
+{
+ nlohmann::json::object_t* obj =
+ res.jsonValue.get_ptr<nlohmann::json::object_t*>();
+ if (obj == nullptr)
+ {
+ // Shouldn't be possible. All responses should be objects.
+ messages::internalError(res);
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "Handling top/skip";
+ nlohmann::json::object_t::iterator members = obj->find("Members");
+ if (members == obj->end())
+ {
+ // From the Redfish specification 7.3.1
+ // ... the HTTP 400 Bad Request status code with the
+ // QueryNotSupportedOnResource message from the Base Message Registry
+ // for any supported query parameters that apply only to resource
+ // collections but are used on singular resources.
+ messages::queryNotSupportedOnResource(res);
+ return;
+ }
+
+ nlohmann::json::array_t* arr =
+ members->second.get_ptr<nlohmann::json::array_t*>();
+ if (arr == nullptr)
+ {
+ messages::internalError(res);
+ return;
+ }
+
+ // Per section 7.3.1 of the Redfish specification, $skip is run before $top
+ // Can only skip as many values as we have
+ size_t skip = std::min(arr->size(), query.skip);
+ arr->erase(arr->begin(), arr->begin() + static_cast<ssize_t>(skip));
+
+ size_t top = std::min(arr->size(), query.top);
+ arr->erase(arr->begin() + static_cast<ssize_t>(top), arr->end());
+}
+
inline void
processAllParams(crow::App& app, const Query query,
-
std::function<void(crow::Response&)>& completionHandler,
crow::Response& intermediateResponse)
{
@@ -520,6 +560,12 @@ inline void
processOnly(app, intermediateResponse, completionHandler);
return;
}
+
+ if (query.top != std::numeric_limits<size_t>::max() || query.skip != 0)
+ {
+ processTopAndSkip(query, intermediateResponse);
+ }
+
if (query.expandType != ExpandType::None)
{
BMCWEB_LOG_DEBUG << "Executing expand query";
diff --git a/redfish-core/include/utils/query_param_test.cpp b/redfish-core/include/utils/query_param_test.cpp
index e5d8de753a..93013c2f3f 100644
--- a/redfish-core/include/utils/query_param_test.cpp
+++ b/redfish-core/include/utils/query_param_test.cpp
@@ -150,6 +150,73 @@ TEST(QueryParams, ParseParametersExpand)
}
}
+TEST(QueryParams, ParseParametersTop)
+{
+ auto ret = boost::urls::parse_relative_ref("/redfish/v1?$top=1");
+ ASSERT_TRUE(ret);
+
+ crow::Response res;
+
+ using redfish::query_param::parseParameters;
+ using redfish::query_param::Query;
+ std::optional<Query> query = parseParameters(ret->params(), res);
+ ASSERT_TRUE(query != std::nullopt);
+ EXPECT_EQ(query->top, 1);
+}
+
+TEST(QueryParams, ParseParametersTopOutOfRangeNegative)
+{
+ auto ret = boost::urls::parse_relative_ref("/redfish/v1?$top=-1");
+ ASSERT_TRUE(ret);
+
+ crow::Response res;
+
+ using redfish::query_param::parseParameters;
+ using redfish::query_param::Query;
+ std::optional<Query> query = parseParameters(ret->params(), res);
+ ASSERT_TRUE(query == std::nullopt);
+}
+
+TEST(QueryParams, ParseParametersTopOutOfRangePositive)
+{
+ auto ret = boost::urls::parse_relative_ref("/redfish/v1?$top=1001");
+ ASSERT_TRUE(ret);
+
+ crow::Response res;
+
+ using redfish::query_param::parseParameters;
+ using redfish::query_param::Query;
+ std::optional<Query> query = parseParameters(ret->params(), res);
+ ASSERT_TRUE(query == std::nullopt);
+}
+
+TEST(QueryParams, ParseParametersSkip)
+{
+ auto ret = boost::urls::parse_relative_ref("/redfish/v1?$skip=1");
+ ASSERT_TRUE(ret);
+
+ crow::Response res;
+
+ using redfish::query_param::parseParameters;
+ using redfish::query_param::Query;
+ std::optional<Query> query = parseParameters(ret->params(), res);
+ ASSERT_TRUE(query != std::nullopt);
+ EXPECT_EQ(query->skip, 1);
+}
+TEST(QueryParams, ParseParametersSkipOutOfRange)
+{
+ auto ret = boost::urls::parse_relative_ref(
+ "/redfish/v1?$skip=99999999999999999999");
+ ASSERT_TRUE(ret);
+
+ crow::Response res;
+
+ using redfish::query_param::parseParameters;
+ using redfish::query_param::Query;
+ std::optional<Query> query = parseParameters(ret->params(), res);
+ ASSERT_EQ(query, std::nullopt);
+}
+
TEST(QueryParams, ParseParametersUnexpectedGetsIgnored)
{
auto ret = boost::urls::parse_relative_ref("/redfish/v1?unexpected_param");