Task: Add payload support

This adds the payload values to task responses.

Tested: passed validator

Change-Id: I50467e28ce8142d198f916ea0c63bd413edcd524
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/http/http_request.h b/http/http_request.h
index ff09bf1..b440f44 100644
--- a/http/http_request.h
+++ b/http/http_request.h
@@ -15,6 +15,7 @@
 struct Request
 {
     boost::beast::http::request<boost::beast::http::string_body>& req;
+    boost::beast::http::fields& fields;
     std::string_view url{};
     QueryString urlParams{};
     bool isSecure{false};
@@ -31,7 +32,7 @@
     Request(
         boost::beast::http::request<boost::beast::http::string_body>& reqIn) :
         req(reqIn),
-        body(reqIn.body())
+        fields(reqIn.base()), body(reqIn.body())
     {
     }
 
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index fd414aa..b7fe62c 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -1850,10 +1850,10 @@
     {
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
 
-        auto generateonDemandLogCallback = [asyncResp](
-                                               const boost::system::error_code
-                                                   ec,
-                                               const std::string &resp) {
+        auto generateonDemandLogCallback = [asyncResp,
+                                            req](const boost::system::error_code
+                                                     ec,
+                                                 const std::string &resp) {
             if (ec)
             {
                 if (ec.value() == boost::system::errc::operation_not_supported)
@@ -1887,6 +1887,7 @@
                 "crashdump'");
             task->startTimer(std::chrono::minutes(5));
             task->populateResp(asyncResp->res);
+            task->payload.emplace(req);
         };
         crow::connections::systemBus->async_method_call(
             std::move(generateonDemandLogCallback), crashdumpObject,
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index e95eb2e..e224d6c 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -32,6 +32,58 @@
 
 constexpr bool completed = true;
 
+struct Payload
+{
+    Payload(const crow::Request &req) :
+        targetUri(req.url), httpOperation(req.methodString()),
+        httpHeaders(nlohmann::json::array())
+
+    {
+        using field_ns = boost::beast::http::field;
+        constexpr const std::array<boost::beast::http::field, 7>
+            headerWhitelist = {field_ns::accept,     field_ns::accept_encoding,
+                               field_ns::user_agent, field_ns::host,
+                               field_ns::connection, field_ns::content_length,
+                               field_ns::upgrade};
+
+        jsonBody = nlohmann::json::parse(req.body, nullptr, false);
+        if (jsonBody.is_discarded())
+        {
+            jsonBody = nullptr;
+        }
+
+        for (const auto &field : req.fields)
+        {
+            if (std::find(headerWhitelist.begin(), headerWhitelist.end(),
+                          field.name()) == headerWhitelist.end())
+            {
+                continue;
+            }
+            std::string header;
+            header.reserve(field.name_string().size() + 2 +
+                           field.value().size());
+            header += field.name_string();
+            header += ": ";
+            header += field.value();
+            httpHeaders.emplace_back(std::move(header));
+        }
+    }
+    Payload() = delete;
+
+    std::string targetUri;
+    std::string httpOperation;
+    nlohmann::json httpHeaders;
+    nlohmann::json jsonBody;
+};
+
+inline void to_json(nlohmann::json &j, const Payload &p)
+{
+    j = {{"TargetUri", p.targetUri},
+         {"HttpOperation", p.httpOperation},
+         {"HttpHeaders", p.httpHeaders},
+         {"JsonBody", p.jsonBody.dump()}};
+}
+
 struct TaskData : std::enable_shared_from_this<TaskData>
 {
   private:
@@ -169,6 +221,7 @@
     boost::asio::steady_timer timer;
     std::unique_ptr<sdbusplus::bus::match::match> match;
     std::optional<time_t> endTime;
+    std::optional<Payload> payload;
     bool gave204 = false;
 };
 
@@ -299,6 +352,10 @@
             asyncResp->res.jsonValue["TaskMonitor"] =
                 "/redfish/v1/TaskService/Tasks/" + strParam + "/Monitor";
         }
+        if (ptr->payload)
+        {
+            asyncResp->res.jsonValue["Payload"] = *(ptr->payload);
+        }
     }
 };
 
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 3ca7721..e9793eb 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -58,7 +58,8 @@
 // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
 // then no asyncResp updates will occur
 static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
-                                   sdbusplus::message::message &m)
+                                   sdbusplus::message::message &m,
+                                   const crow::Request &req)
 {
     std::vector<std::pair<
         std::string,
@@ -81,10 +82,10 @@
 
             // Retrieve service and activate
             crow::connections::systemBus->async_method_call(
-                [objPath, asyncResp](
-                    const boost::system::error_code error_code,
-                    const std::vector<std::pair<
-                        std::string, std::vector<std::string>>> &objInfo) {
+                [objPath, asyncResp,
+                 req](const boost::system::error_code error_code,
+                      const std::vector<std::pair<
+                          std::string, std::vector<std::string>>> &objInfo) {
                     if (error_code)
                     {
                         BMCWEB_LOG_DEBUG << "error_code = " << error_code;
@@ -188,6 +189,7 @@
                                     objPath.str + "'");
                         task->startTimer(std::chrono::minutes(5));
                         task->populateResp(asyncResp->res);
+                        task->payload.emplace(req);
                     }
                     fwUpdateInProgress = false;
                 },
@@ -244,9 +246,9 @@
             }
         });
 
-    auto callback = [asyncResp](sdbusplus::message::message &m) {
+    auto callback = [asyncResp, req](sdbusplus::message::message &m) {
         BMCWEB_LOG_DEBUG << "Match fired";
-        softwareInterfaceAdded(asyncResp, m);
+        softwareInterfaceAdded(asyncResp, m, req);
     };
 
     fwUpdateInProgress = true;