diff options
Diffstat (limited to 'boost/beast/http/impl/write.hpp')
-rw-r--r-- | boost/beast/http/impl/write.hpp | 950 |
1 files changed, 950 insertions, 0 deletions
diff --git a/boost/beast/http/impl/write.hpp b/boost/beast/http/impl/write.hpp new file mode 100644 index 0000000000..5636ce92f8 --- /dev/null +++ b/boost/beast/http/impl/write.hpp @@ -0,0 +1,950 @@ +// +// 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/bind_handler.hpp> +#include <boost/beast/core/buffers_range.hpp> +#include <boost/beast/core/ostream.hpp> +#include <boost/beast/core/stream_traits.hpp> +#include <boost/asio/coroutine.hpp> +#include <boost/asio/post.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) + { + 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); + return net::post( + s_.get_executor(), + beast::bind_front_handler( + std::move(*this), ec, 0)); + } + if(f.invoked) + { + // *this is now moved-from, + return; + } + // What else could it be? + BOOST_ASSERT(sr_.is_done()); + } + + return net::post( + s_.get_executor(), + beast::bind_front_handler( + 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 net::coroutine +{ + Stream& s_; + serializer<isRequest, Body, Fields>& sr_; + std::size_t bytes_transferred_ = 0; + +public: + template<class Handler_> + write_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 = {}, + std::size_t bytes_transferred = 0) + { + BOOST_ASIO_CORO_REENTER(*this) + { + if(Predicate{}(sr_)) + { + BOOST_ASIO_CORO_YIELD + net::post( + s_.get_executor(), + std::move(*this)); + goto upcall; + } + for(;;) + { + BOOST_ASIO_CORO_YIELD + beast::http::async_write_some( + s_, sr_, std::move(*this)); + bytes_transferred_ += bytes_transferred; + 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()() + { + async_write(s_, sr_, std::move(*this)); + } + + void + operator()( + error_code ec, std::size_t bytes_transferred) + { + this->complete_now(ec, bytes_transferred); + } +}; + +struct run_write_some_op +{ + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields> + void + operator()( + WriteHandler&& h, + Stream* s, + 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, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *sr); + } +}; + +struct run_write_op +{ + template< + class WriteHandler, + class Stream, + class Predicate, + bool isRequest, class Body, class Fields> + void + operator()( + WriteHandler&& h, + Stream* s, + Predicate const&, + 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_op< + typename std::decay<WriteHandler>::type, + Stream, + Predicate, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *sr); + } +}; + +struct run_write_msg_op +{ + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields, + class... Args> + void + operator()( + WriteHandler&& h, + Stream* s, + 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, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *m, + std::forward<Args>(args)...); + } + + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields, + class... Args> + void + operator()( + WriteHandler&& h, + Stream* s, + 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, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *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, + class 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{}, + handler, + &stream, + &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, + class 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, + class 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"); + sr.split(true); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_op{}, + handler, + &stream, + detail::serializer_is_header_done{}, + &sr); +} + +//------------------------------------------------------------------------------ + +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, + class 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"); + sr.split(false); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_op{}, + handler, + &stream, + detail::serializer_is_done{}, + &sr); +} + +//------------------------------------------------------------------------------ + +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, + class WriteHandler> +typename std::enable_if< + is_mutable_body_writer<Body>::value, + BOOST_BEAST_ASYNC_RESULT2(WriteHandler)>::type +async_write( + AsyncWriteStream& stream, + message<isRequest, Body, Fields>& msg, + 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_msg_op{}, + handler, + &stream, + &msg, + std::false_type{}); +} + +template< + class AsyncWriteStream, + bool isRequest, class Body, class Fields, + class WriteHandler> +typename std::enable_if< + ! is_mutable_body_writer<Body>::value, + BOOST_BEAST_ASYNC_RESULT2(WriteHandler)>::type +async_write( + AsyncWriteStream& stream, + message<isRequest, Body, Fields> const& msg, + 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_msg_op{}, + handler, + &stream, + &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 << buffers(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 << buffers(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 |