xref: /unit/test/test_asgi_websockets.py (revision 2073:bc6ad31ce286)
1import struct
2import time
3
4import pytest
5from packaging import version
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': {
14            'python': lambda v: version.parse(v) >= version.parse('3.5')
15        }
16    }
17    load_module = 'asgi'
18
19    ws = TestApplicationWebsocket()
20
21    @pytest.fixture(autouse=True)
22    def setup_method_fixture(self, request, skip_alert):
23        assert 'success' in self.conf(
24            {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
25        ), 'clear keepalive_interval'
26
27        skip_alert(r'socket close\(\d+\) failed')
28
29    def close_connection(self, sock):
30        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
31
32        self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
33
34        self.check_close(sock)
35
36    def check_close(self, sock, code=1000, no_close=False, frame=None):
37        if frame == None:
38            frame = self.ws.frame_read(sock)
39
40        assert frame['fin'] == True, 'close fin'
41        assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
42        assert frame['code'] == code, 'close code'
43
44        if not no_close:
45            sock.close()
46
47    def check_frame(self, frame, fin, opcode, payload, decode=True):
48        if opcode == self.ws.OP_BINARY or not decode:
49            data = frame['data']
50        else:
51            data = frame['data'].decode('utf-8')
52
53        assert frame['fin'] == fin, 'fin'
54        assert frame['opcode'] == opcode, 'opcode'
55        assert data == payload, 'payload'
56
57    def test_asgi_websockets_handshake(self):
58        self.load('websockets/mirror')
59
60        resp, sock, key = self.ws.upgrade()
61        sock.close()
62
63        assert resp['status'] == 101, 'status'
64        assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
65        assert resp['headers']['Connection'] == 'Upgrade', 'connection'
66        assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
67            key
68        ), 'key'
69
70        # remove "mirror" application
71        self.load('websockets/subprotocol')
72
73    def test_asgi_websockets_subprotocol(self):
74        self.load('websockets/subprotocol')
75
76        resp, sock, key = self.ws.upgrade()
77        sock.close()
78
79        assert resp['status'] == 101, 'status'
80        assert (
81            resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')"
82        ), 'subprotocols'
83        assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key'
84
85    def test_asgi_websockets_mirror(self):
86        self.load('websockets/mirror')
87
88        message = 'blah'
89
90        _, sock, _ = self.ws.upgrade()
91
92        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
93        frame = self.ws.frame_read(sock)
94
95        assert message == frame['data'].decode('utf-8'), 'mirror'
96
97        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
98        frame = self.ws.frame_read(sock)
99
100        assert message == frame['data'].decode('utf-8'), 'mirror 2'
101
102        sock.close()
103
104    def test_asgi_websockets_mirror_app_change(self):
105        self.load('websockets/mirror')
106
107        message = 'blah'
108
109        _, sock, _ = self.ws.upgrade()
110
111        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
112        frame = self.ws.frame_read(sock)
113
114        assert message == frame['data'].decode('utf-8'), 'mirror'
115
116        self.load('websockets/subprotocol')
117
118        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
119        frame = self.ws.frame_read(sock)
120
121        assert message == frame['data'].decode('utf-8'), 'mirror 2'
122
123        sock.close()
124
125    def test_asgi_websockets_no_mask(self):
126        self.load('websockets/mirror')
127
128        message = 'blah'
129
130        _, sock, _ = self.ws.upgrade()
131
132        self.ws.frame_write(sock, self.ws.OP_TEXT, message, mask=False)
133
134        frame = self.ws.frame_read(sock)
135
136        assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode'
137        assert frame['code'] == 1002, 'no mask close code'
138
139        sock.close()
140
141    def test_asgi_websockets_fragmentation(self):
142        self.load('websockets/mirror')
143
144        message = 'blah'
145
146        _, sock, _ = self.ws.upgrade()
147
148        self.ws.frame_write(sock, self.ws.OP_TEXT, message, fin=False)
149        self.ws.frame_write(sock, self.ws.OP_CONT, ' ', fin=False)
150        self.ws.frame_write(sock, self.ws.OP_CONT, message)
151
152        frame = self.ws.frame_read(sock)
153
154        assert message + ' ' + message == frame['data'].decode(
155            'utf-8'
156        ), 'mirror framing'
157
158        sock.close()
159
160    def test_asgi_websockets_length_long(self):
161        self.load('websockets/mirror')
162
163        _, sock, _ = self.ws.upgrade()
164
165        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
166        self.ws.frame_write(
167            sock, self.ws.OP_CONT, 'fragment2', length=2**64 - 1
168        )
169
170        self.check_close(sock, 1009)  # 1009 - CLOSE_TOO_LARGE
171
172    def test_asgi_websockets_frame_fragmentation_invalid(self):
173        self.load('websockets/mirror')
174
175        message = 'blah'
176
177        _, sock, _ = self.ws.upgrade()
178
179        self.ws.frame_write(sock, self.ws.OP_PING, message, fin=False)
180
181        frame = self.ws.frame_read(sock)
182
183        frame.pop('data')
184        assert frame == {
185            'fin': True,
186            'rsv1': False,
187            'rsv2': False,
188            'rsv3': False,
189            'opcode': self.ws.OP_CLOSE,
190            'mask': 0,
191            'code': 1002,
192            'reason': 'Fragmented control frame',
193        }, 'close frame'
194
195        sock.close()
196
197    def test_asgi_websockets_large(self):
198        self.load('websockets/mirror')
199
200        message = '0123456789' * 300
201
202        _, sock, _ = self.ws.upgrade()
203
204        self.ws.frame_write(sock, self.ws.OP_TEXT, message)
205
206        frame = self.ws.frame_read(sock)
207        data = frame['data'].decode('utf-8')
208
209        frame = self.ws.frame_read(sock)
210        data += frame['data'].decode('utf-8')
211
212        assert message == data, 'large'
213
214        sock.close()
215
216    def test_asgi_websockets_two_clients(self):
217        self.load('websockets/mirror')
218
219        message1 = 'blah1'
220        message2 = 'blah2'
221
222        _, sock1, _ = self.ws.upgrade()
223        _, sock2, _ = self.ws.upgrade()
224
225        self.ws.frame_write(sock1, self.ws.OP_TEXT, message1)
226        self.ws.frame_write(sock2, self.ws.OP_TEXT, message2)
227
228        frame1 = self.ws.frame_read(sock1)
229        frame2 = self.ws.frame_read(sock2)
230
231        assert message1 == frame1['data'].decode('utf-8'), 'client 1'
232        assert message2 == frame2['data'].decode('utf-8'), 'client 2'
233
234        sock1.close()
235        sock2.close()
236
237    @pytest.mark.skip('not yet')
238    def test_asgi_websockets_handshake_upgrade_absent(
239        self,
240    ):  # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1
241        self.load('websockets/mirror')
242
243        resp = self.get(
244            headers={
245                'Host': 'localhost',
246                'Connection': 'Upgrade',
247                'Sec-WebSocket-Key': self.ws.key(),
248                'Sec-WebSocket-Protocol': 'chat',
249                'Sec-WebSocket-Version': 13,
250            },
251        )
252
253        assert resp['status'] == 400, 'upgrade absent'
254
255    def test_asgi_websockets_handshake_case_insensitive(self):
256        self.load('websockets/mirror')
257
258        resp, sock, _ = self.ws.upgrade(
259            headers={
260                'Host': 'localhost',
261                'Upgrade': 'WEBSOCKET',
262                'Connection': 'UPGRADE',
263                'Sec-WebSocket-Key': self.ws.key(),
264                'Sec-WebSocket-Protocol': 'chat',
265                'Sec-WebSocket-Version': 13,
266            }
267        )
268        sock.close()
269
270        assert resp['status'] == 101, 'status'
271
272    @pytest.mark.skip('not yet')
273    def test_asgi_websockets_handshake_connection_absent(self):  # FAIL
274        self.load('websockets/mirror')
275
276        resp = self.get(
277            headers={
278                'Host': 'localhost',
279                'Upgrade': 'websocket',
280                'Sec-WebSocket-Key': self.ws.key(),
281                'Sec-WebSocket-Protocol': 'chat',
282                'Sec-WebSocket-Version': 13,
283            },
284        )
285
286        assert resp['status'] == 400, 'status'
287
288    def test_asgi_websockets_handshake_version_absent(self):
289        self.load('websockets/mirror')
290
291        resp = self.get(
292            headers={
293                'Host': 'localhost',
294                'Upgrade': 'websocket',
295                'Connection': 'Upgrade',
296                'Sec-WebSocket-Key': self.ws.key(),
297                'Sec-WebSocket-Protocol': 'chat',
298            },
299        )
300
301        assert resp['status'] == 426, 'status'
302
303    @pytest.mark.skip('not yet')
304    def test_asgi_websockets_handshake_key_invalid(self):
305        self.load('websockets/mirror')
306
307        resp = self.get(
308            headers={
309                'Host': 'localhost',
310                'Upgrade': 'websocket',
311                'Connection': 'Upgrade',
312                'Sec-WebSocket-Key': '!',
313                'Sec-WebSocket-Protocol': 'chat',
314                'Sec-WebSocket-Version': 13,
315            },
316        )
317
318        assert resp['status'] == 400, 'key length'
319
320        key = self.ws.key()
321        resp = self.get(
322            headers={
323                'Host': 'localhost',
324                'Upgrade': 'websocket',
325                'Connection': 'Upgrade',
326                'Sec-WebSocket-Key': [key, key],
327                'Sec-WebSocket-Protocol': 'chat',
328                'Sec-WebSocket-Version': 13,
329            },
330        )
331
332        assert (
333            resp['status'] == 400
334        ), 'key double'  # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
335
336    def test_asgi_websockets_handshake_method_invalid(self):
337        self.load('websockets/mirror')
338
339        resp = self.post(
340            headers={
341                'Host': 'localhost',
342                'Upgrade': 'websocket',
343                'Connection': 'Upgrade',
344                'Sec-WebSocket-Key': self.ws.key(),
345                'Sec-WebSocket-Protocol': 'chat',
346                'Sec-WebSocket-Version': 13,
347            },
348        )
349
350        assert resp['status'] == 400, 'status'
351
352    def test_asgi_websockets_handshake_http_10(self):
353        self.load('websockets/mirror')
354
355        resp = self.get(
356            headers={
357                'Host': 'localhost',
358                'Upgrade': 'websocket',
359                'Connection': 'Upgrade',
360                'Sec-WebSocket-Key': self.ws.key(),
361                'Sec-WebSocket-Protocol': 'chat',
362                'Sec-WebSocket-Version': 13,
363            },
364            http_10=True,
365        )
366
367        assert resp['status'] == 400, 'status'
368
369    def test_asgi_websockets_handshake_uri_invalid(self):
370        self.load('websockets/mirror')
371
372        resp = self.get(
373            headers={
374                'Host': 'localhost',
375                'Upgrade': 'websocket',
376                'Connection': 'Upgrade',
377                'Sec-WebSocket-Key': self.ws.key(),
378                'Sec-WebSocket-Protocol': 'chat',
379                'Sec-WebSocket-Version': 13,
380            },
381            url='!',
382        )
383
384        assert resp['status'] == 400, 'status'
385
386    def test_asgi_websockets_protocol_absent(self):
387        self.load('websockets/mirror')
388
389        key = self.ws.key()
390        resp, sock, _ = self.ws.upgrade(
391            headers={
392                'Host': 'localhost',
393                'Upgrade': 'websocket',
394                'Connection': 'Upgrade',
395                'Sec-WebSocket-Key': key,
396                'Sec-WebSocket-Version': 13,
397            }
398        )
399        sock.close()
400
401        assert resp['status'] == 101, 'status'
402        assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
403        assert resp['headers']['Connection'] == 'Upgrade', 'connection'
404        assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
405            key
406        ), 'key'
407
408    # autobahn-testsuite
409    #
410    # Some following tests fail because of Unit does not support UTF-8
411    # validation for websocket frames.  It should be implemented
412    # by application, if necessary.
413
414    def test_asgi_websockets_1_1_1__1_1_8(self):
415        self.load('websockets/mirror')
416
417        opcode = self.ws.OP_TEXT
418
419        _, sock, _ = self.ws.upgrade()
420
421        def check_length(length, chopsize=None):
422            payload = '*' * length
423
424            self.ws.frame_write(sock, opcode, payload, chopsize=chopsize)
425
426            frame = self.ws.frame_read(sock)
427            self.check_frame(frame, True, opcode, payload)
428
429        check_length(0)  # 1_1_1
430        check_length(125)  # 1_1_2
431        check_length(126)  # 1_1_3
432        check_length(127)  # 1_1_4
433        check_length(128)  # 1_1_5
434        check_length(65535)  # 1_1_6
435        check_length(65536)  # 1_1_7
436        check_length(65536, chopsize=997)  # 1_1_8
437
438        self.close_connection(sock)
439
440    def test_asgi_websockets_1_2_1__1_2_8(self):
441        self.load('websockets/mirror')
442
443        opcode = self.ws.OP_BINARY
444
445        _, sock, _ = self.ws.upgrade()
446
447        def check_length(length, chopsize=None):
448            payload = b'\xfe' * length
449
450            self.ws.frame_write(sock, opcode, payload, chopsize=chopsize)
451            frame = self.ws.frame_read(sock)
452
453            self.check_frame(frame, True, opcode, payload)
454
455        check_length(0)  # 1_2_1
456        check_length(125)  # 1_2_2
457        check_length(126)  # 1_2_3
458        check_length(127)  # 1_2_4
459        check_length(128)  # 1_2_5
460        check_length(65535)  # 1_2_6
461        check_length(65536)  # 1_2_7
462        check_length(65536, chopsize=997)  # 1_2_8
463
464        self.close_connection(sock)
465
466    def test_asgi_websockets_2_1__2_6(self):
467        self.load('websockets/mirror')
468
469        op_ping = self.ws.OP_PING
470        op_pong = self.ws.OP_PONG
471
472        _, sock, _ = self.ws.upgrade()
473
474        def check_ping(payload, chopsize=None, decode=True):
475            self.ws.frame_write(sock, op_ping, payload, chopsize=chopsize)
476            frame = self.ws.frame_read(sock)
477
478            self.check_frame(frame, True, op_pong, payload, decode=decode)
479
480        check_ping('')  # 2_1
481        check_ping('Hello, world!')  # 2_2
482        check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False)  # 2_3
483        check_ping(b'\xfe' * 125, decode=False)  # 2_4
484        check_ping(b'\xfe' * 125, chopsize=1, decode=False)  # 2_6
485
486        self.close_connection(sock)
487
488        # 2_5
489
490        _, sock, _ = self.ws.upgrade()
491
492        self.ws.frame_write(sock, self.ws.OP_PING, b'\xfe' * 126)
493        self.check_close(sock, 1002)
494
495    def test_asgi_websockets_2_7__2_9(self):
496        self.load('websockets/mirror')
497
498        # 2_7
499
500        _, sock, _ = self.ws.upgrade()
501
502        self.ws.frame_write(sock, self.ws.OP_PONG, '')
503        assert self.recvall(sock, read_timeout=0.1) == b'', '2_7'
504
505        # 2_8
506
507        self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
508        assert self.recvall(sock, read_timeout=0.1) == b'', '2_8'
509
510        # 2_9
511
512        payload = 'ping payload'
513
514        self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
515        self.ws.frame_write(sock, self.ws.OP_PING, payload)
516
517        frame = self.ws.frame_read(sock)
518        self.check_frame(frame, True, self.ws.OP_PONG, payload)
519
520        self.close_connection(sock)
521
522    def test_asgi_websockets_2_10__2_11(self):
523        self.load('websockets/mirror')
524
525        # 2_10
526
527        _, sock, _ = self.ws.upgrade()
528
529        for i in range(0, 10):
530            self.ws.frame_write(sock, self.ws.OP_PING, 'payload-%d' % i)
531
532        for i in range(0, 10):
533            frame = self.ws.frame_read(sock)
534            self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i)
535
536        # 2_11
537
538        for i in range(0, 10):
539            opcode = self.ws.OP_PING
540            self.ws.frame_write(sock, opcode, 'payload-%d' % i, chopsize=1)
541
542        for i in range(0, 10):
543            frame = self.ws.frame_read(sock)
544            self.check_frame(frame, True, self.ws.OP_PONG, 'payload-%d' % i)
545
546        self.close_connection(sock)
547
548    @pytest.mark.skip('not yet')
549    def test_asgi_websockets_3_1__3_7(self):
550        self.load('websockets/mirror')
551
552        payload = 'Hello, world!'
553
554        # 3_1
555
556        _, sock, _ = self.ws.upgrade()
557
558        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv1=True)
559        self.check_close(sock, 1002)
560
561        # 3_2
562
563        _, sock, _ = self.ws.upgrade()
564
565        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
566        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, rsv2=True)
567        self.ws.frame_write(sock, self.ws.OP_PING, '')
568
569        frame = self.ws.frame_read(sock)
570        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
571
572        self.check_close(sock, 1002, no_close=True)
573
574        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2'
575        sock.close()
576
577        # 3_3
578
579        _, sock, _ = self.ws.upgrade()
580
581        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
582
583        frame = self.ws.frame_read(sock)
584        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
585
586        self.ws.frame_write(
587            sock, self.ws.OP_TEXT, payload, rsv1=True, rsv2=True
588        )
589
590        self.check_close(sock, 1002, no_close=True)
591
592        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3'
593        sock.close()
594
595        # 3_4
596
597        _, sock, _ = self.ws.upgrade()
598
599        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
600        self.ws.frame_write(
601            sock, self.ws.OP_TEXT, payload, rsv3=True, chopsize=1
602        )
603        self.ws.frame_write(sock, self.ws.OP_PING, '')
604
605        frame = self.ws.frame_read(sock)
606        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
607
608        self.check_close(sock, 1002, no_close=True)
609
610        assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4'
611        sock.close()
612
613        # 3_5
614
615        _, sock, _ = self.ws.upgrade()
616
617        self.ws.frame_write(
618            sock,
619            self.ws.OP_BINARY,
620            b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff',
621            rsv1=True,
622            rsv3=True,
623        )
624
625        self.check_close(sock, 1002)
626
627        # 3_6
628
629        _, sock, _ = self.ws.upgrade()
630
631        self.ws.frame_write(
632            sock, self.ws.OP_PING, payload, rsv2=True, rsv3=True
633        )
634
635        self.check_close(sock, 1002)
636
637        # 3_7
638
639        _, sock, _ = self.ws.upgrade()
640
641        self.ws.frame_write(
642            sock, self.ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True
643        )
644
645        self.check_close(sock, 1002)
646
647    def test_asgi_websockets_4_1_1__4_2_5(self):
648        self.load('websockets/mirror')
649
650        payload = 'Hello, world!'
651
652        # 4_1_1
653
654        _, sock, _ = self.ws.upgrade()
655
656        self.ws.frame_write(sock, 0x03, '')
657        self.check_close(sock, 1002)
658
659        # 4_1_2
660
661        _, sock, _ = self.ws.upgrade()
662
663        self.ws.frame_write(sock, 0x04, 'reserved opcode payload')
664        self.check_close(sock, 1002)
665
666        # 4_1_3
667
668        _, sock, _ = self.ws.upgrade()
669
670        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
671
672        frame = self.ws.frame_read(sock)
673        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
674
675        self.ws.frame_write(sock, 0x05, '')
676        self.ws.frame_write(sock, self.ws.OP_PING, '')
677
678        self.check_close(sock, 1002)
679
680        # 4_1_4
681
682        _, sock, _ = self.ws.upgrade()
683
684        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
685
686        frame = self.ws.frame_read(sock)
687        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
688
689        self.ws.frame_write(sock, 0x06, payload)
690        self.ws.frame_write(sock, self.ws.OP_PING, '')
691
692        self.check_close(sock, 1002)
693
694        # 4_1_5
695
696        _, sock, _ = self.ws.upgrade()
697
698        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
699
700        frame = self.ws.frame_read(sock)
701        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
702
703        self.ws.frame_write(sock, 0x07, payload, chopsize=1)
704        self.ws.frame_write(sock, self.ws.OP_PING, '')
705
706        self.check_close(sock, 1002)
707
708        # 4_2_1
709
710        _, sock, _ = self.ws.upgrade()
711
712        self.ws.frame_write(sock, 0x0B, '')
713        self.check_close(sock, 1002)
714
715        # 4_2_2
716
717        _, sock, _ = self.ws.upgrade()
718
719        self.ws.frame_write(sock, 0x0C, 'reserved opcode payload')
720        self.check_close(sock, 1002)
721
722        # 4_2_3
723
724        _, sock, _ = self.ws.upgrade()
725
726        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
727
728        frame = self.ws.frame_read(sock)
729        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
730
731        self.ws.frame_write(sock, 0x0D, '')
732        self.ws.frame_write(sock, self.ws.OP_PING, '')
733
734        self.check_close(sock, 1002)
735
736        # 4_2_4
737
738        _, sock, _ = self.ws.upgrade()
739
740        self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
741
742        frame = self.ws.frame_read(sock)
743        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
744
745        self.ws.frame_write(sock, 0x0E, payload)
746        self.ws.frame_write(sock, self.ws.OP_PING, '')
747
748        self.check_close(sock, 1002)
749
750        # 4_2_5
751
752        _, sock, _ = self.ws.upgrade()
753
754        self.ws.frame_write(sock, self.ws.OP_TEXT, payload, chopsize=1)
755
756        frame = self.ws.frame_read(sock)
757        self.check_frame(frame, True, self.ws.OP_TEXT, payload)
758
759        self.ws.frame_write(sock, 0x0F, payload, chopsize=1)
760        self.ws.frame_write(sock, self.ws.OP_PING, '')
761
762        self.check_close(sock, 1002)
763
764    def test_asgi_websockets_5_1__5_20(self):
765        self.load('websockets/mirror')
766
767        # 5_1
768
769        _, sock, _ = self.ws.upgrade()
770
771        self.ws.frame_write(sock, self.ws.OP_PING, 'fragment1', fin=False)
772        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
773        self.check_close(sock, 1002)
774
775        # 5_2
776
777        _, sock, _ = self.ws.upgrade()
778
779        self.ws.frame_write(sock, self.ws.OP_PONG, 'fragment1', fin=False)
780        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
781        self.check_close(sock, 1002)
782
783        # 5_3
784
785        _, sock, _ = self.ws.upgrade()
786
787        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
788        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
789
790        frame = self.ws.frame_read(sock)
791        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
792
793        # 5_4
794
795        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
796        assert self.recvall(sock, read_timeout=0.1) == b'', '5_4'
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_5
803
804        self.ws.frame_write(
805            sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1
806        )
807        self.ws.frame_write(
808            sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1
809        )
810
811        frame = self.ws.frame_read(sock)
812        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
813
814        # 5_6
815
816        ping_payload = 'ping payload'
817
818        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
819        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
820        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
821
822        frame = self.ws.frame_read(sock)
823        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
824
825        frame = self.ws.frame_read(sock)
826        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
827
828        # 5_7
829
830        ping_payload = 'ping payload'
831
832        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
833        assert self.recvall(sock, read_timeout=0.1) == b'', '5_7'
834
835        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
836
837        frame = self.ws.frame_read(sock)
838        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
839
840        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
841
842        frame = self.ws.frame_read(sock)
843        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
844
845        # 5_8
846
847        ping_payload = 'ping payload'
848
849        self.ws.frame_write(
850            sock, self.ws.OP_TEXT, 'fragment1', fin=False, chopsize=1
851        )
852        self.ws.frame_write(sock, self.ws.OP_PING, ping_payload, chopsize=1)
853        self.ws.frame_write(
854            sock, self.ws.OP_CONT, 'fragment2', fin=True, chopsize=1
855        )
856
857        frame = self.ws.frame_read(sock)
858        self.check_frame(frame, True, self.ws.OP_PONG, ping_payload)
859
860        frame = self.ws.frame_read(sock)
861        self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
862
863        # 5_9
864
865        self.ws.frame_write(
866            sock, self.ws.OP_CONT, 'non-continuation payload', fin=True
867        )
868        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
869        self.check_close(sock, 1002)
870
871        # 5_10
872
873        _, sock, _ = self.ws.upgrade()
874
875        self.ws.frame_write(
876            sock, self.ws.OP_CONT, 'non-continuation payload', fin=True
877        )
878        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
879        self.check_close(sock, 1002)
880
881        # 5_11
882
883        _, sock, _ = self.ws.upgrade()
884
885        self.ws.frame_write(
886            sock,
887            self.ws.OP_CONT,
888            'non-continuation payload',
889            fin=True,
890            chopsize=1,
891        )
892        self.ws.frame_write(
893            sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1
894        )
895        self.check_close(sock, 1002)
896
897        # 5_12
898
899        _, sock, _ = self.ws.upgrade()
900
901        self.ws.frame_write(
902            sock, self.ws.OP_CONT, 'non-continuation payload', fin=False
903        )
904        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
905        self.check_close(sock, 1002)
906
907        # 5_13
908
909        _, sock, _ = self.ws.upgrade()
910
911        self.ws.frame_write(
912            sock, self.ws.OP_CONT, 'non-continuation payload', fin=False
913        )
914        self.ws.frame_write(sock, self.ws.OP_TEXT, 'Hello, world!', fin=True)
915        self.check_close(sock, 1002)
916
917        # 5_14
918
919        _, sock, _ = self.ws.upgrade()
920
921        self.ws.frame_write(
922            sock,
923            self.ws.OP_CONT,
924            'non-continuation payload',
925            fin=False,
926            chopsize=1,
927        )
928        self.ws.frame_write(
929            sock, self.ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1
930        )
931        self.check_close(sock, 1002)
932
933        # 5_15
934
935        _, sock, _ = self.ws.upgrade()
936
937        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
938        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
939        self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
940        self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True)
941
942        frame = self.ws.frame_read(sock)
943
944        if frame['opcode'] == self.ws.OP_TEXT:
945            self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
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