2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 // Test that header file is self-contained.
11 #include <boost/beast/websocket/stream.hpp>
15 #include <boost/asio/write.hpp>
17 #if BOOST_ASIO_HAS_CO_AWAIT
18 #include <boost/asio/use_awaitable.hpp>
21 #include <boost/config/workaround.hpp>
22 #if BOOST_WORKAROUND(BOOST_GCC, < 80200)
23 #define BOOST_BEAST_SYMBOL_HIDDEN __attribute__ ((visibility("hidden")))
25 #define BOOST_BEAST_SYMBOL_HIDDEN
32 class BOOST_BEAST_SYMBOL_HIDDEN read2_test
33 : public websocket_test_suite
36 template<class Wrap
, bool deflateSupported
>
40 ws_type_t
<deflateSupported
>& ws
,
47 fail("", __FILE__
, __LINE__
);
49 catch(system_error
const& se
)
51 if(se
.code() != error::closed
)
54 ws
.reason().code
== code
);
58 template<class Wrap
, bool deflateSupported
>
62 ws_type_t
<deflateSupported
>& ws
,
69 fail("", __FILE__
, __LINE__
);
71 catch(system_error
const& se
)
78 template<bool deflateSupported
= true, class Wrap
>
80 doTestRead(Wrap
const& w
)
82 permessage_deflate pmd
;
83 pmd
.client_enable
= false;
84 pmd
.server_enable
= false;
89 stream
<test::stream
, deflateSupported
> ws
{ioc_
};
90 ws
.next_layer().connect(es
.stream());
91 ws
.handshake("localhost", "/");
97 fail("", __FILE__
, __LINE__
);
99 catch(system_error
const& se
)
102 se
.code() == net::error::operation_aborted
,
103 se
.code().message());
107 // empty, fragmented message
108 doTest
<deflateSupported
>(pmd
,
109 [&](ws_type_t
<deflateSupported
>& ws
)
111 ws
.next_layer().append(
113 "\x01\x00" "\x80\x00", 4));
116 BEAST_EXPECT(b
.size() == 0);
120 // triggers "fill the read buffer first"
121 doTest
<deflateSupported
>(pmd
,
122 [&](ws_type_t
<deflateSupported
>& ws
)
124 w
.write_raw(ws
, sbuf(
125 "\x01\x81\xff\xff\xff\xff"));
126 w
.write_raw(ws
, sbuf(
128 w
.write_raw(ws
, sbuf(
129 "\x80\x81\xff\xff\xff\xff\xd5"));
132 BEAST_EXPECT(buffers_to_string(b
.data()) == "**");
136 doTest
<deflateSupported
>(pmd
,
137 [&](ws_type_t
<deflateSupported
>& ws
)
139 put(ws
.next_layer().buffer(), cbuf(
141 bool invoked
= false;
143 [&](frame_type kind
, string_view
)
145 BEAST_EXPECT(! invoked
);
146 BEAST_EXPECT(kind
== frame_type::ping
);
149 w
.write(ws
, sbuf("Hello"));
152 BEAST_EXPECT(invoked
);
153 BEAST_EXPECT(ws
.got_text());
154 BEAST_EXPECT(buffers_to_string(b
.data()) == "Hello");
158 doTest
<deflateSupported
>(pmd
,
159 [&](ws_type_t
<deflateSupported
>& ws
)
161 put(ws
.next_layer().buffer(), cbuf(
163 bool invoked
= false;
165 [&](frame_type kind
, string_view
)
167 BEAST_EXPECT(! invoked
);
168 BEAST_EXPECT(kind
== frame_type::close
);
171 w
.write(ws
, sbuf("Hello"));
172 doReadTest(w
, ws
, close_code::none
);
176 doTest
<deflateSupported
>(pmd
,
177 [&](ws_type_t
<deflateSupported
>& ws
)
181 [&](frame_type kind
, string_view s
)
183 BEAST_EXPECT(kind
== frame_type::pong
);
184 BEAST_EXPECT(! once
);
186 BEAST_EXPECT(s
== "");
190 w
.write(ws
, sbuf("Hello"));
194 BEAST_EXPECT(ws
.got_binary());
195 BEAST_EXPECT(buffers_to_string(b
.data()) == "Hello");
198 // ping then fragmented message
199 doTest
<deflateSupported
>(pmd
,
200 [&](ws_type_t
<deflateSupported
>& ws
)
204 [&](frame_type kind
, string_view s
)
206 BEAST_EXPECT(kind
== frame_type::pong
);
207 BEAST_EXPECT(! once
);
209 BEAST_EXPECT(s
== "payload");
212 w
.write_some(ws
, false, sbuf("Hello, "));
213 w
.write_some(ws
, false, sbuf(""));
214 w
.write_some(ws
, true, sbuf("World!"));
218 BEAST_EXPECT(buffers_to_string(b
.data()) == "Hello, World!");
221 // masked message, big
222 doStreamLoop([&](test::stream
& ts
)
224 echo_server es
{log
, kind::async_client
};
225 ws_type_t
<deflateSupported
> ws
{ts
};
226 ws
.next_layer().connect(es
.stream());
228 es
.async_handshake();
232 std::string
const s(2000, '*');
233 ws
.auto_fragment(false);
235 w
.write(ws
, net::buffer(s
));
238 BEAST_EXPECT(ws
.got_text());
239 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
240 ws
.next_layer().close();
250 doFailLoop([&](test::fail_count
& fc
)
252 echo_server es
{log
, kind::async
};
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
259 std::size_t count
= 0;
262 [&](error_code ec
, std::size_t)
265 if(ec
!= error::closed
)
266 BOOST_THROW_EXCEPTION(
270 BEAST_EXPECT(count
== 1);
274 doTest
<deflateSupported
>(pmd
,
275 [&](ws_type_t
<deflateSupported
>& ws
)
280 net::error::operation_aborted
);
284 doTest
<deflateSupported
>(pmd
,
285 [&](ws_type_t
<deflateSupported
>& ws
)
287 std::string
const s
= "Hello, world!";
288 ws
.auto_fragment(false);
290 w
.write(ws
, net::buffer(s
));
295 fail("", __FILE__
, __LINE__
);
297 catch(system_error
const& se
)
299 if(se
.code() != error::buffer_overflow
)
305 doTest
<deflateSupported
>(pmd
,
306 [&](ws_type_t
<deflateSupported
>& ws
)
308 auto const s
= std::string(2000, '*') +
311 w
.write(ws
, net::buffer(s
));
312 doReadTest(w
, ws
, close_code::bad_payload
);
315 // invalid fixed frame header
316 doTest
<deflateSupported
>(pmd
,
317 [&](ws_type_t
<deflateSupported
>& ws
)
319 w
.write_raw(ws
, cbuf(
320 {0x8f, 0x80, 0xff, 0xff, 0xff, 0xff}));
321 doReadTest(w
, ws
, close_code::protocol_error
);
325 doTest
<deflateSupported
>(pmd
,
326 [&](ws_type_t
<deflateSupported
>& ws
)
328 put(ws
.next_layer().buffer(), cbuf(
329 {0x88, 0x02, 0x03, 0xed}));
330 doFailTest(w
, ws
, error::bad_close_code
);
333 // message size above 2^64
334 doTest
<deflateSupported
>(pmd
,
335 [&](ws_type_t
<deflateSupported
>& ws
)
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
);
344 // message size exceeds max
345 doTest
<deflateSupported
>(pmd
,
346 [&](ws_type_t
<deflateSupported
>& ws
)
348 ws
.read_message_max(1);
349 w
.write(ws
, sbuf("**"));
350 doFailTest(w
, ws
, error::message_too_big
);
354 doTest
<deflateSupported
>(pmd
,
355 [&](ws_type_t
<deflateSupported
>& ws
)
357 put(ws
.next_layer().buffer(), cbuf(
358 {0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc}));
359 doFailTest(w
, ws
, error::bad_frame_payload
);
363 doTest
<deflateSupported
>(pmd
,
364 [&](ws_type_t
<deflateSupported
>& ws
)
366 std::string
const s
=
367 "Hello, world!" "\xc0";
368 w
.write(ws
, net::buffer(s
));
369 doReadTest(w
, ws
, close_code::bad_payload
);
372 // incomplete utf8, big
373 doTest
<deflateSupported
>(pmd
,
374 [&](ws_type_t
<deflateSupported
>& ws
)
376 std::string
const s
=
378 std::string(4000, '*') + "\xc0";
379 ws
.next_layer().append(s
);
385 b
.commit(w
.read_some(ws
, b
.prepare(4000)));
387 while(! ws
.is_message_done());
389 catch(system_error
const& se
)
391 if(se
.code() != error::bad_frame_payload
)
399 [&](error_code ev
, string_view s
)
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
);
410 fail("", __FILE__
, __LINE__
);
412 catch(system_error
const& se
)
414 BEAST_EXPECTS(se
.code() == ev
,
415 se
.code().message());
417 ws
.next_layer().close();
421 check(error::bad_close_size
,
424 // invalid close code 1005
425 check(error::bad_close_code
,
429 check(error::bad_close_payload
,
430 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
434 "\x88\x06\xfc\x15utf8");
440 doTestReadDeflate(Wrap
const& w
)
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;
449 // message size limit
451 [&](ws_type_t
<true>& ws
)
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
);
459 // invalid inflate block
461 [&](ws_type_t
<true>& ws
)
463 auto const& s
= random_string();
465 ws
.next_layer().append(
466 "\xc2\x40" + s
.substr(0, 64));
472 catch(system_error
const& se
)
474 if(se
.code() == test::error::test_failure
)
476 BEAST_EXPECTS(se
.code().category() ==
477 make_error_code(static_cast<
478 zlib::error
>(0)).category(),
479 se
.code().message());
487 // no_context_takeover
488 pmd
.server_no_context_takeover
= true;
490 [&](ws_type_t
<true>& ws
)
492 auto const& s
= random_string();
494 w
.write(ws
, net::buffer(s
));
497 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
499 pmd
.client_no_context_takeover
= false;
505 permessage_deflate
const& pmd
,
509 doTest(pmd
, [&](ws_type
& ws
)
511 std::string
const s
= "Hello, world!";
512 ws
.auto_fragment(false);
514 w
.write(ws
, net::buffer(s
));
517 BEAST_EXPECT(ws
.got_text());
518 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
522 doStreamLoop([&](test::stream
& ts
)
524 echo_server es
{log
, kind::async_client
};
526 ws
.next_layer().connect(es
.stream());
528 es
.async_handshake();
532 std::string
const s
= "Hello, world!";
533 ws
.auto_fragment(false);
535 w
.write(ws
, net::buffer(s
));
538 BEAST_EXPECT(ws
.got_text());
539 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
540 ws
.next_layer().close();
550 doTest(pmd
, [&](ws_type
& ws
)
552 std::string
const s
= "";
554 w
.write(ws
, net::buffer(s
));
557 BEAST_EXPECT(ws
.got_text());
558 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
562 doTest(pmd
, [&](ws_type
& ws
)
564 std::string
const s
= "Hello";
565 w
.write(ws
, net::buffer(s
));
567 auto const bytes_written
=
568 w
.read_some(ws
, net::buffer(buf
, sizeof(buf
)));
569 BEAST_EXPECT(bytes_written
> 0);
571 string_view(buf
, 3).substr(0, bytes_written
) ==
572 s
.substr(0, bytes_written
));
575 // partial message, dynamic buffer
576 doTest(pmd
, [&](ws_type
& ws
)
578 std::string
const s
= "Hello, world!";
579 w
.write(ws
, net::buffer(s
));
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
);
591 doTest(pmd
, [&](ws_type
& ws
)
593 auto const& s
= random_string();
595 w
.write(ws
, net::buffer(s
));
598 BEAST_EXPECT(buffers_to_string(b
.data()) == s
);
602 doTest(pmd
, [&](ws_type
& ws
)
604 std::string
const s
= "\x03\xea\xf0\x28\x8c\xbc";
605 ws
.auto_fragment(false);
607 w
.write(ws
, net::buffer(s
));
608 doReadTest(w
, ws
, close_code::bad_payload
);
615 doTestRead
<false>(SyncClient
{});
616 doTestRead
<true>(SyncClient
{});
617 doTestReadDeflate(SyncClient
{});
618 yield_to([&](yield_context yield
)
620 doTestRead
<false>(AsyncClient
{yield
});
621 doTestRead
<true>(AsyncClient
{yield
});
622 doTestReadDeflate(AsyncClient
{yield
});
625 permessage_deflate pmd
;
626 pmd
.client_enable
= false;
627 pmd
.server_enable
= false;
628 doTestRead(pmd
, SyncClient
{});
629 yield_to([&](yield_context yield
)
631 doTestRead(pmd
, AsyncClient
{yield
});
634 pmd
.client_enable
= true;
635 pmd
.server_enable
= true;
636 pmd
.client_max_window_bits
= 9;
637 pmd
.server_max_window_bits
= 9;
639 doTestRead(pmd
, SyncClient
{});
640 yield_to([&](yield_context yield
)
642 doTestRead(pmd
, AsyncClient
{yield
});
648 [&](error_code ev
, string_view s
)
651 stream
<test::stream
> ws
{ioc_
};
652 ws
.next_layer().connect(es
.stream());
653 ws
.handshake("localhost", "/");
654 ws
.next_layer().append(s
);
658 BEAST_EXPECTS(ec
== ev
, ec
.message());
659 ws
.next_layer().close();
663 check(error::bad_close_size
,
666 // invalid close code 1005
667 check(error::bad_close_code
,
671 check(error::bad_close_payload
,
672 "\x88\x06\xfc\x15\x0f\xd7\x73\x43");
676 "\x88\x06\xfc\x15utf8");
680 #if BOOST_ASIO_HAS_CO_AWAIT
681 void testAwaitableCompiles(
682 stream
<test::stream
>& s
,
684 net::mutable_buffer buf
,
687 static_assert(std::is_same_v
<
688 net::awaitable
<std::size_t>, decltype(
689 s
.async_read(dynbuf
, net::use_awaitable
))>);
691 static_assert(std::is_same_v
<
692 net::awaitable
<std::size_t>, decltype(
693 s
.async_read_some(buf
, net::use_awaitable
))>);
695 static_assert(std::is_same_v
<
696 net::awaitable
<std::size_t>, decltype(
697 s
.async_read_some(dynbuf
, limit
, net::use_awaitable
))>);
705 #if BOOST_ASIO_HAS_CO_AWAIT
706 boost::ignore_unused(&read2_test::testAwaitableCompiles
);
711 BEAST_DEFINE_TESTSUITE(beast
,websocket
,read2
);