]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/websocket/read2.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / read2.cpp
1
2 // Copyright (c) 2016-2019 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 #if BOOST_ASIO_HAS_CO_AWAIT
18 #include <boost/asio/use_awaitable.hpp>
19 #endif
20
21 #include <boost/config/workaround.hpp>
22 #if BOOST_WORKAROUND(BOOST_GCC, < 80200)
23 #define BOOST_BEAST_SYMBOL_HIDDEN __attribute__ ((visibility("hidden")))
24 #else
25 #define BOOST_BEAST_SYMBOL_HIDDEN
26 #endif
27
28 namespace boost {
29 namespace beast {
30 namespace websocket {
31
32 class BOOST_BEAST_SYMBOL_HIDDEN read2_test
33 : public websocket_test_suite
34 {
35 public:
36 template<class Wrap, bool deflateSupported>
37 void
38 doReadTest(
39 Wrap const& w,
40 ws_type_t<deflateSupported>& ws,
41 close_code code)
42 {
43 try
44 {
45 multi_buffer b;
46 w.read(ws, b);
47 fail("", __FILE__, __LINE__);
48 }
49 catch(system_error const& se)
50 {
51 if(se.code() != error::closed)
52 throw;
53 BEAST_EXPECT(
54 ws.reason().code == code);
55 }
56 }
57
58 template<class Wrap, bool deflateSupported>
59 void
60 doFailTest(
61 Wrap const& w,
62 ws_type_t<deflateSupported>& ws,
63 error_code ev)
64 {
65 try
66 {
67 multi_buffer b;
68 w.read(ws, b);
69 fail("", __FILE__, __LINE__);
70 }
71 catch(system_error const& se)
72 {
73 if(se.code() != ev)
74 throw;
75 }
76 }
77
78 template<bool deflateSupported = true, class Wrap>
79 void
80 doTestRead(Wrap const& w)
81 {
82 permessage_deflate pmd;
83 pmd.client_enable = false;
84 pmd.server_enable = false;
85
86 // already closed
87 {
88 echo_server es{log};
89 stream<test::stream, deflateSupported> ws{ioc_};
90 ws.next_layer().connect(es.stream());
91 ws.handshake("localhost", "/");
92 ws.close({});
93 try
94 {
95 multi_buffer b;
96 w.read(ws, b);
97 fail("", __FILE__, __LINE__);
98 }
99 catch(system_error const& se)
100 {
101 BEAST_EXPECTS(
102 se.code() == net::error::operation_aborted,
103 se.code().message());
104 }
105 }
106
107 // empty, fragmented message
108 doTest<deflateSupported>(pmd,
109 [&](ws_type_t<deflateSupported>& ws)
110 {
111 ws.next_layer().append(
112 string_view(
113 "\x01\x00" "\x80\x00", 4));
114 multi_buffer b;
115 w.read(ws, b);
116 BEAST_EXPECT(b.size() == 0);
117 });
118
119 // two part message
120 // triggers "fill the read buffer first"
121 doTest<deflateSupported>(pmd,
122 [&](ws_type_t<deflateSupported>& ws)
123 {
124 w.write_raw(ws, sbuf(
125 "\x01\x81\xff\xff\xff\xff"));
126 w.write_raw(ws, sbuf(
127 "\xd5"));
128 w.write_raw(ws, sbuf(
129 "\x80\x81\xff\xff\xff\xff\xd5"));
130 multi_buffer b;
131 w.read(ws, b);
132 BEAST_EXPECT(buffers_to_string(b.data()) == "**");
133 });
134
135 // ping
136 doTest<deflateSupported>(pmd,
137 [&](ws_type_t<deflateSupported>& ws)
138 {
139 put(ws.next_layer().buffer(), cbuf(
140 {0x89, 0x00}));
141 bool invoked = false;
142 ws.control_callback(
143 [&](frame_type kind, string_view)
144 {
145 BEAST_EXPECT(! invoked);
146 BEAST_EXPECT(kind == frame_type::ping);
147 invoked = true;
148 });
149 w.write(ws, sbuf("Hello"));
150 multi_buffer b;
151 w.read(ws, b);
152 BEAST_EXPECT(invoked);
153 BEAST_EXPECT(ws.got_text());
154 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello");
155 });
156
157 // ping
158 doTest<deflateSupported>(pmd,
159 [&](ws_type_t<deflateSupported>& ws)
160 {
161 put(ws.next_layer().buffer(), cbuf(
162 {0x88, 0x00}));
163 bool invoked = false;
164 ws.control_callback(
165 [&](frame_type kind, string_view)
166 {
167 BEAST_EXPECT(! invoked);
168 BEAST_EXPECT(kind == frame_type::close);
169 invoked = true;
170 });
171 w.write(ws, sbuf("Hello"));
172 doReadTest(w, ws, close_code::none);
173 });
174
175 // ping then message
176 doTest<deflateSupported>(pmd,
177 [&](ws_type_t<deflateSupported>& ws)
178 {
179 bool once = false;
180 ws.control_callback(
181 [&](frame_type kind, string_view s)
182 {
183 BEAST_EXPECT(kind == frame_type::pong);
184 BEAST_EXPECT(! once);
185 once = true;
186 BEAST_EXPECT(s == "");
187 });
188 w.ping(ws, "");
189 ws.binary(true);
190 w.write(ws, sbuf("Hello"));
191 multi_buffer b;
192 w.read(ws, b);
193 BEAST_EXPECT(once);
194 BEAST_EXPECT(ws.got_binary());
195 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello");
196 });
197
198 // ping then fragmented message
199 doTest<deflateSupported>(pmd,
200 [&](ws_type_t<deflateSupported>& ws)
201 {
202 bool once = false;
203 ws.control_callback(
204 [&](frame_type kind, string_view s)
205 {
206 BEAST_EXPECT(kind == frame_type::pong);
207 BEAST_EXPECT(! once);
208 once = true;
209 BEAST_EXPECT(s == "payload");
210 });
211 ws.ping("payload");
212 w.write_some(ws, false, sbuf("Hello, "));
213 w.write_some(ws, false, sbuf(""));
214 w.write_some(ws, true, sbuf("World!"));
215 multi_buffer b;
216 w.read(ws, b);
217 BEAST_EXPECT(once);
218 BEAST_EXPECT(buffers_to_string(b.data()) == "Hello, World!");
219 });
220
221 // masked message, big
222 doStreamLoop([&](test::stream& ts)
223 {
224 echo_server es{log, kind::async_client};
225 ws_type_t<deflateSupported> ws{ts};
226 ws.next_layer().connect(es.stream());
227 ws.set_option(pmd);
228 es.async_handshake();
229 try
230 {
231 w.accept(ws);
232 std::string const s(2000, '*');
233 ws.auto_fragment(false);
234 ws.binary(false);
235 w.write(ws, net::buffer(s));
236 multi_buffer b;
237 w.read(ws, b);
238 BEAST_EXPECT(ws.got_text());
239 BEAST_EXPECT(buffers_to_string(b.data()) == s);
240 ws.next_layer().close();
241 }
242 catch(...)
243 {
244 ts.close();
245 throw;
246 }
247 });
248
249 // close
250 doFailLoop([&](test::fail_count& fc)
251 {
252 echo_server es{log, kind::async};
253 net::io_context ioc;
254 stream<test::stream, deflateSupported> ws{ioc, fc};
255 ws.next_layer().connect(es.stream());
256 ws.handshake("localhost", "/");
257 // Cause close to be received
258 es.async_close();
259 std::size_t count = 0;
260 multi_buffer b;
261 ws.async_read(b,
262 [&](error_code ec, std::size_t)
263 {
264 ++count;
265 if(ec != error::closed)
266 BOOST_THROW_EXCEPTION(
267 system_error{ec});
268 });
269 ioc.run();
270 BEAST_EXPECT(count == 1);
271 });
272
273 // already closed
274 doTest<deflateSupported>(pmd,
275 [&](ws_type_t<deflateSupported>& ws)
276 {
277 w.close(ws, {});
278 multi_buffer b;
279 doFailTest(w, ws,
280 net::error::operation_aborted);
281 });
282
283 // buffer overflow
284 doTest<deflateSupported>(pmd,
285 [&](ws_type_t<deflateSupported>& ws)
286 {
287 std::string const s = "Hello, world!";
288 ws.auto_fragment(false);
289 ws.binary(false);
290 w.write(ws, net::buffer(s));
291 try
292 {
293 multi_buffer b(3);
294 w.read(ws, b);
295 fail("", __FILE__, __LINE__);
296 }
297 catch(system_error const& se)
298 {
299 if(se.code() != error::buffer_overflow)
300 throw;
301 }
302 });
303
304 // bad utf8, big
305 doTest<deflateSupported>(pmd,
306 [&](ws_type_t<deflateSupported>& ws)
307 {
308 auto const s = std::string(2000, '*') +
309 random_string();
310 ws.text(true);
311 w.write(ws, net::buffer(s));
312 doReadTest(w, ws, close_code::bad_payload);
313 });
314
315 // invalid fixed frame header
316 doTest<deflateSupported>(pmd,
317 [&](ws_type_t<deflateSupported>& ws)
318 {
319 w.write_raw(ws, cbuf(
320 {0x8f, 0x80, 0xff, 0xff, 0xff, 0xff}));
321 doReadTest(w, ws, close_code::protocol_error);
322 });
323
324 // bad close
325 doTest<deflateSupported>(pmd,
326 [&](ws_type_t<deflateSupported>& ws)
327 {
328 put(ws.next_layer().buffer(), cbuf(
329 {0x88, 0x02, 0x03, 0xed}));
330 doFailTest(w, ws, error::bad_close_code);
331 });
332
333 // message size above 2^64
334 doTest<deflateSupported>(pmd,
335 [&](ws_type_t<deflateSupported>& ws)
336 {
337 w.write_some(ws, false, sbuf("*"));
338 w.write_raw(ws, cbuf(
339 {0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
340 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}));
341 doReadTest(w, ws, close_code::too_big);
342 });
343
344 // message size exceeds max
345 doTest<deflateSupported>(pmd,
346 [&](ws_type_t<deflateSupported>& ws)
347 {
348 ws.read_message_max(1);
349 w.write(ws, sbuf("**"));
350 doFailTest(w, ws, error::message_too_big);
351 });
352
353 // bad utf8
354 doTest<deflateSupported>(pmd,
355 [&](ws_type_t<deflateSupported>& ws)
356 {
357 put(ws.next_layer().buffer(), cbuf(
358 {0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc}));
359 doFailTest(w, ws, error::bad_frame_payload);
360 });
361
362 // incomplete utf8
363 doTest<deflateSupported>(pmd,
364 [&](ws_type_t<deflateSupported>& ws)
365 {
366 std::string const s =
367 "Hello, world!" "\xc0";
368 w.write(ws, net::buffer(s));
369 doReadTest(w, ws, close_code::bad_payload);
370 });
371
372 // incomplete utf8, big
373 doTest<deflateSupported>(pmd,
374 [&](ws_type_t<deflateSupported>& ws)
375 {
376 std::string const s =
377 "\x81\x7e\x0f\xa1" +
378 std::string(4000, '*') + "\xc0";
379 ws.next_layer().append(s);
380 multi_buffer b;
381 try
382 {
383 do
384 {
385 b.commit(w.read_some(ws, b.prepare(4000)));
386 }
387 while(! ws.is_message_done());
388 }
389 catch(system_error const& se)
390 {
391 if(se.code() != error::bad_frame_payload)
392 throw;
393 }
394 });
395
396 // close frames
397 {
398 auto const check =
399 [&](error_code ev, string_view s)
400 {
401 echo_server es{log};
402 stream<test::stream, deflateSupported> ws{ioc_};
403 ws.next_layer().connect(es.stream());
404 w.handshake(ws, "localhost", "/");
405 ws.next_layer().append(s);
406 static_buffer<1> b;
407 try
408 {
409 w.read(ws, b);
410 fail("", __FILE__, __LINE__);
411 }
412 catch(system_error const& se)
413 {
414 BEAST_EXPECTS(se.code() == ev,
415 se.code().message());
416 }
417 ws.next_layer().close();
418 };
419
420 // payload length 1
421 check(error::bad_close_size,
422 "\x88\x01\x01");
423
424 // invalid close code 1005
425 check(error::bad_close_code,
426 "\x88\x02\x03\xed");
427
428 // invalid utf8
429 check(error::bad_close_payload,
430 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
431
432 // good utf8
433 check(error::closed,
434 "\x88\x06\xfc\x15utf8");
435 }
436 }
437
438 template<class Wrap>
439 void
440 doTestReadDeflate(Wrap const& w)
441 {
442 permessage_deflate pmd;
443 pmd.client_enable = true;
444 pmd.server_enable = true;
445 pmd.client_max_window_bits = 9;
446 pmd.server_max_window_bits = 9;
447 pmd.compLevel = 1;
448
449 // message size limit
450 doTest<true>(pmd,
451 [&](ws_type_t<true>& ws)
452 {
453 std::string const s = std::string(128, '*');
454 w.write(ws, net::buffer(s));
455 ws.read_message_max(32);
456 doFailTest(w, ws, error::message_too_big);
457 });
458
459 // invalid inflate block
460 doTest<true>(pmd,
461 [&](ws_type_t<true>& ws)
462 {
463 auto const& s = random_string();
464 ws.binary(true);
465 ws.next_layer().append(
466 "\xc2\x40" + s.substr(0, 64));
467 flat_buffer b;
468 try
469 {
470 w.read(ws, b);
471 }
472 catch(system_error const& se)
473 {
474 if(se.code() == test::error::test_failure)
475 throw;
476 BEAST_EXPECTS(se.code().category() ==
477 make_error_code(static_cast<
478 zlib::error>(0)).category(),
479 se.code().message());
480 }
481 catch(...)
482 {
483 throw;
484 }
485 });
486
487 // no_context_takeover
488 pmd.server_no_context_takeover = true;
489 doTest<true>(pmd,
490 [&](ws_type_t<true>& ws)
491 {
492 auto const& s = random_string();
493 ws.binary(true);
494 w.write(ws, net::buffer(s));
495 multi_buffer b;
496 w.read(ws, b);
497 BEAST_EXPECT(buffers_to_string(b.data()) == s);
498 });
499 pmd.client_no_context_takeover = false;
500 }
501
502 template<class Wrap>
503 void
504 doTestRead(
505 permessage_deflate const& pmd,
506 Wrap const& w)
507 {
508 // message
509 doTest(pmd, [&](ws_type& ws)
510 {
511 std::string const s = "Hello, world!";
512 ws.auto_fragment(false);
513 ws.binary(false);
514 w.write(ws, net::buffer(s));
515 multi_buffer b;
516 w.read(ws, b);
517 BEAST_EXPECT(ws.got_text());
518 BEAST_EXPECT(buffers_to_string(b.data()) == s);
519 });
520
521 // masked message
522 doStreamLoop([&](test::stream& ts)
523 {
524 echo_server es{log, kind::async_client};
525 ws_type ws{ts};
526 ws.next_layer().connect(es.stream());
527 ws.set_option(pmd);
528 es.async_handshake();
529 try
530 {
531 w.accept(ws);
532 std::string const s = "Hello, world!";
533 ws.auto_fragment(false);
534 ws.binary(false);
535 w.write(ws, net::buffer(s));
536 multi_buffer b;
537 w.read(ws, b);
538 BEAST_EXPECT(ws.got_text());
539 BEAST_EXPECT(buffers_to_string(b.data()) == s);
540 ws.next_layer().close();
541 }
542 catch(...)
543 {
544 ts.close();
545 throw;
546 }
547 });
548
549 // empty message
550 doTest(pmd, [&](ws_type& ws)
551 {
552 std::string const s = "";
553 ws.text(true);
554 w.write(ws, net::buffer(s));
555 multi_buffer b;
556 w.read(ws, b);
557 BEAST_EXPECT(ws.got_text());
558 BEAST_EXPECT(buffers_to_string(b.data()) == s);
559 });
560
561 // partial message
562 doTest(pmd, [&](ws_type& ws)
563 {
564 std::string const s = "Hello";
565 w.write(ws, net::buffer(s));
566 char buf[3];
567 auto const bytes_written =
568 w.read_some(ws, net::buffer(buf, sizeof(buf)));
569 BEAST_EXPECT(bytes_written > 0);
570 BEAST_EXPECT(
571 string_view(buf, 3).substr(0, bytes_written) ==
572 s.substr(0, bytes_written));
573 });
574
575 // partial message, dynamic buffer
576 doTest(pmd, [&](ws_type& ws)
577 {
578 std::string const s = "Hello, world!";
579 w.write(ws, net::buffer(s));
580 multi_buffer b;
581 auto bytes_written =
582 w.read_some(ws, 3, b);
583 BEAST_EXPECT(bytes_written > 0);
584 BEAST_EXPECT(buffers_to_string(b.data()) ==
585 s.substr(0, b.size()));
586 w.read_some(ws, 256, b);
587 BEAST_EXPECT(buffers_to_string(b.data()) == s);
588 });
589
590 // big message
591 doTest(pmd, [&](ws_type& ws)
592 {
593 auto const& s = random_string();
594 ws.binary(true);
595 w.write(ws, net::buffer(s));
596 multi_buffer b;
597 w.read(ws, b);
598 BEAST_EXPECT(buffers_to_string(b.data()) == s);
599 });
600
601 // message, bad utf8
602 doTest(pmd, [&](ws_type& ws)
603 {
604 std::string const s = "\x03\xea\xf0\x28\x8c\xbc";
605 ws.auto_fragment(false);
606 ws.text(true);
607 w.write(ws, net::buffer(s));
608 doReadTest(w, ws, close_code::bad_payload);
609 });
610 }
611
612 void
613 testRead()
614 {
615 doTestRead<false>(SyncClient{});
616 doTestRead<true>(SyncClient{});
617 doTestReadDeflate(SyncClient{});
618 yield_to([&](yield_context yield)
619 {
620 doTestRead<false>(AsyncClient{yield});
621 doTestRead<true>(AsyncClient{yield});
622 doTestReadDeflate(AsyncClient{yield});
623 });
624
625 permessage_deflate pmd;
626 pmd.client_enable = false;
627 pmd.server_enable = false;
628 doTestRead(pmd, SyncClient{});
629 yield_to([&](yield_context yield)
630 {
631 doTestRead(pmd, AsyncClient{yield});
632 });
633
634 pmd.client_enable = true;
635 pmd.server_enable = true;
636 pmd.client_max_window_bits = 9;
637 pmd.server_max_window_bits = 9;
638 pmd.compLevel = 1;
639 doTestRead(pmd, SyncClient{});
640 yield_to([&](yield_context yield)
641 {
642 doTestRead(pmd, AsyncClient{yield});
643 });
644
645 // Read close frames
646 {
647 auto const check =
648 [&](error_code ev, string_view s)
649 {
650 echo_server es{log};
651 stream<test::stream> ws{ioc_};
652 ws.next_layer().connect(es.stream());
653 ws.handshake("localhost", "/");
654 ws.next_layer().append(s);
655 static_buffer<1> b;
656 error_code ec;
657 ws.read(b, ec);
658 BEAST_EXPECTS(ec == ev, ec.message());
659 ws.next_layer().close();
660 };
661
662 // payload length 1
663 check(error::bad_close_size,
664 "\x88\x01\x01");
665
666 // invalid close code 1005
667 check(error::bad_close_code,
668 "\x88\x02\x03\xed");
669
670 // invalid utf8
671 check(error::bad_close_payload,
672 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
673
674 // good utf8
675 check(error::closed,
676 "\x88\x06\xfc\x15utf8");
677 }
678 }
679
680 #if BOOST_ASIO_HAS_CO_AWAIT
681 void testAwaitableCompiles(
682 stream<test::stream>& s,
683 flat_buffer& dynbuf,
684 net::mutable_buffer buf,
685 std::size_t limit)
686 {
687 static_assert(std::is_same_v<
688 net::awaitable<std::size_t>, decltype(
689 s.async_read(dynbuf, net::use_awaitable))>);
690
691 static_assert(std::is_same_v<
692 net::awaitable<std::size_t>, decltype(
693 s.async_read_some(buf, net::use_awaitable))>);
694
695 static_assert(std::is_same_v<
696 net::awaitable<std::size_t>, decltype(
697 s.async_read_some(dynbuf, limit, net::use_awaitable))>);
698 }
699 #endif
700
701 void
702 run() override
703 {
704 testRead();
705 #if BOOST_ASIO_HAS_CO_AWAIT
706 boost::ignore_unused(&read2_test::testAwaitableCompiles);
707 #endif
708 }
709 };
710
711 BEAST_DEFINE_TESTSUITE(beast,websocket,read2);
712
713 } // websocket
714 } // beast
715 } // boost