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