REST: Add method return support for structs

A struct is in its own sd_bus_message container,
and the output JSON looks like an array.

Change-Id: Ie8e5848a5fa9bc9605f5dda06dc1b5d7be4dea3c
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
index a9a6a10..a5024be 100644
--- a/include/openbmc_dbus_rest.hpp
+++ b/include/openbmc_dbus_rest.hpp
@@ -954,6 +954,47 @@
     return 0;
 }
 
+int readStructFromMessage(const std::string &typeCode,
+                          sdbusplus::message::message &m, nlohmann::json &data)
+{
+    if (typeCode.size() < 3)
+    {
+        BMCWEB_LOG_ERROR << "Type code " << typeCode
+                         << " too small for a struct";
+        return -1;
+    }
+
+    std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
+    std::vector<std::string> types = dbusArgSplit(containedTypes);
+
+    int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
+                                           containedTypes.c_str());
+    if (r < 0)
+    {
+        BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
+                         << r;
+        return r;
+    }
+
+    for (const std::string &type : types)
+    {
+        data.push_back(nlohmann::json());
+        r = convertDBusToJSON(type, m, data.back());
+        if (r < 0)
+        {
+            return r;
+        }
+    }
+
+    r = sd_bus_message_exit_container(m.get());
+    if (r < 0)
+    {
+        BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
+        return r;
+    }
+    return 0;
+}
+
 int convertDBusToJSON(const std::string &returnType,
                       sdbusplus::message::message &m, nlohmann::json &response)
 {
@@ -1083,9 +1124,18 @@
                 return r;
             }
         }
+        else if (boost::starts_with(typeCode, "(") &&
+                 boost::ends_with(typeCode, ")"))
+        {
+            r = readStructFromMessage(typeCode, m, thisElement);
+            if (r < 0)
+            {
+                return r;
+            }
+        }
         else
         {
-            // TODO: add struct, variant support
+            // TODO: add variant support
             BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
             return -2;
         }