1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 #ifndef BEAST_TEST_WEBSOCKET_TEST_HPP 11 #define BEAST_TEST_WEBSOCKET_TEST_HPP 12 13 #include <boost/beast/core/bind_handler.hpp> 14 #include <boost/beast/core/buffer_traits.hpp> 15 #include <boost/beast/core/buffers_to_string.hpp> 16 #include <boost/beast/core/ostream.hpp> 17 #include <boost/beast/core/multi_buffer.hpp> 18 #include <boost/beast/websocket/stream.hpp> 19 #include <boost/beast/_experimental/test/stream.hpp> 20 #include <boost/beast/test/yield_to.hpp> 21 #include <boost/beast/_experimental/unit_test/suite.hpp> 22 #include <boost/asio/executor_work_guard.hpp> 23 #include <boost/asio/io_context.hpp> 24 #include <boost/optional.hpp> 25 #include <cstdlib> 26 #include <memory> 27 #include <random> 28 #include <string> 29 30 namespace boost { 31 namespace beast { 32 namespace websocket { 33 34 class websocket_test_suite 35 : public beast::unit_test::suite 36 , public test::enable_yield_to 37 { 38 public: 39 template<bool deflateSupported> 40 using ws_type_t = 41 websocket::stream<test::stream&, deflateSupported>; 42 43 using ws_type = 44 websocket::stream<test::stream&>; 45 46 struct move_only_handler 47 { 48 move_only_handler() = default; 49 move_only_handler(move_only_handler&&) = default; 50 move_only_handler(move_only_handler const&) = delete; 51 52 template<class... Args> 53 void operator ()boost::beast::websocket::websocket_test_suite::move_only_handler54 operator()(Args&&...) const 55 { 56 } 57 }; 58 59 enum class kind 60 { 61 sync, 62 async, 63 async_client 64 }; 65 66 class echo_server 67 { 68 enum 69 { 70 buf_size = 20000 71 }; 72 73 std::ostream& log_; 74 net::io_context ioc_; 75 net::any_io_executor work_; 76 static_buffer<buf_size> buffer_; 77 test::stream ts_; 78 std::thread t_; 79 websocket::stream<test::stream&> ws_; 80 bool close_ = false; 81 82 public: 83 explicit echo_server(std::ostream & log,kind k=kind::sync)84 echo_server( 85 std::ostream& log, 86 kind k = kind::sync) 87 : log_(log) 88 , work_(net::require(ioc_.get_executor(), 89 net::execution::outstanding_work.tracked)) 90 , ts_(ioc_) 91 , ws_(ts_) 92 { 93 permessage_deflate pmd; 94 pmd.server_enable = true; 95 pmd.server_max_window_bits = 9; 96 pmd.compLevel = 1; 97 ws_.set_option(pmd); 98 99 switch(k) 100 { 101 case kind::sync: 102 t_ = std::thread{[&]{ do_sync(); }}; 103 break; 104 105 case kind::async: 106 t_ = std::thread{[&]{ ioc_.run(); }}; 107 do_accept(); 108 break; 109 110 case kind::async_client: 111 t_ = std::thread{[&]{ ioc_.run(); }}; 112 break; 113 } 114 } 115 ~echo_server()116 ~echo_server() 117 { 118 work_ = {}; 119 t_.join(); 120 } 121 122 test::stream& stream()123 stream() 124 { 125 return ts_; 126 } 127 128 void async_handshake()129 async_handshake() 130 { 131 ws_.async_handshake("localhost", "/", 132 bind_front_handler( 133 &echo_server::on_handshake, 134 this)); 135 } 136 137 void async_close()138 async_close() 139 { 140 net::post(ioc_, 141 [&] 142 { 143 if(ws_.is_open()) 144 { 145 ws_.async_close({}, 146 bind_front_handler( 147 &echo_server::on_close, 148 this)); 149 } 150 else 151 { 152 close_ = true; 153 } 154 }); 155 } 156 157 private: 158 void do_sync()159 do_sync() 160 { 161 try 162 { 163 ws_.accept(); 164 for(;;) 165 { 166 ws_.read(buffer_); 167 ws_.text(ws_.got_text()); 168 ws_.write(buffer_.data()); 169 buffer_.consume(buffer_.size()); 170 } 171 } 172 catch(system_error const& se) 173 { 174 boost::ignore_unused(se); 175 #if 0 176 if( se.code() != error::closed && 177 se.code() != error::failed && 178 se.code() != net::error::eof) 179 log_ << "echo_server: " << se.code().message() << std::endl; 180 #endif 181 } 182 catch(std::exception const& e) 183 { 184 log_ << "echo_server: " << e.what() << std::endl; 185 } 186 } 187 188 void do_accept()189 do_accept() 190 { 191 ws_.async_accept( 192 bind_front_handler( 193 &echo_server::on_accept, 194 this)); 195 } 196 197 void on_handshake(error_code ec)198 on_handshake(error_code ec) 199 { 200 if(ec) 201 return fail(ec); 202 203 do_read(); 204 } 205 206 void on_accept(error_code ec)207 on_accept(error_code ec) 208 { 209 if(ec) 210 return fail(ec); 211 212 if(close_) 213 { 214 return ws_.async_close({}, 215 bind_front_handler( 216 &echo_server::on_close, 217 this)); 218 } 219 220 do_read(); 221 } 222 223 void do_read()224 do_read() 225 { 226 ws_.async_read(buffer_, 227 beast::bind_front_handler( 228 &echo_server::on_read, 229 this)); 230 } 231 232 void on_read(error_code ec,std::size_t)233 on_read(error_code ec, std::size_t) 234 { 235 if(ec) 236 return fail(ec); 237 ws_.text(ws_.got_text()); 238 ws_.async_write(buffer_.data(), 239 beast::bind_front_handler( 240 &echo_server::on_write, 241 this)); 242 } 243 244 void on_write(error_code ec,std::size_t)245 on_write(error_code ec, std::size_t) 246 { 247 if(ec) 248 return fail(ec); 249 buffer_.consume(buffer_.size()); 250 do_read(); 251 } 252 253 void on_close(error_code ec)254 on_close(error_code ec) 255 { 256 if(ec) 257 return fail(ec); 258 } 259 260 void fail(error_code ec)261 fail(error_code ec) 262 { 263 boost::ignore_unused(ec); 264 #if 0 265 if( ec != error::closed && 266 ec != error::failed && 267 ec != net::error::eof) 268 log_ << 269 "echo_server_async: " << 270 ec.message() << 271 std::endl; 272 #endif 273 } 274 }; 275 276 template<class Test> 277 void doFailLoop(Test const & f,std::size_t limit=200)278 doFailLoop( 279 Test const& f, std::size_t limit = 200) 280 { 281 std::size_t n; 282 for(n = 0; n < limit; ++n) 283 { 284 test::fail_count fc{n}; 285 try 286 { 287 f(fc); 288 break; 289 } 290 catch(system_error const& se) 291 { 292 BEAST_EXPECTS( 293 se.code() == test::error::test_failure, 294 se.code().message()); 295 } 296 } 297 BEAST_EXPECT(n < limit); 298 } 299 300 template<class Test> 301 void doStreamLoop(Test const & f)302 doStreamLoop(Test const& f) 303 { 304 // This number has to be high for the 305 // test that writes the large buffer. 306 static std::size_t constexpr limit = 200; 307 308 doFailLoop( 309 [&](test::fail_count& fc) 310 { 311 test::stream ts{ioc_, fc}; 312 f(ts); 313 ts.close(); 314 } 315 , limit); 316 } 317 318 template<bool deflateSupported = true, class Test> 319 void doTest(permessage_deflate const & pmd,Test const & f)320 doTest( 321 permessage_deflate const& pmd, 322 Test const& f) 323 { 324 // This number has to be high for the 325 // test that writes the large buffer. 326 static std::size_t constexpr limit = 200; 327 328 for(int i = 0; i < 2; ++i) 329 { 330 std::size_t n; 331 for(n = 0; n < limit; ++n) 332 { 333 test::fail_count fc{n}; 334 test::stream ts{ioc_, fc}; 335 ws_type_t<deflateSupported> ws{ts}; 336 ws.set_option(pmd); 337 338 echo_server es{log, i==1 ? 339 kind::async : kind::sync}; 340 error_code ec; 341 ws.next_layer().connect(es.stream()); 342 ws.handshake("localhost", "/", ec); 343 if(ec) 344 { 345 ts.close(); 346 if( ! BEAST_EXPECTS( 347 ec == test::error::test_failure, 348 ec.message())) 349 BOOST_THROW_EXCEPTION(system_error{ec}); 350 continue; 351 } 352 try 353 { 354 f(ws); 355 ts.close(); 356 break; 357 } 358 catch(system_error const& se) 359 { 360 BEAST_EXPECTS( 361 se.code() == test::error::test_failure, 362 se.code().message()); 363 } 364 catch(std::exception const& e) 365 { 366 fail(e.what(), __FILE__, __LINE__); 367 } 368 ts.close(); 369 continue; 370 } 371 BEAST_EXPECT(n < limit); 372 } 373 } 374 375 //-------------------------------------------------------------------------- 376 cbuf(std::initializer_list<std::uint8_t> bytes)377 net::const_buffer cbuf(std::initializer_list<std::uint8_t> bytes) 378 { 379 return {bytes.begin(), bytes.size()}; 380 } 381 382 template<std::size_t N> 383 static 384 net::const_buffer sbuf(const char (& s)[N])385 sbuf(const char (&s)[N]) 386 { 387 return net::const_buffer(&s[0], N-1); 388 } 389 390 template< 391 class DynamicBuffer, 392 class ConstBufferSequence> 393 void put(DynamicBuffer & buffer,ConstBufferSequence const & buffers)394 put( 395 DynamicBuffer& buffer, 396 ConstBufferSequence const& buffers) 397 { 398 buffer.commit(net::buffer_copy( 399 buffer.prepare(buffer_bytes(buffers)), 400 buffers)); 401 } 402 403 template<class Pred> 404 bool run_until(net::io_context & ioc,std::size_t limit,Pred && pred)405 run_until(net::io_context& ioc, 406 std::size_t limit, Pred&& pred) 407 { 408 for(std::size_t i = 0; i < limit; ++i) 409 { 410 if(pred()) 411 return true; 412 ioc.run_one(); 413 } 414 return false; 415 } 416 417 template<class Pred> 418 bool run_until(net::io_context & ioc,Pred && pred)419 run_until( 420 net::io_context& ioc, Pred&& pred) 421 { 422 return run_until(ioc, 100, pred); 423 } 424 425 inline 426 std::string const& random_string()427 random_string() 428 { 429 static std::string const s = [] 430 { 431 std::size_t constexpr N = 16384; 432 std::mt19937 mt{1}; 433 std::string tmp; 434 tmp.reserve(N); 435 for(std::size_t i = 0; i < N; ++ i) 436 tmp.push_back(static_cast<char>( 437 std::uniform_int_distribution< 438 unsigned>{0, 255}(mt))); 439 return tmp; 440 }(); 441 return s; 442 } 443 444 //-------------------------------------------------------------------------- 445 446 struct SyncClient 447 { 448 template<class NextLayer, bool deflateSupported> 449 void acceptboost::beast::websocket::websocket_test_suite::SyncClient450 accept( 451 stream<NextLayer, deflateSupported>& ws) const 452 { 453 ws.accept(); 454 } 455 456 template< 457 class NextLayer, bool deflateSupported, 458 class Buffers> 459 typename std::enable_if< 460 ! http::detail::is_header<Buffers>::value>::type acceptboost::beast::websocket::websocket_test_suite::SyncClient461 accept(stream<NextLayer, deflateSupported>& ws, 462 Buffers const& buffers) const 463 { 464 ws.accept(buffers); 465 } 466 467 template<class NextLayer, bool deflateSupported> 468 void acceptboost::beast::websocket::websocket_test_suite::SyncClient469 accept( 470 stream<NextLayer, deflateSupported>& ws, 471 http::request<http::empty_body> const& req) const 472 { 473 ws.accept(req); 474 } 475 476 template< 477 class NextLayer, bool deflateSupported, 478 class Decorator> 479 void accept_exboost::beast::websocket::websocket_test_suite::SyncClient480 accept_ex( 481 stream<NextLayer, deflateSupported>& ws, 482 Decorator const& d) const 483 { 484 ws.accept_ex(d); 485 } 486 487 template< 488 class NextLayer, bool deflateSupported, 489 class Buffers, class Decorator> 490 typename std::enable_if< 491 ! http::detail::is_header<Buffers>::value>::type accept_exboost::beast::websocket::websocket_test_suite::SyncClient492 accept_ex( 493 stream<NextLayer, deflateSupported>& ws, 494 Buffers const& buffers, 495 Decorator const& d) const 496 { 497 ws.accept_ex(buffers, d); 498 } 499 500 template< 501 class NextLayer, bool deflateSupported, 502 class Decorator> 503 void accept_exboost::beast::websocket::websocket_test_suite::SyncClient504 accept_ex( 505 stream<NextLayer, deflateSupported>& ws, 506 http::request<http::empty_body> const& req, 507 Decorator const& d) const 508 { 509 ws.accept_ex(req, d); 510 } 511 512 template< 513 class NextLayer, bool deflateSupported, 514 class Buffers, class Decorator> 515 void accept_exboost::beast::websocket::websocket_test_suite::SyncClient516 accept_ex( 517 stream<NextLayer, deflateSupported>& ws, 518 http::request<http::empty_body> const& req, 519 Buffers const& buffers, 520 Decorator const& d) const 521 { 522 ws.accept_ex(req, buffers, d); 523 } 524 525 template<class NextLayer, bool deflateSupported> 526 void handshakeboost::beast::websocket::websocket_test_suite::SyncClient527 handshake( 528 stream<NextLayer, deflateSupported>& ws, 529 string_view uri, 530 string_view path) const 531 { 532 ws.handshake(uri, path); 533 } 534 535 template<class NextLayer, bool deflateSupported> 536 void handshakeboost::beast::websocket::websocket_test_suite::SyncClient537 handshake( 538 stream<NextLayer, deflateSupported>& ws, 539 response_type& res, 540 string_view uri, 541 string_view path) const 542 { 543 ws.handshake(res, uri, path); 544 } 545 546 template< 547 class NextLayer, bool deflateSupported, 548 class Decorator> 549 void handshake_exboost::beast::websocket::websocket_test_suite::SyncClient550 handshake_ex( 551 stream<NextLayer, deflateSupported>& ws, 552 string_view uri, 553 string_view path, 554 Decorator const& d) const 555 { 556 ws.handshake_ex(uri, path, d); 557 } 558 559 template< 560 class NextLayer, bool deflateSupported, 561 class Decorator> 562 void handshake_exboost::beast::websocket::websocket_test_suite::SyncClient563 handshake_ex( 564 stream<NextLayer, deflateSupported>& ws, 565 response_type& res, 566 string_view uri, 567 string_view path, 568 Decorator const& d) const 569 { 570 ws.handshake_ex(res, uri, path, d); 571 } 572 573 template<class NextLayer, bool deflateSupported> 574 void pingboost::beast::websocket::websocket_test_suite::SyncClient575 ping(stream<NextLayer, deflateSupported>& ws, 576 ping_data const& payload) const 577 { 578 ws.ping(payload); 579 } 580 581 template<class NextLayer, bool deflateSupported> 582 void pongboost::beast::websocket::websocket_test_suite::SyncClient583 pong(stream<NextLayer, deflateSupported>& ws, 584 ping_data const& payload) const 585 { 586 ws.pong(payload); 587 } 588 589 template<class NextLayer, bool deflateSupported> 590 void closeboost::beast::websocket::websocket_test_suite::SyncClient591 close(stream<NextLayer, deflateSupported>& ws, 592 close_reason const& cr) const 593 { 594 ws.close(cr); 595 } 596 597 template< 598 class NextLayer, bool deflateSupported, 599 class DynamicBuffer> 600 std::size_t readboost::beast::websocket::websocket_test_suite::SyncClient601 read(stream<NextLayer, deflateSupported>& ws, 602 DynamicBuffer& buffer) const 603 { 604 return ws.read(buffer); 605 } 606 607 template< 608 class NextLayer, bool deflateSupported, 609 class DynamicBuffer> 610 std::size_t read_someboost::beast::websocket::websocket_test_suite::SyncClient611 read_some( 612 stream<NextLayer, deflateSupported>& ws, 613 std::size_t limit, 614 DynamicBuffer& buffer) const 615 { 616 return ws.read_some(buffer, limit); 617 } 618 619 template< 620 class NextLayer, bool deflateSupported, 621 class MutableBufferSequence> 622 std::size_t read_someboost::beast::websocket::websocket_test_suite::SyncClient623 read_some( 624 stream<NextLayer, deflateSupported>& ws, 625 MutableBufferSequence const& buffers) const 626 { 627 return ws.read_some(buffers); 628 } 629 630 template< 631 class NextLayer, bool deflateSupported, 632 class ConstBufferSequence> 633 std::size_t writeboost::beast::websocket::websocket_test_suite::SyncClient634 write( 635 stream<NextLayer, deflateSupported>& ws, 636 ConstBufferSequence const& buffers) const 637 { 638 return ws.write(buffers); 639 } 640 641 template< 642 class NextLayer, bool deflateSupported, 643 class ConstBufferSequence> 644 std::size_t write_someboost::beast::websocket::websocket_test_suite::SyncClient645 write_some( 646 stream<NextLayer, deflateSupported>& ws, 647 bool fin, 648 ConstBufferSequence const& buffers) const 649 { 650 return ws.write_some(fin, buffers); 651 } 652 653 template< 654 class NextLayer, bool deflateSupported, 655 class ConstBufferSequence> 656 std::size_t write_rawboost::beast::websocket::websocket_test_suite::SyncClient657 write_raw( 658 stream<NextLayer, deflateSupported>& ws, 659 ConstBufferSequence const& buffers) const 660 { 661 return net::write( 662 ws.next_layer(), buffers); 663 } 664 }; 665 666 //-------------------------------------------------------------------------- 667 668 class AsyncClient 669 { 670 net::yield_context& yield_; 671 672 public: 673 explicit AsyncClient(net::yield_context & yield)674 AsyncClient(net::yield_context& yield) 675 : yield_(yield) 676 { 677 } 678 679 template<class NextLayer, bool deflateSupported> 680 void accept(stream<NextLayer,deflateSupported> & ws) const681 accept(stream<NextLayer, deflateSupported>& ws) const 682 { 683 error_code ec; 684 ws.async_accept(yield_[ec]); 685 if(ec) 686 throw system_error{ec}; 687 } 688 689 template< 690 class NextLayer, bool deflateSupported, 691 class Buffers> 692 typename std::enable_if< 693 ! http::detail::is_header<Buffers>::value>::type accept(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers) const694 accept( 695 stream<NextLayer, deflateSupported>& ws, 696 Buffers const& buffers) const 697 { 698 error_code ec; 699 ws.async_accept(buffers, yield_[ec]); 700 if(ec) 701 throw system_error{ec}; 702 } 703 704 template<class NextLayer, bool deflateSupported> 705 void accept(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req) const706 accept( 707 stream<NextLayer, deflateSupported>& ws, 708 http::request<http::empty_body> const& req) const 709 { 710 error_code ec; 711 ws.async_accept(req, yield_[ec]); 712 if(ec) 713 throw system_error{ec}; 714 } 715 716 template< 717 class NextLayer, bool deflateSupported, 718 class Decorator> 719 void accept_ex(stream<NextLayer,deflateSupported> & ws,Decorator const & d) const720 accept_ex( 721 stream<NextLayer, deflateSupported>& ws, 722 Decorator const& d) const 723 { 724 error_code ec; 725 ws.async_accept_ex(d, yield_[ec]); 726 if(ec) 727 throw system_error{ec}; 728 } 729 730 template< 731 class NextLayer, bool deflateSupported, 732 class Buffers, class Decorator> 733 typename std::enable_if< 734 ! http::detail::is_header<Buffers>::value>::type accept_ex(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers,Decorator const & d) const735 accept_ex( 736 stream<NextLayer, deflateSupported>& ws, 737 Buffers const& buffers, 738 Decorator const& d) const 739 { 740 error_code ec; 741 ws.async_accept_ex(buffers, d, yield_[ec]); 742 if(ec) 743 throw system_error{ec}; 744 } 745 746 template< 747 class NextLayer, bool deflateSupported, 748 class Decorator> 749 void accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Decorator const & d) const750 accept_ex( 751 stream<NextLayer, deflateSupported>& ws, 752 http::request<http::empty_body> const& req, 753 Decorator const& d) const 754 { 755 error_code ec; 756 ws.async_accept_ex(req, d, yield_[ec]); 757 if(ec) 758 throw system_error{ec}; 759 } 760 761 template< 762 class NextLayer, bool deflateSupported, 763 class Buffers, class Decorator> 764 void accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Buffers const & buffers,Decorator const & d) const765 accept_ex( 766 stream<NextLayer, deflateSupported>& ws, 767 http::request<http::empty_body> const& req, 768 Buffers const& buffers, 769 Decorator const& d) const 770 { 771 error_code ec; 772 ws.async_accept_ex( 773 req, buffers, d, yield_[ec]); 774 if(ec) 775 throw system_error{ec}; 776 } 777 778 template< 779 class NextLayer, bool deflateSupported> 780 void handshake(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path) const781 handshake( 782 stream<NextLayer, deflateSupported>& ws, 783 string_view uri, 784 string_view path) const 785 { 786 error_code ec; 787 ws.async_handshake( 788 uri, path, yield_[ec]); 789 if(ec) 790 throw system_error{ec}; 791 } 792 793 template<class NextLayer, bool deflateSupported> 794 void handshake(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path) const795 handshake( 796 stream<NextLayer, deflateSupported>& ws, 797 response_type& res, 798 string_view uri, 799 string_view path) const 800 { 801 error_code ec; 802 ws.async_handshake( 803 res, uri, path, yield_[ec]); 804 if(ec) 805 throw system_error{ec}; 806 } 807 808 template< 809 class NextLayer, bool deflateSupported, 810 class Decorator> 811 void handshake_ex(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path,Decorator const & d) const812 handshake_ex( 813 stream<NextLayer, deflateSupported>& ws, 814 string_view uri, 815 string_view path, 816 Decorator const &d) const 817 { 818 error_code ec; 819 ws.async_handshake_ex( 820 uri, path, d, yield_[ec]); 821 if(ec) 822 throw system_error{ec}; 823 } 824 825 template< 826 class NextLayer, bool deflateSupported, 827 class Decorator> 828 void handshake_ex(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path,Decorator const & d) const829 handshake_ex( 830 stream<NextLayer, deflateSupported>& ws, 831 response_type& res, 832 string_view uri, 833 string_view path, 834 Decorator const &d) const 835 { 836 error_code ec; 837 ws.async_handshake_ex( 838 res, uri, path, d, yield_[ec]); 839 if(ec) 840 throw system_error{ec}; 841 } 842 843 template<class NextLayer, bool deflateSupported> 844 void ping(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const845 ping( 846 stream<NextLayer, deflateSupported>& ws, 847 ping_data const& payload) const 848 { 849 error_code ec; 850 ws.async_ping(payload, yield_[ec]); 851 if(ec) 852 throw system_error{ec}; 853 } 854 855 template<class NextLayer, bool deflateSupported> 856 void pong(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const857 pong( 858 stream<NextLayer, deflateSupported>& ws, 859 ping_data const& payload) const 860 { 861 error_code ec; 862 ws.async_pong(payload, yield_[ec]); 863 if(ec) 864 throw system_error{ec}; 865 } 866 867 template<class NextLayer, bool deflateSupported> 868 void close(stream<NextLayer,deflateSupported> & ws,close_reason const & cr) const869 close( 870 stream<NextLayer, deflateSupported>& ws, 871 close_reason const& cr) const 872 { 873 error_code ec; 874 ws.async_close(cr, yield_[ec]); 875 if(ec) 876 throw system_error{ec}; 877 } 878 879 template< 880 class NextLayer, bool deflateSupported, 881 class DynamicBuffer> 882 std::size_t read(stream<NextLayer,deflateSupported> & ws,DynamicBuffer & buffer) const883 read( 884 stream<NextLayer, deflateSupported>& ws, 885 DynamicBuffer& buffer) const 886 { 887 error_code ec; 888 auto const bytes_written = 889 ws.async_read(buffer, yield_[ec]); 890 if(ec) 891 throw system_error{ec}; 892 return bytes_written; 893 } 894 895 template< 896 class NextLayer, bool deflateSupported, 897 class DynamicBuffer> 898 std::size_t read_some(stream<NextLayer,deflateSupported> & ws,std::size_t limit,DynamicBuffer & buffer) const899 read_some( 900 stream<NextLayer, deflateSupported>& ws, 901 std::size_t limit, 902 DynamicBuffer& buffer) const 903 { 904 error_code ec; 905 auto const bytes_written = 906 ws.async_read_some(buffer, limit, yield_[ec]); 907 if(ec) 908 throw system_error{ec}; 909 return bytes_written; 910 } 911 912 template< 913 class NextLayer, bool deflateSupported, 914 class MutableBufferSequence> 915 std::size_t read_some(stream<NextLayer,deflateSupported> & ws,MutableBufferSequence const & buffers) const916 read_some( 917 stream<NextLayer, deflateSupported>& ws, 918 MutableBufferSequence const& buffers) const 919 { 920 error_code ec; 921 auto const bytes_written = 922 ws.async_read_some(buffers, yield_[ec]); 923 if(ec) 924 throw system_error{ec}; 925 return bytes_written; 926 } 927 928 template< 929 class NextLayer, bool deflateSupported, 930 class ConstBufferSequence> 931 std::size_t write(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const932 write( 933 stream<NextLayer, deflateSupported>& ws, 934 ConstBufferSequence const& buffers) const 935 { 936 error_code ec; 937 auto const bytes_transferred = 938 ws.async_write(buffers, yield_[ec]); 939 if(ec) 940 throw system_error{ec}; 941 return bytes_transferred; 942 } 943 944 template< 945 class NextLayer, bool deflateSupported, 946 class ConstBufferSequence> 947 std::size_t write_some(stream<NextLayer,deflateSupported> & ws,bool fin,ConstBufferSequence const & buffers) const948 write_some( 949 stream<NextLayer, deflateSupported>& ws, 950 bool fin, 951 ConstBufferSequence const& buffers) const 952 { 953 error_code ec; 954 auto const bytes_transferred = 955 ws.async_write_some(fin, buffers, yield_[ec]); 956 if(ec) 957 throw system_error{ec}; 958 return bytes_transferred; 959 } 960 961 template< 962 class NextLayer, bool deflateSupported, 963 class ConstBufferSequence> 964 std::size_t write_raw(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const965 write_raw( 966 stream<NextLayer, deflateSupported>& ws, 967 ConstBufferSequence const& buffers) const 968 { 969 error_code ec; 970 auto const bytes_transferred = 971 net::async_write( 972 ws.next_layer(), buffers, yield_[ec]); 973 if(ec) 974 throw system_error{ec}; 975 return bytes_transferred; 976 } 977 }; 978 }; 979 980 struct test_sync_api 981 { 982 template<class NextLayer, bool deflateSupported> 983 void acceptboost::beast::websocket::test_sync_api984 accept( 985 stream<NextLayer, deflateSupported>& ws) const 986 { 987 ws.accept(); 988 } 989 990 template< 991 class NextLayer, bool deflateSupported, 992 class Buffers> 993 typename std::enable_if< 994 ! http::detail::is_header<Buffers>::value>::type acceptboost::beast::websocket::test_sync_api995 accept(stream<NextLayer, deflateSupported>& ws, 996 Buffers const& buffers) const 997 { 998 ws.accept(buffers); 999 } 1000 1001 template<class NextLayer, bool deflateSupported> 1002 void acceptboost::beast::websocket::test_sync_api1003 accept( 1004 stream<NextLayer, deflateSupported>& ws, 1005 http::request<http::empty_body> const& req) const 1006 { 1007 ws.accept(req); 1008 } 1009 1010 template< 1011 class NextLayer, bool deflateSupported, 1012 class Decorator> 1013 void accept_exboost::beast::websocket::test_sync_api1014 accept_ex( 1015 stream<NextLayer, deflateSupported>& ws, 1016 Decorator const& d) const 1017 { 1018 ws.accept_ex(d); 1019 } 1020 1021 template< 1022 class NextLayer, bool deflateSupported, 1023 class Buffers, class Decorator> 1024 typename std::enable_if< 1025 ! http::detail::is_header<Buffers>::value>::type accept_exboost::beast::websocket::test_sync_api1026 accept_ex( 1027 stream<NextLayer, deflateSupported>& ws, 1028 Buffers const& buffers, 1029 Decorator const& d) const 1030 { 1031 ws.accept_ex(buffers, d); 1032 } 1033 1034 template< 1035 class NextLayer, bool deflateSupported, 1036 class Decorator> 1037 void accept_exboost::beast::websocket::test_sync_api1038 accept_ex( 1039 stream<NextLayer, deflateSupported>& ws, 1040 http::request<http::empty_body> const& req, 1041 Decorator const& d) const 1042 { 1043 ws.accept_ex(req, d); 1044 } 1045 1046 template< 1047 class NextLayer, bool deflateSupported, 1048 class Buffers, class Decorator> 1049 void accept_exboost::beast::websocket::test_sync_api1050 accept_ex( 1051 stream<NextLayer, deflateSupported>& ws, 1052 http::request<http::empty_body> const& req, 1053 Buffers const& buffers, 1054 Decorator const& d) const 1055 { 1056 ws.accept_ex(req, buffers, d); 1057 } 1058 1059 template<class NextLayer, bool deflateSupported> 1060 void handshakeboost::beast::websocket::test_sync_api1061 handshake( 1062 stream<NextLayer, deflateSupported>& ws, 1063 response_type& res, 1064 string_view uri, 1065 string_view path) const 1066 { 1067 ws.handshake(res, uri, path); 1068 } 1069 1070 template< 1071 class NextLayer, bool deflateSupported, 1072 class Decorator> 1073 void handshake_exboost::beast::websocket::test_sync_api1074 handshake_ex( 1075 stream<NextLayer, deflateSupported>& ws, 1076 string_view uri, 1077 string_view path, 1078 Decorator const& d) const 1079 { 1080 ws.handshake_ex(uri, path, d); 1081 } 1082 1083 template< 1084 class NextLayer, bool deflateSupported, 1085 class Decorator> 1086 void handshake_exboost::beast::websocket::test_sync_api1087 handshake_ex( 1088 stream<NextLayer, deflateSupported>& ws, 1089 response_type& res, 1090 string_view uri, 1091 string_view path, 1092 Decorator const& d) const 1093 { 1094 ws.handshake_ex(res, uri, path, d); 1095 } 1096 1097 template<class NextLayer, bool deflateSupported> 1098 void pingboost::beast::websocket::test_sync_api1099 ping(stream<NextLayer, deflateSupported>& ws, 1100 ping_data const& payload) const 1101 { 1102 ws.ping(payload); 1103 } 1104 1105 template<class NextLayer, bool deflateSupported> 1106 void pongboost::beast::websocket::test_sync_api1107 pong(stream<NextLayer, deflateSupported>& ws, 1108 ping_data const& payload) const 1109 { 1110 ws.pong(payload); 1111 } 1112 1113 template<class NextLayer, bool deflateSupported> 1114 void closeboost::beast::websocket::test_sync_api1115 close(stream<NextLayer, deflateSupported>& ws, 1116 close_reason const& cr) const 1117 { 1118 ws.close(cr); 1119 } 1120 1121 template< 1122 class NextLayer, bool deflateSupported, 1123 class DynamicBuffer> 1124 std::size_t readboost::beast::websocket::test_sync_api1125 read(stream<NextLayer, deflateSupported>& ws, 1126 DynamicBuffer& buffer) const 1127 { 1128 return ws.read(buffer); 1129 } 1130 1131 template< 1132 class NextLayer, bool deflateSupported, 1133 class DynamicBuffer> 1134 std::size_t read_someboost::beast::websocket::test_sync_api1135 read_some( 1136 stream<NextLayer, deflateSupported>& ws, 1137 std::size_t limit, 1138 DynamicBuffer& buffer) const 1139 { 1140 return ws.read_some(buffer, limit); 1141 } 1142 1143 template< 1144 class NextLayer, bool deflateSupported, 1145 class MutableBufferSequence> 1146 std::size_t read_someboost::beast::websocket::test_sync_api1147 read_some( 1148 stream<NextLayer, deflateSupported>& ws, 1149 MutableBufferSequence const& buffers) const 1150 { 1151 return ws.read_some(buffers); 1152 } 1153 1154 template< 1155 class NextLayer, bool deflateSupported, 1156 class ConstBufferSequence> 1157 std::size_t writeboost::beast::websocket::test_sync_api1158 write( 1159 stream<NextLayer, deflateSupported>& ws, 1160 ConstBufferSequence const& buffers) const 1161 { 1162 return ws.write(buffers); 1163 } 1164 1165 template< 1166 class NextLayer, bool deflateSupported, 1167 class ConstBufferSequence> 1168 std::size_t write_someboost::beast::websocket::test_sync_api1169 write_some( 1170 stream<NextLayer, deflateSupported>& ws, 1171 bool fin, 1172 ConstBufferSequence const& buffers) const 1173 { 1174 return ws.write_some(fin, buffers); 1175 } 1176 1177 template< 1178 class NextLayer, bool deflateSupported, 1179 class ConstBufferSequence> 1180 std::size_t write_rawboost::beast::websocket::test_sync_api1181 write_raw( 1182 stream<NextLayer, deflateSupported>& ws, 1183 ConstBufferSequence const& buffers) const 1184 { 1185 return net::write( 1186 ws.next_layer(), buffers); 1187 } 1188 }; 1189 1190 //-------------------------------------------------------------------------- 1191 1192 class test_async_api 1193 { 1194 struct handler 1195 { 1196 error_code& ec_; 1197 std::size_t* n_ = 0; 1198 bool pass_ = false; 1199 1200 explicit handlerboost::beast::websocket::test_async_api::handler1201 handler(error_code& ec) 1202 : ec_(ec) 1203 { 1204 } 1205 1206 explicit handlerboost::beast::websocket::test_async_api::handler1207 handler(error_code& ec, std::size_t& n) 1208 : ec_(ec) 1209 , n_(&n) 1210 { 1211 *n_ = 0; 1212 } 1213 handlerboost::beast::websocket::test_async_api::handler1214 handler(handler&& other) 1215 : ec_(other.ec_) 1216 , pass_(boost::exchange(other.pass_, true)) 1217 { 1218 } 1219 ~handlerboost::beast::websocket::test_async_api::handler1220 ~handler() 1221 { 1222 BEAST_EXPECT(pass_); 1223 } 1224 1225 void operator ()boost::beast::websocket::test_async_api::handler1226 operator()(error_code ec) 1227 { 1228 BEAST_EXPECT(! pass_); 1229 pass_ = true; 1230 ec_ = ec; 1231 } 1232 1233 void operator ()boost::beast::websocket::test_async_api::handler1234 operator()(error_code ec, std::size_t n) 1235 { 1236 BEAST_EXPECT(! pass_); 1237 pass_ = true; 1238 ec_ = ec; 1239 if(n_) 1240 *n_ = n; 1241 } 1242 }; 1243 1244 public: 1245 template<class NextLayer, bool deflateSupported> 1246 void accept(stream<NextLayer,deflateSupported> & ws) const1247 accept( 1248 stream<NextLayer, deflateSupported>& ws) const 1249 { 1250 error_code ec; 1251 ws.async_accept(handler(ec)); 1252 net::query(ws.get_executor(), net::execution::context).run(); 1253 net::query(ws.get_executor(), net::execution::context).restart(); 1254 if(ec) 1255 throw system_error{ec}; 1256 } 1257 1258 template< 1259 class NextLayer, bool deflateSupported, 1260 class Buffers> 1261 typename std::enable_if< 1262 ! http::detail::is_header<Buffers>::value>::type accept(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers) const1263 accept( 1264 stream<NextLayer, deflateSupported>& ws, 1265 Buffers const& buffers) const 1266 { 1267 error_code ec; 1268 ws.async_accept(buffers, handler(ec)); 1269 net::query(ws.get_executor(), net::execution::context).run(); 1270 net::query(ws.get_executor(), net::execution::context).restart(); 1271 if(ec) 1272 throw system_error{ec}; 1273 } 1274 1275 template<class NextLayer, bool deflateSupported> 1276 void accept(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req) const1277 accept( 1278 stream<NextLayer, deflateSupported>& ws, 1279 http::request<http::empty_body> const& req) const 1280 { 1281 error_code ec; 1282 ws.async_accept(req, handler(ec)); 1283 net::query(ws.get_executor(), net::execution::context).run(); 1284 net::query(ws.get_executor(), net::execution::context).restart(); 1285 if(ec) 1286 throw system_error{ec}; 1287 } 1288 1289 template< 1290 class NextLayer, bool deflateSupported, 1291 class Decorator> 1292 void accept_ex(stream<NextLayer,deflateSupported> & ws,Decorator const & d) const1293 accept_ex( 1294 stream<NextLayer, deflateSupported>& ws, 1295 Decorator const& d) const 1296 { 1297 error_code ec; 1298 ws.async_accept_ex(d, handler(ec)); 1299 net::query(ws.get_executor(), net::execution::context).run(); 1300 net::query(ws.get_executor(), net::execution::context).restart(); 1301 if(ec) 1302 throw system_error{ec}; 1303 } 1304 1305 template< 1306 class NextLayer, bool deflateSupported, 1307 class Buffers, class Decorator> 1308 typename std::enable_if< 1309 ! http::detail::is_header<Buffers>::value>::type accept_ex(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers,Decorator const & d) const1310 accept_ex( 1311 stream<NextLayer, deflateSupported>& ws, 1312 Buffers const& buffers, 1313 Decorator const& d) const 1314 { 1315 error_code ec; 1316 ws.async_accept_ex(buffers, d, handler(ec)); 1317 net::query(ws.get_executor(), net::execution::context).run(); 1318 net::query(ws.get_executor(), net::execution::context).restart(); 1319 if(ec) 1320 throw system_error{ec}; 1321 } 1322 1323 template< 1324 class NextLayer, bool deflateSupported, 1325 class Decorator> 1326 void accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Decorator const & d) const1327 accept_ex( 1328 stream<NextLayer, deflateSupported>& ws, 1329 http::request<http::empty_body> const& req, 1330 Decorator const& d) const 1331 { 1332 error_code ec; 1333 ws.async_accept_ex(req, d, handler(ec)); 1334 net::query(ws.get_executor(), net::execution::context).run(); 1335 net::query(ws.get_executor(), net::execution::context).restart(); 1336 if(ec) 1337 throw system_error{ec}; 1338 } 1339 1340 template< 1341 class NextLayer, bool deflateSupported, 1342 class Buffers, class Decorator> 1343 void accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Buffers const & buffers,Decorator const & d) const1344 accept_ex( 1345 stream<NextLayer, deflateSupported>& ws, 1346 http::request<http::empty_body> const& req, 1347 Buffers const& buffers, 1348 Decorator const& d) const 1349 { 1350 error_code ec; 1351 ws.async_accept_ex( 1352 req, buffers, d, handler(ec)); 1353 net::query(ws.get_executor(), net::execution::context).run(); 1354 net::query(ws.get_executor(), net::execution::context).restart(); 1355 if(ec) 1356 throw system_error{ec}; 1357 } 1358 1359 template< 1360 class NextLayer, bool deflateSupported> 1361 void handshake(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path) const1362 handshake( 1363 stream<NextLayer, deflateSupported>& ws, 1364 string_view uri, 1365 string_view path) const 1366 { 1367 error_code ec; 1368 ws.async_handshake( 1369 uri, path, handler(ec)); 1370 net::query(ws.get_executor(), net::execution::context).run(); 1371 net::query(ws.get_executor(), net::execution::context).restart(); 1372 if(ec) 1373 throw system_error{ec}; 1374 } 1375 1376 template<class NextLayer, bool deflateSupported> 1377 void handshake(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path) const1378 handshake( 1379 stream<NextLayer, deflateSupported>& ws, 1380 response_type& res, 1381 string_view uri, 1382 string_view path) const 1383 { 1384 error_code ec; 1385 ws.async_handshake( 1386 res, uri, path, handler(ec)); 1387 net::query(ws.get_executor(), net::execution::context).run(); 1388 net::query(ws.get_executor(), net::execution::context).restart(); 1389 if(ec) 1390 throw system_error{ec}; 1391 } 1392 1393 template< 1394 class NextLayer, bool deflateSupported, 1395 class Decorator> 1396 void handshake_ex(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path,Decorator const & d) const1397 handshake_ex( 1398 stream<NextLayer, deflateSupported>& ws, 1399 string_view uri, 1400 string_view path, 1401 Decorator const &d) const 1402 { 1403 error_code ec; 1404 ws.async_handshake_ex( 1405 uri, path, d, handler(ec)); 1406 net::query(ws.get_executor(), net::execution::context).run(); 1407 net::query(ws.get_executor(), net::execution::context).restart(); 1408 if(ec) 1409 throw system_error{ec}; 1410 } 1411 1412 template< 1413 class NextLayer, bool deflateSupported, 1414 class Decorator> 1415 void handshake_ex(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path,Decorator const & d) const1416 handshake_ex( 1417 stream<NextLayer, deflateSupported>& ws, 1418 response_type& res, 1419 string_view uri, 1420 string_view path, 1421 Decorator const &d) const 1422 { 1423 error_code ec; 1424 ws.async_handshake_ex( 1425 res, uri, path, d, handler(ec)); 1426 net::query(ws.get_executor(), net::execution::context).run(); 1427 net::query(ws.get_executor(), net::execution::context).restart(); 1428 if(ec) 1429 throw system_error{ec}; 1430 } 1431 1432 template<class NextLayer, bool deflateSupported> 1433 void ping(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const1434 ping( 1435 stream<NextLayer, deflateSupported>& ws, 1436 ping_data const& payload) const 1437 { 1438 error_code ec; 1439 ws.async_ping(payload, handler(ec)); 1440 net::query(ws.get_executor(), net::execution::context).run(); 1441 net::query(ws.get_executor(), net::execution::context).restart(); 1442 if(ec) 1443 throw system_error{ec}; 1444 } 1445 1446 template<class NextLayer, bool deflateSupported> 1447 void pong(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const1448 pong( 1449 stream<NextLayer, deflateSupported>& ws, 1450 ping_data const& payload) const 1451 { 1452 error_code ec; 1453 ws.async_pong(payload, handler(ec)); 1454 net::query(ws.get_executor(), net::execution::context).run(); 1455 net::query(ws.get_executor(), net::execution::context).restart(); 1456 if(ec) 1457 throw system_error{ec}; 1458 } 1459 1460 template<class NextLayer, bool deflateSupported> 1461 void close(stream<NextLayer,deflateSupported> & ws,close_reason const & cr) const1462 close( 1463 stream<NextLayer, deflateSupported>& ws, 1464 close_reason const& cr) const 1465 { 1466 error_code ec; 1467 ws.async_close(cr, handler(ec)); 1468 net::query(ws.get_executor(), net::execution::context).run(); 1469 net::query(ws.get_executor(), net::execution::context).restart(); 1470 if(ec) 1471 throw system_error{ec}; 1472 } 1473 1474 template< 1475 class NextLayer, bool deflateSupported, 1476 class DynamicBuffer> 1477 std::size_t read(stream<NextLayer,deflateSupported> & ws,DynamicBuffer & buffer) const1478 read( 1479 stream<NextLayer, deflateSupported>& ws, 1480 DynamicBuffer& buffer) const 1481 { 1482 error_code ec; 1483 std::size_t n; 1484 ws.async_read(buffer, handler(ec, n)); 1485 net::query(ws.get_executor(), net::execution::context).run(); 1486 net::query(ws.get_executor(), net::execution::context).restart(); 1487 if(ec) 1488 throw system_error{ec}; 1489 return n; 1490 } 1491 1492 template< 1493 class NextLayer, bool deflateSupported, 1494 class DynamicBuffer> 1495 std::size_t read_some(stream<NextLayer,deflateSupported> & ws,std::size_t limit,DynamicBuffer & buffer) const1496 read_some( 1497 stream<NextLayer, deflateSupported>& ws, 1498 std::size_t limit, 1499 DynamicBuffer& buffer) const 1500 { 1501 error_code ec; 1502 std::size_t n; 1503 ws.async_read_some(buffer, limit, handler(ec, n)); 1504 net::query(ws.get_executor(), net::execution::context).run(); 1505 net::query(ws.get_executor(), net::execution::context).restart(); 1506 if(ec) 1507 throw system_error{ec}; 1508 return n; 1509 } 1510 1511 template< 1512 class NextLayer, bool deflateSupported, 1513 class MutableBufferSequence> 1514 std::size_t read_some(stream<NextLayer,deflateSupported> & ws,MutableBufferSequence const & buffers) const1515 read_some( 1516 stream<NextLayer, deflateSupported>& ws, 1517 MutableBufferSequence const& buffers) const 1518 { 1519 error_code ec; 1520 std::size_t n; 1521 ws.async_read_some(buffers, handler(ec, n)); 1522 net::query(ws.get_executor(), net::execution::context).run(); 1523 net::query(ws.get_executor(), net::execution::context).restart(); 1524 if(ec) 1525 throw system_error{ec}; 1526 return n; 1527 } 1528 1529 template< 1530 class NextLayer, bool deflateSupported, 1531 class ConstBufferSequence> 1532 std::size_t write(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const1533 write( 1534 stream<NextLayer, deflateSupported>& ws, 1535 ConstBufferSequence const& buffers) const 1536 { 1537 error_code ec; 1538 std::size_t n; 1539 ws.async_write(buffers, handler(ec, n)); 1540 net::query(ws.get_executor(), net::execution::context).run(); 1541 net::query(ws.get_executor(), net::execution::context).restart(); 1542 if(ec) 1543 throw system_error{ec}; 1544 return n; 1545 } 1546 1547 template< 1548 class NextLayer, bool deflateSupported, 1549 class ConstBufferSequence> 1550 std::size_t write_some(stream<NextLayer,deflateSupported> & ws,bool fin,ConstBufferSequence const & buffers) const1551 write_some( 1552 stream<NextLayer, deflateSupported>& ws, 1553 bool fin, 1554 ConstBufferSequence const& buffers) const 1555 { 1556 error_code ec; 1557 std::size_t n; 1558 ws.async_write_some(fin, buffers, handler(ec, n)); 1559 net::query(ws.get_executor(), net::execution::context).run(); 1560 net::query(ws.get_executor(), net::execution::context).restart(); 1561 if(ec) 1562 throw system_error{ec}; 1563 return n; 1564 } 1565 1566 template< 1567 class NextLayer, bool deflateSupported, 1568 class ConstBufferSequence> 1569 std::size_t write_raw(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const1570 write_raw( 1571 stream<NextLayer, deflateSupported>& ws, 1572 ConstBufferSequence const& buffers) const 1573 { 1574 error_code ec; 1575 std::size_t n; 1576 net::async_write(ws.next_layer(), 1577 buffers, handler(ec, n)); 1578 net::query(ws.get_executor(), net::execution::context).run(); 1579 net::query(ws.get_executor(), net::execution::context).restart(); 1580 if(ec) 1581 throw system_error{ec}; 1582 return n; 1583 } 1584 }; 1585 1586 } // websocket 1587 } // beast 1588 } // boost 1589 1590 #endif 1591