]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/websocket/ping.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / ping.cpp
CommitLineData
b32b8144 1//
92f5a8d4 2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
b32b8144
FG
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
92f5a8d4
TL
13#include <boost/beast/_experimental/test/tcp.hpp>
14
b32b8144
FG
15#include "test.hpp"
16
92f5a8d4
TL
17#include <boost/asio/ip/tcp.hpp>
18#include <boost/asio/io_context.hpp>
11fdf7f2
TL
19#include <boost/asio/strand.hpp>
20
20effc67
TL
21#if BOOST_ASIO_HAS_CO_AWAIT
22#include <boost/asio/use_awaitable.hpp>
23#endif
24
b32b8144
FG
25namespace boost {
26namespace beast {
27namespace websocket {
28
29class ping_test : public websocket_test_suite
30{
31public:
32 template<class Wrap>
33 void
34 doTestPing(Wrap const& w)
35 {
36 permessage_deflate pmd;
37 pmd.client_enable = false;
38 pmd.server_enable = false;
39
40 // ping
41 doTest(pmd, [&](ws_type& ws)
42 {
43 w.ping(ws, {});
44 });
45
46 // pong
47 doTest(pmd, [&](ws_type& ws)
48 {
49 w.pong(ws, {});
50 });
51
52 // ping, already closed
53 {
54 echo_server es{log};
55 stream<test::stream> ws{ioc_};
56 ws.next_layer().connect(es.stream());
57 ws.handshake("localhost", "/");
58 ws.close({});
59 try
60 {
61 w.ping(ws, {});
62 fail("", __FILE__, __LINE__);
63 }
64 catch(system_error const& se)
65 {
66 BEAST_EXPECTS(
92f5a8d4 67 se.code() == net::error::operation_aborted,
b32b8144
FG
68 se.code().message());
69 }
70 }
71
72 // pong, already closed
73 {
74 echo_server es{log};
75 stream<test::stream> ws{ioc_};
76 ws.next_layer().connect(es.stream());
77 ws.handshake("localhost", "/");
78 ws.close({});
79 try
80 {
81 w.pong(ws, {});
82 fail("", __FILE__, __LINE__);
83 }
84 catch(system_error const& se)
85 {
86 BEAST_EXPECTS(
92f5a8d4 87 se.code() == net::error::operation_aborted,
b32b8144
FG
88 se.code().message());
89 }
90 }
91 }
92
93 void
94 testPing()
95 {
96 doTestPing(SyncClient{});
97
98 yield_to([&](yield_context yield)
99 {
100 doTestPing(AsyncClient{yield});
101 });
102 }
103
104 void
105 testSuspend()
106 {
107 // suspend on write
92f5a8d4 108 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
109 {
110 echo_server es{log};
92f5a8d4 111 net::io_context ioc;
b32b8144
FG
112 stream<test::stream> ws{ioc, fc};
113 ws.next_layer().connect(es.stream());
114 ws.handshake("localhost", "/");
115 std::size_t count = 0;
116 ws.async_write(sbuf("Hello, world"),
117 [&](error_code ec, std::size_t n)
118 {
119 ++count;
120 if(ec)
121 BOOST_THROW_EXCEPTION(
122 system_error{ec});
123 BEAST_EXPECT(n == 12);
124 });
92f5a8d4 125 BEAST_EXPECT(ws.impl_->wr_block.is_locked());
b32b8144
FG
126 BEAST_EXPECT(count == 0);
127 ws.async_ping({},
128 [&](error_code ec)
129 {
130 ++count;
131 if(ec)
132 BOOST_THROW_EXCEPTION(
133 system_error{ec});
134 });
135 BEAST_EXPECT(count == 0);
136 ioc.run();
137 BEAST_EXPECT(count == 2);
138 });
139
140 // suspend on close
92f5a8d4 141 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
142 {
143 echo_server es{log};
92f5a8d4 144 net::io_context ioc;
b32b8144
FG
145 stream<test::stream> ws{ioc, fc};
146 ws.next_layer().connect(es.stream());
147 ws.handshake("localhost", "/");
148 std::size_t count = 0;
149 ws.async_close({},
150 [&](error_code ec)
151 {
152 ++count;
153 if(ec)
154 BOOST_THROW_EXCEPTION(
155 system_error{ec});
156 });
92f5a8d4 157 BEAST_EXPECT(ws.impl_->wr_block.is_locked());
b32b8144
FG
158 BEAST_EXPECT(count == 0);
159 ws.async_ping({},
160 [&](error_code ec)
161 {
162 ++count;
92f5a8d4 163 if(ec != net::error::operation_aborted)
b32b8144
FG
164 BOOST_THROW_EXCEPTION(
165 system_error{ec});
166 });
167 BEAST_EXPECT(count == 0);
168 ioc.run();
169 BEAST_EXPECT(count == 2);
170 });
171
172 // suspend on read ping + message
92f5a8d4 173 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
174 {
175 echo_server es{log};
92f5a8d4 176 net::io_context ioc;
b32b8144
FG
177 stream<test::stream> ws{ioc, fc};
178 ws.next_layer().connect(es.stream());
179 ws.handshake("localhost", "/");
180 // add a ping and message to the input
181 ws.next_layer().append(string_view{
182 "\x89\x00" "\x81\x01*", 5});
183 std::size_t count = 0;
184 multi_buffer b;
185 ws.async_read(b,
186 [&](error_code ec, std::size_t)
187 {
188 ++count;
189 if(ec)
190 BOOST_THROW_EXCEPTION(
191 system_error{ec});
192 });
92f5a8d4 193 while(! ws.impl_->wr_block.is_locked())
b32b8144
FG
194 {
195 ioc.run_one();
196 if(! BEAST_EXPECT(! ioc.stopped()))
197 break;
198 }
199 BEAST_EXPECT(count == 0);
200 ws.async_ping({},
201 [&](error_code ec)
202 {
203 ++count;
204 if(ec)
205 BOOST_THROW_EXCEPTION(
206 system_error{ec});
207 });
208 BEAST_EXPECT(count == 0);
209 ioc.run();
210 BEAST_EXPECT(count == 2);
211 });
212
213 // suspend on read bad message
92f5a8d4 214 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
215 {
216 echo_server es{log};
92f5a8d4 217 net::io_context ioc;
b32b8144
FG
218 stream<test::stream> ws{ioc, fc};
219 ws.next_layer().connect(es.stream());
220 ws.handshake("localhost", "/");
221 // add an invalid frame to the input
222 ws.next_layer().append(string_view{
223 "\x09\x00", 2});
224
225 std::size_t count = 0;
226 multi_buffer b;
227 ws.async_read(b,
228 [&](error_code ec, std::size_t)
229 {
230 ++count;
11fdf7f2 231 if(ec != error::bad_control_fragment)
b32b8144
FG
232 BOOST_THROW_EXCEPTION(
233 system_error{ec});
234 });
92f5a8d4 235 while(! ws.impl_->wr_block.is_locked())
b32b8144
FG
236 {
237 ioc.run_one();
238 if(! BEAST_EXPECT(! ioc.stopped()))
239 break;
240 }
241 BEAST_EXPECT(count == 0);
242 ws.async_ping({},
243 [&](error_code ec)
244 {
245 ++count;
92f5a8d4 246 if(ec != net::error::operation_aborted)
b32b8144
FG
247 BOOST_THROW_EXCEPTION(
248 system_error{ec});
249 });
250 BEAST_EXPECT(count == 0);
251 ioc.run();
252 BEAST_EXPECT(count == 2);
253 });
254
255 // suspend on read close #1
92f5a8d4 256 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
257 {
258 echo_server es{log};
92f5a8d4 259 net::io_context ioc;
b32b8144
FG
260 stream<test::stream> ws{ioc, fc};
261 ws.next_layer().connect(es.stream());
262 ws.handshake("localhost", "/");
263 // add a close frame to the input
264 ws.next_layer().append(string_view{
265 "\x88\x00", 2});
266 std::size_t count = 0;
267 multi_buffer b;
268 ws.async_read(b,
269 [&](error_code ec, std::size_t)
270 {
271 ++count;
272 if(ec != error::closed)
273 BOOST_THROW_EXCEPTION(
274 system_error{ec});
275 });
92f5a8d4 276 while(! ws.impl_->wr_block.is_locked())
b32b8144
FG
277 {
278 ioc.run_one();
279 if(! BEAST_EXPECT(! ioc.stopped()))
280 break;
281 }
282 BEAST_EXPECT(count == 0);
283 ws.async_ping({},
284 [&](error_code ec)
285 {
286 ++count;
92f5a8d4 287 if(ec != net::error::operation_aborted)
b32b8144
FG
288 BOOST_THROW_EXCEPTION(
289 system_error{ec});
290 });
291 BEAST_EXPECT(count == 0);
292 ioc.run();
293 BEAST_EXPECT(count == 2);
294 });
295
296 // suspend on read close #2
92f5a8d4 297 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
298 {
299 echo_server es{log, kind::async};
92f5a8d4 300 net::io_context ioc;
b32b8144
FG
301 stream<test::stream> ws{ioc, fc};
302 ws.next_layer().connect(es.stream());
303 ws.handshake("localhost", "/");
304 // Cause close to be received
305 es.async_close();
306 std::size_t count = 0;
307 multi_buffer b;
308 ws.async_read(b,
309 [&](error_code ec, std::size_t)
310 {
311 ++count;
312 if(ec != error::closed)
313 BOOST_THROW_EXCEPTION(
314 system_error{ec});
315 });
92f5a8d4 316 while(! ws.impl_->wr_block.is_locked())
b32b8144
FG
317 {
318 ioc.run_one();
319 if(! BEAST_EXPECT(! ioc.stopped()))
320 break;
321 }
322 BEAST_EXPECT(count == 0);
323 ws.async_ping({},
324 [&](error_code ec)
325 {
326 ++count;
92f5a8d4 327 if(ec != net::error::operation_aborted)
b32b8144
FG
328 BOOST_THROW_EXCEPTION(
329 system_error{ec});
330 });
331 BEAST_EXPECT(count == 0);
332 ioc.run();
333 BEAST_EXPECT(count == 2);
334 });
335
336 // don't ping on close
92f5a8d4 337 doFailLoop([&](test::fail_count& fc)
b32b8144
FG
338 {
339 echo_server es{log};
340 error_code ec;
92f5a8d4 341 net::io_context ioc;
b32b8144
FG
342 stream<test::stream> ws{ioc, fc};
343 ws.next_layer().connect(es.stream());
344 ws.handshake("localhost", "/");
345 std::size_t count = 0;
346 ws.async_write(sbuf("*"),
347 [&](error_code ec, std::size_t n)
348 {
349 ++count;
350 if(ec)
351 BOOST_THROW_EXCEPTION(
352 system_error{ec});
353 BEAST_EXPECT(n == 1);
354 });
92f5a8d4 355 BEAST_EXPECT(ws.impl_->wr_block.is_locked());
b32b8144
FG
356 ws.async_ping("",
357 [&](error_code ec)
358 {
359 ++count;
92f5a8d4 360 if(ec != net::error::operation_aborted)
b32b8144
FG
361 BOOST_THROW_EXCEPTION(
362 system_error{ec});
363 });
364 ws.async_close({},
365 [&](error_code)
366 {
367 ++count;
368 if(ec)
369 BOOST_THROW_EXCEPTION(
370 system_error{ec});
371 });
372 ioc.run();
373 BEAST_EXPECT(count == 3);
374 });
375
92f5a8d4
TL
376 // suspend idle ping
377 {
378 using socket_type =
379 net::basic_stream_socket<
380 net::ip::tcp,
20effc67 381 net::any_io_executor>;
92f5a8d4
TL
382 net::io_context ioc;
383 stream<socket_type> ws1(ioc);
384 stream<socket_type> ws2(ioc);
385 ws1.set_option(stream_base::timeout{
386 stream_base::none(),
387 std::chrono::seconds(0),
388 true});
389 test::connect(
390 ws1.next_layer(),
391 ws2.next_layer());
392 ws1.async_handshake("localhost", "/",
393 [](error_code){});
394 ws2.async_accept([](error_code){});
395 ioc.run();
396 ioc.restart();
397 flat_buffer b1;
398 auto mb = b1.prepare(65536);
399 std::memset(mb.data(), 0, mb.size());
400 b1.commit(65536);
401 ws1.async_write(b1.data(),
402 [&](error_code, std::size_t){});
403 BEAST_EXPECT(
404 ws1.impl_->wr_block.is_locked());
405 ws1.async_read_some(net::mutable_buffer{},
406 [&](error_code, std::size_t){});
407 ioc.run();
408 ioc.restart();
409 flat_buffer b2;
410 ws2.async_read(b2,
411 [&](error_code, std::size_t){});
412 ioc.run();
413 }
414 //);
415
b32b8144
FG
416 {
417 echo_server es{log, kind::async};
92f5a8d4 418 net::io_context ioc;
b32b8144
FG
419 stream<test::stream> ws{ioc};
420 ws.next_layer().connect(es.stream());
421 ws.handshake("localhost", "/");
422
423 // Cause close to be received
424 es.async_close();
425
426 multi_buffer b;
427 std::size_t count = 0;
428 // Read a close frame.
429 // Sends a close frame, blocking writes.
430 ws.async_read(b,
431 [&](error_code ec, std::size_t)
432 {
433 // Read should complete with error::closed
434 ++count;
435 BEAST_EXPECTS(ec == error::closed,
436 ec.message());
b32b8144
FG
437 });
438 if(! BEAST_EXPECT(run_until(ioc, 100,
92f5a8d4 439 [&]{ return ws.impl_->wr_close; })))
b32b8144
FG
440 return;
441 // Try to ping
442 ws.async_ping("payload",
443 [&](error_code ec)
444 {
445 // Pings after a close are aborted
446 ++count;
92f5a8d4 447 BEAST_EXPECTS(ec == net::
b32b8144
FG
448 error::operation_aborted,
449 ec.message());
450 // Subsequent calls to close are aborted
451 ws.async_close({},
452 [&](error_code ec)
453 {
454 ++count;
92f5a8d4 455 BEAST_EXPECTS(ec == net::
b32b8144
FG
456 error::operation_aborted,
457 ec.message());
458 });
459 });
460 static std::size_t constexpr limit = 100;
461 std::size_t n;
462 for(n = 0; n < limit; ++n)
463 {
11fdf7f2 464 if(count >= 3)
b32b8144
FG
465 break;
466 ioc.run_one();
467 }
468 BEAST_EXPECT(n < limit);
469 ioc.run();
470 }
471 }
472
11fdf7f2
TL
473 void
474 testMoveOnly()
475 {
92f5a8d4 476 net::io_context ioc;
11fdf7f2
TL
477 stream<test::stream> ws{ioc};
478 ws.async_ping({}, move_only_handler{});
479 }
480
481 struct copyable_handler
482 {
483 template<class... Args>
484 void
485 operator()(Args&&...) const
486 {
487 }
488 };
489
20effc67
TL
490#if BOOST_ASIO_HAS_CO_AWAIT
491 void testAwaitableCompiles(
492 stream<test::stream>& s,
493 ping_data& pdat)
494 {
495 static_assert(std::is_same_v<
496 net::awaitable<void>, decltype(
497 s.async_ping(pdat, net::use_awaitable))>);
498
499 static_assert(std::is_same_v<
500 net::awaitable<void>, decltype(
501 s.async_pong(pdat, net::use_awaitable))>);
502 }
503#endif
504
b32b8144
FG
505 void
506 run() override
507 {
508 testPing();
509 testSuspend();
11fdf7f2 510 testMoveOnly();
20effc67
TL
511#if BOOST_ASIO_HAS_CO_AWAIT
512 boost::ignore_unused(&ping_test::testAwaitableCompiles);
513#endif
b32b8144
FG
514 }
515};
516
517BEAST_DEFINE_TESTSUITE(beast,websocket,ping);
518
519} // websocket
520} // beast
521} // boost