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");
}