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/handler_continuation_hook.hpp>
24 #include <boost/asio/post.hpp>
25 #include <boost/assert.hpp>
26 #include <boost/config.hpp>
27 #include <boost/optional.hpp>
28 #include <boost/throw_exception.hpp>
36 //------------------------------------------------------------------------------
38 template<class Stream, class DynamicBuffer,
39 bool isRequest, class Derived, class Handler>
45 basic_parser<isRequest, Derived>& p_;
46 boost::optional<typename
47 DynamicBuffer::mutable_buffers_type> mb_;
48 std::size_t bytes_transferred_ = 0;
52 read_some_op(read_some_op&&) = default;
53 read_some_op(read_some_op const&) = default;
55 template<class DeducedHandler>
56 read_some_op(DeducedHandler&& h, Stream& s,
57 DynamicBuffer& b, basic_parser<isRequest, Derived>& p)
61 , h_(std::forward<DeducedHandler>(h))
65 using allocator_type =
66 boost::asio::associated_allocator_t<Handler>;
69 get_allocator() const noexcept
71 return boost::asio::get_associated_allocator(h_);
74 using executor_type = boost::asio::associated_executor_t<
75 Handler, decltype(std::declval<Stream&>().get_executor())>;
78 get_executor() const noexcept
80 return boost::asio::get_associated_executor(
81 h_, s_.get_executor());
87 std::size_t bytes_transferred = 0);
90 bool asio_handler_is_continuation(read_some_op* op)
92 using boost::asio::asio_handler_is_continuation;
93 return op->state_ >= 2 ? true :
94 asio_handler_is_continuation(
95 std::addressof(op->h_));
99 template<class Stream, class DynamicBuffer,
100 bool isRequest, class Derived, class Handler>
102 read_some_op<Stream, DynamicBuffer,
103 isRequest, Derived, Handler>::
106 std::size_t bytes_transferred)
119 if(ec == boost::asio::error::eof)
121 BOOST_ASSERT(bytes_transferred == 0);
124 // caller sees EOF on next read
125 ec.assign(0, ec.category());
129 BOOST_ASSERT(p_.is_done());
132 ec = error::end_of_stream;
137 b_.commit(bytes_transferred);
141 auto const used = p_.put(b_.data(), ec);
142 bytes_transferred_ += used;
144 if(! ec || ec != http::error::need_more)
146 ec.assign(0, ec.category());
152 mb_.emplace(b_.prepare(
153 read_size_or_throw(b_, 65536)));
155 catch(std::length_error const&)
157 ec = error::buffer_overflow;
160 return s_.async_read_some(*mb_, std::move(*this));
166 return boost::asio::post(
168 bind_handler(std::move(*this), ec, 0));
174 h_(ec, bytes_transferred_);
177 //------------------------------------------------------------------------------
179 struct parser_is_done
181 template<bool isRequest, class Derived>
183 operator()(basic_parser<
184 isRequest, Derived> const& p) const
190 struct parser_is_header_done
192 template<bool isRequest, class Derived>
194 operator()(basic_parser<
195 isRequest, Derived> const& p) const
197 return p.is_header_done();
201 template<class Stream, class DynamicBuffer,
202 bool isRequest, class Derived, class Condition,
209 basic_parser<isRequest, Derived>& p_;
210 std::size_t bytes_transferred_ = 0;
214 read_op(read_op&&) = default;
215 read_op(read_op const&) = default;
217 template<class DeducedHandler>
218 read_op(DeducedHandler&& h, Stream& s,
219 DynamicBuffer& b, basic_parser<isRequest,
224 , h_(std::forward<DeducedHandler>(h))
228 using allocator_type =
229 boost::asio::associated_allocator_t<Handler>;
232 get_allocator() const noexcept
234 return boost::asio::get_associated_allocator(h_);
237 using executor_type = boost::asio::associated_executor_t<
238 Handler, decltype(std::declval<Stream&>().get_executor())>;
241 get_executor() const noexcept
243 return boost::asio::get_associated_executor(
244 h_, s_.get_executor());
250 std::size_t bytes_transferred = 0);
253 bool asio_handler_is_continuation(read_op* op)
255 using boost::asio::asio_handler_is_continuation;
256 return op->state_ >= 3 ? true :
257 asio_handler_is_continuation(
258 std::addressof(op->h_));
262 template<class Stream, class DynamicBuffer,
263 bool isRequest, class Derived, class Condition,
266 read_op<Stream, DynamicBuffer,
267 isRequest, Derived, Condition, Handler>::
270 std::size_t bytes_transferred)
278 return boost::asio::post(
280 bind_handler(std::move(*this), ec));
285 return async_read_some(
286 s_, b_, p_, std::move(*this));
295 bytes_transferred_ += bytes_transferred;
302 h_(ec, bytes_transferred_);
305 //------------------------------------------------------------------------------
307 template<class Stream, class DynamicBuffer,
308 bool isRequest, class Body, class Allocator,
313 parser<isRequest, Body, Allocator>;
316 typename parser_type::value_type;
325 std::size_t bytes_transferred = 0;
327 data(Handler&, Stream& s_,
328 DynamicBuffer& b_, message_type& m_)
338 handler_ptr<data, Handler> d_;
341 read_msg_op(read_msg_op&&) = default;
342 read_msg_op(read_msg_op const&) = default;
344 template<class DeducedHandler, class... Args>
345 read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
346 : d_(std::forward<DeducedHandler>(h),
347 s, std::forward<Args>(args)...)
351 using allocator_type =
352 boost::asio::associated_allocator_t<Handler>;
355 get_allocator() const noexcept
357 return boost::asio::get_associated_allocator(d_.handler());
360 using executor_type = boost::asio::associated_executor_t<
361 Handler, decltype(std::declval<Stream&>().get_executor())>;
364 get_executor() const noexcept
366 return boost::asio::get_associated_executor(
367 d_.handler(), d_->s.get_executor());
373 std::size_t bytes_transferred = 0);
376 bool asio_handler_is_continuation(read_msg_op* op)
378 using boost::asio::asio_handler_is_continuation;
379 return op->d_->state >= 2 ? true :
380 asio_handler_is_continuation(
381 std::addressof(op->d_.handler()));
385 template<class Stream, class DynamicBuffer,
386 bool isRequest, class Body, class Allocator,
389 read_msg_op<Stream, DynamicBuffer,
390 isRequest, Body, Allocator, Handler>::
393 std::size_t bytes_transferred)
402 return async_read_some(
403 d.s, d.b, d.p, std::move(*this));
409 d.bytes_transferred +=
420 bytes_transferred = d.bytes_transferred;
421 d_.invoke(ec, bytes_transferred);
426 //------------------------------------------------------------------------------
429 class SyncReadStream,
431 bool isRequest, class Derived>
434 SyncReadStream& stream,
435 DynamicBuffer& buffer,
436 basic_parser<isRequest, Derived>& parser)
438 static_assert(is_sync_read_stream<SyncReadStream>::value,
439 "SyncReadStream requirements not met");
441 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
442 "DynamicBuffer requirements not met");
443 BOOST_ASSERT(! parser.is_done());
445 auto const bytes_transferred =
446 read_some(stream, buffer, parser, ec);
448 BOOST_THROW_EXCEPTION(system_error{ec});
449 return bytes_transferred;
453 class SyncReadStream,
455 bool isRequest, class Derived>
458 SyncReadStream& stream,
459 DynamicBuffer& buffer,
460 basic_parser<isRequest, Derived>& parser,
463 static_assert(is_sync_read_stream<SyncReadStream>::value,
464 "SyncReadStream requirements not met");
466 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
467 "DynamicBuffer requirements not met");
468 BOOST_ASSERT(! parser.is_done());
469 std::size_t bytes_transferred = 0;
470 if(buffer.size() == 0)
476 auto const n = parser.put(buffer.data(), ec);
477 bytes_transferred += n;
481 if(ec != http::error::need_more)
485 boost::optional<typename
486 DynamicBuffer::mutable_buffers_type> b;
489 b.emplace(buffer.prepare(
490 read_size_or_throw(buffer, 65536)));
492 catch(std::length_error const&)
494 ec = error::buffer_overflow;
495 return bytes_transferred;
497 auto const n = stream.read_some(*b, ec);
498 if(ec == boost::asio::error::eof)
500 BOOST_ASSERT(n == 0);
501 if(parser.got_some())
503 // caller sees EOF on next read
507 BOOST_ASSERT(parser.is_done());
510 ec = error::end_of_stream;
517 return bytes_transferred;
521 class AsyncReadStream,
523 bool isRequest, class Derived,
525 BOOST_ASIO_INITFN_RESULT_TYPE(
526 ReadHandler, void(error_code, std::size_t))
528 AsyncReadStream& stream,
529 DynamicBuffer& buffer,
530 basic_parser<isRequest, Derived>& parser,
531 ReadHandler&& handler)
533 static_assert(is_async_read_stream<AsyncReadStream>::value,
534 "AsyncReadStream requirements not met");
536 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
537 "DynamicBuffer requirements not met");
538 BOOST_ASSERT(! parser.is_done());
539 boost::asio::async_completion<ReadHandler,
540 void(error_code, std::size_t)> init{handler};
541 detail::read_some_op<AsyncReadStream,
542 DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
543 ReadHandler, void(error_code, std::size_t))>{
544 init.completion_handler, stream, buffer, parser}();
545 return init.result.get();
548 //------------------------------------------------------------------------------
551 class SyncReadStream,
553 bool isRequest, class Derived>
556 SyncReadStream& stream,
557 DynamicBuffer& buffer,
558 basic_parser<isRequest, Derived>& parser)
560 static_assert(is_sync_read_stream<SyncReadStream>::value,
561 "SyncReadStream requirements not met");
563 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
564 "DynamicBuffer requirements not met");
566 auto const bytes_transferred =
567 read_header(stream, buffer, parser, ec);
569 BOOST_THROW_EXCEPTION(system_error{ec});
570 return bytes_transferred;
574 class SyncReadStream,
576 bool isRequest, class Derived>
579 SyncReadStream& stream,
580 DynamicBuffer& buffer,
581 basic_parser<isRequest, Derived>& parser,
584 static_assert(is_sync_read_stream<SyncReadStream>::value,
585 "SyncReadStream requirements not met");
587 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
588 "DynamicBuffer requirements not met");
590 if(parser.is_header_done())
592 ec.assign(0, ec.category());
595 std::size_t bytes_transferred = 0;
598 bytes_transferred += read_some(
599 stream, buffer, parser, ec);
601 return bytes_transferred;
603 while(! parser.is_header_done());
604 return bytes_transferred;
608 class AsyncReadStream,
610 bool isRequest, class Derived,
612 BOOST_ASIO_INITFN_RESULT_TYPE(
613 ReadHandler, void(error_code, std::size_t))
615 AsyncReadStream& stream,
616 DynamicBuffer& buffer,
617 basic_parser<isRequest, Derived>& parser,
618 ReadHandler&& handler)
620 static_assert(is_async_read_stream<AsyncReadStream>::value,
621 "AsyncReadStream requirements not met");
623 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
624 "DynamicBuffer requirements not met");
626 boost::asio::async_completion<ReadHandler,
627 void(error_code, std::size_t)> init{handler};
628 detail::read_op<AsyncReadStream, DynamicBuffer,
629 isRequest, Derived, detail::parser_is_header_done,
630 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
631 init.completion_handler, stream, buffer, parser}();
632 return init.result.get();
635 //------------------------------------------------------------------------------
638 class SyncReadStream,
640 bool isRequest, class Derived>
643 SyncReadStream& stream,
644 DynamicBuffer& buffer,
645 basic_parser<isRequest, Derived>& parser)
647 static_assert(is_sync_read_stream<SyncReadStream>::value,
648 "SyncReadStream requirements not met");
650 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
651 "DynamicBuffer requirements not met");
653 auto const bytes_transferred =
654 read(stream, buffer, parser, ec);
656 BOOST_THROW_EXCEPTION(system_error{ec});
657 return bytes_transferred;
661 class SyncReadStream,
663 bool isRequest, class Derived>
666 SyncReadStream& stream,
667 DynamicBuffer& buffer,
668 basic_parser<isRequest, Derived>& parser,
671 static_assert(is_sync_read_stream<SyncReadStream>::value,
672 "SyncReadStream requirements not met");
674 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
675 "DynamicBuffer requirements not met");
679 ec.assign(0, ec.category());
682 std::size_t bytes_transferred = 0;
685 bytes_transferred += read_some(
686 stream, buffer, parser, ec);
688 return bytes_transferred;
690 while(! parser.is_done());
691 return bytes_transferred;
695 class AsyncReadStream,
697 bool isRequest, class Derived,
699 BOOST_ASIO_INITFN_RESULT_TYPE(
700 ReadHandler, void(error_code, std::size_t))
702 AsyncReadStream& stream,
703 DynamicBuffer& buffer,
704 basic_parser<isRequest, Derived>& parser,
705 ReadHandler&& handler)
707 static_assert(is_async_read_stream<AsyncReadStream>::value,
708 "AsyncReadStream requirements not met");
710 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
711 "DynamicBuffer requirements not met");
713 boost::asio::async_completion<
715 void(error_code, std::size_t)> init{handler};
716 detail::read_op<AsyncReadStream, DynamicBuffer,
717 isRequest, Derived, detail::parser_is_done,
718 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
719 init.completion_handler, stream, buffer, parser}();
720 return init.result.get();
723 //------------------------------------------------------------------------------
726 class SyncReadStream,
728 bool isRequest, class Body, class Allocator>
731 SyncReadStream& stream,
732 DynamicBuffer& buffer,
733 message<isRequest, Body, basic_fields<Allocator>>& msg)
735 static_assert(is_sync_read_stream<SyncReadStream>::value,
736 "SyncReadStream requirements not met");
738 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
739 "DynamicBuffer requirements not met");
740 static_assert(is_body<Body>::value,
741 "Body requirements not met");
742 static_assert(is_body_reader<Body>::value,
743 "BodyReader requirements not met");
745 auto const bytes_transferred =
746 read(stream, buffer, msg, ec);
748 BOOST_THROW_EXCEPTION(system_error{ec});
749 return bytes_transferred;
753 class SyncReadStream,
755 bool isRequest, class Body, class Allocator>
758 SyncReadStream& stream,
759 DynamicBuffer& buffer,
760 message<isRequest, Body, basic_fields<Allocator>>& msg,
763 static_assert(is_sync_read_stream<SyncReadStream>::value,
764 "SyncReadStream requirements not met");
766 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
767 "DynamicBuffer requirements not met");
768 static_assert(is_body<Body>::value,
769 "Body requirements not met");
770 static_assert(is_body_reader<Body>::value,
771 "BodyReader requirements not met");
772 parser<isRequest, Body, Allocator> p{std::move(msg)};
774 auto const bytes_transferred =
775 read(stream, buffer, p.base(), ec);
777 return bytes_transferred;
779 return bytes_transferred;
783 class AsyncReadStream,
785 bool isRequest, class Body, class Allocator,
787 BOOST_ASIO_INITFN_RESULT_TYPE(
788 ReadHandler, void(error_code, std::size_t))
790 AsyncReadStream& stream,
791 DynamicBuffer& buffer,
792 message<isRequest, Body, basic_fields<Allocator>>& msg,
793 ReadHandler&& handler)
795 static_assert(is_async_read_stream<AsyncReadStream>::value,
796 "AsyncReadStream requirements not met");
798 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
799 "DynamicBuffer requirements not met");
800 static_assert(is_body<Body>::value,
801 "Body requirements not met");
802 static_assert(is_body_reader<Body>::value,
803 "BodyReader requirements not met");
804 boost::asio::async_completion<
806 void(error_code, std::size_t)> init{handler};
810 isRequest, Body, Allocator,
811 BOOST_ASIO_HANDLER_TYPE(
812 ReadHandler, void(error_code, std::size_t))>{
813 init.completion_handler, stream, buffer, msg}();
814 return init.result.get();