blob: eaafd5dbeb24b39aa42e51ed57bb916449f5275a [file] [log] [blame]
Abhilash Rajub5f288d2023-11-08 22:32:44 -06001#pragma once
2
3#include "utility.hpp"
4
5#include <boost/beast/core/file_posix.hpp>
6#include <boost/beast/http/message.hpp>
7#include <boost/system/error_code.hpp>
8
9namespace bmcweb
10{
11struct FileBody
12{
13 class writer;
14 class value_type;
15
16 static std::uint64_t size(const value_type& body);
17};
18
19enum class EncodingType
20{
21 Raw,
22 Base64,
23};
24
25class FileBody::value_type
26{
27 boost::beast::file_posix fileHandle;
28
29 std::uint64_t fileSize = 0;
30
31 public:
32 EncodingType encodingType = EncodingType::Raw;
33
34 ~value_type() = default;
35 value_type() = default;
36 explicit value_type(EncodingType enc) : encodingType(enc) {}
37 value_type(value_type&& other) = default;
38 value_type& operator=(value_type&& other) = default;
39 value_type(const value_type& other) = delete;
40 value_type& operator=(const value_type& other) = delete;
41
42 boost::beast::file_posix& file()
43 {
44 return fileHandle;
45 }
46
47 std::uint64_t size() const
48 {
49 return fileSize;
50 }
51
52 void open(const char* path, boost::beast::file_mode mode,
53 boost::system::error_code& ec)
54 {
55 fileHandle.open(path, mode, ec);
56 fileSize = fileHandle.size(ec);
57 }
58
59 void setFd(int fd, boost::system::error_code& ec)
60 {
61 fileHandle.native_handle(fd);
62 fileSize = fileHandle.size(ec);
63 }
64};
65
66inline std::uint64_t FileBody::size(const value_type& body)
67{
68 return body.size();
69}
70
71class FileBody::writer
72{
73 public:
74 using const_buffers_type = boost::asio::const_buffer;
75
76 private:
77 std::string buf;
78 crow::utility::Base64Encoder encoder;
79
80 value_type& body;
81 std::uint64_t remain;
82 constexpr static size_t readBufSize = 4096;
83 std::array<char, readBufSize> fileReadBuf{};
84
85 public:
86 template <bool IsRequest, class Fields>
87 writer(boost::beast::http::header<IsRequest, Fields>& /*header*/,
88 value_type& bodyIn) :
89 body(bodyIn),
90 remain(body.size())
91 {}
92
93 static void init(boost::beast::error_code& ec)
94 {
95 ec = {};
96 }
97
98 boost::optional<std::pair<const_buffers_type, bool>>
99 get(boost::beast::error_code& ec)
100 {
101 size_t toRead = fileReadBuf.size();
102 if (remain < toRead)
103 {
104 toRead = static_cast<size_t>(remain);
105 }
106 size_t read = body.file().read(fileReadBuf.data(), toRead, ec);
107 if (read != toRead || ec)
108 {
109 return boost::none;
110 }
111 remain -= read;
112
113 std::string_view chunkView(fileReadBuf.data(), read);
114
115 std::pair<const_buffers_type, bool> ret;
116 ret.second = remain > 0;
117 if (body.encodingType == EncodingType::Base64)
118 {
119 buf.clear();
120 buf.reserve(
121 crow::utility::Base64Encoder::encodedSize(chunkView.size()));
122 encoder.encode(chunkView, buf);
123 if (!ret.second)
124 {
125 encoder.finalize(buf);
126 }
127 ret.first = const_buffers_type(buf.data(), buf.size());
128 }
129 else
130 {
131 ret.first = const_buffers_type(chunkView.data(), chunkView.size());
132 }
133 return ret;
134 }
135};
136} // namespace bmcweb