4#include <boost/beast/http/message.hpp>
34 std::uint64_t totalFile,
35 std::string_view contentType,
36 std::string
const& splitter)
41 std::string{
"\r\n"} + splitter +
"\r\n" +
42 "Content-Type: " + std::string{contentType} +
"\r\n" +
72 constexpr const char* hexCharacters =
"0123456789ABCDEF";
74 std::random_device rd;
75 std::mt19937 gen(rd());
76 std::uniform_int_distribution<> distrib(0, 15);
78 return static_cast<char>(hexCharacters[distrib(gen)]);
114 auto pos =
file_.tellg();
115 file_.seekg(0, std::ios::end);
118 return static_cast<std::uint64_t
>(
size);
123 return file_.is_open();
138 void open(std::filesystem::path
const& filename, std::ios_base::openmode mode, std::error_code& ec)
141 auto excMask =
file_.exceptions();
142 file_.exceptions(excMask | std::ios::failbit | std::ios::badbit);
145 file_.open(filename, std::ios::binary | mode);
147 catch (std::system_error& e)
151 file_.exceptions(excMask);
162 if (
ranges.ranges.empty())
163 throw std::invalid_argument(
"Ranges must not be empty");
165 if (
ranges.ranges.size() > 1)
170 if (
ranges.ranges.empty())
171 throw std::runtime_error(
"No ranges specified");
173 for (
auto const& range :
ranges.ranges)
175 if (range.end < range.start)
176 throw std::invalid_argument(
"end < start");
178 throw std::invalid_argument(
"range.end > file size");
183 auto seq = Sequence{range.start, range.end, totalFile, contentType, splitter_};
184 totalSize_ += seq.headSection.size() + (range.end - range.start);
197 file_.seekg(
static_cast<std::streamoff
>(
ranges.ranges.front().start));
208 std::size_t
read(
char* buf, std::size_t amount)
210 std::uint64_t origAmount = amount;
211 auto& current = sequences_.back();
213 if (current.headConsumed != current.headSection.size())
215 auto copied = current.headSection.copy(
218 static_cast<std::uint64_t
>(amount),
219 static_cast<std::uint64_t
>(current.headSection.size()) - current.headConsumed),
220 current.headConsumed);
222 current.headConsumed += copied;
226 file_.seekg(
static_cast<std::streamoff
>(current.start));
230 static_cast<std::streamoff
>(
231 std::min(
static_cast<std::uint64_t
>(amount), current.end - current.start)));
232 auto gcount =
static_cast<std::uint64_t
>(file_.gcount());
234 current.start += gcount;
236 if (current.start == current.end)
237 sequences_.pop_back();
239 if (sequences_.empty())
240 return (origAmount - amount);
242 return (origAmount - amount) + read(buf + gcount, amount);
254 std::streamsize
write(
char const* buf, std::streamsize amount,
bool& error)
256 file_.write(buf, amount);
272 file_ = std::move(file);
281 file_.seekg(0, std::ios::beg);
290 std::fstream file_{};
300 using namespace MemoryLiterals;
304 template <
unsigned Size>
323 template <
bool isRequest,
class Fields>
325 void init(boost::optional<std::uint64_t>
const&, boost::beast::error_code& ec);
326 template <
class ConstBufferSequence>
327 std::size_t put(ConstBufferSequence
const& buffers, boost::beast::error_code& ec);
328 void finish(boost::beast::error_code& ec);
338 template <
bool isRequest,
class Fields>
340 void init(boost::beast::error_code& ec);
341 boost::optional<std::pair<const_buffers_type, bool>> get(boost::beast::error_code& ec);
353 template <
bool isRequest,
class Fields>
354 inline RangeFileBody::reader::reader(boost::beast::http::header<isRequest, Fields>&,
value_type& bodyValue)
359 BOOST_ASSERT(body_.isOpen());
362 template <
class ConstBufferSequence>
365 std::size_t writtenBytes = 0;
366 for (
auto it = boost::asio::buffer_sequence_begin(buffers); it != boost::asio::buffer_sequence_end(buffers);
370 boost::asio::const_buffer buffer = *it;
372 writtenBytes +=
static_cast<std::size_t
>(body_.write(
373 reinterpret_cast<char const*
>(buffer.data()),
static_cast<std::streamsize
>(buffer.size()), fail));
376 ec = boost::beast::http::error::body_limit;
389 template <
bool isRequest,
class Fields>
394 throw std::invalid_argument{
"File must be open"};
400 inline boost::optional<std::pair<RangeFileBody::const_buffers_type, bool>>
403 const auto remain = body_.remaining();
404 const auto amount = remain >
sizeof(buf_) ?
sizeof(buf_) :
static_cast<std::size_t
>(remain);
412 const auto readCount = body_.read(buf_, amount);
415 ec = boost::beast::http::error::short_read;
419 BOOST_ASSERT(readCount != 0);
420 BOOST_ASSERT(readCount <= remain);
Support range requests for get requests including multipart/byterange.
Definition range_file_body.hpp:23
std::streamsize write(char const *buf, std::streamsize amount, bool &error)
Writes the given buffer to the file.
Definition range_file_body.hpp:254
void reset(std::fstream &&file)
Resets the file stream with a new stream.
Definition range_file_body.hpp:268
RangeFileBodyImpl(RangeFileBodyImpl &&)=default
void reset()
Resets the fstream state and goes back to the start.
Definition range_file_body.hpp:278
RangeFileBodyImpl & operator=(RangeFileBodyImpl const &)=delete
std::fstream & file()
Definition range_file_body.hpp:87
std::uint64_t consumed_
Definition range_file_body.hpp:295
RangeFileBodyImpl(RangeFileBodyImpl const &)=delete
static constexpr unsigned SplitterLength
Definition range_file_body.hpp:24
std::uint64_t fileSize()
Definition range_file_body.hpp:112
std::size_t read(char *buf, std::size_t amount)
Reads some of the multipart data into the buffer.
Definition range_file_body.hpp:208
void close()
Definition range_file_body.hpp:126
~RangeFileBodyImpl()=default
bool isMultipart() const
Definition range_file_body.hpp:102
void open(std::filesystem::path const &filename, std::ios_base::openmode mode, std::error_code &ec)
Opens the file.
Definition range_file_body.hpp:138
bool isOpen() const
Definition range_file_body.hpp:121
std::vector< Sequence > sequences_
Definition range_file_body.hpp:292
RangeFileBodyImpl()
Definition range_file_body.hpp:65
std::uint64_t size() const
Definition range_file_body.hpp:92
std::string splitter_
Definition range_file_body.hpp:293
RangeFileBodyImpl & operator=(RangeFileBodyImpl &&)=default
void setReadRanges(Ranges const &ranges, std::string_view contentType)
Set the Read Range.
Definition range_file_body.hpp:160
std::pair< std::uint64_t, std::uint64_t > firstRange()
Definition range_file_body.hpp:107
std::fstream file_
Definition range_file_body.hpp:290
std::uint64_t totalSize_
Definition range_file_body.hpp:294
std::string boundary() const
Definition range_file_body.hpp:284
std::uint64_t remaining() const
Definition range_file_body.hpp:97
Definition range_file_body.hpp:321
void init(boost::optional< std::uint64_t > const &, boost::beast::error_code &ec)
Definition range_file_body.hpp:357
std::size_t put(ConstBufferSequence const &buffers, boost::beast::error_code &ec)
Definition range_file_body.hpp:363
value_type & body_
Definition range_file_body.hpp:331
void finish(boost::beast::error_code &ec)
Definition range_file_body.hpp:384
Definition range_file_body.hpp:334
value_type & body_
Definition range_file_body.hpp:344
writer(boost::beast::http::header< isRequest, Fields > &, value_type &)
Definition range_file_body.hpp:390
boost::optional< std::pair< const_buffers_type, bool > > get(boost::beast::error_code &ec)
Definition range_file_body.hpp:401
void init(boost::beast::error_code &ec)
Definition range_file_body.hpp:396
boost::asio::const_buffer const_buffers_type
Definition range_file_body.hpp:336
This body is a file body, but with range request support.
Definition range_file_body.hpp:315
static std::uint64_t size(value_type const &vt)
Definition range_file_body.hpp:347
boost::asio::const_buffer const_buffers_type
Definition range_file_body.hpp:318
const auto ranges
Definition ranges.cpp:19
static constexpr std::uint64_t bufferSize()
Definition range_file_body.hpp:298
Definition authorization.hpp:10
std::string to_string(AuthorizationScheme scheme)
Definition authorization.cpp:28
Definition range_file_body.hpp:306
Definition range_file_body.hpp:28
std::uint64_t headConsumed
Definition range_file_body.hpp:60
std::uint64_t end
Definition range_file_body.hpp:59
Sequence(std::uint64_t start, std::uint64_t end)
Definition range_file_body.hpp:52
Sequence(std::uint64_t start, std::uint64_t end, std::uint64_t totalFile, std::string_view contentType, std::string const &splitter)
Definition range_file_body.hpp:31
Sequence(std::string const &splitter)
Definition range_file_body.hpp:46
std::string headSection
Definition range_file_body.hpp:61
std::uint64_t start
Definition range_file_body.hpp:58