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