2 // Copyright (c) 2013-2017 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)
8 // Test that header file is self-contained.
9 #include <beast/websocket/stream.hpp>
11 #include "websocket_async_echo_server.hpp"
12 #include "websocket_sync_echo_server.hpp"
14 #include <beast/core/streambuf.hpp>
15 #include <beast/core/to_string.hpp>
16 #include <beast/test/fail_stream.hpp>
17 #include <beast/test/string_istream.hpp>
18 #include <beast/test/yield_to.hpp>
19 #include <beast/unit_test/suite.hpp>
20 #include <boost/asio.hpp>
21 #include <boost/asio/spawn.hpp>
22 #include <boost/optional.hpp>
24 #include <condition_variable>
30 : public beast::unit_test::suite
31 , public test::enable_yield_to
34 using self
= stream_test
;
35 using endpoint_type
= boost::asio::ip::tcp::endpoint
;
36 using address_type
= boost::asio::ip::address
;
37 using socket_type
= boost::asio::ip::tcp::socket
;
41 stream
<socket_type
> ws
;
43 con(endpoint_type
const& ep
, boost::asio::io_service
& ios
)
46 ws
.next_layer().connect(ep
);
47 ws
.handshake("localhost", "/");
51 template<std::size_t N
>
54 std::array
<std::uint8_t, N
> v_
;
55 boost::asio::const_buffer cb_
;
58 using value_type
= decltype(cb_
);
59 using const_iterator
= value_type
const*;
64 : v_({{ static_cast<std::uint8_t>(vn
)... }})
65 , cb_(v_
.data(), v_
.size())
83 cbuf_helper
<sizeof...(Vn
)>
86 return cbuf_helper
<sizeof...(Vn
)>(vn
...);
89 template<std::size_t N
>
91 boost::asio::const_buffers_1
92 sbuf(const char (&s
)[N
])
94 return boost::asio::const_buffers_1(&s
[0], N
-1);
100 run_until(boost::asio::io_service
& ios
,
101 std::size_t limit
, Pred
&& pred
)
103 for(std::size_t i
= 0; i
< limit
; ++i
)
112 struct test_decorator
116 test_decorator(test_decorator
const&) = default;
118 test_decorator(int& what_
)
124 template<class Fields
>
126 operator()(http::header
<true, Fields
>&) const
131 template<class Fields
>
133 operator()(http::header
<false, Fields
>&) const
142 stream
<socket_type
> ws(ios_
);
143 ws
.set_option(auto_fragment
{true});
144 ws
.set_option(keep_alive
{false});
145 ws
.set_option(write_buffer_size
{2048});
146 ws
.set_option(message_type
{opcode::text
});
147 ws
.set_option(read_buffer_size
{8192});
148 ws
.set_option(read_message_max
{1 * 1024 * 1024});
151 ws
.set_option(write_buffer_size
{7});
154 catch(std::exception
const&)
160 message_type
{opcode::close
};
163 catch(std::exception
const&)
172 static std::size_t constexpr limit
= 100;
174 for(n
= 0; n
< limit
; ++n
)
177 http::request_header req
;
181 req
.fields
.insert("Host", "localhost");
182 req
.fields
.insert("Upgrade", "websocket");
183 req
.fields
.insert("Connection", "upgrade");
184 req
.fields
.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
185 req
.fields
.insert("Sec-WebSocket-Version", "13");
186 stream
<test::fail_stream
<
187 test::string_istream
>> ws(n
, ios_
, "");
193 catch(system_error
const&)
197 BEAST_EXPECT(n
< limit
);
201 stream
<test::string_istream
> ws(ios_
,
203 "Host: localhost:80\r\n"
204 "Upgrade: WebSocket\r\n"
205 "Connection: upgrade\r\n"
206 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
207 "Sec-WebSocket-Version: 13\r\n"
215 catch(system_error
const&)
222 stream
<test::string_istream
> ws(ios_
,
231 catch(system_error
const&)
238 void testBadHandshakes()
241 [&](error_code
const& ev
, std::string
const& s
)
243 for(std::size_t i
= 0; i
< s
.size(); ++i
)
245 stream
<test::string_istream
> ws(ios_
,
246 s
.substr(i
, s
.size() - i
));
247 ws
.set_option(keep_alive
{true});
250 ws
.accept(boost::asio::buffer(
252 BEAST_EXPECTS(! ev
, ev
.message());
254 catch(system_error
const& se
)
256 BEAST_EXPECTS(se
.code() == ev
, se
.what());
261 check(error::handshake_failed
,
263 "Host: localhost:80\r\n"
264 "Upgrade: WebSocket\r\n"
265 "Connection: keep-alive,upgrade\r\n"
266 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
267 "Sec-WebSocket-Version: 13\r\n"
271 check(error::handshake_failed
,
272 "POST / HTTP/1.1\r\n"
273 "Host: localhost:80\r\n"
274 "Upgrade: WebSocket\r\n"
275 "Connection: keep-alive,upgrade\r\n"
276 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
277 "Sec-WebSocket-Version: 13\r\n"
281 check(error::handshake_failed
,
283 "Upgrade: WebSocket\r\n"
284 "Connection: keep-alive,upgrade\r\n"
285 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
286 "Sec-WebSocket-Version: 13\r\n"
289 // missing Sec-WebSocket-Key
290 check(error::handshake_failed
,
292 "Host: localhost:80\r\n"
293 "Upgrade: WebSocket\r\n"
294 "Connection: keep-alive,upgrade\r\n"
295 "Sec-WebSocket-Version: 13\r\n"
298 // missing Sec-WebSocket-Version
299 check(error::handshake_failed
,
301 "Host: localhost:80\r\n"
302 "Upgrade: WebSocket\r\n"
303 "Connection: keep-alive,upgrade\r\n"
304 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
307 // wrong Sec-WebSocket-Version
308 check(error::handshake_failed
,
310 "Host: localhost:80\r\n"
311 "Upgrade: WebSocket\r\n"
312 "Connection: keep-alive,upgrade\r\n"
313 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
314 "Sec-WebSocket-Version: 1\r\n"
317 // missing upgrade token
318 check(error::handshake_failed
,
320 "Host: localhost:80\r\n"
321 "Upgrade: HTTP/2\r\n"
322 "Connection: upgrade\r\n"
323 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
324 "Sec-WebSocket-Version: 13\r\n"
327 // missing connection token
328 check(error::handshake_failed
,
330 "Host: localhost:80\r\n"
331 "Upgrade: WebSocket\r\n"
332 "Connection: keep-alive\r\n"
333 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
334 "Sec-WebSocket-Version: 13\r\n"
340 "Host: localhost:80\r\n"
341 "Upgrade: WebSocket\r\n"
342 "Connection: upgrade\r\n"
343 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
344 "Sec-WebSocket-Version: 13\r\n"
349 void testBadResponses()
352 [&](std::string
const& s
)
354 stream
<test::string_istream
> ws(ios_
, s
);
357 ws
.handshake("localhost:80", "/");
360 catch(system_error
const& se
)
362 BEAST_EXPECT(se
.code() == error::response_failed
);
365 // wrong HTTP version
367 "HTTP/1.0 101 Switching Protocols\r\n"
369 "Upgrade: WebSocket\r\n"
370 "Connection: upgrade\r\n"
371 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
372 "Sec-WebSocket-Version: 13\r\n"
377 "HTTP/1.1 200 OK\r\n"
379 "Upgrade: WebSocket\r\n"
380 "Connection: upgrade\r\n"
381 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
382 "Sec-WebSocket-Version: 13\r\n"
385 // missing upgrade token
387 "HTTP/1.1 101 Switching Protocols\r\n"
389 "Upgrade: HTTP/2\r\n"
390 "Connection: upgrade\r\n"
391 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
392 "Sec-WebSocket-Version: 13\r\n"
395 // missing connection token
397 "HTTP/1.1 101 Switching Protocols\r\n"
399 "Upgrade: WebSocket\r\n"
400 "Connection: keep-alive\r\n"
401 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
402 "Sec-WebSocket-Version: 13\r\n"
405 // missing accept key
407 "HTTP/1.1 101 Switching Protocols\r\n"
409 "Upgrade: WebSocket\r\n"
410 "Connection: upgrade\r\n"
411 "Sec-WebSocket-Version: 13\r\n"
416 "HTTP/1.1 101 Switching Protocols\r\n"
418 "Upgrade: WebSocket\r\n"
419 "Connection: upgrade\r\n"
420 "Sec-WebSocket-Accept: *\r\n"
421 "Sec-WebSocket-Version: 13\r\n"
427 testDecorator(endpoint_type
const& ep
)
430 socket_type sock
{ios_
};
431 sock
.connect(ep
, ec
);
432 if(! BEAST_EXPECTS(! ec
, ec
.message()))
434 stream
<socket_type
&> ws
{sock
};
436 ws
.set_option(decorate(test_decorator
{what
}));
437 BEAST_EXPECT(what
== 0);
438 ws
.handshake("localhost", "/", ec
);
439 if(! BEAST_EXPECTS(! ec
, ec
.message()))
441 BEAST_EXPECT(what
== 1);
444 void testMask(endpoint_type
const& ep
,
445 yield_context do_yield
)
449 for(char n
= 0; n
< 20; ++n
)
452 socket_type
sock(ios_
);
453 sock
.connect(ep
, ec
);
454 if(! BEAST_EXPECTS(! ec
, ec
.message()))
456 stream
<socket_type
&> ws(sock
);
457 ws
.handshake("localhost", "/", ec
);
458 if(! BEAST_EXPECTS(! ec
, ec
.message()))
460 ws
.write(boost::asio::buffer(v
), ec
);
461 if(! BEAST_EXPECTS(! ec
, ec
.message()))
466 if(! BEAST_EXPECTS(! ec
, ec
.message()))
468 BEAST_EXPECT(to_string(db
.data()) ==
469 std::string(v
.data(), v
.size()));
475 for(char n
= 0; n
< 20; ++n
)
478 socket_type
sock(ios_
);
479 sock
.connect(ep
, ec
);
480 if(! BEAST_EXPECTS(! ec
, ec
.message()))
482 stream
<socket_type
&> ws(sock
);
483 ws
.handshake("localhost", "/", ec
);
484 if(! BEAST_EXPECTS(! ec
, ec
.message()))
486 ws
.async_write(boost::asio::buffer(v
), do_yield
[ec
]);
487 if(! BEAST_EXPECTS(! ec
, ec
.message()))
491 ws
.async_read(op
, db
, do_yield
[ec
]);
492 if(! BEAST_EXPECTS(! ec
, ec
.message()))
494 BEAST_EXPECT(to_string(db
.data()) ==
495 std::string(v
.data(), v
.size()));
501 void testClose(endpoint_type
const& ep
, yield_context
)
506 boost::asio::write(c
.ws
.next_layer(),
507 cbuf(0x88, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00));
510 // invalid close code 1005
512 boost::asio::write(c
.ws
.next_layer(),
513 cbuf(0x88, 0x82, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x12));
518 boost::asio::write(c
.ws
.next_layer(),
519 cbuf(0x88, 0x86, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x15,
520 0x0f, 0xd7, 0x73, 0x43));
525 boost::asio::write(c
.ws
.next_layer(),
526 cbuf(0x88, 0x86, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x15,
527 'u', 't', 'f', '8'));
532 void testInvokable1(endpoint_type
const& ep
)
534 boost::asio::io_service ios
;
535 stream
<socket_type
> ws(ios
);
536 ws
.next_layer().connect(ep
);
537 ws
.handshake("localhost", "/");
539 // Make remote send a ping frame
540 ws
.set_option(message_type(opcode::text
));
541 ws
.write(buffer_cat(sbuf("PING"), sbuf("ping")));
543 std::size_t count
= 0;
545 // Write a text message
547 ws
.async_write(sbuf("Hello"),
557 ws
.async_read(op
, db
,
562 // Run until the read_op writes a close frame.
563 while(! ws
.wr_block_
)
565 // Write a text message, leaving
566 // the write_op suspended as invokable.
567 ws
.async_write(sbuf("Hello"),
571 // Send is canceled because close received.
572 BEAST_EXPECT(ec
== boost::asio::
573 error::operation_aborted
,
575 // Writes after close are aborted.
576 ws
.async_write(sbuf("World"),
580 BEAST_EXPECT(ec
== boost::asio::
581 error::operation_aborted
,
585 // Run until all completions are delivered.
586 static std::size_t constexpr limit
= 100;
588 for(n
= 0; n
< limit
; ++n
)
594 BEAST_EXPECT(n
< limit
);
599 void testInvokable2(endpoint_type
const& ep
)
601 boost::asio::io_service ios
;
602 stream
<socket_type
> ws(ios
);
603 ws
.next_layer().connect(ep
);
604 ws
.handshake("localhost", "/");
606 // Make remote send a text message with bad utf8.
607 ws
.set_option(message_type(opcode::binary
));
608 ws
.write(buffer_cat(sbuf("TEXT"),
609 cbuf(0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc)));
612 std::size_t count
= 0;
613 // Read text message with bad utf8.
614 // Causes a close to be sent, blocking writes.
615 ws
.async_read(op
, db
,
618 // Read should fail with protocol error
621 ec
== error::failed
, ec
.message());
622 // Reads after failure are aborted
623 ws
.async_read(op
, db
,
627 BEAST_EXPECTS(ec
== boost::asio::
628 error::operation_aborted
,
632 // Run until the read_op writes a close frame.
633 while(! ws
.wr_block_
)
635 // Write a text message, leaving
636 // the write_op suspended as invokable.
637 ws
.async_write(sbuf("Hello"),
641 // Send is canceled because close received.
642 BEAST_EXPECTS(ec
== boost::asio::
643 error::operation_aborted
,
645 // Writes after close are aborted.
646 ws
.async_write(sbuf("World"),
650 BEAST_EXPECTS(ec
== boost::asio::
651 error::operation_aborted
,
655 // Run until all completions are delivered.
656 static std::size_t constexpr limit
= 100;
658 for(n
= 0; n
< limit
; ++n
)
664 BEAST_EXPECT(n
< limit
);
668 void testInvokable3(endpoint_type
const& ep
)
670 boost::asio::io_service ios
;
671 stream
<socket_type
> ws(ios
);
672 ws
.next_layer().connect(ep
);
673 ws
.handshake("localhost", "/");
675 // Cause close to be received
676 ws
.set_option(message_type(opcode::binary
));
677 ws
.write(sbuf("CLOSE"));
680 std::size_t count
= 0;
681 // Read a close frame.
682 // Sends a close frame, blocking writes.
683 ws
.async_read(op
, db
,
686 // Read should complete with error::closed
688 BEAST_EXPECTS(ec
== error::closed
,
690 // Pings after a close are aborted
695 BEAST_EXPECTS(ec
== boost::asio::
696 error::operation_aborted
,
700 if(! BEAST_EXPECT(run_until(ios
, 100,
701 [&]{ return ws
.wr_close_
; })))
704 ws
.async_ping("payload",
707 // Pings after a close are aborted
709 BEAST_EXPECTS(ec
== boost::asio::
710 error::operation_aborted
,
712 // Subsequent calls to close are aborted
717 BEAST_EXPECTS(ec
== boost::asio::
718 error::operation_aborted
,
722 static std::size_t constexpr limit
= 100;
724 for(n
= 0; n
< limit
; ++n
)
730 BEAST_EXPECT(n
< limit
);
734 void testInvokable4(endpoint_type
const& ep
)
736 boost::asio::io_service ios
;
737 stream
<socket_type
> ws(ios
);
738 ws
.next_layer().connect(ep
);
739 ws
.handshake("localhost", "/");
741 // Cause close to be received
742 ws
.set_option(message_type(opcode::binary
));
743 ws
.write(sbuf("CLOSE"));
746 std::size_t count
= 0;
747 ws
.async_read(op
, db
,
751 BEAST_EXPECTS(ec
== error::closed
,
754 while(! ws
.wr_block_
)
757 ws
.async_close("payload",
761 BEAST_EXPECTS(ec
== boost::asio::
762 error::operation_aborted
,
765 static std::size_t constexpr limit
= 100;
767 for(n
= 0; n
< limit
; ++n
)
773 BEAST_EXPECT(n
< limit
);
778 void testInvokable5(endpoint_type
const& ep
)
780 boost::asio::io_service ios
;
781 stream
<socket_type
> ws(ios
);
782 ws
.next_layer().connect(ep
);
783 ws
.handshake("localhost", "/");
785 ws
.async_write(sbuf("CLOSE"),
789 ws
.async_write(sbuf("PING"),
797 ws
.async_read(op
, db
,
800 BEAST_EXPECTS(ec
== error::closed
, ec
.message());
802 if(! BEAST_EXPECT(run_until(ios
, 100,
803 [&]{ return ios
.stopped(); })))
809 https://github.com/vinniefalco/Beast/issues/300
811 Write a message as two individual frames
814 testWriteFrames(endpoint_type
const& ep
)
817 socket_type sock
{ios_
};
818 sock
.connect(ep
, ec
);
819 if(! BEAST_EXPECTS(! ec
, ec
.message()))
821 stream
<socket_type
&> ws
{sock
};
822 ws
.handshake("localhost", "/", ec
);
823 if(! BEAST_EXPECTS(! ec
, ec
.message()))
825 ws
.write_frame(false, sbuf("u"));
826 ws
.write_frame(true, sbuf("v"));
830 if(! BEAST_EXPECTS(! ec
, ec
.message()))
835 testAsyncWriteFrame(endpoint_type
const& ep
)
839 boost::asio::io_service ios
;
841 socket_type
sock(ios
);
842 sock
.connect(ep
, ec
);
843 if(! BEAST_EXPECTS(! ec
, ec
.message()))
845 stream
<socket_type
&> ws(sock
);
846 ws
.handshake("localhost", "/", ec
);
847 if(! BEAST_EXPECTS(! ec
, ec
.message()))
849 ws
.async_write_frame(false,
850 boost::asio::null_buffers
{},
855 ws
.next_layer().cancel(ec
);
856 if(! BEAST_EXPECTS(! ec
, ec
.message()))
859 // Destruction of the io_service will cause destruction
860 // of the write_frame_op without invoking the final handler.
868 template<class NextLayer
>
870 handshake(stream
<NextLayer
>& ws
,
871 boost::string_ref
const& uri
,
872 boost::string_ref
const& path
) const
874 ws
.handshake(uri
, path
);
877 template<class NextLayer
>
879 ping(stream
<NextLayer
>& ws
,
880 ping_data
const& payload
) const
885 template<class NextLayer
>
887 pong(stream
<NextLayer
>& ws
,
888 ping_data
const& payload
) const
893 template<class NextLayer
>
895 close(stream
<NextLayer
>& ws
,
896 close_reason
const& cr
) const
902 class NextLayer
, class DynamicBuffer
>
904 read(stream
<NextLayer
>& ws
,
905 opcode
& op
, DynamicBuffer
& dynabuf
) const
907 ws
.read(op
, dynabuf
);
911 class NextLayer
, class ConstBufferSequence
>
913 write(stream
<NextLayer
>& ws
,
914 ConstBufferSequence
const& buffers
) const
920 class NextLayer
, class ConstBufferSequence
>
922 write_frame(stream
<NextLayer
>& ws
, bool fin
,
923 ConstBufferSequence
const& buffers
) const
925 ws
.write_frame(fin
, buffers
);
929 class NextLayer
, class ConstBufferSequence
>
931 write_raw(stream
<NextLayer
>& ws
,
932 ConstBufferSequence
const& buffers
) const
935 ws
.next_layer(), buffers
);
941 yield_context
& yield_
;
945 AsyncClient(yield_context
& yield
)
950 template<class NextLayer
>
952 handshake(stream
<NextLayer
>& ws
,
953 boost::string_ref
const& uri
,
954 boost::string_ref
const& path
) const
957 ws
.async_handshake(uri
, path
, yield_
[ec
]);
959 throw system_error
{ec
};
962 template<class NextLayer
>
964 ping(stream
<NextLayer
>& ws
,
965 ping_data
const& payload
) const
968 ws
.async_ping(payload
, yield_
[ec
]);
970 throw system_error
{ec
};
973 template<class NextLayer
>
975 pong(stream
<NextLayer
>& ws
,
976 ping_data
const& payload
) const
979 ws
.async_pong(payload
, yield_
[ec
]);
981 throw system_error
{ec
};
984 template<class NextLayer
>
986 close(stream
<NextLayer
>& ws
,
987 close_reason
const& cr
) const
990 ws
.async_close(cr
, yield_
[ec
]);
992 throw system_error
{ec
};
996 class NextLayer
, class DynamicBuffer
>
998 read(stream
<NextLayer
>& ws
,
999 opcode
& op
, DynamicBuffer
& dynabuf
) const
1002 ws
.async_read(op
, dynabuf
, yield_
[ec
]);
1004 throw system_error
{ec
};
1008 class NextLayer
, class ConstBufferSequence
>
1010 write(stream
<NextLayer
>& ws
,
1011 ConstBufferSequence
const& buffers
) const
1014 ws
.async_write(buffers
, yield_
[ec
]);
1016 throw system_error
{ec
};
1020 class NextLayer
, class ConstBufferSequence
>
1022 write_frame(stream
<NextLayer
>& ws
, bool fin
,
1023 ConstBufferSequence
const& buffers
) const
1026 ws
.async_write_frame(fin
, buffers
, yield_
[ec
]);
1028 throw system_error
{ec
};
1032 class NextLayer
, class ConstBufferSequence
>
1034 write_raw(stream
<NextLayer
>& ws
,
1035 ConstBufferSequence
const& buffers
) const
1038 boost::asio::async_write(
1039 ws
.next_layer(), buffers
, yield_
[ec
]);
1041 throw system_error
{ec
};
1049 template<class Client
>
1051 testEndpoint(Client
const& c
,
1052 endpoint_type
const& ep
, permessage_deflate
const& pmd
)
1054 using boost::asio::buffer
;
1055 static std::size_t constexpr limit
= 200;
1057 for(n
= 0; n
<= limit
; ++n
)
1059 stream
<test::fail_stream
<socket_type
>> ws
{n
, ios_
};
1061 auto const restart
=
1072 catch(system_error
const& se
)
1078 ws
.lowest_layer().connect(ep
, ec
);
1079 if(! BEAST_EXPECTS(! ec
, ec
.message()))
1081 c
.handshake(ws
, "localhost", "/");
1088 ws
.lowest_layer().connect(ep
, ec
);
1089 if(! BEAST_EXPECTS(! ec
, ec
.message()))
1092 c
.handshake(ws
, "localhost", "/");
1095 ws
.set_option(auto_fragment
{false});
1096 ws
.set_option(message_type(opcode::text
));
1097 c
.write(ws
, sbuf("Hello"));
1099 // receive echoed message
1103 BEAST_EXPECT(op
== opcode::text
);
1104 BEAST_EXPECT(to_string(db
.data()) == "Hello");
1107 // close, no payload
1109 restart(error::closed
);
1112 c
.close(ws
, close_code::going_away
);
1113 restart(error::closed
);
1115 // close with code and reason string
1116 c
.close(ws
, {close_code::going_away
, "Going away"});
1117 restart(error::closed
);
1119 // send ping and message
1121 ws
.set_option(ping_callback
{
1122 [&](bool is_pong
, ping_data
const& payload
)
1124 BEAST_EXPECT(is_pong
);
1125 BEAST_EXPECT(! pong
);
1127 BEAST_EXPECT(payload
== "");
1130 ws
.set_option(message_type(opcode::binary
));
1131 c
.write(ws
, sbuf("Hello"));
1133 // receive echoed message
1137 BEAST_EXPECT(pong
== 1);
1138 BEAST_EXPECT(op
== opcode::binary
);
1139 BEAST_EXPECT(to_string(db
.data()) == "Hello");
1141 ws
.set_option(ping_callback
{});
1143 // send ping and fragmented message
1144 ws
.set_option(ping_callback
{
1145 [&](bool is_pong
, ping_data
const& payload
)
1147 BEAST_EXPECT(is_pong
);
1148 BEAST_EXPECT(payload
== "payload");
1151 c
.write_frame(ws
, false, sbuf("Hello, "));
1152 c
.write_frame(ws
, false, sbuf(""));
1153 c
.write_frame(ws
, true, sbuf("World!"));
1155 // receive echoed message
1159 BEAST_EXPECT(pong
== 1);
1160 BEAST_EXPECT(to_string(db
.data()) == "Hello, World!");
1162 ws
.set_option(ping_callback
{});
1167 // send auto fragmented message
1168 ws
.set_option(auto_fragment
{true});
1169 ws
.set_option(write_buffer_size
{8});
1170 c
.write(ws
, sbuf("Now is the time for all good men"));
1172 // receive echoed message
1176 BEAST_EXPECT(to_string(sb
.data()) == "Now is the time for all good men");
1178 ws
.set_option(auto_fragment
{false});
1179 ws
.set_option(write_buffer_size
{4096});
1181 // send message with write buffer limit
1183 std::string
s(2000, '*');
1184 ws
.set_option(write_buffer_size(1200));
1185 c
.write(ws
, buffer(s
.data(), s
.size()));
1187 // receive echoed message
1191 BEAST_EXPECT(to_string(db
.data()) == s
);
1196 ws
.set_option(message_type(opcode::binary
));
1197 c
.write(ws
, sbuf("PING"));
1198 ws
.set_option(message_type(opcode::text
));
1199 c
.write(ws
, sbuf("Hello"));
1201 // receive echoed message
1205 BEAST_EXPECT(op
== opcode::text
);
1206 BEAST_EXPECT(to_string(db
.data()) == "Hello");
1210 ws
.set_option(message_type(opcode::binary
));
1211 c
.write(ws
, sbuf("CLOSE"));
1212 restart(error::closed
);
1215 ws
.set_option(message_type(opcode::binary
));
1216 c
.write(ws
, buffer_cat(sbuf("TEXT"),
1217 cbuf(0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc)));
1218 restart(error::failed
);
1221 ws
.set_option(message_type(opcode::binary
));
1222 c
.write(ws
, buffer_cat(sbuf("TEXT"),
1223 cbuf(0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc)));
1224 c
.write(ws
, sbuf("Hello"));
1225 restart(error::failed
);
1228 ws
.set_option(message_type(opcode::binary
));
1229 c
.write(ws
, buffer_cat(sbuf("RAW"),
1230 cbuf(0x88, 0x02, 0x03, 0xed)));
1231 restart(error::failed
);
1235 cbuf(0x80, 0x80, 0xff, 0xff, 0xff, 0xff));
1236 restart(error::closed
);
1238 // invalid fixed frame header
1240 cbuf(0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
1241 restart(error::closed
);
1243 // cause non-canonical extended size
1244 c
.write(ws
, buffer_cat(sbuf("RAW"),
1245 cbuf(0x82, 0x7e, 0x00, 0x01, 0x00)));
1246 restart(error::failed
);
1248 if(! pmd
.client_enable
)
1251 c
.write_frame(ws
, false, boost::asio::null_buffers
{});
1253 cbuf(0x81, 0x80, 0xff, 0xff, 0xff, 0xff));
1254 restart(error::closed
);
1256 // message size above 2^64
1257 c
.write_frame(ws
, false, cbuf(0x00));
1259 cbuf(0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
1260 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
1261 restart(error::closed
);
1263 // message size exceeds max
1264 ws
.set_option(read_message_max
{1});
1265 c
.write(ws
, cbuf(0x00, 0x00));
1266 restart(error::failed
);
1267 ws
.set_option(read_message_max
{16*1024*1024});
1270 catch(system_error
const&)
1276 BEAST_EXPECT(n
< limit
);
1281 static_assert(std::is_constructible
<
1282 stream
<socket_type
>, boost::asio::io_service
&>::value
, "");
1284 static_assert(std::is_move_constructible
<
1285 stream
<socket_type
>>::value
, "");
1287 static_assert(std::is_move_assignable
<
1288 stream
<socket_type
>>::value
, "");
1290 static_assert(std::is_constructible
<
1291 stream
<socket_type
&>, socket_type
&>::value
, "");
1293 static_assert(std::is_move_constructible
<
1294 stream
<socket_type
&>>::value
, "");
1296 static_assert(! std::is_move_assignable
<
1297 stream
<socket_type
&>>::value
, "");
1299 log
<< "sizeof(websocket::stream) == " <<
1300 sizeof(websocket::stream
<boost::asio::ip::tcp::socket
&>) << std::endl
;
1302 auto const any
= endpoint_type
{
1303 address_type::from_string("127.0.0.1"), 0};
1307 testBadHandshakes();
1310 permessage_deflate pmd
;
1311 pmd
.client_enable
= false;
1312 pmd
.server_enable
= false;
1316 ::websocket::sync_echo_server server
{nullptr};
1317 server
.set_option(pmd
);
1318 server
.open(any
, ec
);
1319 BEAST_EXPECTS(! ec
, ec
.message());
1320 auto const ep
= server
.local_endpoint();
1322 //testInvokable1(ep);
1326 //testInvokable5(ep);
1327 testWriteFrames(ep
);
1328 testAsyncWriteFrame(ep
);
1333 ::websocket::async_echo_server server
{nullptr, 4};
1334 server
.open(any
, ec
);
1335 BEAST_EXPECTS(! ec
, ec
.message());
1336 auto const ep
= server
.local_endpoint();
1337 testAsyncWriteFrame(ep
);
1340 auto const doClientTests
=
1341 [this, any
](permessage_deflate
const& pmd
)
1345 ::websocket::sync_echo_server server
{nullptr};
1346 server
.set_option(pmd
);
1347 server
.open(any
, ec
);
1348 BEAST_EXPECTS(! ec
, ec
.message());
1349 auto const ep
= server
.local_endpoint();
1350 testEndpoint(SyncClient
{}, ep
, pmd
);
1352 [&](yield_context yield
)
1355 AsyncClient
{yield
}, ep
, pmd
);
1360 ::websocket::async_echo_server server
{nullptr, 4};
1361 server
.set_option(pmd
);
1362 server
.open(any
, ec
);
1363 BEAST_EXPECTS(! ec
, ec
.message());
1364 auto const ep
= server
.local_endpoint();
1365 testEndpoint(SyncClient
{}, ep
, pmd
);
1367 [&](yield_context yield
)
1370 AsyncClient
{yield
}, ep
, pmd
);
1375 pmd
.client_enable
= false;
1376 pmd
.server_enable
= false;
1379 pmd
.client_enable
= true;
1380 pmd
.server_enable
= true;
1381 pmd
.client_max_window_bits
= 10;
1382 pmd
.client_no_context_takeover
= false;
1385 pmd
.client_enable
= true;
1386 pmd
.server_enable
= true;
1387 pmd
.client_max_window_bits
= 10;
1388 pmd
.client_no_context_takeover
= true;
1393 BEAST_DEFINE_TESTSUITE(stream
,websocket
,beast
);