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_STREAM_IMPL_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
0012
0013 #include <boost/beast/websocket/rfc6455.hpp>
0014 #include <boost/beast/websocket/detail/frame.hpp>
0015 #include <boost/beast/websocket/detail/hybi13.hpp>
0016 #include <boost/beast/websocket/detail/mask.hpp>
0017 #include <boost/beast/websocket/detail/pmd_extension.hpp>
0018 #include <boost/beast/websocket/detail/prng.hpp>
0019 #include <boost/beast/websocket/detail/service.hpp>
0020 #include <boost/beast/websocket/detail/soft_mutex.hpp>
0021 #include <boost/beast/websocket/detail/utf8_checker.hpp>
0022 #include <boost/beast/http/read.hpp>
0023 #include <boost/beast/http/write.hpp>
0024 #include <boost/beast/http/rfc7230.hpp>
0025 #include <boost/beast/core/buffers_cat.hpp>
0026 #include <boost/beast/core/buffers_prefix.hpp>
0027 #include <boost/beast/core/buffers_suffix.hpp>
0028 #include <boost/beast/core/flat_static_buffer.hpp>
0029 #include <boost/beast/core/saved_handler.hpp>
0030 #include <boost/beast/core/static_buffer.hpp>
0031 #include <boost/beast/core/stream_traits.hpp>
0032 #include <boost/beast/core/detail/clamp.hpp>
0033 #include <boost/asio/steady_timer.hpp>
0034 #include <boost/core/empty_value.hpp>
0035 #include <boost/enable_shared_from_this.hpp>
0036 #include <boost/shared_ptr.hpp>
0037 #include <boost/optional.hpp>
0038
0039 namespace boost {
0040 namespace beast {
0041 namespace websocket {
0042
0043 template<
0044 class NextLayer, bool deflateSupported>
0045 struct stream<NextLayer, deflateSupported>::impl_type
0046 : boost::empty_value<NextLayer>
0047 , detail::service::impl_type
0048 , detail::impl_base<deflateSupported>
0049 {
0050 NextLayer& stream() noexcept
0051 {
0052 return this->boost::empty_value<
0053 NextLayer>::get();
0054 }
0055
0056 boost::weak_ptr<impl_type>
0057 weak_from_this()
0058 {
0059 return boost::static_pointer_cast<
0060 impl_type>(this->detail::service::
0061 impl_type::shared_from_this());
0062 }
0063
0064 boost::shared_ptr<impl_type>
0065 shared_this()
0066 {
0067 return boost::static_pointer_cast<
0068 impl_type>(this->detail::service::
0069 impl_type::shared_from_this());
0070 }
0071 using executor_type = typename std::decay<NextLayer>::type::executor_type;
0072 typename net::steady_timer::rebind_executor<executor_type>::other
0073 timer;
0074 close_reason cr;
0075 control_cb_type ctrl_cb;
0076
0077 std::size_t rd_msg_max = 16 * 1024 * 1024;
0078 std::uint64_t rd_size = 0;
0079 std::uint64_t rd_remain = 0;
0080 detail::frame_header rd_fh;
0081 detail::prepared_key rd_key;
0082 detail::frame_buffer rd_fb;
0083 detail::utf8_checker rd_utf8;
0084 static_buffer<
0085 +tcp_frame_size> rd_buf;
0086 detail::opcode rd_op = detail::opcode::text;
0087 bool rd_cont = false;
0088 bool rd_done = true;
0089 bool rd_close = false;
0090 detail::soft_mutex rd_block;
0091
0092 role_type role = role_type::client;
0093 status status_ = status::closed;
0094
0095 detail::soft_mutex wr_block;
0096 bool wr_close = false;
0097 bool wr_cont = false;
0098 bool wr_frag = false;
0099 bool wr_frag_opt = true;
0100 bool wr_compress;
0101 bool wr_compress_opt = true;
0102 detail::opcode wr_opcode = detail::opcode::text;
0103 std::unique_ptr<
0104 std::uint8_t[]> wr_buf;
0105 std::size_t wr_buf_size = 0;
0106 std::size_t wr_buf_opt = 4096;
0107 detail::fh_buffer wr_fb;
0108
0109 saved_handler op_rd;
0110 saved_handler op_wr;
0111 saved_handler op_ping;
0112 saved_handler op_idle_ping;
0113 saved_handler op_close;
0114 saved_handler op_r_rd;
0115 saved_handler op_r_close;
0116
0117 bool idle_pinging = false;
0118 bool secure_prng_ = true;
0119 bool ec_delivered = false;
0120 bool timed_out = false;
0121 int idle_counter = 0;
0122
0123 detail::decorator decorator_opt;
0124 timeout timeout_opt;
0125
0126 template<class... Args>
0127 impl_type(Args&&... args)
0128 : boost::empty_value<NextLayer>(
0129 boost::empty_init_t{},
0130 std::forward<Args>(args)...)
0131 , detail::service::impl_type(
0132 this->get_context(
0133 this->boost::empty_value<NextLayer>::get().get_executor()))
0134 , timer(this->boost::empty_value<NextLayer>::get().get_executor())
0135 {
0136 timeout_opt.handshake_timeout = none();
0137 timeout_opt.idle_timeout = none();
0138 timeout_opt.keep_alive_pings = false;
0139 }
0140
0141 void
0142 shutdown() override
0143 {
0144 op_rd.reset();
0145 op_wr.reset();
0146 op_ping.reset();
0147 op_idle_ping.reset();
0148 op_close.reset();
0149 op_r_rd.reset();
0150 op_r_close.reset();
0151 }
0152
0153 void
0154 open(role_type role_)
0155 {
0156
0157 timer.expires_at(never());
0158 timed_out = false;
0159 cr.code = close_code::none;
0160 role = role_;
0161 status_ = status::open;
0162 rd_remain = 0;
0163 rd_cont = false;
0164 rd_done = true;
0165
0166
0167 rd_fh.fin = false;
0168 rd_close = false;
0169 wr_close = false;
0170
0171
0172
0173 wr_block.reset();
0174 rd_block.reset();
0175
0176 wr_cont = false;
0177 wr_buf_size = 0;
0178
0179 this->open_pmd(role);
0180 }
0181
0182 void
0183 close()
0184 {
0185 timer.cancel();
0186 wr_buf.reset();
0187 this->close_pmd();
0188 }
0189
0190 void
0191 reset()
0192 {
0193 BOOST_ASSERT(status_ != status::open);
0194 timer.expires_at(never());
0195 cr.code = close_code::none;
0196 rd_remain = 0;
0197 rd_cont = false;
0198 rd_done = true;
0199 rd_buf.consume(rd_buf.size());
0200 rd_fh.fin = false;
0201 rd_close = false;
0202 wr_close = false;
0203 wr_cont = false;
0204
0205
0206
0207 wr_block.reset();
0208 rd_block.reset();
0209
0210
0211 timer.cancel();
0212 }
0213
0214 void
0215 time_out()
0216 {
0217 timed_out = true;
0218 change_status(status::closed);
0219 close_socket(get_lowest_layer(stream()));
0220 }
0221
0222
0223
0224 void
0225 begin_msg(std::size_t n_bytes)
0226 {
0227 wr_frag = wr_frag_opt;
0228 wr_compress =
0229 this->pmd_enabled() &&
0230 wr_compress_opt &&
0231 this->should_compress(n_bytes);
0232
0233
0234 if( this->pmd_enabled() ||
0235 role == role_type::client)
0236 {
0237 if(! wr_buf ||
0238 wr_buf_size != wr_buf_opt)
0239 {
0240 wr_buf_size = wr_buf_opt;
0241 wr_buf = boost::make_unique_noinit<
0242 std::uint8_t[]>(wr_buf_size);
0243 }
0244 }
0245 else
0246 {
0247 wr_buf_size = wr_buf_opt;
0248 wr_buf.reset();
0249 }
0250
0251
0252 }
0253
0254
0255
0256 template<class Decorator>
0257 request_type
0258 build_request(
0259 detail::sec_ws_key_type& key,
0260 string_view host, string_view target,
0261 Decorator const& decorator);
0262
0263 void
0264 on_response(
0265 response_type const& res,
0266 detail::sec_ws_key_type const& key,
0267 error_code& ec);
0268
0269 template<class Body, class Allocator, class Decorator>
0270 response_type
0271 build_response(
0272 http::request<Body,
0273 http::basic_fields<Allocator>> const& req,
0274 Decorator const& decorator,
0275 error_code& result);
0276
0277
0278
0279 template<class DynamicBuffer>
0280 bool
0281 parse_fh(detail::frame_header& fh,
0282 DynamicBuffer& b, error_code& ec);
0283
0284 std::uint32_t
0285 create_mask()
0286 {
0287 auto g = detail::make_prng(secure_prng_);
0288 for(;;)
0289 if(auto key = g())
0290 return key;
0291 }
0292
0293 template<class DynamicBuffer>
0294 std::size_t
0295 read_size_hint_db(DynamicBuffer& buffer) const
0296 {
0297 auto const initial_size = (std::min)(
0298 +tcp_frame_size,
0299 buffer.max_size() - buffer.size());
0300 if(initial_size == 0)
0301 return 1;
0302 return this->read_size_hint_pmd(
0303 initial_size, rd_done, rd_remain, rd_fh);
0304 }
0305
0306 template<class DynamicBuffer>
0307 void
0308 write_ping(DynamicBuffer& db,
0309 detail::opcode code, ping_data const& data);
0310
0311 template<class DynamicBuffer>
0312 void
0313 write_close(DynamicBuffer& db, close_reason const& cr);
0314
0315
0316
0317 void
0318 set_option(timeout const& opt)
0319 {
0320 if( opt.handshake_timeout == none() &&
0321 opt.idle_timeout == none())
0322 {
0323
0324 timer.cancel();
0325 timer.expires_at(never());
0326 }
0327
0328 timeout_opt = opt;
0329 }
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 bool
0340 check_stop_now(error_code& ec)
0341 {
0342
0343 if(timed_out)
0344 {
0345 timed_out = false;
0346 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0347 return true;
0348 }
0349
0350
0351 if( status_ == status::closed ||
0352 status_ == status::failed)
0353 {
0354
0355 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0356 return true;
0357 }
0358
0359
0360 if(! ec)
0361 return false;
0362
0363
0364 if(ec_delivered)
0365 {
0366
0367 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0368 return true;
0369 }
0370
0371
0372 ec_delivered = true;
0373 if(status_ != status::closed)
0374 status_ = status::failed;
0375 return true;
0376 }
0377
0378
0379 void
0380 change_status(status new_status)
0381 {
0382 switch(new_status)
0383 {
0384 case status::handshake:
0385 break;
0386
0387 case status::open:
0388 break;
0389
0390 case status::closing:
0391
0392 break;
0393
0394 case status::failed:
0395 case status::closed:
0396
0397 break;
0398
0399 default:
0400 break;
0401 }
0402 status_ = new_status;
0403 }
0404
0405
0406 void
0407 reset_idle()
0408 {
0409 idle_counter = 0;
0410 }
0411
0412
0413 template<class Executor>
0414 void
0415 update_timer(Executor const& ex)
0416 {
0417 switch(status_)
0418 {
0419 case status::handshake:
0420 BOOST_ASSERT(idle_counter == 0);
0421 if(! is_timer_set() &&
0422 timeout_opt.handshake_timeout != none())
0423 {
0424 timer.expires_after(
0425 timeout_opt.handshake_timeout);
0426
0427 BOOST_ASIO_HANDLER_LOCATION((
0428 __FILE__, __LINE__,
0429 "websocket::check_stop_now"
0430 ));
0431
0432 timer.async_wait(
0433 timeout_handler<Executor>(
0434 ex, this->weak_from_this()));
0435 }
0436 break;
0437
0438 case status::open:
0439 if(timeout_opt.idle_timeout != none())
0440 {
0441 idle_counter = 0;
0442 if(timeout_opt.keep_alive_pings)
0443 timer.expires_after(
0444 timeout_opt.idle_timeout / 2);
0445 else
0446 timer.expires_after(
0447 timeout_opt.idle_timeout);
0448
0449 BOOST_ASIO_HANDLER_LOCATION((
0450 __FILE__, __LINE__,
0451 "websocket::check_stop_now"
0452 ));
0453
0454 timer.async_wait(
0455 timeout_handler<Executor>(
0456 ex, this->weak_from_this()));
0457 }
0458 else
0459 {
0460 timer.cancel();
0461 timer.expires_at(never());
0462 }
0463 break;
0464
0465 case status::closing:
0466 if(timeout_opt.handshake_timeout != none())
0467 {
0468 idle_counter = 0;
0469 timer.expires_after(
0470 timeout_opt.handshake_timeout);
0471
0472 BOOST_ASIO_HANDLER_LOCATION((
0473 __FILE__, __LINE__,
0474 "websocket::check_stop_now"
0475 ));
0476
0477 timer.async_wait(
0478 timeout_handler<Executor>(
0479 ex, this->weak_from_this()));
0480 }
0481 else
0482 {
0483
0484
0485
0486
0487
0488 }
0489 break;
0490
0491 case status::failed:
0492 case status::closed:
0493
0494 timer.cancel();
0495 timer.expires_at(never());
0496 break;
0497 }
0498 }
0499
0500 private:
0501 template<class Executor>
0502 static net::execution_context&
0503 get_context(Executor const& ex,
0504 typename std::enable_if< net::execution::is_executor<Executor>::value >::type* = 0)
0505 {
0506 return net::query(ex, net::execution::context);
0507 }
0508
0509 template<class Executor>
0510 static net::execution_context&
0511 get_context(Executor const& ex,
0512 typename std::enable_if< !net::execution::is_executor<Executor>::value >::type* = 0)
0513 {
0514 return ex.context();
0515 }
0516
0517 bool
0518 is_timer_set() const
0519 {
0520 return timer.expiry() != never();
0521 }
0522
0523 template<class Executor>
0524 class timeout_handler
0525 : boost::empty_value<Executor>
0526 {
0527 boost::weak_ptr<impl_type> wp_;
0528
0529 public:
0530 timeout_handler(
0531 Executor const& ex,
0532 boost::weak_ptr<impl_type>&& wp)
0533 : boost::empty_value<Executor>(
0534 boost::empty_init_t{}, ex)
0535 , wp_(std::move(wp))
0536 {
0537 }
0538
0539 using executor_type = Executor;
0540
0541 executor_type
0542 get_executor() const noexcept
0543 {
0544 return this->get();
0545 }
0546
0547 void
0548 operator()(error_code ec)
0549 {
0550
0551 if(ec == net::error::operation_aborted)
0552 return;
0553 BOOST_ASSERT(! ec);
0554
0555
0556 auto sp = wp_.lock();
0557 if(! sp)
0558 return;
0559 auto& impl = *sp;
0560
0561 switch(impl.status_)
0562 {
0563 case status::handshake:
0564 impl.time_out();
0565 return;
0566
0567 case status::open:
0568
0569 if(impl.timeout_opt.idle_timeout == none())
0570 return;
0571
0572 if( impl.timeout_opt.keep_alive_pings &&
0573 impl.idle_counter < 1)
0574 {
0575 {
0576 BOOST_ASIO_HANDLER_LOCATION((
0577 __FILE__, __LINE__,
0578 "websocket::timeout_handler"
0579 ));
0580
0581 idle_ping_op<Executor>(sp, get_executor());
0582 }
0583 ++impl.idle_counter;
0584 impl.timer.expires_after(
0585 impl.timeout_opt.idle_timeout / 2);
0586
0587 {
0588 BOOST_ASIO_HANDLER_LOCATION((
0589 __FILE__, __LINE__,
0590 "websocket::timeout_handler"
0591 ));
0592
0593 impl.timer.async_wait(std::move(*this));
0594 }
0595 return;
0596 }
0597
0598 impl.time_out();
0599 return;
0600
0601 case status::closing:
0602 impl.time_out();
0603 return;
0604
0605 case status::closed:
0606 case status::failed:
0607
0608 return;
0609 }
0610 }
0611 };
0612 };
0613
0614
0615
0616
0617
0618
0619
0620 template<class NextLayer, bool deflateSupported>
0621 template<class Decorator>
0622 request_type
0623 stream<NextLayer, deflateSupported>::impl_type::
0624 build_request(
0625 detail::sec_ws_key_type& key,
0626 string_view host, string_view target,
0627 Decorator const& decorator)
0628 {
0629 request_type req;
0630 req.target(target);
0631 req.version(11);
0632 req.method(http::verb::get);
0633 req.set(http::field::host, host);
0634 req.set(http::field::upgrade, "websocket");
0635 req.set(http::field::connection, "Upgrade");
0636 detail::make_sec_ws_key(key);
0637 req.set(http::field::sec_websocket_key, to_string_view(key));
0638 req.set(http::field::sec_websocket_version, "13");
0639 this->build_request_pmd(req);
0640 decorator_opt(req);
0641 decorator(req);
0642 return req;
0643 }
0644
0645
0646 template<class NextLayer, bool deflateSupported>
0647 void
0648 stream<NextLayer, deflateSupported>::impl_type::
0649 on_response(
0650 response_type const& res,
0651 detail::sec_ws_key_type const& key,
0652 error_code& ec)
0653 {
0654 auto const err =
0655 [&](error e)
0656 {
0657 BOOST_BEAST_ASSIGN_EC(ec, e);
0658 };
0659 if(res.result() != http::status::switching_protocols)
0660 return err(error::upgrade_declined);
0661 if(res.version() != 11)
0662 return err(error::bad_http_version);
0663 {
0664 auto const it = res.find(http::field::connection);
0665 if(it == res.end())
0666 return err(error::no_connection);
0667 if(! http::token_list{it->value()}.exists("upgrade"))
0668 return err(error::no_connection_upgrade);
0669 }
0670 {
0671 auto const it = res.find(http::field::upgrade);
0672 if(it == res.end())
0673 return err(error::no_upgrade);
0674 if(! http::token_list{it->value()}.exists("websocket"))
0675 return err(error::no_upgrade_websocket);
0676 }
0677 {
0678 auto const it = res.find(
0679 http::field::sec_websocket_accept);
0680 if(it == res.end())
0681 return err(error::no_sec_accept);
0682 detail::sec_ws_accept_type acc;
0683 detail::make_sec_ws_accept(acc, to_string_view(key));
0684 if (to_string_view(acc).compare(it->value()) != 0)
0685 return err(error::bad_sec_accept);
0686 }
0687
0688 ec = {};
0689 this->on_response_pmd(res);
0690 this->open(role_type::client);
0691 }
0692
0693
0694
0695
0696
0697 template<class NextLayer, bool deflateSupported>
0698 template<class DynamicBuffer>
0699 bool
0700 stream<NextLayer, deflateSupported>::impl_type::
0701 parse_fh(
0702 detail::frame_header& fh,
0703 DynamicBuffer& b,
0704 error_code& ec)
0705 {
0706 if(buffer_bytes(b.data()) < 2)
0707 {
0708
0709 ec = {};
0710 return false;
0711 }
0712 buffers_suffix<typename
0713 DynamicBuffer::const_buffers_type> cb{
0714 b.data()};
0715 std::size_t need;
0716 {
0717 std::uint8_t tmp[2];
0718 cb.consume(net::buffer_copy(
0719 net::buffer(tmp), cb));
0720 fh.len = tmp[1] & 0x7f;
0721 switch(fh.len)
0722 {
0723 case 126: need = 2; break;
0724 case 127: need = 8; break;
0725 default:
0726 need = 0;
0727 }
0728 fh.mask = (tmp[1] & 0x80) != 0;
0729 if(fh.mask)
0730 need += 4;
0731 if(buffer_bytes(cb) < need)
0732 {
0733
0734 ec = {};
0735 return false;
0736 }
0737 fh.op = static_cast<
0738 detail::opcode>(tmp[0] & 0x0f);
0739 fh.fin = (tmp[0] & 0x80) != 0;
0740 fh.rsv1 = (tmp[0] & 0x40) != 0;
0741 fh.rsv2 = (tmp[0] & 0x20) != 0;
0742 fh.rsv3 = (tmp[0] & 0x10) != 0;
0743 }
0744 switch(fh.op)
0745 {
0746 case detail::opcode::binary:
0747 case detail::opcode::text:
0748 if(rd_cont)
0749 {
0750
0751 BOOST_BEAST_ASSIGN_EC(ec, error::bad_data_frame);
0752 return false;
0753 }
0754 if(fh.rsv2 || fh.rsv3 ||
0755 ! this->rd_deflated(fh.rsv1))
0756 {
0757
0758 BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0759 return false;
0760 }
0761 break;
0762
0763 case detail::opcode::cont:
0764 if(! rd_cont)
0765 {
0766
0767 BOOST_BEAST_ASSIGN_EC(ec, error::bad_continuation);
0768 return false;
0769 }
0770 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
0771 {
0772
0773 BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0774 return false;
0775 }
0776 break;
0777
0778 default:
0779 if(detail::is_reserved(fh.op))
0780 {
0781
0782 BOOST_BEAST_ASSIGN_EC(ec, error::bad_opcode);
0783 return false;
0784 }
0785 if(! fh.fin)
0786 {
0787
0788 BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_fragment);
0789 return false;
0790 }
0791 if(fh.len > 125)
0792 {
0793
0794 BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_size);
0795 return false;
0796 }
0797 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
0798 {
0799
0800 BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0801 return false;
0802 }
0803 break;
0804 }
0805 if(role == role_type::server && ! fh.mask)
0806 {
0807
0808 BOOST_BEAST_ASSIGN_EC(ec, error::bad_unmasked_frame);
0809 return false;
0810 }
0811 if(role == role_type::client && fh.mask)
0812 {
0813
0814 BOOST_BEAST_ASSIGN_EC(ec, error::bad_masked_frame);
0815 return false;
0816 }
0817 if(detail::is_control(fh.op) &&
0818 buffer_bytes(cb) < need + fh.len)
0819 {
0820
0821
0822 return false;
0823 }
0824 switch(fh.len)
0825 {
0826 case 126:
0827 {
0828
0829 std::uint16_t len_be;
0830 BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
0831 cb.consume(net::buffer_copy(
0832 net::mutable_buffer(&len_be, sizeof(len_be)), cb));
0833 fh.len = endian::big_to_native(len_be);
0834 if(fh.len < 126)
0835 {
0836
0837 BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
0838 return false;
0839 }
0840 break;
0841 }
0842 case 127:
0843 {
0844 std::uint64_t len_be;
0845 BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
0846 cb.consume(net::buffer_copy(
0847 net::mutable_buffer(&len_be, sizeof(len_be)), cb));
0848 fh.len = endian::big_to_native(len_be);
0849 if(fh.len < 65536)
0850 {
0851
0852 BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
0853 return false;
0854 }
0855 break;
0856 }
0857 }
0858 if(fh.mask)
0859 {
0860 std::uint32_t key_le;
0861 BOOST_ASSERT(buffer_bytes(cb) >= sizeof(key_le));
0862 cb.consume(net::buffer_copy(
0863 net::mutable_buffer(&key_le, sizeof(key_le)), cb));
0864 fh.key = endian::little_to_native(key_le);
0865 detail::prepare_key(rd_key, fh.key);
0866 }
0867 else
0868 {
0869
0870 fh.key = 0;
0871 }
0872 if(! detail::is_control(fh.op))
0873 {
0874 if(fh.op != detail::opcode::cont)
0875 {
0876 rd_size = 0;
0877 rd_op = fh.op;
0878 }
0879 else
0880 {
0881 if(rd_size > (std::numeric_limits<
0882 std::uint64_t>::max)() - fh.len)
0883 {
0884
0885 BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
0886 return false;
0887 }
0888 }
0889 if(! this->rd_deflated())
0890 {
0891 if(rd_msg_max && beast::detail::sum_exceeds(
0892 rd_size, fh.len, rd_msg_max))
0893 {
0894
0895 BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
0896 return false;
0897 }
0898 }
0899 rd_cont = ! fh.fin;
0900 rd_remain = fh.len;
0901 }
0902 b.consume(b.size() - buffer_bytes(cb));
0903 ec = {};
0904 return true;
0905 }
0906
0907 template<class NextLayer, bool deflateSupported>
0908 template<class DynamicBuffer>
0909 void
0910 stream<NextLayer, deflateSupported>::impl_type::
0911 write_ping(DynamicBuffer& db,
0912 detail::opcode code, ping_data const& data)
0913 {
0914 detail::frame_header fh;
0915 fh.op = code;
0916 fh.fin = true;
0917 fh.rsv1 = false;
0918 fh.rsv2 = false;
0919 fh.rsv3 = false;
0920 fh.len = data.size();
0921 fh.mask = role == role_type::client;
0922 if(fh.mask)
0923 fh.key = create_mask();
0924 detail::write(db, fh);
0925 if(data.empty())
0926 return;
0927 detail::prepared_key key;
0928 if(fh.mask)
0929 detail::prepare_key(key, fh.key);
0930 auto mb = db.prepare(data.size());
0931 net::buffer_copy(mb,
0932 net::const_buffer(
0933 data.data(), data.size()));
0934 if(fh.mask)
0935 detail::mask_inplace(mb, key);
0936 db.commit(data.size());
0937 }
0938
0939 template<class NextLayer, bool deflateSupported>
0940 template<class DynamicBuffer>
0941 void
0942 stream<NextLayer, deflateSupported>::impl_type::
0943 write_close(DynamicBuffer& db, close_reason const& cr)
0944 {
0945 using namespace boost::endian;
0946 detail::frame_header fh;
0947 fh.op = detail::opcode::close;
0948 fh.fin = true;
0949 fh.rsv1 = false;
0950 fh.rsv2 = false;
0951 fh.rsv3 = false;
0952 fh.len = cr.code == close_code::none ?
0953 0 : 2 + cr.reason.size();
0954 if(role == role_type::client)
0955 {
0956 fh.mask = true;
0957 fh.key = create_mask();
0958 }
0959 else
0960 {
0961 fh.mask = false;
0962 }
0963 detail::write(db, fh);
0964 if(cr.code != close_code::none)
0965 {
0966 detail::prepared_key key;
0967 if(fh.mask)
0968 detail::prepare_key(key, fh.key);
0969 {
0970 auto code_be = endian::native_to_big<std::uint16_t>(cr.code);
0971 auto mb = db.prepare(2);
0972 net::buffer_copy(mb,
0973 net::const_buffer(&code_be, sizeof(code_be)));
0974 if(fh.mask)
0975 detail::mask_inplace(mb, key);
0976 db.commit(2);
0977 }
0978 if(! cr.reason.empty())
0979 {
0980 auto mb = db.prepare(cr.reason.size());
0981 net::buffer_copy(mb,
0982 net::const_buffer(
0983 cr.reason.data(), cr.reason.size()));
0984 if(fh.mask)
0985 detail::mask_inplace(mb, key);
0986 db.commit(cr.reason.size());
0987 }
0988 }
0989 }
0990
0991 }
0992 }
0993 }
0994
0995 #endif