From f65a611b85e4e05f4433fba431228d9302532b85 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 7 Jul 2017 07:07:50 -0700 Subject: [PATCH] Always go through write_some: HTTP stream serialization algorithms always go through write_some or async_write some. --- CHANGELOG.md | 6 + include/beast/http/impl/write.ipp | 307 ++++++++++++++---------------- test/http/write.cpp | 12 +- 3 files changed, 159 insertions(+), 166 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9d98a2..e1b5bba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Version 76: + +* Always go through write_some + +-------------------------------------------------------------------------------- + Version 75: * Use file_body for valid requests, string_body otherwise. diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index 8b33e2c5..a6d9301a 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -28,14 +28,13 @@ namespace beast { namespace http { namespace detail { -template +template class write_some_op { Stream& s_; - serializer& sr_; + serializer& sr_; Handler h_; class lambda @@ -56,8 +55,8 @@ class write_some_op operator()(error_code& ec, ConstBufferSequence const& buffers) { - ec.assign(0, ec.category()); invoked = true; + ec.assign(0, ec.category()); return op_.s_.async_write_some( buffers, std::move(op_)); } @@ -119,42 +118,54 @@ public: } }; -template +template void -write_some_op:: +write_some_op:: operator()() { error_code ec; - if(sr_.is_done()) - return s_.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); - lambda f{*this}; - sr_.next(ec, f); - if(ec) + if(! sr_.is_done()) { - BOOST_ASSERT(! f.invoked); - return s_.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); + lambda f{*this}; + sr_.next(ec, f); + if(ec) + { + BOOST_ASSERT(! f.invoked); + return s_.get_io_service().post( + bind_handler(std::move(*this), ec, 0)); + } + if(f.invoked) + { + // *this has been moved from, + // cannot access members here. + return; + } + // What else could it be? + BOOST_ASSERT(sr_.is_done()); } - if(f.invoked) - // *this has been moved from, - // cannot access members here. - return; return s_.get_io_service().post( bind_handler(std::move(*this), ec, 0)); } -template +template void -write_some_op:: -operator()(error_code ec, std::size_t bytes_transferred) +write_some_op:: +operator()( + error_code ec, std::size_t bytes_transferred) { if(! ec) + { sr_.consume(bytes_transferred); + if(sr_.is_done()) + if(sr_.need_close()) + ec = error::end_of_stream; + } h_(ec); } @@ -184,9 +195,12 @@ struct serializer_is_done } }; -template +//------------------------------------------------------------------------------ + +template< + class Stream, class Handler, class Predicate, + bool isRequest, class Body, + class Fields, class Decorator> class write_op { int state_ = 0; @@ -195,31 +209,6 @@ class write_op Body, Fields, Decorator>& sr_; Handler h_; - class lambda - { - write_op& op_; - - public: - bool invoked = false; - - explicit - lambda(write_op& op) - : op_(op) - { - } - - template - void - operator()(error_code& ec, - ConstBufferSequence const& buffers) - { - ec.assign(0, ec.category()); - invoked = true; - return op_.s_.async_write_some( - buffers, std::move(op_)); - } - }; - public: write_op(write_op&&) = default; write_op(write_op const&) = default; @@ -235,8 +224,7 @@ public: } void - operator()(error_code ec, - std::size_t bytes_transferred); + operator()(error_code ec); friend void* asio_handler_allocate( @@ -275,14 +263,14 @@ public: } }; -template +template< + class Stream, class Handler, class Predicate, + bool isRequest, class Body, + class Fields, class Decorator> void -write_op:: -operator()(error_code ec, - std::size_t bytes_transferred) +write_op:: +operator()(error_code ec) { if(ec) goto upcall; @@ -294,25 +282,10 @@ operator()(error_code ec, { state_ = 1; return s_.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); + bind_handler(std::move(*this), ec)); } - lambda f{*this}; state_ = 2; - sr_.next(ec, f); - if(ec) - { - BOOST_ASSERT(! f.invoked); - return s_.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); - } - if(f.invoked) - // *this has been moved from, - // cannot access members here. - return; - BOOST_ASSERT(Predicate{}(sr_)); - state_ = 1; - return s_.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); + return async_write_some(s_, sr_, std::move(*this)); } case 1: @@ -324,22 +297,9 @@ operator()(error_code ec, case 3: { - sr_.consume(bytes_transferred); if(Predicate{}(sr_)) goto upcall; - lambda f{*this}; - sr_.next(ec, f); - if(ec) - { - BOOST_ASSERT(! f.invoked); - goto upcall; - } - if(f.invoked) - // *this has been moved from, - // cannot access members here. - return; - BOOST_ASSERT(Predicate{}(sr_)); - goto upcall; + return async_write_some(s_, sr_, std::move(*this)); } } upcall: @@ -424,7 +384,8 @@ public: template void -write_msg_op:: +write_msg_op< + Stream, Handler, isRequest, Body, Fields>:: operator()() { auto& d = *d_; @@ -434,13 +395,10 @@ operator()() template void -write_msg_op:: +write_msg_op< + Stream, Handler, isRequest, Body, Fields>:: operator()(error_code ec) { - auto& d = *d_; - if(! ec) - if(d.sr.need_close()) - ec = error::end_of_stream; d_.invoke(ec); } @@ -502,6 +460,38 @@ public: //------------------------------------------------------------------------------ +namespace detail { + +template< + class SyncWriteStream, + bool isRequest, class Body, class Fields, class Decorator> +void +write_some( + SyncWriteStream& stream, serializer< + isRequest, Body, Fields, Decorator>& sr, + error_code& ec) +{ + if(! sr.is_done()) + { + write_some_lambda f{stream}; + sr.next(ec, f); + if(ec) + return; + if(f.invoked) + sr.consume(f.bytes_transferred); + if(sr.is_done()) + if(sr.need_close()) + ec = error::end_of_stream; + return; + } + if(sr.need_close()) + ec = error::end_of_stream; + else + ec.assign(0, ec.category()); +} + +} // detail + template void @@ -534,17 +524,7 @@ write_some(SyncWriteStream& stream, serializer< "Body requirements not met"); static_assert(is_body_reader::value, "BodyReader requirements not met"); - detail::write_some_lambda f{stream}; - if(sr.is_done()) - { - ec.assign(0, ec.category()); - return; - } - sr.next(ec, f); - if(ec) - return; - if(f.invoked) - sr.consume(f.bytes_transferred); + detail::write_some(stream, sr, ec); } template init{handler}; - detail::write_some_op>{ + detail::write_some_op, + isRequest, Body, Fields, Decorator>{ init.completion_handler, stream, sr}(); return init.result.get(); } @@ -607,21 +587,23 @@ write_header(SyncWriteStream& stream, serializer< static_assert(is_body_reader::value, "BodyReader requirements not met"); sr.split(true); - if(sr.is_header_done()) + if(! sr.is_header_done()) + { + detail::write_lambda f{stream}; + do + { + sr.next(ec, f); + if(ec) + return; + BOOST_ASSERT(f.invoked); + sr.consume(f.bytes_transferred); + } + while(! sr.is_header_done()); + } + else { ec.assign(0, ec.category()); - return; } - detail::write_lambda f{stream}; - do - { - sr.next(ec, f); - if(ec) - return; - BOOST_ASSERT(f.invoked); - sr.consume(f.bytes_transferred); - } - while(! sr.is_header_done()); } template init{handler}; - detail::write_op>{ - init.completion_handler, stream, sr}( - error_code{}, 0); + detail::write_op, + detail::serializer_is_header_done, + isRequest, Body, Fields, Decorator>{ + init.completion_handler, stream, sr}( + error_code{}, 0); return init.result.get(); } //------------------------------------------------------------------------------ -template +template< + class SyncWriteStream, + bool isRequest, class Body, + class Fields, class Decorator> void -write(SyncWriteStream& stream, serializer< - isRequest, Body, Fields, Decorator>& sr) +write( + SyncWriteStream& stream, + serializer& sr) { static_assert(is_sync_write_stream::value, "SyncWriteStream requirements not met"); @@ -667,34 +652,27 @@ write(SyncWriteStream& stream, serializer< BOOST_THROW_EXCEPTION(system_error{ec}); } -template +template< + class SyncWriteStream, + bool isRequest, class Body, + class Fields, class Decorator> void -write(SyncWriteStream& stream, serializer< - isRequest, Body, Fields, Decorator>& sr, - error_code& ec) +write( + SyncWriteStream& stream, + serializer& sr, + error_code& ec) { static_assert(is_sync_write_stream::value, "SyncWriteStream requirements not met"); sr.split(false); - if(sr.is_done()) + for(;;) { - ec.assign(0, ec.category()); - return; - } - detail::write_lambda f{stream}; - do - { - sr.next(ec, f); + write_some(stream, sr, ec); if(ec) return; - if(f.invoked) - sr.consume(f.bytes_transferred); + if(sr.is_done()) + break; } - while(! sr.is_done()); - if(sr.need_close()) - ec = error::end_of_stream; } template init{handler}; - detail::write_op>{ + detail::write_op, + detail::serializer_is_done, + isRequest, Body, Fields, Decorator>{ init.completion_handler, stream, sr}( - error_code{}, 0); + error_code{}); return init.result.get(); } @@ -779,9 +758,9 @@ async_write(AsyncWriteStream& stream, async_completion init{handler}; detail::write_msg_op, - isRequest, Body, Fields>{ - init.completion_handler, stream, msg}(); + WriteHandler, void(error_code)>, isRequest, + Body, Fields>{init.completion_handler, + stream, msg}(); return init.result.get(); } diff --git a/test/http/write.cpp b/test/http/write.cpp index 9d494014..d072fa2b 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -811,8 +811,16 @@ public: void run() override { - yield_to([&](yield_context yield){ testAsyncWrite(yield); }); - yield_to([&](yield_context yield){ testFailures(yield); }); + yield_to( + [&](yield_context yield) + { + testAsyncWrite(yield); + }); + yield_to( + [&](yield_context yield) + { + testFailures(yield); + }); testOutput(); test_std_ostream(); testIoService();