Implement odata annotations ignoring
From the quoted section of the spec in the patchset, we should be
ignoring odata annotations on PATCH requests. This commit implements a
preliminary loop through the json object, and removes the odata items
before processing begins.
Tested:
curl -vvvv --insecure --user root:0penBmc -X PATCH -d '{"@odata.etag":
"my_etag"}' https://192.168.7.2/redfish/v1/AccountService/Accounts/root
returns: Base.1.11.0.NoOperation
Redfish protocol validator now passes the REQ_PATCH_ODATA_PROPS test.
Included unit tests passing.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I62be75342681d147b8536fd122bbc793eeaa3788
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
index b688576..317cf11 100644
--- a/redfish-core/include/utils/json_utils.hpp
+++ b/redfish-core/include/utils/json_utils.hpp
@@ -531,13 +531,27 @@
BMCWEB_LOG_DEBUG << "Json value not readable";
return std::nullopt;
}
-
- if (jsonRequest.empty())
+ nlohmann::json::object_t* object =
+ jsonRequest.get_ptr<nlohmann::json::object_t*>();
+ if (object == nullptr || object->empty())
{
BMCWEB_LOG_DEBUG << "Json value is empty";
messages::emptyJSON(res);
return std::nullopt;
}
+ std::erase_if(*object,
+ [](const std::pair<std::string, nlohmann::json>& item) {
+ return item.first.starts_with("@odata.");
+ });
+ if (object->empty())
+ {
+ // If the update request only contains OData annotations, the service
+ // should return the HTTP 400 Bad Request status code with the
+ // NoOperation message from the Base Message Registry, ...
+ messages::noOperation(res);
+ return std::nullopt;
+ }
+
return {std::move(jsonRequest)};
}
diff --git a/redfish-core/ut/json_utils_test.cpp b/redfish-core/ut/json_utils_test.cpp
index 9312f1a..cf7b734 100644
--- a/redfish-core/ut/json_utils_test.cpp
+++ b/redfish-core/ut/json_utils_test.cpp
@@ -274,6 +274,34 @@
EXPECT_FALSE(res.jsonValue.empty());
}
+TEST(readJsonPatch, OdataIgnored)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = R"({"@odata.etag": "etag", "integer": 1})";
+
+ std::optional<int64_t> integer = 0;
+ EXPECT_TRUE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_TRUE(res.jsonValue.empty());
+}
+
+TEST(readJsonPatch, OnlyOdataGivesNoOperation)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = R"({"@odata.etag": "etag"})";
+
+ std::optional<int64_t> integer = 0;
+ EXPECT_FALSE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_FALSE(res.jsonValue.empty());
+}
+
TEST(readJsonAction, ValidElements)
{
crow::Response res;