summaryrefslogtreecommitdiff
path: root/include/openbmc_dbus_rest.hpp
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2022-05-04 21:33:42 +0300
committerEd Tanous <edtanous@google.com>2022-05-13 00:46:22 +0300
commit1656b296313d75b172dcdbe5f37ff1d1b54800dc (patch)
tree826f8bff20cd2d9947a9f1edba0609199715d244 /include/openbmc_dbus_rest.hpp
parent4c25d66ea7b0d56ee9bbc6fa392582fb76b44911 (diff)
downloadbmcweb-1656b296313d75b172dcdbe5f37ff1d1b54800dc.tar.xz
Move /bus/system/<str>/<path> POST to method
Per the reorganization we've done elsewhere, move this large lambda function to simplify it. Tested: Code move only. Code compiles. Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ib0586b34809167120bdc127868706ac517db4474
Diffstat (limited to 'include/openbmc_dbus_rest.hpp')
-rw-r--r--include/openbmc_dbus_rest.hpp662
1 files changed, 317 insertions, 345 deletions
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
index 042f193952..4f4bd71ff6 100644
--- a/include/openbmc_dbus_rest.hpp
+++ b/include/openbmc_dbus_rest.hpp
@@ -2102,6 +2102,321 @@ inline void handleDBusUrl(const crow::Request& req,
methodNotAllowedDesc, methodNotAllowedMsg);
}
+inline void
+ handleBusSystemPost(const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& processName,
+ const std::string& requestedPath)
+{
+ std::vector<std::string> strs;
+ boost::split(strs, requestedPath, boost::is_any_of("/"));
+ std::string objectPath;
+ std::string interfaceName;
+ std::string methodName;
+ auto it = strs.begin();
+ if (it == strs.end())
+ {
+ objectPath = "/";
+ }
+ while (it != strs.end())
+ {
+ // Check if segment contains ".". If it does, it must be an
+ // interface
+ if (it->find(".") != std::string::npos)
+ {
+ break;
+ // This check is necessary as the trailing slash gets
+ // parsed as part of our <path> specifier above, which
+ // causes the normal trailing backslash redirector to
+ // fail.
+ }
+ if (!it->empty())
+ {
+ objectPath += "/" + *it;
+ }
+ it++;
+ }
+ if (it != strs.end())
+ {
+ interfaceName = *it;
+ it++;
+
+ // after interface, we might have a method name
+ if (it != strs.end())
+ {
+ methodName = *it;
+ it++;
+ }
+ }
+ if (it != strs.end())
+ {
+ // if there is more levels past the method name, something
+ // went wrong, return not found
+ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+ if (interfaceName.empty())
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, processName,
+ objectPath](const boost::system::error_code ec,
+ const std::string& introspectXml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ return;
+ }
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspectXml.c_str());
+ tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << processName << " " << objectPath
+ << "\n";
+ asyncResp->res.jsonValue = {{"status", "XML parse error"}};
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << introspectXml;
+ asyncResp->res.jsonValue = {{"status", "ok"},
+ {"bus_name", processName},
+ {"object_path", objectPath}};
+ nlohmann::json& interfacesArray =
+ asyncResp->res.jsonValue["interfaces"];
+ interfacesArray = nlohmann::json::array();
+ tinyxml2::XMLElement* interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr)
+ {
+ const char* ifaceName = interface->Attribute("name");
+ if (ifaceName != nullptr)
+ {
+ interfacesArray.push_back({{"name", ifaceName}});
+ }
+
+ interface = interface->NextSiblingElement("interface");
+ }
+ },
+ processName, objectPath, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
+ }
+ else if (methodName.empty())
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, processName, objectPath,
+ interfaceName](const boost::system::error_code ec,
+ const std::string& introspectXml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ return;
+ }
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspectXml.data(), introspectXml.size());
+ tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << processName << " " << objectPath
+ << "\n";
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ asyncResp->res.jsonValue = {{"status", "ok"},
+ {"bus_name", processName},
+ {"interface", interfaceName},
+ {"object_path", objectPath}};
+
+ nlohmann::json& methodsArray =
+ asyncResp->res.jsonValue["methods"];
+ methodsArray = nlohmann::json::array();
+
+ nlohmann::json& signalsArray =
+ asyncResp->res.jsonValue["signals"];
+ signalsArray = nlohmann::json::array();
+
+ nlohmann::json& propertiesObj =
+ asyncResp->res.jsonValue["properties"];
+ propertiesObj = nlohmann::json::object();
+
+ // if we know we're the only call, build the
+ // json directly
+ tinyxml2::XMLElement* interface =
+ pRoot->FirstChildElement("interface");
+ while (interface != nullptr)
+ {
+ const char* ifaceName = interface->Attribute("name");
+
+ if (ifaceName != nullptr && ifaceName == interfaceName)
+ {
+ break;
+ }
+
+ interface = interface->NextSiblingElement("interface");
+ }
+ if (interface == nullptr)
+ {
+ // if we got to the end of the list and
+ // never found a match, throw 404
+ asyncResp->res.result(
+ boost::beast::http::status::not_found);
+ return;
+ }
+
+ tinyxml2::XMLElement* methods =
+ interface->FirstChildElement("method");
+ while (methods != nullptr)
+ {
+ nlohmann::json argsArray = nlohmann::json::array();
+ tinyxml2::XMLElement* arg =
+ methods->FirstChildElement("arg");
+ while (arg != nullptr)
+ {
+ nlohmann::json thisArg;
+ for (const char* fieldName : std::array<const char*, 3>{
+ "name", "direction", "type"})
+ {
+ const char* fieldValue = arg->Attribute(fieldName);
+ if (fieldValue != nullptr)
+ {
+ thisArg[fieldName] = fieldValue;
+ }
+ }
+ argsArray.push_back(std::move(thisArg));
+ arg = arg->NextSiblingElement("arg");
+ }
+
+ const char* name = methods->Attribute("name");
+ if (name != nullptr)
+ {
+ std::string uri;
+ uri.reserve(14 + processName.size() +
+ objectPath.size() + interfaceName.size() +
+ strlen(name));
+ uri += "/bus/system/";
+ uri += processName;
+ uri += objectPath;
+ uri += "/";
+ uri += interfaceName;
+ uri += "/";
+ uri += name;
+ methodsArray.push_back({{"name", name},
+ {"uri", std::move(uri)},
+ {"args", argsArray}});
+ }
+ methods = methods->NextSiblingElement("method");
+ }
+ tinyxml2::XMLElement* signals =
+ interface->FirstChildElement("signal");
+ while (signals != nullptr)
+ {
+ nlohmann::json argsArray = nlohmann::json::array();
+
+ tinyxml2::XMLElement* arg =
+ signals->FirstChildElement("arg");
+ while (arg != nullptr)
+ {
+ const char* name = arg->Attribute("name");
+ const char* type = arg->Attribute("type");
+ if (name != nullptr && type != nullptr)
+ {
+ argsArray.push_back({
+ {"name", name},
+ {"type", type},
+ });
+ }
+ arg = arg->NextSiblingElement("arg");
+ }
+ const char* name = signals->Attribute("name");
+ if (name != nullptr)
+ {
+ signalsArray.push_back(
+ {{"name", name}, {"args", argsArray}});
+ }
+
+ signals = signals->NextSiblingElement("signal");
+ }
+
+ tinyxml2::XMLElement* property =
+ interface->FirstChildElement("property");
+ while (property != nullptr)
+ {
+ const char* name = property->Attribute("name");
+ const char* type = property->Attribute("type");
+ if (type != nullptr && name != nullptr)
+ {
+ sdbusplus::message::message m =
+ crow::connections::systemBus->new_method_call(
+ processName.c_str(), objectPath.c_str(),
+ "org.freedesktop."
+ "DBus."
+ "Properties",
+ "Get");
+ m.append(interfaceName, name);
+ nlohmann::json& propertyItem = propertiesObj[name];
+ crow::connections::systemBus->async_send(
+ m, [&propertyItem,
+ asyncResp](boost::system::error_code& e,
+ sdbusplus::message::message& msg) {
+ if (e)
+ {
+ return;
+ }
+
+ convertDBusToJSON("v", msg, propertyItem);
+ });
+ }
+ property = property->NextSiblingElement("property");
+ }
+ },
+ processName, objectPath, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
+ }
+ else
+ {
+ if (req.method() != boost::beast::http::verb::post)
+ {
+ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+ nlohmann::json requestDbusData =
+ nlohmann::json::parse(req.body, nullptr, false);
+
+ if (requestDbusData.is_discarded())
+ {
+ asyncResp->res.result(boost::beast::http::status::bad_request);
+ return;
+ }
+ if (!requestDbusData.is_array())
+ {
+ asyncResp->res.result(boost::beast::http::status::bad_request);
+ return;
+ }
+ auto transaction =
+ std::make_shared<InProgressActionData>(asyncResp->res);
+
+ transaction->path = objectPath;
+ transaction->methodName = methodName;
+ transaction->arguments = std::move(requestDbusData);
+
+ findActionOnInterface(transaction, processName);
+ }
+}
+
inline void requestRoutes(App& app)
{
BMCWEB_ROUTE(app, "/bus/")
@@ -2275,351 +2590,8 @@ inline void requestRoutes(App& app)
BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
.privileges({{"ConfigureComponents", "ConfigureManager"}})
- .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
- [](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& processName,
- const std::string& requestedPath) {
- std::vector<std::string> strs;
- boost::split(strs, requestedPath, boost::is_any_of("/"));
- std::string objectPath;
- std::string interfaceName;
- std::string methodName;
- auto it = strs.begin();
- if (it == strs.end())
- {
- objectPath = "/";
- }
- while (it != strs.end())
- {
- // Check if segment contains ".". If it does, it must be an
- // interface
- if (it->find(".") != std::string::npos)
- {
- break;
- // This check is necessary as the trailing slash gets
- // parsed as part of our <path> specifier above, which
- // causes the normal trailing backslash redirector to
- // fail.
- }
- if (!it->empty())
- {
- objectPath += "/" + *it;
- }
- it++;
- }
- if (it != strs.end())
- {
- interfaceName = *it;
- it++;
-
- // after interface, we might have a method name
- if (it != strs.end())
- {
- methodName = *it;
- it++;
- }
- }
- if (it != strs.end())
- {
- // if there is more levels past the method name, something
- // went wrong, return not found
- asyncResp->res.result(
- boost::beast::http::status::not_found);
- return;
- }
- if (interfaceName.empty())
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp, processName,
- objectPath](const boost::system::error_code ec,
- const std::string& introspectXml) {
- if (ec)
- {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: "
- << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
- return;
- }
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspectXml.c_str());
- tinyxml2::XMLNode* pRoot =
- doc.FirstChildElement("node");
- if (pRoot == nullptr)
- {
- BMCWEB_LOG_ERROR
- << "XML document failed to parse "
- << processName << " " << objectPath << "\n";
- asyncResp->res.jsonValue = {
- {"status", "XML parse error"}};
- asyncResp->res.result(
- boost::beast::http::status::
- internal_server_error);
- return;
- }
-
- BMCWEB_LOG_DEBUG << introspectXml;
- asyncResp->res.jsonValue = {
- {"status", "ok"},
- {"bus_name", processName},
- {"object_path", objectPath}};
- nlohmann::json& interfacesArray =
- asyncResp->res.jsonValue["interfaces"];
- interfacesArray = nlohmann::json::array();
- tinyxml2::XMLElement* interface =
- pRoot->FirstChildElement("interface");
-
- while (interface != nullptr)
- {
- const char* ifaceName =
- interface->Attribute("name");
- if (ifaceName != nullptr)
- {
- interfacesArray.push_back(
- {{"name", ifaceName}});
- }
-
- interface =
- interface->NextSiblingElement("interface");
- }
- },
- processName, objectPath,
- "org.freedesktop.DBus.Introspectable", "Introspect");
- }
- else if (methodName.empty())
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp, processName, objectPath,
- interfaceName](const boost::system::error_code ec,
- const std::string& introspectXml) {
- if (ec)
- {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: "
- << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
- return;
- }
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspectXml.data(),
- introspectXml.size());
- tinyxml2::XMLNode* pRoot =
- doc.FirstChildElement("node");
- if (pRoot == nullptr)
- {
- BMCWEB_LOG_ERROR
- << "XML document failed to parse "
- << processName << " " << objectPath << "\n";
- asyncResp->res.result(
- boost::beast::http::status::
- internal_server_error);
- return;
- }
- asyncResp->res.jsonValue = {
- {"status", "ok"},
- {"bus_name", processName},
- {"interface", interfaceName},
- {"object_path", objectPath}};
-
- nlohmann::json& methodsArray =
- asyncResp->res.jsonValue["methods"];
- methodsArray = nlohmann::json::array();
-
- nlohmann::json& signalsArray =
- asyncResp->res.jsonValue["signals"];
- signalsArray = nlohmann::json::array();
-
- nlohmann::json& propertiesObj =
- asyncResp->res.jsonValue["properties"];
- propertiesObj = nlohmann::json::object();
-
- // if we know we're the only call, build the
- // json directly
- tinyxml2::XMLElement* interface =
- pRoot->FirstChildElement("interface");
- while (interface != nullptr)
- {
- const char* ifaceName =
- interface->Attribute("name");
-
- if (ifaceName != nullptr &&
- ifaceName == interfaceName)
- {
- break;
- }
-
- interface =
- interface->NextSiblingElement("interface");
- }
- if (interface == nullptr)
- {
- // if we got to the end of the list and
- // never found a match, throw 404
- asyncResp->res.result(
- boost::beast::http::status::not_found);
- return;
- }
-
- tinyxml2::XMLElement* methods =
- interface->FirstChildElement("method");
- while (methods != nullptr)
- {
- nlohmann::json argsArray =
- nlohmann::json::array();
- tinyxml2::XMLElement* arg =
- methods->FirstChildElement("arg");
- while (arg != nullptr)
- {
- nlohmann::json thisArg;
- for (const char* fieldName :
- std::array<const char*, 3>{
- "name", "direction", "type"})
- {
- const char* fieldValue =
- arg->Attribute(fieldName);
- if (fieldValue != nullptr)
- {
- thisArg[fieldName] = fieldValue;
- }
- }
- argsArray.push_back(std::move(thisArg));
- arg = arg->NextSiblingElement("arg");
- }
-
- const char* name = methods->Attribute("name");
- if (name != nullptr)
- {
- std::string uri;
- uri.reserve(14 + processName.size() +
- objectPath.size() +
- interfaceName.size() +
- strlen(name));
- uri += "/bus/system/";
- uri += processName;
- uri += objectPath;
- uri += "/";
- uri += interfaceName;
- uri += "/";
- uri += name;
- methodsArray.push_back(
- {{"name", name},
- {"uri", std::move(uri)},
- {"args", argsArray}});
- }
- methods = methods->NextSiblingElement("method");
- }
- tinyxml2::XMLElement* signals =
- interface->FirstChildElement("signal");
- while (signals != nullptr)
- {
- nlohmann::json argsArray =
- nlohmann::json::array();
-
- tinyxml2::XMLElement* arg =
- signals->FirstChildElement("arg");
- while (arg != nullptr)
- {
- const char* name = arg->Attribute("name");
- const char* type = arg->Attribute("type");
- if (name != nullptr && type != nullptr)
- {
- argsArray.push_back({
- {"name", name},
- {"type", type},
- });
- }
- arg = arg->NextSiblingElement("arg");
- }
- const char* name = signals->Attribute("name");
- if (name != nullptr)
- {
- signalsArray.push_back(
- {{"name", name}, {"args", argsArray}});
- }
-
- signals = signals->NextSiblingElement("signal");
- }
-
- tinyxml2::XMLElement* property =
- interface->FirstChildElement("property");
- while (property != nullptr)
- {
- const char* name = property->Attribute("name");
- const char* type = property->Attribute("type");
- if (type != nullptr && name != nullptr)
- {
- sdbusplus::message::message m =
- crow::connections::systemBus
- ->new_method_call(
- processName.c_str(),
- objectPath.c_str(),
- "org.freedesktop."
- "DBus."
- "Properties",
- "Get");
- m.append(interfaceName, name);
- nlohmann::json& propertyItem =
- propertiesObj[name];
- crow::connections::systemBus->async_send(
- m,
- [&propertyItem, asyncResp](
- boost::system::error_code& e,
- sdbusplus::message::message& msg) {
- if (e)
- {
- return;
- }
-
- convertDBusToJSON("v", msg,
- propertyItem);
- });
- }
- property =
- property->NextSiblingElement("property");
- }
- },
- processName, objectPath,
- "org.freedesktop.DBus.Introspectable", "Introspect");
- }
- else
- {
- if (req.method() != boost::beast::http::verb::post)
- {
- asyncResp->res.result(
- boost::beast::http::status::not_found);
- return;
- }
-
- nlohmann::json requestDbusData =
- nlohmann::json::parse(req.body, nullptr, false);
-
- if (requestDbusData.is_discarded())
- {
- asyncResp->res.result(
- boost::beast::http::status::bad_request);
- return;
- }
- if (!requestDbusData.is_array())
- {
- asyncResp->res.result(
- boost::beast::http::status::bad_request);
- return;
- }
- auto transaction =
- std::make_shared<InProgressActionData>(asyncResp->res);
-
- transaction->path = objectPath;
- transaction->methodName = methodName;
- transaction->arguments = std::move(requestDbusData);
-
- findActionOnInterface(transaction, processName);
- }
- });
+ .methods(boost::beast::http::verb::get,
+ boost::beast::http::verb::post)(handleBusSystemPost);
}
} // namespace openbmc_mapper
} // namespace crow