blob: eaafd5dbeb24b39aa42e51ed57bb916449f5275a [file] [log] [blame]
#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