beast file_body & file support seek.

win32 file_body handles seek correctly.
Added seek to win32 file.
file_body_writer handles offsets.
This commit is contained in:
Klemens
2022-12-17 17:59:48 +08:00
committed by Klemens Morgenstern
parent 4ff4c79d5b
commit 1d965752b2
3 changed files with 167 additions and 2 deletions

View File

@@ -160,6 +160,19 @@ public:
*/
void
reset(File&& file, error_code& ec);
/** Set the cursor position of the file.
This function can be used to move the cursor of the file ahead
so that only a part gets read. This file will also adjust the
value_type, in case the file is already part of a body.
@param offset The offset in bytes from the beginning of the file
@param ec Set to the error, if any occurred
*/
void seek(std::uint64_t offset, error_code& ec);
};
template<class File>
@@ -210,8 +223,29 @@ reset(File&& file, error_code& ec)
// Cache the size
file_size_ = file_.size(ec);
// Consider the offset
if (!ec)
file_size_ -= file_.pos(ec);
}
template<class File>
void
basic_file_body<File>::
value_type::
seek(std::uint64_t offset, error_code& ec)
{
file_.seek(offset, ec);
// Cache the size
if (!ec)
file_size_ = file_.size(ec);
// Consider the offset
if (!ec)
file_size_ -= file_.pos(ec);
}
// This is called from message::payload_size
template<class File>
std::uint64_t

View File

@@ -94,7 +94,7 @@ struct basic_file_body<file_win32>
std::uint64_t
size() const
{
return size_;
return last_ - first_;
}
void
@@ -105,6 +105,9 @@ struct basic_file_body<file_win32>
void
reset(file_win32&& file, error_code& ec);
void
seek(std::uint64_t offset, error_code& ec);
};
//--------------------------------------------------------------------------
@@ -284,11 +287,29 @@ reset(file_win32&& file, error_code& ec)
close();
return;
}
first_ = 0;
first_ = file_.pos(ec);
if(ec)
{
close();
return;
}
last_ = size_;
}
}
inline
void
basic_file_body<file_win32>::
value_type::
seek(std::uint64_t offset, error_code& ec)
{
first_ = offset;
file_.seek(offset, ec);
}
//------------------------------------------------------------------------------
namespace detail {

View File

@@ -17,6 +17,7 @@
#include <boost/beast/core/static_string.hpp>
#include <boost/beast/http/parser.hpp>
#include <boost/beast/http/serializer.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/filesystem.hpp>
#include <boost/asio/error.hpp>
@@ -43,6 +44,23 @@ public:
}
};
struct string_parser
{
parser<false, string_body> p;
std::size_t last_consumption;
template<class ConstBufferSequence>
void
operator()(error_code&, ConstBufferSequence const& buffers)
{
error_code ec;
BEAST_EXPECT(!p.is_done());
if (!p.is_done())
last_consumption = p.put(buffers, ec);
BEAST_EXPECT(!ec);
}
};
struct temp_file
{
temp_file(std::ostream& logger)
@@ -193,6 +211,87 @@ public:
}
}
template<class File, bool useReset>
void
readPartialFile()
{
auto temp = temp_file(log);
error_code ec;
string_view const ten =
"0123456789"; // 40
// create the temporary file
{
std::ofstream fstemp(temp.path().native());
std::size_t written = 0;
std::size_t to_write = 2048;
while (written < to_write)
{
auto size = (std::min)(ten.size(), to_write - written);
fstemp << ten.substr(0, size);
BEAST_EXPECT(fstemp.good());
written += size;
}
fstemp.close();
}
// open the file and read the header
{
using file_body_type = basic_file_body<File>;
typename file_body_type::value_type value;
// opened in write mode so we can truncate later
value.open(temp.path().string<std::string>().c_str(), file_mode::read, ec);
BEAST_EXPECTS(!ec, ec.message());
response<basic_file_body<File>> res{status::ok, 11};
res.set(field::server, "test");
if (useReset)
{
File f;
f.open(temp.path().string<std::string>().c_str(), file_mode::read, ec);
BEAST_EXPECTS(!ec, ec.message());
f.seek(1005, ec); // so we start at char 5
BEAST_EXPECTS(!ec, ec.message());
res.body().reset(std::move(f), ec);
BEAST_EXPECTS(!ec, ec.message());
}
else
{
res.body().open(temp.path().string<std::string>().c_str(), file_mode::read, ec);
BEAST_EXPECTS(!ec, ec.message());
res.body().seek(1005, ec); // so we start at char 5
BEAST_EXPECTS(!ec, ec.message());
}
res.prepare_payload();
BEAST_EXPECT(res.payload_size().value_or(0) == (2048 - 1005));
BEAST_EXPECTS(! ec, ec.message());
string_parser visit;
serializer<false, basic_file_body<File>, fields> sr{res};
while (!sr.is_done())
{
sr.next(ec, visit);
sr.consume(visit.last_consumption);
}
BEAST_EXPECT(visit.p.is_header_done());
BEAST_EXPECT(visit.p.content_length_remaining().value() == 0);
BEAST_EXPECT(visit.p.is_done());
auto data = visit.p.get();
BEAST_EXPECT(data.payload_size().value_or(0) == (2048 - 1005));
BEAST_EXPECT(data.body().size() == (2048 - 1005));
BEAST_EXPECT(data.body().front() == '5');
}
}
void
run() override
{
@@ -212,6 +311,17 @@ public:
fileBodyUnexpectedEofOnGet<file_win32>();
#endif
readPartialFile<file_stdio, true>();
readPartialFile<file_stdio, false>();
#if BOOST_BEAST_USE_POSIX_FILE
readPartialFile<file_posix, true>();
readPartialFile<file_posix, false>();
#endif
#if BOOST_BEAST_USE_WIN32_FILE
readPartialFile<file_win32, true>();
readPartialFile<file_win32, false>();
#endif
}
};