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