Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-08 08:26:50

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 // Copyright (c) 2020 Richard Hodges (hodges.r@gmail.com)
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0006 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 // Official repository: https://github.com/boostorg/beast
0009 //
0010 
0011 #ifndef BOOST_BEAST_HTTP_IMPL_READ_HPP
0012 #define BOOST_BEAST_HTTP_IMPL_READ_HPP
0013 
0014 #include <boost/beast/http/type_traits.hpp>
0015 #include <boost/beast/http/error.hpp>
0016 #include <boost/beast/http/parser.hpp>
0017 #include <boost/beast/http/read.hpp>
0018 #include <boost/beast/core/async_base.hpp>
0019 #include <boost/beast/core/stream_traits.hpp>
0020 #include <boost/beast/core/detail/buffer.hpp>
0021 #include <boost/beast/core/detail/read.hpp>
0022 #include <boost/asio/append.hpp>
0023 #include <boost/asio/compose.hpp>
0024 #include <boost/asio/coroutine.hpp>
0025 #include <boost/asio/error.hpp>
0026 
0027 namespace boost {
0028 namespace beast {
0029 namespace http {
0030 
0031 namespace detail {
0032 
0033 struct parser_is_done
0034 {
0035     template<bool isRequest>
0036     bool
0037     operator()(basic_parser<isRequest> const& p) const
0038     {
0039         return p.is_done();
0040     }
0041 };
0042 
0043 struct parser_is_header_done
0044 {
0045     template<bool isRequest>
0046     bool
0047     operator()(basic_parser<isRequest> const& p) const
0048     {
0049         return p.is_header_done();
0050     }
0051 };
0052 
0053 //------------------------------------------------------------------------------
0054 
0055 template<
0056     class Stream, class DynamicBuffer,
0057     bool isRequest, class Body, class Allocator,
0058     class Handler>
0059 class read_msg_op
0060     : public beast::stable_async_base<
0061         Handler, beast::executor_type<Stream>>
0062     , public asio::coroutine
0063 {
0064     using parser_type =
0065         parser<isRequest, Body, Allocator>;
0066 
0067     using message_type =
0068         typename parser_type::value_type;
0069 
0070     struct data
0071     {
0072         Stream& s;
0073         message_type& m;
0074         parser_type p;
0075 
0076         data(
0077             Stream& s_,
0078             message_type& m_)
0079             : s(s_)
0080             , m(m_)
0081             , p(std::move(m))
0082         {
0083         }
0084     };
0085 
0086     data& d_;
0087 
0088 public:
0089     template<class Handler_>
0090     read_msg_op(
0091         Handler_&& h,
0092         Stream& s,
0093         DynamicBuffer& b,
0094         message_type& m)
0095         : stable_async_base<
0096             Handler, beast::executor_type<Stream>>(
0097                 std::forward<Handler_>(h), s.get_executor())
0098         , d_(beast::allocate_stable<data>(
0099             *this, s, m))
0100     {
0101         BOOST_ASIO_HANDLER_LOCATION((
0102             __FILE__, __LINE__,
0103             "http::async_read(msg)"));
0104 
0105         http::async_read(d_.s, b, d_.p, std::move(*this));
0106     }
0107 
0108     void
0109     operator()(
0110         error_code ec,
0111         std::size_t bytes_transferred)
0112     {
0113         if(! ec)
0114             d_.m = d_.p.release();
0115         this->complete_now(ec, bytes_transferred);
0116     }
0117 };
0118 
0119 template <typename AsyncReadStream>
0120 struct run_read_msg_op
0121 {
0122     AsyncReadStream* stream;
0123 
0124     using executor_type = typename AsyncReadStream::executor_type;
0125 
0126     executor_type
0127     get_executor() const noexcept
0128     {
0129         return stream->get_executor();
0130     }
0131 
0132     template<
0133         class ReadHandler,
0134         class DynamicBuffer,
0135         bool isRequest, class Body, class Allocator>
0136     void
0137     operator()(
0138         ReadHandler&& h,
0139         DynamicBuffer* b,
0140         message<isRequest, Body,
0141             basic_fields<Allocator>>* m)
0142     {
0143         // If you get an error on the following line it means
0144         // that your handler does not meet the documented type
0145         // requirements for the handler.
0146 
0147         static_assert(
0148             beast::detail::is_invocable<ReadHandler,
0149             void(error_code, std::size_t)>::value,
0150             "ReadHandler type requirements not met");
0151 
0152         read_msg_op<
0153             AsyncReadStream,
0154             DynamicBuffer,
0155             isRequest, Body, Allocator,
0156             typename std::decay<ReadHandler>::type>(
0157                 std::forward<ReadHandler>(h), *stream, *b, *m);
0158     }
0159 };
0160 
0161 template<class AsyncReadStream, class DynamicBuffer, bool isRequest>
0162 class read_some_op : asio::coroutine
0163 {
0164     AsyncReadStream& s_;
0165     DynamicBuffer& b_;
0166     basic_parser<isRequest>& p_;
0167     std::size_t bytes_transferred_;
0168     bool cont_;
0169 
0170 public:
0171     read_some_op(
0172         AsyncReadStream& s,
0173         DynamicBuffer& b,
0174         basic_parser<isRequest>& p)
0175         : s_(s)
0176         , b_(b)
0177         , p_(p)
0178         , bytes_transferred_(0)
0179         , cont_(false)
0180     {
0181     }
0182 
0183     template<class Self>
0184     void operator()(
0185         Self& self,
0186         error_code ec = {},
0187         std::size_t bytes_transferred = 0)
0188     {
0189         BOOST_ASIO_CORO_REENTER(*this)
0190         {
0191             if(b_.size() == 0)
0192                 goto do_read;
0193             for(;;)
0194             {
0195                 // parse
0196                 {
0197                     auto const used = p_.put(b_.data(), ec);
0198                     bytes_transferred_ += used;
0199                     b_.consume(used);
0200                 }
0201                 if(ec != http::error::need_more)
0202                     break;
0203 
0204             do_read:
0205                 BOOST_ASIO_CORO_YIELD
0206                 {
0207                     cont_ = true;
0208                     // VFALCO This was read_size_or_throw
0209                     auto const size = read_size(b_, 65536);
0210                     if(size == 0)
0211                     {
0212                         BOOST_BEAST_ASSIGN_EC(ec, error::buffer_overflow);
0213                         goto upcall;
0214                     }
0215                     auto const mb =
0216                         beast::detail::dynamic_buffer_prepare(
0217                             b_, size, ec, error::buffer_overflow);
0218                     if(ec)
0219                         goto upcall;
0220 
0221                     BOOST_ASIO_HANDLER_LOCATION((
0222                         __FILE__, __LINE__,
0223                         "http::async_read_some"));
0224 
0225                     s_.async_read_some(*mb, std::move(self));
0226                 }
0227                 b_.commit(bytes_transferred);
0228                 if(ec == net::error::eof)
0229                 {
0230                     BOOST_ASSERT(bytes_transferred == 0);
0231                     if(p_.got_some())
0232                     {
0233                         // caller sees EOF on next read
0234                         ec.assign(0, ec.category());
0235                         p_.put_eof(ec);
0236                         if(ec)
0237                             goto upcall;
0238                         BOOST_ASSERT(p_.is_done());
0239                         goto upcall;
0240                     }
0241                     BOOST_BEAST_ASSIGN_EC(ec, error::end_of_stream);
0242                     break;
0243                 }
0244                 if(ec)
0245                     break;
0246             }
0247 
0248         upcall:
0249             if(! cont_)
0250             {
0251                 BOOST_ASIO_CORO_YIELD
0252                 {
0253                     BOOST_ASIO_HANDLER_LOCATION((
0254                         __FILE__, __LINE__,
0255                         "http::async_read_some"));
0256 
0257 
0258                     const auto ex =
0259                         asio::get_associated_immediate_executor(
0260                             self, s_.get_executor());
0261 
0262                     net::dispatch(ex, net::append(std::move(self), ec));
0263                 }
0264             }
0265             self.complete(ec, bytes_transferred_);
0266         }
0267     }
0268 };
0269 
0270 template<class Stream, class DynamicBuffer, bool isRequest, class Condition>
0271 class read_op
0272     : asio::coroutine
0273 {
0274     Stream& s_;
0275     DynamicBuffer& b_;
0276     basic_parser<isRequest>& p_;
0277     std::size_t bytes_transferred_;
0278 
0279 public:
0280     read_op(Stream& s, DynamicBuffer& b, basic_parser<isRequest>& p)
0281     : s_(s)
0282     , b_(b)
0283     , p_(p)
0284     , bytes_transferred_(0)
0285     {
0286     }
0287 
0288     template<class Self>
0289     void operator()(Self& self, error_code ec = {}, std::size_t bytes_transferred = 0)
0290     {
0291         BOOST_ASIO_CORO_REENTER(*this)
0292         {
0293             if (Condition{}(p_))
0294             {
0295                 BOOST_ASIO_CORO_YIELD
0296                 {
0297                     BOOST_ASIO_HANDLER_LOCATION((
0298                         __FILE__, __LINE__,
0299                         "http::async_read"));
0300 
0301                     const auto ex =
0302                         asio::get_associated_immediate_executor(
0303                             self, s_.get_executor());
0304 
0305                     net::dispatch(ex, std::move(self));
0306                 }
0307             }
0308             else
0309             {
0310                 do
0311                 {
0312                     BOOST_ASIO_CORO_YIELD
0313                     {
0314                         BOOST_ASIO_HANDLER_LOCATION((
0315                             __FILE__, __LINE__,
0316                             "http::async_read"));
0317 
0318                         async_read_some(
0319                             s_, b_, p_, std::move(self));
0320                     }
0321                     bytes_transferred_ += bytes_transferred;
0322                 } while (!ec &&
0323                          !Condition{}(p_));
0324             }
0325             self.complete(ec, bytes_transferred_);
0326         }
0327     }
0328 };
0329 
0330 
0331 template<
0332     class SyncReadStream,
0333     class DynamicBuffer,
0334     bool isRequest>
0335 std::size_t
0336 read_some(SyncReadStream& s, DynamicBuffer& b, basic_parser<isRequest>& p, error_code& ec)
0337 {
0338     std::size_t total = 0;
0339     ec.clear();
0340     if(b.size() == 0)
0341         goto do_read;
0342     for(;;)
0343     {
0344         // parse
0345         {
0346             auto const used = p.put(b.data(), ec);
0347             total += used;
0348             b.consume(used);
0349         }
0350         if(ec != http::error::need_more)
0351             break;
0352 
0353     do_read:
0354         // VFALCO This was read_size_or_throw
0355         auto const size = read_size(b, 65536);
0356         if(size == 0)
0357         {
0358             BOOST_BEAST_ASSIGN_EC(ec, error::buffer_overflow);
0359             return total;
0360         }
0361         auto const mb =
0362             beast::detail::dynamic_buffer_prepare(
0363                 b, size, ec, error::buffer_overflow);
0364         if(ec)
0365             return total;
0366         std::size_t
0367             bytes_transferred =
0368                 s.read_some(*mb, ec);
0369         b.commit(bytes_transferred);
0370         if(ec == net::error::eof)
0371         {
0372             BOOST_ASSERT(bytes_transferred == 0);
0373             if(p.got_some())
0374             {
0375                 // caller sees EOF on next read
0376                 ec.assign(0, ec.category());
0377                 p.put_eof(ec);
0378                 if(ec)
0379                     return total;
0380                 BOOST_ASSERT(p.is_done());
0381                 return total;
0382             }
0383             BOOST_BEAST_ASSIGN_EC(ec, error::end_of_stream);
0384             break;
0385         }
0386         if(ec)
0387             break;
0388     }
0389 
0390     return total;
0391 }
0392 
0393 template<class Condition, class Stream, class DynamicBuffer, bool isRequest>
0394 std::size_t sync_read_op(Stream& s, DynamicBuffer& b, basic_parser<isRequest>& p, error_code& ec)
0395 {
0396     std::size_t total = 0;
0397     ec.clear();
0398 
0399     if (!Condition{}(p))
0400     {
0401         do
0402         {
0403             total +=
0404                 detail::read_some(s, b, p, ec);
0405         } while (!ec &&
0406                  !Condition{}(p));
0407     }
0408     return total;
0409 }
0410 
0411 } // detail
0412 
0413 //------------------------------------------------------------------------------
0414 
0415 template<
0416     class SyncReadStream,
0417     class DynamicBuffer,
0418     bool isRequest>
0419 std::size_t
0420 read_some(
0421     SyncReadStream& stream,
0422     DynamicBuffer& buffer,
0423     basic_parser<isRequest>& parser)
0424 {
0425     static_assert(
0426         is_sync_read_stream<SyncReadStream>::value,
0427         "SyncReadStream type requirements not met");
0428     static_assert(
0429         net::is_dynamic_buffer<DynamicBuffer>::value,
0430         "DynamicBuffer type requirements not met");
0431     error_code ec;
0432     auto const bytes_transferred =
0433         http::read_some(stream, buffer, parser, ec);
0434     if(ec)
0435         BOOST_THROW_EXCEPTION(system_error{ec});
0436     return bytes_transferred;
0437 }
0438 
0439 template<
0440     class SyncReadStream,
0441     class DynamicBuffer,
0442     bool isRequest>
0443 std::size_t
0444 read_some(
0445     SyncReadStream& stream,
0446     DynamicBuffer& buffer,
0447     basic_parser<isRequest>& parser,
0448     error_code& ec)
0449 {
0450     static_assert(
0451         is_sync_read_stream<SyncReadStream>::value,
0452         "SyncReadStream type requirements not met");
0453     static_assert(
0454         net::is_dynamic_buffer<DynamicBuffer>::value,
0455         "DynamicBuffer type requirements not met");
0456     return detail::read_some(stream, buffer, parser, ec);
0457 }
0458 
0459 template<
0460     class AsyncReadStream,
0461     class DynamicBuffer,
0462     bool isRequest,
0463     BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0464 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0465 async_read_some(
0466     AsyncReadStream& stream,
0467     DynamicBuffer& buffer,
0468     basic_parser<isRequest>& parser,
0469     ReadHandler&& handler)
0470 {
0471     return net::async_compose<ReadHandler,
0472         void(beast::error_code, std::size_t)>(
0473             detail::read_some_op<AsyncReadStream, DynamicBuffer, isRequest> {
0474                 stream,
0475                 buffer,
0476                 parser
0477             },
0478             handler,
0479             stream);
0480 }
0481 
0482 //------------------------------------------------------------------------------
0483 
0484 template<
0485     class SyncReadStream,
0486     class DynamicBuffer,
0487     bool isRequest>
0488 std::size_t
0489 read_header(
0490     SyncReadStream& stream,
0491     DynamicBuffer& buffer,
0492     basic_parser<isRequest>& parser)
0493 {
0494     static_assert(
0495         is_sync_read_stream<SyncReadStream>::value,
0496         "SyncReadStream type requirements not met");
0497     static_assert(
0498         net::is_dynamic_buffer<DynamicBuffer>::value,
0499         "DynamicBuffer type requirements not met");
0500     error_code ec;
0501     auto const bytes_transferred =
0502         http::read_header(stream, buffer, parser, ec);
0503     if(ec)
0504         BOOST_THROW_EXCEPTION(system_error{ec});
0505     return bytes_transferred;
0506 }
0507 
0508 template<
0509     class SyncReadStream,
0510     class DynamicBuffer,
0511     bool isRequest>
0512 std::size_t
0513 read_header(
0514     SyncReadStream& stream,
0515     DynamicBuffer& buffer,
0516     basic_parser<isRequest>& parser,
0517     error_code& ec)
0518 {
0519     static_assert(
0520         is_sync_read_stream<SyncReadStream>::value,
0521         "SyncReadStream type requirements not met");
0522     static_assert(
0523         net::is_dynamic_buffer<DynamicBuffer>::value,
0524         "DynamicBuffer type requirements not met");
0525     parser.eager(false);
0526     return detail::sync_read_op<
0527         detail::parser_is_header_done>(
0528             stream, buffer, parser, ec);
0529 }
0530 
0531 template<
0532     class AsyncReadStream,
0533     class DynamicBuffer,
0534     bool isRequest,
0535     BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0536 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0537 async_read_header(
0538     AsyncReadStream& stream,
0539     DynamicBuffer& buffer,
0540     basic_parser<isRequest>& parser,
0541     ReadHandler&& handler)
0542 {
0543     parser.eager(false);
0544     return net::async_compose<
0545         ReadHandler,
0546         void(error_code, std::size_t)>(
0547         detail::read_op<
0548             AsyncReadStream,
0549             DynamicBuffer,
0550             isRequest,
0551             detail::parser_is_header_done>(
0552                 stream, buffer, parser),
0553             handler, stream);
0554 }
0555 
0556 //------------------------------------------------------------------------------
0557 
0558 template<
0559     class SyncReadStream,
0560     class DynamicBuffer,
0561     bool isRequest>
0562 std::size_t
0563 read(
0564     SyncReadStream& stream,
0565     DynamicBuffer& buffer,
0566     basic_parser<isRequest>& parser)
0567 {
0568     static_assert(
0569         is_sync_read_stream<SyncReadStream>::value,
0570         "SyncReadStream type requirements not met");
0571     static_assert(
0572         net::is_dynamic_buffer<DynamicBuffer>::value,
0573         "DynamicBuffer type requirements not met");
0574     error_code ec;
0575     auto const bytes_transferred =
0576         http::read(stream, buffer, parser, ec);
0577     if(ec)
0578         BOOST_THROW_EXCEPTION(system_error{ec});
0579     return bytes_transferred;
0580 }
0581 
0582 template<
0583     class SyncReadStream,
0584     class DynamicBuffer,
0585     bool isRequest>
0586 std::size_t
0587 read(
0588     SyncReadStream& stream,
0589     DynamicBuffer& buffer,
0590     basic_parser<isRequest>& parser,
0591     error_code& ec)
0592 {
0593     static_assert(
0594         is_sync_read_stream<SyncReadStream>::value,
0595         "SyncReadStream type requirements not met");
0596     static_assert(
0597         net::is_dynamic_buffer<DynamicBuffer>::value,
0598         "DynamicBuffer type requirements not met");
0599     parser.eager(true);
0600     return detail::sync_read_op<
0601         detail::parser_is_done>(
0602             stream, buffer, parser, ec);
0603 }
0604 
0605 template<
0606     class AsyncReadStream,
0607     class DynamicBuffer,
0608     bool isRequest,
0609     BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0610 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0611 async_read(
0612     AsyncReadStream& stream,
0613     DynamicBuffer& buffer,
0614     basic_parser<isRequest>& parser,
0615     ReadHandler&& handler)
0616 {
0617     static_assert(
0618         is_async_read_stream<AsyncReadStream>::value,
0619         "AsyncReadStream type requirements not met");
0620     static_assert(
0621         net::is_dynamic_buffer<DynamicBuffer>::value,
0622         "DynamicBuffer type requirements not met");
0623     parser.eager(true);
0624     return net::async_compose<
0625         ReadHandler,
0626         void(error_code, std::size_t)>(
0627             detail::read_op<
0628                 AsyncReadStream,
0629                 DynamicBuffer,
0630                 isRequest,
0631                 detail::parser_is_done>(
0632                     stream, buffer, parser),
0633             handler, stream);
0634 }
0635 
0636 //------------------------------------------------------------------------------
0637 
0638 template<
0639     class SyncReadStream,
0640     class DynamicBuffer,
0641     bool isRequest, class Body, class Allocator>
0642 std::size_t
0643 read(
0644     SyncReadStream& stream,
0645     DynamicBuffer& buffer,
0646     message<isRequest, Body, basic_fields<Allocator>>& msg)
0647 {
0648     static_assert(
0649         is_sync_read_stream<SyncReadStream>::value,
0650         "SyncReadStream type requirements not met");
0651     static_assert(
0652         net::is_dynamic_buffer<DynamicBuffer>::value,
0653         "DynamicBuffer type requirements not met");
0654     static_assert(is_body<Body>::value,
0655         "Body type requirements not met");
0656     static_assert(is_body_reader<Body>::value,
0657         "BodyReader type requirements not met");
0658     error_code ec;
0659     auto const bytes_transferred =
0660         http::read(stream, buffer, msg, ec);
0661     if(ec)
0662         BOOST_THROW_EXCEPTION(system_error{ec});
0663     return bytes_transferred;
0664 }
0665 
0666 template<
0667     class SyncReadStream,
0668     class DynamicBuffer,
0669     bool isRequest, class Body, class Allocator>
0670 std::size_t
0671 read(
0672     SyncReadStream& stream,
0673     DynamicBuffer& buffer,
0674     message<isRequest, Body, basic_fields<Allocator>>& msg,
0675     error_code& ec)
0676 {
0677     static_assert(
0678         is_sync_read_stream<SyncReadStream>::value,
0679         "SyncReadStream type requirements not met");
0680     static_assert(
0681         net::is_dynamic_buffer<DynamicBuffer>::value,
0682         "DynamicBuffer type requirements not met");
0683     static_assert(is_body<Body>::value,
0684         "Body type requirements not met");
0685     static_assert(is_body_reader<Body>::value,
0686         "BodyReader type requirements not met");
0687     parser<isRequest, Body, Allocator> p(std::move(msg));
0688     p.eager(true);
0689     auto const bytes_transferred =
0690         http::read(stream, buffer, p, ec);
0691     if(ec)
0692         return bytes_transferred;
0693     msg = p.release();
0694     return bytes_transferred;
0695 }
0696 
0697 template<
0698     class AsyncReadStream,
0699     class DynamicBuffer,
0700     bool isRequest, class Body, class Allocator,
0701     BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0702 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0703 async_read(
0704     AsyncReadStream& stream,
0705     DynamicBuffer& buffer,
0706     message<isRequest, Body, basic_fields<Allocator>>& msg,
0707     ReadHandler&& handler)
0708 {
0709     static_assert(
0710         is_async_read_stream<AsyncReadStream>::value,
0711         "AsyncReadStream type requirements not met");
0712     static_assert(
0713         net::is_dynamic_buffer<DynamicBuffer>::value,
0714         "DynamicBuffer type requirements not met");
0715     static_assert(is_body<Body>::value,
0716         "Body type requirements not met");
0717     static_assert(is_body_reader<Body>::value,
0718         "BodyReader type requirements not met");
0719     return net::async_initiate<
0720         ReadHandler,
0721         void(error_code, std::size_t)>(
0722             detail::run_read_msg_op<AsyncReadStream>{&stream},
0723                 handler, &buffer, &msg);
0724 }
0725 
0726 } // http
0727 } // beast
0728 } // boost
0729 
0730 #endif