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