Refactor multipart update parameter extraction
This commit extracts helper functions to improve code readability:
- parseFormPartName(): Parses the 'name' parameter from Content-
Disposition
- processUpdateParameters(): Handles UpdateParameters JSON processing
The extractMultipartUpdateParameters() function is refactored to use
these helpers, making the code more modular and easier to understand.
This is a pure refactoring with no functional changes.
Change-Id: I9bfd3c92666bbe362512d9fdd9472a4e44ad2241
Signed-off-by: Ed Tanous <etanous@nvidia.com>
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 0ac36b5..18abc2e 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -684,11 +684,14 @@
"RequestedApplyTime", applyTimeNewVal);
}
-struct MultiPartUpdateParameters
+struct MultiPartUpdate
{
- std::optional<std::string> applyTime;
std::string uploadData;
- std::vector<std::string> targets;
+ struct UpdateParameters
+ {
+ std::optional<std::string> applyTime;
+ std::vector<std::string> targets;
+ } params;
};
inline std::optional<std::string> processUrl(
@@ -718,12 +721,82 @@
return std::make_optional(firmwareId);
}
-inline std::optional<MultiPartUpdateParameters>
- extractMultipartUpdateParameters(
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- MultipartParser parser)
+inline std::optional<std::string> parseFormPartName(
+ const boost::beast::http::fields::const_iterator& contentDisposition)
{
- MultiPartUpdateParameters multiRet;
+ size_t semicolonPos = contentDisposition->value().find(';');
+ if (semicolonPos == std::string::npos)
+ {
+ return std::nullopt;
+ }
+
+ for (const auto& param : boost::beast::http::param_list{
+ contentDisposition->value().substr(semicolonPos)})
+ {
+ if (param.first == "name" && !param.second.empty())
+ {
+ return std::string(param.second);
+ }
+ }
+ return std::nullopt;
+}
+
+inline std::optional<MultiPartUpdate::UpdateParameters> processUpdateParameters(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ std::string_view content)
+{
+ MultiPartUpdate::UpdateParameters multiRet;
+ nlohmann::json jsonContent = nlohmann::json::parse(content, nullptr, false);
+ if (jsonContent.is_discarded())
+ {
+ return std::nullopt;
+ }
+ nlohmann::json::object_t* obj =
+ jsonContent.get_ptr<nlohmann::json::object_t*>();
+ if (obj == nullptr)
+ {
+ messages::propertyValueTypeError(asyncResp->res, content,
+ "UpdateParameters");
+ return std::nullopt;
+ }
+
+ std::vector<std::string> tempTargets;
+ if (!json_util::readJsonObject( //
+ *obj, asyncResp->res, //
+ "@Redfish.OperationApplyTime", multiRet.applyTime, //
+ "Targets", tempTargets //
+ ))
+ {
+ return std::nullopt;
+ }
+
+ for (size_t urlIndex = 0; urlIndex < tempTargets.size(); urlIndex++)
+ {
+ const std::string& target = tempTargets[urlIndex];
+ boost::system::result<boost::urls::url_view> url =
+ boost::urls::parse_origin_form(target);
+ auto res = processUrl(url);
+ if (!res.has_value())
+ {
+ messages::propertyValueFormatError(
+ asyncResp->res, target, std::format("Targets/{}", urlIndex));
+ return std::nullopt;
+ }
+ multiRet.targets.emplace_back(res.value());
+ }
+ if (multiRet.targets.size() != 1)
+ {
+ messages::propertyValueFormatError(asyncResp->res, multiRet.targets,
+ "Targets");
+ return std::nullopt;
+ }
+ return multiRet;
+}
+
+inline std::optional<MultiPartUpdate> extractMultipartUpdateParameters(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, MultipartParser parser)
+{
+ MultiPartUpdate multiRet;
for (FormPart& formpart : parser.mime_fields)
{
boost::beast::http::fields::const_iterator it =
@@ -735,75 +808,27 @@
}
BMCWEB_LOG_INFO("Parsing value {}", it->value());
- // The construction parameters of param_list must start with `;`
- size_t index = it->value().find(';');
- if (index == std::string::npos)
+ auto formFieldNameOpt = parseFormPartName(it);
+ if (!formFieldNameOpt.has_value())
{
continue;
}
- for (const auto& param :
- boost::beast::http::param_list{it->value().substr(index)})
+ const std::string& formFieldName = formFieldNameOpt.value();
+
+ if (formFieldName == "UpdateParameters")
{
- if (param.first != "name" || param.second.empty())
+ std::optional<MultiPartUpdate::UpdateParameters> params =
+ processUpdateParameters(asyncResp, formpart.content);
+ if (!params)
{
- continue;
+ return std::nullopt;
}
-
- if (param.second == "UpdateParameters")
- {
- std::vector<std::string> tempTargets;
- nlohmann::json content =
- nlohmann::json::parse(formpart.content, nullptr, false);
- if (content.is_discarded())
- {
- return std::nullopt;
- }
- nlohmann::json::object_t* obj =
- content.get_ptr<nlohmann::json::object_t*>();
- if (obj == nullptr)
- {
- messages::propertyValueTypeError(
- asyncResp->res, formpart.content, "UpdateParameters");
- return std::nullopt;
- }
-
- if (!json_util::readJsonObject( //
- *obj, asyncResp->res, //
- "@Redfish.OperationApplyTime", multiRet.applyTime, //
- "Targets", tempTargets //
- ))
- {
- return std::nullopt;
- }
-
- for (size_t urlIndex = 0; urlIndex < tempTargets.size();
- urlIndex++)
- {
- const std::string& target = tempTargets[urlIndex];
- boost::system::result<boost::urls::url_view> url =
- boost::urls::parse_origin_form(target);
- auto res = processUrl(url);
- if (!res.has_value())
- {
- messages::propertyValueFormatError(
- asyncResp->res, target,
- std::format("Targets/{}", urlIndex));
- return std::nullopt;
- }
- multiRet.targets.emplace_back(res.value());
- }
- if (multiRet.targets.size() != 1)
- {
- messages::propertyValueFormatError(
- asyncResp->res, multiRet.targets, "Targets");
- return std::nullopt;
- }
- }
- else if (param.second == "UpdateFile")
- {
- multiRet.uploadData = std::move(formpart.content);
- }
+ multiRet.params = std::move(*params);
+ }
+ else if (formFieldName == "UpdateFile")
+ {
+ multiRet.uploadData = std::move(formpart.content);
}
}
@@ -813,7 +838,7 @@
messages::propertyMissing(asyncResp->res, "UpdateFile");
return std::nullopt;
}
- if (multiRet.targets.empty())
+ if (multiRet.params.targets.empty())
{
messages::propertyMissing(asyncResp->res, "Targets");
return std::nullopt;
@@ -979,21 +1004,21 @@
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const crow::Request& req, MultipartParser&& parser)
{
- std::optional<MultiPartUpdateParameters> multipart =
+ std::optional<MultiPartUpdate> multipart =
extractMultipartUpdateParameters(asyncResp, std::move(parser));
if (!multipart)
{
return;
}
- if (!multipart->applyTime)
+ if (!multipart->params.applyTime)
{
- multipart->applyTime = "OnReset";
+ multipart->params.applyTime = "OnReset";
}
if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
{
std::string applyTimeNewVal;
- if (!convertApplyTime(asyncResp->res, *multipart->applyTime,
+ if (!convertApplyTime(asyncResp->res, *multipart->params.applyTime,
applyTimeNewVal))
{
return;
@@ -1002,11 +1027,11 @@
processUpdateRequest(asyncResp, std::move(payload),
multipart->uploadData, applyTimeNewVal,
- multipart->targets);
+ multipart->params.targets);
}
else
{
- setApplyTime(asyncResp, *multipart->applyTime);
+ setApplyTime(asyncResp, *multipart->params.applyTime);
// Setup callback for when new software detected
monitorForSoftwareAvailable(asyncResp, req,