Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:30

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