• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
doReadTest(Wrap const & w,ws_type_t<deflateSupported> & ws,close_code code)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
doFailTest(Wrap const & w,ws_type_t<deflateSupported> & ws,error_code ev)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
doTestRead(Wrap const & w)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
doTestReadDeflate(Wrap const & w)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
doTestRead(permessage_deflate const & pmd,Wrap const & w)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
testRead()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
testAwaitableCompiles(stream<test::stream> & s,flat_buffer & dynbuf,net::mutable_buffer buf,std::size_t limit)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
run()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
716