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 <boost/beast/_experimental/test/stream.hpp> 14 #include <boost/beast/_experimental/test/tcp.hpp> 15 16 #include "test.hpp" 17 18 #include <boost/asio/io_context.hpp> 19 #include <boost/asio/strand.hpp> 20 #include <thread> 21 #if BOOST_ASIO_HAS_CO_AWAIT 22 #include <boost/asio/use_awaitable.hpp> 23 #endif 24 25 namespace boost { 26 namespace beast { 27 namespace websocket { 28 29 class handshake_test : public websocket_test_suite 30 { 31 public: 32 template<class Wrap> 33 void doTestHandshake(Wrap const & w)34 doTestHandshake(Wrap const& w) 35 { 36 class req_decorator 37 { 38 bool& b_; 39 40 public: 41 req_decorator(req_decorator const&) = default; 42 43 explicit 44 req_decorator(bool& b) 45 : b_(b) 46 { 47 } 48 49 void 50 operator()(request_type&) const 51 { 52 b_ = true; 53 } 54 }; 55 56 // handshake 57 doStreamLoop([&](test::stream& ts) 58 { 59 echo_server es{log}; 60 ws_type ws{ts}; 61 ws.next_layer().connect(es.stream()); 62 try 63 { 64 w.handshake(ws, "localhost", "/"); 65 } 66 catch(...) 67 { 68 ts.close(); 69 throw; 70 } 71 ts.close(); 72 }); 73 74 // handshake, response 75 doStreamLoop([&](test::stream& ts) 76 { 77 echo_server es{log}; 78 ws_type ws{ts}; 79 ws.next_layer().connect(es.stream()); 80 response_type res; 81 try 82 { 83 w.handshake(ws, res, "localhost", "/"); 84 // VFALCO validate res? 85 } 86 catch(...) 87 { 88 ts.close(); 89 throw; 90 } 91 ts.close(); 92 }); 93 94 // handshake, decorator 95 doStreamLoop([&](test::stream& ts) 96 { 97 echo_server es{log}; 98 ws_type ws{ts}; 99 ws.next_layer().connect(es.stream()); 100 bool called = false; 101 try 102 { 103 ws.set_option(stream_base::decorator( 104 req_decorator{called})); 105 w.handshake(ws, "localhost", "/"); 106 BEAST_EXPECT(called); 107 } 108 catch(...) 109 { 110 ts.close(); 111 throw; 112 } 113 ts.close(); 114 }); 115 116 // handshake, response, decorator 117 doStreamLoop([&](test::stream& ts) 118 { 119 echo_server es{log}; 120 ws_type ws{ts}; 121 ws.next_layer().connect(es.stream()); 122 bool called = false; 123 response_type res; 124 try 125 { 126 ws.set_option(stream_base::decorator( 127 req_decorator{called})); 128 w.handshake(ws, res, "localhost", "/"); 129 // VFALCO validate res? 130 BEAST_EXPECT(called); 131 } 132 catch(...) 133 { 134 ts.close(); 135 throw; 136 } 137 ts.close(); 138 }); 139 } 140 141 void testHandshake()142 testHandshake() 143 { 144 doTestHandshake(SyncClient{}); 145 146 yield_to([&](yield_context yield) 147 { 148 doTestHandshake(AsyncClient{yield}); 149 }); 150 151 auto const check = 152 [&](error e, std::string const& s) 153 { 154 stream<test::stream> ws{ioc_}; 155 auto tr = connect(ws.next_layer()); 156 ws.next_layer().append(s); 157 tr.close(); 158 try 159 { 160 ws.handshake("localhost:80", "/"); 161 fail(); 162 } 163 catch(system_error const& se) 164 { 165 BEAST_EXPECTS(se.code() == e, se.what()); 166 } 167 }; 168 // bad HTTP version 169 check(error::bad_http_version, 170 "HTTP/1.0 101 Switching Protocols\r\n" 171 "Server: beast\r\n" 172 "Upgrade: WebSocket\r\n" 173 "Connection: upgrade\r\n" 174 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 175 "Sec-WebSocket-Version: 13\r\n" 176 "\r\n" 177 ); 178 // no Connection 179 check(error::no_connection, 180 "HTTP/1.1 101 Switching Protocols\r\n" 181 "Server: beast\r\n" 182 "Upgrade: WebSocket\r\n" 183 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 184 "Sec-WebSocket-Version: 13\r\n" 185 "\r\n" 186 ); 187 // no Connection upgrade 188 check(error::no_connection_upgrade, 189 "HTTP/1.1 101 Switching Protocols\r\n" 190 "Server: beast\r\n" 191 "Upgrade: WebSocket\r\n" 192 "Connection: keep-alive\r\n" 193 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 194 "Sec-WebSocket-Version: 13\r\n" 195 "\r\n" 196 ); 197 // no Upgrade 198 check(error::no_upgrade, 199 "HTTP/1.1 101 Switching Protocols\r\n" 200 "Server: beast\r\n" 201 "Connection: upgrade\r\n" 202 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 203 "Sec-WebSocket-Version: 13\r\n" 204 "\r\n" 205 ); 206 // no Upgrade websocket 207 check(error::no_upgrade_websocket, 208 "HTTP/1.1 101 Switching Protocols\r\n" 209 "Server: beast\r\n" 210 "Upgrade: HTTP/2\r\n" 211 "Connection: upgrade\r\n" 212 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 213 "Sec-WebSocket-Version: 13\r\n" 214 "\r\n" 215 ); 216 // no Sec-WebSocket-Accept 217 check(error::no_sec_accept, 218 "HTTP/1.1 101 Switching Protocols\r\n" 219 "Server: beast\r\n" 220 "Upgrade: WebSocket\r\n" 221 "Connection: upgrade\r\n" 222 "Sec-WebSocket-Version: 13\r\n" 223 "\r\n" 224 ); 225 // bad Sec-WebSocket-Accept 226 check(error::bad_sec_accept, 227 "HTTP/1.1 101 Switching Protocols\r\n" 228 "Server: beast\r\n" 229 "Upgrade: WebSocket\r\n" 230 "Connection: upgrade\r\n" 231 "Sec-WebSocket-Accept: *\r\n" 232 "Sec-WebSocket-Version: 13\r\n" 233 "\r\n" 234 ); 235 // declined 236 check(error::upgrade_declined, 237 "HTTP/1.1 200 OK\r\n" 238 "Server: beast\r\n" 239 "Upgrade: WebSocket\r\n" 240 "Connection: upgrade\r\n" 241 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 242 "Sec-WebSocket-Version: 13\r\n" 243 "\r\n" 244 ); 245 } 246 247 // Compression Extensions for WebSocket 248 // 249 // https://tools.ietf.org/html/rfc7692 250 // 251 void testExtRead()252 testExtRead() 253 { 254 detail::pmd_offer po; 255 256 auto const accept = 257 [&](string_view s) 258 { 259 http::fields f; 260 f.set(http::field::sec_websocket_extensions, s); 261 po = detail::pmd_offer(); 262 detail::pmd_read(po, f); 263 BEAST_EXPECT(po.accept); 264 }; 265 266 auto const reject = 267 [&](string_view s) 268 { 269 http::fields f; 270 f.set(http::field::sec_websocket_extensions, s); 271 po = detail::pmd_offer(); 272 detail::pmd_read(po, f); 273 BEAST_EXPECT(! po.accept); 274 }; 275 276 // duplicate parameters 277 reject("permessage-deflate; server_max_window_bits=8; server_max_window_bits=8"); 278 279 // missing value 280 reject("permessage-deflate; server_max_window_bits"); 281 reject("permessage-deflate; server_max_window_bits="); 282 283 // invalid value 284 reject("permessage-deflate; server_max_window_bits=-1"); 285 reject("permessage-deflate; server_max_window_bits=7"); 286 reject("permessage-deflate; server_max_window_bits=16"); 287 reject("permessage-deflate; server_max_window_bits=999999999999999999999999"); 288 reject("permessage-deflate; server_max_window_bits=9a"); 289 290 // duplicate parameters 291 reject("permessage-deflate; client_max_window_bits=8; client_max_window_bits=8"); 292 293 // optional value excluded 294 accept("permessage-deflate; client_max_window_bits"); 295 BEAST_EXPECT(po.client_max_window_bits == -1); 296 accept("permessage-deflate; client_max_window_bits="); 297 BEAST_EXPECT(po.client_max_window_bits == -1); 298 299 // invalid value 300 reject("permessage-deflate; client_max_window_bits=-1"); 301 reject("permessage-deflate; client_max_window_bits=7"); 302 reject("permessage-deflate; client_max_window_bits=16"); 303 reject("permessage-deflate; client_max_window_bits=999999999999999999999999"); 304 305 // duplicate parameters 306 reject("permessage-deflate; server_no_context_takeover; server_no_context_takeover"); 307 308 // valueless parameter 309 accept("permessage-deflate; server_no_context_takeover"); 310 BEAST_EXPECT(po.server_no_context_takeover); 311 accept("permessage-deflate; server_no_context_takeover="); 312 BEAST_EXPECT(po.server_no_context_takeover); 313 314 // disallowed value 315 reject("permessage-deflate; server_no_context_takeover=-1"); 316 reject("permessage-deflate; server_no_context_takeover=x"); 317 reject("permessage-deflate; server_no_context_takeover=\"yz\""); 318 reject("permessage-deflate; server_no_context_takeover=999999999999999999999999"); 319 320 // duplicate parameters 321 reject("permessage-deflate; client_no_context_takeover; client_no_context_takeover"); 322 323 // valueless parameter 324 accept("permessage-deflate; client_no_context_takeover"); 325 BEAST_EXPECT(po.client_no_context_takeover); 326 accept("permessage-deflate; client_no_context_takeover="); 327 BEAST_EXPECT(po.client_no_context_takeover); 328 329 // disallowed value 330 reject("permessage-deflate; client_no_context_takeover=-1"); 331 reject("permessage-deflate; client_no_context_takeover=x"); 332 reject("permessage-deflate; client_no_context_takeover=\"yz\""); 333 reject("permessage-deflate; client_no_context_takeover=999999999999999999999999"); 334 335 // unknown extension parameter 336 reject("permessage-deflate; unknown"); 337 reject("permessage-deflate; unknown="); 338 reject("permessage-deflate; unknown=1"); 339 reject("permessage-deflate; unknown=x"); 340 reject("permessage-deflate; unknown=\"xy\""); 341 } 342 343 void testExtWrite()344 testExtWrite() 345 { 346 detail::pmd_offer po; 347 348 auto const check = 349 [&](string_view match) 350 { 351 http::fields f; 352 detail::pmd_write(f, po); 353 BEAST_EXPECT( 354 f[http::field::sec_websocket_extensions] 355 == match); 356 }; 357 358 po.accept = true; 359 po.server_max_window_bits = 0; 360 po.client_max_window_bits = 0; 361 po.server_no_context_takeover = false; 362 po.client_no_context_takeover = false; 363 364 check("permessage-deflate"); 365 366 po.server_max_window_bits = 10; 367 check("permessage-deflate; server_max_window_bits=10"); 368 369 po.server_max_window_bits = -1; 370 check("permessage-deflate; server_max_window_bits"); 371 372 po.server_max_window_bits = 0; 373 po.client_max_window_bits = 10; 374 check("permessage-deflate; client_max_window_bits=10"); 375 376 po.client_max_window_bits = -1; 377 check("permessage-deflate; client_max_window_bits"); 378 379 po.client_max_window_bits = 0; 380 po.server_no_context_takeover = true; 381 check("permessage-deflate; server_no_context_takeover"); 382 383 po.server_no_context_takeover = false; 384 po.client_no_context_takeover = true; 385 check("permessage-deflate; client_no_context_takeover"); 386 } 387 388 void testExtNegotiate()389 testExtNegotiate() 390 { 391 permessage_deflate pmd; 392 393 auto const reject = 394 [&]( 395 string_view offer) 396 { 397 detail::pmd_offer po; 398 { 399 http::fields f; 400 f.set(http::field::sec_websocket_extensions, offer); 401 detail::pmd_read(po, f); 402 } 403 http::fields f; 404 detail::pmd_offer config; 405 detail::pmd_negotiate(f, config, po, pmd); 406 BEAST_EXPECT(! config.accept); 407 }; 408 409 auto const accept = 410 [&]( 411 string_view offer, 412 string_view result) 413 { 414 detail::pmd_offer po; 415 { 416 http::fields f; 417 f.set(http::field::sec_websocket_extensions, offer); 418 detail::pmd_read(po, f); 419 } 420 http::fields f; 421 detail::pmd_offer config; 422 detail::pmd_negotiate(f, config, po, pmd); 423 auto const got = 424 f[http::field::sec_websocket_extensions]; 425 BEAST_EXPECTS(got == result, got); 426 { 427 detail::pmd_offer poc; 428 detail::pmd_read(poc, f); 429 detail::pmd_normalize(poc); 430 BEAST_EXPECT(poc.accept); 431 } 432 BEAST_EXPECT(config.server_max_window_bits != 0); 433 BEAST_EXPECT(config.client_max_window_bits != 0); 434 }; 435 436 pmd.server_enable = true; 437 pmd.server_max_window_bits = 15; 438 pmd.client_max_window_bits = 15; 439 pmd.server_no_context_takeover = false; 440 pmd.client_no_context_takeover = false; 441 442 // default 443 accept( 444 "permessage-deflate", 445 "permessage-deflate"); 446 447 // non-default server_max_window_bits 448 accept( 449 "permessage-deflate; server_max_window_bits=14", 450 "permessage-deflate; server_max_window_bits=14"); 451 452 // explicit default server_max_window_bits 453 accept( 454 "permessage-deflate; server_max_window_bits=15", 455 "permessage-deflate"); 456 457 // minimum window size of 8 bits (a zlib bug) 458 accept( 459 "permessage-deflate; server_max_window_bits=8", 460 "permessage-deflate; server_max_window_bits=9"); 461 462 // non-default server_max_window_bits setting 463 pmd.server_max_window_bits = 10; 464 accept( 465 "permessage-deflate", 466 "permessage-deflate; server_max_window_bits=10"); 467 468 // clamped server_max_window_bits setting #1 469 pmd.server_max_window_bits = 10; 470 accept( 471 "permessage-deflate; server_max_window_bits=14", 472 "permessage-deflate; server_max_window_bits=10"); 473 474 // clamped server_max_window_bits setting #2 475 pmd.server_max_window_bits=8; 476 accept( 477 "permessage-deflate; server_max_window_bits=14", 478 "permessage-deflate; server_max_window_bits=9"); 479 480 pmd.server_max_window_bits = 15; 481 482 // present with no value 483 accept( 484 "permessage-deflate; client_max_window_bits", 485 "permessage-deflate"); 486 487 // present with no value, non-default setting 488 pmd.client_max_window_bits = 10; 489 accept( 490 "permessage-deflate; client_max_window_bits", 491 "permessage-deflate; client_max_window_bits=10"); 492 493 // absent, non-default setting 494 pmd.client_max_window_bits = 10; 495 reject( 496 "permessage-deflate"); 497 } 498 499 void testMoveOnly()500 testMoveOnly() 501 { 502 net::io_context ioc; 503 stream<test::stream> ws{ioc}; 504 ws.async_handshake("", "", move_only_handler{}); 505 } 506 507 struct copyable_handler 508 { 509 template<class... Args> 510 void operator ()boost::beast::websocket::handshake_test::copyable_handler511 operator()(Args&&...) const 512 { 513 } 514 }; 515 516 void testAsync()517 testAsync() 518 { 519 using tcp = net::ip::tcp; 520 521 net::io_context ioc; 522 523 // success, no timeout 524 525 { 526 stream<tcp::socket> ws1(ioc); 527 stream<tcp::socket> ws2(ioc); 528 test::connect(ws1.next_layer(), ws2.next_layer()); 529 530 ws1.async_handshake("test", "/", test::success_handler()); 531 ws2.async_accept(test::success_handler()); 532 test::run_for(ioc, std::chrono::seconds(1)); 533 } 534 535 { 536 stream<test::stream> ws1(ioc); 537 stream<test::stream> ws2(ioc); 538 test::connect(ws1.next_layer(), ws2.next_layer()); 539 540 ws1.async_handshake("test", "/", test::success_handler()); 541 ws2.async_accept(test::success_handler()); 542 test::run_for(ioc, std::chrono::seconds(1)); 543 } 544 545 // success, timeout enabled 546 547 { 548 stream<tcp::socket> ws1(ioc); 549 stream<tcp::socket> ws2(ioc); 550 test::connect(ws1.next_layer(), ws2.next_layer()); 551 552 ws1.set_option(stream_base::timeout{ 553 std::chrono::milliseconds(50), 554 stream_base::none(), 555 false}); 556 ws1.async_handshake("test", "/", test::success_handler()); 557 ws2.async_accept(test::success_handler()); 558 test::run_for(ioc, std::chrono::seconds(1)); 559 } 560 561 { 562 stream<test::stream> ws1(ioc); 563 stream<test::stream> ws2(ioc); 564 test::connect(ws1.next_layer(), ws2.next_layer()); 565 566 ws1.set_option(stream_base::timeout{ 567 std::chrono::milliseconds(50), 568 stream_base::none(), 569 false}); 570 ws1.async_handshake("test", "/", test::success_handler()); 571 ws2.async_accept(test::success_handler()); 572 test::run_for(ioc, std::chrono::seconds(1)); 573 } 574 575 // timeout 576 577 { 578 stream<tcp::socket> ws1(ioc); 579 stream<tcp::socket> ws2(ioc); 580 test::connect(ws1.next_layer(), ws2.next_layer()); 581 582 ws1.set_option(stream_base::timeout{ 583 std::chrono::milliseconds(50), 584 stream_base::none(), 585 false}); 586 ws1.async_handshake("test", "/", 587 test::fail_handler(beast::error::timeout)); 588 test::run_for(ioc, std::chrono::seconds(1)); 589 } 590 591 { 592 stream<test::stream> ws1(ioc); 593 stream<test::stream> ws2(ioc); 594 test::connect(ws1.next_layer(), ws2.next_layer()); 595 596 ws1.set_option(stream_base::timeout{ 597 std::chrono::milliseconds(50), 598 stream_base::none(), 599 false}); 600 ws1.async_handshake("test", "/", 601 test::fail_handler(beast::error::timeout)); 602 test::run_for(ioc, std::chrono::seconds(1)); 603 } 604 605 // abandoned operation 606 607 { 608 { 609 stream<tcp::socket> ws1(ioc); 610 ws1.async_handshake("test", "/", 611 test::fail_handler( 612 net::error::operation_aborted)); 613 } 614 test::run(ioc); 615 } 616 } 617 618 // https://github.com/boostorg/beast/issues/1460 619 void testIssue1460()620 testIssue1460() 621 { 622 net::io_context ioc; 623 auto const make_big = [](response_type& res) 624 { 625 res.insert("Date", "Mon, 18 Feb 2019 12:48:36 GMT"); 626 res.insert("Set-Cookie", 627 "__cfduid=de1e209833e7f05aaa1044c6d448994761550494116; " 628 "expires=Tue, 18-Feb-20 12:48:36 GMT; path=/; domain=.cryptofacilities.com; HttpOnly; Secure"); 629 res.insert("Feature-Policy", 630 "accelerometer 'none'; ambient-light-sensor 'none'; " 631 "animations 'none'; autoplay 'none'; camera 'none'; document-write 'none'; " 632 "encrypted-media 'none'; geolocation 'none'; gyroscope 'none'; legacy-image-formats 'none'; " 633 "magnetometer 'none'; max-downscaling-image 'none'; microphone 'none'; midi 'none'; " 634 "payment 'none'; picture-in-picture 'none'; unsized-media 'none'; usb 'none'; vr 'none'"); 635 res.insert("Referrer-Policy", "origin"); 636 res.insert("Strict-Transport-Security", "max-age=15552000; includeSubDomains; preload"); 637 res.insert("X-Content-Type-Options", "nosniff"); 638 res.insert("Content-Security-Policy", 639 "default-src 'none'; manifest-src 'self'; object-src 'self'; " 640 "child-src 'self' https://www.google.com; " 641 "font-src 'self' https://use.typekit.net https://maxcdn.bootstrapcdn.com https://fonts.gstatic.com data:; " 642 "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.cloudflare.com https://use.typekit.net " 643 "https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com https://www.googleadservices.com " 644 "https://googleads.g.doubleclick.net https://www.gstatic.com; connect-src 'self' wss://*.cryptofacilities.com/ws/v1 wss://*.cryptofacilities.com/ws/indices " 645 "https://uat.cryptofacilities.com https://uat.cf0.io wss://*.cf0.io https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com " 646 "https://fonts.googleapis.com https://google-analytics.com https://use.typekit.net https://p.typekit.net https://fonts.gstatic.com https://www.gstatic.com " 647 "https://chart.googleapis.com; worker-src 'self'; img-src 'self' https://chart.googleapis.com https://p.typekit.net https://www.google.co.uk https://www.google.com " 648 "https://www.google-analytics.com https://stats.g.doubleclick.net data:; style-src 'self' 'unsafe-inline' https://use.typekit.net https://p.typekit.net " 649 "https://fonts.googleapis.com https://maxcdn.bootstrapcdn.com"); 650 res.insert("X-Frame-Options", "SAMEORIGIN"); 651 res.insert("X-Xss-Protection", "1; mode=block"); 652 res.insert("Expect-CT", "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""); 653 res.insert("Server", "cloudflare"); 654 res.insert("CF-RAY", "4ab09be1a9d0cb06-ARN"); 655 res.insert("Bulk", 656 "****************************************************************************************************" 657 "****************************************************************************************************" 658 "****************************************************************************************************" 659 "****************************************************************************************************" 660 "****************************************************************************************************" 661 "****************************************************************************************************" 662 "****************************************************************************************************" 663 "****************************************************************************************************" 664 "****************************************************************************************************" 665 "****************************************************************************************************" 666 "****************************************************************************************************" 667 "****************************************************************************************************" 668 "****************************************************************************************************" 669 "****************************************************************************************************" 670 "****************************************************************************************************" 671 "****************************************************************************************************" 672 "****************************************************************************************************" 673 "****************************************************************************************************" 674 "****************************************************************************************************" 675 "****************************************************************************************************"); 676 }; 677 678 { 679 stream<test::stream> ws1(ioc); 680 stream<test::stream> ws2(ioc); 681 test::connect(ws1.next_layer(), ws2.next_layer()); 682 683 ws2.set_option(stream_base::decorator(make_big)); 684 error_code ec; 685 ws2.async_accept(test::success_handler()); 686 std::thread t( 687 [&ioc] 688 { 689 ioc.run(); 690 ioc.restart(); 691 }); 692 ws1.handshake("test", "/", ec); 693 BEAST_EXPECTS(! ec, ec.message()); 694 t.join(); 695 } 696 697 { 698 stream<test::stream> ws1(ioc); 699 stream<test::stream> ws2(ioc); 700 test::connect(ws1.next_layer(), ws2.next_layer()); 701 702 ws2.set_option(stream_base::decorator(make_big)); 703 ws2.async_accept(test::success_handler()); 704 ws1.async_handshake("test", "/", test::success_handler()); 705 ioc.run(); 706 ioc.restart(); 707 } 708 } 709 710 #if BOOST_ASIO_HAS_CO_AWAIT testAwaitableCompiles(stream<test::stream> & s,std::string host,std::string port,response_type & resp)711 void testAwaitableCompiles( 712 stream<test::stream>& s, 713 std::string host, 714 std::string port, 715 response_type& resp) 716 { 717 static_assert(std::is_same_v< 718 net::awaitable<void>, decltype( 719 s.async_handshake(host, port, net::use_awaitable))>); 720 721 static_assert(std::is_same_v< 722 net::awaitable<void>, decltype( 723 s.async_handshake(resp, host, port, net::use_awaitable))>); 724 } 725 #endif 726 727 void run()728 run() override 729 { 730 testHandshake(); 731 testExtRead(); 732 testExtWrite(); 733 testExtNegotiate(); 734 testMoveOnly(); 735 testAsync(); 736 testIssue1460(); 737 #if BOOST_ASIO_HAS_CO_AWAIT 738 boost::ignore_unused(&handshake_test::testAwaitableCompiles); 739 #endif 740 } 741 }; 742 743 BEAST_DEFINE_TESTSUITE(beast,websocket,handshake); 744 745 } // websocket 746 } // beast 747 } // boost 748