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