2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP
11 #define BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP
13 #include <boost/beast/http/type_traits.hpp>
14 #include <boost/beast/http/error.hpp>
15 #include <boost/beast/http/parser.hpp>
16 #include <boost/beast/http/read.hpp>
17 #include <boost/beast/core/bind_handler.hpp>
18 #include <boost/beast/core/handler_ptr.hpp>
19 #include <boost/beast/core/read_size.hpp>
20 #include <boost/beast/core/type_traits.hpp>
21 #include <boost/asio/associated_allocator.hpp>
22 #include <boost/asio/associated_executor.hpp>
23 #include <boost/asio/coroutine.hpp>
24 #include <boost/asio/handler_continuation_hook.hpp>
25 #include <boost/asio/handler_invoke_hook.hpp>
26 #include <boost/asio/post.hpp>
27 #include <boost/assert.hpp>
28 #include <boost/config.hpp>
29 #include <boost/optional.hpp>
30 #include <boost/throw_exception.hpp>
38 //------------------------------------------------------------------------------
40 template<class Stream, class DynamicBuffer,
41 bool isRequest, class Derived, class Handler>
43 : public boost::asio::coroutine
47 basic_parser<isRequest, Derived>& p_;
48 std::size_t bytes_transferred_ = 0;
53 read_some_op(read_some_op&&) = default;
54 read_some_op(read_some_op const&) = delete;
56 template<class DeducedHandler>
57 read_some_op(DeducedHandler&& h, Stream& s,
58 DynamicBuffer& b, basic_parser<isRequest, Derived>& p)
62 , h_(std::forward<DeducedHandler>(h))
66 using allocator_type =
67 boost::asio::associated_allocator_t<Handler>;
70 get_allocator() const noexcept
72 return (boost::asio::get_associated_allocator)(h_);
75 using executor_type = boost::asio::associated_executor_t<
76 Handler, decltype(std::declval<Stream&>().get_executor())>;
79 get_executor() const noexcept
81 return (boost::asio::get_associated_executor)(
82 h_, s_.get_executor());
88 std::size_t bytes_transferred = 0,
92 bool asio_handler_is_continuation(read_some_op* op)
94 using boost::asio::asio_handler_is_continuation;
95 return op->cont_ ? true :
96 asio_handler_is_continuation(
97 std::addressof(op->h_));
100 template<class Function>
102 void asio_handler_invoke(Function&& f, read_some_op* op)
104 using boost::asio::asio_handler_invoke;
105 asio_handler_invoke(f, std::addressof(op->h_));
109 template<class Stream, class DynamicBuffer,
110 bool isRequest, class Derived, class Handler>
112 read_some_op<Stream, DynamicBuffer,
113 isRequest, Derived, Handler>::
116 std::size_t bytes_transferred,
120 boost::optional<typename
121 DynamicBuffer::mutable_buffers_type> mb;
122 BOOST_ASIO_CORO_REENTER(*this)
130 auto const used = p_.put(b_.data(), ec);
131 bytes_transferred_ += used;
134 if(ec != http::error::need_more)
140 mb.emplace(b_.prepare(
141 read_size_or_throw(b_, 65536)));
143 catch(std::length_error const&)
145 ec = error::buffer_overflow;
148 BOOST_ASIO_CORO_YIELD
149 s_.async_read_some(*mb, std::move(*this));
150 if(ec == boost::asio::error::eof)
152 BOOST_ASSERT(bytes_transferred == 0);
155 // caller sees EOF on next read
156 ec.assign(0, ec.category());
160 BOOST_ASSERT(p_.is_done());
163 ec = error::end_of_stream;
168 b_.commit(bytes_transferred);
173 return boost::asio::post(
175 bind_handler(std::move(h_),
176 ec, bytes_transferred_));
177 h_(ec, bytes_transferred_);
181 //------------------------------------------------------------------------------
183 struct parser_is_done
185 template<bool isRequest, class Derived>
187 operator()(basic_parser<
188 isRequest, Derived> const& p) const
194 struct parser_is_header_done
196 template<bool isRequest, class Derived>
198 operator()(basic_parser<
199 isRequest, Derived> const& p) const
201 return p.is_header_done();
205 template<class Stream, class DynamicBuffer,
206 bool isRequest, class Derived, class Condition,
209 : public boost::asio::coroutine
213 basic_parser<isRequest, Derived>& p_;
214 std::size_t bytes_transferred_ = 0;
219 read_op(read_op&&) = default;
220 read_op(read_op const&) = delete;
222 template<class DeducedHandler>
223 read_op(DeducedHandler&& h, Stream& s,
224 DynamicBuffer& b, basic_parser<isRequest,
229 , h_(std::forward<DeducedHandler>(h))
233 using allocator_type =
234 boost::asio::associated_allocator_t<Handler>;
237 get_allocator() const noexcept
239 return (boost::asio::get_associated_allocator)(h_);
242 using executor_type = boost::asio::associated_executor_t<
243 Handler, decltype(std::declval<Stream&>().get_executor())>;
246 get_executor() const noexcept
248 return (boost::asio::get_associated_executor)(
249 h_, s_.get_executor());
255 std::size_t bytes_transferred = 0,
259 bool asio_handler_is_continuation(read_op* op)
261 using boost::asio::asio_handler_is_continuation;
262 return op->cont_ ? true :
263 asio_handler_is_continuation(
264 std::addressof(op->h_));
267 template<class Function>
269 void asio_handler_invoke(Function&& f, read_op* op)
271 using boost::asio::asio_handler_invoke;
272 asio_handler_invoke(f, std::addressof(op->h_));
276 template<class Stream, class DynamicBuffer,
277 bool isRequest, class Derived, class Condition,
280 read_op<Stream, DynamicBuffer,
281 isRequest, Derived, Condition, Handler>::
284 std::size_t bytes_transferred,
288 BOOST_ASIO_CORO_REENTER(*this)
292 BOOST_ASIO_CORO_YIELD
293 boost::asio::post(s_.get_executor(),
294 bind_handler(std::move(*this), ec));
299 BOOST_ASIO_CORO_YIELD
301 s_, b_, p_, std::move(*this));
304 bytes_transferred_ += bytes_transferred;
309 h_(ec, bytes_transferred_);
313 //------------------------------------------------------------------------------
315 template<class Stream, class DynamicBuffer,
316 bool isRequest, class Body, class Allocator,
319 : public boost::asio::coroutine
322 parser<isRequest, Body, Allocator>;
325 typename parser_type::value_type;
333 std::size_t bytes_transferred = 0;
336 data(Handler const&, Stream& s_,
337 DynamicBuffer& b_, message_type& m_)
347 handler_ptr<data, Handler> d_;
350 read_msg_op(read_msg_op&&) = default;
351 read_msg_op(read_msg_op const&) = delete;
353 template<class DeducedHandler, class... Args>
354 read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
355 : d_(std::forward<DeducedHandler>(h),
356 s, std::forward<Args>(args)...)
360 using allocator_type =
361 boost::asio::associated_allocator_t<Handler>;
364 get_allocator() const noexcept
366 return (boost::asio::get_associated_allocator)(d_.handler());
369 using executor_type = boost::asio::associated_executor_t<
370 Handler, decltype(std::declval<Stream&>().get_executor())>;
373 get_executor() const noexcept
375 return (boost::asio::get_associated_executor)(
376 d_.handler(), d_->s.get_executor());
382 std::size_t bytes_transferred = 0,
386 bool asio_handler_is_continuation(read_msg_op* op)
388 using boost::asio::asio_handler_is_continuation;
389 return op->d_->cont ? true :
390 asio_handler_is_continuation(
391 std::addressof(op->d_.handler()));
394 template<class Function>
396 void asio_handler_invoke(Function&& f, read_msg_op* op)
398 using boost::asio::asio_handler_invoke;
399 asio_handler_invoke(f, std::addressof(op->d_.handler()));
403 template<class Stream, class DynamicBuffer,
404 bool isRequest, class Body, class Allocator,
407 read_msg_op<Stream, DynamicBuffer,
408 isRequest, Body, Allocator, Handler>::
411 std::size_t bytes_transferred,
416 BOOST_ASIO_CORO_REENTER(*this)
420 BOOST_ASIO_CORO_YIELD
422 d.s, d.b, d.p, std::move(*this));
425 d.bytes_transferred +=
434 bytes_transferred = d.bytes_transferred;
435 d_.invoke(ec, bytes_transferred);
441 //------------------------------------------------------------------------------
444 class SyncReadStream,
446 bool isRequest, class Derived>
449 SyncReadStream& stream,
450 DynamicBuffer& buffer,
451 basic_parser<isRequest, Derived>& parser)
453 static_assert(is_sync_read_stream<SyncReadStream>::value,
454 "SyncReadStream requirements not met");
456 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
457 "DynamicBuffer requirements not met");
458 BOOST_ASSERT(! parser.is_done());
460 auto const bytes_transferred =
461 read_some(stream, buffer, parser, ec);
463 BOOST_THROW_EXCEPTION(system_error{ec});
464 return bytes_transferred;
468 class SyncReadStream,
470 bool isRequest, class Derived>
473 SyncReadStream& stream,
474 DynamicBuffer& buffer,
475 basic_parser<isRequest, Derived>& parser,
478 static_assert(is_sync_read_stream<SyncReadStream>::value,
479 "SyncReadStream requirements not met");
481 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
482 "DynamicBuffer requirements not met");
483 BOOST_ASSERT(! parser.is_done());
484 std::size_t bytes_transferred = 0;
485 if(buffer.size() == 0)
491 auto const n = parser.put(buffer.data(), ec);
492 bytes_transferred += n;
496 if(ec != http::error::need_more)
500 boost::optional<typename
501 DynamicBuffer::mutable_buffers_type> b;
504 b.emplace(buffer.prepare(
505 read_size_or_throw(buffer, 65536)));
507 catch(std::length_error const&)
509 ec = error::buffer_overflow;
510 return bytes_transferred;
512 auto const n = stream.read_some(*b, ec);
513 if(ec == boost::asio::error::eof)
515 BOOST_ASSERT(n == 0);
516 if(parser.got_some())
518 // caller sees EOF on next read
522 BOOST_ASSERT(parser.is_done());
525 ec = error::end_of_stream;
532 return bytes_transferred;
536 class AsyncReadStream,
538 bool isRequest, class Derived,
540 BOOST_ASIO_INITFN_RESULT_TYPE(
541 ReadHandler, void(error_code, std::size_t))
543 AsyncReadStream& stream,
544 DynamicBuffer& buffer,
545 basic_parser<isRequest, Derived>& parser,
546 ReadHandler&& handler)
548 static_assert(is_async_read_stream<AsyncReadStream>::value,
549 "AsyncReadStream requirements not met");
551 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
552 "DynamicBuffer requirements not met");
553 BOOST_ASSERT(! parser.is_done());
554 BOOST_BEAST_HANDLER_INIT(
555 ReadHandler, void(error_code, std::size_t));
556 detail::read_some_op<AsyncReadStream,
557 DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
558 ReadHandler, void(error_code, std::size_t))>{
559 std::move(init.completion_handler), stream, buffer, parser}(
561 return init.result.get();
564 //------------------------------------------------------------------------------
567 class SyncReadStream,
569 bool isRequest, class Derived>
572 SyncReadStream& stream,
573 DynamicBuffer& buffer,
574 basic_parser<isRequest, Derived>& parser)
576 static_assert(is_sync_read_stream<SyncReadStream>::value,
577 "SyncReadStream requirements not met");
579 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
580 "DynamicBuffer requirements not met");
582 auto const bytes_transferred =
583 read_header(stream, buffer, parser, ec);
585 BOOST_THROW_EXCEPTION(system_error{ec});
586 return bytes_transferred;
590 class SyncReadStream,
592 bool isRequest, class Derived>
595 SyncReadStream& stream,
596 DynamicBuffer& buffer,
597 basic_parser<isRequest, Derived>& parser,
600 static_assert(is_sync_read_stream<SyncReadStream>::value,
601 "SyncReadStream requirements not met");
603 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
604 "DynamicBuffer requirements not met");
606 if(parser.is_header_done())
608 ec.assign(0, ec.category());
611 std::size_t bytes_transferred = 0;
614 bytes_transferred += read_some(
615 stream, buffer, parser, ec);
617 return bytes_transferred;
619 while(! parser.is_header_done());
620 return bytes_transferred;
624 class AsyncReadStream,
626 bool isRequest, class Derived,
628 BOOST_ASIO_INITFN_RESULT_TYPE(
629 ReadHandler, void(error_code, std::size_t))
631 AsyncReadStream& stream,
632 DynamicBuffer& buffer,
633 basic_parser<isRequest, Derived>& parser,
634 ReadHandler&& handler)
636 static_assert(is_async_read_stream<AsyncReadStream>::value,
637 "AsyncReadStream requirements not met");
639 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
640 "DynamicBuffer requirements not met");
642 BOOST_BEAST_HANDLER_INIT(
643 ReadHandler, void(error_code, std::size_t));
644 detail::read_op<AsyncReadStream, DynamicBuffer,
645 isRequest, Derived, detail::parser_is_header_done,
646 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
647 std::move(init.completion_handler), stream,
648 buffer, parser}({}, 0, false);
649 return init.result.get();
652 //------------------------------------------------------------------------------
655 class SyncReadStream,
657 bool isRequest, class Derived>
660 SyncReadStream& stream,
661 DynamicBuffer& buffer,
662 basic_parser<isRequest, Derived>& parser)
664 static_assert(is_sync_read_stream<SyncReadStream>::value,
665 "SyncReadStream requirements not met");
667 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
668 "DynamicBuffer requirements not met");
670 auto const bytes_transferred =
671 read(stream, buffer, parser, ec);
673 BOOST_THROW_EXCEPTION(system_error{ec});
674 return bytes_transferred;
678 class SyncReadStream,
680 bool isRequest, class Derived>
683 SyncReadStream& stream,
684 DynamicBuffer& buffer,
685 basic_parser<isRequest, Derived>& parser,
688 static_assert(is_sync_read_stream<SyncReadStream>::value,
689 "SyncReadStream requirements not met");
691 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
692 "DynamicBuffer requirements not met");
696 ec.assign(0, ec.category());
699 std::size_t bytes_transferred = 0;
702 bytes_transferred += read_some(
703 stream, buffer, parser, ec);
705 return bytes_transferred;
707 while(! parser.is_done());
708 return bytes_transferred;
712 class AsyncReadStream,
714 bool isRequest, class Derived,
716 BOOST_ASIO_INITFN_RESULT_TYPE(
717 ReadHandler, void(error_code, std::size_t))
719 AsyncReadStream& stream,
720 DynamicBuffer& buffer,
721 basic_parser<isRequest, Derived>& parser,
722 ReadHandler&& handler)
724 static_assert(is_async_read_stream<AsyncReadStream>::value,
725 "AsyncReadStream requirements not met");
727 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
728 "DynamicBuffer requirements not met");
730 BOOST_BEAST_HANDLER_INIT(
731 ReadHandler, void(error_code, std::size_t));
732 detail::read_op<AsyncReadStream, DynamicBuffer,
733 isRequest, Derived, detail::parser_is_done,
734 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
735 std::move(init.completion_handler), stream, buffer, parser}(
737 return init.result.get();
740 //------------------------------------------------------------------------------
743 class SyncReadStream,
745 bool isRequest, class Body, class Allocator>
748 SyncReadStream& stream,
749 DynamicBuffer& buffer,
750 message<isRequest, Body, basic_fields<Allocator>>& msg)
752 static_assert(is_sync_read_stream<SyncReadStream>::value,
753 "SyncReadStream requirements not met");
755 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
756 "DynamicBuffer requirements not met");
757 static_assert(is_body<Body>::value,
758 "Body requirements not met");
759 static_assert(is_body_reader<Body>::value,
760 "BodyReader requirements not met");
762 auto const bytes_transferred =
763 read(stream, buffer, msg, ec);
765 BOOST_THROW_EXCEPTION(system_error{ec});
766 return bytes_transferred;
770 class SyncReadStream,
772 bool isRequest, class Body, class Allocator>
775 SyncReadStream& stream,
776 DynamicBuffer& buffer,
777 message<isRequest, Body, basic_fields<Allocator>>& msg,
780 static_assert(is_sync_read_stream<SyncReadStream>::value,
781 "SyncReadStream requirements not met");
783 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
784 "DynamicBuffer requirements not met");
785 static_assert(is_body<Body>::value,
786 "Body requirements not met");
787 static_assert(is_body_reader<Body>::value,
788 "BodyReader requirements not met");
789 parser<isRequest, Body, Allocator> p{std::move(msg)};
791 auto const bytes_transferred =
792 read(stream, buffer, p.base(), ec);
794 return bytes_transferred;
796 return bytes_transferred;
800 class AsyncReadStream,
802 bool isRequest, class Body, class Allocator,
804 BOOST_ASIO_INITFN_RESULT_TYPE(
805 ReadHandler, void(error_code, std::size_t))
807 AsyncReadStream& stream,
808 DynamicBuffer& buffer,
809 message<isRequest, Body, basic_fields<Allocator>>& msg,
810 ReadHandler&& handler)
812 static_assert(is_async_read_stream<AsyncReadStream>::value,
813 "AsyncReadStream requirements not met");
815 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
816 "DynamicBuffer requirements not met");
817 static_assert(is_body<Body>::value,
818 "Body requirements not met");
819 static_assert(is_body_reader<Body>::value,
820 "BodyReader requirements not met");
821 BOOST_BEAST_HANDLER_INIT(
822 ReadHandler, void(error_code, std::size_t));
826 isRequest, Body, Allocator,
827 BOOST_ASIO_HANDLER_TYPE(
828 ReadHandler, void(error_code, std::size_t))>{
829 std::move(init.completion_handler), stream, buffer, msg}(
831 return init.result.get();