File indexing completed on 2025-01-18 09:29:30
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/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
0134
0135
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
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
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
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
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
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
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 }
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 }
0719 }
0720 }
0721
0722 #endif