// // Copyright (c) 2013-2016 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) // #ifndef BEAST_HTTP_STREAM_IPP_INCLUDED #define BEAST_HTTP_STREAM_IPP_INCLUDED #include #include #include #include #include #include namespace beast { namespace http { template template class stream::read_op { using alloc_type = handler_alloc; struct data { stream& s; message_v1& m; Handler h; bool cont; int state = 0; template data(DeducedHandler&& h_, stream& s_, message_v1& m_) : s(s_) , m(m_) , h(std::forward(h_)) , cont(boost_asio_handler_cont_helpers:: is_continuation(h)) { } }; std::shared_ptr d_; public: read_op(read_op&&) = default; read_op(read_op const&) = default; template read_op(DeducedHandler&& h, stream& s, Args&&... args) : d_(std::allocate_shared(alloc_type{h}, std::forward(h), s, std::forward(args)...)) { (*this)(error_code{}, false); } void operator()(error_code const& ec, bool again = true); friend void* asio_handler_allocate( std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: allocate(size, op->d_->h); } friend void asio_handler_deallocate( void* p, std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: deallocate(p, size, op->d_->h); } friend bool asio_handler_is_continuation(read_op* op) { return op->d_->cont; } template friend void asio_handler_invoke(Function&& f, read_op* op) { return boost_asio_handler_invoke_helpers:: invoke(f, op->d_->h); } }; template template void stream:: read_op:: operator()(error_code const& ec, bool again) { auto& d = *d_; d.cont = d.cont || again; while(! ec && d.state != 99) { switch(d.state) { case 0: d.state = 99; beast::http::async_read(d.s.next_layer_, d.s.rd_buf_, d.m, std::move(*this)); return; } } d.h(ec); } //------------------------------------------------------------------------------ template template class stream::write_op : public op { using alloc_type = handler_alloc; struct data { stream& s; message_v1 m; Handler h; bool cont; int state = 0; template data(DeducedHandler&& h_, stream& s_, message_v1 const& m_, bool cont_) : s(s_) , m(m_) , h(std::forward(h_)) , cont(cont_) { } template data(DeducedHandler&& h_, stream& s_, message_v1&& m_, bool cont_) : s(s_) , m(std::move(m_)) , h(std::forward(h_)) , cont(cont_) { } }; std::shared_ptr d_; public: write_op(write_op&&) = default; write_op(write_op const&) = default; template write_op(DeducedHandler&& h, stream& s, Args&&... args) : d_(std::allocate_shared(alloc_type{h}, std::forward(h), s, std::forward(args)...)) { } void operator()() override { (*this)(error_code{}, false); } void cancel() override; void operator()(error_code const& ec, bool again = true); friend void* asio_handler_allocate( std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: allocate(size, op->d_->h); } friend void asio_handler_deallocate( void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: deallocate(p, size, op->d_->h); } friend bool asio_handler_is_continuation(write_op* op) { return op->d_->cont; } template friend void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: invoke(f, op->d_->h); } }; template template void stream:: write_op:: cancel() { auto& d = *d_; d.s.get_io_service().post( bind_handler(std::move(*this), boost::asio::error::operation_aborted)); } template template void stream:: write_op:: operator()(error_code const& ec, bool again) { auto& d = *d_; d.cont = d.cont || again; while(! ec && d.state != 99) { switch(d.state) { case 0: d.state = 99; beast::http::async_write(d.s.next_layer_, d.m, std::move(*this)); return; } } d.h(ec); if(! d.s.wr_q_.empty()) { auto& op = d.s.wr_q_.front(); op(); // VFALCO Use allocator delete &op; d.s.wr_q_.pop_front(); } else { d.s.wr_active_ = false; } } //------------------------------------------------------------------------------ template stream:: ~stream() { // Can't destroy with pending operations! assert(wr_q_.empty()); } template template stream:: stream(Args&&... args) : next_layer_(std::forward(args)...) { } template void stream:: cancel(error_code& ec) { cancel_all(); lowest_layer().cancel(ec); } template template void stream:: read(message_v1& msg, error_code& ec) { beast::http::read(next_layer_, rd_buf_, msg, ec); } template template auto stream:: async_read(message_v1& msg, ReadHandler&& handler) -> typename async_completion< ReadHandler, void(error_code)>::result_type { async_completion< ReadHandler, void(error_code) > completion(handler); read_op{ completion.handler, *this, msg}; return completion.result.get(); } template template void stream:: write(message_v1 const& msg, error_code& ec) { beast::http::write(next_layer_, msg, ec); } template template auto stream:: async_write(message_v1 const& msg, WriteHandler&& handler) -> typename async_completion< WriteHandler, void(error_code)>::result_type { async_completion< WriteHandler, void(error_code)> completion(handler); auto const cont = wr_active_ || boost_asio_handler_cont_helpers::is_continuation(handler); if(! wr_active_) { wr_active_ = true; write_op{ completion.handler, *this, msg, cont }(); } else { // VFALCO Use allocator wr_q_.push_back(*new write_op( completion.handler, *this, msg, cont)); } return completion.result.get(); } template template auto stream:: async_write(message_v1&& msg, WriteHandler&& handler) -> typename async_completion< WriteHandler, void(error_code)>::result_type { async_completion< WriteHandler, void(error_code)> completion(handler); auto const cont = wr_active_ || boost_asio_handler_cont_helpers::is_continuation(handler); if(! wr_active_) { wr_active_ = true; write_op{completion.handler, *this, std::move(msg), cont}(); } else { // VFALCO Use allocator wr_q_.push_back(*new write_op(completion.handler, *this, std::move(msg), cont)); } return completion.result.get(); } template void stream:: cancel_all() { for(auto it = wr_q_.begin(); it != wr_q_.end();) { auto& op = *it++; op.cancel(); // VFALCO Use allocator delete &op; } wr_q_.clear(); } } // http } // beast #endif