Make log services use parameter delegation
The commit prior to this one added support for delegation of $expand and
$only query param types; This commit adds support for delegation of top
and skip (which we already have a few handlers for) and moves them to
the new style.
Note, this makes top and skip query params NOT below the
insecure-enable-redfish-query. top and skip have existed for a while,
and are unlikely to have security issues, as they're relatively simple
transforms.
Tested:
curl --insecure --user root:0penBmc https://192.168.7.2/redfish/v1/Managers/bmc/LogServices/Journal/Entries\?\$top\=3\&\$skip\=0
With varying $top between 1-5 and $skip between 0-5 gave the expected
number of log results.
Unit tests pass.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: Ia213a5e929c40579825eaf251e4b9159bc84c802
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 49911f3..3a8ce10 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -180,49 +180,6 @@
return true;
}
-static bool getSkipParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const crow::Request& req, uint64_t& skip)
-{
- boost::urls::params_view::iterator it = req.urlView.params().find("$skip");
- if (it != req.urlView.params().end())
- {
- std::from_chars_result r = std::from_chars(
- (*it).value.data(), (*it).value.data() + (*it).value.size(), skip);
- if (r.ec != std::errc())
- {
- messages::queryParameterValueTypeError(asyncResp->res, "", "$skip");
- return false;
- }
- }
- return true;
-}
-
-static constexpr const uint64_t maxEntriesPerPage = 1000;
-static bool getTopParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const crow::Request& req, uint64_t& top)
-{
- boost::urls::params_view::iterator it = req.urlView.params().find("$top");
- if (it != req.urlView.params().end())
- {
- std::from_chars_result r = std::from_chars(
- (*it).value.data(), (*it).value.data() + (*it).value.size(), top);
- if (r.ec != std::errc())
- {
- messages::queryParameterValueTypeError(asyncResp->res, "", "$top");
- return false;
- }
- if (top < 1U || top > maxEntriesPerPage)
- {
-
- messages::queryParameterOutOfRange(
- asyncResp->res, std::to_string(top), "$top",
- "1-" + std::to_string(maxEntriesPerPage));
- return false;
- }
- }
- return true;
-}
-
inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
const bool firstEntry = true)
{
@@ -1200,17 +1157,13 @@
const std::shared_ptr<
bmcweb::AsyncResp>&
asyncResp) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
- {
- return;
- }
- uint64_t skip = 0;
- uint64_t top = maxEntriesPerPage; // Show max entries by default
- if (!getSkipParam(asyncResp, req, skip))
- {
- return;
- }
- if (!getTopParam(asyncResp, req, top))
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateTop = true,
+ .canDelegateSkip = true,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, asyncResp->res, delegatedQuery, capabilities))
{
return;
}
@@ -1252,7 +1205,8 @@
// Handle paging using skip (number of entries to skip
// from the start) and top (number of entries to
// display)
- if (entryCount <= skip || entryCount > skip + top)
+ if (entryCount <= delegatedQuery.skip ||
+ entryCount > delegatedQuery.skip + delegatedQuery.top)
{
continue;
}
@@ -1279,11 +1233,11 @@
}
}
asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
- if (skip + top < entryCount)
+ if (delegatedQuery.skip + delegatedQuery.top < entryCount)
{
asyncResp->res.jsonValue["Members@odata.nextLink"] =
"/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
- std::to_string(skip + top);
+ std::to_string(delegatedQuery.skip + delegatedQuery.top);
}
});
}
@@ -1861,7 +1815,7 @@
inline bool
getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
- uint64_t& skip, uint64_t& top,
+ uint64_t skip, uint64_t top,
std::vector<std::string>& logEntries, size_t& logCount)
{
GzFileReader logFile;
@@ -1940,19 +1894,13 @@
const std::shared_ptr<
bmcweb::AsyncResp>&
asyncResp) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
- {
- return;
- }
- uint64_t skip = 0;
- uint64_t top = maxEntriesPerPage; // Show max 1000 entries by
- // default, allow range 1 to
- // 1000 entries per page.
- if (!getSkipParam(asyncResp, req, skip))
- {
- return;
- }
- if (!getTopParam(asyncResp, req, top))
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateTop = true,
+ .canDelegateSkip = true,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, asyncResp->res, delegatedQuery, capabilities))
{
return;
}
@@ -1978,8 +1926,8 @@
// This vector only store the entries we want to expose that
// control by skip and top.
std::vector<std::string> logEntries;
- if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
- logCount))
+ if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
+ delegatedQuery.top, logEntries, logCount))
{
messages::internalError(asyncResp->res);
return;
@@ -1997,16 +1945,18 @@
{
logEntryArray.push_back({});
nlohmann::json& hostLogEntry = logEntryArray.back();
- fillHostLoggerEntryJson(std::to_string(skip + i),
- logEntries[i], hostLogEntry);
+ fillHostLoggerEntryJson(
+ std::to_string(delegatedQuery.skip + i), logEntries[i],
+ hostLogEntry);
}
asyncResp->res.jsonValue["Members@odata.count"] = logCount;
- if (skip + top < logCount)
+ if (delegatedQuery.skip + delegatedQuery.top < logCount)
{
asyncResp->res.jsonValue["Members@odata.nextLink"] =
"/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
- std::to_string(skip + top);
+ std::to_string(delegatedQuery.skip +
+ delegatedQuery.top);
}
}
});
@@ -2219,18 +2169,13 @@
const std::shared_ptr<
bmcweb::AsyncResp>&
asyncResp) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
- {
- return;
- }
- static constexpr const long maxEntriesPerPage = 1000;
- uint64_t skip = 0;
- uint64_t top = maxEntriesPerPage; // Show max entries by default
- if (!getSkipParam(asyncResp, req, skip))
- {
- return;
- }
- if (!getTopParam(asyncResp, req, top))
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateTop = true,
+ .canDelegateSkip = true,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, asyncResp->res, delegatedQuery, capabilities))
{
return;
}
@@ -2268,7 +2213,8 @@
entryCount++;
// Handle paging using skip (number of entries to skip from
// the start) and top (number of entries to display)
- if (entryCount <= skip || entryCount > skip + top)
+ if (entryCount <= delegatedQuery.skip ||
+ entryCount > delegatedQuery.skip + delegatedQuery.top)
{
continue;
}
@@ -2294,11 +2240,11 @@
}
}
asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
- if (skip + top < entryCount)
+ if (delegatedQuery.skip + delegatedQuery.top < entryCount)
{
asyncResp->res.jsonValue["Members@odata.nextLink"] =
"/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
- std::to_string(skip + top);
+ std::to_string(delegatedQuery.skip + delegatedQuery.top);
}
});
}
@@ -3478,7 +3424,13 @@
.methods(boost::beast::http::verb::get)(
[&app](const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
+ query_param::QueryCapabilities capabilities = {
+ .canDelegateTop = true,
+ .canDelegateSkip = true,
+ };
+ query_param::Query delegatedQuery;
+ if (!redfish::setUpRedfishRouteWithDelegation(
+ app, req, asyncResp->res, delegatedQuery, capabilities))
{
return;
}
@@ -3492,17 +3444,8 @@
asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
asyncResp->res.jsonValue["Members@odata.count"] = 0;
- uint64_t skip = 0;
- uint64_t top = maxEntriesPerPage; // Show max entries by default
- if (!getSkipParam(asyncResp, req, skip))
- {
- return;
- }
- if (!getTopParam(asyncResp, req, top))
- {
- return;
- }
- getCurrentBootNumber(asyncResp, skip, top);
+ getCurrentBootNumber(asyncResp, delegatedQuery.skip,
+ delegatedQuery.top);
});
}