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