]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/websocket/read.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / read.cpp
1 //
2 // Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 // Test that header file is self-contained.
11 #include <boost/beast/websocket/stream.hpp>
12
13 #include "test.hpp"
14
15 #include <boost/asio/write.hpp>
16
17 #include <boost/beast/core/buffers_to_string.hpp>
18
19 namespace boost {
20 namespace beast {
21 namespace websocket {
22
23 class read_test : public websocket_test_suite
24 {
25 public:
26 template<class Wrap>
27 void
28 doReadTest(
29 Wrap const& w,
30 ws_type& ws,
31 close_code code)
32 {
33 try
34 {
35 multi_buffer b;
36 w.read(ws, b);
37 fail("", __FILE__, __LINE__);
38 }
39 catch(system_error const& se)
40 {
41 if(se.code() != error::closed)
42 throw;
43 BEAST_EXPECT(
44 ws.reason().code == code);
45 }
46 }
47
48 template<class Wrap>
49 void
50 doFailTest(
51 Wrap const& w,
52 ws_type& ws,
53 error_code ev)
54 {
55 try
56 {
57 multi_buffer b;
58 w.read(ws, b);
59 fail("", __FILE__, __LINE__);
60 }
61 catch(system_error const& se)
62 {
63 if(se.code() != ev)
64 throw;
65 }
66 }
67
68 template<class Wrap>
69 void
70 doTestRead(Wrap const& w)
71 {
72 using boost::asio::buffer;
73
74 permessage_deflate pmd;
75 pmd.client_enable = false;
76 pmd.server_enable = false;
77
78 // already closed
79 {
80 echo_server es{log};
81 stream<test::stream> ws{ioc_};
82 ws.next_layer().connect(es.stream());
83 ws.handshake("localhost", "/");
84 ws.close({});
85 try
86 {
87 multi_buffer b;
88 w.read(ws, b);
89 fail("", __FILE__, __LINE__);
90 }
91 catch(system_error const& se)
92 {
93 BEAST_EXPECTS(
94 se.code() == boost::asio::error::operation_aborted,
95 se.code().message());
96 }
97 }
98
99 // empty, fragmented message
100 doTest(pmd, [&](ws_type& ws)
101 {
102 ws.next_layer().append(
103 string_view(
104 "\x01\x00" "\x80\x00", 4));
105 multi_buffer b;
106 w.read(ws, b);
107 BEAST_EXPECT(b.size() == 0);
108 });
109
110 // two part message
111 // triggers "fill the read buffer first"
112 doTest(pmd, [&](ws_type& ws)
113 {
114 w.write_raw(ws, sbuf(
115 "\x01\x81\xff\xff\xff\xff"));
116 w.write_raw(ws, sbuf(
117 "\xd5"));
118 w.write_raw(ws, sbuf(
119 "\x80\x81\xff\xff\xff\xff\xd5"));
120 multi_buffer b;
121 w.read(ws, b);
122 BEAST_EXPECT(to_string(b.data()) == "**");
123 });
124
125 // ping
126 doTest(pmd, [&](ws_type& ws)
127 {
128 put(ws.next_layer().buffer(), cbuf(
129 0x89, 0x00));
130 bool invoked = false;
131 auto cb = [&](frame_type kind, string_view)
132 {
133 BEAST_EXPECT(! invoked);
134 BEAST_EXPECT(kind == frame_type::ping);
135 invoked = true;
136 };
137 ws.control_callback(cb);
138 w.write(ws, sbuf("Hello"));
139 multi_buffer b;
140 w.read(ws, b);
141 BEAST_EXPECT(invoked);
142 BEAST_EXPECT(ws.got_text());
143 BEAST_EXPECT(to_string(b.data()) == "Hello");
144 });
145
146 // ping
147 doTest(pmd, [&](ws_type& ws)
148 {
149 put(ws.next_layer().buffer(), cbuf(
150 0x88, 0x00));
151 bool invoked = false;
152 auto cb = [&](frame_type kind, string_view)
153 {
154 BEAST_EXPECT(! invoked);
155 BEAST_EXPECT(kind == frame_type::close);
156 invoked = true;
157 };
158 ws.control_callback(cb);
159 w.write(ws, sbuf("Hello"));
160 doReadTest(w, ws, close_code::none);
161 });
162
163 // ping then message
164 doTest(pmd, [&](ws_type& ws)
165 {
166 bool once = false;
167 auto cb =
168 [&](frame_type kind, string_view s)
169 {
170 BEAST_EXPECT(kind == frame_type::pong);
171 BEAST_EXPECT(! once);
172 once = true;
173 BEAST_EXPECT(s == "");
174 };
175 ws.control_callback(cb);
176 w.ping(ws, "");
177 ws.binary(true);
178 w.write(ws, sbuf("Hello"));
179 multi_buffer b;
180 w.read(ws, b);
181 BEAST_EXPECT(once);
182 BEAST_EXPECT(ws.got_binary());
183 BEAST_EXPECT(to_string(b.data()) == "Hello");
184 });
185
186 // ping then fragmented message
187 doTest(pmd, [&](ws_type& ws)
188 {
189 bool once = false;
190 auto cb =
191 [&](frame_type kind, string_view s)
192 {
193 BEAST_EXPECT(kind == frame_type::pong);
194 BEAST_EXPECT(! once);
195 once = true;
196 BEAST_EXPECT(s == "payload");
197 };
198 ws.control_callback(cb);
199 ws.ping("payload");
200 w.write_some(ws, false, sbuf("Hello, "));
201 w.write_some(ws, false, sbuf(""));
202 w.write_some(ws, true, sbuf("World!"));
203 multi_buffer b;
204 w.read(ws, b);
205 BEAST_EXPECT(once);
206 BEAST_EXPECT(to_string(b.data()) == "Hello, World!");
207 });
208
209 // masked message, big
210 doStreamLoop([&](test::stream& ts)
211 {
212 echo_server es{log, kind::async_client};
213 ws_type ws{ts};
214 ws.next_layer().connect(es.stream());
215 ws.set_option(pmd);
216 es.async_handshake();
217 try
218 {
219 w.accept(ws);
220 std::string const s(2000, '*');
221 ws.auto_fragment(false);
222 ws.binary(false);
223 w.write(ws, buffer(s));
224 multi_buffer b;
225 w.read(ws, b);
226 BEAST_EXPECT(ws.got_text());
227 BEAST_EXPECT(to_string(b.data()) == s);
228 ws.next_layer().close();
229 }
230 catch(...)
231 {
232 ts.close();
233 throw;
234 }
235 });
236
237 // close
238 doFailLoop([&](test::fail_counter& fc)
239 {
240 echo_server es{log, kind::async};
241 boost::asio::io_context ioc;
242 stream<test::stream> ws{ioc, fc};
243 ws.next_layer().connect(es.stream());
244 ws.handshake("localhost", "/");
245 // Cause close to be received
246 es.async_close();
247 std::size_t count = 0;
248 multi_buffer b;
249 ws.async_read(b,
250 [&](error_code ec, std::size_t)
251 {
252 ++count;
253 if(ec != error::closed)
254 BOOST_THROW_EXCEPTION(
255 system_error{ec});
256 });
257 ioc.run();
258 BEAST_EXPECT(count == 1);
259 });
260
261 // already closed
262 doTest(pmd, [&](ws_type& ws)
263 {
264 w.close(ws, {});
265 multi_buffer b;
266 doFailTest(w, ws,
267 boost::asio::error::operation_aborted);
268 });
269
270 // buffer overflow
271 doTest(pmd, [&](ws_type& ws)
272 {
273 std::string const s = "Hello, world!";
274 ws.auto_fragment(false);
275 ws.binary(false);
276 w.write(ws, buffer(s));
277 try
278 {
279 multi_buffer b(3);
280 w.read(ws, b);
281 fail("", __FILE__, __LINE__);
282 }
283 catch(system_error const& se)
284 {
285 if(se.code() != error::buffer_overflow)
286 throw;
287 }
288 });
289
290 // bad utf8, big
291 doTest(pmd, [&](ws_type& ws)
292 {
293 auto const s = std::string(2000, '*') +
294 random_string();
295 ws.text(true);
296 w.write(ws, buffer(s));
297 doReadTest(w, ws, close_code::bad_payload);
298 });
299
300 // invalid fixed frame header
301 doTest(pmd, [&](ws_type& ws)
302 {
303 w.write_raw(ws, cbuf(
304 0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
305 doReadTest(w, ws, close_code::protocol_error);
306 });
307
308 // bad close
309 doTest(pmd, [&](ws_type& ws)
310 {
311 put(ws.next_layer().buffer(), cbuf(
312 0x88, 0x02, 0x03, 0xed));
313 doFailTest(w, ws, error::failed);
314 });
315
316 // message size above 2^64
317 doTest(pmd, [&](ws_type& ws)
318 {
319 w.write_some(ws, false, sbuf("*"));
320 w.write_raw(ws, cbuf(
321 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
322 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
323 doReadTest(w, ws, close_code::too_big);
324 });
325
326 // message size exceeds max
327 doTest(pmd, [&](ws_type& ws)
328 {
329 ws.read_message_max(1);
330 w.write(ws, sbuf("**"));
331 doFailTest(w, ws, error::failed);
332 });
333
334 // bad utf8
335 doTest(pmd, [&](ws_type& ws)
336 {
337 put(ws.next_layer().buffer(), cbuf(
338 0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
339 doFailTest(w, ws, error::failed);
340 });
341
342 // incomplete utf8
343 doTest(pmd, [&](ws_type& ws)
344 {
345 std::string const s =
346 "Hello, world!" "\xc0";
347 w.write(ws, buffer(s));
348 doReadTest(w, ws, close_code::bad_payload);
349 });
350
351 // incomplete utf8, big
352 doTest(pmd, [&](ws_type& ws)
353 {
354 std::string const s =
355 "\x81\x7e\x0f\xa1" +
356 std::string(4000, '*') + "\xc0";
357 ws.next_layer().append(s);
358 multi_buffer b;
359 try
360 {
361 do
362 {
363 b.commit(w.read_some(ws, b.prepare(4000)));
364 }
365 while(! ws.is_message_done());
366 }
367 catch(system_error const& se)
368 {
369 if(se.code() != error::failed)
370 throw;
371 }
372 });
373
374 // close frames
375 {
376 auto const check =
377 [&](error_code ev, string_view s)
378 {
379 echo_server es{log};
380 stream<test::stream> ws{ioc_};
381 ws.next_layer().connect(es.stream());
382 w.handshake(ws, "localhost", "/");
383 ws.next_layer().append(s);
384 static_buffer<1> b;
385 error_code ec;
386 try
387 {
388 w.read(ws, b);
389 fail("", __FILE__, __LINE__);
390 }
391 catch(system_error const& se)
392 {
393 BEAST_EXPECTS(se.code() == ev,
394 se.code().message());
395 }
396 ws.next_layer().close();
397 };
398
399 // payload length 1
400 check(error::failed,
401 "\x88\x01\x01");
402
403 // invalid close code 1005
404 check(error::failed,
405 "\x88\x02\x03\xed");
406
407 // invalid utf8
408 check(error::failed,
409 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
410
411 // good utf8
412 check(error::closed,
413 "\x88\x06\xfc\x15utf8");
414 }
415
416 //
417 // permessage-deflate
418 //
419
420 pmd.client_enable = true;
421 pmd.server_enable = true;
422 pmd.client_max_window_bits = 9;
423 pmd.server_max_window_bits = 9;
424 pmd.compLevel = 1;
425
426 // message size limit
427 doTest(pmd, [&](ws_type& ws)
428 {
429 std::string const s = std::string(128, '*');
430 w.write(ws, buffer(s));
431 ws.read_message_max(32);
432 doFailTest(w, ws, error::failed);
433 });
434
435 // invalid inflate block
436 doTest(pmd, [&](ws_type& ws)
437 {
438 auto const& s = random_string();
439 ws.binary(true);
440 ws.next_layer().append(
441 "\xc2\x40" + s.substr(0, 64));
442 flat_buffer b;
443 try
444 {
445 w.read(ws, b);
446 }
447 catch(system_error const& se)
448 {
449 if(se.code() == test::error::fail_error)
450 throw;
451 BEAST_EXPECTS(se.code().category() ==
452 zlib::detail::get_error_category(),
453 se.code().message());
454 }
455 catch(...)
456 {
457 throw;
458 }
459 });
460
461 // no_context_takeover
462 pmd.server_no_context_takeover = true;
463 doTest(pmd, [&](ws_type& ws)
464 {
465 auto const& s = random_string();
466 ws.binary(true);
467 w.write(ws, buffer(s));
468 multi_buffer b;
469 w.read(ws, b);
470 BEAST_EXPECT(to_string(b.data()) == s);
471 });
472 pmd.client_no_context_takeover = false;
473 }
474
475 template<class Wrap>
476 void
477 doTestRead(
478 permessage_deflate const& pmd,
479 Wrap const& w)
480 {
481 using boost::asio::buffer;
482
483 // message
484 doTest(pmd, [&](ws_type& ws)
485 {
486 std::string const s = "Hello, world!";
487 ws.auto_fragment(false);
488 ws.binary(false);
489 w.write(ws, buffer(s));
490 multi_buffer b;
491 w.read(ws, b);
492 BEAST_EXPECT(ws.got_text());
493 BEAST_EXPECT(to_string(b.data()) == s);
494 });
495
496 // masked message
497 doStreamLoop([&](test::stream& ts)
498 {
499 echo_server es{log, kind::async_client};
500 ws_type ws{ts};
501 ws.next_layer().connect(es.stream());
502 ws.set_option(pmd);
503 es.async_handshake();
504 try
505 {
506 w.accept(ws);
507 std::string const s = "Hello, world!";
508 ws.auto_fragment(false);
509 ws.binary(false);
510 w.write(ws, buffer(s));
511 multi_buffer b;
512 w.read(ws, b);
513 BEAST_EXPECT(ws.got_text());
514 BEAST_EXPECT(to_string(b.data()) == s);
515 ws.next_layer().close();
516 }
517 catch(...)
518 {
519 ts.close();
520 throw;
521 }
522 });
523
524 // empty message
525 doTest(pmd, [&](ws_type& ws)
526 {
527 std::string const s = "";
528 ws.text(true);
529 w.write(ws, buffer(s));
530 multi_buffer b;
531 w.read(ws, b);
532 BEAST_EXPECT(ws.got_text());
533 BEAST_EXPECT(to_string(b.data()) == s);
534 });
535
536 // partial message
537 doTest(pmd, [&](ws_type& ws)
538 {
539 std::string const s = "Hello";
540 w.write(ws, buffer(s));
541 char buf[3];
542 auto const bytes_written =
543 w.read_some(ws, buffer(buf, sizeof(buf)));
544 BEAST_EXPECT(bytes_written > 0);
545 BEAST_EXPECT(
546 string_view(buf, 3).substr(0, bytes_written) ==
547 s.substr(0, bytes_written));
548 });
549
550 // partial message, dynamic buffer
551 doTest(pmd, [&](ws_type& ws)
552 {
553 std::string const s = "Hello, world!";
554 w.write(ws, buffer(s));
555 multi_buffer b;
556 auto bytes_written =
557 w.read_some(ws, 3, b);
558 BEAST_EXPECT(bytes_written > 0);
559 BEAST_EXPECT(to_string(b.data()) ==
560 s.substr(0, b.size()));
561 w.read_some(ws, 256, b);
562 BEAST_EXPECT(to_string(b.data()) == s);
563 });
564
565 // big message
566 doTest(pmd, [&](ws_type& ws)
567 {
568 auto const& s = random_string();
569 ws.binary(true);
570 w.write(ws, buffer(s));
571 multi_buffer b;
572 w.read(ws, b);
573 BEAST_EXPECT(to_string(b.data()) == s);
574 });
575
576 // message, bad utf8
577 doTest(pmd, [&](ws_type& ws)
578 {
579 std::string const s = "\x03\xea\xf0\x28\x8c\xbc";
580 ws.auto_fragment(false);
581 ws.text(true);
582 w.write(ws, buffer(s));
583 doReadTest(w, ws, close_code::bad_payload);
584 });
585 }
586
587 void
588 testRead()
589 {
590 using boost::asio::buffer;
591
592 doTestRead(SyncClient{});
593 yield_to([&](yield_context yield)
594 {
595 doTestRead(AsyncClient{yield});
596 });
597
598 permessage_deflate pmd;
599 pmd.client_enable = false;
600 pmd.server_enable = false;
601 doTestRead(pmd, SyncClient{});
602 yield_to([&](yield_context yield)
603 {
604 doTestRead(pmd, AsyncClient{yield});
605 });
606
607 pmd.client_enable = true;
608 pmd.server_enable = true;
609 pmd.client_max_window_bits = 9;
610 pmd.server_max_window_bits = 9;
611 pmd.compLevel = 1;
612 doTestRead(pmd, SyncClient{});
613 yield_to([&](yield_context yield)
614 {
615 doTestRead(pmd, AsyncClient{yield});
616 });
617
618 // Read close frames
619 {
620 auto const check =
621 [&](error_code ev, string_view s)
622 {
623 echo_server es{log};
624 stream<test::stream> ws{ioc_};
625 ws.next_layer().connect(es.stream());
626 ws.handshake("localhost", "/");
627 ws.next_layer().append(s);
628 static_buffer<1> b;
629 error_code ec;
630 ws.read(b, ec);
631 BEAST_EXPECTS(ec == ev, ec.message());
632 ws.next_layer().close();
633 };
634
635 // payload length 1
636 check(error::failed,
637 "\x88\x01\x01");
638
639 // invalid close code 1005
640 check(error::failed,
641 "\x88\x02\x03\xed");
642
643 // invalid utf8
644 check(error::failed,
645 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
646
647 // good utf8
648 check(error::closed,
649 "\x88\x06\xfc\x15utf8");
650 }
651 }
652
653 void
654 testSuspend()
655 {
656 using boost::asio::buffer;
657 #if 1
658 // suspend on read block
659 doFailLoop([&](test::fail_counter& fc)
660 {
661 echo_server es{log};
662 boost::asio::io_context ioc;
663 stream<test::stream> ws{ioc, fc};
664 ws.next_layer().connect(es.stream());
665 ws.handshake("localhost", "/");
666 std::size_t count = 0;
667 ws.async_close({},
668 [&](error_code ec)
669 {
670 if(ec)
671 BOOST_THROW_EXCEPTION(
672 system_error{ec});
673 BEAST_EXPECT(++count == 1);
674 });
675 while(! ws.rd_block_)
676 ioc.run_one();
677 multi_buffer b;
678 ws.async_read(b,
679 [&](error_code ec, std::size_t)
680 {
681 if(ec != boost::asio::error::operation_aborted)
682 BOOST_THROW_EXCEPTION(
683 system_error{ec});
684 BEAST_EXPECT(++count == 2);
685 });
686 ioc.run();
687 BEAST_EXPECT(count == 2);
688 });
689 #endif
690
691 // suspend on release read block
692 doFailLoop([&](test::fail_counter& fc)
693 {
694 //log << "fc.count()==" << fc.count() << std::endl;
695 echo_server es{log};
696 boost::asio::io_context ioc;
697 stream<test::stream> ws{ioc, fc};
698 ws.next_layer().connect(es.stream());
699 ws.handshake("localhost", "/");
700 std::size_t count = 0;
701 multi_buffer b;
702 ws.async_read(b,
703 [&](error_code ec, std::size_t)
704 {
705 if(ec != boost::asio::error::operation_aborted)
706 BOOST_THROW_EXCEPTION(
707 system_error{ec});
708 BEAST_EXPECT(++count == 2);
709 });
710 BOOST_ASSERT(ws.rd_block_);
711 ws.async_close({},
712 [&](error_code ec)
713 {
714 if(ec)
715 BOOST_THROW_EXCEPTION(
716 system_error{ec});
717 BEAST_EXPECT(++count == 1);
718 });
719 ioc.run();
720 BEAST_EXPECT(count == 2);
721 });
722
723 #if 1
724 // suspend on write pong
725 doFailLoop([&](test::fail_counter& fc)
726 {
727 echo_server es{log};
728 boost::asio::io_context ioc;
729 stream<test::stream> ws{ioc, fc};
730 ws.next_layer().connect(es.stream());
731 ws.handshake("localhost", "/");
732 // insert a ping
733 ws.next_layer().append(string_view(
734 "\x89\x00", 2));
735 std::size_t count = 0;
736 std::string const s = "Hello, world";
737 multi_buffer b;
738 ws.async_read(b,
739 [&](error_code ec, std::size_t)
740 {
741 if(ec)
742 BOOST_THROW_EXCEPTION(
743 system_error{ec});
744 BEAST_EXPECT(to_string(b.data()) == s);
745 ++count;
746 });
747 BEAST_EXPECT(ws.rd_block_);
748 ws.async_write(buffer(s),
749 [&](error_code ec, std::size_t n)
750 {
751 if(ec)
752 BOOST_THROW_EXCEPTION(
753 system_error{ec});
754 BEAST_EXPECT(n == s.size());
755 ++count;
756 });
757 BEAST_EXPECT(ws.wr_block_);
758 ioc.run();
759 BEAST_EXPECT(count == 2);
760 });
761
762 // Ignore ping when closing
763 doFailLoop([&](test::fail_counter& fc)
764 {
765 echo_server es{log};
766 boost::asio::io_context ioc;
767 stream<test::stream> ws{ioc, fc};
768 ws.next_layer().connect(es.stream());
769 ws.handshake("localhost", "/");
770 std::size_t count = 0;
771 // insert fragmented message with
772 // a ping in between the frames.
773 ws.next_layer().append(string_view(
774 "\x01\x01*"
775 "\x89\x00"
776 "\x80\x01*", 8));
777 multi_buffer b;
778 ws.async_read(b,
779 [&](error_code ec, std::size_t)
780 {
781 if(ec)
782 BOOST_THROW_EXCEPTION(
783 system_error{ec});
784 BEAST_EXPECT(to_string(b.data()) == "**");
785 BEAST_EXPECT(++count == 1);
786 b.consume(b.size());
787 ws.async_read(b,
788 [&](error_code ec, std::size_t)
789 {
790 if(ec != boost::asio::error::operation_aborted)
791 BOOST_THROW_EXCEPTION(
792 system_error{ec});
793 BEAST_EXPECT(++count == 3);
794 });
795 });
796 BEAST_EXPECT(ws.rd_block_);
797 ws.async_close({},
798 [&](error_code ec)
799 {
800 if(ec)
801 BOOST_THROW_EXCEPTION(
802 system_error{ec});
803 BEAST_EXPECT(++count == 2);
804 });
805 BEAST_EXPECT(ws.wr_block_);
806 ioc.run();
807 BEAST_EXPECT(count == 3);
808 });
809
810 // See if we are already closing
811 doFailLoop([&](test::fail_counter& fc)
812 {
813 echo_server es{log};
814 boost::asio::io_context ioc;
815 stream<test::stream> ws{ioc, fc};
816 ws.next_layer().connect(es.stream());
817 ws.handshake("localhost", "/");
818 std::size_t count = 0;
819 // insert fragmented message with
820 // a close in between the frames.
821 ws.next_layer().append(string_view(
822 "\x01\x01*"
823 "\x88\x00"
824 "\x80\x01*", 8));
825 multi_buffer b;
826 ws.async_read(b,
827 [&](error_code ec, std::size_t)
828 {
829 if(ec != boost::asio::error::operation_aborted)
830 BOOST_THROW_EXCEPTION(
831 system_error{ec});
832 BEAST_EXPECT(++count == 2);
833 });
834 BEAST_EXPECT(ws.rd_block_);
835 ws.async_close({},
836 [&](error_code ec)
837 {
838 if(ec)
839 BOOST_THROW_EXCEPTION(
840 system_error{ec});
841 BEAST_EXPECT(++count == 1);
842 });
843 BEAST_EXPECT(ws.wr_block_);
844 ioc.run();
845 BEAST_EXPECT(count == 2);
846 });
847 #endif
848 }
849
850 void
851 testParseFrame()
852 {
853 auto const bad =
854 [&](string_view s)
855 {
856 echo_server es{log};
857 boost::asio::io_context ioc;
858 stream<test::stream> ws{ioc};
859 ws.next_layer().connect(es.stream());
860 ws.handshake("localhost", "/");
861 ws.next_layer().append(s);
862 error_code ec;
863 multi_buffer b;
864 ws.read(b, ec);
865 BEAST_EXPECT(ec);
866 };
867
868 // chopped frame header
869 {
870 echo_server es{log};
871 boost::asio::io_context ioc;
872 stream<test::stream> ws{ioc};
873 ws.next_layer().connect(es.stream());
874 ws.handshake("localhost", "/");
875 ws.next_layer().append(
876 "\x81\x7e\x01");
877 std::size_t count = 0;
878 std::string const s(257, '*');
879 error_code ec;
880 multi_buffer b;
881 ws.async_read(b,
882 [&](error_code ec, std::size_t)
883 {
884 ++count;
885 BEAST_EXPECTS(! ec, ec.message());
886 BEAST_EXPECT(to_string(b.data()) == s);
887 });
888 ioc.run_one();
889 es.stream().write_some(
890 boost::asio::buffer("\x01" + s));
891 ioc.run();
892 BEAST_EXPECT(count == 1);
893 }
894
895 // new data frame when continuation expected
896 bad("\x01\x01*" "\x81\x01*");
897
898 // reserved bits not cleared
899 bad("\xb1\x01*");
900 bad("\xc1\x01*");
901 bad("\xd1\x01*");
902
903 // continuation without an active message
904 bad("\x80\x01*");
905
906 // reserved bits not cleared (cont)
907 bad("\x01\x01*" "\xb0\x01*");
908 bad("\x01\x01*" "\xc0\x01*");
909 bad("\x01\x01*" "\xd0\x01*");
910
911 // reserved opcode
912 bad("\x83\x01*");
913
914 // fragmented control message
915 bad("\x09\x01*");
916
917 // invalid length for control message
918 bad("\x89\x7e\x01\x01");
919
920 // reserved bits not cleared (control)
921 bad("\xb9\x01*");
922 bad("\xc9\x01*");
923 bad("\xd9\x01*");
924
925 // unmasked frame from client
926 {
927 echo_server es{log, kind::async_client};
928 boost::asio::io_context ioc;
929 stream<test::stream> ws{ioc};
930 ws.next_layer().connect(es.stream());
931 es.async_handshake();
932 ws.accept();
933 ws.next_layer().append(
934 "\x81\x01*");
935 error_code ec;
936 multi_buffer b;
937 ws.read(b, ec);
938 BEAST_EXPECT(ec);
939 }
940
941 // masked frame from server
942 bad("\x81\x80\xff\xff\xff\xff");
943
944 // chopped control frame payload
945 {
946 echo_server es{log};
947 boost::asio::io_context ioc;
948 stream<test::stream> ws{ioc};
949 ws.next_layer().connect(es.stream());
950 ws.handshake("localhost", "/");
951 ws.next_layer().append(
952 "\x89\x02*");
953 std::size_t count = 0;
954 error_code ec;
955 multi_buffer b;
956 ws.async_read(b,
957 [&](error_code ec, std::size_t)
958 {
959 ++count;
960 BEAST_EXPECTS(! ec, ec.message());
961 BEAST_EXPECT(to_string(b.data()) == "**");
962 });
963 ioc.run_one();
964 es.stream().write_some(
965 boost::asio::buffer(
966 "*" "\x81\x02**"));
967 ioc.run();
968 BEAST_EXPECT(count == 1);
969 }
970
971 // length not canonical
972 bad(string_view("\x81\x7e\x00\x7d", 4));
973 bad(string_view("\x81\x7f\x00\x00\x00\x00\x00\x00\xff\xff", 10));
974 }
975
976 void
977 testContHook()
978 {
979 {
980 struct handler
981 {
982 void operator()(error_code, std::size_t) {}
983 };
984
985 char buf[32];
986 stream<test::stream> ws{ioc_};
987 stream<test::stream>::read_some_op<
988 boost::asio::mutable_buffer,
989 handler> op{handler{}, ws,
990 boost::asio::mutable_buffer{
991 buf, sizeof(buf)}};
992 using boost::asio::asio_handler_is_continuation;
993 asio_handler_is_continuation(&op);
994 pass();
995 }
996 {
997 struct handler
998 {
999 void operator()(error_code, std::size_t) {}
1000 };
1001
1002 multi_buffer b;
1003 stream<test::stream> ws{ioc_};
1004 stream<test::stream>::read_op<
1005 multi_buffer, handler> op{
1006 handler{}, ws, b, 32, true};
1007 using boost::asio::asio_handler_is_continuation;
1008 asio_handler_is_continuation(&op);
1009 pass();
1010 }
1011 }
1012
1013 void
1014 testIssue802()
1015 {
1016 for(std::size_t i = 0; i < 100; ++i)
1017 {
1018 echo_server es{log, kind::async};
1019 boost::asio::io_context ioc;
1020 stream<test::stream> ws{ioc};
1021 ws.next_layer().connect(es.stream());
1022 ws.handshake("localhost", "/");
1023 // too-big message frame indicates payload of 2^64-1
1024 boost::asio::write(ws.next_layer(), sbuf(
1025 "\x81\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"));
1026 multi_buffer b;
1027 error_code ec;
1028 ws.read(b, ec);
1029 BEAST_EXPECT(ec == error::closed);
1030 BEAST_EXPECT(ws.reason().code == 1009);
1031 }
1032 }
1033
1034 void
1035 testIssue807()
1036 {
1037 echo_server es{log};
1038 boost::asio::io_context ioc;
1039 stream<test::stream> ws{ioc};
1040 ws.next_layer().connect(es.stream());
1041 ws.handshake("localhost", "/");
1042 ws.write(sbuf("Hello, world!"));
1043 char buf[4];
1044 boost::asio::mutable_buffer b{buf, 0};
1045 auto const n = ws.read_some(b);
1046 BEAST_EXPECT(n == 0);
1047 }
1048
1049 /* Bishop Fox Hybrid Assessment issue 1
1050
1051 Happens with permessage-deflate enabled and a
1052 compressed frame with the FIN bit set ends with an
1053 invalid prefix.
1054 */
1055 void
1056 testIssueBF1()
1057 {
1058 permessage_deflate pmd;
1059 pmd.client_enable = true;
1060 pmd.server_enable = true;
1061
1062 // read
1063 #if 0
1064 {
1065 echo_server es{log};
1066 boost::asio::io_context ioc;
1067 stream<test::stream> ws{ioc};
1068 ws.set_option(pmd);
1069 ws.next_layer().connect(es.stream());
1070 ws.handshake("localhost", "/");
1071 // invalid 1-byte deflate block in frame
1072 boost::asio::write(ws.next_layer(), sbuf(
1073 "\xc1\x81\x3a\xa1\x74\x3b\x49"));
1074 }
1075 #endif
1076 {
1077 boost::asio::io_context ioc;
1078 stream<test::stream> wsc{ioc};
1079 stream<test::stream> wss{ioc};
1080 wsc.set_option(pmd);
1081 wss.set_option(pmd);
1082 wsc.next_layer().connect(wss.next_layer());
1083 wsc.async_handshake(
1084 "localhost", "/", [](error_code){});
1085 wss.async_accept([](error_code){});
1086 ioc.run();
1087 ioc.restart();
1088 BEAST_EXPECT(wsc.is_open());
1089 BEAST_EXPECT(wss.is_open());
1090 // invalid 1-byte deflate block in frame
1091 boost::asio::write(wsc.next_layer(), sbuf(
1092 "\xc1\x81\x3a\xa1\x74\x3b\x49"));
1093 error_code ec;
1094 multi_buffer b;
1095 wss.read(b, ec);
1096 BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
1097 }
1098
1099 // async read
1100 #if 0
1101 {
1102 echo_server es{log, kind::async};
1103 boost::asio::io_context ioc;
1104 stream<test::stream> ws{ioc};
1105 ws.set_option(pmd);
1106 ws.next_layer().connect(es.stream());
1107 ws.handshake("localhost", "/");
1108 // invalid 1-byte deflate block in frame
1109 boost::asio::write(ws.next_layer(), sbuf(
1110 "\xc1\x81\x3a\xa1\x74\x3b\x49"));
1111 }
1112 #endif
1113 {
1114 boost::asio::io_context ioc;
1115 stream<test::stream> wsc{ioc};
1116 stream<test::stream> wss{ioc};
1117 wsc.set_option(pmd);
1118 wss.set_option(pmd);
1119 wsc.next_layer().connect(wss.next_layer());
1120 wsc.async_handshake(
1121 "localhost", "/", [](error_code){});
1122 wss.async_accept([](error_code){});
1123 ioc.run();
1124 ioc.restart();
1125 BEAST_EXPECT(wsc.is_open());
1126 BEAST_EXPECT(wss.is_open());
1127 // invalid 1-byte deflate block in frame
1128 boost::asio::write(wsc.next_layer(), sbuf(
1129 "\xc1\x81\x3a\xa1\x74\x3b\x49"));
1130 error_code ec;
1131 flat_buffer b;
1132 wss.async_read(b,
1133 [&ec](error_code ec_, std::size_t){ ec = ec_; });
1134 ioc.run();
1135 BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
1136 }
1137 }
1138
1139 /* Bishop Fox Hybrid Assessment issue 2
1140
1141 Happens with permessage-deflate enabled,
1142 and a deflate block with the BFINAL bit set
1143 is encountered in a compressed payload.
1144 */
1145 void
1146 testIssueBF2()
1147 {
1148 permessage_deflate pmd;
1149 pmd.client_enable = true;
1150 pmd.server_enable = true;
1151
1152 // read
1153 {
1154 boost::asio::io_context ioc;
1155 stream<test::stream> wsc{ioc};
1156 stream<test::stream> wss{ioc};
1157 wsc.set_option(pmd);
1158 wss.set_option(pmd);
1159 wsc.next_layer().connect(wss.next_layer());
1160 wsc.async_handshake(
1161 "localhost", "/", [](error_code){});
1162 wss.async_accept([](error_code){});
1163 ioc.run();
1164 ioc.restart();
1165 BEAST_EXPECT(wsc.is_open());
1166 BEAST_EXPECT(wss.is_open());
1167 // contains a deflate block with BFINAL set
1168 boost::asio::write(wsc.next_layer(), sbuf(
1169 "\xc1\xf8\xd1\xe4\xcc\x3e\xda\xe4\xcc\x3e"
1170 "\x2b\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\x1e"
1171 "\x36\x3e\x35\xae\x4f\x54\x18\xae\x4f\x7b"
1172 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1173 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
1174 "\xd1\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\xe4"
1175 "\x28\x74\x52\x8e\x05\x74\x52\xa1\xcc\x3e"
1176 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1177 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
1178 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1179 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\x36\x3e"
1180 "\xd1\xec\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1181 "\xcc\x3e\xd1\xe4\xcc\x3e"));
1182 error_code ec;
1183 flat_buffer b;
1184 wss.read(b, ec);
1185 BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
1186 }
1187
1188 // async read
1189 {
1190 boost::asio::io_context ioc;
1191 stream<test::stream> wsc{ioc};
1192 stream<test::stream> wss{ioc};
1193 wsc.set_option(pmd);
1194 wss.set_option(pmd);
1195 wsc.next_layer().connect(wss.next_layer());
1196 wsc.async_handshake(
1197 "localhost", "/", [](error_code){});
1198 wss.async_accept([](error_code){});
1199 ioc.run();
1200 ioc.restart();
1201 BEAST_EXPECT(wsc.is_open());
1202 BEAST_EXPECT(wss.is_open());
1203 // contains a deflate block with BFINAL set
1204 boost::asio::write(wsc.next_layer(), sbuf(
1205 "\xc1\xf8\xd1\xe4\xcc\x3e\xda\xe4\xcc\x3e"
1206 "\x2b\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\x1e"
1207 "\x36\x3e\x35\xae\x4f\x54\x18\xae\x4f\x7b"
1208 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1209 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
1210 "\xd1\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\xe4"
1211 "\x28\x74\x52\x8e\x05\x74\x52\xa1\xcc\x3e"
1212 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1213 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
1214 "\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1215 "\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\x36\x3e"
1216 "\xd1\xec\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
1217 "\xcc\x3e\xd1\xe4\xcc\x3e"));
1218 error_code ec;
1219 flat_buffer b;
1220 wss.async_read(b,
1221 [&ec](error_code ec_, std::size_t){ ec = ec_; });
1222 ioc.run();
1223 BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
1224 }
1225 }
1226
1227 void
1228 run() override
1229 {
1230 testRead();
1231 testSuspend();
1232 testParseFrame();
1233 testContHook();
1234 testIssue802();
1235 testIssue807();
1236 testIssueBF1();
1237 testIssueBF2();
1238 }
1239 };
1240
1241 BEAST_DEFINE_TESTSUITE(beast,websocket,read);
1242
1243 } // websocket
1244 } // beast
1245 } // boost