File indexing completed on 2026-08-08 08:43:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_READ_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_READ_HPP
0012
0013 #include <boost/beast/core/buffer_traits.hpp>
0014 #include <boost/beast/websocket/teardown.hpp>
0015 #include <boost/beast/websocket/detail/mask.hpp>
0016 #include <boost/beast/websocket/impl/stream_impl.hpp>
0017 #include <boost/beast/core/async_base.hpp>
0018 #include <boost/beast/core/buffers_prefix.hpp>
0019 #include <boost/beast/core/buffers_suffix.hpp>
0020 #include <boost/beast/core/flat_static_buffer.hpp>
0021 #include <boost/beast/core/read_size.hpp>
0022 #include <boost/beast/core/stream_traits.hpp>
0023 #include <boost/beast/core/detail/bind_continuation.hpp>
0024 #include <boost/beast/core/detail/buffer.hpp>
0025 #include <boost/beast/core/detail/clamp.hpp>
0026 #include <boost/beast/core/detail/config.hpp>
0027 #include <boost/asio/coroutine.hpp>
0028 #include <boost/assert.hpp>
0029 #include <boost/config.hpp>
0030 #include <boost/optional.hpp>
0031 #include <boost/throw_exception.hpp>
0032 #include <algorithm>
0033 #include <limits>
0034 #include <memory>
0035
0036 namespace boost {
0037 namespace beast {
0038 namespace websocket {
0039
0040
0041
0042
0043
0044 template<class NextLayer, bool deflateSupported>
0045 template<class Handler, class MutableBufferSequence>
0046 class stream<NextLayer, deflateSupported>::read_some_op
0047 : public beast::async_base<
0048 Handler, beast::executor_type<stream>>
0049 , public asio::coroutine
0050 {
0051 boost::weak_ptr<impl_type> wp_;
0052 MutableBufferSequence bs_;
0053 buffers_suffix<MutableBufferSequence> cb_;
0054 std::size_t bytes_written_ = 0;
0055 error_code result_;
0056 close_code code_;
0057 bool did_read_ = false;
0058
0059 public:
0060 static constexpr int id = 1;
0061
0062 template<class Handler_>
0063 read_some_op(
0064 Handler_&& h,
0065 boost::shared_ptr<impl_type> const& sp,
0066 MutableBufferSequence const& bs)
0067 : async_base<
0068 Handler, beast::executor_type<stream>>(
0069 std::forward<Handler_>(h),
0070 sp->stream().get_executor())
0071 , wp_(sp)
0072 , bs_(bs)
0073 , cb_(bs)
0074 , code_(close_code::none)
0075 {
0076 (*this)({}, 0, false);
0077 }
0078
0079 void operator()(
0080 error_code ec = {},
0081 std::size_t bytes_transferred = 0,
0082 bool cont = true)
0083 {
0084 using beast::detail::clamp;
0085 auto sp = wp_.lock();
0086 if(! sp)
0087 {
0088 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0089 bytes_written_ = 0;
0090 return this->complete(cont, ec, bytes_written_);
0091 }
0092 auto& impl = *sp;
0093 BOOST_ASIO_CORO_REENTER(*this)
0094 {
0095 impl.update_timer(this->get_executor());
0096
0097 acquire_read_lock:
0098
0099 if(! impl.rd_block.try_lock(this))
0100 {
0101 do_suspend:
0102 BOOST_ASIO_CORO_YIELD
0103 {
0104 BOOST_ASIO_HANDLER_LOCATION((
0105 __FILE__, __LINE__,
0106 "websocket::async_read_some"));
0107
0108 this->set_allowed_cancellation(net::cancellation_type::all);
0109 impl.op_r_rd.emplace(std::move(*this), net::cancellation_type::all);
0110 }
0111 if (ec)
0112 return this->complete(cont, ec, bytes_written_);
0113
0114 this->set_allowed_cancellation(net::cancellation_type::terminal);
0115
0116 impl.rd_block.lock(this);
0117 BOOST_ASIO_CORO_YIELD
0118 {
0119 BOOST_ASIO_HANDLER_LOCATION((
0120 __FILE__, __LINE__,
0121 "websocket::async_read_some"));
0122
0123 const auto ex = this->get_immediate_executor();
0124 net::dispatch(ex, std::move(*this));
0125 }
0126 BOOST_ASSERT(impl.rd_block.is_locked(this));
0127
0128 BOOST_ASSERT(!ec);
0129 if(impl.check_stop_now(ec))
0130 {
0131
0132
0133
0134
0135
0136 goto upcall;
0137 }
0138
0139
0140
0141
0142 BOOST_ASSERT(impl.wr_close);
0143 BOOST_ASSERT(impl.status_ != status::open);
0144 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0145 goto upcall;
0146 }
0147 else
0148 {
0149
0150 if( impl.status_ == status::closed ||
0151 impl.status_ == status::failed)
0152 {
0153 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0154 goto upcall;
0155 }
0156 }
0157
0158
0159
0160
0161
0162 loop:
0163 BOOST_ASSERT(impl.rd_block.is_locked(this));
0164
0165
0166
0167
0168 if(impl.rd_remain == 0 &&
0169 (! impl.rd_fh.fin || impl.rd_done))
0170 {
0171
0172 while(! impl.parse_fh(
0173 impl.rd_fh, impl.rd_buf, result_))
0174 {
0175 if(result_)
0176 {
0177
0178 if(result_ == error::message_too_big)
0179 code_ = close_code::too_big;
0180 else
0181 code_ = close_code::protocol_error;
0182 goto close;
0183 }
0184 BOOST_ASSERT(impl.rd_block.is_locked(this));
0185 BOOST_ASIO_CORO_YIELD
0186 {
0187 BOOST_ASIO_HANDLER_LOCATION((
0188 __FILE__, __LINE__,
0189 "websocket::async_read_some"));
0190
0191 impl.stream().async_read_some(
0192 impl.rd_buf.prepare(read_size(
0193 impl.rd_buf, impl.rd_buf.max_size())),
0194 std::move(*this));
0195 }
0196 BOOST_ASSERT(impl.rd_block.is_locked(this));
0197 impl.rd_buf.commit(bytes_transferred);
0198 if(impl.check_stop_now(ec))
0199 goto upcall;
0200 impl.reset_idle();
0201
0202
0203
0204 impl.rd_block.unlock(this);
0205 if( impl.op_r_close.maybe_invoke())
0206 {
0207
0208 BOOST_ASSERT(impl.rd_block.is_locked());
0209 goto do_suspend;
0210 }
0211
0212 impl.rd_block.lock(this);
0213 }
0214
0215
0216 if(impl.rd_fh.len > 0 && impl.rd_fh.mask)
0217 detail::mask_inplace(buffers_prefix(
0218 clamp(impl.rd_fh.len),
0219 impl.rd_buf.data()),
0220 impl.rd_key);
0221 if(detail::is_control(impl.rd_fh.op))
0222 {
0223
0224
0225 impl.rd_fh.fin = false;
0226
0227
0228 if(impl.rd_fh.op == detail::opcode::ping)
0229 {
0230 impl.update_timer(this->get_executor());
0231
0232 if(impl.ctrl_cb)
0233 {
0234 if(! cont)
0235 {
0236 BOOST_ASIO_CORO_YIELD
0237 {
0238 BOOST_ASIO_HANDLER_LOCATION((
0239 __FILE__, __LINE__,
0240 "websocket::async_read_some"));
0241
0242 const auto ex = this->get_immediate_executor();
0243 net::dispatch(ex, std::move(*this));
0244 }
0245 BOOST_ASSERT(cont);
0246
0247 }
0248 }
0249 {
0250 auto const b = buffers_prefix(
0251 clamp(impl.rd_fh.len),
0252 impl.rd_buf.data());
0253 auto const len = buffer_bytes(b);
0254 BOOST_ASSERT(len == impl.rd_fh.len);
0255 ping_data payload;
0256 detail::read_ping(payload, b);
0257 impl.rd_buf.consume(len);
0258
0259 if(impl.status_ == status::closing)
0260 goto loop;
0261 if(impl.ctrl_cb)
0262 impl.ctrl_cb(
0263 frame_type::ping, to_string_view(payload));
0264 impl.rd_fb.clear();
0265 impl.template write_ping<
0266 flat_static_buffer_base>(impl.rd_fb,
0267 detail::opcode::pong, payload);
0268 }
0269
0270
0271
0272 impl.rd_block.unlock(this);
0273 impl.op_r_close.maybe_invoke();
0274
0275
0276 if(! impl.wr_block.try_lock(this))
0277 {
0278 BOOST_ASIO_CORO_YIELD
0279 {
0280 BOOST_ASIO_HANDLER_LOCATION((
0281 __FILE__, __LINE__,
0282 "websocket::async_read_some"));
0283
0284 impl.op_rd.emplace(std::move(*this));
0285 }
0286 if (ec)
0287 return this->complete(cont, ec, bytes_written_);
0288
0289 impl.wr_block.lock(this);
0290 BOOST_ASIO_CORO_YIELD
0291 {
0292 BOOST_ASIO_HANDLER_LOCATION((
0293 __FILE__, __LINE__,
0294 "websocket::async_read_some"));
0295
0296 const auto ex = this->get_immediate_executor();
0297 net::dispatch(ex, std::move(*this));
0298 }
0299 BOOST_ASSERT(impl.wr_block.is_locked(this));
0300 if(impl.check_stop_now(ec))
0301 goto upcall;
0302 }
0303
0304
0305 BOOST_ASSERT(impl.wr_block.is_locked(this));
0306 BOOST_ASIO_CORO_YIELD
0307 {
0308 BOOST_ASIO_HANDLER_LOCATION((
0309 __FILE__, __LINE__,
0310 "websocket::async_read_some"));
0311
0312 net::async_write(
0313 impl.stream(), net::const_buffer(impl.rd_fb.data()),
0314 beast::detail::bind_continuation(std::move(*this)));
0315 }
0316 BOOST_ASSERT(impl.wr_block.is_locked(this));
0317 if(impl.check_stop_now(ec))
0318 goto upcall;
0319 impl.wr_block.unlock(this);
0320 impl.op_close.maybe_invoke()
0321 || impl.op_idle_ping.maybe_invoke()
0322 || impl.op_ping.maybe_invoke()
0323 || impl.op_wr.maybe_invoke();
0324 goto acquire_read_lock;
0325 }
0326
0327
0328 if(impl.rd_fh.op == detail::opcode::pong)
0329 {
0330
0331 if(! impl.wr_close && impl.ctrl_cb)
0332 {
0333 if(! cont)
0334 {
0335 BOOST_ASIO_CORO_YIELD
0336 {
0337 BOOST_ASIO_HANDLER_LOCATION((
0338 __FILE__, __LINE__,
0339 "websocket::async_read_some"));
0340
0341 const auto ex = this->get_immediate_executor();
0342 net::dispatch(ex, std::move(*this));
0343 }
0344 BOOST_ASSERT(cont);
0345 }
0346 }
0347 auto const cb = buffers_prefix(clamp(
0348 impl.rd_fh.len), impl.rd_buf.data());
0349 auto const len = buffer_bytes(cb);
0350 BOOST_ASSERT(len == impl.rd_fh.len);
0351 ping_data payload;
0352 detail::read_ping(payload, cb);
0353 impl.rd_buf.consume(len);
0354
0355 if(! impl.wr_close && impl.ctrl_cb)
0356 impl.ctrl_cb(frame_type::pong, to_string_view(payload));
0357 goto loop;
0358 }
0359
0360
0361 BOOST_ASSERT(impl.rd_fh.op == detail::opcode::close);
0362 {
0363 if(impl.ctrl_cb)
0364 {
0365 if(! cont)
0366 {
0367 BOOST_ASIO_CORO_YIELD
0368 {
0369 BOOST_ASIO_HANDLER_LOCATION((
0370 __FILE__, __LINE__,
0371 "websocket::async_read_some"));
0372
0373 const auto ex = this->get_immediate_executor();
0374 net::dispatch(ex, std::move(*this));
0375 }
0376 BOOST_ASSERT(cont);
0377 }
0378 }
0379 auto const cb = buffers_prefix(clamp(
0380 impl.rd_fh.len), impl.rd_buf.data());
0381 auto const len = buffer_bytes(cb);
0382 BOOST_ASSERT(len == impl.rd_fh.len);
0383 BOOST_ASSERT(! impl.rd_close);
0384 impl.rd_close = true;
0385 close_reason cr;
0386 detail::read_close(cr, cb, result_);
0387 if(result_)
0388 {
0389
0390 code_ = close_code::protocol_error;
0391 goto close;
0392 }
0393 impl.cr = cr;
0394 impl.rd_buf.consume(len);
0395 if(impl.ctrl_cb)
0396 impl.ctrl_cb(frame_type::close,
0397 to_string_view(impl.cr.reason));
0398
0399 if(impl.status_ == status::closing)
0400 {
0401
0402 BOOST_ASSERT(impl.wr_close);
0403 code_ = close_code::none;
0404 result_ = error::closed;
0405 goto close;
0406 }
0407
0408 code_ = cr.code == close_code::none ?
0409 close_code::normal :
0410 static_cast<close_code>(cr.code);
0411 result_ = error::closed;
0412 goto close;
0413 }
0414 }
0415 if(impl.rd_fh.len == 0 && ! impl.rd_fh.fin)
0416 {
0417
0418 goto loop;
0419 }
0420 impl.rd_done = false;
0421 }
0422 if(! impl.rd_deflated())
0423 {
0424 if(impl.rd_remain > 0)
0425 {
0426 if(impl.rd_buf.size() == 0 && impl.rd_buf.max_size() >
0427 (std::min)(clamp(impl.rd_remain),
0428 buffer_bytes(cb_)))
0429 {
0430
0431
0432 BOOST_ASIO_CORO_YIELD
0433 {
0434 BOOST_ASIO_HANDLER_LOCATION((
0435 __FILE__, __LINE__,
0436 "websocket::async_read_some"));
0437
0438 impl.stream().async_read_some(
0439 impl.rd_buf.prepare(read_size(
0440 impl.rd_buf, impl.rd_buf.max_size())),
0441 std::move(*this));
0442 }
0443 impl.rd_buf.commit(bytes_transferred);
0444 if(impl.check_stop_now(ec))
0445 goto upcall;
0446 impl.reset_idle();
0447 if(impl.rd_fh.mask)
0448 detail::mask_inplace(buffers_prefix(clamp(
0449 impl.rd_remain), impl.rd_buf.data()),
0450 impl.rd_key);
0451 }
0452 if(impl.rd_buf.size() > 0)
0453 {
0454
0455
0456 bytes_transferred = net::buffer_copy(cb_,
0457 impl.rd_buf.data(), clamp(impl.rd_remain));
0458 auto const mb = buffers_prefix(
0459 bytes_transferred, cb_);
0460 impl.rd_remain -= bytes_transferred;
0461 if(impl.rd_op == detail::opcode::text)
0462 {
0463 if(! impl.rd_utf8.write(mb) ||
0464 (impl.rd_remain == 0 && impl.rd_fh.fin &&
0465 ! impl.rd_utf8.finish()))
0466 {
0467
0468 code_ = close_code::bad_payload;
0469 result_ = error::bad_frame_payload;
0470 goto close;
0471 }
0472 }
0473 bytes_written_ += bytes_transferred;
0474 impl.rd_size += bytes_transferred;
0475 impl.rd_buf.consume(bytes_transferred);
0476 }
0477 else
0478 {
0479
0480 BOOST_ASSERT(impl.rd_remain > 0);
0481 BOOST_ASSERT(buffer_bytes(cb_) > 0);
0482 BOOST_ASSERT(buffer_bytes(buffers_prefix(
0483 clamp(impl.rd_remain), cb_)) > 0);
0484 BOOST_ASIO_CORO_YIELD
0485 {
0486 BOOST_ASIO_HANDLER_LOCATION((
0487 __FILE__, __LINE__,
0488 "websocket::async_read_some"));
0489
0490 impl.stream().async_read_some(buffers_prefix(
0491 clamp(impl.rd_remain), cb_), std::move(*this));
0492 }
0493 if(impl.check_stop_now(ec))
0494 goto upcall;
0495 impl.reset_idle();
0496 BOOST_ASSERT(bytes_transferred > 0);
0497 auto const mb = buffers_prefix(
0498 bytes_transferred, cb_);
0499 impl.rd_remain -= bytes_transferred;
0500 if(impl.rd_fh.mask)
0501 detail::mask_inplace(mb, impl.rd_key);
0502 if(impl.rd_op == detail::opcode::text)
0503 {
0504 if(! impl.rd_utf8.write(mb) ||
0505 (impl.rd_remain == 0 && impl.rd_fh.fin &&
0506 ! impl.rd_utf8.finish()))
0507 {
0508
0509 code_ = close_code::bad_payload;
0510 result_ = error::bad_frame_payload;
0511 goto close;
0512 }
0513 }
0514 bytes_written_ += bytes_transferred;
0515 impl.rd_size += bytes_transferred;
0516 }
0517 }
0518 BOOST_ASSERT( ! impl.rd_done );
0519 if( impl.rd_remain == 0 && impl.rd_fh.fin )
0520 impl.rd_done = true;
0521 }
0522 else
0523 {
0524
0525
0526
0527 while(buffer_bytes(cb_) > 0)
0528 {
0529 if( impl.rd_remain > 0 &&
0530 impl.rd_buf.size() == 0 &&
0531 ! did_read_)
0532 {
0533
0534 BOOST_ASIO_CORO_YIELD
0535 {
0536 BOOST_ASIO_HANDLER_LOCATION((
0537 __FILE__, __LINE__,
0538 "websocket::async_read_some"));
0539
0540 impl.stream().async_read_some(
0541 impl.rd_buf.prepare(read_size(
0542 impl.rd_buf, impl.rd_buf.max_size())),
0543 std::move(*this));
0544 }
0545 if(impl.check_stop_now(ec))
0546 goto upcall;
0547 impl.reset_idle();
0548 BOOST_ASSERT(bytes_transferred > 0);
0549 impl.rd_buf.commit(bytes_transferred);
0550 if(impl.rd_fh.mask)
0551 detail::mask_inplace(
0552 buffers_prefix(clamp(impl.rd_remain),
0553 impl.rd_buf.data()), impl.rd_key);
0554 did_read_ = true;
0555 }
0556 zlib::z_params zs;
0557 {
0558 auto const out = buffers_front(cb_);
0559 zs.next_out = out.data();
0560 zs.avail_out = out.size();
0561 BOOST_ASSERT(zs.avail_out > 0);
0562 }
0563 if(impl.rd_remain > 0)
0564 {
0565 if(impl.rd_buf.size() > 0)
0566 {
0567
0568 auto const in = buffers_prefix(
0569 clamp(impl.rd_remain), buffers_front(
0570 impl.rd_buf.data()));
0571 zs.avail_in = in.size();
0572 zs.next_in = in.data();
0573 }
0574 else
0575 {
0576 break;
0577 }
0578 impl.inflate(zs, ec);
0579 if(impl.check_stop_now(ec))
0580 goto upcall;
0581 impl.rd_remain -= zs.total_in;
0582 impl.rd_buf.consume(zs.total_in);
0583 }
0584 else if(impl.rd_fh.fin)
0585 {
0586 impl.inflate_with_eb(zs, ec);
0587 if(impl.check_stop_now(ec))
0588 goto upcall;
0589 if(zs.total_out == 0)
0590 {
0591 impl.do_context_takeover_read(impl.role);
0592 impl.rd_done = true;
0593 break;
0594 }
0595 }
0596 else
0597 {
0598 break;
0599 }
0600 if(impl.rd_msg_max && beast::detail::sum_exceeds(
0601 impl.rd_size, zs.total_out, impl.rd_msg_max))
0602 {
0603
0604 code_ = close_code::too_big;
0605 result_ = error::message_too_big;
0606 goto close;
0607 }
0608 cb_.consume(zs.total_out);
0609 impl.rd_size += zs.total_out;
0610 bytes_written_ += zs.total_out;
0611 }
0612 if(impl.rd_op == detail::opcode::text)
0613 {
0614
0615 if(! impl.rd_utf8.write(
0616 buffers_prefix(bytes_written_, bs_)) || (
0617 impl.rd_done && ! impl.rd_utf8.finish()))
0618 {
0619
0620 code_ = close_code::bad_payload;
0621 result_ = error::bad_frame_payload;
0622 goto close;
0623 }
0624 }
0625 }
0626 goto upcall;
0627
0628 close:
0629
0630 if(! impl.wr_block.try_lock(this))
0631 {
0632 BOOST_ASIO_CORO_YIELD
0633 {
0634 BOOST_ASIO_HANDLER_LOCATION((
0635 __FILE__, __LINE__,
0636 "websocket::async_read_some"));
0637
0638 impl.op_rd.emplace(std::move(*this));
0639 }
0640 if (ec)
0641 return this->complete(cont, ec, bytes_written_);
0642
0643 impl.wr_block.lock(this);
0644 BOOST_ASIO_CORO_YIELD
0645 {
0646 BOOST_ASIO_HANDLER_LOCATION((
0647 __FILE__, __LINE__,
0648 "websocket::async_read_some"));
0649
0650 const auto ex = this->get_immediate_executor();
0651 net::dispatch(ex, std::move(*this));
0652 }
0653 BOOST_ASSERT(impl.wr_block.is_locked(this));
0654 if(impl.check_stop_now(ec))
0655 goto upcall;
0656 }
0657
0658 impl.change_status(status::closing);
0659 impl.update_timer(this->get_executor());
0660
0661 if(! impl.wr_close)
0662 {
0663 impl.wr_close = true;
0664
0665
0666 impl.rd_fb.clear();
0667 impl.template write_close<
0668 flat_static_buffer_base>(
0669 impl.rd_fb, code_);
0670
0671
0672 BOOST_ASSERT(impl.wr_block.is_locked(this));
0673 BOOST_ASIO_CORO_YIELD
0674 {
0675 BOOST_ASIO_HANDLER_LOCATION((
0676 __FILE__, __LINE__,
0677 "websocket::async_read_some"));
0678
0679 net::async_write(impl.stream(), net::const_buffer(impl.rd_fb.data()),
0680 beast::detail::bind_continuation(std::move(*this)));
0681 }
0682 BOOST_ASSERT(impl.wr_block.is_locked(this));
0683 if(impl.check_stop_now(ec))
0684 goto upcall;
0685 }
0686
0687
0688 using beast::websocket::async_teardown;
0689 BOOST_ASSERT(impl.wr_block.is_locked(this));
0690 BOOST_ASIO_CORO_YIELD
0691 {
0692 BOOST_ASIO_HANDLER_LOCATION((
0693 __FILE__, __LINE__,
0694 "websocket::async_read_some"));
0695
0696 async_teardown(impl.role, impl.stream(),
0697 beast::detail::bind_continuation(std::move(*this)));
0698 }
0699 BOOST_ASSERT(impl.wr_block.is_locked(this));
0700 if(ec == net::error::eof)
0701 {
0702
0703
0704 ec = {};
0705 }
0706 if(! ec)
0707 {
0708 BOOST_BEAST_ASSIGN_EC(ec, result_);
0709 }
0710 if(ec && ec != error::closed)
0711 impl.change_status(status::failed);
0712 else
0713 impl.change_status(status::closed);
0714 impl.close();
0715
0716 upcall:
0717 impl.rd_block.try_unlock(this);
0718 impl.op_r_close.maybe_invoke();
0719 if(impl.wr_block.try_unlock(this))
0720 impl.op_close.maybe_invoke()
0721 || impl.op_idle_ping.maybe_invoke()
0722 || impl.op_ping.maybe_invoke()
0723 || impl.op_wr.maybe_invoke();
0724 this->complete(cont, ec, bytes_written_);
0725 }
0726 }
0727 };
0728
0729
0730
0731 template<class NextLayer, bool deflateSupported>
0732 template<class Handler, class DynamicBuffer>
0733 class stream<NextLayer, deflateSupported>::read_op
0734 : public beast::async_base<
0735 Handler, beast::executor_type<stream>>
0736 , public asio::coroutine
0737 {
0738 boost::weak_ptr<impl_type> wp_;
0739 DynamicBuffer& b_;
0740 std::size_t limit_;
0741 std::size_t bytes_written_ = 0;
0742 bool some_;
0743
0744 public:
0745 template<class Handler_>
0746 read_op(
0747 Handler_&& h,
0748 boost::shared_ptr<impl_type> const& sp,
0749 DynamicBuffer& b,
0750 std::size_t limit,
0751 bool some)
0752 : async_base<Handler,
0753 beast::executor_type<stream>>(
0754 std::forward<Handler_>(h),
0755 sp->stream().get_executor())
0756 , wp_(sp)
0757 , b_(b)
0758 , limit_(limit ? limit : (
0759 std::numeric_limits<std::size_t>::max)())
0760 , some_(some)
0761 {
0762 (*this)({}, 0, false);
0763 }
0764
0765 void operator()(
0766 error_code ec = {},
0767 std::size_t bytes_transferred = 0,
0768 bool cont = true)
0769 {
0770 using beast::detail::clamp;
0771 auto sp = wp_.lock();
0772 if(! sp)
0773 {
0774 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0775 bytes_written_ = 0;
0776 return this->complete(cont, ec, bytes_written_);
0777 }
0778 auto& impl = *sp;
0779 using mutable_buffers_type = typename
0780 DynamicBuffer::mutable_buffers_type;
0781 BOOST_ASIO_CORO_REENTER(*this)
0782 {
0783 do
0784 {
0785
0786 BOOST_ASIO_CORO_YIELD
0787 {
0788 auto mb = beast::detail::dynamic_buffer_prepare(b_,
0789 clamp(impl.read_size_hint_db(b_), limit_),
0790 ec, error::buffer_overflow);
0791 if(impl.check_stop_now(ec))
0792 goto upcall;
0793
0794 BOOST_ASIO_HANDLER_LOCATION((
0795 __FILE__, __LINE__,
0796 "websocket::async_read"));
0797
0798 read_some_op<read_op, mutable_buffers_type>(
0799 std::move(*this), sp, *mb);
0800 }
0801
0802 b_.commit(bytes_transferred);
0803 bytes_written_ += bytes_transferred;
0804 if(ec)
0805 goto upcall;
0806 }
0807 while(! some_ && ! impl.rd_done);
0808
0809 upcall:
0810 this->complete(cont, ec, bytes_written_);
0811 }
0812 }
0813 };
0814
0815 template<class NextLayer, bool deflateSupported>
0816 struct stream<NextLayer, deflateSupported>::
0817 run_read_some_op
0818 {
0819 boost::shared_ptr<impl_type> const& self;
0820
0821 using executor_type = typename stream::executor_type;
0822
0823 executor_type
0824 get_executor() const noexcept
0825 {
0826 return self->stream().get_executor();
0827 }
0828
0829 template<
0830 class ReadHandler,
0831 class MutableBufferSequence>
0832 void
0833 operator()(
0834 ReadHandler&& h,
0835 MutableBufferSequence const& b)
0836 {
0837
0838
0839
0840
0841 static_assert(
0842 beast::detail::is_invocable<ReadHandler,
0843 void(error_code, std::size_t)>::value,
0844 "ReadHandler type requirements not met");
0845
0846 read_some_op<
0847 typename std::decay<ReadHandler>::type,
0848 MutableBufferSequence>(
0849 std::forward<ReadHandler>(h),
0850 self,
0851 b);
0852 }
0853 };
0854
0855 template<class NextLayer, bool deflateSupported>
0856 struct stream<NextLayer, deflateSupported>::
0857 run_read_op
0858 {
0859 boost::shared_ptr<impl_type> const& self;
0860
0861 using executor_type = typename stream::executor_type;
0862
0863 executor_type
0864 get_executor() const noexcept
0865 {
0866 return self->stream().get_executor();
0867 }
0868
0869 template<
0870 class ReadHandler,
0871 class DynamicBuffer>
0872 void
0873 operator()(
0874 ReadHandler&& h,
0875 DynamicBuffer* b,
0876 std::size_t limit,
0877 bool some)
0878 {
0879
0880
0881
0882
0883 static_assert(
0884 beast::detail::is_invocable<ReadHandler,
0885 void(error_code, std::size_t)>::value,
0886 "ReadHandler type requirements not met");
0887
0888 read_op<
0889 typename std::decay<ReadHandler>::type,
0890 DynamicBuffer>(
0891 std::forward<ReadHandler>(h),
0892 self,
0893 *b,
0894 limit,
0895 some);
0896 }
0897 };
0898
0899
0900
0901 template<class NextLayer, bool deflateSupported>
0902 template<class DynamicBuffer>
0903 std::size_t
0904 stream<NextLayer, deflateSupported>::
0905 read(DynamicBuffer& buffer)
0906 {
0907 static_assert(is_sync_stream<next_layer_type>::value,
0908 "SyncStream type requirements not met");
0909 static_assert(
0910 net::is_dynamic_buffer<DynamicBuffer>::value,
0911 "DynamicBuffer type requirements not met");
0912 error_code ec;
0913 auto const bytes_written = read(buffer, ec);
0914 if(ec)
0915 BOOST_THROW_EXCEPTION(system_error{ec});
0916 return bytes_written;
0917 }
0918
0919 template<class NextLayer, bool deflateSupported>
0920 template<class DynamicBuffer>
0921 std::size_t
0922 stream<NextLayer, deflateSupported>::
0923 read(DynamicBuffer& buffer, error_code& ec)
0924 {
0925 static_assert(is_sync_stream<next_layer_type>::value,
0926 "SyncStream type requirements not met");
0927 static_assert(
0928 net::is_dynamic_buffer<DynamicBuffer>::value,
0929 "DynamicBuffer type requirements not met");
0930 std::size_t bytes_written = 0;
0931 do
0932 {
0933 bytes_written += read_some(buffer, 0, ec);
0934 if(ec)
0935 return bytes_written;
0936 }
0937 while(! is_message_done());
0938 return bytes_written;
0939 }
0940
0941 template<class NextLayer, bool deflateSupported>
0942 template<class DynamicBuffer, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0943 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0944 stream<NextLayer, deflateSupported>::
0945 async_read(DynamicBuffer& buffer, ReadHandler&& handler)
0946 {
0947 static_assert(is_async_stream<next_layer_type>::value,
0948 "AsyncStream type requirements not met");
0949 static_assert(
0950 net::is_dynamic_buffer<DynamicBuffer>::value,
0951 "DynamicBuffer type requirements not met");
0952 return net::async_initiate<
0953 ReadHandler,
0954 void(error_code, std::size_t)>(
0955 run_read_op{impl_},
0956 handler,
0957 &buffer,
0958 0,
0959 false);
0960 }
0961
0962
0963
0964 template<class NextLayer, bool deflateSupported>
0965 template<class DynamicBuffer>
0966 std::size_t
0967 stream<NextLayer, deflateSupported>::
0968 read_some(
0969 DynamicBuffer& buffer,
0970 std::size_t limit)
0971 {
0972 static_assert(is_sync_stream<next_layer_type>::value,
0973 "SyncStream type requirements not met");
0974 static_assert(
0975 net::is_dynamic_buffer<DynamicBuffer>::value,
0976 "DynamicBuffer type requirements not met");
0977 error_code ec;
0978 auto const bytes_written =
0979 read_some(buffer, limit, ec);
0980 if(ec)
0981 BOOST_THROW_EXCEPTION(system_error{ec});
0982 return bytes_written;
0983 }
0984
0985 template<class NextLayer, bool deflateSupported>
0986 template<class DynamicBuffer>
0987 std::size_t
0988 stream<NextLayer, deflateSupported>::
0989 read_some(
0990 DynamicBuffer& buffer,
0991 std::size_t limit,
0992 error_code& ec)
0993 {
0994 static_assert(is_sync_stream<next_layer_type>::value,
0995 "SyncStream type requirements not met");
0996 static_assert(
0997 net::is_dynamic_buffer<DynamicBuffer>::value,
0998 "DynamicBuffer type requirements not met");
0999 using beast::detail::clamp;
1000 if(! limit)
1001 limit = (std::numeric_limits<std::size_t>::max)();
1002 auto const size =
1003 clamp(impl_->read_size_hint_db(buffer), limit);
1004 BOOST_ASSERT(size > 0);
1005 auto mb = beast::detail::dynamic_buffer_prepare(
1006 buffer, size, ec, error::buffer_overflow);
1007 if(impl_->check_stop_now(ec))
1008 return 0;
1009 auto const bytes_written = read_some(*mb, ec);
1010 buffer.commit(bytes_written);
1011 return bytes_written;
1012 }
1013
1014 template<class NextLayer, bool deflateSupported>
1015 template<class DynamicBuffer, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
1016 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
1017 stream<NextLayer, deflateSupported>::
1018 async_read_some(
1019 DynamicBuffer& buffer,
1020 std::size_t limit,
1021 ReadHandler&& handler)
1022 {
1023 static_assert(is_async_stream<next_layer_type>::value,
1024 "AsyncStream type requirements not met");
1025 static_assert(
1026 net::is_dynamic_buffer<DynamicBuffer>::value,
1027 "DynamicBuffer type requirements not met");
1028 return net::async_initiate<
1029 ReadHandler,
1030 void(error_code, std::size_t)>(
1031 run_read_op{impl_},
1032 handler,
1033 &buffer,
1034 limit,
1035 true);
1036 }
1037
1038
1039
1040 template<class NextLayer, bool deflateSupported>
1041 template<class MutableBufferSequence>
1042 std::size_t
1043 stream<NextLayer, deflateSupported>::
1044 read_some(
1045 MutableBufferSequence const& buffers)
1046 {
1047 static_assert(is_sync_stream<next_layer_type>::value,
1048 "SyncStream type requirements not met");
1049 static_assert(net::is_mutable_buffer_sequence<
1050 MutableBufferSequence>::value,
1051 "MutableBufferSequence type requirements not met");
1052 error_code ec;
1053 auto const bytes_written = read_some(buffers, ec);
1054 if(ec)
1055 BOOST_THROW_EXCEPTION(system_error{ec});
1056 return bytes_written;
1057 }
1058
1059 template<class NextLayer, bool deflateSupported>
1060 template<class MutableBufferSequence>
1061 std::size_t
1062 stream<NextLayer, deflateSupported>::
1063 read_some(
1064 MutableBufferSequence const& buffers,
1065 error_code& ec)
1066 {
1067 static_assert(is_sync_stream<next_layer_type>::value,
1068 "SyncStream type requirements not met");
1069 static_assert(net::is_mutable_buffer_sequence<
1070 MutableBufferSequence>::value,
1071 "MutableBufferSequence type requirements not met");
1072 using beast::detail::clamp;
1073 auto& impl = *impl_;
1074 close_code code{};
1075 std::size_t bytes_written = 0;
1076 ec = {};
1077
1078 if(impl.check_stop_now(ec))
1079 return bytes_written;
1080 loop:
1081
1082
1083
1084
1085 if(impl.rd_remain == 0 && (
1086 ! impl.rd_fh.fin || impl.rd_done))
1087 {
1088
1089 error_code result;
1090 while(! impl.parse_fh(impl.rd_fh, impl.rd_buf, result))
1091 {
1092 if(result)
1093 {
1094
1095 if(result == error::message_too_big)
1096 code = close_code::too_big;
1097 else
1098 code = close_code::protocol_error;
1099 do_fail(code, result, ec);
1100 return bytes_written;
1101 }
1102 auto const bytes_transferred =
1103 impl.stream().read_some(
1104 impl.rd_buf.prepare(read_size(
1105 impl.rd_buf, impl.rd_buf.max_size())),
1106 ec);
1107 impl.rd_buf.commit(bytes_transferred);
1108 if(impl.check_stop_now(ec))
1109 return bytes_written;
1110 }
1111
1112
1113 if(impl.rd_fh.len > 0 && impl.rd_fh.mask)
1114 detail::mask_inplace(buffers_prefix(
1115 clamp(impl.rd_fh.len), impl.rd_buf.data()),
1116 impl.rd_key);
1117 if(detail::is_control(impl.rd_fh.op))
1118 {
1119
1120 auto const b = buffers_prefix(
1121 clamp(impl.rd_fh.len), impl.rd_buf.data());
1122 auto const len = buffer_bytes(b);
1123 BOOST_ASSERT(len == impl.rd_fh.len);
1124
1125
1126
1127 impl.rd_fh.fin = false;
1128
1129
1130 if(impl.rd_fh.op == detail::opcode::ping)
1131 {
1132 ping_data payload;
1133 detail::read_ping(payload, b);
1134 impl.rd_buf.consume(len);
1135 if(impl.wr_close)
1136 {
1137
1138 goto loop;
1139 }
1140 if(impl.ctrl_cb)
1141 impl.ctrl_cb(frame_type::ping, to_string_view(payload));
1142 detail::frame_buffer fb;
1143 impl.template write_ping<flat_static_buffer_base>(fb,
1144 detail::opcode::pong, payload);
1145 net::write(impl.stream(), fb.data(), ec);
1146 if(impl.check_stop_now(ec))
1147 return bytes_written;
1148 goto loop;
1149 }
1150
1151 if(impl.rd_fh.op == detail::opcode::pong)
1152 {
1153 ping_data payload;
1154 detail::read_ping(payload, b);
1155 impl.rd_buf.consume(len);
1156 if(impl.ctrl_cb)
1157 impl.ctrl_cb(frame_type::pong, to_string_view(payload));
1158 goto loop;
1159 }
1160
1161 BOOST_ASSERT(impl.rd_fh.op == detail::opcode::close);
1162 {
1163 BOOST_ASSERT(! impl.rd_close);
1164 impl.rd_close = true;
1165 close_reason cr;
1166 detail::read_close(cr, b, result);
1167 if(result)
1168 {
1169
1170 do_fail(close_code::protocol_error,
1171 result, ec);
1172 return bytes_written;
1173 }
1174 impl.cr = cr;
1175 impl.rd_buf.consume(len);
1176 if(impl.ctrl_cb)
1177 impl.ctrl_cb(frame_type::close, to_string_view(impl.cr.reason));
1178 BOOST_ASSERT(! impl.wr_close);
1179
1180 do_fail(
1181 cr.code == close_code::none ?
1182 close_code::normal :
1183 static_cast<close_code>(cr.code),
1184 error::closed, ec);
1185 return bytes_written;
1186 }
1187 }
1188 if(impl.rd_fh.len == 0 && ! impl.rd_fh.fin)
1189 {
1190
1191 goto loop;
1192 }
1193 impl.rd_done = false;
1194 }
1195 else
1196 {
1197 ec = {};
1198 }
1199 if(! impl.rd_deflated())
1200 {
1201 if(impl.rd_remain > 0)
1202 {
1203 if(impl.rd_buf.size() == 0 && impl.rd_buf.max_size() >
1204 (std::min)(clamp(impl.rd_remain),
1205 buffer_bytes(buffers)))
1206 {
1207
1208
1209 impl.rd_buf.commit(impl.stream().read_some(
1210 impl.rd_buf.prepare(read_size(impl.rd_buf,
1211 impl.rd_buf.max_size())), ec));
1212 if(impl.check_stop_now(ec))
1213 return bytes_written;
1214 if(impl.rd_fh.mask)
1215 detail::mask_inplace(
1216 buffers_prefix(clamp(impl.rd_remain),
1217 impl.rd_buf.data()), impl.rd_key);
1218 }
1219 if(impl.rd_buf.size() > 0)
1220 {
1221
1222
1223 auto const bytes_transferred = net::buffer_copy(
1224 buffers, impl.rd_buf.data(),
1225 clamp(impl.rd_remain));
1226 auto const mb = buffers_prefix(
1227 bytes_transferred, buffers);
1228 impl.rd_remain -= bytes_transferred;
1229 if(impl.rd_op == detail::opcode::text)
1230 {
1231 if(! impl.rd_utf8.write(mb) ||
1232 (impl.rd_remain == 0 && impl.rd_fh.fin &&
1233 ! impl.rd_utf8.finish()))
1234 {
1235
1236 do_fail(close_code::bad_payload,
1237 error::bad_frame_payload, ec);
1238 return bytes_written;
1239 }
1240 }
1241 bytes_written += bytes_transferred;
1242 impl.rd_size += bytes_transferred;
1243 impl.rd_buf.consume(bytes_transferred);
1244 }
1245 else
1246 {
1247
1248 BOOST_ASSERT(impl.rd_remain > 0);
1249 BOOST_ASSERT(buffer_bytes(buffers) > 0);
1250 BOOST_ASSERT(buffer_bytes(buffers_prefix(
1251 clamp(impl.rd_remain), buffers)) > 0);
1252 auto const bytes_transferred =
1253 impl.stream().read_some(buffers_prefix(
1254 clamp(impl.rd_remain), buffers), ec);
1255
1256 if(impl.check_stop_now(ec))
1257 return bytes_written;
1258 BOOST_ASSERT(bytes_transferred > 0);
1259 auto const mb = buffers_prefix(
1260 bytes_transferred, buffers);
1261 impl.rd_remain -= bytes_transferred;
1262 if(impl.rd_fh.mask)
1263 detail::mask_inplace(mb, impl.rd_key);
1264 if(impl.rd_op == detail::opcode::text)
1265 {
1266 if(! impl.rd_utf8.write(mb) ||
1267 (impl.rd_remain == 0 && impl.rd_fh.fin &&
1268 ! impl.rd_utf8.finish()))
1269 {
1270
1271 do_fail(close_code::bad_payload,
1272 error::bad_frame_payload, ec);
1273 return bytes_written;
1274 }
1275 }
1276 bytes_written += bytes_transferred;
1277 impl.rd_size += bytes_transferred;
1278 }
1279 }
1280 BOOST_ASSERT( ! impl.rd_done );
1281 if( impl.rd_remain == 0 && impl.rd_fh.fin )
1282 impl.rd_done = true;
1283 }
1284 else
1285 {
1286
1287
1288
1289
1290 bool did_read = false;
1291 buffers_suffix<MutableBufferSequence> cb(buffers);
1292 while(buffer_bytes(cb) > 0)
1293 {
1294 zlib::z_params zs;
1295 {
1296 auto const out = beast::buffers_front(cb);
1297 zs.next_out = out.data();
1298 zs.avail_out = out.size();
1299 BOOST_ASSERT(zs.avail_out > 0);
1300 }
1301 if(impl.rd_remain > 0)
1302 {
1303 if(impl.rd_buf.size() > 0)
1304 {
1305
1306 auto const in = buffers_prefix(
1307 clamp(impl.rd_remain), beast::buffers_front(
1308 impl.rd_buf.data()));
1309 zs.avail_in = in.size();
1310 zs.next_in = in.data();
1311 }
1312 else if(! did_read)
1313 {
1314
1315 auto const bytes_transferred =
1316 impl.stream().read_some(
1317 impl.rd_buf.prepare(read_size(
1318 impl.rd_buf, impl.rd_buf.max_size())),
1319 ec);
1320 if(impl.check_stop_now(ec))
1321 return bytes_written;
1322 BOOST_ASSERT(bytes_transferred > 0);
1323 impl.rd_buf.commit(bytes_transferred);
1324 if(impl.rd_fh.mask)
1325 detail::mask_inplace(
1326 buffers_prefix(clamp(impl.rd_remain),
1327 impl.rd_buf.data()), impl.rd_key);
1328 auto const in = buffers_prefix(
1329 clamp(impl.rd_remain), buffers_front(
1330 impl.rd_buf.data()));
1331 zs.avail_in = in.size();
1332 zs.next_in = in.data();
1333 did_read = true;
1334 }
1335 else
1336 {
1337 break;
1338 }
1339 impl.inflate(zs, ec);
1340 if(impl.check_stop_now(ec))
1341 return bytes_written;
1342 impl.rd_remain -= zs.total_in;
1343 impl.rd_buf.consume(zs.total_in);
1344 }
1345 else if(impl.rd_fh.fin)
1346 {
1347 impl.inflate_with_eb(zs, ec);
1348 if(impl.check_stop_now(ec))
1349 return bytes_written;
1350 if(zs.total_out == 0)
1351 {
1352 impl.do_context_takeover_read(impl.role);
1353 impl.rd_done = true;
1354 break;
1355 }
1356 }
1357 else
1358 {
1359 break;
1360 }
1361 if(impl.rd_msg_max && beast::detail::sum_exceeds(
1362 impl.rd_size, zs.total_out, impl.rd_msg_max))
1363 {
1364 do_fail(close_code::too_big,
1365 error::message_too_big, ec);
1366 return bytes_written;
1367 }
1368 cb.consume(zs.total_out);
1369 impl.rd_size += zs.total_out;
1370 bytes_written += zs.total_out;
1371 }
1372 if(impl.rd_op == detail::opcode::text)
1373 {
1374
1375 if(! impl.rd_utf8.write(beast::buffers_prefix(
1376 bytes_written, buffers)) || (
1377 impl.rd_done && ! impl.rd_utf8.finish()))
1378 {
1379
1380 do_fail(close_code::bad_payload,
1381 error::bad_frame_payload, ec);
1382 return bytes_written;
1383 }
1384 }
1385 }
1386 return bytes_written;
1387 }
1388
1389 template<class NextLayer, bool deflateSupported>
1390 template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
1391 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
1392 stream<NextLayer, deflateSupported>::
1393 async_read_some(
1394 MutableBufferSequence const& buffers,
1395 ReadHandler&& handler)
1396 {
1397 static_assert(is_async_stream<next_layer_type>::value,
1398 "AsyncStream type requirements not met");
1399 static_assert(net::is_mutable_buffer_sequence<
1400 MutableBufferSequence>::value,
1401 "MutableBufferSequence type requirements not met");
1402 return net::async_initiate<
1403 ReadHandler,
1404 void(error_code, std::size_t)>(
1405 run_read_some_op{impl_},
1406 handler,
1407 buffers);
1408 }
1409
1410 }
1411 }
1412 }
1413
1414 #endif