1import struct 2import time 3 4import pytest 5from packaging import version 6 7from unit.applications.lang.python import ApplicationPython 8from unit.applications.websockets import ApplicationWebsocket 9 10prerequisites = { 11 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')} 12} 13 14client = ApplicationPython(load_module='asgi') 15ws = ApplicationWebsocket() 16 17 18@pytest.fixture(autouse=True) 19def setup_method_fixture(skip_alert): 20 assert 'success' in client.conf( 21 {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' 22 ), 'clear keepalive_interval' 23 24 skip_alert(r'socket close\(\d+\) failed') 25 26 27def close_connection(sock): 28 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' 29 30 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 31 32 check_close(sock) 33 34 35def check_close(sock, code=1000, no_close=False, frame=None): 36 if frame is None: 37 frame = ws.frame_read(sock) 38 39 assert frame['fin'], 'close fin' 40 assert frame['opcode'] == ws.OP_CLOSE, 'close opcode' 41 assert frame['code'] == code, 'close code' 42 43 if not no_close: 44 sock.close() 45 46 47def check_frame(frame, fin, opcode, payload, decode=True): 48 if opcode == ws.OP_BINARY or not decode: 49 data = frame['data'] 50 else: 51 data = frame['data'].decode('utf-8') 52 53 assert frame['fin'] == fin, 'fin' 54 assert frame['opcode'] == opcode, 'opcode' 55 assert data == payload, 'payload' 56 57 58def test_asgi_websockets_handshake(): 59 client.load('websockets/mirror') 60 61 resp, sock, key = ws.upgrade() 62 sock.close() 63 64 assert resp['status'] == 101, 'status' 65 assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' 66 assert resp['headers']['Connection'] == 'Upgrade', 'connection' 67 assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' 68 69 # remove "mirror" application 70 client.load('websockets/subprotocol') 71 72 73def test_asgi_websockets_subprotocol(): 74 client.load('websockets/subprotocol') 75 76 resp, sock, _ = ws.upgrade() 77 sock.close() 78 79 assert resp['status'] == 101, 'status' 80 assert ( 81 resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')" 82 ), 'subprotocols' 83 assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key' 84 85 86def test_asgi_websockets_mirror(): 87 client.load('websockets/mirror') 88 89 message = 'blah' 90 91 _, sock, _ = ws.upgrade() 92 93 ws.frame_write(sock, ws.OP_TEXT, message) 94 frame = ws.frame_read(sock) 95 96 assert message == frame['data'].decode('utf-8'), 'mirror' 97 98 ws.frame_write(sock, ws.OP_TEXT, message) 99 frame = ws.frame_read(sock) 100 101 assert message == frame['data'].decode('utf-8'), 'mirror 2' 102 103 sock.close() 104 105 106def test_asgi_websockets_mirror_app_change(): 107 client.load('websockets/mirror') 108 109 message = 'blah' 110 111 _, sock, _ = ws.upgrade() 112 113 ws.frame_write(sock, ws.OP_TEXT, message) 114 frame = ws.frame_read(sock) 115 116 assert message == frame['data'].decode('utf-8'), 'mirror' 117 118 client.load('websockets/subprotocol') 119 120 ws.frame_write(sock, ws.OP_TEXT, message) 121 frame = ws.frame_read(sock) 122 123 assert message == frame['data'].decode('utf-8'), 'mirror 2' 124 125 sock.close() 126 127 128def test_asgi_websockets_no_mask(): 129 client.load('websockets/mirror') 130 131 message = 'blah' 132 133 _, sock, _ = ws.upgrade() 134 135 ws.frame_write(sock, ws.OP_TEXT, message, mask=False) 136 137 frame = ws.frame_read(sock) 138 139 assert frame['opcode'] == ws.OP_CLOSE, 'no mask opcode' 140 assert frame['code'] == 1002, 'no mask close code' 141 142 sock.close() 143 144 145def test_asgi_websockets_fragmentation(): 146 client.load('websockets/mirror') 147 148 message = 'blah' 149 150 _, sock, _ = ws.upgrade() 151 152 ws.frame_write(sock, ws.OP_TEXT, message, fin=False) 153 ws.frame_write(sock, ws.OP_CONT, ' ', fin=False) 154 ws.frame_write(sock, ws.OP_CONT, message) 155 156 frame = ws.frame_read(sock) 157 158 assert f'{message} {message}' == frame['data'].decode( 159 'utf-8' 160 ), 'mirror framing' 161 162 sock.close() 163 164 165def test_asgi_websockets_length_long(): 166 client.load('websockets/mirror') 167 168 _, sock, _ = ws.upgrade() 169 170 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 171 ws.frame_write(sock, ws.OP_CONT, 'fragment2', length=2**64 - 1) 172 173 check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE 174 175 176def test_asgi_websockets_frame_fragmentation_invalid(): 177 client.load('websockets/mirror') 178 179 message = 'blah' 180 181 _, sock, _ = ws.upgrade() 182 183 ws.frame_write(sock, ws.OP_PING, message, fin=False) 184 185 frame = ws.frame_read(sock) 186 187 frame.pop('data') 188 assert frame == { 189 'fin': True, 190 'rsv1': False, 191 'rsv2': False, 192 'rsv3': False, 193 'opcode': ws.OP_CLOSE, 194 'mask': 0, 195 'code': 1002, 196 'reason': 'Fragmented control frame', 197 }, 'close frame' 198 199 sock.close() 200 201 202def test_asgi_websockets_large(): 203 client.load('websockets/mirror') 204 205 message = '0123456789' * 300 206 207 _, sock, _ = ws.upgrade() 208 209 ws.frame_write(sock, ws.OP_TEXT, message) 210 211 frame = ws.frame_read(sock) 212 data = frame['data'].decode('utf-8') 213 214 frame = ws.frame_read(sock) 215 data += frame['data'].decode('utf-8') 216 217 assert message == data, 'large' 218 219 sock.close() 220 221 222def test_asgi_websockets_two_clients(): 223 client.load('websockets/mirror') 224 225 message1 = 'blah1' 226 message2 = 'blah2' 227 228 _, sock1, _ = ws.upgrade() 229 _, sock2, _ = ws.upgrade() 230 231 ws.frame_write(sock1, ws.OP_TEXT, message1) 232 ws.frame_write(sock2, ws.OP_TEXT, message2) 233 234 frame1 = ws.frame_read(sock1) 235 frame2 = ws.frame_read(sock2) 236 237 assert message1 == frame1['data'].decode('utf-8'), 'client 1' 238 assert message2 == frame2['data'].decode('utf-8'), 'client 2' 239 240 sock1.close() 241 sock2.close() 242 243 244# FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 245@pytest.mark.skip('not yet') 246def test_asgi_websockets_handshake_upgrade_absent(): 247 client.load('websockets/mirror') 248 249 resp = client.get( 250 headers={ 251 'Host': 'localhost', 252 'Connection': 'Upgrade', 253 'Sec-WebSocket-Key': ws.key(), 254 'Sec-WebSocket-Protocol': 'chat', 255 'Sec-WebSocket-Version': 13, 256 }, 257 ) 258 259 assert resp['status'] == 400, 'upgrade absent' 260 261 262def test_asgi_websockets_handshake_case_insensitive(): 263 client.load('websockets/mirror') 264 265 resp, sock, _ = ws.upgrade( 266 headers={ 267 'Host': 'localhost', 268 'Upgrade': 'WEBSOCKET', 269 'Connection': 'UPGRADE', 270 'Sec-WebSocket-Key': ws.key(), 271 'Sec-WebSocket-Protocol': 'chat', 272 'Sec-WebSocket-Version': 13, 273 } 274 ) 275 sock.close() 276 277 assert resp['status'] == 101, 'status' 278 279 280@pytest.mark.skip('not yet') 281def test_asgi_websockets_handshake_connection_absent(): # FAIL 282 client.load('websockets/mirror') 283 284 resp = client.get( 285 headers={ 286 'Host': 'localhost', 287 'Upgrade': 'websocket', 288 'Sec-WebSocket-Key': ws.key(), 289 'Sec-WebSocket-Protocol': 'chat', 290 'Sec-WebSocket-Version': 13, 291 }, 292 ) 293 294 assert resp['status'] == 400, 'status' 295 296 297def test_asgi_websockets_handshake_version_absent(): 298 client.load('websockets/mirror') 299 300 resp = client.get( 301 headers={ 302 'Host': 'localhost', 303 'Upgrade': 'websocket', 304 'Connection': 'Upgrade', 305 'Sec-WebSocket-Key': ws.key(), 306 'Sec-WebSocket-Protocol': 'chat', 307 }, 308 ) 309 310 assert resp['status'] == 426, 'status' 311 312 313@pytest.mark.skip('not yet') 314def test_asgi_websockets_handshake_key_invalid(): 315 client.load('websockets/mirror') 316 317 resp = client.get( 318 headers={ 319 'Host': 'localhost', 320 'Upgrade': 'websocket', 321 'Connection': 'Upgrade', 322 'Sec-WebSocket-Key': '!', 323 'Sec-WebSocket-Protocol': 'chat', 324 'Sec-WebSocket-Version': 13, 325 }, 326 ) 327 328 assert resp['status'] == 400, 'key length' 329 330 key = ws.key() 331 resp = client.get( 332 headers={ 333 'Host': 'localhost', 334 'Upgrade': 'websocket', 335 'Connection': 'Upgrade', 336 'Sec-WebSocket-Key': [key, key], 337 'Sec-WebSocket-Protocol': 'chat', 338 'Sec-WebSocket-Version': 13, 339 }, 340 ) 341 342 assert ( 343 resp['status'] == 400 344 ), 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 345 346 347def test_asgi_websockets_handshake_method_invalid(): 348 client.load('websockets/mirror') 349 350 resp = client.post( 351 headers={ 352 'Host': 'localhost', 353 'Upgrade': 'websocket', 354 'Connection': 'Upgrade', 355 'Sec-WebSocket-Key': ws.key(), 356 'Sec-WebSocket-Protocol': 'chat', 357 'Sec-WebSocket-Version': 13, 358 }, 359 ) 360 361 assert resp['status'] == 400, 'status' 362 363 364def test_asgi_websockets_handshake_http_10(): 365 client.load('websockets/mirror') 366 367 resp = client.get( 368 headers={ 369 'Host': 'localhost', 370 'Upgrade': 'websocket', 371 'Connection': 'Upgrade', 372 'Sec-WebSocket-Key': ws.key(), 373 'Sec-WebSocket-Protocol': 'chat', 374 'Sec-WebSocket-Version': 13, 375 }, 376 http_10=True, 377 ) 378 379 assert resp['status'] == 400, 'status' 380 381 382def test_asgi_websockets_handshake_uri_invalid(): 383 client.load('websockets/mirror') 384 385 resp = client.get( 386 headers={ 387 'Host': 'localhost', 388 'Upgrade': 'websocket', 389 'Connection': 'Upgrade', 390 'Sec-WebSocket-Key': ws.key(), 391 'Sec-WebSocket-Protocol': 'chat', 392 'Sec-WebSocket-Version': 13, 393 }, 394 url='!', 395 ) 396 397 assert resp['status'] == 400, 'status' 398 399 400def test_asgi_websockets_protocol_absent(): 401 client.load('websockets/mirror') 402 403 key = ws.key() 404 resp, sock, _ = ws.upgrade( 405 headers={ 406 'Host': 'localhost', 407 'Upgrade': 'websocket', 408 'Connection': 'Upgrade', 409 'Sec-WebSocket-Key': key, 410 'Sec-WebSocket-Version': 13, 411 } 412 ) 413 sock.close() 414 415 assert resp['status'] == 101, 'status' 416 assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' 417 assert resp['headers']['Connection'] == 'Upgrade', 'connection' 418 assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' 419 420 421# autobahn-testsuite 422# 423# Some following tests fail because of Unit does not support UTF-8 424# validation for websocket frames. It should be implemented 425# by application, if necessary. 426 427 428def test_asgi_websockets_1_1_1__1_1_8(): 429 client.load('websockets/mirror') 430 431 opcode = ws.OP_TEXT 432 433 _, sock, _ = ws.upgrade() 434 435 def check_length(length, chopsize=None): 436 payload = '*' * length 437 438 ws.frame_write(sock, opcode, payload, chopsize=chopsize) 439 440 frame = ws.frame_read(sock) 441 check_frame(frame, True, opcode, payload) 442 443 check_length(0) # 1_1_1 444 check_length(125) # 1_1_2 445 check_length(126) # 1_1_3 446 check_length(127) # 1_1_4 447 check_length(128) # 1_1_5 448 check_length(65535) # 1_1_6 449 check_length(65536) # 1_1_7 450 check_length(65536, chopsize=997) # 1_1_8 451 452 close_connection(sock) 453 454 455def test_asgi_websockets_1_2_1__1_2_8(): 456 client.load('websockets/mirror') 457 458 opcode = ws.OP_BINARY 459 460 _, sock, _ = ws.upgrade() 461 462 def check_length(length, chopsize=None): 463 payload = b'\xfe' * length 464 465 ws.frame_write(sock, opcode, payload, chopsize=chopsize) 466 frame = ws.frame_read(sock) 467 468 check_frame(frame, True, opcode, payload) 469 470 check_length(0) # 1_2_1 471 check_length(125) # 1_2_2 472 check_length(126) # 1_2_3 473 check_length(127) # 1_2_4 474 check_length(128) # 1_2_5 475 check_length(65535) # 1_2_6 476 check_length(65536) # 1_2_7 477 check_length(65536, chopsize=997) # 1_2_8 478 479 close_connection(sock) 480 481 482def test_asgi_websockets_2_1__2_6(): 483 client.load('websockets/mirror') 484 485 op_ping = ws.OP_PING 486 op_pong = ws.OP_PONG 487 488 _, sock, _ = ws.upgrade() 489 490 def check_ping(payload, chopsize=None, decode=True): 491 ws.frame_write(sock, op_ping, payload, chopsize=chopsize) 492 frame = ws.frame_read(sock) 493 494 check_frame(frame, True, op_pong, payload, decode=decode) 495 496 check_ping('') # 2_1 497 check_ping('Hello, world!') # 2_2 498 check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False) # 2_3 499 check_ping(b'\xfe' * 125, decode=False) # 2_4 500 check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 501 502 close_connection(sock) 503 504 # 2_5 505 506 _, sock, _ = ws.upgrade() 507 508 ws.frame_write(sock, ws.OP_PING, b'\xfe' * 126) 509 check_close(sock, 1002) 510 511 512def test_asgi_websockets_2_7__2_9(): 513 client.load('websockets/mirror') 514 515 # 2_7 516 517 _, sock, _ = ws.upgrade() 518 519 ws.frame_write(sock, ws.OP_PONG, '') 520 assert client.recvall(sock, read_timeout=0.1) == b'', '2_7' 521 522 # 2_8 523 524 ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') 525 assert client.recvall(sock, read_timeout=0.1) == b'', '2_8' 526 527 # 2_9 528 529 payload = 'ping payload' 530 531 ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') 532 ws.frame_write(sock, ws.OP_PING, payload) 533 534 frame = ws.frame_read(sock) 535 check_frame(frame, True, ws.OP_PONG, payload) 536 537 close_connection(sock) 538 539 540def test_asgi_websockets_2_10__2_11(): 541 client.load('websockets/mirror') 542 543 # 2_10 544 545 _, sock, _ = ws.upgrade() 546 547 for i in range(0, 10): 548 ws.frame_write(sock, ws.OP_PING, f'payload-{i}') 549 550 for i in range(0, 10): 551 frame = ws.frame_read(sock) 552 check_frame(frame, True, ws.OP_PONG, f'payload-{i}') 553 554 # 2_11 555 556 for i in range(0, 10): 557 opcode = ws.OP_PING 558 ws.frame_write(sock, opcode, f'payload-{i}', chopsize=1) 559 560 for i in range(0, 10): 561 frame = ws.frame_read(sock) 562 check_frame(frame, True, ws.OP_PONG, f'payload-{i}') 563 564 close_connection(sock) 565 566 567@pytest.mark.skip('not yet') 568def test_asgi_websockets_3_1__3_7(): 569 client.load('websockets/mirror') 570 571 payload = 'Hello, world!' 572 573 # 3_1 574 575 _, sock, _ = ws.upgrade() 576 577 ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True) 578 check_close(sock, 1002) 579 580 # 3_2 581 582 _, sock, _ = ws.upgrade() 583 584 ws.frame_write(sock, ws.OP_TEXT, payload) 585 ws.frame_write(sock, ws.OP_TEXT, payload, rsv2=True) 586 ws.frame_write(sock, ws.OP_PING, '') 587 588 frame = ws.frame_read(sock) 589 check_frame(frame, True, ws.OP_TEXT, payload) 590 591 check_close(sock, 1002, no_close=True) 592 593 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' 594 sock.close() 595 596 # 3_3 597 598 _, sock, _ = ws.upgrade() 599 600 ws.frame_write(sock, ws.OP_TEXT, payload) 601 602 frame = ws.frame_read(sock) 603 check_frame(frame, True, ws.OP_TEXT, payload) 604 605 ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True, rsv2=True) 606 607 check_close(sock, 1002, no_close=True) 608 609 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' 610 sock.close() 611 612 # 3_4 613 614 _, sock, _ = ws.upgrade() 615 616 ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) 617 ws.frame_write(sock, ws.OP_TEXT, payload, rsv3=True, chopsize=1) 618 ws.frame_write(sock, ws.OP_PING, '') 619 620 frame = ws.frame_read(sock) 621 check_frame(frame, True, ws.OP_TEXT, payload) 622 623 check_close(sock, 1002, no_close=True) 624 625 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' 626 sock.close() 627 628 # 3_5 629 630 _, sock, _ = ws.upgrade() 631 632 ws.frame_write( 633 sock, 634 ws.OP_BINARY, 635 b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', 636 rsv1=True, 637 rsv3=True, 638 ) 639 640 check_close(sock, 1002) 641 642 # 3_6 643 644 _, sock, _ = ws.upgrade() 645 646 ws.frame_write(sock, ws.OP_PING, payload, rsv2=True, rsv3=True) 647 648 check_close(sock, 1002) 649 650 # 3_7 651 652 _, sock, _ = ws.upgrade() 653 654 ws.frame_write(sock, ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True) 655 656 check_close(sock, 1002) 657 658 659def test_asgi_websockets_4_1_1__4_2_5(): 660 client.load('websockets/mirror') 661 662 payload = 'Hello, world!' 663 664 # 4_1_1 665 666 _, sock, _ = ws.upgrade() 667 668 ws.frame_write(sock, 0x03, '') 669 check_close(sock, 1002) 670 671 # 4_1_2 672 673 _, sock, _ = ws.upgrade() 674 675 ws.frame_write(sock, 0x04, 'reserved opcode payload') 676 check_close(sock, 1002) 677 678 # 4_1_3 679 680 _, sock, _ = ws.upgrade() 681 682 ws.frame_write(sock, ws.OP_TEXT, payload) 683 684 frame = ws.frame_read(sock) 685 check_frame(frame, True, ws.OP_TEXT, payload) 686 687 ws.frame_write(sock, 0x05, '') 688 ws.frame_write(sock, ws.OP_PING, '') 689 690 check_close(sock, 1002) 691 692 # 4_1_4 693 694 _, sock, _ = ws.upgrade() 695 696 ws.frame_write(sock, ws.OP_TEXT, payload) 697 698 frame = ws.frame_read(sock) 699 check_frame(frame, True, ws.OP_TEXT, payload) 700 701 ws.frame_write(sock, 0x06, payload) 702 ws.frame_write(sock, ws.OP_PING, '') 703 704 check_close(sock, 1002) 705 706 # 4_1_5 707 708 _, sock, _ = ws.upgrade() 709 710 ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) 711 712 frame = ws.frame_read(sock) 713 check_frame(frame, True, ws.OP_TEXT, payload) 714 715 ws.frame_write(sock, 0x07, payload, chopsize=1) 716 ws.frame_write(sock, ws.OP_PING, '') 717 718 check_close(sock, 1002) 719 720 # 4_2_1 721 722 _, sock, _ = ws.upgrade() 723 724 ws.frame_write(sock, 0x0B, '') 725 check_close(sock, 1002) 726 727 # 4_2_2 728 729 _, sock, _ = ws.upgrade() 730 731 ws.frame_write(sock, 0x0C, 'reserved opcode payload') 732 check_close(sock, 1002) 733 734 # 4_2_3 735 736 _, sock, _ = ws.upgrade() 737 738 ws.frame_write(sock, ws.OP_TEXT, payload) 739 740 frame = ws.frame_read(sock) 741 check_frame(frame, True, ws.OP_TEXT, payload) 742 743 ws.frame_write(sock, 0x0D, '') 744 ws.frame_write(sock, ws.OP_PING, '') 745 746 check_close(sock, 1002) 747 748 # 4_2_4 749 750 _, sock, _ = ws.upgrade() 751 752 ws.frame_write(sock, ws.OP_TEXT, payload) 753 754 frame = ws.frame_read(sock) 755 check_frame(frame, True, ws.OP_TEXT, payload) 756 757 ws.frame_write(sock, 0x0E, payload) 758 ws.frame_write(sock, ws.OP_PING, '') 759 760 check_close(sock, 1002) 761 762 # 4_2_5 763 764 _, sock, _ = ws.upgrade() 765 766 ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) 767 768 frame = ws.frame_read(sock) 769 check_frame(frame, True, ws.OP_TEXT, payload) 770 771 ws.frame_write(sock, 0x0F, payload, chopsize=1) 772 ws.frame_write(sock, ws.OP_PING, '') 773 774 check_close(sock, 1002) 775 776 777def test_asgi_websockets_5_1__5_20(): 778 client.load('websockets/mirror') 779 780 # 5_1 781 782 _, sock, _ = ws.upgrade() 783 784 ws.frame_write(sock, ws.OP_PING, 'fragment1', fin=False) 785 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 786 check_close(sock, 1002) 787 788 # 5_2 789 790 _, sock, _ = ws.upgrade() 791 792 ws.frame_write(sock, ws.OP_PONG, 'fragment1', fin=False) 793 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 794 check_close(sock, 1002) 795 796 # 5_3 797 798 _, sock, _ = ws.upgrade() 799 800 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 801 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 802 803 frame = ws.frame_read(sock) 804 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 805 806 # 5_4 807 808 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 809 assert client.recvall(sock, read_timeout=0.1) == b'', '5_4' 810 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 811 812 frame = ws.frame_read(sock) 813 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 814 815 # 5_5 816 817 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) 818 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) 819 820 frame = ws.frame_read(sock) 821 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 822 823 # 5_6 824 825 ping_payload = 'ping payload' 826 827 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 828 ws.frame_write(sock, ws.OP_PING, ping_payload) 829 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 830 831 frame = ws.frame_read(sock) 832 check_frame(frame, True, ws.OP_PONG, ping_payload) 833 834 frame = ws.frame_read(sock) 835 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 836 837 # 5_7 838 839 ping_payload = 'ping payload' 840 841 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 842 assert client.recvall(sock, read_timeout=0.1) == b'', '5_7' 843 844 ws.frame_write(sock, ws.OP_PING, ping_payload) 845 846 frame = ws.frame_read(sock) 847 check_frame(frame, True, ws.OP_PONG, ping_payload) 848 849 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 850 851 frame = ws.frame_read(sock) 852 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 853 854 # 5_8 855 856 ping_payload = 'ping payload' 857 858 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) 859 ws.frame_write(sock, ws.OP_PING, ping_payload, chopsize=1) 860 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) 861 862 frame = ws.frame_read(sock) 863 check_frame(frame, True, ws.OP_PONG, ping_payload) 864 865 frame = ws.frame_read(sock) 866 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 867 868 # 5_9 869 870 ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) 871 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) 872 check_close(sock, 1002) 873 874 # 5_10 875 876 _, sock, _ = ws.upgrade() 877 878 ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) 879 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) 880 check_close(sock, 1002) 881 882 # 5_11 883 884 _, sock, _ = ws.upgrade() 885 886 ws.frame_write( 887 sock, 888 ws.OP_CONT, 889 'non-continuation payload', 890 fin=True, 891 chopsize=1, 892 ) 893 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) 894 check_close(sock, 1002) 895 896 # 5_12 897 898 _, sock, _ = ws.upgrade() 899 900 ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) 901 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) 902 check_close(sock, 1002) 903 904 # 5_13 905 906 _, sock, _ = ws.upgrade() 907 908 ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) 909 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) 910 check_close(sock, 1002) 911 912 # 5_14 913 914 _, sock, _ = ws.upgrade() 915 916 ws.frame_write( 917 sock, 918 ws.OP_CONT, 919 'non-continuation payload', 920 fin=False, 921 chopsize=1, 922 ) 923 ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) 924 check_close(sock, 1002) 925 926 # 5_15 927 928 _, sock, _ = ws.upgrade() 929 930 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 931 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) 932 ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) 933 ws.frame_write(sock, ws.OP_TEXT, 'fragment4', fin=True) 934 935 frame = ws.frame_read(sock) 936 937 if frame['opcode'] == ws.OP_TEXT: 938 check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') 939 frame = None 940 941 check_close(sock, 1002, frame=frame) 942 943 # 5_16 944 945 _, sock, _ = ws.upgrade() 946 947 for _ in range(0, 2): 948 ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=False) 949 ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) 950 ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) 951 check_close(sock, 1002) 952 953 # 5_17 954 955 _, sock, _ = ws.upgrade() 956 957 for _ in range(0, 2): 958 ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=True) 959 ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) 960 ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) 961 check_close(sock, 1002) 962 963 # 5_18 964 965 _, sock, _ = ws.upgrade() 966 967 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 968 ws.frame_write(sock, ws.OP_TEXT, 'fragment2') 969 check_close(sock, 1002) 970 971 # 5_19 972 973 _, sock, _ = ws.upgrade() 974 975 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 976 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) 977 ws.frame_write(sock, ws.OP_PING, 'pongme 1!') 978 979 time.sleep(1) 980 981 ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) 982 ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) 983 ws.frame_write(sock, ws.OP_PING, 'pongme 2!') 984 ws.frame_write(sock, ws.OP_CONT, 'fragment5') 985 986 frame = ws.frame_read(sock) 987 check_frame(frame, True, ws.OP_PONG, 'pongme 1!') 988 989 frame = ws.frame_read(sock) 990 check_frame(frame, True, ws.OP_PONG, 'pongme 2!') 991 992 check_frame( 993 ws.frame_read(sock), 994 True, 995 ws.OP_TEXT, 996 'fragment1fragment2fragment3fragment4fragment5', 997 ) 998 999 # 5_20 1000 1001 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 1002 ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) 1003 ws.frame_write(sock, ws.OP_PING, 'pongme 1!') 1004 1005 frame = ws.frame_read(sock) 1006 check_frame(frame, True, ws.OP_PONG, 'pongme 1!') 1007 1008 time.sleep(1) 1009 1010 ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) 1011 ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) 1012 ws.frame_write(sock, ws.OP_PING, 'pongme 2!') 1013 1014 frame = ws.frame_read(sock) 1015 check_frame(frame, True, ws.OP_PONG, 'pongme 2!') 1016 1017 assert client.recvall(sock, read_timeout=0.1) == b'', '5_20' 1018 ws.frame_write(sock, ws.OP_CONT, 'fragment5') 1019 1020 check_frame( 1021 ws.frame_read(sock), 1022 True, 1023 ws.OP_TEXT, 1024 'fragment1fragment2fragment3fragment4fragment5', 1025 ) 1026 1027 close_connection(sock) 1028 1029 1030def test_asgi_websockets_6_1_1__6_4_4(): 1031 client.load('websockets/mirror') 1032 1033 # 6_1_1 1034 1035 _, sock, _ = ws.upgrade() 1036 1037 ws.frame_write(sock, ws.OP_TEXT, '') 1038 frame = ws.frame_read(sock) 1039 check_frame(frame, True, ws.OP_TEXT, '') 1040 1041 # 6_1_2 1042 1043 ws.frame_write(sock, ws.OP_TEXT, '', fin=False) 1044 ws.frame_write(sock, ws.OP_CONT, '', fin=False) 1045 ws.frame_write(sock, ws.OP_CONT, '') 1046 1047 frame = ws.frame_read(sock) 1048 check_frame(frame, True, ws.OP_TEXT, '') 1049 1050 # 6_1_3 1051 1052 payload = 'middle frame payload' 1053 1054 ws.frame_write(sock, ws.OP_TEXT, '', fin=False) 1055 ws.frame_write(sock, ws.OP_CONT, payload, fin=False) 1056 ws.frame_write(sock, ws.OP_CONT, '') 1057 1058 frame = ws.frame_read(sock) 1059 check_frame(frame, True, ws.OP_TEXT, payload) 1060 1061 # 6_2_1 1062 1063 payload = 'Hello-µ@ßöäüàá-UTF-8!!' 1064 1065 ws.frame_write(sock, ws.OP_TEXT, payload) 1066 1067 frame = ws.frame_read(sock) 1068 check_frame(frame, True, ws.OP_TEXT, payload) 1069 1070 # 6_2_2 1071 1072 ws.frame_write(sock, ws.OP_TEXT, payload[:12], fin=False) 1073 ws.frame_write(sock, ws.OP_CONT, payload[12:]) 1074 1075 frame = ws.frame_read(sock) 1076 check_frame(frame, True, ws.OP_TEXT, payload) 1077 1078 # 6_2_3 1079 1080 ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) 1081 1082 frame = ws.frame_read(sock) 1083 check_frame(frame, True, ws.OP_TEXT, payload) 1084 1085 # 6_2_4 1086 1087 payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' 1088 1089 ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) 1090 1091 frame = ws.frame_read(sock) 1092 check_frame(frame, True, ws.OP_TEXT, payload) 1093 1094 close_connection(sock) 1095 1096 1097# Unit does not support UTF-8 validation 1098# 1099# # 6_3_1 FAIL 1100# 1101# payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' 1102# payload_2 = '\xed\xa0\x80' 1103# payload_3 = '\x65\x64\x69\x74\x65\x64' 1104# 1105# payload = payload_1 + payload_2 + payload_3 1106# 1107# ws.message(sock, ws.OP_TEXT, payload) 1108# check_close(sock, 1007) 1109# 1110# # 6_3_2 FAIL 1111# 1112# _, sock, _ = ws.upgrade() 1113# 1114# ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) 1115# check_close(sock, 1007) 1116# 1117# # 6_4_1 ... 6_4_4 FAIL 1118 1119 1120def test_asgi_websockets_7_1_1__7_5_1(): 1121 client.load('websockets/mirror') 1122 1123 # 7_1_1 1124 1125 _, sock, _ = ws.upgrade() 1126 1127 payload = "Hello World!" 1128 1129 ws.frame_write(sock, ws.OP_TEXT, payload) 1130 1131 frame = ws.frame_read(sock) 1132 check_frame(frame, True, ws.OP_TEXT, payload) 1133 1134 close_connection(sock) 1135 1136 # 7_1_2 1137 1138 _, sock, _ = ws.upgrade() 1139 1140 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1141 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1142 1143 check_close(sock) 1144 1145 # 7_1_3 1146 1147 _, sock, _ = ws.upgrade() 1148 1149 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1150 check_close(sock, no_close=True) 1151 1152 ws.frame_write(sock, ws.OP_PING, '') 1153 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' 1154 1155 sock.close() 1156 1157 # 7_1_4 1158 1159 _, sock, _ = ws.upgrade() 1160 1161 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1162 check_close(sock, no_close=True) 1163 1164 ws.frame_write(sock, ws.OP_TEXT, payload) 1165 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' 1166 1167 sock.close() 1168 1169 # 7_1_5 1170 1171 _, sock, _ = ws.upgrade() 1172 1173 ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) 1174 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1175 check_close(sock, no_close=True) 1176 1177 ws.frame_write(sock, ws.OP_CONT, 'fragment2') 1178 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' 1179 1180 sock.close() 1181 1182 # 7_1_6 1183 1184 _, sock, _ = ws.upgrade() 1185 1186 ws.frame_write(sock, ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) 1187 ws.frame_write(sock, ws.OP_TEXT, payload) 1188 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1189 1190 client.recvall(sock, read_timeout=1) 1191 1192 ws.frame_write(sock, ws.OP_PING, '') 1193 assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' 1194 1195 sock.close() 1196 1197 # 7_3_1 1198 1199 _, sock, _ = ws.upgrade() 1200 1201 ws.frame_write(sock, ws.OP_CLOSE, '') 1202 check_close(sock) 1203 1204 # 7_3_2 1205 1206 _, sock, _ = ws.upgrade() 1207 1208 ws.frame_write(sock, ws.OP_CLOSE, 'a') 1209 check_close(sock, 1002) 1210 1211 # 7_3_3 1212 1213 _, sock, _ = ws.upgrade() 1214 1215 ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) 1216 check_close(sock) 1217 1218 # 7_3_4 1219 1220 _, sock, _ = ws.upgrade() 1221 1222 payload = ws.serialize_close(reason='Hello World!') 1223 1224 ws.frame_write(sock, ws.OP_CLOSE, payload) 1225 check_close(sock) 1226 1227 # 7_3_5 1228 1229 _, sock, _ = ws.upgrade() 1230 1231 payload = ws.serialize_close(reason='*' * 123) 1232 1233 ws.frame_write(sock, ws.OP_CLOSE, payload) 1234 check_close(sock) 1235 1236 # 7_3_6 1237 1238 _, sock, _ = ws.upgrade() 1239 1240 payload = ws.serialize_close(reason='*' * 124) 1241 1242 ws.frame_write(sock, ws.OP_CLOSE, payload) 1243 check_close(sock, 1002) 1244 1245 1246# # 7_5_1 FAIL Unit does not support UTF-8 validation 1247# 1248# _, sock, _ = ws.upgrade() 1249# 1250# payload = ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \ 1251# '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64') 1252# 1253# ws.frame_write(sock, ws.OP_CLOSE, payload) 1254# check_close(sock, 1007) 1255 1256 1257def test_asgi_websockets_7_7_X__7_9_X(): 1258 client.load('websockets/mirror') 1259 1260 valid_codes = [ 1261 1000, 1262 1001, 1263 1002, 1264 1003, 1265 1007, 1266 1008, 1267 1009, 1268 1010, 1269 1011, 1270 3000, 1271 3999, 1272 4000, 1273 4999, 1274 ] 1275 1276 invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999] 1277 1278 for code in valid_codes: 1279 _, sock, _ = ws.upgrade() 1280 1281 payload = ws.serialize_close(code=code) 1282 1283 ws.frame_write(sock, ws.OP_CLOSE, payload) 1284 check_close(sock) 1285 1286 for code in invalid_codes: 1287 _, sock, _ = ws.upgrade() 1288 1289 payload = ws.serialize_close(code=code) 1290 1291 ws.frame_write(sock, ws.OP_CLOSE, payload) 1292 check_close(sock, 1002) 1293 1294 1295def test_asgi_websockets_7_13_1__7_13_2(): 1296 client.load('websockets/mirror') 1297 1298 # 7_13_1 1299 1300 _, sock, _ = ws.upgrade() 1301 1302 payload = ws.serialize_close(code=5000) 1303 1304 ws.frame_write(sock, ws.OP_CLOSE, payload) 1305 check_close(sock, 1002) 1306 1307 # 7_13_2 1308 1309 _, sock, _ = ws.upgrade() 1310 1311 payload = struct.pack('!I', 65536) + ''.encode('utf-8') 1312 1313 ws.frame_write(sock, ws.OP_CLOSE, payload) 1314 check_close(sock, 1002) 1315 1316 1317def test_asgi_websockets_9_1_1__9_6_6(is_unsafe, system): 1318 if not is_unsafe: 1319 pytest.skip('unsafe, long run') 1320 1321 client.load('websockets/mirror') 1322 1323 assert 'success' in client.conf( 1324 { 1325 'http': { 1326 'websocket': { 1327 'max_frame_size': 33554432, 1328 'keepalive_interval': 0, 1329 } 1330 } 1331 }, 1332 'settings', 1333 ), 'increase max_frame_size and keepalive_interval' 1334 1335 _, sock, _ = ws.upgrade() 1336 1337 op_text = ws.OP_TEXT 1338 op_binary = ws.OP_BINARY 1339 1340 def check_payload(opcode, length, chopsize=None): 1341 if opcode == ws.OP_TEXT: 1342 payload = '*' * length 1343 else: 1344 payload = b'*' * length 1345 1346 ws.frame_write(sock, opcode, payload, chopsize=chopsize) 1347 frame = ws.frame_read(sock, read_timeout=5) 1348 check_frame(frame, True, opcode, payload) 1349 1350 def check_message(opcode, f_size): 1351 if opcode == ws.OP_TEXT: 1352 payload = '*' * 4 * 2**20 1353 else: 1354 payload = b'*' * 4 * 2**20 1355 1356 ws.message(sock, opcode, payload, fragmention_size=f_size) 1357 frame = ws.frame_read(sock, read_timeout=5) 1358 check_frame(frame, True, opcode, payload) 1359 1360 check_payload(op_text, 64 * 2**10) # 9_1_1 1361 check_payload(op_text, 256 * 2**10) # 9_1_2 1362 check_payload(op_text, 2**20) # 9_1_3 1363 check_payload(op_text, 4 * 2**20) # 9_1_4 1364 check_payload(op_text, 8 * 2**20) # 9_1_5 1365 check_payload(op_text, 16 * 2**20) # 9_1_6 1366 1367 check_payload(op_binary, 64 * 2**10) # 9_2_1 1368 check_payload(op_binary, 256 * 2**10) # 9_2_2 1369 check_payload(op_binary, 2**20) # 9_2_3 1370 check_payload(op_binary, 4 * 2**20) # 9_2_4 1371 check_payload(op_binary, 8 * 2**20) # 9_2_5 1372 check_payload(op_binary, 16 * 2**20) # 9_2_6 1373 1374 if system not in ['Darwin', 'FreeBSD']: 1375 check_message(op_text, 64) # 9_3_1 1376 check_message(op_text, 256) # 9_3_2 1377 check_message(op_text, 2**10) # 9_3_3 1378 check_message(op_text, 4 * 2**10) # 9_3_4 1379 check_message(op_text, 16 * 2**10) # 9_3_5 1380 check_message(op_text, 64 * 2**10) # 9_3_6 1381 check_message(op_text, 256 * 2**10) # 9_3_7 1382 check_message(op_text, 2**20) # 9_3_8 1383 check_message(op_text, 4 * 2**20) # 9_3_9 1384 1385 check_message(op_binary, 64) # 9_4_1 1386 check_message(op_binary, 256) # 9_4_2 1387 check_message(op_binary, 2**10) # 9_4_3 1388 check_message(op_binary, 4 * 2**10) # 9_4_4 1389 check_message(op_binary, 16 * 2**10) # 9_4_5 1390 check_message(op_binary, 64 * 2**10) # 9_4_6 1391 check_message(op_binary, 256 * 2**10) # 9_4_7 1392 check_message(op_binary, 2**20) # 9_4_8 1393 check_message(op_binary, 4 * 2**20) # 9_4_9 1394 1395 check_payload(op_text, 2**20, chopsize=64) # 9_5_1 1396 check_payload(op_text, 2**20, chopsize=128) # 9_5_2 1397 check_payload(op_text, 2**20, chopsize=256) # 9_5_3 1398 check_payload(op_text, 2**20, chopsize=512) # 9_5_4 1399 check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 1400 check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 1401 1402 check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 1403 check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 1404 check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 1405 check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 1406 check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 1407 check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 1408 1409 close_connection(sock) 1410 1411 1412def test_asgi_websockets_10_1_1(): 1413 client.load('websockets/mirror') 1414 1415 _, sock, _ = ws.upgrade() 1416 1417 payload = '*' * 65536 1418 1419 ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1300) 1420 1421 frame = ws.frame_read(sock) 1422 check_frame(frame, True, ws.OP_TEXT, payload) 1423 1424 close_connection(sock) 1425 1426 1427# settings 1428 1429 1430def test_asgi_websockets_max_frame_size(): 1431 client.load('websockets/mirror') 1432 1433 assert 'success' in client.conf( 1434 {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' 1435 ), 'configure max_frame_size' 1436 1437 _, sock, _ = ws.upgrade() 1438 1439 payload = '*' * 94 1440 opcode = ws.OP_TEXT 1441 1442 ws.frame_write(sock, opcode, payload) # frame length is 100 1443 1444 frame = ws.frame_read(sock) 1445 check_frame(frame, True, opcode, payload) 1446 1447 payload = '*' * 95 1448 1449 ws.frame_write(sock, opcode, payload) # frame length is 101 1450 check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE 1451 1452 1453def test_asgi_websockets_read_timeout(): 1454 client.load('websockets/mirror') 1455 1456 assert 'success' in client.conf( 1457 {'http': {'websocket': {'read_timeout': 5}}}, 'settings' 1458 ), 'configure read_timeout' 1459 1460 _, sock, _ = ws.upgrade() 1461 1462 frame = ws.frame_to_send(ws.OP_TEXT, 'blah') 1463 sock.sendall(frame[:2]) 1464 1465 time.sleep(2) 1466 1467 check_close(sock, 1001) # 1001 - CLOSE_GOING_AWAY 1468 1469 1470def test_asgi_websockets_keepalive_interval(): 1471 client.load('websockets/mirror') 1472 1473 assert 'success' in client.conf( 1474 {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' 1475 ), 'configure keepalive_interval' 1476 1477 _, sock, _ = ws.upgrade() 1478 1479 frame = ws.frame_to_send(ws.OP_TEXT, 'blah') 1480 sock.sendall(frame[:2]) 1481 1482 time.sleep(2) 1483 1484 frame = ws.frame_read(sock) 1485 check_frame(frame, True, ws.OP_PING, '') # PING frame 1486 1487 sock.close() 1488 1489 1490def test_asgi_websockets_client_locks_app(): 1491 client.load('websockets/mirror') 1492 1493 message = 'blah' 1494 1495 _, sock, _ = ws.upgrade() 1496 1497 assert 'success' in client.conf({}), 'remove app' 1498 1499 ws.frame_write(sock, ws.OP_TEXT, message) 1500 1501 frame = ws.frame_read(sock) 1502 1503 assert message == frame['data'].decode('utf-8'), 'client' 1504 1505 sock.close() 1506