File indexing completed on 2025-07-05 08:28:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
0012
0013 #include <boost/beast/websocket/detail/mask.hpp>
0014 #include <boost/beast/core/async_base.hpp>
0015 #include <boost/beast/core/buffer_traits.hpp>
0016 #include <boost/beast/core/buffers_cat.hpp>
0017 #include <boost/beast/core/buffers_prefix.hpp>
0018 #include <boost/beast/core/buffers_range.hpp>
0019 #include <boost/beast/core/buffers_suffix.hpp>
0020 #include <boost/beast/core/flat_static_buffer.hpp>
0021 #include <boost/beast/core/stream_traits.hpp>
0022 #include <boost/beast/core/detail/bind_continuation.hpp>
0023 #include <boost/beast/core/detail/clamp.hpp>
0024 #include <boost/beast/core/detail/config.hpp>
0025 #include <boost/beast/websocket/detail/frame.hpp>
0026 #include <boost/beast/websocket/impl/stream_impl.hpp>
0027 #include <boost/asio/coroutine.hpp>
0028 #include <boost/assert.hpp>
0029 #include <boost/config.hpp>
0030 #include <boost/throw_exception.hpp>
0031 #include <algorithm>
0032 #include <memory>
0033
0034 namespace boost {
0035 namespace beast {
0036 namespace websocket {
0037
0038 template<class NextLayer, bool deflateSupported>
0039 template<class Handler, class Buffers>
0040 class stream<NextLayer, deflateSupported>::write_some_op
0041 : public beast::async_base<
0042 Handler, beast::executor_type<stream>>
0043 , public asio::coroutine
0044 {
0045 enum
0046 {
0047 do_nomask_nofrag,
0048 do_nomask_frag,
0049 do_mask_nofrag,
0050 do_mask_frag,
0051 do_deflate
0052 };
0053
0054 boost::weak_ptr<impl_type> wp_;
0055 buffers_suffix<Buffers> cb_;
0056 detail::frame_header fh_;
0057 detail::prepared_key key_;
0058 std::size_t bytes_transferred_ = 0;
0059 std::size_t remain_;
0060 std::size_t in_;
0061 int how_;
0062 bool fin_;
0063 bool more_ = false;
0064 bool cont_ = false;
0065
0066 public:
0067 static constexpr int id = 2;
0068
0069 template<class Handler_>
0070 write_some_op(
0071 Handler_&& h,
0072 boost::shared_ptr<impl_type> const& sp,
0073 bool fin,
0074 Buffers const& bs)
0075 : beast::async_base<Handler,
0076 beast::executor_type<stream>>(
0077 std::forward<Handler_>(h),
0078 sp->stream().get_executor())
0079 , wp_(sp)
0080 , cb_(bs)
0081 , fin_(fin)
0082 {
0083 auto& impl = *sp;
0084
0085
0086 if(! impl.wr_cont)
0087 {
0088 impl.begin_msg(beast::buffer_bytes(bs));
0089 fh_.rsv1 = impl.wr_compress;
0090 }
0091 else
0092 {
0093 fh_.rsv1 = false;
0094 }
0095 fh_.rsv2 = false;
0096 fh_.rsv3 = false;
0097 fh_.op = impl.wr_cont ?
0098 detail::opcode::cont : impl.wr_opcode;
0099 fh_.mask =
0100 impl.role == role_type::client;
0101
0102
0103 if(impl.wr_compress)
0104 {
0105 how_ = do_deflate;
0106 }
0107 else if(! fh_.mask)
0108 {
0109 if(! impl.wr_frag)
0110 {
0111 how_ = do_nomask_nofrag;
0112 }
0113 else
0114 {
0115 BOOST_ASSERT(impl.wr_buf_size != 0);
0116 remain_ = beast::buffer_bytes(cb_);
0117 if(remain_ > impl.wr_buf_size)
0118 how_ = do_nomask_frag;
0119 else
0120 how_ = do_nomask_nofrag;
0121 }
0122 }
0123 else
0124 {
0125 if(! impl.wr_frag)
0126 {
0127 how_ = do_mask_nofrag;
0128 }
0129 else
0130 {
0131 BOOST_ASSERT(impl.wr_buf_size != 0);
0132 remain_ = beast::buffer_bytes(cb_);
0133 if(remain_ > impl.wr_buf_size)
0134 how_ = do_mask_frag;
0135 else
0136 how_ = do_mask_nofrag;
0137 }
0138 }
0139 (*this)({}, 0, false);
0140 }
0141
0142 void operator()(
0143 error_code ec = {},
0144 std::size_t bytes_transferred = 0,
0145 bool cont = true);
0146 };
0147
0148 template<class NextLayer, bool deflateSupported>
0149 template<class Handler, class Buffers>
0150 void
0151 stream<NextLayer, deflateSupported>::
0152 write_some_op<Handler, Buffers>::
0153 operator()(
0154 error_code ec,
0155 std::size_t bytes_transferred,
0156 bool cont)
0157 {
0158 using beast::detail::clamp;
0159 std::size_t n;
0160 net::mutable_buffer b;
0161 auto sp = wp_.lock();
0162 if(! sp)
0163 {
0164 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0165 bytes_transferred_ = 0;
0166 return this->complete(cont, ec, bytes_transferred_);
0167 }
0168 auto& impl = *sp;
0169 BOOST_ASIO_CORO_REENTER(*this)
0170 {
0171
0172 if(! impl.wr_block.try_lock(this))
0173 {
0174 do_suspend:
0175 BOOST_ASIO_CORO_YIELD
0176 {
0177 BOOST_ASIO_HANDLER_LOCATION((
0178 __FILE__, __LINE__,
0179 fin_ ?
0180 "websocket::async_write" :
0181 "websocket::async_write_some"
0182 ));
0183 this->set_allowed_cancellation(net::cancellation_type::all);
0184 impl.op_wr.emplace(std::move(*this),
0185 net::cancellation_type::all);
0186 }
0187 if (ec)
0188 return this->complete(cont, ec, bytes_transferred_);
0189
0190 this->set_allowed_cancellation(net::cancellation_type::terminal);
0191 impl.wr_block.lock(this);
0192 BOOST_ASIO_CORO_YIELD
0193 {
0194 BOOST_ASIO_HANDLER_LOCATION((
0195 __FILE__, __LINE__,
0196 fin_ ?
0197 "websocket::async_write" :
0198 "websocket::async_write_some"
0199 ));
0200
0201 const auto ex = this->get_immediate_executor();
0202 net::dispatch(ex, std::move(*this));
0203 }
0204 BOOST_ASSERT(impl.wr_block.is_locked(this));
0205 }
0206 if(impl.check_stop_now(ec))
0207 goto upcall;
0208
0209
0210
0211 if(how_ == do_nomask_nofrag)
0212 {
0213
0214 fh_.fin = fin_;
0215 fh_.len = beast::buffer_bytes(cb_);
0216 impl.wr_fb.clear();
0217 detail::write<flat_static_buffer_base>(
0218 impl.wr_fb, fh_);
0219 impl.wr_cont = ! fin_;
0220 BOOST_ASIO_CORO_YIELD
0221 {
0222 BOOST_ASIO_HANDLER_LOCATION((
0223 __FILE__, __LINE__,
0224 fin_ ?
0225 "websocket::async_write" :
0226 "websocket::async_write_some"
0227 ));
0228
0229 net::async_write(impl.stream(),
0230 buffers_cat(
0231 net::const_buffer(impl.wr_fb.data()),
0232 net::const_buffer(0, 0),
0233 cb_,
0234 buffers_prefix(0, cb_)
0235 ),
0236 beast::detail::bind_continuation(std::move(*this)));
0237 }
0238 bytes_transferred_ += clamp(fh_.len);
0239 if(impl.check_stop_now(ec))
0240 goto upcall;
0241 goto upcall;
0242 }
0243
0244
0245
0246 if(how_ == do_nomask_frag)
0247 {
0248
0249 for(;;)
0250 {
0251 n = clamp(remain_, impl.wr_buf_size);
0252 fh_.len = n;
0253 remain_ -= n;
0254 fh_.fin = fin_ ? remain_ == 0 : false;
0255 impl.wr_fb.clear();
0256 detail::write<flat_static_buffer_base>(
0257 impl.wr_fb, fh_);
0258 impl.wr_cont = ! fin_;
0259
0260 BOOST_ASIO_CORO_YIELD
0261 {
0262 BOOST_ASIO_HANDLER_LOCATION((
0263 __FILE__, __LINE__,
0264 fin_ ?
0265 "websocket::async_write" :
0266 "websocket::async_write_some"
0267 ));
0268
0269 buffers_suffix<Buffers> empty_cb(cb_);
0270 empty_cb.consume(~std::size_t(0));
0271
0272 net::async_write(impl.stream(),
0273 buffers_cat(
0274 net::const_buffer(impl.wr_fb.data()),
0275 net::const_buffer(0, 0),
0276 empty_cb,
0277 buffers_prefix(clamp(fh_.len), cb_)
0278 ),
0279 beast::detail::bind_continuation(std::move(*this)));
0280 }
0281 n = clamp(fh_.len);
0282 bytes_transferred_ += n;
0283 if(impl.check_stop_now(ec))
0284 goto upcall;
0285 if(remain_ == 0)
0286 break;
0287 cb_.consume(n);
0288 fh_.op = detail::opcode::cont;
0289
0290
0291
0292 impl.wr_block.unlock(this);
0293 if( impl.op_close.maybe_invoke()
0294 || impl.op_idle_ping.maybe_invoke()
0295 || impl.op_rd.maybe_invoke()
0296 || impl.op_ping.maybe_invoke())
0297 {
0298 BOOST_ASSERT(impl.wr_block.is_locked());
0299 goto do_suspend;
0300 }
0301 impl.wr_block.lock(this);
0302 }
0303 goto upcall;
0304 }
0305
0306
0307
0308 if(how_ == do_mask_nofrag)
0309 {
0310
0311 remain_ = beast::buffer_bytes(cb_);
0312 fh_.fin = fin_;
0313 fh_.len = remain_;
0314 fh_.key = impl.create_mask();
0315 detail::prepare_key(key_, fh_.key);
0316 impl.wr_fb.clear();
0317 detail::write<flat_static_buffer_base>(
0318 impl.wr_fb, fh_);
0319 n = clamp(remain_, impl.wr_buf_size);
0320 net::buffer_copy(net::buffer(
0321 impl.wr_buf.get(), n), cb_);
0322 detail::mask_inplace(net::buffer(
0323 impl.wr_buf.get(), n), key_);
0324 remain_ -= n;
0325 impl.wr_cont = ! fin_;
0326
0327 BOOST_ASIO_CORO_YIELD
0328 {
0329 BOOST_ASIO_HANDLER_LOCATION((
0330 __FILE__, __LINE__,
0331 fin_ ?
0332 "websocket::async_write" :
0333 "websocket::async_write_some"
0334 ));
0335
0336 buffers_suffix<Buffers> empty_cb(cb_);
0337 empty_cb.consume(~std::size_t(0));
0338
0339 net::async_write(impl.stream(),
0340 buffers_cat(
0341 net::const_buffer(impl.wr_fb.data()),
0342 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0343 empty_cb,
0344 buffers_prefix(0, empty_cb)
0345 ),
0346 beast::detail::bind_continuation(std::move(*this)));
0347 }
0348
0349 if(bytes_transferred > impl.wr_fb.size())
0350 bytes_transferred_ += bytes_transferred - impl.wr_fb.size();
0351 if(impl.check_stop_now(ec))
0352 goto upcall;
0353 while(remain_ > 0)
0354 {
0355 cb_.consume(impl.wr_buf_size);
0356 n = clamp(remain_, impl.wr_buf_size);
0357 net::buffer_copy(net::buffer(
0358 impl.wr_buf.get(), n), cb_);
0359 detail::mask_inplace(net::buffer(
0360 impl.wr_buf.get(), n), key_);
0361 remain_ -= n;
0362
0363 BOOST_ASIO_CORO_YIELD
0364 {
0365 BOOST_ASIO_HANDLER_LOCATION((
0366 __FILE__, __LINE__,
0367 fin_ ?
0368 "websocket::async_write" :
0369 "websocket::async_write_some"
0370 ));
0371
0372 buffers_suffix<Buffers> empty_cb(cb_);
0373 empty_cb.consume(~std::size_t(0));
0374
0375 net::async_write(impl.stream(),
0376 buffers_cat(
0377 net::const_buffer(0, 0),
0378 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0379 empty_cb,
0380 buffers_prefix(0, empty_cb)
0381 ),
0382 beast::detail::bind_continuation(std::move(*this)));
0383 }
0384 bytes_transferred_ += bytes_transferred;
0385 if(impl.check_stop_now(ec))
0386 goto upcall;
0387 }
0388 goto upcall;
0389 }
0390
0391
0392
0393 if(how_ == do_mask_frag)
0394 {
0395
0396 for(;;)
0397 {
0398 n = clamp(remain_, impl.wr_buf_size);
0399 remain_ -= n;
0400 fh_.len = n;
0401 fh_.key = impl.create_mask();
0402 fh_.fin = fin_ ? remain_ == 0 : false;
0403 detail::prepare_key(key_, fh_.key);
0404 net::buffer_copy(net::buffer(
0405 impl.wr_buf.get(), n), cb_);
0406 detail::mask_inplace(net::buffer(
0407 impl.wr_buf.get(), n), key_);
0408 impl.wr_fb.clear();
0409 detail::write<flat_static_buffer_base>(
0410 impl.wr_fb, fh_);
0411 impl.wr_cont = ! fin_;
0412
0413 BOOST_ASIO_CORO_YIELD
0414 {
0415 BOOST_ASIO_HANDLER_LOCATION((
0416 __FILE__, __LINE__,
0417 fin_ ?
0418 "websocket::async_write" :
0419 "websocket::async_write_some"
0420 ));
0421
0422 buffers_suffix<Buffers> empty_cb(cb_);
0423 empty_cb.consume(~std::size_t(0));
0424
0425 net::async_write(impl.stream(),
0426 buffers_cat(
0427 net::const_buffer(impl.wr_fb.data()),
0428 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0429 empty_cb,
0430 buffers_prefix(0, empty_cb)
0431 ),
0432 beast::detail::bind_continuation(std::move(*this)));
0433 }
0434 if(bytes_transferred > impl.wr_fb.size())
0435 n = bytes_transferred - impl.wr_fb.size();
0436 else
0437 n = 0;
0438 bytes_transferred_ += n;
0439 if(impl.check_stop_now(ec))
0440 goto upcall;
0441 if(remain_ == 0)
0442 break;
0443 cb_.consume(n);
0444 fh_.op = detail::opcode::cont;
0445
0446
0447 impl.wr_block.unlock(this);
0448 if( impl.op_close.maybe_invoke()
0449 || impl.op_idle_ping.maybe_invoke()
0450 || impl.op_rd.maybe_invoke()
0451 || impl.op_ping.maybe_invoke())
0452 {
0453 BOOST_ASSERT(impl.wr_block.is_locked());
0454 goto do_suspend;
0455 }
0456 impl.wr_block.lock(this);
0457 }
0458 goto upcall;
0459 }
0460
0461
0462
0463 if(how_ == do_deflate)
0464 {
0465
0466 for(;;)
0467 {
0468 b = net::buffer(impl.wr_buf.get(),
0469 impl.wr_buf_size);
0470 more_ = impl.deflate(b, cb_, fin_, in_, ec);
0471 if(impl.check_stop_now(ec))
0472 goto upcall;
0473 n = beast::buffer_bytes(b);
0474 if(n == 0)
0475 {
0476
0477
0478 BOOST_ASSERT(! fin_);
0479 BOOST_ASSERT(beast::buffer_bytes(cb_) == 0);
0480 goto upcall;
0481 }
0482 if(fh_.mask)
0483 {
0484 fh_.key = impl.create_mask();
0485 detail::prepared_key key;
0486 detail::prepare_key(key, fh_.key);
0487 detail::mask_inplace(b, key);
0488 }
0489 fh_.fin = ! more_;
0490 fh_.len = n;
0491 impl.wr_fb.clear();
0492 detail::write<
0493 flat_static_buffer_base>(impl.wr_fb, fh_);
0494 impl.wr_cont = ! fin_;
0495
0496 BOOST_ASIO_CORO_YIELD
0497 {
0498 BOOST_ASIO_HANDLER_LOCATION((
0499 __FILE__, __LINE__,
0500 fin_ ?
0501 "websocket::async_write" :
0502 "websocket::async_write_some"
0503 ));
0504
0505 buffers_suffix<Buffers> empty_cb(cb_);
0506 empty_cb.consume(~std::size_t(0));
0507
0508 net::async_write(impl.stream(),
0509 buffers_cat(
0510 net::const_buffer(impl.wr_fb.data()),
0511 net::const_buffer(b),
0512 empty_cb,
0513 buffers_prefix(0, empty_cb)
0514 ),
0515 beast::detail::bind_continuation(std::move(*this)));
0516 }
0517 bytes_transferred_ += in_;
0518 if(impl.check_stop_now(ec))
0519 goto upcall;
0520 if(more_)
0521 {
0522 fh_.op = detail::opcode::cont;
0523 fh_.rsv1 = false;
0524
0525
0526 impl.wr_block.unlock(this);
0527 if( impl.op_close.maybe_invoke()
0528 || impl.op_idle_ping.maybe_invoke()
0529 || impl.op_rd.maybe_invoke()
0530 || impl.op_ping.maybe_invoke())
0531 {
0532 BOOST_ASSERT(impl.wr_block.is_locked());
0533 goto do_suspend;
0534 }
0535 impl.wr_block.lock(this);
0536 }
0537 else
0538 {
0539 if(fh_.fin)
0540 impl.do_context_takeover_write(impl.role);
0541 goto upcall;
0542 }
0543 }
0544 }
0545
0546
0547
0548 upcall:
0549 impl.wr_block.unlock(this);
0550 impl.op_close.maybe_invoke()
0551 || impl.op_idle_ping.maybe_invoke()
0552 || impl.op_rd.maybe_invoke()
0553 || impl.op_ping.maybe_invoke();
0554 this->complete(cont, ec, bytes_transferred_);
0555 }
0556 }
0557
0558 template<class NextLayer, bool deflateSupported>
0559 struct stream<NextLayer, deflateSupported>::
0560 run_write_some_op
0561 {
0562 boost::shared_ptr<impl_type> const& self;
0563
0564 using executor_type = typename stream::executor_type;
0565
0566 executor_type
0567 get_executor() const noexcept
0568 {
0569 return self->stream().get_executor();
0570 }
0571
0572 template<
0573 class WriteHandler,
0574 class ConstBufferSequence>
0575 void
0576 operator()(
0577 WriteHandler&& h,
0578 bool fin,
0579 ConstBufferSequence const& b)
0580 {
0581
0582
0583
0584
0585 static_assert(
0586 beast::detail::is_invocable<WriteHandler,
0587 void(error_code, std::size_t)>::value,
0588 "WriteHandler type requirements not met");
0589
0590 write_some_op<
0591 typename std::decay<WriteHandler>::type,
0592 ConstBufferSequence>(
0593 std::forward<WriteHandler>(h),
0594 self,
0595 fin,
0596 b);
0597 }
0598 };
0599
0600
0601
0602 template<class NextLayer, bool deflateSupported>
0603 template<class ConstBufferSequence>
0604 std::size_t
0605 stream<NextLayer, deflateSupported>::
0606 write_some(bool fin, ConstBufferSequence const& buffers)
0607 {
0608 static_assert(is_sync_stream<next_layer_type>::value,
0609 "SyncStream type requirements not met");
0610 static_assert(net::is_const_buffer_sequence<
0611 ConstBufferSequence>::value,
0612 "ConstBufferSequence type requirements not met");
0613 error_code ec;
0614 auto const bytes_transferred =
0615 write_some(fin, buffers, ec);
0616 if(ec)
0617 BOOST_THROW_EXCEPTION(system_error{ec});
0618 return bytes_transferred;
0619 }
0620
0621 template<class NextLayer, bool deflateSupported>
0622 template<class ConstBufferSequence>
0623 std::size_t
0624 stream<NextLayer, deflateSupported>::
0625 write_some(bool fin,
0626 ConstBufferSequence const& buffers, error_code& ec)
0627 {
0628 static_assert(is_sync_stream<next_layer_type>::value,
0629 "SyncStream type requirements not met");
0630 static_assert(net::is_const_buffer_sequence<
0631 ConstBufferSequence>::value,
0632 "ConstBufferSequence type requirements not met");
0633 using beast::detail::clamp;
0634 auto& impl = *impl_;
0635 std::size_t bytes_transferred = 0;
0636 ec = {};
0637 if(impl.check_stop_now(ec))
0638 return bytes_transferred;
0639 detail::frame_header fh;
0640 if(! impl.wr_cont)
0641 {
0642 impl.begin_msg(beast::buffer_bytes(buffers));
0643 fh.rsv1 = impl.wr_compress;
0644 }
0645 else
0646 {
0647 fh.rsv1 = false;
0648 }
0649 fh.rsv2 = false;
0650 fh.rsv3 = false;
0651 fh.op = impl.wr_cont ?
0652 detail::opcode::cont : impl.wr_opcode;
0653 fh.mask = impl.role == role_type::client;
0654 auto remain = beast::buffer_bytes(buffers);
0655 if(impl.wr_compress)
0656 {
0657
0658 buffers_suffix<
0659 ConstBufferSequence> cb(buffers);
0660 for(;;)
0661 {
0662 auto b = net::buffer(
0663 impl.wr_buf.get(), impl.wr_buf_size);
0664 auto const more = impl.deflate(
0665 b, cb, fin, bytes_transferred, ec);
0666 if(impl.check_stop_now(ec))
0667 return bytes_transferred;
0668 auto const n = beast::buffer_bytes(b);
0669 if(n == 0)
0670 {
0671
0672
0673
0674 BOOST_ASSERT(! fin);
0675 BOOST_ASSERT(beast::buffer_bytes(cb) == 0);
0676 fh.fin = false;
0677 break;
0678 }
0679 if(fh.mask)
0680 {
0681 fh.key = this->impl_->create_mask();
0682 detail::prepared_key key;
0683 detail::prepare_key(key, fh.key);
0684 detail::mask_inplace(b, key);
0685 }
0686 fh.fin = ! more;
0687 fh.len = n;
0688 detail::fh_buffer fh_buf;
0689 detail::write<
0690 flat_static_buffer_base>(fh_buf, fh);
0691 impl.wr_cont = ! fin;
0692 net::write(impl.stream(),
0693 buffers_cat(fh_buf.data(), b), ec);
0694 if(impl.check_stop_now(ec))
0695 return bytes_transferred;
0696 if(! more)
0697 break;
0698 fh.op = detail::opcode::cont;
0699 fh.rsv1 = false;
0700 }
0701 if(fh.fin)
0702 impl.do_context_takeover_write(impl.role);
0703 }
0704 else if(! fh.mask)
0705 {
0706 if(! impl.wr_frag)
0707 {
0708
0709 fh.fin = fin;
0710 fh.len = remain;
0711 detail::fh_buffer fh_buf;
0712 detail::write<
0713 flat_static_buffer_base>(fh_buf, fh);
0714 impl.wr_cont = ! fin;
0715 net::write(impl.stream(),
0716 buffers_cat(fh_buf.data(), buffers), ec);
0717 if(impl.check_stop_now(ec))
0718 return bytes_transferred;
0719 bytes_transferred += remain;
0720 }
0721 else
0722 {
0723
0724 BOOST_ASSERT(impl.wr_buf_size != 0);
0725 buffers_suffix<
0726 ConstBufferSequence> cb{buffers};
0727 for(;;)
0728 {
0729 auto const n = clamp(remain, impl.wr_buf_size);
0730 remain -= n;
0731 fh.len = n;
0732 fh.fin = fin ? remain == 0 : false;
0733 detail::fh_buffer fh_buf;
0734 detail::write<
0735 flat_static_buffer_base>(fh_buf, fh);
0736 impl.wr_cont = ! fin;
0737 net::write(impl.stream(),
0738 beast::buffers_cat(fh_buf.data(),
0739 beast::buffers_prefix(n, cb)), ec);
0740 bytes_transferred += n;
0741 if(impl.check_stop_now(ec))
0742 return bytes_transferred;
0743 if(remain == 0)
0744 break;
0745 fh.op = detail::opcode::cont;
0746 cb.consume(n);
0747 }
0748 }
0749 }
0750 else if(! impl.wr_frag)
0751 {
0752
0753 fh.fin = fin;
0754 fh.len = remain;
0755 fh.key = this->impl_->create_mask();
0756 detail::prepared_key key;
0757 detail::prepare_key(key, fh.key);
0758 detail::fh_buffer fh_buf;
0759 detail::write<
0760 flat_static_buffer_base>(fh_buf, fh);
0761 buffers_suffix<
0762 ConstBufferSequence> cb{buffers};
0763 {
0764 auto const n =
0765 clamp(remain, impl.wr_buf_size);
0766 auto const b =
0767 net::buffer(impl.wr_buf.get(), n);
0768 net::buffer_copy(b, cb);
0769 cb.consume(n);
0770 remain -= n;
0771 detail::mask_inplace(b, key);
0772 impl.wr_cont = ! fin;
0773 net::write(impl.stream(),
0774 buffers_cat(fh_buf.data(), b), ec);
0775 bytes_transferred += n;
0776 if(impl.check_stop_now(ec))
0777 return bytes_transferred;
0778 }
0779 while(remain > 0)
0780 {
0781 auto const n =
0782 clamp(remain, impl.wr_buf_size);
0783 auto const b =
0784 net::buffer(impl.wr_buf.get(), n);
0785 net::buffer_copy(b, cb);
0786 cb.consume(n);
0787 remain -= n;
0788 detail::mask_inplace(b, key);
0789 net::write(impl.stream(), b, ec);
0790 bytes_transferred += n;
0791 if(impl.check_stop_now(ec))
0792 return bytes_transferred;
0793 }
0794 }
0795 else
0796 {
0797
0798 BOOST_ASSERT(impl.wr_buf_size != 0);
0799 buffers_suffix<
0800 ConstBufferSequence> cb(buffers);
0801 for(;;)
0802 {
0803 fh.key = this->impl_->create_mask();
0804 detail::prepared_key key;
0805 detail::prepare_key(key, fh.key);
0806 auto const n =
0807 clamp(remain, impl.wr_buf_size);
0808 auto const b =
0809 net::buffer(impl.wr_buf.get(), n);
0810 net::buffer_copy(b, cb);
0811 detail::mask_inplace(b, key);
0812 fh.len = n;
0813 remain -= n;
0814 fh.fin = fin ? remain == 0 : false;
0815 impl.wr_cont = ! fh.fin;
0816 detail::fh_buffer fh_buf;
0817 detail::write<
0818 flat_static_buffer_base>(fh_buf, fh);
0819 net::write(impl.stream(),
0820 buffers_cat(fh_buf.data(), b), ec);
0821 bytes_transferred += n;
0822 if(impl.check_stop_now(ec))
0823 return bytes_transferred;
0824 if(remain == 0)
0825 break;
0826 fh.op = detail::opcode::cont;
0827 cb.consume(n);
0828 }
0829 }
0830 return bytes_transferred;
0831 }
0832
0833 template<class NextLayer, bool deflateSupported>
0834 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0835 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0836 stream<NextLayer, deflateSupported>::
0837 async_write_some(bool fin,
0838 ConstBufferSequence const& bs, WriteHandler&& handler)
0839 {
0840 static_assert(is_async_stream<next_layer_type>::value,
0841 "AsyncStream type requirements not met");
0842 static_assert(net::is_const_buffer_sequence<
0843 ConstBufferSequence>::value,
0844 "ConstBufferSequence type requirements not met");
0845 return net::async_initiate<
0846 WriteHandler,
0847 void(error_code, std::size_t)>(
0848 run_write_some_op{impl_},
0849 handler,
0850 fin,
0851 bs);
0852 }
0853
0854
0855
0856 template<class NextLayer, bool deflateSupported>
0857 template<class ConstBufferSequence>
0858 std::size_t
0859 stream<NextLayer, deflateSupported>::
0860 write(ConstBufferSequence const& buffers)
0861 {
0862 static_assert(is_sync_stream<next_layer_type>::value,
0863 "SyncStream type requirements not met");
0864 static_assert(net::is_const_buffer_sequence<
0865 ConstBufferSequence>::value,
0866 "ConstBufferSequence type requirements not met");
0867 error_code ec;
0868 auto const bytes_transferred = write(buffers, ec);
0869 if(ec)
0870 BOOST_THROW_EXCEPTION(system_error{ec});
0871 return bytes_transferred;
0872 }
0873
0874 template<class NextLayer, bool deflateSupported>
0875 template<class ConstBufferSequence>
0876 std::size_t
0877 stream<NextLayer, deflateSupported>::
0878 write(ConstBufferSequence const& buffers, error_code& ec)
0879 {
0880 static_assert(is_sync_stream<next_layer_type>::value,
0881 "SyncStream type requirements not met");
0882 static_assert(net::is_const_buffer_sequence<
0883 ConstBufferSequence>::value,
0884 "ConstBufferSequence type requirements not met");
0885 return write_some(true, buffers, ec);
0886 }
0887
0888 template<class NextLayer, bool deflateSupported>
0889 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0890 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0891 stream<NextLayer, deflateSupported>::
0892 async_write(
0893 ConstBufferSequence const& bs, WriteHandler&& handler)
0894 {
0895 static_assert(is_async_stream<next_layer_type>::value,
0896 "AsyncStream type requirements not met");
0897 static_assert(net::is_const_buffer_sequence<
0898 ConstBufferSequence>::value,
0899 "ConstBufferSequence type requirements not met");
0900 return net::async_initiate<
0901 WriteHandler,
0902 void(error_code, std::size_t)>(
0903 run_write_some_op{impl_},
0904 handler,
0905 true,
0906 bs);
0907 }
0908
0909 }
0910 }
0911 }
0912
0913 #endif