Add asio_handler_invoke overloads for stream algorithms:

fix #1012

This fixes a bug where asynchronous stream alogrithms do not
work correctly with the legacy `io_service::strand` implementation.
This commit is contained in:
Vinnie Falco
2018-03-01 06:36:18 -08:00
parent 2543dbe5b9
commit 726118468b
27 changed files with 483 additions and 5 deletions

View File

@@ -1,3 +1,9 @@
Version 162:
* Add asio_handler_invoke overloads for stream algorithms
--------------------------------------------------------------------------------
Version 161:
* Don't copy the handler in write_some_op

View File

@@ -74,7 +74,9 @@ get_filename_component (BOOST_ROOT ../../ ABSOLUTE)
# VFALCO I want static but "b2 stage" builds a minimal set which excludes static
add_definitions (-DBOOST_ALL_STATIC_LINK=1)
add_definitions (-DBOOST_ASIO_NO_DEPRECATED=1)
# Some of the tests use deprecated APIs
#add_definitions (-DBOOST_ASIO_NO_DEPRECATED=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_ARRAY=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_BIND=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1)

View File

@@ -86,7 +86,7 @@ project /boost/beast
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
<define>BOOST_ASIO_NO_DEPRECATED=1
#<define>BOOST_ASIO_NO_DEPRECATED=1 # some tests use deprecated strand
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
<toolset>msvc:<cxxflags>"/bigobj"
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1

View File

@@ -116,6 +116,8 @@ to update to the latest Boost release.
* ([issue 1043]) Examples clear the HTTP message before reading
* ([issue 1012]) Add asio_handler_invoke overloads for stream algorithms
[*API Changes]
* Remove unintended public members of

View File

@@ -14,6 +14,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/is_placeholder.hpp>
#include <functional>
@@ -153,6 +154,14 @@ public:
return asio_handler_is_continuation(std::addressof(h->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, bound_handler* h)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(h->h_));
}
template<class... Values>
void
operator()(Values&&... values)

View File

@@ -19,6 +19,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
@@ -80,6 +81,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer>

View File

@@ -21,6 +21,7 @@
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/windows/overlapped_ptr.hpp>
#include <boost/make_unique.hpp>
#include <boost/smart_ptr/make_shared_array.hpp>
@@ -393,6 +394,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_some_win32_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<

View File

@@ -22,6 +22,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
@@ -95,6 +96,14 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer,
@@ -254,6 +263,14 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer,
@@ -373,6 +390,14 @@ public:
asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_msg_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->d_.handler()));
}
};
template<class Stream, class DynamicBuffer,

View File

@@ -19,6 +19,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/write.hpp>
#include <boost/optional.hpp>
@@ -112,6 +113,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<
@@ -246,6 +255,14 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<
@@ -360,6 +377,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_msg_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->d_.handler()));
}
};
template<class Stream, class Handler,

View File

@@ -23,6 +23,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
@@ -103,6 +104,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, response_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->d_.handler()));
}
};
template<class NextLayer, bool deflateSupported>
@@ -203,6 +212,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, accept_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->d_.handler()));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -19,6 +19,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -107,6 +108,15 @@ public:
return op->d_->cont || asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, close_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f,
std::addressof(op->d_.handler()));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -21,6 +21,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -108,6 +109,15 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, handshake_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f,
std::addressof(op->d_.handler()));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -19,6 +19,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -105,6 +106,15 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, ping_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->d_.handler()));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -22,6 +22,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
@@ -145,6 +146,14 @@ public:
return op->cont_ || asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class NextLayer, bool deflateSupported>
@@ -765,6 +774,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -16,6 +16,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <memory>
@@ -74,6 +75,22 @@ public:
operator()(
error_code ec = {},
std::size_t bytes_transferred = 0);
friend
bool asio_handler_is_continuation(teardown_tcp_op* op)
{
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, teardown_tcp_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Handler>

View File

@@ -23,6 +23,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
@@ -207,6 +208,15 @@ public:
return op->cont_ || asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->h_));
}
};
template<class NextLayer, bool deflateSupported>

View File

@@ -11,7 +11,10 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/test/stream.hpp>
#include <boost/beast/unit_test/suite.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <string>
namespace boost {
@@ -56,6 +59,28 @@ public:
bind_handler(handler<int, std::string>{}, ph::_1, ph::_2)(1, "hello");
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
boost::asio::post(ioc.get_executor(),
s.wrap(copyable_handler{}));
}
void
run() override
{
@@ -64,6 +89,7 @@ public:
std::placeholders::_1), 42);
f();
testPlaceholders();
testAsioHandlerInvoke();
}
};

View File

@@ -15,8 +15,10 @@
#include <boost/beast/test/yield_to.hpp>
#include <boost/beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
namespace boost {
@@ -206,6 +208,30 @@ public:
BEAST_EXPECT(n < limit);
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
buffered_read_stream<
test::stream&, multi_buffer> brs(ts);
brs.async_read_some(boost::asio::mutable_buffer{},
s.wrap(copyable_handler{}));
}
void run() override
{
testSpecialMembers();
@@ -214,6 +240,7 @@ public:
testRead(yield);});
testAsyncLoop();
testAsioHandlerInvoke();
}
};

View File

