File indexing completed on 2025-07-08 08:26:50
0001
0002
0003
0004
0005
0006
0007
0008
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
0144
0145
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
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
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
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
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
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
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 }
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 }
0727 }
0728 }
0729
0730 #endif