summaryrefslogtreecommitdiff
path: root/http
diff options
context:
space:
mode:
authorAbhilash Raju <abhilash.kollam@gmail.com>2023-11-09 07:32:44 +0300
committerEd Tanous <ed@tanous.net>2024-01-22 22:15:20 +0300
commitb5f288d294e17719f30e32acc40e07681baf04b9 (patch)
tree7ccfd67ef408e0fc5d508ac9266040d3d4a879fe /http
parentee192c065cc658b2489d04c791e2fb956a331699 (diff)
downloadbmcweb-b5f288d294e17719f30e32acc40e07681baf04b9.tar.xz
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>
Diffstat (limited to 'http')
-rw-r--r--http/http_file_body.hpp136
-rw-r--r--http/http_response.hpp34
2 files changed, 163 insertions, 7 deletions
diff --git a/http/http_file_body.hpp b/http/http_file_body.hpp
new file mode 100644
index 0000000000..eaafd5dbeb
--- /dev/null
+++ b/http/http_file_body.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+#include "utility.hpp"
+
+#include <boost/beast/core/file_posix.hpp>
+#include <boost/beast/http/message.hpp>
+#include <boost/system/error_code.hpp>
+
+namespace bmcweb
+{
+struct FileBody
+{
+ class writer;
+ class value_type;
+
+ static std::uint64_t size(const value_type& body);
+};
+
+enum class EncodingType
+{
+ Raw,
+ Base64,
+};
+
+class FileBody::value_type
+{
+ boost::beast::file_posix fileHandle;
+
+ std::uint64_t fileSize = 0;
+
+ public:
+ EncodingType encodingType = EncodingType::Raw;
+
+ ~value_type() = default;
+ value_type() = default;
+ explicit value_type(EncodingType enc) : encodingType(enc) {}
+ value_type(value_type&& other) = default;
+ value_type& operator=(value_type&& other) = default;
+ value_type(const value_type& other) = delete;
+ value_type& operator=(const value_type& other) = delete;
+
+ boost::beast::file_posix& file()
+ {
+ return fileHandle;
+ }
+
+ std::uint64_t size() const
+ {
+ return fileSize;
+ }
+
+ void open(const char* path, boost::beast::file_mode mode,
+ boost::system::error_code& ec)
+ {
+ fileHandle.open(path, mode, ec);
+ fileSize = fileHandle.size(ec);
+ }
+
+ void setFd(int fd, boost::system::error_code& ec)
+ {
+ fileHandle.native_handle(fd);
+ fileSize = fileHandle.size(ec);
+ }
+};
+
+inline std::uint64_t FileBody::size(const value_type& body)
+{
+ return body.size();
+}
+
+class FileBody::writer
+{
+ public:
+ using const_buffers_type = boost::asio::const_buffer;
+
+ private:
+ std::string buf;
+ crow::utility::Base64Encoder encoder;
+
+ value_type& body;
+ std::uint64_t remain;
+ constexpr static size_t readBufSize = 4096;
+ std::array<char, readBufSize> fileReadBuf{};
+
+ public:
+ template <bool IsRequest, class Fields>
+ writer(boost::beast::http::header<IsRequest, Fields>& /*header*/,
+ value_type& bodyIn) :
+ body(bodyIn),
+ remain(body.size())
+ {}
+
+ static void init(boost::beast::error_code& ec)
+ {
+ ec = {};
+ }
+
+ boost::optional<std::pair<const_buffers_type, bool>>
+ get(boost::beast::error_code& ec)
+ {
+ size_t toRead = fileReadBuf.size();
+ if (remain < toRead)
+ {
+ toRead = static_cast<size_t>(remain);
+ }
+ size_t read = body.file().read(fileReadBuf.data(), toRead, ec);
+ if (read != toRead || ec)
+ {
+ return boost::none;
+ }
+ remain -= read;
+
+ std::string_view chunkView(fileReadBuf.data(), read);
+
+ std::pair<const_buffers_type, bool> ret;
+ ret.second = remain > 0;
+ if (body.encodingType == EncodingType::Base64)
+ {
+ buf.clear();
+ buf.reserve(
+ crow::utility::Base64Encoder::encodedSize(chunkView.size()));
+ encoder.encode(chunkView, buf);
+ if (!ret.second)
+ {
+ encoder.finalize(buf);
+ }
+ ret.first = const_buffers_type(buf.data(), buf.size());
+ }
+ else
+ {
+ ret.first = const_buffers_type(chunkView.data(), chunkView.size());
+ }
+ return ret;
+ }
+};
+} // namespace bmcweb
diff --git a/http/http_response.hpp b/http/http_response.hpp
index ec54a90c4b..40158992e4 100644
--- a/http/http_response.hpp
+++ b/http/http_response.hpp
@@ -1,8 +1,8 @@
#pragma once
+#include "http_file_body.hpp"
#include "logging.hpp"
#include "utils/hex_utils.hpp"
-#include <boost/beast/http/file_body.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/message_generator.hpp>
#include <boost/beast/http/string_body.hpp>
@@ -27,7 +27,7 @@ struct Response
friend class crow::Connection;
using string_response = http::response<http::string_body>;
- using file_response = http::response<http::file_body>;
+ using file_response = http::response<bmcweb::FileBody>;
// Use boost variant2 because it doesn't have valueless by exception
boost::variant2::variant<string_response, file_response> response;
@@ -356,25 +356,45 @@ struct Response
response);
}
- bool openFile(const std::filesystem::path& path)
+ bool openFile(const std::filesystem::path& path,
+ bmcweb::EncodingType enc = bmcweb::EncodingType::Raw)
{
- http::file_body::value_type file;
+ file_response::body_type::value_type body(enc);
boost::beast::error_code ec;
- file.open(path.c_str(), boost::beast::file_mode::read, ec);
+ body.open(path.c_str(), boost::beast::file_mode::read, ec);
if (ec)
{
return false;
}
+ updateFileBody(std::move(body));
+ return true;
+ }
+
+ bool openFd(int fd, bmcweb::EncodingType enc = bmcweb::EncodingType::Raw)
+ {
+ file_response::body_type::value_type body(enc);
+ boost::beast::error_code ec;
+ body.setFd(fd, ec);
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("Failed to set fd");
+ return false;
+ }
+ updateFileBody(std::move(body));
+ return true;
+ }
+
+ private:
+ void updateFileBody(file_response::body_type::value_type file)
+ {
// store the headers on stack temporarily so we can reconstruct the new
// base with the old headers copied in.
http::header<false> headTemp = std::move(fields());
file_response& fileResponse =
response.emplace<file_response>(std::move(headTemp));
fileResponse.body() = std::move(file);
- return true;
}
- private:
std::optional<std::string> expectedHash;
bool completed = false;
std::function<void(Response&)> completeRequestHandler;