@@ -21,7 +21,8 @@
#include <boost/beast/test/stream.hpp>
#include <boost/beast/test/yield_to.hpp>
#include <boost/beast/unit_test/suite.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <atomic>
namespace boost {
@@ -480,6 +481,47 @@ public:
});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request_parser<dynamic_body> p;
async_read_some(ts, b, p, s.wrap(copyable_handler{}));
}
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request_parser<dynamic_body> p;
async_read(ts, b, p, s.wrap(copyable_handler{}));
}
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request<dynamic_body> m;
async_read(ts, b, m, s.wrap(copyable_handler{}));
}
}
void
run() override
{
@@ -502,6 +544,7 @@ public:
testIoService();
testRegression430();
testReadGrind();
testAsioHandlerInvoke();
}
};

View File

@@ -22,6 +22,8 @@
#include <boost/beast/test/yield_to.hpp>
#include <boost/beast/unit_test/suite.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <sstream>
#include <string>
@@ -857,6 +859,49 @@ public:
ioc.run();
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request<empty_body> m;
request_serializer<empty_body, fields> sr{m};
async_write_some(ts, sr, s.wrap(copyable_handler{}));
}
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request<empty_body> m;
request_serializer<empty_body, fields> sr{m};
async_write(ts, sr, s.wrap(copyable_handler{}));
}
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
test::stream ts{ioc};
flat_buffer b;
request<empty_body> m;
async_write(ts, m, s.wrap(copyable_handler{}));
}
}
void
run() override
{
@@ -878,6 +923,7 @@ public:
testWriteStream<test_body< true, false>>(yield);
testWriteStream<test_body< true, true>>(yield);
});
testAsioHandlerInvoke();
}
};

View File

@@ -12,6 +12,9 @@
#include "test.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
namespace boost {
namespace beast {
namespace websocket {
@@ -618,11 +621,33 @@ public:
ws.async_accept(move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
ws.async_accept(s.wrap(copyable_handler{}));
}
void
run() override
{
testAccept();
testMoveOnly();
testAsioHandlerInvoke();
}
};

View File

@@ -12,6 +12,9 @@
#include "test.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
namespace boost {
namespace beast {
namespace websocket {
@@ -630,6 +633,27 @@ public:
ws.async_close({}, move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
ws.async_close({}, s.wrap(copyable_handler{}));
}
void
run() override
{
@@ -637,6 +661,7 @@ public:
testSuspend();
testContHook();
testMoveOnly();
testAsioHandlerInvoke();
}
};

View File

@@ -12,6 +12,9 @@
#include "test.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
namespace boost {
namespace beast {
namespace websocket {
@@ -492,6 +495,27 @@ public:
ws.async_handshake("", "", move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
ws.async_handshake("localhost", "/", s.wrap(copyable_handler{}));
}
void
run() override
{
@@ -500,6 +524,7 @@ public:
testExtWrite();
testExtNegotiate();
testMoveOnly();
testAsioHandlerInvoke();
}
};

View File

@@ -12,6 +12,9 @@
#include "test.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
namespace boost {
namespace beast {
namespace websocket {
@@ -443,6 +446,27 @@ public:
ws.async_ping({}, move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
ws.async_ping({}, s.wrap(copyable_handler{}));
}
void
run() override
{
@@ -450,6 +474,7 @@ public:
testSuspend();
testContHook();
testMoveOnly();
testAsioHandlerInvoke();
}
};

View File

@@ -12,6 +12,8 @@
#include "test.hpp"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/write.hpp>
namespace boost {
@@ -649,6 +651,30 @@ public:
move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
flat_buffer b;
ws.async_read(b, s.wrap(copyable_handler{}));
}
}
void
run() override
{
@@ -660,6 +686,7 @@ public:
testIssueBF1();
testIssueBF2();
testMoveOnly();
testAsioHandlerInvoke();
}
};

View File

@@ -10,6 +10,9 @@
// Test that header file is self-contained.
#include <boost/beast/websocket/stream.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include "test.hpp"
namespace boost {
@@ -641,6 +644,31 @@ public:
move_only_handler{});
}
struct copyable_handler
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
void
testAsioHandlerInvoke()
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
{
boost::asio::io_context ioc;
boost::asio::io_service::strand s{ioc};
stream<test::stream> ws{ioc};
flat_buffer b;
ws.async_write(boost::asio::const_buffer{},
s.wrap(copyable_handler{}));
}
}
void
run() override
{

View File

@@ -432,9 +432,13 @@ read_some(MutableBufferSequence const& buffers,
"MutableBufferSequence requirements not met");
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
BOOST_ASSERT(buffer_size(buffers) > 0);
if(in_->fc && in_->fc->fail(ec))
return 0;
if(buffer_size(buffers) == 0)
{
ec.clear();
return 0;
}
std::unique_lock<std::mutex> lock{in_->m};
BOOST_ASSERT(! in_->op);
in_->cv.wait(lock,
@@ -478,7 +482,6 @@ async_read_some(
"MutableBufferSequence requirements not met");
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
BOOST_ASSERT(buffer_size(buffers) > 0);
BOOST_BEAST_HANDLER_INIT(
ReadHandler, void(error_code, std::size_t));
if(in_->fc)