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 // Test that header file is self-contained. 11 #include <boost/beast/websocket/stream.hpp> 12 13 #include "test.hpp" 14 15 #include <boost/asio/write.hpp> 16 17 #if BOOST_ASIO_HAS_CO_AWAIT 18 #include <boost/asio/use_awaitable.hpp> 19 #endif 20 21 #include <boost/config/workaround.hpp> 22 #if BOOST_WORKAROUND(BOOST_GCC, < 80200) 23 #define BOOST_BEAST_SYMBOL_HIDDEN __attribute__ ((visibility("hidden"))) 24 #else 25 #define BOOST_BEAST_SYMBOL_HIDDEN 26 #endif 27 28 namespace boost { 29 namespace beast { 30 namespace websocket { 31 32 class BOOST_BEAST_SYMBOL_HIDDEN read2_test 33 : public websocket_test_suite 34 { 35 public: 36 template<class Wrap, bool deflateSupported> 37 void doReadTest(Wrap const & w,ws_type_t<deflateSupported> & ws,close_code code)38 doReadTest( 39 Wrap const& w, 40 ws_type_t<deflateSupported>& ws, 41 close_code code) 42 { 43 try 44 { 45 multi_buffer b; 46 w.read(ws, b); 47 fail("", __FILE__, __LINE__); 48 } 49 catch(system_error const& se) 50 { 51 if(se.code() != error::closed) 52 throw; 53 BEAST_EXPECT( 54 ws.reason().code == code); 55 } 56 } 57 58 template<class Wrap, bool deflateSupported> 59 void doFailTest(Wrap const & w,ws_type_t<deflateSupported> & ws,error_code ev)60 doFailTest( 61 Wrap const& w, 62 ws_type_t<deflateSupported>& ws, 63 error_code ev) 64 { 65 try 66 { 67 multi_buffer b; 68 w.read(ws, b); 69 fail("", __FILE__, __LINE__); 70 } 71 catch(system_error const& se) 72 { 73 if(se.code() != ev) 74 throw; 75 } 76 } 77 78 template<bool deflateSupported = true, class Wrap> 79 void doTestRead(Wrap const & w)80 doTestRead(Wrap const& w) 81 { 82 permessage_deflate pmd; 83 pmd.client_enable = false; 84 pmd.server_enable = false; 85 86 // already closed 87 { 88 echo_server es{log}; 89 stream<test::stream, deflateSupported> ws{ioc_}; 90 ws.next_layer().connect(es.stream()); 91 ws.handshake("localhost", "/"); 92 ws.close({}); 93 try 94 { 95 multi_buffer b; 96 w.read(ws, b); 97 fail("", __FILE__, __LINE__); 98 } 99 catch(system_error const& se) 100 { 101 BEAST_EXPECTS( 102 se.code() == net::error::operation_aborted, 103 se.code().message()); 104 } 105 } 106 107 // empty, fragmented message 108 doTest<deflateSupported>(pmd, 109 [&](ws_type_t<deflateSupported>& ws) 110 { 111 ws.next_layer().append( 112 string_view( 113 "\x01\x00" "\x80\x00", 4)); 114 multi_buffer b; 115 w.read(ws, b); 116 BEAST_EXPECT(b.size() == 0); 117 }); 118 119 // two part message 120 // triggers "fill the read buffer first" 121 doTest<deflateSupported>(pmd, 122 [&](ws_type_t<deflateSupported>& ws) 123 { 124 w.write_raw(ws, sbuf( 125 "\x01\x81\xff\xff\xff\xff")); 126 w.write_raw(ws, sbuf( 127 "\xd5")); 128 w.write_raw(ws, sbuf( 129 "\x80\x81\xff\xff\xff\xff\xd5")); 130 multi_buffer b; 131 w.read(ws, b); 132 BEAST_EXPECT(buffers_to_string(b.data()) == "**"); 133 }); 134 135 // ping 136 doTest<deflateSupported>(pmd, 137 [&](ws_type_t<deflateSupported>& ws) 138 { 139 put(ws.next_layer().buffer(), cbuf( 140 {0x89, 0x00})); 141 bool invoked = false; 142 ws.control_callback( 143 [&](frame_type kind, string_view) 144 { 145 BEAST_EXPECT(! invoked); 146 BEAST_EXPECT(kind == frame_type::ping); 147 invoked = true; 148 }); 149 w.write(ws, sbuf("Hello")); 150 multi_buffer b; 151 w.read(ws, b); 152 BEAST_EXPECT(invoked); 153 BEAST_EXPECT(ws.got_text()); 154 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello"); 155 }); 156 157 // ping 158 doTest<deflateSupported>(pmd, 159 [&](ws_type_t<deflateSupported>& ws) 160 { 161 put(ws.next_layer().buffer(), cbuf( 162 {0x88, 0x00})); 163 bool invoked = false; 164 ws.control_callback( 165 [&](frame_type kind, string_view) 166 { 167 BEAST_EXPECT(! invoked); 168 BEAST_EXPECT(kind == frame_type::close); 169 invoked = true; 170 }); 171 w.write(ws, sbuf("Hello")); 172 doReadTest(w, ws, close_code::none); 173 }); 174 175 // ping then message 176 doTest<deflateSupported>(pmd, 177 [&](ws_type_t<deflateSupported>& ws) 178 { 179 bool once = false; 180 ws.control_callback( 181 [&](frame_type kind, string_view s) 182 { 183 BEAST_EXPECT(kind == frame_type::pong); 184 BEAST_EXPECT(! once); 185 once = true; 186 BEAST_EXPECT(s == ""); 187 }); 188 w.ping(ws, ""); 189 ws.binary(true); 190 w.write(ws, sbuf("Hello")); 191 multi_buffer b; 192 w.read(ws, b); 193 BEAST_EXPECT(once); 194 BEAST_EXPECT(ws.got_binary()); 195 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello"); 196 }); 197 198 // ping then fragmented message 199 doTest<deflateSupported>(pmd, 200 [&](ws_type_t<deflateSupported>& ws) 201 { 202 bool once = false; 203 ws.control_callback( 204 [&](frame_type kind, string_view s) 205 { 206 BEAST_EXPECT(kind == frame_type::pong); 207 BEAST_EXPECT(! once); 208 once = true; 209 BEAST_EXPECT(s == "payload"); 210 }); 211 ws.ping("payload"); 212 w.write_some(ws, false, sbuf("Hello, ")); 213 w.write_some(ws, false, sbuf("")); 214 w.write_some(ws, true, sbuf("World!")); 215 multi_buffer b; 216 w.read(ws, b); 217 BEAST_EXPECT(once); 218 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello, World!"); 219 }); 220 221 // masked message, big 222 doStreamLoop([&](test::stream& ts) 223 { 224 echo_server es{log, kind::async_client}; 225 ws_type_t<deflateSupported> ws{ts}; 226 ws.next_layer().connect(es.stream()); 227 ws.set_option(pmd); 228 es.async_handshake(); 229 try 230 { 231 w.accept(ws); 232 std::string const s(2000, '*'); 233 ws.auto_fragment(false); 234 ws.binary(false); 235 w.write(ws, net::buffer(s)); 236 multi_buffer b; 237 w.read(ws, b); 238 BEAST_EXPECT(ws.got_text()); 239 BEAST_EXPECT(buffers_to_string(b.data()) == s); 240 ws.next_layer().close(); 241 } 242 catch(...) 243 { 244 ts.close(); 245 throw; 246 } 247 }); 248 249 // close 250 doFailLoop([&](test::fail_count& fc) 251 { 252 echo_server es{log, kind::async}; 253 net::io_context ioc; 254 stream<test::stream, deflateSupported> ws{ioc, fc}; 255 ws.next_layer().connect(es.stream()); 256 ws.handshake("localhost", "/"); 257 // Cause close to be received 258 es.async_close(); 259 std::size_t count = 0; 260 multi_buffer b; 261 ws.async_read(b, 262 [&](error_code ec, std::size_t) 263 { 264 ++count; 265 if(ec != error::closed) 266 BOOST_THROW_EXCEPTION( 267 system_error{ec}); 268 }); 269 ioc.run(); 270 BEAST_EXPECT(count == 1); 271 }); 272 273 // already closed 274 doTest<deflateSupported>(pmd, 275 [&](ws_type_t<deflateSupported>& ws) 276 { 277 w.close(ws, {}); 278 multi_buffer b; 279 doFailTest(w, ws, 280 net::error::operation_aborted); 281 }); 282 283 // buffer overflow 284 doTest<deflateSupported>(pmd, 285 [&](ws_type_t<deflateSupported>& ws) 286 { 287 std::string const s = "Hello, world!"; 288 ws.auto_fragment(false); 289 ws.binary(false); 290 w.write(ws, net::buffer(s)); 291 try 292 { 293 multi_buffer b(3); 294 w.read(ws, b); 295 fail("", __FILE__, __LINE__); 296 } 297 catch(system_error const& se) 298 { 299 if(se.code() != error::buffer_overflow) 300 throw; 301 } 302 }); 303 304 // bad utf8, big 305 doTest<deflateSupported>(pmd, 306 [&](ws_type_t<deflateSupported>& ws) 307 { 308 auto const s = std::string(2000, '*') + 309 random_string(); 310 ws.text(true); 311 w.write(ws, net::buffer(s)); 312 doReadTest(w, ws, close_code::bad_payload); 313 }); 314 315 // invalid fixed frame header 316 doTest<deflateSupported>(pmd, 317 [&](ws_type_t<deflateSupported>& ws) 318 { 319 w.write_raw(ws, cbuf( 320 {0x8f, 0x80, 0xff, 0xff, 0xff, 0xff})); 321 doReadTest(w, ws, close_code::protocol_error); 322 }); 323 324 // bad close 325 doTest<deflateSupported>(pmd, 326 [&](ws_type_t<deflateSupported>& ws) 327 { 328 put(ws.next_layer().buffer(), cbuf( 329 {0x88, 0x02, 0x03, 0xed})); 330 doFailTest(w, ws, error::bad_close_code); 331 }); 332 333 // message size above 2^64 334 doTest<deflateSupported>(pmd, 335 [&](ws_type_t<deflateSupported>& ws) 336 { 337 w.write_some(ws, false, sbuf("*")); 338 w.write_raw(ws, cbuf( 339 {0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 340 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})); 341 doReadTest(w, ws, close_code::too_big); 342 }); 343 344 // message size exceeds max 345 doTest<deflateSupported>(pmd, 346 [&](ws_type_t<deflateSupported>& ws) 347 { 348 ws.read_message_max(1); 349 w.write(ws, sbuf("**")); 350 doFailTest(w, ws, error::message_too_big); 351 }); 352 353 // bad utf8 354 doTest<deflateSupported>(pmd, 355 [&](ws_type_t<deflateSupported>& ws) 356 { 357 put(ws.next_layer().buffer(), cbuf( 358 {0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc})); 359 doFailTest(w, ws, error::bad_frame_payload); 360 }); 361 362 // incomplete utf8 363 doTest<deflateSupported>(pmd, 364 [&](ws_type_t<deflateSupported>& ws) 365 { 366 std::string const s = 367 "Hello, world!" "\xc0"; 368 w.write(ws, net::buffer(s)); 369 doReadTest(w, ws, close_code::bad_payload); 370 }); 371 372 // incomplete utf8, big 373 doTest<deflateSupported>(pmd, 374 [&](ws_type_t<deflateSupported>& ws) 375 { 376 std::string const s = 377 "\x81\x7e\x0f\xa1" + 378 std::string(4000, '*') + "\xc0"; 379 ws.next_layer().append(s); 380 multi_buffer b; 381 try 382 { 383 do 384 { 385 b.commit(w.read_some(ws, b.prepare(4000))); 386 } 387 while(! ws.is_message_done()); 388 } 389 catch(system_error const& se) 390 { 391 if(se.code() != error::bad_frame_payload) 392 throw; 393 } 394 }); 395 396 // close frames 397 { 398 auto const check = 399 [&](error_code ev, string_view s) 400 { 401 echo_server es{log}; 402 stream<test::stream, deflateSupported> ws{ioc_}; 403 ws.next_layer().connect(es.stream()); 404 w.handshake(ws, "localhost", "/"); 405 ws.next_layer().append(s); 406 static_buffer<1> b; 407 try 408 { 409 w.read(ws, b); 410 fail("", __FILE__, __LINE__); 411 } 412 catch(system_error const& se) 413 { 414 BEAST_EXPECTS(se.code() == ev, 415 se.code().message()); 416 } 417 ws.next_layer().close(); 418 }; 419 420 // payload length 1 421 check(error::bad_close_size, 422 "\x88\x01\x01"); 423 424 // invalid close code 1005 425 check(error::bad_close_code, 426 "\x88\x02\x03\xed"); 427 428 // invalid utf8 429 check(error::bad_close_payload, 430 "\x88\x06\xfc\x15\x0f\xd7\x73\x43"); 431 432 // good utf8 433 check(error::closed, 434 "\x88\x06\xfc\x15utf8"); 435 } 436 } 437 438 template<class Wrap> 439 void doTestReadDeflate(Wrap const & w)440 doTestReadDeflate(Wrap const& w) 441 { 442 permessage_deflate pmd; 443 pmd.client_enable = true; 444 pmd.server_enable = true; 445 pmd.client_max_window_bits = 9; 446 pmd.server_max_window_bits = 9; 447 pmd.compLevel = 1; 448 449 // message size limit 450 doTest<true>(pmd, 451 [&](ws_type_t<true>& ws) 452 { 453 std::string const s = std::string(128, '*'); 454 w.write(ws, net::buffer(s)); 455 ws.read_message_max(32); 456 doFailTest(w, ws, error::message_too_big); 457 }); 458 459 // invalid inflate block 460 doTest<true>(pmd, 461 [&](ws_type_t<true>& ws) 462 { 463 auto const& s = random_string(); 464 ws.binary(true); 465 ws.next_layer().append( 466 "\xc2\x40" + s.substr(0, 64)); 467 flat_buffer b; 468 try 469 { 470 w.read(ws, b); 471 } 472 catch(system_error const& se) 473 { 474 if(se.code() == test::error::test_failure) 475 throw; 476 BEAST_EXPECTS(se.code().category() == 477 make_error_code(static_cast< 478 zlib::error>(0)).category(), 479 se.code().message()); 480 } 481 catch(...) 482 { 483 throw; 484 } 485 }); 486 487 // no_context_takeover 488 pmd.server_no_context_takeover = true; 489 doTest<true>(pmd, 490 [&](ws_type_t<true>& ws) 491 { 492 auto const& s = random_string(); 493 ws.binary(true); 494 w.write(ws, net::buffer(s)); 495 multi_buffer b; 496 w.read(ws, b); 497 BEAST_EXPECT(buffers_to_string(b.data()) == s); 498 }); 499 pmd.client_no_context_takeover = false; 500 } 501 502 template<class Wrap> 503 void doTestRead(permessage_deflate const & pmd,Wrap const & w)504 doTestRead( 505 permessage_deflate const& pmd, 506 Wrap const& w) 507 { 508 // message 509 doTest(pmd, [&](ws_type& ws) 510 { 511 std::string const s = "Hello, world!"; 512 ws.auto_fragment(false); 513 ws.binary(false); 514 w.write(ws, net::buffer(s)); 515 multi_buffer b; 516 w.read(ws, b); 517 BEAST_EXPECT(ws.got_text()); 518 BEAST_EXPECT(buffers_to_string(b.data()) == s); 519 }); 520 521 // masked message 522 doStreamLoop([&](test::stream& ts) 523 { 524 echo_server es{log, kind::async_client}; 525 ws_type ws{ts}; 526 ws.next_layer().connect(es.stream()); 527 ws.set_option(pmd); 528 es.async_handshake(); 529 try 530 { 531 w.accept(ws); 532 std::string const s = "Hello, world!"; 533 ws.auto_fragment(false); 534 ws.binary(false); 535 w.write(ws, net::buffer(s)); 536 multi_buffer b; 537 w.read(ws, b); 538 BEAST_EXPECT(ws.got_text()); 539 BEAST_EXPECT(buffers_to_string(b.data()) == s); 540 ws.next_layer().close(); 541 } 542 catch(...) 543 { 544 ts.close(); 545 throw; 546 } 547 }); 548 549 // empty message 550 doTest(pmd, [&](ws_type& ws) 551 { 552 std::string const s = ""; 553 ws.text(true); 554 w.write(ws, net::buffer(s)); 555 multi_buffer b; 556 w.read(ws, b); 557 BEAST_EXPECT(ws.got_text()); 558 BEAST_EXPECT(buffers_to_string(b.data()) == s); 559 }); 560 561 // partial message 562 doTest(pmd, [&](ws_type& ws) 563 { 564 std::string const s = "Hello"; 565 w.write(ws, net::buffer(s)); 566 char buf[3]; 567 auto const bytes_written = 568 w.read_some(ws, net::buffer(buf, sizeof(buf))); 569 BEAST_EXPECT(bytes_written > 0); 570 BEAST_EXPECT( 571 string_view(buf, 3).substr(0, bytes_written) == 572 s.substr(0, bytes_written)); 573 }); 574 575 // partial message, dynamic buffer 576 doTest(pmd, [&](ws_type& ws) 577 { 578 std::string const s = "Hello, world!"; 579 w.write(ws, net::buffer(s)); 580 multi_buffer b; 581 auto bytes_written = 582 w.read_some(ws, 3, b); 583 BEAST_EXPECT(bytes_written > 0); 584 BEAST_EXPECT(buffers_to_string(b.data()) == 585 s.substr(0, b.size())); 586 w.read_some(ws, 256, b); 587 BEAST_EXPECT(buffers_to_string(b.data()) == s); 588 }); 589 590 // big message 591 doTest(pmd, [&](ws_type& ws) 592 { 593 auto const& s = random_string(); 594 ws.binary(true); 595 w.write(ws, net::buffer(s)); 596 multi_buffer b; 597 w.read(ws, b); 598 BEAST_EXPECT(buffers_to_string(b.data()) == s); 599 }); 600 601 // message, bad utf8 602 doTest(pmd, [&](ws_type& ws) 603 { 604 std::string const s = "\x03\xea\xf0\x28\x8c\xbc"; 605 ws.auto_fragment(false); 606 ws.text(true); 607 w.write(ws, net::buffer(s)); 608 doReadTest(w, ws, close_code::bad_payload); 609 }); 610 } 611 612 void testRead()613 testRead() 614 { 615 doTestRead<false>(SyncClient{}); 616 doTestRead<true>(SyncClient{}); 617 doTestReadDeflate(SyncClient{}); 618 yield_to([&](yield_context yield) 619 { 620 doTestRead<false>(AsyncClient{yield}); 621 doTestRead<true>(AsyncClient{yield}); 622 doTestReadDeflate(AsyncClient{yield}); 623 }); 624 625 permessage_deflate pmd; 626 pmd.client_enable = false; 627 pmd.server_enable = false; 628 doTestRead(pmd, SyncClient{}); 629 yield_to([&](yield_context yield) 630 { 631 doTestRead(pmd, AsyncClient{yield}); 632 }); 633 634 pmd.client_enable = true; 635 pmd.server_enable = true; 636 pmd.client_max_window_bits = 9; 637 pmd.server_max_window_bits = 9; 638 pmd.compLevel = 1; 639 doTestRead(pmd, SyncClient{}); 640 yield_to([&](yield_context yield) 641 { 642 doTestRead(pmd, AsyncClient{yield}); 643 }); 644 645 // Read close frames 646 { 647 auto const check = 648 [&](error_code ev, string_view s) 649 { 650 echo_server es{log}; 651 stream<test::stream> ws{ioc_}; 652 ws.next_layer().connect(es.stream()); 653 ws.handshake("localhost", "/"); 654 ws.next_layer().append(s); 655 static_buffer<1> b; 656 error_code ec; 657 ws.read(b, ec); 658 BEAST_EXPECTS(ec == ev, ec.message()); 659 ws.next_layer().close(); 660 }; 661 662 // payload length 1 663 check(error::bad_close_size, 664 "\x88\x01\x01"); 665 666 // invalid close code 1005 667 check(error::bad_close_code, 668 "\x88\x02\x03\xed"); 669 670 // invalid utf8 671 check(error::bad_close_payload, 672 "\x88\x06\xfc\x15\x0f\xd7\x73\x43"); 673 674 // good utf8 675 check(error::closed, 676 "\x88\x06\xfc\x15utf8"); 677 } 678 } 679 680 #if BOOST_ASIO_HAS_CO_AWAIT testAwaitableCompiles(stream<test::stream> & s,flat_buffer & dynbuf,net::mutable_buffer buf,std::size_t limit)681 void testAwaitableCompiles( 682 stream<test::stream>& s, 683 flat_buffer& dynbuf, 684 net::mutable_buffer buf, 685 std::size_t limit) 686 { 687 static_assert(std::is_same_v< 688 net::awaitable<std::size_t>, decltype( 689 s.async_read(dynbuf, net::use_awaitable))>); 690 691 static_assert(std::is_same_v< 692 net::awaitable<std::size_t>, decltype( 693 s.async_read_some(buf, net::use_awaitable))>); 694 695 static_assert(std::is_same_v< 696 net::awaitable<std::size_t>, decltype( 697 s.async_read_some(dynbuf, limit, net::use_awaitable))>); 698 } 699 #endif 700 701 void run()702 run() override 703 { 704 testRead(); 705 #if BOOST_ASIO_HAS_CO_AWAIT 706 boost::ignore_unused(&read2_test::testAwaitableCompiles); 707 #endif 708 } 709 }; 710 711 BEAST_DEFINE_TESTSUITE(beast,websocket,read2); 712 713 } // websocket 714 } // beast 715 } // boost 716