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:
|
||||
|
||||
* 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))
|
||||
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)
|
||||
{
|
||||
ec.clear();
|
||||
@ -398,7 +398,7 @@ async_read_some(
|
||||
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)
|
||||
{
|
||||
lock.unlock();
|
||||
@ -474,6 +474,17 @@ write_some(
|
||||
|
||||
++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
|
||||
auto out = out_.lock();
|
||||
if(! out)
|
||||
@ -482,10 +493,6 @@ write_some(
|
||||
return 0;
|
||||
}
|
||||
|
||||
// test failure
|
||||
if(in_->fc && in_->fc->fail(ec))
|
||||
return 0;
|
||||
|
||||
// copy buffers
|
||||
auto n = std::min<std::size_t>(
|
||||
buffer_size(buffers), in_->write_max);
|
||||
@ -513,19 +520,6 @@ async_write_some(ConstBufferSequence const& buffers,
|
||||
|
||||
++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
|
||||
error_code ec;
|
||||
if(in_->fc && in_->fc->fail(ec))
|
||||
@ -539,6 +533,30 @@ async_write_some(ConstBufferSequence const& buffers,
|
||||
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
|
||||
auto n = std::min<std::size_t>(
|
||||
buffer_size(buffers), in_->write_max);
|
||||
|
@ -23,22 +23,25 @@ class flat_stream_base
|
||||
public:
|
||||
// Largest buffer size we will flatten.
|
||||
// 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;
|
||||
bool needs_coalescing;
|
||||
bool flatten;
|
||||
};
|
||||
|
||||
// calculates the coalesce settings for a buffer sequence
|
||||
// calculates the flatten settings for a buffer sequence
|
||||
template<class BufferSequence>
|
||||
static
|
||||
coalesce_result
|
||||
coalesce(
|
||||
flatten_result
|
||||
flatten(
|
||||
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 last = net::buffer_sequence_end(buffers);
|
||||
if(first != last)
|
||||
@ -56,7 +59,7 @@ public:
|
||||
result.size += n;
|
||||
prev = it;
|
||||
}
|
||||
result.needs_coalescing = prev != first;
|
||||
result.flatten = prev != first;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -90,13 +90,6 @@ class flat_stream
|
||||
: private detail::flat_stream_base
|
||||
#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;
|
||||
|
||||
NextLayer stream_;
|
||||
|
@ -43,8 +43,8 @@ public:
|
||||
s.get_executor())
|
||||
{
|
||||
auto const result =
|
||||
coalesce(b, coalesce_limit);
|
||||
if(result.needs_coalescing)
|
||||
flatten(b, max_size);
|
||||
if(result.flatten)
|
||||
{
|
||||
s.buffer_.clear();
|
||||
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<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
auto const result = coalesce(buffers, coalesce_limit);
|
||||
if(result.needs_coalescing)
|
||||
auto const result = flatten(buffers, max_size);
|
||||
if(result.flatten)
|
||||
{
|
||||
if(result.size > max_stack)
|
||||
if(result.size <= max_stack)
|
||||
return stack_write_some(result.size, buffers, ec);
|
||||
|
||||
buffer_.clear();
|
||||
|
@ -12,26 +12,168 @@
|
||||
|
||||
#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/test/stream.hpp>
|
||||
#include <boost/beast/websocket/role.hpp>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class flat_stream_test
|
||||
: public unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
class flat_stream_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
testStream()
|
||||
testMembers()
|
||||
{
|
||||
net::io_context ioc;
|
||||
|
||||
test_sync_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
|
||||
@ -49,9 +191,9 @@ public:
|
||||
for(auto const n : v0)
|
||||
v.emplace_back("", n);
|
||||
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.needs_coalescing == copy);
|
||||
BEAST_EXPECT(result.flatten == copy);
|
||||
return result;
|
||||
};
|
||||
check({}, 1, 0, false);
|
||||
@ -67,50 +209,11 @@ public:
|
||||
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
|
||||
run() override
|
||||
{
|
||||
testStream();
|
||||
testMembers();
|
||||
testSplit();
|
||||
testHttp();
|
||||
testWebsocket();
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user