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