Support the $filter query params for SSE stream
This commit adds the support for $filter query
paramater in the URI for SSE stream.
Method: GET
URI: /redfish/v1/EventService/Subscriptions/SSE?
$filter=(MessageIds%20eq%20DCPowerOn) or
(MessageIds%20eq%20DCPowerOn)
Tested:
- From browser sent request using SSE URI along with filter query param
- query params were read and parsed successfully.
- used SubmitTestEvent and could see test events coming to BMC.
- Ran redfish validator successfully.
- Performed GET on Subscription collections and Subscription/<id> URI
and checked for valid data.
Change-Id: Ie18546749495175ede918ab933ff8dd1d65b775f
Signed-off-by: Ayushi Smriti <smriti.ayushi@linux.intel.com>
Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 03d5dc3..801a7ad 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -267,6 +267,95 @@
} // namespace event_log
#endif
+bool isFilterQuerySpecialChar(char c)
+{
+ switch (c)
+ {
+ case '(':
+ case ')':
+ case '\'':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool readSSEQueryParams(std::string sseFilter, std::string& formatType,
+ std::vector<std::string>& messageIds,
+ std::vector<std::string>& registryPrefixes,
+ std::vector<nlohmann::json>& metricReportDefinitions)
+{
+ sseFilter.erase(std::remove_if(sseFilter.begin(), sseFilter.end(),
+ isFilterQuerySpecialChar),
+ sseFilter.end());
+
+ std::vector<std::string> result;
+ boost::split(result, sseFilter, boost::is_any_of(" "),
+ boost::token_compress_on);
+
+ BMCWEB_LOG_DEBUG << "No of tokens in SEE query: " << result.size();
+
+ constexpr uint8_t divisor = 4;
+ constexpr uint8_t minTokenSize = 3;
+ if (result.size() % divisor != minTokenSize)
+ {
+ BMCWEB_LOG_ERROR << "Invalid SSE filter specified.";
+ return false;
+ }
+
+ for (std::size_t i = 0; i < result.size(); i += divisor)
+ {
+ std::string& key = result[i];
+ std::string& op = result[i + 1];
+ std::string& value = result[i + 2];
+
+ if ((i + minTokenSize) < result.size())
+ {
+ std::string& seperator = result[i + minTokenSize];
+ // SSE supports only "or" and "and" in query params.
+ if ((seperator != "or") && (seperator != "and"))
+ {
+ BMCWEB_LOG_ERROR
+ << "Invalid group operator in SSE query parameters";
+ return false;
+ }
+ }
+
+ // SSE supports only "eq" as per spec.
+ if (op != "eq")
+ {
+ BMCWEB_LOG_ERROR
+ << "Invalid assignment operator in SSE query parameters";
+ return false;
+ }
+
+ BMCWEB_LOG_DEBUG << key << " : " << value;
+ if (key == "EventFormatType")
+ {
+ formatType = value;
+ }
+ else if (key == "MessageId")
+ {
+ messageIds.push_back(value);
+ }
+ else if (key == "RegistryPrefix")
+ {
+ registryPrefixes.push_back(value);
+ }
+ else if (key == "MetricReportDefinition")
+ {
+ metricReportDefinitions.push_back(value);
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR << "Invalid property(" << key
+ << ")in SSE filter query.";
+ return false;
+ }
+ }
+ return true;
+}
+
class Subscription
{
public:
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index adb6238..da537bf 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -72,6 +72,14 @@
retryTimeoutInterval;
asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
+
+ nlohmann::json supportedSSEFilters = {
+ {"EventFormatType", true}, {"MessageId", true},
+ {"MetricReportDefinition", true}, {"RegistryPrefix", true},
+ {"OriginResource", false}, {"ResourceType", false}};
+
+ asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
+ supportedSSEFilters;
}
void doPatch(crow::Response& res, const crow::Request& req,
@@ -432,19 +440,61 @@
// GET on this URI means, Its SSE subscriptionType.
subValue->subscriptionType = "SSE";
+
+ // Default values
subValue->protocol = "Redfish";
+ subValue->retryPolicy = "TerminateAfterRetries";
char* filters = req.urlParams.get("$filter");
if (filters == nullptr)
{
subValue->eventFormatType = "Event";
- subValue->retryPolicy = "TerminateAfterRetries";
}
else
{
- // TODO: Need to read this from query params.
- subValue->eventFormatType = "Event";
- subValue->retryPolicy = "TerminateAfterRetries";
+ // Reading from query params.
+ bool status = readSSEQueryParams(
+ filters, subValue->eventFormatType, subValue->registryMsgIds,
+ subValue->registryPrefixes, subValue->metricReportDefinitions);
+
+ if (!status)
+ {
+ messages::invalidObject(res, filters);
+ return;
+ }
+
+ if (!subValue->eventFormatType.empty())
+ {
+ if (std::find(supportedEvtFormatTypes.begin(),
+ supportedEvtFormatTypes.end(),
+ subValue->eventFormatType) ==
+ supportedEvtFormatTypes.end())
+ {
+ messages::propertyValueNotInList(
+ res, subValue->eventFormatType, "EventFormatType");
+ return;
+ }
+ }
+ else
+ {
+ // If nothing specified, using default "Event"
+ subValue->eventFormatType.assign({"Event"});
+ }
+
+ if (!subValue->registryPrefixes.empty())
+ {
+ for (const std::string& it : subValue->registryPrefixes)
+ {
+ if (std::find(supportedRegPrefixes.begin(),
+ supportedRegPrefixes.end(),
+ it) == supportedRegPrefixes.end())
+ {
+ messages::propertyValueNotInList(res, it,
+ "RegistryPrefixes");
+ return;
+ }
+ }
+ }
}
std::string id =