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