2 // Copyright (w) 2016-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)
7 // Official repository: https://github.com/boostorg/beast
10 // Test that header file is self-contained.
11 #include <boost/beast/websocket/stream.hpp>
19 class ping_test
: public websocket_test_suite
24 doTestPing(Wrap
const& w
)
26 permessage_deflate pmd
;
27 pmd
.client_enable
= false;
28 pmd
.server_enable
= false;
31 doTest(pmd
, [&](ws_type
& ws
)
37 doTest(pmd
, [&](ws_type
& ws
)
42 // ping, already closed
45 stream
<test::stream
> ws
{ioc_
};
46 ws
.next_layer().connect(es
.stream());
47 ws
.handshake("localhost", "/");
52 fail("", __FILE__
, __LINE__
);
54 catch(system_error
const& se
)
57 se
.code() == boost::asio::error::operation_aborted
,
62 // pong, already closed
65 stream
<test::stream
> ws
{ioc_
};
66 ws
.next_layer().connect(es
.stream());
67 ws
.handshake("localhost", "/");
72 fail("", __FILE__
, __LINE__
);
74 catch(system_error
const& se
)
77 se
.code() == boost::asio::error::operation_aborted
,
86 doTestPing(SyncClient
{});
88 yield_to([&](yield_context yield
)
90 doTestPing(AsyncClient
{yield
});
98 doFailLoop([&](test::fail_counter
& fc
)
101 boost::asio::io_context ioc
;
102 stream
<test::stream
> ws
{ioc
, fc
};
103 ws
.next_layer().connect(es
.stream());
104 ws
.handshake("localhost", "/");
105 std::size_t count
= 0;
106 ws
.async_write(sbuf("Hello, world"),
107 [&](error_code ec
, std::size_t n
)
111 BOOST_THROW_EXCEPTION(
113 BEAST_EXPECT(n
== 12);
115 BEAST_EXPECT(ws
.wr_block_
);
116 BEAST_EXPECT(count
== 0);
122 BOOST_THROW_EXCEPTION(
125 BEAST_EXPECT(count
== 0);
127 BEAST_EXPECT(count
== 2);
131 doFailLoop([&](test::fail_counter
& fc
)
134 boost::asio::io_context ioc
;
135 stream
<test::stream
> ws
{ioc
, fc
};
136 ws
.next_layer().connect(es
.stream());
137 ws
.handshake("localhost", "/");
138 std::size_t count
= 0;
144 BOOST_THROW_EXCEPTION(
147 BEAST_EXPECT(ws
.wr_block_
);
148 BEAST_EXPECT(count
== 0);
153 if(ec
!= boost::asio::error::operation_aborted
)
154 BOOST_THROW_EXCEPTION(
157 BEAST_EXPECT(count
== 0);
159 BEAST_EXPECT(count
== 2);
162 // suspend on read ping + message
163 doFailLoop([&](test::fail_counter
& fc
)
166 boost::asio::io_context ioc
;
167 stream
<test::stream
> ws
{ioc
, fc
};
168 ws
.next_layer().connect(es
.stream());
169 ws
.handshake("localhost", "/");
170 // add a ping and message to the input
171 ws
.next_layer().append(string_view
{
172 "\x89\x00" "\x81\x01*", 5});
173 std::size_t count
= 0;
176 [&](error_code ec
, std::size_t)
180 BOOST_THROW_EXCEPTION(
183 while(! ws
.wr_block_
)
186 if(! BEAST_EXPECT(! ioc
.stopped()))
189 BEAST_EXPECT(count
== 0);
195 BOOST_THROW_EXCEPTION(
198 BEAST_EXPECT(count
== 0);
200 BEAST_EXPECT(count
== 2);
203 // suspend on read bad message
204 doFailLoop([&](test::fail_counter
& fc
)
207 boost::asio::io_context ioc
;
208 stream
<test::stream
> ws
{ioc
, fc
};
209 ws
.next_layer().connect(es
.stream());
210 ws
.handshake("localhost", "/");
211 // add an invalid frame to the input
212 ws
.next_layer().append(string_view
{
215 std::size_t count
= 0;
218 [&](error_code ec
, std::size_t)
221 if(ec
!= error::failed
)
222 BOOST_THROW_EXCEPTION(
225 while(! ws
.wr_block_
)
228 if(! BEAST_EXPECT(! ioc
.stopped()))
231 BEAST_EXPECT(count
== 0);
236 if(ec
!= boost::asio::error::operation_aborted
)
237 BOOST_THROW_EXCEPTION(
240 BEAST_EXPECT(count
== 0);
242 BEAST_EXPECT(count
== 2);
245 // suspend on read close #1
246 doFailLoop([&](test::fail_counter
& fc
)
249 boost::asio::io_context ioc
;
250 stream
<test::stream
> ws
{ioc
, fc
};
251 ws
.next_layer().connect(es
.stream());
252 ws
.handshake("localhost", "/");
253 // add a close frame to the input
254 ws
.next_layer().append(string_view
{
256 std::size_t count
= 0;
259 [&](error_code ec
, std::size_t)
262 if(ec
!= error::closed
)
263 BOOST_THROW_EXCEPTION(
266 while(! ws
.wr_block_
)
269 if(! BEAST_EXPECT(! ioc
.stopped()))
272 BEAST_EXPECT(count
== 0);
277 if(ec
!= boost::asio::error::operation_aborted
)
278 BOOST_THROW_EXCEPTION(
281 BEAST_EXPECT(count
== 0);
283 BEAST_EXPECT(count
== 2);
286 // suspend on read close #2
287 doFailLoop([&](test::fail_counter
& fc
)
289 echo_server es
{log
, kind::async
};
290 boost::asio::io_context ioc
;
291 stream
<test::stream
> ws
{ioc
, fc
};
292 ws
.next_layer().connect(es
.stream());
293 ws
.handshake("localhost", "/");
294 // Cause close to be received
296 std::size_t count
= 0;
299 [&](error_code ec
, std::size_t)
302 if(ec
!= error::closed
)
303 BOOST_THROW_EXCEPTION(
306 while(! ws
.wr_block_
)
309 if(! BEAST_EXPECT(! ioc
.stopped()))
312 BEAST_EXPECT(count
== 0);
317 if(ec
!= boost::asio::error::operation_aborted
)
318 BOOST_THROW_EXCEPTION(
321 BEAST_EXPECT(count
== 0);
323 BEAST_EXPECT(count
== 2);
326 // don't ping on close
327 doFailLoop([&](test::fail_counter
& fc
)
331 boost::asio::io_context ioc
;
332 stream
<test::stream
> ws
{ioc
, fc
};
333 ws
.next_layer().connect(es
.stream());
334 ws
.handshake("localhost", "/");
335 std::size_t count
= 0;
336 ws
.async_write(sbuf("*"),
337 [&](error_code ec
, std::size_t n
)
341 BOOST_THROW_EXCEPTION(
343 BEAST_EXPECT(n
== 1);
345 BEAST_EXPECT(ws
.wr_block_
);
350 if(ec
!= boost::asio::error::operation_aborted
)
351 BOOST_THROW_EXCEPTION(
359 BOOST_THROW_EXCEPTION(
363 BEAST_EXPECT(count
== 3);
367 echo_server es
{log
, kind::async
};
368 boost::asio::io_context ioc
;
369 stream
<test::stream
> ws
{ioc
};
370 ws
.next_layer().connect(es
.stream());
371 ws
.handshake("localhost", "/");
373 // Cause close to be received
377 std::size_t count
= 0;
378 // Read a close frame.
379 // Sends a close frame, blocking writes.
381 [&](error_code ec
, std::size_t)
383 // Read should complete with error::closed
385 BEAST_EXPECTS(ec
== error::closed
,
387 // Pings after a close are aborted
392 BEAST_EXPECTS(ec
== boost::asio::
393 error::operation_aborted
,
397 if(! BEAST_EXPECT(run_until(ioc
, 100,
398 [&]{ return ws
.wr_close_
; })))
401 ws
.async_ping("payload",
404 // Pings after a close are aborted
406 BEAST_EXPECTS(ec
== boost::asio::
407 error::operation_aborted
,
409 // Subsequent calls to close are aborted
414 BEAST_EXPECTS(ec
== boost::asio::
415 error::operation_aborted
,
419 static std::size_t constexpr limit
= 100;
421 for(n
= 0; n
< limit
; ++n
)
427 BEAST_EXPECT(n
< limit
);
437 void operator()(error_code
) {}
440 stream
<test::stream
> ws
{ioc_
};
441 stream
<test::stream
>::ping_op
<handler
> op
{
442 handler
{}, ws
, detail::opcode::ping
, {}};
443 using boost::asio::asio_handler_is_continuation
;
444 asio_handler_is_continuation(&op
);
456 BEAST_DEFINE_TESTSUITE(beast
,websocket
,ping
);