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