forked from boostorg/beast
Using `asio::deferred` as a completion token defers the initiation of operations and creates a lazy operation which might even be discarded. We need to move mutating operations to the initiator function objects or the constructor of operation objects, which are guaranteed to run when the deferred operation is launched.
1015 lines
27 KiB
C++
1015 lines
27 KiB
C++
//
|
|
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
// Official repository: https://github.com/boostorg/beast
|
|
//
|
|
|
|
#ifndef BOOST_BEAST_HTTP_IMPL_WRITE_HPP
|
|
#define BOOST_BEAST_HTTP_IMPL_WRITE_HPP
|
|
|
|
#include <boost/beast/http/type_traits.hpp>
|
|
#include <boost/beast/core/async_base.hpp>
|
|
#include <boost/beast/core/buffers_range.hpp>
|
|
#include <boost/beast/core/make_printable.hpp>
|
|
#include <boost/beast/core/stream_traits.hpp>
|
|
#include <boost/beast/core/detail/is_invocable.hpp>
|
|
#include <boost/asio/append.hpp>
|
|
#include <boost/asio/coroutine.hpp>
|
|
#include <boost/asio/dispatch.hpp>
|
|
#include <boost/asio/write.hpp>
|
|
#include <boost/optional.hpp>
|
|
#include <boost/throw_exception.hpp>
|
|
#include <ostream>
|
|
#include <sstream>
|
|
|
|
namespace boost {
|
|
namespace beast {
|
|
namespace http {
|
|
namespace detail {
|
|
|
|
template<
|
|
class Handler,
|
|
class Stream,
|
|
bool isRequest, class Body, class Fields>
|
|
class write_some_op
|
|
: public beast::async_base<
|
|
Handler, beast::executor_type<Stream>>
|
|
{
|
|
Stream& s_;
|
|
serializer<isRequest,Body, Fields>& sr_;
|
|
|
|
class lambda
|
|
{
|
|
write_some_op& op_;
|
|
|
|
public:
|
|
bool invoked = false;
|
|
|
|
explicit
|
|
lambda(write_some_op& op)
|
|
: op_(op)
|
|
{
|
|
}
|
|
|
|
template<class ConstBufferSequence>
|
|
void
|
|
operator()(
|
|
error_code& ec,
|
|
ConstBufferSequence const& buffers)
|
|
{
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write_some"));
|
|
|
|
invoked = true;
|
|
ec = {};
|
|
op_.s_.async_write_some(
|
|
buffers, std::move(op_));
|
|
}
|
|
};
|
|
|
|
public:
|
|
template<class Handler_>
|
|
write_some_op(
|
|
Handler_&& h,
|
|
Stream& s,
|
|
serializer<isRequest, Body, Fields>& sr)
|
|
: async_base<
|
|
Handler, beast::executor_type<Stream>>(
|
|
std::forward<Handler_>(h), s.get_executor())
|
|
, s_(s)
|
|
, sr_(sr)
|
|
{
|
|
(*this)();
|
|
}
|
|
|
|
void
|
|
operator()()
|
|
{
|
|
error_code ec;
|
|
if(! sr_.is_done())
|
|
{
|
|
lambda f{*this};
|
|
sr_.next(ec, f);
|
|
if(ec)
|
|
{
|
|
BOOST_ASSERT(! f.invoked);
|
|
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write_some"));
|
|
|
|
const auto ex = asio::get_associated_immediate_executor(*this, s_.get_executor());
|
|
return net::dispatch(ex, net::append(std::move(*this), ec, 0));
|
|
}
|
|
if(f.invoked)
|
|
{
|
|
// *this is now moved-from,
|
|
return;
|
|
}
|
|
// What else could it be?
|
|
BOOST_ASSERT(sr_.is_done());
|
|
}
|
|
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write_some"));
|
|
|
|
const auto ex = this->get_immediate_executor();
|
|
return net::dispatch(ex, net::append(std::move(*this), ec, 0));
|
|
}
|
|
|
|
void
|
|
operator()(
|
|
error_code ec,
|
|
std::size_t bytes_transferred)
|
|
{
|
|
if(! ec)
|
|
sr_.consume(bytes_transferred);
|
|
this->complete_now(ec, bytes_transferred);
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
struct serializer_is_header_done
|
|
{
|
|
template<
|
|
bool isRequest, class Body, class Fields>
|
|
bool
|
|
operator()(
|
|
serializer<isRequest, Body, Fields>& sr) const
|
|
{
|
|
return sr.is_header_done();
|
|
}
|
|
};
|
|
|
|
struct serializer_is_done
|
|
{
|
|
template<
|
|
bool isRequest, class Body, class Fields>
|
|
bool
|
|
operator()(
|
|
serializer<isRequest, Body, Fields>& sr) const
|
|
{
|
|
return sr.is_done();
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class Handler,
|
|
class Stream,
|
|
class Predicate,
|
|
bool isRequest, class Body, class Fields>
|
|
class write_op
|
|
: public beast::async_base<
|
|
Handler, beast::executor_type<Stream>>
|
|
, public asio::coroutine
|
|
{
|
|
Stream& s_;
|
|
serializer<isRequest, Body, Fields>& sr_;
|
|
std::size_t bytes_transferred_ = 0;
|
|
net::cancellation_state st_{this->
|
|
beast::async_base<Handler, beast::executor_type<Stream>>
|
|
::get_cancellation_slot()};
|
|
|
|
public:
|
|
using cancellation_slot_type = net::cancellation_slot;
|
|
cancellation_slot_type get_cancellation_slot() const noexcept
|
|
{
|
|
return st_.slot();
|
|
}
|
|
|
|
|
|
template<class Handler_>
|
|
write_op(
|
|
Handler_&& h,
|
|
Stream& s,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
bool split)
|
|
: async_base<
|
|
Handler, beast::executor_type<Stream>>(
|
|
std::forward<Handler_>(h), s.get_executor())
|
|
, s_(s)
|
|
, sr_(sr)
|
|
{
|
|
sr.split(split);
|
|
(*this)();
|
|
}
|
|
|
|
void
|
|
operator()(
|
|
error_code ec = {},
|
|
std::size_t bytes_transferred = 0)
|
|
{
|
|
BOOST_ASIO_CORO_REENTER(*this)
|
|
{
|
|
if(Predicate{}(sr_))
|
|
{
|
|
BOOST_ASIO_CORO_YIELD
|
|
{
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write"));
|
|
|
|
const auto ex = this->get_immediate_executor();
|
|
net::dispatch(
|
|
ex,
|
|
std::move(*this));
|
|
}
|
|
goto upcall;
|
|
}
|
|
for(;;)
|
|
{
|
|
BOOST_ASIO_CORO_YIELD
|
|
{
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write"));
|
|
|
|
beast::http::async_write_some(
|
|
s_, sr_, std::move(*this));
|
|
}
|
|
bytes_transferred_ += bytes_transferred;
|
|
if (!ec && st_.cancelled() != net::cancellation_type::none)
|
|
{
|
|
BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
|
|
}
|
|
if(ec)
|
|
goto upcall;
|
|
if(Predicate{}(sr_))
|
|
break;
|
|
}
|
|
upcall:
|
|
this->complete_now(ec, bytes_transferred_);
|
|
}
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class Handler,
|
|
class Stream,
|
|
bool isRequest, class Body, class Fields>
|
|
class write_msg_op
|
|
: public beast::stable_async_base<
|
|
Handler, beast::executor_type<Stream>>
|
|
{
|
|
Stream& s_;
|
|
serializer<isRequest, Body, Fields>& sr_;
|
|
|
|
public:
|
|
template<
|
|
class Handler_,
|
|
class... Args>
|
|
write_msg_op(
|
|
Handler_&& h,
|
|
Stream& s,
|
|
Args&&... args)
|
|
: stable_async_base<
|
|
Handler, beast::executor_type<Stream>>(
|
|
std::forward<Handler_>(h), s.get_executor())
|
|
, s_(s)
|
|
, sr_(beast::allocate_stable<
|
|
serializer<isRequest, Body, Fields>>(
|
|
*this, std::forward<Args>(args)...))
|
|
{
|
|
(*this)();
|
|
}
|
|
|
|
void
|
|
operator()()
|
|
{
|
|
BOOST_ASIO_HANDLER_LOCATION((
|
|
__FILE__, __LINE__,
|
|
"http::async_write(msg)"));
|
|
|
|
async_write(s_, sr_, std::move(*this));
|
|
}
|
|
|
|
void
|
|
operator()(
|
|
error_code ec, std::size_t bytes_transferred)
|
|
{
|
|
this->complete_now(ec, bytes_transferred);
|
|
}
|
|
};
|
|
|
|
template <typename AsyncWriteStream>
|
|
struct run_write_some_op
|
|
{
|
|
AsyncWriteStream* stream;
|
|
|
|
using executor_type = typename AsyncWriteStream::executor_type;
|
|
|
|
executor_type
|
|
get_executor() const noexcept
|
|
{
|
|
return stream->get_executor();
|
|
}
|
|
|
|
template<
|
|
class WriteHandler,
|
|
bool isRequest, class Body, class Fields>
|
|
void
|
|
operator()(
|
|
WriteHandler&& h,
|
|
serializer<isRequest, Body, Fields>* sr)
|
|
{
|
|
// If you get an error on the following line it means
|
|
// that your handler does not meet the documented type
|
|
// requirements for the handler.
|
|
|
|
static_assert(
|
|
beast::detail::is_invocable<WriteHandler,
|
|
void(error_code, std::size_t)>::value,
|
|
"WriteHandler type requirements not met");
|
|
|
|
write_some_op<
|
|
typename std::decay<WriteHandler>::type,
|
|
AsyncWriteStream,
|
|
isRequest, Body, Fields>(
|
|
std::forward<WriteHandler>(h), *stream, *sr);
|
|
}
|
|
};
|
|
|
|
template <typename AsyncWriteStream>
|
|
struct run_write_op
|
|
{
|
|
AsyncWriteStream* stream;
|
|
|
|
using executor_type = typename AsyncWriteStream::executor_type;
|
|
|
|
executor_type
|
|
get_executor() const noexcept
|
|
{
|
|
return stream->get_executor();
|
|
}
|
|
|
|
template<
|
|
class WriteHandler,
|
|
class Predicate,
|
|
bool isRequest, class Body, class Fields>
|
|
void
|
|
operator()(
|
|
WriteHandler&& h,
|
|
Predicate const&,
|
|
serializer<isRequest, Body, Fields>* sr,
|
|
bool split)
|
|
{
|
|
// If you get an error on the following line it means
|
|
// that your handler does not meet the documented type
|
|
// requirements for the handler.
|
|
|
|
static_assert(
|
|
beast::detail::is_invocable<WriteHandler,
|
|
void(error_code, std::size_t)>::value,
|
|
"WriteHandler type requirements not met");
|
|
|
|
write_op<
|
|
typename std::decay<WriteHandler>::type,
|
|
AsyncWriteStream,
|
|
Predicate,
|
|
isRequest, Body, Fields>(
|
|
std::forward<WriteHandler>(h), *stream, *sr, split);
|
|
}
|
|
};
|
|
|
|
template <typename AsyncWriteStream>
|
|
struct run_write_msg_op
|
|
{
|
|
AsyncWriteStream* stream;
|
|
|
|
using executor_type = typename AsyncWriteStream::executor_type;
|
|
|
|
executor_type
|
|
get_executor() const noexcept
|
|
{
|
|
return stream->get_executor();
|
|
}
|
|
|
|
template<
|
|
class WriteHandler,
|
|
bool isRequest, class Body, class Fields,
|
|
class... Args>
|
|
void
|
|
operator()(
|
|
WriteHandler&& h,
|
|
message<isRequest, Body, Fields>* m,
|
|
std::false_type,
|
|
Args&&... args)
|
|
{
|
|
// If you get an error on the following line it means
|
|
// that your handler does not meet the documented type
|
|
// requirements for the handler.
|
|
|
|
static_assert(
|
|
beast::detail::is_invocable<WriteHandler,
|
|
void(error_code, std::size_t)>::value,
|
|
"WriteHandler type requirements not met");
|
|
|
|
write_msg_op<
|
|
typename std::decay<WriteHandler>::type,
|
|
AsyncWriteStream,
|
|
isRequest, Body, Fields>(
|
|
std::forward<WriteHandler>(h), *stream, *m,
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<
|
|
class WriteHandler,
|
|
bool isRequest, class Body, class Fields,
|
|
class... Args>
|
|
void
|
|
operator()(
|
|
WriteHandler&& h,
|
|
message<isRequest, Body, Fields> const* m,
|
|
std::true_type,
|
|
Args&&... args)
|
|
{
|
|
// If you get an error on the following line it means
|
|
// that your handler does not meet the documented type
|
|
// requirements for the handler.
|
|
|
|
static_assert(
|
|
beast::detail::is_invocable<WriteHandler,
|
|
void(error_code, std::size_t)>::value,
|
|
"WriteHandler type requirements not met");
|
|
|
|
write_msg_op<
|
|
typename std::decay<WriteHandler>::type,
|
|
AsyncWriteStream,
|
|
isRequest, Body, Fields>(
|
|
std::forward<WriteHandler>(h), *stream, *m,
|
|
std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<class Stream>
|
|
class write_some_lambda
|
|
{
|
|
Stream& stream_;
|
|
|
|
public:
|
|
bool invoked = false;
|
|
std::size_t bytes_transferred = 0;
|
|
|
|
explicit
|
|
write_some_lambda(Stream& stream)
|
|
: stream_(stream)
|
|
{
|
|
}
|
|
|
|
template<class ConstBufferSequence>
|
|
void
|
|
operator()(error_code& ec,
|
|
ConstBufferSequence const& buffers)
|
|
{
|
|
invoked = true;
|
|
bytes_transferred =
|
|
stream_.write_some(buffers, ec);
|
|
}
|
|
};
|
|
|
|
template<class Stream>
|
|
class write_lambda
|
|
{
|
|
Stream& stream_;
|
|
|
|
public:
|
|
bool invoked = false;
|
|
std::size_t bytes_transferred = 0;
|
|
|
|
explicit
|
|
write_lambda(Stream& stream)
|
|
: stream_(stream)
|
|
{
|
|
}
|
|
|
|
template<class ConstBufferSequence>
|
|
void
|
|
operator()(error_code& ec,
|
|
ConstBufferSequence const& buffers)
|
|
{
|
|
invoked = true;
|
|
bytes_transferred = net::write(
|
|
stream_, buffers, ec);
|
|
}
|
|
};
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write_some_impl(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
error_code& ec)
|
|
{
|
|
if(! sr.is_done())
|
|
{
|
|
write_some_lambda<SyncWriteStream> f{stream};
|
|
sr.next(ec, f);
|
|
if(ec)
|
|
return f.bytes_transferred;
|
|
if(f.invoked)
|
|
sr.consume(f.bytes_transferred);
|
|
return f.bytes_transferred;
|
|
}
|
|
ec = {};
|
|
return 0;
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write_some_impl(
|
|
AsyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
WriteHandler&& handler)
|
|
{
|
|
return net::async_initiate<
|
|
WriteHandler,
|
|
void(error_code, std::size_t)>(
|
|
run_write_some_op<AsyncWriteStream>{&stream},
|
|
handler,
|
|
&sr);
|
|
}
|
|
|
|
} // detail
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write_some(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
error_code ec;
|
|
auto const bytes_transferred =
|
|
write_some(stream, sr, ec);
|
|
if(ec)
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write_some(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
error_code& ec)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return detail::write_some_impl(stream, sr, ec);
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write_some(
|
|
AsyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
WriteHandler&& handler)
|
|
{
|
|
static_assert(is_async_write_stream<
|
|
AsyncWriteStream>::value,
|
|
"AsyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return detail::async_write_some_impl(stream, sr,
|
|
std::forward<WriteHandler>(handler));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write_header(SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
error_code ec;
|
|
auto const bytes_transferred =
|
|
write_header(stream, sr, ec);
|
|
if(ec)
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write_header(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
error_code& ec)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
sr.split(true);
|
|
std::size_t bytes_transferred = 0;
|
|
if(! sr.is_header_done())
|
|
{
|
|
detail::write_lambda<SyncWriteStream> f{stream};
|
|
do
|
|
{
|
|
sr.next(ec, f);
|
|
bytes_transferred += f.bytes_transferred;
|
|
if(ec)
|
|
return bytes_transferred;
|
|
BOOST_ASSERT(f.invoked);
|
|
sr.consume(f.bytes_transferred);
|
|
}
|
|
while(! sr.is_header_done());
|
|
}
|
|
else
|
|
{
|
|
ec = {};
|
|
}
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write_header(
|
|
AsyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
WriteHandler&& handler)
|
|
{
|
|
static_assert(is_async_write_stream<
|
|
AsyncWriteStream>::value,
|
|
"AsyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return net::async_initiate<
|
|
WriteHandler,
|
|
void(error_code, std::size_t)>(
|
|
detail::run_write_op<AsyncWriteStream>{&stream},
|
|
handler,
|
|
detail::serializer_is_header_done{},
|
|
&sr,
|
|
true);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
error_code ec;
|
|
auto const bytes_transferred =
|
|
write(stream, sr, ec);
|
|
if(ec)
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
std::size_t
|
|
write(
|
|
SyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
error_code& ec)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
std::size_t bytes_transferred = 0;
|
|
sr.split(false);
|
|
for(;;)
|
|
{
|
|
bytes_transferred +=
|
|
write_some(stream, sr, ec);
|
|
if(ec)
|
|
return bytes_transferred;
|
|
if(sr.is_done())
|
|
break;
|
|
}
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write(
|
|
AsyncWriteStream& stream,
|
|
serializer<isRequest, Body, Fields>& sr,
|
|
WriteHandler&& handler)
|
|
{
|
|
static_assert(is_async_write_stream<
|
|
AsyncWriteStream>::value,
|
|
"AsyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return net::async_initiate<
|
|
WriteHandler,
|
|
void(error_code, std::size_t)>(
|
|
detail::run_write_op<AsyncWriteStream>{&stream},
|
|
handler,
|
|
detail::serializer_is_done{},
|
|
&sr,
|
|
false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
typename std::enable_if<
|
|
is_mutable_body_writer<Body>::value,
|
|
std::size_t>::type
|
|
write(
|
|
SyncWriteStream& stream,
|
|
message<isRequest, Body, Fields>& msg)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
error_code ec;
|
|
auto const bytes_transferred =
|
|
write(stream, msg, ec);
|
|
if(ec)
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
typename std::enable_if<
|
|
! is_mutable_body_writer<Body>::value,
|
|
std::size_t>::type
|
|
write(
|
|
SyncWriteStream& stream,
|
|
message<isRequest, Body, Fields> const& msg)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
error_code ec;
|
|
auto const bytes_transferred =
|
|
write(stream, msg, ec);
|
|
if(ec)
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
return bytes_transferred;
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
typename std::enable_if<
|
|
is_mutable_body_writer<Body>::value,
|
|
std::size_t>::type
|
|
write(
|
|
SyncWriteStream& stream,
|
|
message<isRequest, Body, Fields>& msg,
|
|
error_code& ec)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
serializer<isRequest, Body, Fields> sr{msg};
|
|
return write(stream, sr, ec);
|
|
}
|
|
|
|
template<
|
|
class SyncWriteStream,
|
|
bool isRequest, class Body, class Fields>
|
|
typename std::enable_if<
|
|
! is_mutable_body_writer<Body>::value,
|
|
std::size_t>::type
|
|
write(
|
|
SyncWriteStream& stream,
|
|
message<isRequest, Body, Fields> const& msg,
|
|
error_code& ec)
|
|
{
|
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
"SyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
serializer<isRequest, Body, Fields> sr{msg};
|
|
return write(stream, sr, ec);
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write(
|
|
AsyncWriteStream& stream,
|
|
message<isRequest, Body, Fields>& msg,
|
|
WriteHandler&& handler,
|
|
typename std::enable_if<
|
|
is_mutable_body_writer<Body>::value>::type*)
|
|
{
|
|
static_assert(
|
|
is_async_write_stream<AsyncWriteStream>::value,
|
|
"AsyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return net::async_initiate<
|
|
WriteHandler,
|
|
void(error_code, std::size_t)>(
|
|
detail::run_write_msg_op<AsyncWriteStream>{&stream},
|
|
handler,
|
|
&msg,
|
|
std::false_type{});
|
|
}
|
|
|
|
template<
|
|
class AsyncWriteStream,
|
|
bool isRequest, class Body, class Fields,
|
|
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
|
|
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
|
|
async_write(
|
|
AsyncWriteStream& stream,
|
|
message<isRequest, Body, Fields> const& msg,
|
|
WriteHandler&& handler,
|
|
typename std::enable_if<
|
|
! is_mutable_body_writer<Body>::value>::type*)
|
|
{
|
|
static_assert(
|
|
is_async_write_stream<AsyncWriteStream>::value,
|
|
"AsyncWriteStream type requirements not met");
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
return net::async_initiate<
|
|
WriteHandler,
|
|
void(error_code, std::size_t)>(
|
|
detail::run_write_msg_op<AsyncWriteStream>{&stream},
|
|
handler,
|
|
&msg,
|
|
std::true_type{});
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace detail {
|
|
|
|
template<class Serializer>
|
|
class write_ostream_lambda
|
|
{
|
|
std::ostream& os_;
|
|
Serializer& sr_;
|
|
|
|
public:
|
|
write_ostream_lambda(std::ostream& os,
|
|
Serializer& sr)
|
|
: os_(os)
|
|
, sr_(sr)
|
|
{
|
|
}
|
|
|
|
template<class ConstBufferSequence>
|
|
void
|
|
operator()(error_code& ec,
|
|
ConstBufferSequence const& buffers) const
|
|
{
|
|
ec = {};
|
|
if(os_.fail())
|
|
return;
|
|
std::size_t bytes_transferred = 0;
|
|
for(auto b : beast::buffers_range_ref(buffers))
|
|
{
|
|
os_.write(static_cast<char const*>(
|
|
b.data()), b.size());
|
|
if(os_.fail())
|
|
return;
|
|
bytes_transferred += b.size();
|
|
}
|
|
sr_.consume(bytes_transferred);
|
|
}
|
|
};
|
|
|
|
} // detail
|
|
|
|
template<class Fields>
|
|
std::ostream&
|
|
operator<<(std::ostream& os,
|
|
header<true, Fields> const& h)
|
|
{
|
|
typename Fields::writer fr{
|
|
h, h.version(), h.method()};
|
|
return os << beast::make_printable(fr.get());
|
|
}
|
|
|
|
template<class Fields>
|
|
std::ostream&
|
|
operator<<(std::ostream& os,
|
|
header<false, Fields> const& h)
|
|
{
|
|
typename Fields::writer fr{
|
|
h, h.version(), h.result_int()};
|
|
return os << beast::make_printable(fr.get());
|
|
}
|
|
|
|
template<bool isRequest, class Body, class Fields>
|
|
std::ostream&
|
|
operator<<(std::ostream& os,
|
|
message<isRequest, Body, Fields> const& msg)
|
|
{
|
|
static_assert(is_body<Body>::value,
|
|
"Body type requirements not met");
|
|
static_assert(is_body_writer<Body>::value,
|
|
"BodyWriter type requirements not met");
|
|
serializer<isRequest, Body, Fields> sr{msg};
|
|
error_code ec;
|
|
detail::write_ostream_lambda<decltype(sr)> f{os, sr};
|
|
do
|
|
{
|
|
sr.next(ec, f);
|
|
if(os.fail())
|
|
break;
|
|
if(ec)
|
|
{
|
|
os.setstate(std::ios::failbit);
|
|
break;
|
|
}
|
|
}
|
|
while(! sr.is_done());
|
|
return os;
|
|
}
|
|
|
|
} // http
|
|
} // beast
|
|
} // boost
|
|
|
|
#endif
|