diff --git a/CHANGELOG.md b/CHANGELOG.md index 65990d50..243ae321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Version 169: * Use buffers_to_string in tests * Use boost::void_t +* Refactor HTTP write_op implementation -------------------------------------------------------------------------------- diff --git a/include/boost/beast/http/impl/write.ipp b/include/boost/beast/http/impl/write.ipp index 2f7d6218..40cafeff 100644 --- a/include/boost/beast/http/impl/write.ipp +++ b/include/boost/beast/http/impl/write.ipp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -206,7 +207,7 @@ struct serializer_is_done template< class Stream, class Handler, class Predicate, bool isRequest, class Body, class Fields> -class write_op +class write_op : public boost::asio::coroutine { Stream& s_; boost::asio::executor_work_guard& sr_; std::size_t bytes_transferred_ = 0; Handler h_; - int state_ = 0; + bool cont_; public: write_op(write_op&&) = default; @@ -227,6 +228,12 @@ public: , wg_(s_.get_executor()) , sr_(sr) , h_(std::forward(h)) + , cont_([&] + { + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(h_)); + }()) { } @@ -257,10 +264,7 @@ public: friend bool asio_handler_is_continuation(write_op* op) { - using boost::asio::asio_handler_is_continuation; - return op->state_ >= 3 || - asio_handler_is_continuation( - std::addressof(op->h_)); + return op->cont_; } template @@ -279,44 +283,34 @@ void write_op:: operator()( - error_code ec, std::size_t bytes_transferred) + error_code ec, + std::size_t bytes_transferred) { - if(ec) - goto upcall; - switch(state_) - { - case 0: + BOOST_ASIO_CORO_REENTER(*this) { if(Predicate{}(sr_)) { - state_ = 1; - return boost::asio::post( + BOOST_ASIO_CORO_YIELD + boost::asio::post( s_.get_executor(), - bind_handler(std::move(*this), ec, 0)); - } - state_ = 2; - return beast::http::async_write_some( - s_, sr_, std::move(*this)); - } - - case 1: - goto upcall; - - case 2: - state_ = 3; - BOOST_FALLTHROUGH; - - case 3: - { - bytes_transferred_ += bytes_transferred; - if(Predicate{}(sr_)) + bind_handler(std::move(*this))); goto upcall; - return beast::http::async_write_some( - s_, sr_, std::move(*this)); + } + 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; + cont_ = true; + } + upcall: + h_(ec, bytes_transferred_); } - } -upcall: - h_(ec, bytes_transferred_); } //------------------------------------------------------------------------------