mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
flat_stream tests and tidy
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
Version 212:
|
Version 212:
|
||||||
|
|
||||||
* dynamic_buffer_ref tests and tidy
|
* dynamic_buffer_ref tests and tidy
|
||||||
|
* flat_stream tests and tidy
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ read_some(MutableBufferSequence const& buffers,
|
|||||||
if(in_->fc && in_->fc->fail(ec))
|
if(in_->fc && in_->fc->fail(ec))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// 0-byte reads are no-ops
|
// A request to read 0 bytes from a stream is a no-op.
|
||||||
if(buffer_size(buffers) == 0)
|
if(buffer_size(buffers) == 0)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
@ -398,7 +398,7 @@ async_read_some(
|
|||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0-byte reads are no-ops
|
// A request to read 0 bytes from a stream is a no-op.
|
||||||
if(buffer_size(buffers) == 0)
|
if(buffer_size(buffers) == 0)
|
||||||
{
|
{
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
@ -474,6 +474,17 @@ write_some(
|
|||||||
|
|
||||||
++in_->nwrite;
|
++in_->nwrite;
|
||||||
|
|
||||||
|
// test failure
|
||||||
|
if(in_->fc && in_->fc->fail(ec))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// A request to write 0 bytes to a stream is a no-op.
|
||||||
|
if(buffer_size(buffers) == 0)
|
||||||
|
{
|
||||||
|
ec.clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// connection closed
|
// connection closed
|
||||||
auto out = out_.lock();
|
auto out = out_.lock();
|
||||||
if(! out)
|
if(! out)
|
||||||
@ -482,10 +493,6 @@ write_some(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test failure
|
|
||||||
if(in_->fc && in_->fc->fail(ec))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// copy buffers
|
// copy buffers
|
||||||
auto n = std::min<std::size_t>(
|
auto n = std::min<std::size_t>(
|
||||||
buffer_size(buffers), in_->write_max);
|
buffer_size(buffers), in_->write_max);
|
||||||
@ -513,19 +520,6 @@ async_write_some(ConstBufferSequence const& buffers,
|
|||||||
|
|
||||||
++in_->nwrite;
|
++in_->nwrite;
|
||||||
|
|
||||||
// connection closed
|
|
||||||
auto out = out_.lock();
|
|
||||||
if(! out)
|
|
||||||
{
|
|
||||||
net::post(
|
|
||||||
in_->ioc.get_executor(),
|
|
||||||
beast::bind_front_handler(
|
|
||||||
std::move(init.completion_handler),
|
|
||||||
net::error::connection_reset,
|
|
||||||
std::size_t{0}));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// test failure
|
// test failure
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(in_->fc && in_->fc->fail(ec))
|
if(in_->fc && in_->fc->fail(ec))
|
||||||
@ -539,6 +533,30 @@ async_write_some(ConstBufferSequence const& buffers,
|
|||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A request to read 0 bytes from a stream is a no-op.
|
||||||
|
if(buffer_size(buffers) == 0)
|
||||||
|
{
|
||||||
|
net::post(
|
||||||
|
in_->ioc.get_executor(),
|
||||||
|
beast::bind_front_handler(
|
||||||
|
std::move(init.completion_handler),
|
||||||
|
ec, std::size_t{0}));
|
||||||
|
return init.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection closed
|
||||||
|
auto out = out_.lock();
|
||||||
|
if(! out)
|
||||||
|
{
|
||||||
|
net::post(
|
||||||
|
in_->ioc.get_executor(),
|
||||||
|
beast::bind_front_handler(
|
||||||
|
std::move(init.completion_handler),
|
||||||
|
net::error::connection_reset,
|
||||||
|
std::size_t{0}));
|
||||||
|
return init.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
// copy buffers
|
// copy buffers
|
||||||
auto n = std::min<std::size_t>(
|
auto n = std::min<std::size_t>(
|
||||||
buffer_size(buffers), in_->write_max);
|
buffer_size(buffers), in_->write_max);
|
||||||
|
@ -23,22 +23,25 @@ class flat_stream_base
|
|||||||
public:
|
public:
|
||||||
// Largest buffer size we will flatten.
|
// Largest buffer size we will flatten.
|
||||||
// 16KB is the upper limit on reasonably sized HTTP messages.
|
// 16KB is the upper limit on reasonably sized HTTP messages.
|
||||||
static std::size_t constexpr coalesce_limit = 16 * 1024;
|
static std::size_t constexpr max_size = 16 * 1024;
|
||||||
|
|
||||||
struct coalesce_result
|
// Largest stack we will use to flatten
|
||||||
|
static std::size_t constexpr max_stack = 8 * 1024;
|
||||||
|
|
||||||
|
struct flatten_result
|
||||||
{
|
{
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
bool needs_coalescing;
|
bool flatten;
|
||||||
};
|
};
|
||||||
|
|
||||||
// calculates the coalesce settings for a buffer sequence
|
// calculates the flatten settings for a buffer sequence
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
static
|
static
|
||||||
coalesce_result
|
flatten_result
|
||||||
coalesce(
|
flatten(
|
||||||
BufferSequence const& buffers, std::size_t limit)
|
BufferSequence const& buffers, std::size_t limit)
|
||||||
{
|
{
|
||||||
coalesce_result result{0, false};
|
flatten_result result{0, false};
|
||||||
auto first = net::buffer_sequence_begin(buffers);
|
auto first = net::buffer_sequence_begin(buffers);
|
||||||
auto last = net::buffer_sequence_end(buffers);
|
auto last = net::buffer_sequence_end(buffers);
|
||||||
if(first != last)
|
if(first != last)
|
||||||
@ -56,7 +59,7 @@ public:
|
|||||||
result.size += n;
|
result.size += n;
|
||||||
prev = it;
|
prev = it;
|
||||||
}
|
}
|
||||||
result.needs_coalescing = prev != first;
|
result.flatten = prev != first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -90,13 +90,6 @@ class flat_stream
|
|||||||
: private detail::flat_stream_base
|
: private detail::flat_stream_base
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// Largest buffer size we will flatten.
|
|
||||||
// 16KB is the upper limit on reasonably sized HTTP messages.
|
|
||||||
static std::size_t constexpr max_size = 16 * 1024;
|
|
||||||
|
|
||||||
// Largest stack we will use to flatten
|
|
||||||
static std::size_t constexpr max_stack = 16 * 1024;
|
|
||||||
|
|
||||||
template<class> class write_op;
|
template<class> class write_op;
|
||||||
|
|
||||||
NextLayer stream_;
|
NextLayer stream_;
|
||||||
|
@ -43,8 +43,8 @@ public:
|
|||||||
s.get_executor())
|
s.get_executor())
|
||||||
{
|
{
|
||||||
auto const result =
|
auto const result =
|
||||||
coalesce(b, coalesce_limit);
|
flatten(b, max_size);
|
||||||
if(result.needs_coalescing)
|
if(result.flatten)
|
||||||
{
|
{
|
||||||
s.buffer_.clear();
|
s.buffer_.clear();
|
||||||
s.buffer_.commit(net::buffer_copy(
|
s.buffer_.commit(net::buffer_copy(
|
||||||
@ -178,10 +178,10 @@ write_some(ConstBufferSequence const& buffers, error_code& ec)
|
|||||||
static_assert(net::is_const_buffer_sequence<
|
static_assert(net::is_const_buffer_sequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
auto const result = coalesce(buffers, coalesce_limit);
|
auto const result = flatten(buffers, max_size);
|
||||||
if(result.needs_coalescing)
|
if(result.flatten)
|
||||||
{
|
{
|
||||||
if(result.size > max_stack)
|
if(result.size <= max_stack)
|
||||||
return stack_write_some(result.size, buffers, ec);
|
return stack_write_some(result.size, buffers, ec);
|
||||||
|
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
|
@ -12,26 +12,168 @@
|
|||||||
|
|
||||||
#include "stream_tests.hpp"
|
#include "stream_tests.hpp"
|
||||||
|
|
||||||
#include <boost/beast/test/websocket.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
|
||||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
#include <boost/beast/_experimental/test/stream.hpp>
|
#include <boost/beast/_experimental/test/stream.hpp>
|
||||||
|
#include <boost/beast/websocket/role.hpp>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
class flat_stream_test
|
class flat_stream_test : public unit_test::suite
|
||||||
: public unit_test::suite
|
|
||||||
, public test::enable_yield_to
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
testStream()
|
testMembers()
|
||||||
{
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
|
||||||
test_sync_stream<flat_stream<test::stream>>();
|
test_sync_stream<flat_stream<test::stream>>();
|
||||||
|
|
||||||
test_async_stream<flat_stream<test::stream>>();
|
test_async_stream<flat_stream<test::stream>>();
|
||||||
|
|
||||||
|
// read/write
|
||||||
|
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
{
|
||||||
|
// VFALCO Hack to make test stream code = eof
|
||||||
|
test::stream ts(ioc);
|
||||||
|
s.next_layer().connect(ts);
|
||||||
|
}
|
||||||
|
char buf[1];
|
||||||
|
net::mutable_buffer m1 = net::buffer(buf);
|
||||||
|
|
||||||
|
BEAST_EXPECT(s.read_some(net::mutable_buffer{}) == 0);
|
||||||
|
BEAST_EXPECT(s.read_some(net::mutable_buffer{}, ec) == 0);
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
s.read_some(m1);
|
||||||
|
BEAST_FAIL();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
BEAST_PASS();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
BEAST_FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_EXPECT(s.write_some(net::const_buffer{}) == 0);
|
||||||
|
BEAST_EXPECT(s.write_some(net::const_buffer{}, ec) == 0);
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
s.write_some(m1);
|
||||||
|
BEAST_FAIL();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
BEAST_PASS();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
BEAST_FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool invoked;
|
||||||
|
|
||||||
|
invoked = false;
|
||||||
|
s.async_read_some(net::mutable_buffer{},
|
||||||
|
[&](error_code ec, std::size_t)
|
||||||
|
{
|
||||||
|
invoked = true;
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
});
|
||||||
|
ioc.run();
|
||||||
|
ioc.restart();
|
||||||
|
BEAST_EXPECT(invoked);
|
||||||
|
|
||||||
|
invoked = false;
|
||||||
|
s.async_write_some(net::const_buffer{},
|
||||||
|
[&](error_code ec, std::size_t)
|
||||||
|
{
|
||||||
|
invoked = true;
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
});
|
||||||
|
ioc.run();
|
||||||
|
ioc.restart();
|
||||||
|
BEAST_EXPECT(invoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack_write_some
|
||||||
|
|
||||||
|
{
|
||||||
|
char b[detail::flat_stream_base::max_size];
|
||||||
|
std::array<net::const_buffer, 3> bs;
|
||||||
|
bs[0] = net::const_buffer(b, 100);
|
||||||
|
bs[1] = net::const_buffer(b + 100, 200);
|
||||||
|
bs[2] = net::const_buffer(b + 100 + 200, 300);
|
||||||
|
BEAST_EXPECT(buffer_size(bs) <=
|
||||||
|
detail::flat_stream_base::max_stack);
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
error_code ec;
|
||||||
|
s.write_some(bs, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write_some
|
||||||
|
|
||||||
|
{
|
||||||
|
char b[detail::flat_stream_base::max_size];
|
||||||
|
std::array<net::const_buffer, 2> bs;
|
||||||
|
bs[0] = net::const_buffer(b,
|
||||||
|
detail::flat_stream_base::max_stack);
|
||||||
|
bs[1] = net::const_buffer(b + bs[0].size(), 1024);
|
||||||
|
BEAST_EXPECT(buffer_size(bs) <=
|
||||||
|
detail::flat_stream_base::max_size);
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
error_code ec;
|
||||||
|
s.write_some(bs, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// async_write_some
|
||||||
|
|
||||||
|
{
|
||||||
|
char b[detail::flat_stream_base::max_size];
|
||||||
|
std::array<net::const_buffer, 2> bs;
|
||||||
|
bs[0] = net::const_buffer(b,
|
||||||
|
detail::flat_stream_base::max_stack);
|
||||||
|
bs[1] = net::const_buffer(b + bs[0].size(), 1024);
|
||||||
|
BEAST_EXPECT(buffer_size(bs) <=
|
||||||
|
detail::flat_stream_base::max_size);
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
error_code ec;
|
||||||
|
s.async_write_some(bs,
|
||||||
|
[](error_code, std::size_t)
|
||||||
|
{
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// teardown
|
||||||
|
|
||||||
|
{
|
||||||
|
test::stream ts(ioc);
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
ts.connect(s.next_layer());
|
||||||
|
error_code ec;
|
||||||
|
teardown(websocket::role_type::client, s, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::stream ts(ioc);
|
||||||
|
flat_stream<test::stream> s(ioc);
|
||||||
|
ts.connect(s.next_layer());
|
||||||
|
async_teardown(websocket::role_type::client, s,
|
||||||
|
[](error_code)
|
||||||
|
{
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -49,9 +191,9 @@ public:
|
|||||||
for(auto const n : v0)
|
for(auto const n : v0)
|
||||||
v.emplace_back("", n);
|
v.emplace_back("", n);
|
||||||
auto const result =
|
auto const result =
|
||||||
boost::beast::detail::flat_stream_base::coalesce(v, limit);
|
boost::beast::detail::flat_stream_base::flatten(v, limit);
|
||||||
BEAST_EXPECT(result.size == count);
|
BEAST_EXPECT(result.size == count);
|
||||||
BEAST_EXPECT(result.needs_coalescing == copy);
|
BEAST_EXPECT(result.flatten == copy);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
check({}, 1, 0, false);
|
check({}, 1, 0, false);
|
||||||
@ -67,50 +209,11 @@ public:
|
|||||||
check({1,2,3,4}, 3, 3, true);
|
check({1,2,3,4}, 3, 3, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
testHttp()
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testWebsocket()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
test::ws_echo_server es{log};
|
|
||||||
net::io_context ioc;
|
|
||||||
websocket::stream<flat_stream<test::stream>> ws{ioc};
|
|
||||||
ws.next_layer().next_layer().connect(es.stream());
|
|
||||||
ws.handshake("localhost", "/", ec);
|
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
|
||||||
ws.close({}, ec);
|
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
test::ws_echo_server es{log};
|
|
||||||
net::io_context ioc;
|
|
||||||
websocket::stream<flat_stream<test::stream>> ws{ioc};
|
|
||||||
get_lowest_layer(ws).connect(es.stream());
|
|
||||||
ws.async_handshake("localhost", "/",
|
|
||||||
[&](error_code)
|
|
||||||
{
|
|
||||||
ws.async_close({},
|
|
||||||
[&](error_code)
|
|
||||||
{
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ioc.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
testStream();
|
testMembers();
|
||||||
testSplit();
|
testSplit();
|
||||||
testHttp();
|
|
||||||
testWebsocket();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user