1 #pragma once
2 
3 #include <crow/app.h>
4 #include <tinyxml2.h>
5 
6 #include <async_resp.hpp>
7 #include <boost/algorithm/string.hpp>
8 #include <boost/container/flat_set.hpp>
9 #include <dbus_singleton.hpp>
10 #include <experimental/filesystem>
11 #include <fstream>
12 
13 namespace crow
14 {
15 namespace openbmc_mapper
16 {
17 
18 void introspectObjects(const std::string &processName,
19                        const std::string &objectPath,
20                        std::shared_ptr<bmcweb::AsyncResp> transaction)
21 {
22     if (transaction->res.jsonValue.is_null())
23     {
24         transaction->res.jsonValue = {{"status", "ok"},
25                                       {"bus_name", processName},
26                                       {"objects", nlohmann::json::array()}};
27     }
28 
29     crow::connections::systemBus->async_method_call(
30         [transaction, processName{std::string(processName)},
31          objectPath{std::string(objectPath)}](
32             const boost::system::error_code ec,
33             const std::string &introspect_xml) {
34             if (ec)
35             {
36                 BMCWEB_LOG_ERROR
37                     << "Introspect call failed with error: " << ec.message()
38                     << " on process: " << processName << " path: " << objectPath
39                     << "\n";
40                 return;
41             }
42             transaction->res.jsonValue["objects"].push_back(
43                 {{"path", objectPath}});
44 
45             tinyxml2::XMLDocument doc;
46 
47             doc.Parse(introspect_xml.c_str());
48             tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
49             if (pRoot == nullptr)
50             {
51                 BMCWEB_LOG_ERROR << "XML document failed to parse "
52                                  << processName << " " << objectPath << "\n";
53             }
54             else
55             {
56                 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
57                 while (node != nullptr)
58                 {
59                     const char *childPath = node->Attribute("name");
60                     if (childPath != nullptr)
61                     {
62                         std::string newpath;
63                         if (objectPath != "/")
64                         {
65                             newpath += objectPath;
66                         }
67                         newpath += std::string("/") + childPath;
68                         // introspect the subobjects as well
69                         introspectObjects(processName, newpath, transaction);
70                     }
71 
72                     node = node->NextSiblingElement("node");
73                 }
74             }
75         },
76         processName, objectPath, "org.freedesktop.DBus.Introspectable",
77         "Introspect");
78 }
79 
80 // A smattering of common types to unpack.  TODO(ed) this should really iterate
81 // the sdbusplus object directly and build the json response
82 using DbusRestVariantType = sdbusplus::message::variant<
83     std::vector<std::tuple<std::string, std::string, std::string>>, std::string,
84     int64_t, uint64_t, double, int32_t, uint32_t, int16_t, uint16_t, uint8_t,
85     bool>;
86 
87 using ManagedObjectType = std::vector<std::pair<
88     sdbusplus::message::object_path,
89     boost::container::flat_map<
90         std::string,
91         boost::container::flat_map<std::string, DbusRestVariantType>>>>;
92 
93 void getManagedObjectsForEnumerate(const std::string &object_name,
94                                    const std::string &object_manager_path,
95                                    const std::string &connection_name,
96                                    crow::Response &res,
97                                    std::shared_ptr<nlohmann::json> transaction)
98 {
99     crow::connections::systemBus->async_method_call(
100         [&res, transaction, object_name{std::string(object_name)}](
101             const boost::system::error_code ec,
102             const ManagedObjectType &objects) {
103             if (ec)
104             {
105                 BMCWEB_LOG_ERROR << ec;
106             }
107             else
108             {
109                 nlohmann::json &dataJson = *transaction;
110 
111                 for (auto &objectPath : objects)
112                 {
113                     BMCWEB_LOG_DEBUG
114                         << "Reading object "
115                         << static_cast<const std::string &>(objectPath.first);
116                     nlohmann::json &objectJson =
117                         dataJson[static_cast<const std::string &>(
118                             objectPath.first)];
119                     if (objectJson.is_null())
120                     {
121                         objectJson = nlohmann::json::object();
122                     }
123                     for (const auto &interface : objectPath.second)
124                     {
125                         for (const auto &property : interface.second)
126                         {
127                             nlohmann::json &propertyJson =
128                                 objectJson[property.first];
129                             mapbox::util::apply_visitor(
130                                 [&propertyJson](auto &&val) {
131                                     propertyJson = val;
132                                 },
133                                 property.second);
134                         }
135                     }
136                 }
137             }
138 
139             if (transaction.use_count() == 1)
140             {
141                 res.jsonValue = {{"message", "200 OK"},
142                                  {"status", "ok"},
143                                  {"data", std::move(*transaction)}};
144                 res.end();
145             }
146         },
147         connection_name, object_manager_path,
148         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
149 }
150 
151 void findObjectManagerPathForEnumerate(
152     const std::string &object_name, const std::string &connection_name,
153     crow::Response &res, std::shared_ptr<nlohmann::json> transaction)
154 {
155     crow::connections::systemBus->async_method_call(
156         [&res, transaction, object_name{std::string(object_name)},
157          connection_name{std::string(connection_name)}](
158             const boost::system::error_code ec,
159             const boost::container::flat_map<
160                 std::string, boost::container::flat_map<
161                                  std::string, std::vector<std::string>>>
162                 &objects) {
163             if (ec)
164             {
165                 BMCWEB_LOG_ERROR << ec;
166                 return;
167             }
168 
169             for (const auto &pathGroup : objects)
170             {
171                 for (const auto &connectionGroup : pathGroup.second)
172                 {
173                     if (connectionGroup.first == connection_name)
174                     {
175                         // Found the object manager path for this resource.
176                         getManagedObjectsForEnumerate(
177                             object_name, pathGroup.first, connection_name, res,
178                             transaction);
179                         return;
180                     }
181                 }
182             }
183         },
184         "xyz.openbmc_project.ObjectMapper",
185         "/xyz/openbmc_project/object_mapper",
186         "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
187         std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
188 }
189 
190 using GetSubTreeType = std::vector<
191     std::pair<std::string,
192               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
193 
194 // Structure for storing data on an in progress action
195 struct InProgressActionData
196 {
197     InProgressActionData(crow::Response &res) : res(res){};
198     ~InProgressActionData()
199     {
200         if (res.result() == boost::beast::http::status::internal_server_error)
201         {
202             // Reset the json object to clear out any data that made it in
203             // before the error happened todo(ed) handle error condition with
204             // proper code
205             res.jsonValue = nlohmann::json::object();
206         }
207         res.end();
208     }
209 
210     void setErrorStatus()
211     {
212         res.result(boost::beast::http::status::internal_server_error);
213     }
214     crow::Response &res;
215     std::string path;
216     std::string methodName;
217     nlohmann::json arguments;
218 };
219 
220 std::vector<std::string> dbusArgSplit(const std::string &string)
221 {
222     std::vector<std::string> ret;
223     if (string.empty())
224     {
225         return ret;
226     }
227     ret.push_back("");
228     int containerDepth = 0;
229 
230     for (std::string::const_iterator character = string.begin();
231          character != string.end(); character++)
232     {
233         ret.back() += *character;
234         switch (*character)
235         {
236             case ('a'):
237                 break;
238             case ('('):
239             case ('{'):
240                 containerDepth++;
241                 break;
242             case ('}'):
243             case (')'):
244                 containerDepth--;
245                 if (containerDepth == 0)
246                 {
247                     if (character + 1 != string.end())
248                     {
249                         ret.push_back("");
250                     }
251                 }
252                 break;
253             default:
254                 if (containerDepth == 0)
255                 {
256                     if (character + 1 != string.end())
257                     {
258                         ret.push_back("");
259                     }
260                 }
261                 break;
262         }
263     }
264 }
265 
266 int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
267                       const nlohmann::json &input_json)
268 {
269     int r = 0;
270     BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
271                      << " to type: " << arg_type;
272     const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
273 
274     // Assume a single object for now.
275     const nlohmann::json *j = &input_json;
276     nlohmann::json::const_iterator jIt = input_json.begin();
277 
278     for (const std::string &argCode : argTypes)
279     {
280         // If we are decoding multiple objects, grab the pointer to the
281         // iterator, and increment it for the next loop
282         if (argTypes.size() > 1)
283         {
284             if (jIt == input_json.end())
285             {
286                 return -2;
287             }
288             j = &*jIt;
289             jIt++;
290         }
291         const int64_t *intValue = j->get_ptr<const int64_t *>();
292         const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
293         const std::string *stringValue = j->get_ptr<const std::string *>();
294         const double *doubleValue = j->get_ptr<const double *>();
295         const bool *b = j->get_ptr<const bool *>();
296         int64_t v = 0;
297         double d = 0.0;
298 
299         // Do some basic type conversions that make sense.  uint can be
300         // converted to int.  int and uint can be converted to double
301         if (uintValue != nullptr && intValue == nullptr)
302         {
303             v = static_cast<int64_t>(*uintValue);
304             intValue = &v;
305         }
306         if (uintValue != nullptr && doubleValue == nullptr)
307         {
308             d = static_cast<double>(*uintValue);
309             doubleValue = &d;
310         }
311         if (intValue != nullptr && doubleValue == nullptr)
312         {
313             d = static_cast<double>(*intValue);
314             doubleValue = &d;
315         }
316 
317         if (argCode == "s")
318         {
319             if (stringValue == nullptr)
320             {
321                 return -1;
322             }
323             r = sd_bus_message_append_basic(m, argCode[0],
324                                             (void *)stringValue->c_str());
325             if (r < 0)
326             {
327                 return r;
328             }
329         }
330         else if (argCode == "i")
331         {
332             if (intValue == nullptr)
333             {
334                 return -1;
335             }
336             int32_t i = static_cast<int32_t>(*intValue);
337             r = sd_bus_message_append_basic(m, argCode[0], &i);
338             if (r < 0)
339             {
340                 return r;
341             }
342         }
343         else if (argCode == "b")
344         {
345             // lots of ways bool could be represented here.  Try them all
346             int boolInt = false;
347             if (intValue != nullptr)
348             {
349                 boolInt = *intValue > 0 ? 1 : 0;
350             }
351             else if (b != nullptr)
352             {
353                 boolInt = b ? 1 : 0;
354             }
355             else if (stringValue != nullptr)
356             {
357                 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
358             }
359             else
360             {
361                 return -1;
362             }
363             r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
364             if (r < 0)
365             {
366                 return r;
367             }
368         }
369         else if (argCode == "n")
370         {
371             if (intValue == nullptr)
372             {
373                 return -1;
374             }
375             int16_t n = static_cast<int16_t>(*intValue);
376             r = sd_bus_message_append_basic(m, argCode[0], &n);
377             if (r < 0)
378             {
379                 return r;
380             }
381         }
382         else if (argCode == "x")
383         {
384             if (intValue == nullptr)
385             {
386                 return -1;
387             }
388             r = sd_bus_message_append_basic(m, argCode[0], intValue);
389             if (r < 0)
390             {
391                 return r;
392             }
393         }
394         else if (argCode == "y")
395         {
396             if (uintValue == nullptr)
397             {
398                 return -1;
399             }
400             uint8_t y = static_cast<uint8_t>(*uintValue);
401             r = sd_bus_message_append_basic(m, argCode[0], &y);
402         }
403         else if (argCode == "q")
404         {
405             if (uintValue == nullptr)
406             {
407                 return -1;
408             }
409             uint16_t q = static_cast<uint16_t>(*uintValue);
410             r = sd_bus_message_append_basic(m, argCode[0], &q);
411         }
412         else if (argCode == "u")
413         {
414             if (uintValue == nullptr)
415             {
416                 return -1;
417             }
418             uint32_t u = static_cast<uint32_t>(*uintValue);
419             r = sd_bus_message_append_basic(m, argCode[0], &u);
420         }
421         else if (argCode == "t")
422         {
423             if (uintValue == nullptr)
424             {
425                 return -1;
426             }
427             r = sd_bus_message_append_basic(m, argCode[0], uintValue);
428         }
429         else if (argCode == "d")
430         {
431             sd_bus_message_append_basic(m, argCode[0], doubleValue);
432         }
433         else if (boost::starts_with(argCode, "a"))
434         {
435             std::string containedType = argCode.substr(1);
436             r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
437                                               containedType.c_str());
438             if (r < 0)
439             {
440                 return r;
441             }
442 
443             for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
444                  ++it)
445             {
446                 r = convertJsonToDbus(m, containedType, *it);
447                 if (r < 0)
448                 {
449                     return r;
450                 }
451 
452                 it++;
453             }
454             sd_bus_message_close_container(m);
455         }
456         else if (boost::starts_with(argCode, "v"))
457         {
458             std::string containedType = argCode.substr(1);
459             BMCWEB_LOG_DEBUG << "variant type: " << argCode
460                              << " appending variant of type: " << containedType;
461             r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
462                                               containedType.c_str());
463             if (r < 0)
464             {
465                 return r;
466             }
467 
468             r = convertJsonToDbus(m, containedType, input_json);
469             if (r < 0)
470             {
471                 return r;
472             }
473 
474             r = sd_bus_message_close_container(m);
475             if (r < 0)
476             {
477                 return r;
478             }
479         }
480         else if (boost::starts_with(argCode, "(") &&
481                  boost::ends_with(argCode, ")"))
482         {
483             std::string containedType = argCode.substr(1, argCode.size() - 1);
484             r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
485                                               containedType.c_str());
486             nlohmann::json::const_iterator it = j->begin();
487             for (const std::string &argCode : dbusArgSplit(arg_type))
488             {
489                 if (it == j->end())
490                 {
491                     return -1;
492                 }
493                 r = convertJsonToDbus(m, argCode, *it);
494                 if (r < 0)
495                 {
496                     return r;
497                 }
498                 it++;
499             }
500             r = sd_bus_message_close_container(m);
501         }
502         else if (boost::starts_with(argCode, "{") &&
503                  boost::ends_with(argCode, "}"))
504         {
505             std::string containedType = argCode.substr(1, argCode.size() - 1);
506             r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
507                                               containedType.c_str());
508             std::vector<std::string> codes = dbusArgSplit(containedType);
509             if (codes.size() != 2)
510             {
511                 return -1;
512             }
513             const std::string &key_type = codes[0];
514             const std::string &value_type = codes[1];
515             for (auto it : j->items())
516             {
517                 r = convertJsonToDbus(m, key_type, it.key());
518                 if (r < 0)
519                 {
520                     return r;
521                 }
522 
523                 r = convertJsonToDbus(m, value_type, it.value());
524                 if (r < 0)
525                 {
526                     return r;
527                 }
528             }
529             r = sd_bus_message_close_container(m);
530         }
531         else
532         {
533             return -2;
534         }
535         if (r < 0)
536         {
537             return r;
538         }
539 
540         if (argTypes.size() > 1)
541         {
542             jIt++;
543         }
544     }
545 }
546 
547 void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
548                            const std::string &connectionName)
549 {
550     BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
551                      << connectionName;
552     crow::connections::systemBus->async_method_call(
553         [transaction, connectionName{std::string(connectionName)}](
554             const boost::system::error_code ec,
555             const std::string &introspect_xml) {
556             BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
557             if (ec)
558             {
559                 BMCWEB_LOG_ERROR
560                     << "Introspect call failed with error: " << ec.message()
561                     << " on process: " << connectionName << "\n";
562             }
563             else
564             {
565                 tinyxml2::XMLDocument doc;
566 
567                 doc.Parse(introspect_xml.data(), introspect_xml.size());
568                 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
569                 if (pRoot == nullptr)
570                 {
571                     BMCWEB_LOG_ERROR << "XML document failed to parse "
572                                      << connectionName << "\n";
573                     return;
574                 }
575                 tinyxml2::XMLElement *interfaceNode =
576                     pRoot->FirstChildElement("interface");
577                 while (interfaceNode != nullptr)
578                 {
579                     const char *thisInterfaceName =
580                         interfaceNode->Attribute("name");
581                     if (thisInterfaceName != nullptr)
582                     {
583                         tinyxml2::XMLElement *methodNode =
584                             interfaceNode->FirstChildElement("method");
585                         while (methodNode != nullptr)
586                         {
587                             const char *thisMethodName =
588                                 methodNode->Attribute("name");
589                             BMCWEB_LOG_DEBUG << "Found method: "
590                                              << thisMethodName;
591                             if (thisMethodName != nullptr &&
592                                 thisMethodName == transaction->methodName)
593                             {
594                                 BMCWEB_LOG_DEBUG
595                                     << "Found method named " << thisMethodName
596                                     << " on interface " << thisInterfaceName;
597                                 sdbusplus::message::message m =
598                                     crow::connections::systemBus
599                                         ->new_method_call(
600                                             connectionName.c_str(),
601                                             transaction->path.c_str(),
602                                             thisInterfaceName,
603                                             transaction->methodName.c_str());
604 
605                                 tinyxml2::XMLElement *argumentNode =
606                                     methodNode->FirstChildElement("arg");
607 
608                                 nlohmann::json::const_iterator argIt =
609                                     transaction->arguments.begin();
610 
611                                 while (argumentNode != nullptr)
612                                 {
613                                     const char *argDirection =
614                                         argumentNode->Attribute("direction");
615                                     const char *argType =
616                                         argumentNode->Attribute("type");
617                                     if (argDirection != nullptr &&
618                                         argType != nullptr &&
619                                         std::string(argDirection) == "in")
620                                     {
621 
622                                         if (argIt ==
623                                             transaction->arguments.end())
624                                         {
625                                             transaction->setErrorStatus();
626                                             return;
627                                         }
628                                         if (convertJsonToDbus(
629                                                 m.get(), std::string(argType),
630                                                 *argIt) < 0)
631                                         {
632                                             transaction->setErrorStatus();
633                                             return;
634                                         }
635 
636                                         argIt++;
637                                     }
638                                     argumentNode =
639                                         methodNode->NextSiblingElement("arg");
640                                 }
641 
642                                 crow::connections::systemBus->async_send(
643                                     m, [transaction](
644                                            boost::system::error_code ec,
645                                            sdbusplus::message::message &m) {
646                                         if (ec)
647                                         {
648                                             transaction->setErrorStatus();
649                                             return;
650                                         }
651                                         transaction->res.jsonValue = {
652                                             {"status", "ok"},
653                                             {"message", "200 OK"},
654                                             {"data", nullptr}};
655                                     });
656                                 break;
657                             }
658                             methodNode =
659                                 methodNode->NextSiblingElement("method");
660                         }
661                     }
662                     interfaceNode =
663                         interfaceNode->NextSiblingElement("interface");
664                 }
665             }
666         },
667         connectionName, transaction->path,
668         "org.freedesktop.DBus.Introspectable", "Introspect");
669 }
670 
671 void handleAction(const crow::Request &req, crow::Response &res,
672                   const std::string &objectPath, const std::string &methodName)
673 {
674     BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
675                      << methodName;
676     nlohmann::json requestDbusData =
677         nlohmann::json::parse(req.body, nullptr, false);
678 
679     if (requestDbusData.is_discarded())
680     {
681         res.result(boost::beast::http::status::bad_request);
682         res.end();
683         return;
684     }
685     nlohmann::json::iterator data = requestDbusData.find("data");
686     if (data == requestDbusData.end())
687     {
688         res.result(boost::beast::http::status::bad_request);
689         res.end();
690         return;
691     }
692 
693     if (!data->is_array())
694     {
695         res.result(boost::beast::http::status::bad_request);
696         res.end();
697         return;
698     }
699     auto transaction = std::make_shared<InProgressActionData>(res);
700 
701     transaction->path = objectPath;
702     transaction->methodName = methodName;
703     transaction->arguments = std::move(*data);
704     crow::connections::systemBus->async_method_call(
705         [transaction](
706             const boost::system::error_code ec,
707             const std::vector<std::pair<std::string, std::vector<std::string>>>
708                 &interfaceNames) {
709             if (ec || interfaceNames.size() <= 0)
710             {
711                 BMCWEB_LOG_ERROR << "Can't find object";
712                 transaction->setErrorStatus();
713                 return;
714             }
715 
716             BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
717                              << " object(s)";
718 
719             for (const std::pair<std::string, std::vector<std::string>>
720                      &object : interfaceNames)
721             {
722                 findActionOnInterface(transaction, object.first);
723             }
724         },
725         "xyz.openbmc_project.ObjectMapper",
726         "/xyz/openbmc_project/object_mapper",
727         "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
728         std::array<std::string, 0>());
729 }
730 
731 void handleList(crow::Response &res, const std::string &objectPath)
732 {
733     crow::connections::systemBus->async_method_call(
734         [&res](const boost::system::error_code ec,
735                std::vector<std::string> &objectPaths) {
736             if (ec)
737             {
738                 res.result(boost::beast::http::status::internal_server_error);
739             }
740             else
741             {
742                 res.jsonValue = {{"status", "ok"},
743                                  {"message", "200 OK"},
744                                  {"data", std::move(objectPaths)}};
745             }
746             res.end();
747         },
748         "xyz.openbmc_project.ObjectMapper",
749         "/xyz/openbmc_project/object_mapper",
750         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
751         static_cast<int32_t>(0), std::array<std::string, 0>());
752 }
753 
754 void handleEnumerate(crow::Response &res, const std::string &objectPath)
755 {
756     crow::connections::systemBus->async_method_call(
757         [&res, objectPath{std::string(objectPath)}](
758             const boost::system::error_code ec,
759             const GetSubTreeType &object_names) {
760             if (ec)
761             {
762                 res.jsonValue = {{"message", "200 OK"},
763                                  {"status", "ok"},
764                                  {"data", nlohmann::json::object()}};
765 
766                 res.end();
767                 return;
768             }
769 
770             boost::container::flat_set<std::string> connections;
771 
772             for (const auto &object : object_names)
773             {
774                 for (const auto &Connection : object.second)
775                 {
776                     connections.insert(Connection.first);
777                 }
778             }
779 
780             if (connections.size() <= 0)
781             {
782                 res.result(boost::beast::http::status::not_found);
783                 res.end();
784                 return;
785             }
786             auto transaction =
787                 std::make_shared<nlohmann::json>(nlohmann::json::object());
788             for (const std::string &Connection : connections)
789             {
790                 findObjectManagerPathForEnumerate(objectPath, Connection, res,
791                                                   transaction);
792             }
793         },
794         "xyz.openbmc_project.ObjectMapper",
795         "/xyz/openbmc_project/object_mapper",
796         "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
797         (int32_t)0, std::array<std::string, 0>());
798 }
799 
800 void handleGet(crow::Response &res, std::string &objectPath,
801                std::string &destProperty)
802 {
803     BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
804     std::shared_ptr<std::string> propertyName =
805         std::make_shared<std::string>(std::move(destProperty));
806 
807     std::shared_ptr<std::string> path =
808         std::make_shared<std::string>(std::move(objectPath));
809 
810     using GetObjectType =
811         std::vector<std::pair<std::string, std::vector<std::string>>>;
812     crow::connections::systemBus->async_method_call(
813         [&res, path, propertyName](const boost::system::error_code ec,
814                                    const GetObjectType &object_names) {
815             if (ec || object_names.size() <= 0)
816             {
817                 res.result(boost::beast::http::status::not_found);
818                 res.end();
819                 return;
820             }
821             std::shared_ptr<nlohmann::json> response =
822                 std::make_shared<nlohmann::json>(nlohmann::json::object());
823             // The mapper should never give us an empty interface names list,
824             // but check anyway
825             for (const std::pair<std::string, std::vector<std::string>>
826                      connection : object_names)
827             {
828                 const std::vector<std::string> &interfaceNames =
829                     connection.second;
830 
831                 if (interfaceNames.size() <= 0)
832                 {
833                     res.result(boost::beast::http::status::not_found);
834                     res.end();
835                     return;
836                 }
837 
838                 for (const std::string &interface : interfaceNames)
839                 {
840                     crow::connections::systemBus->async_method_call(
841                         [&res, response, propertyName](
842                             const boost::system::error_code ec,
843                             const std::vector<
844                                 std::pair<std::string, DbusRestVariantType>>
845                                 &properties) {
846                             if (ec)
847                             {
848                                 BMCWEB_LOG_ERROR << "Bad dbus request error: "
849                                                  << ec;
850                             }
851                             else
852                             {
853                                 for (const std::pair<std::string,
854                                                      DbusRestVariantType>
855                                          &property : properties)
856                                 {
857                                     // if property name is empty, or matches our
858                                     // search query, add it to the response json
859 
860                                     if (propertyName->empty())
861                                     {
862                                         mapbox::util::apply_visitor(
863                                             [&response, &property](auto &&val) {
864                                                 (*response)[property.first] =
865                                                     val;
866                                             },
867                                             property.second);
868                                     }
869                                     else if (property.first == *propertyName)
870                                     {
871                                         mapbox::util::apply_visitor(
872                                             [&response](auto &&val) {
873                                                 (*response) = val;
874                                             },
875                                             property.second);
876                                     }
877                                 }
878                             }
879                             if (response.use_count() == 1)
880                             {
881                                 res.jsonValue = {{"status", "ok"},
882                                                  {"message", "200 OK"},
883                                                  {"data", *response}};
884 
885                                 res.end();
886                             }
887                         },
888                         connection.first, *path,
889                         "org.freedesktop.DBus.Properties", "GetAll", interface);
890                 }
891             }
892         },
893         "xyz.openbmc_project.ObjectMapper",
894         "/xyz/openbmc_project/object_mapper",
895         "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
896         std::array<std::string, 0>());
897 }
898 
899 struct AsyncPutRequest
900 {
901     AsyncPutRequest(crow::Response &res) : res(res)
902     {
903         res.jsonValue = {
904             {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
905     }
906     ~AsyncPutRequest()
907     {
908         if (res.result() == boost::beast::http::status::internal_server_error)
909         {
910             // Reset the json object to clear out any data that made it in
911             // before the error happened todo(ed) handle error condition with
912             // proper code
913             res.jsonValue = nlohmann::json::object();
914         }
915 
916         if (res.jsonValue.empty())
917         {
918             res.result(boost::beast::http::status::forbidden);
919             res.jsonValue = {
920                 {"status", "error"},
921                 {"message", "403 Forbidden"},
922                 {"data",
923                  {{"message", "The specified property cannot be created: " +
924                                   propertyName}}}};
925         }
926 
927         res.end();
928     }
929 
930     void setErrorStatus()
931     {
932         res.result(boost::beast::http::status::internal_server_error);
933     }
934 
935     crow::Response &res;
936     std::string objectPath;
937     std::string propertyName;
938     nlohmann::json propertyValue;
939 };
940 
941 void handlePut(const crow::Request &req, crow::Response &res,
942                const std::string &objectPath, const std::string &destProperty)
943 {
944     nlohmann::json requestDbusData =
945         nlohmann::json::parse(req.body, nullptr, false);
946 
947     if (requestDbusData.is_discarded())
948     {
949         res.result(boost::beast::http::status::bad_request);
950         res.end();
951         return;
952     }
953 
954     nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
955     if (propertyIt == requestDbusData.end())
956     {
957         res.result(boost::beast::http::status::bad_request);
958         res.end();
959         return;
960     }
961     const nlohmann::json &propertySetValue = *propertyIt;
962     auto transaction = std::make_shared<AsyncPutRequest>(res);
963     transaction->objectPath = objectPath;
964     transaction->propertyName = destProperty;
965     transaction->propertyValue = propertySetValue;
966 
967     using GetObjectType =
968         std::vector<std::pair<std::string, std::vector<std::string>>>;
969 
970     crow::connections::systemBus->async_method_call(
971         [transaction](const boost::system::error_code ec,
972                       const GetObjectType &object_names) {
973             if (!ec && object_names.size() <= 0)
974             {
975                 transaction->res.result(boost::beast::http::status::not_found);
976                 return;
977             }
978 
979             for (const std::pair<std::string, std::vector<std::string>>
980                      connection : object_names)
981             {
982                 const std::string &connectionName = connection.first;
983 
984                 crow::connections::systemBus->async_method_call(
985                     [connectionName{std::string(connectionName)},
986                      transaction](const boost::system::error_code ec,
987                                   const std::string &introspectXml) {
988                         if (ec)
989                         {
990                             BMCWEB_LOG_ERROR
991                                 << "Introspect call failed with error: "
992                                 << ec.message()
993                                 << " on process: " << connectionName;
994                             transaction->setErrorStatus();
995                             return;
996                         }
997                         tinyxml2::XMLDocument doc;
998 
999                         doc.Parse(introspectXml.c_str());
1000                         tinyxml2::XMLNode *pRoot =
1001                             doc.FirstChildElement("node");
1002                         if (pRoot == nullptr)
1003                         {
1004                             BMCWEB_LOG_ERROR << "XML document failed to parse: "
1005                                              << introspectXml;
1006                             transaction->setErrorStatus();
1007                             return;
1008                         }
1009                         tinyxml2::XMLElement *ifaceNode =
1010                             pRoot->FirstChildElement("interface");
1011                         while (ifaceNode != nullptr)
1012                         {
1013                             const char *interfaceName =
1014                                 ifaceNode->Attribute("name");
1015                             BMCWEB_LOG_DEBUG << "found interface "
1016                                              << interfaceName;
1017                             tinyxml2::XMLElement *propNode =
1018                                 ifaceNode->FirstChildElement("property");
1019                             while (propNode != nullptr)
1020                             {
1021                                 const char *propertyName =
1022                                     propNode->Attribute("name");
1023                                 BMCWEB_LOG_DEBUG << "Found property "
1024                                                  << propertyName;
1025                                 if (propertyName == transaction->propertyName)
1026                                 {
1027                                     const char *argType =
1028                                         propNode->Attribute("type");
1029                                     if (argType != nullptr)
1030                                     {
1031                                         sdbusplus::message::message m =
1032                                             crow::connections::systemBus
1033                                                 ->new_method_call(
1034                                                     connectionName.c_str(),
1035                                                     transaction->objectPath
1036                                                         .c_str(),
1037                                                     "org.freedesktop.DBus."
1038                                                     "Properties",
1039                                                     "Set");
1040                                         m.append(interfaceName,
1041                                                  transaction->propertyName);
1042                                         int r = sd_bus_message_open_container(
1043                                             m.get(), SD_BUS_TYPE_VARIANT,
1044                                             argType);
1045                                         if (r < 0)
1046                                         {
1047                                             transaction->setErrorStatus();
1048                                             return;
1049                                         }
1050                                         r = convertJsonToDbus(
1051                                             m.get(), argType,
1052                                             transaction->propertyValue);
1053                                         if (r < 0)
1054                                         {
1055                                             transaction->setErrorStatus();
1056                                             return;
1057                                         }
1058                                         r = sd_bus_message_close_container(
1059                                             m.get());
1060                                         if (r < 0)
1061                                         {
1062                                             transaction->setErrorStatus();
1063                                             return;
1064                                         }
1065 
1066                                         crow::connections::systemBus
1067                                             ->async_send(
1068                                                 m,
1069                                                 [transaction](
1070                                                     boost::system::error_code
1071                                                         ec,
1072                                                     sdbusplus::message::message
1073                                                         &m) {
1074                                                     BMCWEB_LOG_DEBUG << "sent";
1075                                                     if (ec)
1076                                                     {
1077                                                         transaction->res
1078                                                             .jsonValue
1079                                                                 ["status"] =
1080                                                             "error";
1081                                                         transaction->res
1082                                                             .jsonValue
1083                                                                 ["message"] =
1084                                                             ec.message();
1085                                                     }
1086                                                 });
1087                                     }
1088                                 }
1089                                 propNode =
1090                                     propNode->NextSiblingElement("property");
1091                             }
1092                             ifaceNode =
1093                                 ifaceNode->NextSiblingElement("interface");
1094                         }
1095                     },
1096                     connectionName, transaction->objectPath,
1097                     "org.freedesktop.DBus.Introspectable", "Introspect");
1098             }
1099         },
1100         "xyz.openbmc_project.ObjectMapper",
1101         "/xyz/openbmc_project/object_mapper",
1102         "xyz.openbmc_project.ObjectMapper", "GetObject",
1103         transaction->objectPath, std::array<std::string, 0>());
1104 }
1105 
1106 template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1107 {
1108     BMCWEB_ROUTE(app, "/bus/")
1109         .methods("GET"_method)(
1110             [](const crow::Request &req, crow::Response &res) {
1111                 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1112                                  {"status", "ok"}};
1113                 res.end();
1114             });
1115 
1116     BMCWEB_ROUTE(app, "/bus/system/")
1117         .methods("GET"_method)(
1118             [](const crow::Request &req, crow::Response &res) {
1119                 auto myCallback = [&res](const boost::system::error_code ec,
1120                                          std::vector<std::string> &names) {
1121                     if (ec)
1122                     {
1123                         BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1124                         res.result(
1125                             boost::beast::http::status::internal_server_error);
1126                     }
1127                     else
1128                     {
1129                         std::sort(names.begin(), names.end());
1130                         res.jsonValue = {{"status", "ok"}};
1131                         auto &objectsSub = res.jsonValue["objects"];
1132                         for (auto &name : names)
1133                         {
1134                             objectsSub.push_back({{"name", name}});
1135                         }
1136                     }
1137                     res.end();
1138                 };
1139                 crow::connections::systemBus->async_method_call(
1140                     std::move(myCallback), "org.freedesktop.DBus", "/",
1141                     "org.freedesktop.DBus", "ListNames");
1142             });
1143 
1144     BMCWEB_ROUTE(app, "/list/")
1145         .methods("GET"_method)(
1146             [](const crow::Request &req, crow::Response &res) {
1147                 handleList(res, "/");
1148             });
1149 
1150     BMCWEB_ROUTE(app, "/xyz/<path>")
1151         .methods("GET"_method, "PUT"_method,
1152                  "POST"_method)([](const crow::Request &req,
1153                                    crow::Response &res,
1154                                    const std::string &path) {
1155             std::string objectPath = "/xyz/" + path;
1156 
1157             // Trim any trailing "/" at the end
1158             if (boost::ends_with(objectPath, "/"))
1159             {
1160                 objectPath.pop_back();
1161             }
1162 
1163             // If accessing a single attribute, fill in and update objectPath,
1164             // otherwise leave destProperty blank
1165             std::string destProperty = "";
1166             const char *attrSeperator = "/attr/";
1167             size_t attrPosition = path.find(attrSeperator);
1168             if (attrPosition != path.npos)
1169             {
1170                 objectPath = "/xyz/" + path.substr(0, attrPosition);
1171                 destProperty = path.substr(attrPosition + strlen(attrSeperator),
1172                                            path.length());
1173             }
1174 
1175             if (req.method() == "POST"_method)
1176             {
1177                 constexpr const char *actionSeperator = "/action/";
1178                 size_t actionPosition = path.find(actionSeperator);
1179                 if (actionPosition != path.npos)
1180                 {
1181                     objectPath = "/xyz/" + path.substr(0, actionPosition);
1182                     std::string postProperty =
1183                         path.substr((actionPosition + strlen(actionSeperator)),
1184                                     path.length());
1185                     handleAction(req, res, objectPath, postProperty);
1186                     return;
1187                 }
1188             }
1189             else if (req.method() == "GET"_method)
1190             {
1191                 if (boost::ends_with(objectPath, "/enumerate"))
1192                 {
1193                     objectPath.erase(objectPath.end() - 10, objectPath.end());
1194                     handleEnumerate(res, objectPath);
1195                 }
1196                 else if (boost::ends_with(objectPath, "/list"))
1197                 {
1198                     objectPath.erase(objectPath.end() - 5, objectPath.end());
1199                     handleList(res, objectPath);
1200                 }
1201                 else
1202                 {
1203                     handleGet(res, objectPath, destProperty);
1204                 }
1205                 return;
1206             }
1207             else if (req.method() == "PUT"_method)
1208             {
1209                 handlePut(req, res, objectPath, destProperty);
1210                 return;
1211             }
1212 
1213             res.result(boost::beast::http::status::method_not_allowed);
1214             res.end();
1215         });
1216 
1217     BMCWEB_ROUTE(app, "/download/dump/<str>/")
1218         .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1219                                   const std::string &dumpId) {
1220             std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
1221             if (!std::regex_match(dumpId, validFilename))
1222             {
1223                 res.result(boost::beast::http::status::not_found);
1224                 res.end();
1225                 return;
1226             }
1227             std::experimental::filesystem::path loc(
1228                 "/var/lib/phosphor-debug-collector/dumps");
1229 
1230             loc += dumpId;
1231 
1232             if (!std::experimental::filesystem::exists(loc) ||
1233                 !std::experimental::filesystem::is_directory(loc))
1234             {
1235                 res.result(boost::beast::http::status::not_found);
1236                 res.end();
1237                 return;
1238             }
1239             std::experimental::filesystem::directory_iterator files(loc);
1240             for (auto &file : files)
1241             {
1242                 std::ifstream readFile(file.path());
1243                 if (readFile.good())
1244                 {
1245                     continue;
1246                 }
1247                 res.addHeader("Content-Type", "application/octet-stream");
1248                 res.body() = {std::istreambuf_iterator<char>(readFile),
1249                               std::istreambuf_iterator<char>()};
1250                 res.end();
1251             }
1252             res.result(boost::beast::http::status::not_found);
1253             res.end();
1254             return;
1255         });
1256 
1257     BMCWEB_ROUTE(app, "/bus/system/<str>/")
1258         .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1259                                   const std::string &Connection) {
1260             introspectObjects(Connection, "/",
1261                               std::make_shared<bmcweb::AsyncResp>(res));
1262         });
1263 
1264     BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1265         .methods("GET"_method,
1266                  "POST"_method)([](const crow::Request &req,
1267                                    crow::Response &res,
1268                                    const std::string &processName,
1269                                    const std::string &requestedPath) {
1270             std::vector<std::string> strs;
1271             boost::split(strs, requestedPath, boost::is_any_of("/"));
1272             std::string objectPath;
1273             std::string interfaceName;
1274             std::string methodName;
1275             auto it = strs.begin();
1276             if (it == strs.end())
1277             {
1278                 objectPath = "/";
1279             }
1280             while (it != strs.end())
1281             {
1282                 // Check if segment contains ".".  If it does, it must be an
1283                 // interface
1284                 if (it->find(".") != std::string::npos)
1285                 {
1286                     break;
1287                     // This check is neccesary as the trailing slash gets parsed
1288                     // as part of our <path> specifier above, which causes the
1289                     // normal trailing backslash redirector to fail.
1290                 }
1291                 else if (!it->empty())
1292                 {
1293                     objectPath += "/" + *it;
1294                 }
1295                 it++;
1296             }
1297             if (it != strs.end())
1298             {
1299                 interfaceName = *it;
1300                 it++;
1301 
1302                 // after interface, we might have a method name
1303                 if (it != strs.end())
1304                 {
1305                     methodName = *it;
1306                     it++;
1307                 }
1308             }
1309             if (it != strs.end())
1310             {
1311                 // if there is more levels past the method name, something went
1312                 // wrong, return not found
1313                 res.result(boost::beast::http::status::not_found);
1314                 res.end();
1315                 return;
1316             }
1317             if (interfaceName.empty())
1318             {
1319                 crow::connections::systemBus->async_method_call(
1320                     [&, processName,
1321                      objectPath](const boost::system::error_code ec,
1322                                  const std::string &introspect_xml) {
1323                         if (ec)
1324                         {
1325                             BMCWEB_LOG_ERROR
1326                                 << "Introspect call failed with error: "
1327                                 << ec.message()
1328                                 << " on process: " << processName
1329                                 << " path: " << objectPath << "\n";
1330                             return;
1331                         }
1332                         tinyxml2::XMLDocument doc;
1333 
1334                         doc.Parse(introspect_xml.c_str());
1335                         tinyxml2::XMLNode *pRoot =
1336                             doc.FirstChildElement("node");
1337                         if (pRoot == nullptr)
1338                         {
1339                             BMCWEB_LOG_ERROR << "XML document failed to parse "
1340                                              << processName << " " << objectPath
1341                                              << "\n";
1342                             res.jsonValue = {{"status", "XML parse error"}};
1343                             res.result(boost::beast::http::status::
1344                                            internal_server_error);
1345                             return;
1346                         }
1347 
1348                         BMCWEB_LOG_DEBUG << introspect_xml;
1349                         res.jsonValue = {{"status", "ok"},
1350                                          {"bus_name", processName},
1351                                          {"object_path", objectPath}};
1352                         nlohmann::json &interfacesArray =
1353                             res.jsonValue["interfaces"];
1354                         interfacesArray = nlohmann::json::array();
1355                         tinyxml2::XMLElement *interface =
1356                             pRoot->FirstChildElement("interface");
1357 
1358                         while (interface != nullptr)
1359                         {
1360                             const char *ifaceName =
1361                                 interface->Attribute("name");
1362                             if (ifaceName != nullptr)
1363                             {
1364                                 interfacesArray.push_back(
1365                                     {{"name", ifaceName}});
1366                             }
1367 
1368                             interface =
1369                                 interface->NextSiblingElement("interface");
1370                         }
1371 
1372                         res.end();
1373                     },
1374                     processName, objectPath,
1375                     "org.freedesktop.DBus.Introspectable", "Introspect");
1376             }
1377             else if (methodName.empty())
1378             {
1379                 crow::connections::systemBus->async_method_call(
1380                     [&, processName, objectPath,
1381                      interfaceName{std::move(interfaceName)}](
1382                         const boost::system::error_code ec,
1383                         const std::string &introspect_xml) {
1384                         if (ec)
1385                         {
1386                             BMCWEB_LOG_ERROR
1387                                 << "Introspect call failed with error: "
1388                                 << ec.message()
1389                                 << " on process: " << processName
1390                                 << " path: " << objectPath << "\n";
1391                         }
1392                         else
1393                         {
1394                             tinyxml2::XMLDocument doc;
1395 
1396                             doc.Parse(introspect_xml.c_str());
1397                             tinyxml2::XMLNode *pRoot =
1398                                 doc.FirstChildElement("node");
1399                             if (pRoot == nullptr)
1400                             {
1401                                 BMCWEB_LOG_ERROR
1402                                     << "XML document failed to parse "
1403                                     << processName << " " << objectPath << "\n";
1404                                 res.result(boost::beast::http::status::
1405                                                internal_server_error);
1406                             }
1407                             else
1408                             {
1409                                 tinyxml2::XMLElement *node =
1410                                     pRoot->FirstChildElement("node");
1411 
1412                                 // if we know we're the only call, build the
1413                                 // json directly
1414                                 tinyxml2::XMLElement *interface =
1415                                     pRoot->FirstChildElement("interface");
1416 
1417                                 res.jsonValue = {
1418                                     {"status", "ok"},
1419                                     {"bus_name", processName},
1420                                     {"interface", interfaceName},
1421                                     {"object_path", objectPath},
1422                                     {"properties", nlohmann::json::object()}};
1423 
1424                                 nlohmann::json &methodsArray =
1425                                     res.jsonValue["methods"];
1426                                 methodsArray = nlohmann::json::array();
1427 
1428                                 nlohmann::json &signalsArray =
1429                                     res.jsonValue["signals"];
1430                                 signalsArray = nlohmann::json::array();
1431 
1432                                 while (interface != nullptr)
1433                                 {
1434                                     const char *ifaceName =
1435                                         interface->Attribute("name");
1436 
1437                                     if (ifaceName != nullptr &&
1438                                         ifaceName == interfaceName)
1439                                     {
1440                                         tinyxml2::XMLElement *methods =
1441                                             interface->FirstChildElement(
1442                                                 "method");
1443                                         while (methods != nullptr)
1444                                         {
1445                                             nlohmann::json argsArray =
1446                                                 nlohmann::json::array();
1447                                             tinyxml2::XMLElement *arg =
1448                                                 methods->FirstChildElement(
1449                                                     "arg");
1450                                             while (arg != nullptr)
1451                                             {
1452                                                 nlohmann::json thisArg;
1453                                                 for (const char *fieldName :
1454                                                      std::array<const char *,
1455                                                                 3>{"name",
1456                                                                    "direction",
1457                                                                    "type"})
1458                                                 {
1459                                                     const char *fieldValue =
1460                                                         arg->Attribute(
1461                                                             fieldName);
1462                                                     if (fieldValue != nullptr)
1463                                                     {
1464                                                         thisArg[fieldName] =
1465                                                             fieldValue;
1466                                                     }
1467                                                 }
1468                                                 argsArray.push_back(
1469                                                     std::move(thisArg));
1470                                                 arg = arg->NextSiblingElement(
1471                                                     "arg");
1472                                             }
1473 
1474                                             const char *name =
1475                                                 methods->Attribute("name");
1476                                             if (name != nullptr)
1477                                             {
1478                                                 methodsArray.push_back(
1479                                                     {{"name", name},
1480                                                      {"uri", "/bus/system/" +
1481                                                                  processName +
1482                                                                  objectPath +
1483                                                                  "/" +
1484                                                                  interfaceName +
1485                                                                  "/" + name},
1486                                                      {"args", argsArray}});
1487                                             }
1488                                             methods =
1489                                                 methods->NextSiblingElement(
1490                                                     "method");
1491                                         }
1492                                         tinyxml2::XMLElement *signals =
1493                                             interface->FirstChildElement(
1494                                                 "signal");
1495                                         while (signals != nullptr)
1496                                         {
1497                                             nlohmann::json argsArray =
1498                                                 nlohmann::json::array();
1499 
1500                                             tinyxml2::XMLElement *arg =
1501                                                 signals->FirstChildElement(
1502                                                     "arg");
1503                                             while (arg != nullptr)
1504                                             {
1505                                                 const char *name =
1506                                                     arg->Attribute("name");
1507                                                 const char *type =
1508                                                     arg->Attribute("type");
1509                                                 if (name != nullptr &&
1510                                                     type != nullptr)
1511                                                 {
1512                                                     argsArray.push_back({
1513                                                         {"name", name},
1514                                                         {"type", type},
1515                                                     });
1516                                                 }
1517                                                 arg = arg->NextSiblingElement(
1518                                                     "arg");
1519                                             }
1520                                             const char *name =
1521                                                 signals->Attribute("name");
1522                                             if (name != nullptr)
1523                                             {
1524                                                 signalsArray.push_back(
1525                                                     {{"name", name},
1526                                                      {"args", argsArray}});
1527                                             }
1528 
1529                                             signals =
1530                                                 signals->NextSiblingElement(
1531                                                     "signal");
1532                                         }
1533 
1534                                         break;
1535                                     }
1536 
1537                                     interface = interface->NextSiblingElement(
1538                                         "interface");
1539                                 }
1540                                 if (interface == nullptr)
1541                                 {
1542                                     // if we got to the end of the list and
1543                                     // never found a match, throw 404
1544                                     res.result(
1545                                         boost::beast::http::status::not_found);
1546                                 }
1547                             }
1548                         }
1549                         res.end();
1550                     },
1551                     processName, objectPath,
1552                     "org.freedesktop.DBus.Introspectable", "Introspect");
1553             }
1554             else
1555             {
1556                 if (req.method() != "POST"_method)
1557                 {
1558                     res.result(boost::beast::http::status::not_found);
1559                     res.end();
1560                     return;
1561                 }
1562 
1563                 nlohmann::json requestDbusData =
1564                     nlohmann::json::parse(req.body, nullptr, false);
1565 
1566                 if (requestDbusData.is_discarded())
1567                 {
1568                     res.result(boost::beast::http::status::bad_request);
1569                     res.end();
1570                     return;
1571                 }
1572                 if (!requestDbusData.is_array())
1573                 {
1574                     res.result(boost::beast::http::status::bad_request);
1575                     res.end();
1576                     return;
1577                 }
1578                 auto transaction = std::make_shared<InProgressActionData>(res);
1579 
1580                 transaction->path = objectPath;
1581                 transaction->methodName = methodName;
1582                 transaction->arguments = std::move(requestDbusData);
1583 
1584                 findActionOnInterface(transaction, processName);
1585             }
1586         });
1587 }
1588 } // namespace openbmc_mapper
1589 } // namespace crow
1590