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