Make use of filebody for dump offload

Logservice has been rewritten to use file_body to offload dump files
from BMC.

There are two kind of dump files, BMC dump and System dump.While BMC
dump just requires default support from beast::file_body, System dump
requires base64 encoding support from beast. But beast::file_body do not
have ready-made support for base64 encoding. So a custom file_body has
been written for the base64 encoding.

The openFile apis in crow::Response do not have support for unix file
descriptor. Since dump files are accesses via descriptors, added new
openFile api that accepts descriptors.

Tested:
Functionality test have been executed to verify the bmc dump offload.
Did sanity test by invoking bmcweb pages via browser.

Change-Id: I24192657c03d8b2f0394d31e7424c6796ba3227a
Signed-off-by: Abhilash Raju <abhilash.kollam@gmail.com>
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 371ae44..24f0251 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -45,6 +45,7 @@
 
 #include <array>
 #include <charconv>
+#include <cstddef>
 #include <filesystem>
 #include <iterator>
 #include <optional>
@@ -745,7 +746,35 @@
         std::format("{}/entry/{}", getDumpPath(dumpType), entryID),
         "xyz.openbmc_project.Object.Delete", "Delete");
 }
+inline bool checkSizeLimit(int fd, crow::Response& res)
+{
+    long long int size = lseek(fd, 0, SEEK_END);
+    if (size <= 0)
+    {
+        BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}",
+                         size);
+        messages::internalError(res);
+        return false;
+    }
 
+    // Arbitrary max size of 20MB to accommodate BMC dumps
+    constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL;
+    if (size > maxFileSize)
+    {
+        BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}",
+                         size, maxFileSize);
+        messages::internalError(res);
+        return false;
+    }
+    off_t rc = lseek(fd, 0, SEEK_SET);
+    if (rc < 0)
+    {
+        BMCWEB_LOG_ERROR("Failed to reset file offset to 0");
+        messages::internalError(res);
+        return false;
+    }
+    return true;
+}
 inline void
     downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
                           const std::string& entryID,
@@ -781,59 +810,29 @@
         messages::internalError(asyncResp->res);
         return;
     }
-
-    long long int size = lseek(fd, 0, SEEK_END);
-    if (size <= 0)
+    if (!checkSizeLimit(fd, asyncResp->res))
     {
-        BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}",
-                         size);
-        messages::internalError(asyncResp->res);
         close(fd);
         return;
     }
-
-    // Arbitrary max size of 20MB to accommodate BMC dumps
-    constexpr int maxFileSize = 20 * 1024 * 1024;
-    if (size > maxFileSize)
-    {
-        BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}",
-                         size, maxFileSize);
-        messages::internalError(asyncResp->res);
-        close(fd);
-        return;
-    }
-    long long int rc = lseek(fd, 0, SEEK_SET);
-    if (rc < 0)
-    {
-        BMCWEB_LOG_ERROR("Failed to reset file offset to 0");
-        messages::internalError(asyncResp->res);
-        close(fd);
-        return;
-    }
-
-    std::string body;
-    body.resize(static_cast<size_t>(size), '\0');
-    rc = read(fd, body.data(), body.size());
-    if ((rc == -1) || (rc != size))
-    {
-        BMCWEB_LOG_ERROR("Failed to read in file");
-        messages::internalError(asyncResp->res);
-        close(fd);
-        return;
-    }
-    close(fd);
     if (downloadEntryType == "System")
     {
-        // Base64 encode response.
-        asyncResp->res.write(crow::utility::base64encode(body));
+        if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64))
+        {
+            messages::internalError(asyncResp->res);
+            close(fd);
+            return;
+        }
         asyncResp->res.addHeader(
             boost::beast::http::field::content_transfer_encoding, "Base64");
+        return;
     }
-    else
+    if (!asyncResp->res.openFd(fd))
     {
-        asyncResp->res.write(std::move(body));
+        messages::internalError(asyncResp->res);
+        close(fd);
+        return;
     }
-
     asyncResp->res.addHeader(boost::beast::http::field::content_type,
                              "application/octet-stream");
 }