11625Smax.romanov@nginx.comimport struct
21625Smax.romanov@nginx.comimport time
31625Smax.romanov@nginx.com
41635Szelenkov@nginx.comimport pytest
5*2066Szelenkov@nginx.comfrom packaging import version
61625Smax.romanov@nginx.comfrom unit.applications.lang.python import TestApplicationPython
71625Smax.romanov@nginx.comfrom unit.applications.websockets import TestApplicationWebsocket
81730Szelenkov@nginx.comfrom unit.option import option
91625Smax.romanov@nginx.com
101625Smax.romanov@nginx.com
111625Smax.romanov@nginx.comclass TestASGIWebsockets(TestApplicationPython):
121848Szelenkov@nginx.com    prerequisites = {
13*2066Szelenkov@nginx.com        'modules': {
14*2066Szelenkov@nginx.com            'python': lambda v: version.parse(v) >= version.parse('3.5')
15*2066Szelenkov@nginx.com        }
161848Szelenkov@nginx.com    }
171625Smax.romanov@nginx.com    load_module = 'asgi'
181625Smax.romanov@nginx.com
191625Smax.romanov@nginx.com    ws = TestApplicationWebsocket()
201625Smax.romanov@nginx.com
211736Szelenkov@nginx.com    @pytest.fixture(autouse=True)
221736Szelenkov@nginx.com    def setup_method_fixture(self, request, skip_alert):
231625Smax.romanov@nginx.com        assert 'success' in self.conf(
241625Smax.romanov@nginx.com            {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
251625Smax.romanov@nginx.com        ), 'clear keepalive_interval'
261625Smax.romanov@nginx.com
271625Smax.romanov@nginx.com        skip_alert(r'socket close\(\d+\) failed')
281625Smax.romanov@nginx.com
291625Smax.romanov@nginx.com    def close_connection(self, sock):
301625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
311625Smax.romanov@nginx.com
321625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
331625Smax.romanov@nginx.com
341625Smax.romanov@nginx.com        self.check_close(sock)
351625Smax.romanov@nginx.com
361819Smax.romanov@nginx.com    def check_close(self, sock, code=1000, no_close=False, frame=None):
371819Smax.romanov@nginx.com        if frame == None:
381819Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
391625Smax.romanov@nginx.com
401625Smax.romanov@nginx.com        assert frame['fin'] == True, 'close fin'
411625Smax.romanov@nginx.com        assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
421625Smax.romanov@nginx.com        assert frame['code'] == code, 'close code'
431625Smax.romanov@nginx.com
441625Smax.romanov@nginx.com        if not no_close:
451625Smax.romanov@nginx.com            sock.close()
461625Smax.romanov@nginx.com
471625Smax.romanov@nginx.com    def check_frame(self, frame, fin, opcode, payload, decode=True):
481625Smax.romanov@nginx.com        if opcode == self.ws.OP_BINARY or not decode:
491625Smax.romanov@nginx.com            data = frame['data']
501625Smax.romanov@nginx.com        else:
511625Smax.romanov@nginx.com            data = frame['data'].decode('utf-8')
521625Smax.romanov@nginx.com
531625Smax.romanov@nginx.com        assert frame['fin'] == fin, 'fin'
541625Smax.romanov@nginx.com        assert frame['opcode'] == opcode, 'opcode'
551625Smax.romanov@nginx.com        assert data == payload, 'payload'
561625Smax.romanov@nginx.com
571625Smax.romanov@nginx.com    def test_asgi_websockets_handshake(self):
581625Smax.romanov@nginx.com        self.load('websockets/mirror')
591625Smax.romanov@nginx.com
601625Smax.romanov@nginx.com        resp, sock, key = self.ws.upgrade()
611625Smax.romanov@nginx.com        sock.close()
621625Smax.romanov@nginx.com
631625Smax.romanov@nginx.com        assert resp['status'] == 101, 'status'
641625Smax.romanov@nginx.com        assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
651625Smax.romanov@nginx.com        assert resp['headers']['Connection'] == 'Upgrade', 'connection'
661625Smax.romanov@nginx.com        assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
671625Smax.romanov@nginx.com            key
681625Smax.romanov@nginx.com        ), 'key'
691625Smax.romanov@nginx.com
701780Smax.romanov@nginx.com        # remove "mirror" application
711780Smax.romanov@nginx.com        self.load('websockets/subprotocol')
721780Smax.romanov@nginx.com
731625Smax.romanov@nginx.com    def test_asgi_websockets_subprotocol(self):
741625Smax.romanov@nginx.com        self.load('websockets/subprotocol')
751625Smax.romanov@nginx.com
761625Smax.romanov@nginx.com        resp, sock, key = self.ws.upgrade()
771625Smax.romanov@nginx.com        sock.close()
781625Smax.romanov@nginx.com
791625Smax.romanov@nginx.com        assert resp['status'] == 101, 'status'
801848Szelenkov@nginx.com        assert (
811848Szelenkov@nginx.com            resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')"
821848Szelenkov@nginx.com        ), 'subprotocols'
831625Smax.romanov@nginx.com        assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key'
841625Smax.romanov@nginx.com
851625Smax.romanov@nginx.com    def test_asgi_websockets_mirror(self):
861625Smax.romanov@nginx.com        self.load('websockets/mirror')
871625Smax.romanov@nginx.com
881625Smax.romanov@nginx.com        message = 'blah'
891625Smax.romanov@nginx.com
901625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
911625Smax.romanov@nginx.com
921625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
931625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
941625Smax.romanov@nginx.com
951625Smax.romanov@nginx.com        assert message == frame['data'].decode('utf-8'), 'mirror'
961625Smax.romanov@nginx.com
971625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
981625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
991625Smax.romanov@nginx.com
1001625Smax.romanov@nginx.com        assert message == frame['data'].decode('utf-8'), 'mirror 2'
1011625Smax.romanov@nginx.com
1021625Smax.romanov@nginx.com        sock.close()
1031625Smax.romanov@nginx.com
1041780Smax.romanov@nginx.com    def test_asgi_websockets_mirror_app_change(self):
1051780Smax.romanov@nginx.com        self.load('websockets/mirror')
1061780Smax.romanov@nginx.com
1071780Smax.romanov@nginx.com        message = 'blah'
1081780Smax.romanov@nginx.com
1091780Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
1101780Smax.romanov@nginx.com
1111780Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
1121780Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
1131780Smax.romanov@nginx.com
1141780Smax.romanov@nginx.com        assert message == frame['data'].decode('utf-8'), 'mirror'
1151780Smax.romanov@nginx.com
1161780Smax.romanov@nginx.com        self.load('websockets/subprotocol')
1171780Smax.romanov@nginx.com
1181780Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
1191780Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
1201780Smax.romanov@nginx.com
1211780Smax.romanov@nginx.com        assert message == frame['data'].decode('utf-8'), 'mirror 2'
1221780Smax.romanov@nginx.com
1231780Smax.romanov@nginx.com        sock.close()
1241780Smax.romanov@nginx.com
1251625Smax.romanov@nginx.com    def test_asgi_websockets_no_mask(self):
1261625Smax.romanov@nginx.com        self.load('websockets/mirror')
1271625Smax.romanov@nginx.com
1281625Smax.romanov@nginx.com        message = 'blah'
1291625Smax.romanov@nginx.com
1301625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
1311625Smax.romanov@nginx.com
1321625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message, mask=False)
1331625Smax.romanov@nginx.com
1341625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
1351625Smax.romanov@nginx.com
1361625Smax.romanov@nginx.com        assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode'
1371625Smax.romanov@nginx.com        assert frame['code'] == 1002, 'no mask close code'
1381625Smax.romanov@nginx.com
1391625Smax.romanov@nginx.com        sock.close()
1401625Smax.romanov@nginx.com
1411625Smax.romanov@nginx.com    def test_asgi_websockets_fragmentation(self):
1421625Smax.romanov@nginx.com        self.load('websockets/mirror')
1431625Smax.romanov@nginx.com
1441625Smax.romanov@nginx.com        message = 'blah'
1451625Smax.romanov@nginx.com
1461625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
1471625Smax.romanov@nginx.com
1481625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message, fin=False)
1491625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, ' ', fin=False)
1501625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, message)
1511625Smax.romanov@nginx.com
1521625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
1531625Smax.romanov@nginx.com
1541625Smax.romanov@nginx.com        assert message + ' ' + message == frame['data'].decode(
1551625Smax.romanov@nginx.com            'utf-8'
1561625Smax.romanov@nginx.com        ), 'mirror framing'
1571625Smax.romanov@nginx.com
1581625Smax.romanov@nginx.com        sock.close()
1591625Smax.romanov@nginx.com
1601629Szelenkov@nginx.com    def test_asgi_websockets_length_long(self):
1611629Szelenkov@nginx.com        self.load('websockets/mirror')
1621629Szelenkov@nginx.com
1631629Szelenkov@nginx.com        _, sock, _ = self.ws.upgrade()
1641629Szelenkov@nginx.com
1651629Szelenkov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
1661629Szelenkov@nginx.com        self.ws.frame_write(
1671848Szelenkov@nginx.com            sock, self.ws.OP_CONT, 'fragment2', length=2 ** 64 - 1
1681629Szelenkov@nginx.com        )
1691629Szelenkov@nginx.com
1701629Szelenkov@nginx.com        self.check_close(sock, 1009)  # 1009 - CLOSE_TOO_LARGE
1711629Szelenkov@nginx.com
1721625Smax.romanov@nginx.com    def test_asgi_websockets_frame_fragmentation_invalid(self):
1731625Smax.romanov@nginx.com        self.load('websockets/mirror')
1741625Smax.romanov@nginx.com
1751625Smax.romanov@nginx.com        message = 'blah'
1761625Smax.romanov@nginx.com
1771625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
1781625Smax.romanov@nginx.com
1791625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, message, fin=False)
1801625Smax.romanov@nginx.com
1811625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
1821625Smax.romanov@nginx.com
1831625Smax.romanov@nginx.com        frame.pop('data')
1841625Smax.romanov@nginx.com        assert frame == {
1851625Smax.romanov@nginx.com            'fin': True,
1861625Smax.romanov@nginx.com            'rsv1': False,
1871625Smax.romanov@nginx.com            'rsv2': False,
1881625Smax.romanov@nginx.com            'rsv3': False,
1891625Smax.romanov@nginx.com            'opcode': self.ws.OP_CLOSE,
1901625Smax.romanov@nginx.com            'mask': 0,
1911625Smax.romanov@nginx.com            'code': 1002,
1921625Smax.romanov@nginx.com            'reason': 'Fragmented control frame',
1931625Smax.romanov@nginx.com        }, 'close frame'
1941625Smax.romanov@nginx.com
1951625Smax.romanov@nginx.com        sock.close()
1961625Smax.romanov@nginx.com
1971625Smax.romanov@nginx.com    def test_asgi_websockets_large(self):
1981625Smax.romanov@nginx.com        self.load('websockets/mirror')
1991625Smax.romanov@nginx.com
2001625Smax.romanov@nginx.com        message = '0123456789' * 300
2011625Smax.romanov@nginx.com
2021625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
2031625Smax.romanov@nginx.com
2041625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
2051625Smax.romanov@nginx.com
2061625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
2071625Smax.romanov@nginx.com        data = frame['data'].decode('utf-8')
2081625Smax.romanov@nginx.com
2091625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
2101625Smax.romanov@nginx.com        data += frame['data'].decode('utf-8')
2111625Smax.romanov@nginx.com
2121625Smax.romanov@nginx.com        assert message == data, 'large'
2131625Smax.romanov@nginx.com
2141625Smax.romanov@nginx.com        sock.close()
2151625Smax.romanov@nginx.com
2161625Smax.romanov@nginx.com    def test_asgi_websockets_two_clients(self):
2171625Smax.romanov@nginx.com        self.load('websockets/mirror')
2181625Smax.romanov@nginx.com
2191625Smax.romanov@nginx.com        message1 = 'blah1'
2201625Smax.romanov@nginx.com        message2 = 'blah2'
2211625Smax.romanov@nginx.com
2221625Smax.romanov@nginx.com        _, sock1, _ = self.ws.upgrade()
2231625Smax.romanov@nginx.com        _, sock2, _ = self.ws.upgrade()
2241625Smax.romanov@nginx.com
2251625Smax.romanov@nginx.com        self.ws.frame_write(sock1, self.ws.OP_TEXT, message1)
2261625Smax.romanov@nginx.com        self.ws.frame_write(sock2, self.ws.OP_TEXT, message2)
2271625Smax.romanov@nginx.com
2281625Smax.romanov@nginx.com        frame1 = self.ws.frame_read(sock1)
2291625Smax.romanov@nginx.com        frame2 = self.ws.frame_read(sock2)
2301625Smax.romanov@nginx.com
2311625Smax.romanov@nginx.com        assert message1 == frame1['data'].decode('utf-8'), 'client 1'
2321625Smax.romanov@nginx.com        assert message2 == frame2['data'].decode('utf-8'), 'client 2'
2331625Smax.romanov@nginx.com
2341625Smax.romanov@nginx.com        sock1.close()
2351625Smax.romanov@nginx.com        sock2.close()
2361625Smax.romanov@nginx.com
2371625Smax.romanov@nginx.com    @pytest.mark.skip('not yet')
2381625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_upgrade_absent(
2391848Szelenkov@nginx.com        self,
2401625Smax.romanov@nginx.com    ):  # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1
2411625Smax.romanov@nginx.com        self.load('websockets/mirror')
2421625Smax.romanov@nginx.com
2431625Smax.romanov@nginx.com        resp = self.get(
2441625Smax.romanov@nginx.com            headers={
2451625Smax.romanov@nginx.com                'Host': 'localhost',
2461625Smax.romanov@nginx.com                'Connection': 'Upgrade',
2471625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
2481625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
2491625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
2501625Smax.romanov@nginx.com            },
2511625Smax.romanov@nginx.com        )
2521625Smax.romanov@nginx.com
2531625Smax.romanov@nginx.com        assert resp['status'] == 400, 'upgrade absent'
2541625Smax.romanov@nginx.com
2551625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_case_insensitive(self):
2561625Smax.romanov@nginx.com        self.load('websockets/mirror')
2571625Smax.romanov@nginx.com
2581625Smax.romanov@nginx.com        resp, sock, _ = self.ws.upgrade(
2591625Smax.romanov@nginx.com            headers={
2601625Smax.romanov@nginx.com                'Host': 'localhost',
2611625Smax.romanov@nginx.com                'Upgrade': 'WEBSOCKET',
2621625Smax.romanov@nginx.com                'Connection': 'UPGRADE',
2631625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
2641625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
2651625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
2661625Smax.romanov@nginx.com            }
2671625Smax.romanov@nginx.com        )
2681625Smax.romanov@nginx.com        sock.close()
2691625Smax.romanov@nginx.com
2701625Smax.romanov@nginx.com        assert resp['status'] == 101, 'status'
2711625Smax.romanov@nginx.com
2721625Smax.romanov@nginx.com    @pytest.mark.skip('not yet')
2731625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_connection_absent(self):  # FAIL
2741625Smax.romanov@nginx.com        self.load('websockets/mirror')
2751625Smax.romanov@nginx.com
2761625Smax.romanov@nginx.com        resp = self.get(
2771625Smax.romanov@nginx.com            headers={
2781625Smax.romanov@nginx.com                'Host': 'localhost',
2791625Smax.romanov@nginx.com                'Upgrade': 'websocket',
2801625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
2811625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
2821625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
2831625Smax.romanov@nginx.com            },
2841625Smax.romanov@nginx.com        )
2851625Smax.romanov@nginx.com
2861625Smax.romanov@nginx.com        assert resp['status'] == 400, 'status'
2871625Smax.romanov@nginx.com
2881625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_version_absent(self):
2891625Smax.romanov@nginx.com        self.load('websockets/mirror')
2901625Smax.romanov@nginx.com
2911625Smax.romanov@nginx.com        resp = self.get(
2921625Smax.romanov@nginx.com            headers={
2931625Smax.romanov@nginx.com                'Host': 'localhost',
2941625Smax.romanov@nginx.com                'Upgrade': 'websocket',
2951625Smax.romanov@nginx.com                'Connection': 'Upgrade',
2961625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
2971625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
2981625Smax.romanov@nginx.com            },
2991625Smax.romanov@nginx.com        )
3001625Smax.romanov@nginx.com
3011625Smax.romanov@nginx.com        assert resp['status'] == 426, 'status'
3021625Smax.romanov@nginx.com
3031625Smax.romanov@nginx.com    @pytest.mark.skip('not yet')
3041625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_key_invalid(self):
3051625Smax.romanov@nginx.com        self.load('websockets/mirror')
3061625Smax.romanov@nginx.com
3071625Smax.romanov@nginx.com        resp = self.get(
3081625Smax.romanov@nginx.com            headers={
3091625Smax.romanov@nginx.com                'Host': 'localhost',
3101625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3111625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3121625Smax.romanov@nginx.com                'Sec-WebSocket-Key': '!',
3131625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
3141625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3151625Smax.romanov@nginx.com            },
3161625Smax.romanov@nginx.com        )
3171625Smax.romanov@nginx.com
3181625Smax.romanov@nginx.com        assert resp['status'] == 400, 'key length'
3191625Smax.romanov@nginx.com
3201625Smax.romanov@nginx.com        key = self.ws.key()
3211625Smax.romanov@nginx.com        resp = self.get(
3221625Smax.romanov@nginx.com            headers={
3231625Smax.romanov@nginx.com                'Host': 'localhost',
3241625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3251625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3261625Smax.romanov@nginx.com                'Sec-WebSocket-Key': [key, key],
3271625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
3281625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3291625Smax.romanov@nginx.com            },
3301625Smax.romanov@nginx.com        )
3311625Smax.romanov@nginx.com
3321848Szelenkov@nginx.com        assert (
3331848Szelenkov@nginx.com            resp['status'] == 400
3341848Szelenkov@nginx.com        ), 'key double'  # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
3351625Smax.romanov@nginx.com
3361625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_method_invalid(self):
3371625Smax.romanov@nginx.com        self.load('websockets/mirror')
3381625Smax.romanov@nginx.com
3391625Smax.romanov@nginx.com        resp = self.post(
3401625Smax.romanov@nginx.com            headers={
3411625Smax.romanov@nginx.com                'Host': 'localhost',
3421625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3431625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3441625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
3451625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
3461625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3471625Smax.romanov@nginx.com            },
3481625Smax.romanov@nginx.com        )
3491625Smax.romanov@nginx.com
3501625Smax.romanov@nginx.com        assert resp['status'] == 400, 'status'
3511625Smax.romanov@nginx.com
3521625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_http_10(self):
3531625Smax.romanov@nginx.com        self.load('websockets/mirror')
3541625Smax.romanov@nginx.com
3551625Smax.romanov@nginx.com        resp = self.get(
3561625Smax.romanov@nginx.com            headers={
3571625Smax.romanov@nginx.com                'Host': 'localhost',
3581625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3591625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3601625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
3611625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
3621625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3631625Smax.romanov@nginx.com            },
3641625Smax.romanov@nginx.com            http_10=True,
3651625Smax.romanov@nginx.com        )
3661625Smax.romanov@nginx.com
3671625Smax.romanov@nginx.com        assert resp['status'] == 400, 'status'
3681625Smax.romanov@nginx.com
3691625Smax.romanov@nginx.com    def test_asgi_websockets_handshake_uri_invalid(self):
3701625Smax.romanov@nginx.com        self.load('websockets/mirror')
3711625Smax.romanov@nginx.com
3721625Smax.romanov@nginx.com        resp = self.get(
3731625Smax.romanov@nginx.com            headers={
3741625Smax.romanov@nginx.com                'Host': 'localhost',
3751625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3761625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3771625Smax.romanov@nginx.com                'Sec-WebSocket-Key': self.ws.key(),
3781625Smax.romanov@nginx.com                'Sec-WebSocket-Protocol': 'chat',
3791625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3801625Smax.romanov@nginx.com            },
3811625Smax.romanov@nginx.com            url='!',
3821625Smax.romanov@nginx.com        )
3831625Smax.romanov@nginx.com
3841625Smax.romanov@nginx.com        assert resp['status'] == 400, 'status'
3851625Smax.romanov@nginx.com
3861625Smax.romanov@nginx.com    def test_asgi_websockets_protocol_absent(self):
3871625Smax.romanov@nginx.com        self.load('websockets/mirror')
3881625Smax.romanov@nginx.com
3891625Smax.romanov@nginx.com        key = self.ws.key()
3901625Smax.romanov@nginx.com        resp, sock, _ = self.ws.upgrade(
3911625Smax.romanov@nginx.com            headers={
3921625Smax.romanov@nginx.com                'Host': 'localhost',
3931625Smax.romanov@nginx.com                'Upgrade': 'websocket',
3941625Smax.romanov@nginx.com                'Connection': 'Upgrade',
3951625Smax.romanov@nginx.com                'Sec-WebSocket-Key': key,
3961625Smax.romanov@nginx.com                'Sec-WebSocket-Version': 13,
3971625Smax.romanov@nginx.com            }
3981625Smax.romanov@nginx.com        )
3991625Smax.romanov@nginx.com        sock.close()
4001625Smax.romanov@nginx.com
4011625Smax.romanov@nginx.com        assert resp['status'] == 101, 'status'
4021625Smax.romanov@nginx.com        assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
4031625Smax.romanov@nginx.com        assert resp['headers']['Connection'] == 'Upgrade', 'connection'
4041625Smax.romanov@nginx.com        assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
4051625Smax.romanov@nginx.com            key
4061625Smax.romanov@nginx.com        ), 'key'
4071625Smax.romanov@nginx.com
4081625Smax.romanov@nginx.com    # autobahn-testsuite
4091625Smax.romanov@nginx.com    #
4101625Smax.romanov@nginx.com    # Some following tests fail because of Unit does not support UTF-8
4111625Smax.romanov@nginx.com    # validation for websocket frames.  It should be implemented
4121625Smax.romanov@nginx.com    # by application, if necessary.
4131625Smax.romanov@nginx.com
4141625Smax.romanov@nginx.com    def test_asgi_websockets_1_1_1__1_1_8(self):
4151625Smax.romanov@nginx.com        self.load('websockets/mirror')
4161625Smax.romanov@nginx.com
4171625Smax.romanov@nginx.com        opcode = self.ws.OP_TEXT
4181625Smax.romanov@nginx.com
4191625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
4201625Smax.romanov@nginx.com
4211625Smax.romanov@nginx.com        def check_length(length, chopsize=None):
4221625Smax.romanov@nginx.com            payload = '*' * length
4231625Smax.romanov@nginx.com
4241625Smax.romanov@nginx.com            self.ws.frame_write(sock, opcode, payload, chopsize=chopsize)
4251625Smax.romanov@nginx.com
4261625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
4271625Smax.romanov@nginx.com            self.check_frame(frame, True, opcode, payload)
4281625Smax.romanov@nginx.com
4291848Szelenkov@nginx.com        check_length(0)  # 1_1_1
4301848Szelenkov@nginx.com        check_length(125)  # 1_1_2
4311848Szelenkov@nginx.com        check_length(126)  # 1_1_3
4321848Szelenkov@nginx.com        check_length(127)  # 1_1_4
4331848Szelenkov@nginx.com        check_length(128)  # 1_1_5
4341848Szelenkov@nginx.com        check_length(65535)  # 1_1_6
4351848Szelenkov@nginx.com        check_length(65536)  # 1_1_7
4361848Szelenkov@nginx.com        check_length(65536, chopsize=997)  # 1_1_8
4371625Smax.romanov@nginx.com
4381625Smax.romanov@nginx.com        self.close_connection(sock)
4391625Smax.romanov@nginx.com
4401625Smax.romanov@nginx.com    def test_asgi_websockets_1_2_1__1_2_8(self):
4411625Smax.romanov@nginx.com        self.load('websockets/mirror')
4421625Smax.romanov@nginx.com
4431625Smax.romanov@nginx.com        opcode = self.ws.OP_BINARY
4441625Smax.romanov@nginx.com
4451625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
4461625Smax.romanov@nginx.com
4471625Smax.romanov@nginx.com        def check_length(length, chopsize=None):
4481625Smax.romanov@nginx.com            payload = b'\xfe' * length
4491625Smax.romanov@nginx.com
4501625Smax.romanov@nginx.com            self.ws.frame_write(sock, opcode, payload, chopsize=chopsize)
4511625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
4521625Smax.romanov@nginx.com
4531625Smax.romanov@nginx.com            self.check_frame(frame, True, opcode, payload)
4541625Smax.romanov@nginx.com
4551848Szelenkov@nginx.com        check_length(0)  # 1_2_1
4561848Szelenkov@nginx.com        check_length(125)  # 1_2_2
4571848Szelenkov@nginx.com        check_length(126)  # 1_2_3
4581848Szelenkov@nginx.com        check_length(127)  # 1_2_4
4591848Szelenkov@nginx.com        check_length(128)  # 1_2_5
4601848Szelenkov@nginx.com        check_length(65535)  # 1_2_6
4611848Szelenkov@nginx.com        check_length(65536)  # 1_2_7
4621848Szelenkov@nginx.com        check_length(65536, chopsize=997)  # 1_2_8
4631625Smax.romanov@nginx.com
4641625Smax.romanov@nginx.com        self.close_connection(sock)
4651625Smax.romanov@nginx.com
4661625Smax.romanov@nginx.com    def test_asgi_websockets_2_1__2_6(self):
4671625Smax.romanov@nginx.com        self.load('websockets/mirror')
4681625Smax.romanov@nginx.com
4691625Smax.romanov@nginx.com        op_ping = self.ws.OP_PING
4701625Smax.romanov@nginx.com        op_pong = self.ws.OP_PONG
4711625Smax.romanov@nginx.com
4721625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
4731625Smax.romanov@nginx.com
4741625Smax.romanov@nginx.com        def check_ping(payload, chopsize=None, decode=True):
4751625Smax.romanov@nginx.com            self.ws.frame_write(sock, op_ping, payload, chopsize=chopsize)
4761625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
4771625Smax.romanov@nginx.com
4781625Smax.romanov@nginx.com            self.check_frame(frame, True, op_pong, payload, decode=decode)
4791625Smax.romanov@nginx.com
4801848Szelenkov@nginx.com        check_ping('')  # 2_1
4811848Szelenkov@nginx.com        check_ping('Hello, world!')  # 2_2
4821625Smax.romanov@nginx.com        check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False)  # 2_3
4831848Szelenkov@nginx.com        check_ping(b'\xfe' * 125, decode=False)  # 2_4
4841848Szelenkov@nginx.com        check_ping(b'\xfe' * 125, chopsize=1, decode=False)  # 2_6
4851625Smax.romanov@nginx.com
4861625Smax.romanov@nginx.com        self.close_connection(sock)
4871625Smax.romanov@nginx.com
4881625Smax.romanov@nginx.com        # 2_5
4891625Smax.romanov@nginx.com
4901625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
4911625Smax.romanov@nginx.com
4921625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, b'\xfe' * 126)
4931625Smax.romanov@nginx.com        self.check_close(sock, 1002)
4941625Smax.romanov@nginx.com
4951625Smax.romanov@nginx.com    def test_asgi_websockets_2_7__2_9(self):
4961625Smax.romanov@nginx.com        self.load('websockets/mirror')
4971625Smax.romanov@nginx.com
4981625Smax.romanov@nginx.com        # 2_7
4991625Smax.romanov@nginx.com
5001625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5011625Smax.romanov@nginx.com
5021625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PONG, '')
5031625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', '2_7'
5041625Smax.romanov@nginx.com
5051625Smax.romanov@nginx.com        # 2_8
5061625Smax.romanov@nginx.com
5071625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
5081625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', '2_8'
5091625Smax.romanov@nginx.com
5101625Smax.romanov@nginx.com        # 2_9
5111625Smax.romanov@nginx.com
5121625Smax.romanov@nginx.com        payload = 'ping payload'
5131625Smax.romanov@nginx.com
5141625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
5151625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, payload)
5161625Smax.romanov@nginx.com
5171625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
5181625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, payload)
5191625Smax.romanov@nginx.com
5201625Smax.romanov@nginx.com        self.close_connection(sock)
5211625Smax.romanov@nginx.com
5221625Smax.romanov@nginx.com    def test_asgi_websockets_2_10__2_11(self):
5231625Smax.romanov@nginx.com        self.load('websockets/mirror')
5241625Smax.romanov@nginx.com
5251625Smax.romanov@nginx.com        # 2_10
5261625Smax.romanov@nginx.com
5271625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5281625Smax.romanov@nginx.com
5291625Smax.romanov@nginx.com        for i in range(0, 10):
5301625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_PING, 'payload-%d' % i)
5311625Smax.romanov@nginx.com
5321625Smax.romanov@nginx.com        for i in range(0, 10):
5331625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
5341625Smax.romanov@nginx.com            self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i)
5351625Smax.romanov@nginx.com
5361625Smax.romanov@nginx.com        # 2_11
5371625Smax.romanov@nginx.com
5381625Smax.romanov@nginx.com        for i in range(0, 10):
5391625Smax.romanov@nginx.com            opcode = self.ws.OP_PING
5401625Smax.romanov@nginx.com            self.ws.frame_write(sock, opcode, 'payload-%d' % i, chopsize=1)
5411625Smax.romanov@nginx.com
5421625Smax.romanov@nginx.com        for i in range(0, 10):
5431625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock)
5441625Smax.romanov@nginx.com            self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i)
5451625Smax.romanov@nginx.com
5461625Smax.romanov@nginx.com        self.close_connection(sock)
5471625Smax.romanov@nginx.com
5481625Smax.romanov@nginx.com    @pytest.mark.skip('not yet')
5491625Smax.romanov@nginx.com    def test_asgi_websockets_3_1__3_7(self):
5501625Smax.romanov@nginx.com        self.load('websockets/mirror')
5511625Smax.romanov@nginx.com
5521625Smax.romanov@nginx.com        payload = 'Hello, world!'
5531625Smax.romanov@nginx.com
5541625Smax.romanov@nginx.com        # 3_1
5551625Smax.romanov@nginx.com
5561625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5571625Smax.romanov@nginx.com
5581625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv1=True)
5591625Smax.romanov@nginx.com        self.check_close(sock, 1002)
5601625Smax.romanov@nginx.com
5611625Smax.romanov@nginx.com        # 3_2
5621625Smax.romanov@nginx.com
5631625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5641625Smax.romanov@nginx.com
5651625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
5661625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv2=True)
5671625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
5681625Smax.romanov@nginx.com
5691625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
5701625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
5711625Smax.romanov@nginx.com
5721625Smax.romanov@nginx.com        self.check_close(sock, 1002, no_close=True)
5731625Smax.romanov@nginx.com
5741625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2'
5751625Smax.romanov@nginx.com        sock.close()
5761625Smax.romanov@nginx.com
5771625Smax.romanov@nginx.com        # 3_3
5781625Smax.romanov@nginx.com
5791625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5801625Smax.romanov@nginx.com
5811625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
5821625Smax.romanov@nginx.com
5831625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
5841625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
5851625Smax.romanov@nginx.com
5861625Smax.romanov@nginx.com        self.ws.frame_write(
5871625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, payload, rsv1=True, rsv2=True
5881625Smax.romanov@nginx.com        )
5891625Smax.romanov@nginx.com
5901625Smax.romanov@nginx.com        self.check_close(sock, 1002, no_close=True)
5911625Smax.romanov@nginx.com
5921625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3'
5931625Smax.romanov@nginx.com        sock.close()
5941625Smax.romanov@nginx.com
5951625Smax.romanov@nginx.com        # 3_4
5961625Smax.romanov@nginx.com
5971625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
5981625Smax.romanov@nginx.com
5991625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
6001625Smax.romanov@nginx.com        self.ws.frame_write(
6011625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, payload, rsv3=True, chopsize=1
6021625Smax.romanov@nginx.com        )
6031625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
6041625Smax.romanov@nginx.com
6051625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
6061625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
6071625Smax.romanov@nginx.com
6081625Smax.romanov@nginx.com        self.check_close(sock, 1002, no_close=True)
6091625Smax.romanov@nginx.com
6101625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4'
6111625Smax.romanov@nginx.com        sock.close()
6121625Smax.romanov@nginx.com
6131625Smax.romanov@nginx.com        # 3_5
6141625Smax.romanov@nginx.com
6151625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6161625Smax.romanov@nginx.com
6171625Smax.romanov@nginx.com        self.ws.frame_write(
6181625Smax.romanov@nginx.com            sock,
6191625Smax.romanov@nginx.com            self.ws.OP_BINARY,
6201625Smax.romanov@nginx.com            b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff',
6211625Smax.romanov@nginx.com            rsv1=True,
6221625Smax.romanov@nginx.com            rsv3=True,
6231625Smax.romanov@nginx.com        )
6241625Smax.romanov@nginx.com
6251625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6261625Smax.romanov@nginx.com
6271625Smax.romanov@nginx.com        # 3_6
6281625Smax.romanov@nginx.com
6291625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6301625Smax.romanov@nginx.com
6311625Smax.romanov@nginx.com        self.ws.frame_write(
6321625Smax.romanov@nginx.com            sock, self.ws.OP_PING, payload, rsv2=True, rsv3=True
6331625Smax.romanov@nginx.com        )
6341625Smax.romanov@nginx.com
6351625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6361625Smax.romanov@nginx.com
6371625Smax.romanov@nginx.com        # 3_7
6381625Smax.romanov@nginx.com
6391625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6401625Smax.romanov@nginx.com
6411625Smax.romanov@nginx.com        self.ws.frame_write(
6421625Smax.romanov@nginx.com            sock, self.ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True
6431625Smax.romanov@nginx.com        )
6441625Smax.romanov@nginx.com
6451625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6461625Smax.romanov@nginx.com
6471625Smax.romanov@nginx.com    def test_asgi_websockets_4_1_1__4_2_5(self):
6481625Smax.romanov@nginx.com        self.load('websockets/mirror')
6491625Smax.romanov@nginx.com
6501625Smax.romanov@nginx.com        payload = 'Hello, world!'
6511625Smax.romanov@nginx.com
6521625Smax.romanov@nginx.com        # 4_1_1
6531625Smax.romanov@nginx.com
6541625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6551625Smax.romanov@nginx.com
6561625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x03, '')
6571625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6581625Smax.romanov@nginx.com
6591625Smax.romanov@nginx.com        # 4_1_2
6601625Smax.romanov@nginx.com
6611625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6621625Smax.romanov@nginx.com
6631625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x04, 'reserved opcode payload')
6641625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6651625Smax.romanov@nginx.com
6661625Smax.romanov@nginx.com        # 4_1_3
6671625Smax.romanov@nginx.com
6681625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6691625Smax.romanov@nginx.com
6701625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
6711625Smax.romanov@nginx.com
6721625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
6731625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
6741625Smax.romanov@nginx.com
6751625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x05, '')
6761625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
6771625Smax.romanov@nginx.com
6781625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6791625Smax.romanov@nginx.com
6801625Smax.romanov@nginx.com        # 4_1_4
6811625Smax.romanov@nginx.com
6821625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6831625Smax.romanov@nginx.com
6841625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
6851625Smax.romanov@nginx.com
6861625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
6871625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
6881625Smax.romanov@nginx.com
6891625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x06, payload)
6901625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
6911625Smax.romanov@nginx.com
6921625Smax.romanov@nginx.com        self.check_close(sock, 1002)
6931625Smax.romanov@nginx.com
6941625Smax.romanov@nginx.com        # 4_1_5
6951625Smax.romanov@nginx.com
6961625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
6971625Smax.romanov@nginx.com
6981625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
6991625Smax.romanov@nginx.com
7001625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
7011625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
7021625Smax.romanov@nginx.com
7031625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x07, payload, chopsize=1)
7041625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
7051625Smax.romanov@nginx.com
7061625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7071625Smax.romanov@nginx.com
7081625Smax.romanov@nginx.com        # 4_2_1
7091625Smax.romanov@nginx.com
7101625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7111625Smax.romanov@nginx.com
7121625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x0B, '')
7131625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7141625Smax.romanov@nginx.com
7151625Smax.romanov@nginx.com        # 4_2_2
7161625Smax.romanov@nginx.com
7171625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7181625Smax.romanov@nginx.com
7191625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x0C, 'reserved opcode payload')
7201625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7211625Smax.romanov@nginx.com
7221625Smax.romanov@nginx.com        # 4_2_3
7231625Smax.romanov@nginx.com
7241625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7251625Smax.romanov@nginx.com
7261625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
7271625Smax.romanov@nginx.com
7281625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
7291625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
7301625Smax.romanov@nginx.com
7311625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x0D, '')
7321625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
7331625Smax.romanov@nginx.com
7341625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7351625Smax.romanov@nginx.com
7361625Smax.romanov@nginx.com        # 4_2_4
7371625Smax.romanov@nginx.com
7381625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7391625Smax.romanov@nginx.com
7401625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
7411625Smax.romanov@nginx.com
7421625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
7431625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
7441625Smax.romanov@nginx.com
7451625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x0E, payload)
7461625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
7471625Smax.romanov@nginx.com
7481625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7491625Smax.romanov@nginx.com
7501625Smax.romanov@nginx.com        # 4_2_5
7511625Smax.romanov@nginx.com
7521625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7531625Smax.romanov@nginx.com
7541625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
7551625Smax.romanov@nginx.com
7561625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
7571625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
7581625Smax.romanov@nginx.com
7591625Smax.romanov@nginx.com        self.ws.frame_write(sock, 0x0F, payload, chopsize=1)
7601625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
7611625Smax.romanov@nginx.com
7621625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7631625Smax.romanov@nginx.com
7641625Smax.romanov@nginx.com    def test_asgi_websockets_5_1__5_20(self):
7651625Smax.romanov@nginx.com        self.load('websockets/mirror')
7661625Smax.romanov@nginx.com
7671625Smax.romanov@nginx.com        # 5_1
7681625Smax.romanov@nginx.com
7691625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7701625Smax.romanov@nginx.com
7711625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, 'fragment1', fin=False)
7721625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
7731625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7741625Smax.romanov@nginx.com
7751625Smax.romanov@nginx.com        # 5_2
7761625Smax.romanov@nginx.com
7771625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7781625Smax.romanov@nginx.com
7791625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PONG, 'fragment1', fin=False)
7801625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
7811625Smax.romanov@nginx.com        self.check_close(sock, 1002)
7821625Smax.romanov@nginx.com
7831625Smax.romanov@nginx.com        # 5_3
7841625Smax.romanov@nginx.com
7851625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
7861625Smax.romanov@nginx.com
7871625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
7881625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
7891625Smax.romanov@nginx.com
7901625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
7911625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
7921625Smax.romanov@nginx.com
7931625Smax.romanov@nginx.com        # 5_4
7941625Smax.romanov@nginx.com
7951625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
7961625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', '5_4'
7971625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
7981625Smax.romanov@nginx.com
7991625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8001625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
8011625Smax.romanov@nginx.com
8021625Smax.romanov@nginx.com        # 5_5
8031625Smax.romanov@nginx.com
8041625Smax.romanov@nginx.com        self.ws.frame_write(
8051625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1
8061625Smax.romanov@nginx.com        )
8071625Smax.romanov@nginx.com        self.ws.frame_write(
8081625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1
8091625Smax.romanov@nginx.com        )
8101625Smax.romanov@nginx.com
8111625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8121625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
8131625Smax.romanov@nginx.com
8141625Smax.romanov@nginx.com        # 5_6
8151625Smax.romanov@nginx.com
8161625Smax.romanov@nginx.com        ping_payload = 'ping payload'
8171625Smax.romanov@nginx.com
8181625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
8191625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
8201625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
8211625Smax.romanov@nginx.com
8221625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8231625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
8241625Smax.romanov@nginx.com
8251625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8261625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
8271625Smax.romanov@nginx.com
8281625Smax.romanov@nginx.com        # 5_7
8291625Smax.romanov@nginx.com
8301625Smax.romanov@nginx.com        ping_payload = 'ping payload'
8311625Smax.romanov@nginx.com
8321625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
8331625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', '5_7'
8341625Smax.romanov@nginx.com
8351625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
8361625Smax.romanov@nginx.com
8371625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8381625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
8391625Smax.romanov@nginx.com
8401625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
8411625Smax.romanov@nginx.com
8421625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8431625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
8441625Smax.romanov@nginx.com
8451625Smax.romanov@nginx.com        # 5_8
8461625Smax.romanov@nginx.com
8471625Smax.romanov@nginx.com        ping_payload = 'ping payload'
8481625Smax.romanov@nginx.com
8491625Smax.romanov@nginx.com        self.ws.frame_write(
8501625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1
8511625Smax.romanov@nginx.com        )
8521625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload, chopsize=1)
8531625Smax.romanov@nginx.com        self.ws.frame_write(
8541625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1
8551625Smax.romanov@nginx.com        )
8561625Smax.romanov@nginx.com
8571625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8581625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
8591625Smax.romanov@nginx.com
8601625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
8611625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
8621625Smax.romanov@nginx.com
8631625Smax.romanov@nginx.com        # 5_9
8641625Smax.romanov@nginx.com
8651625Smax.romanov@nginx.com        self.ws.frame_write(
8661625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'non-continuation payload', fin=True
8671625Smax.romanov@nginx.com        )
8681625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
8691625Smax.romanov@nginx.com        self.check_close(sock, 1002)
8701625Smax.romanov@nginx.com
8711625Smax.romanov@nginx.com        # 5_10
8721625Smax.romanov@nginx.com
8731625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
8741625Smax.romanov@nginx.com
8751625Smax.romanov@nginx.com        self.ws.frame_write(
8761625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'non-continuation payload', fin=True
8771625Smax.romanov@nginx.com        )
8781625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
8791625Smax.romanov@nginx.com        self.check_close(sock, 1002)
8801625Smax.romanov@nginx.com
8811625Smax.romanov@nginx.com        # 5_11
8821625Smax.romanov@nginx.com
8831625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
8841625Smax.romanov@nginx.com
8851625Smax.romanov@nginx.com        self.ws.frame_write(
8861625Smax.romanov@nginx.com            sock,
8871625Smax.romanov@nginx.com            self.ws.OP_CONT,
8881625Smax.romanov@nginx.com            'non-continuation payload',
8891625Smax.romanov@nginx.com            fin=True,
8901625Smax.romanov@nginx.com            chopsize=1,
8911625Smax.romanov@nginx.com        )
8921625Smax.romanov@nginx.com        self.ws.frame_write(
8931625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1
8941625Smax.romanov@nginx.com        )
8951625Smax.romanov@nginx.com        self.check_close(sock, 1002)
8961625Smax.romanov@nginx.com
8971625Smax.romanov@nginx.com        # 5_12
8981625Smax.romanov@nginx.com
8991625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9001625Smax.romanov@nginx.com
9011625Smax.romanov@nginx.com        self.ws.frame_write(
9021625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'non-continuation payload', fin=False
9031625Smax.romanov@nginx.com        )
9041625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
9051625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9061625Smax.romanov@nginx.com
9071625Smax.romanov@nginx.com        # 5_13
9081625Smax.romanov@nginx.com
9091625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9101625Smax.romanov@nginx.com
9111625Smax.romanov@nginx.com        self.ws.frame_write(
9121625Smax.romanov@nginx.com            sock, self.ws.OP_CONT, 'non-continuation payload', fin=False
9131625Smax.romanov@nginx.com        )
9141625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
9151625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9161625Smax.romanov@nginx.com
9171625Smax.romanov@nginx.com        # 5_14
9181625Smax.romanov@nginx.com
9191625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9201625Smax.romanov@nginx.com
9211625Smax.romanov@nginx.com        self.ws.frame_write(
9221625Smax.romanov@nginx.com            sock,
9231625Smax.romanov@nginx.com            self.ws.OP_CONT,
9241625Smax.romanov@nginx.com            'non-continuation payload',
9251625Smax.romanov@nginx.com            fin=False,
9261625Smax.romanov@nginx.com            chopsize=1,
9271625Smax.romanov@nginx.com        )
9281625Smax.romanov@nginx.com        self.ws.frame_write(
9291625Smax.romanov@nginx.com            sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1
9301625Smax.romanov@nginx.com        )
9311625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9321625Smax.romanov@nginx.com
9331625Smax.romanov@nginx.com        # 5_15
9341625Smax.romanov@nginx.com
9351625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9361625Smax.romanov@nginx.com
9371625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
9381625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
9391625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
9401625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True)
9411819Smax.romanov@nginx.com
9421819Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
9431819Smax.romanov@nginx.com
9441819Smax.romanov@nginx.com        if frame['opcode'] == self.ws.OP_TEXT:
9451848Szelenkov@nginx.com            self.check_frame(
9461848Szelenkov@nginx.com                frame, True, self.ws.OP_TEXT, 'fragment1fragment2'
9471848Szelenkov@nginx.com            )
9481819Smax.romanov@nginx.com            frame = None
9491819Smax.romanov@nginx.com
9501819Smax.romanov@nginx.com        self.check_close(sock, 1002, frame=frame)
9511625Smax.romanov@nginx.com
9521625Smax.romanov@nginx.com        # 5_16
9531625Smax.romanov@nginx.com
9541625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9551625Smax.romanov@nginx.com
9561625Smax.romanov@nginx.com        for i in range(0, 2):
9571625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment1', fin=False)
9581625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2', fin=False)
9591625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=True)
9601625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9611625Smax.romanov@nginx.com
9621625Smax.romanov@nginx.com        # 5_17
9631625Smax.romanov@nginx.com
9641625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9651625Smax.romanov@nginx.com
9661625Smax.romanov@nginx.com        for i in range(0, 2):
9671625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment1', fin=True)
9681625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2', fin=False)
9691625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=True)
9701625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9711625Smax.romanov@nginx.com
9721625Smax.romanov@nginx.com        # 5_18
9731625Smax.romanov@nginx.com
9741625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9751625Smax.romanov@nginx.com
9761625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
9771625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment2')
9781625Smax.romanov@nginx.com        self.check_close(sock, 1002)
9791625Smax.romanov@nginx.com
9801625Smax.romanov@nginx.com        # 5_19
9811625Smax.romanov@nginx.com
9821625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
9831625Smax.romanov@nginx.com
9841625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
9851625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=False)
9861625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 1!')
9871625Smax.romanov@nginx.com
9881625Smax.romanov@nginx.com        time.sleep(1)
9891625Smax.romanov@nginx.com
9901625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
9911625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment4', fin=False)
9921625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 2!')
9931625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
9941625Smax.romanov@nginx.com
9951625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
9961625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 1!')
9971625Smax.romanov@nginx.com
9981625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
9991625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
10001625Smax.romanov@nginx.com
10011625Smax.romanov@nginx.com        self.check_frame(
10021625Smax.romanov@nginx.com            self.ws.frame_read(sock),
10031625Smax.romanov@nginx.com            True,
10041625Smax.romanov@nginx.com            self.ws.OP_TEXT,
10051625Smax.romanov@nginx.com            'fragment1fragment2fragment3fragment4fragment5',
10061625Smax.romanov@nginx.com        )
10071625Smax.romanov@nginx.com
10081625Smax.romanov@nginx.com        # 5_20
10091625Smax.romanov@nginx.com
10101625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
10111625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=False)
10121625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 1!')
10131625Smax.romanov@nginx.com
10141625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10151625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 1!')
10161625Smax.romanov@nginx.com
10171625Smax.romanov@nginx.com        time.sleep(1)
10181625Smax.romanov@nginx.com
10191625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
10201625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment4', fin=False)
10211625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, 'pongme 2!')
10221625Smax.romanov@nginx.com
10231625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10241625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
10251625Smax.romanov@nginx.com
10261625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', '5_20'
10271625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
10281625Smax.romanov@nginx.com
10291625Smax.romanov@nginx.com        self.check_frame(
10301625Smax.romanov@nginx.com            self.ws.frame_read(sock),
10311625Smax.romanov@nginx.com            True,
10321625Smax.romanov@nginx.com            self.ws.OP_TEXT,
10331625Smax.romanov@nginx.com            'fragment1fragment2fragment3fragment4fragment5',
10341625Smax.romanov@nginx.com        )
10351625Smax.romanov@nginx.com
10361625Smax.romanov@nginx.com        self.close_connection(sock)
10371625Smax.romanov@nginx.com
10381625Smax.romanov@nginx.com    def test_asgi_websockets_6_1_1__6_4_4(self):
10391625Smax.romanov@nginx.com        self.load('websockets/mirror')
10401625Smax.romanov@nginx.com
10411625Smax.romanov@nginx.com        # 6_1_1
10421625Smax.romanov@nginx.com
10431625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
10441625Smax.romanov@nginx.com
10451625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, '')
10461625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10471625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, '')
10481625Smax.romanov@nginx.com
10491625Smax.romanov@nginx.com        # 6_1_2
10501625Smax.romanov@nginx.com
10511625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, '', fin=False)
10521625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, '', fin=False)
10531625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, '')
10541625Smax.romanov@nginx.com
10551625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10561625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, '')
10571625Smax.romanov@nginx.com
10581625Smax.romanov@nginx.com        # 6_1_3
10591625Smax.romanov@nginx.com
10601625Smax.romanov@nginx.com        payload = 'middle frame payload'
10611625Smax.romanov@nginx.com
10621625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, '', fin=False)
10631625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, payload, fin=False)
10641625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, '')
10651625Smax.romanov@nginx.com
10661625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10671625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
10681625Smax.romanov@nginx.com
10691625Smax.romanov@nginx.com        # 6_2_1
10701625Smax.romanov@nginx.com
10711625Smax.romanov@nginx.com        payload = 'Hello-µ@ßöäüàá-UTF-8!!'
10721625Smax.romanov@nginx.com
10731625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
10741625Smax.romanov@nginx.com
10751625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10761625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
10771625Smax.romanov@nginx.com
10781625Smax.romanov@nginx.com        # 6_2_2
10791625Smax.romanov@nginx.com
10801625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload[:12], fin=False)
10811625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, payload[12:])
10821625Smax.romanov@nginx.com
10831625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10841625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
10851625Smax.romanov@nginx.com
10861625Smax.romanov@nginx.com        # 6_2_3
10871625Smax.romanov@nginx.com
10881625Smax.romanov@nginx.com        self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1)
10891625Smax.romanov@nginx.com
10901625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
10911625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
10921625Smax.romanov@nginx.com
10931625Smax.romanov@nginx.com        # 6_2_4
10941625Smax.romanov@nginx.com
10951625Smax.romanov@nginx.com        payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5'
10961625Smax.romanov@nginx.com
10971625Smax.romanov@nginx.com        self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1)
10981625Smax.romanov@nginx.com
10991625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
11001625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
11011625Smax.romanov@nginx.com
11021625Smax.romanov@nginx.com        self.close_connection(sock)
11031625Smax.romanov@nginx.com
11041848Szelenkov@nginx.com    #        Unit does not support UTF-8 validation
11051848Szelenkov@nginx.com    #
11061848Szelenkov@nginx.com    #        # 6_3_1 FAIL
11071848Szelenkov@nginx.com    #
11081848Szelenkov@nginx.com    #        payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5'
11091848Szelenkov@nginx.com    #        payload_2 = '\xed\xa0\x80'
11101848Szelenkov@nginx.com    #        payload_3 = '\x65\x64\x69\x74\x65\x64'
11111848Szelenkov@nginx.com    #
11121848Szelenkov@nginx.com    #        payload = payload_1 + payload_2 + payload_3
11131848Szelenkov@nginx.com    #
11141848Szelenkov@nginx.com    #        self.ws.message(sock, self.ws.OP_TEXT, payload)
11151848Szelenkov@nginx.com    #        self.check_close(sock, 1007)
11161848Szelenkov@nginx.com    #
11171848Szelenkov@nginx.com    #        # 6_3_2 FAIL
11181848Szelenkov@nginx.com    #
11191848Szelenkov@nginx.com    #        _, sock, _ = self.ws.upgrade()
11201848Szelenkov@nginx.com    #
11211848Szelenkov@nginx.com    #        self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1)
11221848Szelenkov@nginx.com    #        self.check_close(sock, 1007)
11231848Szelenkov@nginx.com    #
11241848Szelenkov@nginx.com    #        # 6_4_1 ... 6_4_4 FAIL
11251625Smax.romanov@nginx.com
11261625Smax.romanov@nginx.com    def test_asgi_websockets_7_1_1__7_5_1(self):
11271625Smax.romanov@nginx.com        self.load('websockets/mirror')
11281625Smax.romanov@nginx.com
11291625Smax.romanov@nginx.com        # 7_1_1
11301625Smax.romanov@nginx.com
11311625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11321625Smax.romanov@nginx.com
11331625Smax.romanov@nginx.com        payload = "Hello World!"
11341625Smax.romanov@nginx.com
11351625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
11361625Smax.romanov@nginx.com
11371625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
11381625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
11391625Smax.romanov@nginx.com
11401625Smax.romanov@nginx.com        self.close_connection(sock)
11411625Smax.romanov@nginx.com
11421625Smax.romanov@nginx.com        # 7_1_2
11431625Smax.romanov@nginx.com
11441625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11451625Smax.romanov@nginx.com
11461625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11471625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11481625Smax.romanov@nginx.com
11491625Smax.romanov@nginx.com        self.check_close(sock)
11501625Smax.romanov@nginx.com
11511625Smax.romanov@nginx.com        # 7_1_3
11521625Smax.romanov@nginx.com
11531625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11541625Smax.romanov@nginx.com
11551625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11561625Smax.romanov@nginx.com        self.check_close(sock, no_close=True)
11571625Smax.romanov@nginx.com
11581625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
11591625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
11601625Smax.romanov@nginx.com
11611625Smax.romanov@nginx.com        sock.close()
11621625Smax.romanov@nginx.com
11631625Smax.romanov@nginx.com        # 7_1_4
11641625Smax.romanov@nginx.com
11651625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11661625Smax.romanov@nginx.com
11671625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11681625Smax.romanov@nginx.com        self.check_close(sock, no_close=True)
11691625Smax.romanov@nginx.com
11701625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
11711625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
11721625Smax.romanov@nginx.com
11731625Smax.romanov@nginx.com        sock.close()
11741625Smax.romanov@nginx.com
11751625Smax.romanov@nginx.com        # 7_1_5
11761625Smax.romanov@nginx.com
11771625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11781625Smax.romanov@nginx.com
11791625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
11801625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11811625Smax.romanov@nginx.com        self.check_close(sock, no_close=True)
11821625Smax.romanov@nginx.com
11831625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2')
11841625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
11851625Smax.romanov@nginx.com
11861625Smax.romanov@nginx.com        sock.close()
11871625Smax.romanov@nginx.com
11881625Smax.romanov@nginx.com        # 7_1_6
11891625Smax.romanov@nginx.com
11901625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
11911625Smax.romanov@nginx.com
11921625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2 ** 10)
11931625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
11941625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
11951625Smax.romanov@nginx.com
11961625Smax.romanov@nginx.com        self.recvall(sock, read_timeout=1)
11971625Smax.romanov@nginx.com
11981625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_PING, '')
11991625Smax.romanov@nginx.com        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
12001625Smax.romanov@nginx.com
12011625Smax.romanov@nginx.com        sock.close()
12021625Smax.romanov@nginx.com
12031625Smax.romanov@nginx.com        # 7_3_1
12041625Smax.romanov@nginx.com
12051625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12061625Smax.romanov@nginx.com
12071625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, '')
12081625Smax.romanov@nginx.com        self.check_close(sock)
12091625Smax.romanov@nginx.com
12101625Smax.romanov@nginx.com        # 7_3_2
12111625Smax.romanov@nginx.com
12121625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12131625Smax.romanov@nginx.com
12141625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, 'a')
12151625Smax.romanov@nginx.com        self.check_close(sock, 1002)
12161625Smax.romanov@nginx.com
12171625Smax.romanov@nginx.com        # 7_3_3
12181625Smax.romanov@nginx.com
12191625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12201625Smax.romanov@nginx.com
12211625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
12221625Smax.romanov@nginx.com        self.check_close(sock)
12231625Smax.romanov@nginx.com
12241625Smax.romanov@nginx.com        # 7_3_4
12251625Smax.romanov@nginx.com
12261625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12271625Smax.romanov@nginx.com
12281625Smax.romanov@nginx.com        payload = self.ws.serialize_close(reason='Hello World!')
12291625Smax.romanov@nginx.com
12301625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12311625Smax.romanov@nginx.com        self.check_close(sock)
12321625Smax.romanov@nginx.com
12331625Smax.romanov@nginx.com        # 7_3_5
12341625Smax.romanov@nginx.com
12351625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12361625Smax.romanov@nginx.com
12371625Smax.romanov@nginx.com        payload = self.ws.serialize_close(reason='*' * 123)
12381625Smax.romanov@nginx.com
12391625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12401625Smax.romanov@nginx.com        self.check_close(sock)
12411625Smax.romanov@nginx.com
12421625Smax.romanov@nginx.com        # 7_3_6
12431625Smax.romanov@nginx.com
12441625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
12451625Smax.romanov@nginx.com
12461625Smax.romanov@nginx.com        payload = self.ws.serialize_close(reason='*' * 124)
12471625Smax.romanov@nginx.com
12481625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12491625Smax.romanov@nginx.com        self.check_close(sock, 1002)
12501625Smax.romanov@nginx.com
12511848Szelenkov@nginx.com    #        # 7_5_1 FAIL Unit does not support UTF-8 validation
12521848Szelenkov@nginx.com    #
12531848Szelenkov@nginx.com    #        _, sock, _ = self.ws.upgrade()
12541848Szelenkov@nginx.com    #
12551848Szelenkov@nginx.com    #        payload = self.ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \
12561848Szelenkov@nginx.com    #            '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64')
12571848Szelenkov@nginx.com    #
12581848Szelenkov@nginx.com    #        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12591848Szelenkov@nginx.com    #        self.check_close(sock, 1007)
12601625Smax.romanov@nginx.com
12611625Smax.romanov@nginx.com    def test_asgi_websockets_7_7_X__7_9_X(self):
12621625Smax.romanov@nginx.com        self.load('websockets/mirror')
12631625Smax.romanov@nginx.com
12641625Smax.romanov@nginx.com        valid_codes = [
12651625Smax.romanov@nginx.com            1000,
12661625Smax.romanov@nginx.com            1001,
12671625Smax.romanov@nginx.com            1002,
12681625Smax.romanov@nginx.com            1003,
12691625Smax.romanov@nginx.com            1007,
12701625Smax.romanov@nginx.com            1008,
12711625Smax.romanov@nginx.com            1009,
12721625Smax.romanov@nginx.com            1010,
12731625Smax.romanov@nginx.com            1011,
12741625Smax.romanov@nginx.com            3000,
12751625Smax.romanov@nginx.com            3999,
12761625Smax.romanov@nginx.com            4000,
12771625Smax.romanov@nginx.com            4999,
12781625Smax.romanov@nginx.com        ]
12791625Smax.romanov@nginx.com
12801625Smax.romanov@nginx.com        invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999]
12811625Smax.romanov@nginx.com
12821625Smax.romanov@nginx.com        for code in valid_codes:
12831625Smax.romanov@nginx.com            _, sock, _ = self.ws.upgrade()
12841625Smax.romanov@nginx.com
12851625Smax.romanov@nginx.com            payload = self.ws.serialize_close(code=code)
12861625Smax.romanov@nginx.com
12871625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12881625Smax.romanov@nginx.com            self.check_close(sock)
12891625Smax.romanov@nginx.com
12901625Smax.romanov@nginx.com        for code in invalid_codes:
12911625Smax.romanov@nginx.com            _, sock, _ = self.ws.upgrade()
12921625Smax.romanov@nginx.com
12931625Smax.romanov@nginx.com            payload = self.ws.serialize_close(code=code)
12941625Smax.romanov@nginx.com
12951625Smax.romanov@nginx.com            self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
12961625Smax.romanov@nginx.com            self.check_close(sock, 1002)
12971625Smax.romanov@nginx.com
12981625Smax.romanov@nginx.com    def test_asgi_websockets_7_13_1__7_13_2(self):
12991625Smax.romanov@nginx.com        self.load('websockets/mirror')
13001625Smax.romanov@nginx.com
13011625Smax.romanov@nginx.com        # 7_13_1
13021625Smax.romanov@nginx.com
13031625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
13041625Smax.romanov@nginx.com
13051625Smax.romanov@nginx.com        payload = self.ws.serialize_close(code=5000)
13061625Smax.romanov@nginx.com
13071625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
13081625Smax.romanov@nginx.com        self.check_close(sock, 1002)
13091625Smax.romanov@nginx.com
13101625Smax.romanov@nginx.com        # 7_13_2
13111625Smax.romanov@nginx.com
13121625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
13131625Smax.romanov@nginx.com
13141625Smax.romanov@nginx.com        payload = struct.pack('!I', 65536) + ''.encode('utf-8')
13151625Smax.romanov@nginx.com
13161625Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
13171625Smax.romanov@nginx.com        self.check_close(sock, 1002)
13181625Smax.romanov@nginx.com
13191625Smax.romanov@nginx.com    def test_asgi_websockets_9_1_1__9_6_6(self, is_unsafe):
13201625Smax.romanov@nginx.com        if not is_unsafe:
13211625Smax.romanov@nginx.com            pytest.skip('unsafe, long run')
13221625Smax.romanov@nginx.com
13231625Smax.romanov@nginx.com        self.load('websockets/mirror')
13241625Smax.romanov@nginx.com
13251625Smax.romanov@nginx.com        assert 'success' in self.conf(
13261625Smax.romanov@nginx.com            {
13271625Smax.romanov@nginx.com                'http': {
13281625Smax.romanov@nginx.com                    'websocket': {
13291625Smax.romanov@nginx.com                        'max_frame_size': 33554432,
13301625Smax.romanov@nginx.com                        'keepalive_interval': 0,
13311625Smax.romanov@nginx.com                    }
13321625Smax.romanov@nginx.com                }
13331625Smax.romanov@nginx.com            },
13341625Smax.romanov@nginx.com            'settings',
13351625Smax.romanov@nginx.com        ), 'increase max_frame_size and keepalive_interval'
13361625Smax.romanov@nginx.com
13371625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
13381625Smax.romanov@nginx.com
13391625Smax.romanov@nginx.com        op_text = self.ws.OP_TEXT
13401625Smax.romanov@nginx.com        op_binary = self.ws.OP_BINARY
13411625Smax.romanov@nginx.com
13421625Smax.romanov@nginx.com        def check_payload(opcode, length, chopsize=None):
13431625Smax.romanov@nginx.com            if opcode == self.ws.OP_TEXT:
13441625Smax.romanov@nginx.com                payload = '*' * length
13451625Smax.romanov@nginx.com            else:
13461625Smax.romanov@nginx.com                payload = b'*' * length
13471625Smax.romanov@nginx.com
13481625Smax.romanov@nginx.com            self.ws.frame_write(sock, opcode, payload, chopsize=chopsize)
13491625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock, read_timeout=5)
13501625Smax.romanov@nginx.com            self.check_frame(frame, True, opcode, payload)
13511625Smax.romanov@nginx.com
13521625Smax.romanov@nginx.com        def check_message(opcode, f_size):
13531625Smax.romanov@nginx.com            if opcode == self.ws.OP_TEXT:
13541625Smax.romanov@nginx.com                payload = '*' * 4 * 2 ** 20
13551625Smax.romanov@nginx.com            else:
13561625Smax.romanov@nginx.com                payload = b'*' * 4 * 2 ** 20
13571625Smax.romanov@nginx.com
13581625Smax.romanov@nginx.com            self.ws.message(sock, opcode, payload, fragmention_size=f_size)
13591625Smax.romanov@nginx.com            frame = self.ws.frame_read(sock, read_timeout=5)
13601625Smax.romanov@nginx.com            self.check_frame(frame, True, opcode, payload)
13611625Smax.romanov@nginx.com
13621848Szelenkov@nginx.com        check_payload(op_text, 64 * 2 ** 10)  # 9_1_1
13631848Szelenkov@nginx.com        check_payload(op_text, 256 * 2 ** 10)  # 9_1_2
13641848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20)  # 9_1_3
13651848Szelenkov@nginx.com        check_payload(op_text, 4 * 2 ** 20)  # 9_1_4
13661848Szelenkov@nginx.com        check_payload(op_text, 8 * 2 ** 20)  # 9_1_5
13671848Szelenkov@nginx.com        check_payload(op_text, 16 * 2 ** 20)  # 9_1_6
13681625Smax.romanov@nginx.com
13691848Szelenkov@nginx.com        check_payload(op_binary, 64 * 2 ** 10)  # 9_2_1
13701848Szelenkov@nginx.com        check_payload(op_binary, 256 * 2 ** 10)  # 9_2_2
13711848Szelenkov@nginx.com        check_payload(op_binary, 2 ** 20)  # 9_2_3
13721848Szelenkov@nginx.com        check_payload(op_binary, 4 * 2 ** 20)  # 9_2_4
13731848Szelenkov@nginx.com        check_payload(op_binary, 8 * 2 ** 20)  # 9_2_5
13741848Szelenkov@nginx.com        check_payload(op_binary, 16 * 2 ** 20)  # 9_2_6
13751625Smax.romanov@nginx.com
13761625Smax.romanov@nginx.com        if option.system != 'Darwin' and option.system != 'FreeBSD':
13771848Szelenkov@nginx.com            check_message(op_text, 64)  # 9_3_1
13781848Szelenkov@nginx.com            check_message(op_text, 256)  # 9_3_2
13791848Szelenkov@nginx.com            check_message(op_text, 2 ** 10)  # 9_3_3
13801848Szelenkov@nginx.com            check_message(op_text, 4 * 2 ** 10)  # 9_3_4
13811848Szelenkov@nginx.com            check_message(op_text, 16 * 2 ** 10)  # 9_3_5
13821848Szelenkov@nginx.com            check_message(op_text, 64 * 2 ** 10)  # 9_3_6
13831848Szelenkov@nginx.com            check_message(op_text, 256 * 2 ** 10)  # 9_3_7
13841848Szelenkov@nginx.com            check_message(op_text, 2 ** 20)  # 9_3_8
13851848Szelenkov@nginx.com            check_message(op_text, 4 * 2 ** 20)  # 9_3_9
13861625Smax.romanov@nginx.com
13871848Szelenkov@nginx.com            check_message(op_binary, 64)  # 9_4_1
13881848Szelenkov@nginx.com            check_message(op_binary, 256)  # 9_4_2
13891848Szelenkov@nginx.com            check_message(op_binary, 2 ** 10)  # 9_4_3
13901848Szelenkov@nginx.com            check_message(op_binary, 4 * 2 ** 10)  # 9_4_4
13911848Szelenkov@nginx.com            check_message(op_binary, 16 * 2 ** 10)  # 9_4_5
13921848Szelenkov@nginx.com            check_message(op_binary, 64 * 2 ** 10)  # 9_4_6
13931848Szelenkov@nginx.com            check_message(op_binary, 256 * 2 ** 10)  # 9_4_7
13941848Szelenkov@nginx.com            check_message(op_binary, 2 ** 20)  # 9_4_8
13951848Szelenkov@nginx.com            check_message(op_binary, 4 * 2 ** 20)  # 9_4_9
13961625Smax.romanov@nginx.com
13971848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=64)  # 9_5_1
13981848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=128)  # 9_5_2
13991848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=256)  # 9_5_3
14001848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=512)  # 9_5_4
14011848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=1024)  # 9_5_5
14021848Szelenkov@nginx.com        check_payload(op_text, 2 ** 20, chopsize=2048)  # 9_5_6
14031625Smax.romanov@nginx.com
14041848Szelenkov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=64)  # 9_6_1
14051848Szelenkov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=128)  # 9_6_2
14061848Szelenkov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=256)  # 9_6_3
14071848Szelenkov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=512)  # 9_6_4
14081625Smax.romanov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=1024)  # 9_6_5
14091625Smax.romanov@nginx.com        check_payload(op_binary, 2 ** 20, chopsize=2048)  # 9_6_6
14101625Smax.romanov@nginx.com
14111625Smax.romanov@nginx.com        self.close_connection(sock)
14121625Smax.romanov@nginx.com
14131625Smax.romanov@nginx.com    def test_asgi_websockets_10_1_1(self):
14141625Smax.romanov@nginx.com        self.load('websockets/mirror')
14151625Smax.romanov@nginx.com
14161625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
14171625Smax.romanov@nginx.com
14181625Smax.romanov@nginx.com        payload = '*' * 65536
14191625Smax.romanov@nginx.com
14201625Smax.romanov@nginx.com        self.ws.message(sock, self.ws.OP_TEXT, payload, fragmention_size=1300)
14211625Smax.romanov@nginx.com
14221625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
14231625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
14241625Smax.romanov@nginx.com
14251625Smax.romanov@nginx.com        self.close_connection(sock)
14261625Smax.romanov@nginx.com
14271625Smax.romanov@nginx.com    # settings
14281625Smax.romanov@nginx.com
14291625Smax.romanov@nginx.com    def test_asgi_websockets_max_frame_size(self):
14301625Smax.romanov@nginx.com        self.load('websockets/mirror')
14311625Smax.romanov@nginx.com
14321625Smax.romanov@nginx.com        assert 'success' in self.conf(
14331625Smax.romanov@nginx.com            {'http': {'websocket': {'max_frame_size': 100}}}, 'settings'
14341625Smax.romanov@nginx.com        ), 'configure max_frame_size'
14351625Smax.romanov@nginx.com
14361625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
14371625Smax.romanov@nginx.com
14381625Smax.romanov@nginx.com        payload = '*' * 94
14391625Smax.romanov@nginx.com        opcode = self.ws.OP_TEXT
14401625Smax.romanov@nginx.com
14411625Smax.romanov@nginx.com        self.ws.frame_write(sock, opcode, payload)  # frame length is 100
14421625Smax.romanov@nginx.com
14431625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
14441625Smax.romanov@nginx.com        self.check_frame(frame, True, opcode, payload)
14451625Smax.romanov@nginx.com
14461625Smax.romanov@nginx.com        payload = '*' * 95
14471625Smax.romanov@nginx.com
14481625Smax.romanov@nginx.com        self.ws.frame_write(sock, opcode, payload)  # frame length is 101
14491625Smax.romanov@nginx.com        self.check_close(sock, 1009)  # 1009 - CLOSE_TOO_LARGE
14501625Smax.romanov@nginx.com
14511625Smax.romanov@nginx.com    def test_asgi_websockets_read_timeout(self):
14521625Smax.romanov@nginx.com        self.load('websockets/mirror')
14531625Smax.romanov@nginx.com
14541625Smax.romanov@nginx.com        assert 'success' in self.conf(
14551625Smax.romanov@nginx.com            {'http': {'websocket': {'read_timeout': 5}}}, 'settings'
14561625Smax.romanov@nginx.com        ), 'configure read_timeout'
14571625Smax.romanov@nginx.com
14581625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
14591625Smax.romanov@nginx.com
14601625Smax.romanov@nginx.com        frame = self.ws.frame_to_send(self.ws.OP_TEXT, 'blah')
14611625Smax.romanov@nginx.com        sock.sendall(frame[:2])
14621625Smax.romanov@nginx.com
14631625Smax.romanov@nginx.com        time.sleep(2)
14641625Smax.romanov@nginx.com
14651625Smax.romanov@nginx.com        self.check_close(sock, 1001)  # 1001 - CLOSE_GOING_AWAY
14661625Smax.romanov@nginx.com
14671625Smax.romanov@nginx.com    def test_asgi_websockets_keepalive_interval(self):
14681625Smax.romanov@nginx.com        self.load('websockets/mirror')
14691625Smax.romanov@nginx.com
14701625Smax.romanov@nginx.com        assert 'success' in self.conf(
14711625Smax.romanov@nginx.com            {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings'
14721625Smax.romanov@nginx.com        ), 'configure keepalive_interval'
14731625Smax.romanov@nginx.com
14741625Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
14751625Smax.romanov@nginx.com
14761625Smax.romanov@nginx.com        frame = self.ws.frame_to_send(self.ws.OP_TEXT, 'blah')
14771625Smax.romanov@nginx.com        sock.sendall(frame[:2])
14781625Smax.romanov@nginx.com
14791625Smax.romanov@nginx.com        time.sleep(2)
14801625Smax.romanov@nginx.com
14811625Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
14821625Smax.romanov@nginx.com        self.check_frame(frame, True, self.ws.OP_PING, '')  # PING frame
14831625Smax.romanov@nginx.com
14841625Smax.romanov@nginx.com        sock.close()
14851956Smax.romanov@nginx.com
14861956Smax.romanov@nginx.com    def test_asgi_websockets_client_locks_app(self):
14871956Smax.romanov@nginx.com        self.load('websockets/mirror')
14881956Smax.romanov@nginx.com
14891956Smax.romanov@nginx.com        message = 'blah'
14901956Smax.romanov@nginx.com
14911956Smax.romanov@nginx.com        _, sock, _ = self.ws.upgrade()
14921956Smax.romanov@nginx.com
14931956Smax.romanov@nginx.com        assert 'success' in self.conf({}), 'remove app'
14941956Smax.romanov@nginx.com
14951956Smax.romanov@nginx.com        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
14961956Smax.romanov@nginx.com
14971956Smax.romanov@nginx.com        frame = self.ws.frame_read(sock)
14981956Smax.romanov@nginx.com
14991956Smax.romanov@nginx.com        assert message == frame['data'].decode('utf-8'), 'client'
15001956Smax.romanov@nginx.com
15011956Smax.romanov@nginx.com        sock.close()
1502