]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/websocket/close.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / close.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 namespace boost {
16 namespace beast {
17 namespace websocket {
18
19 class close_test : public websocket_test_suite
20 {
21 public:
22 template<class Wrap>
23 void
24 doTestClose(Wrap const& w)
25 {
26 permessage_deflate pmd;
27 pmd.client_enable = false;
28 pmd.server_enable = false;
29
30 // close
31 doTest(pmd, [&](ws_type& ws)
32 {
33 w.close(ws, {});
34 });
35
36 // close with code
37 doTest(pmd, [&](ws_type& ws)
38 {
39 w.close(ws, close_code::going_away);
40 });
41
42 // close with code and reason
43 doTest(pmd, [&](ws_type& ws)
44 {
45 w.close(ws, {
46 close_code::going_away,
47 "going away"});
48 });
49
50 // already closed
51 {
52 echo_server es{log};
53 stream<test::stream> ws{ioc_};
54 ws.next_layer().connect(es.stream());
55 w.handshake(ws, "localhost", "/");
56 w.close(ws, {});
57 try
58 {
59 w.close(ws, {});
60 fail("", __FILE__, __LINE__);
61 }
62 catch(system_error const& se)
63 {
64 BEAST_EXPECTS(
65 se.code() == boost::asio::error::operation_aborted,
66 se.code().message());
67 }
68 }
69
70 // drain a message after close
71 doTest(pmd, [&](ws_type& ws)
72 {
73 ws.next_layer().append("\x81\x01\x2a");
74 w.close(ws, {});
75 });
76
77 // drain a big message after close
78 {
79 std::string s;
80 s = "\x81\x7e\x10\x01";
81 s.append(4097, '*');
82 doTest(pmd, [&](ws_type& ws)
83 {
84 ws.next_layer().append(s);
85 w.close(ws, {});
86 });
87 }
88
89 // drain a ping after close
90 doTest(pmd, [&](ws_type& ws)
91 {
92 ws.next_layer().append("\x89\x01*");
93 w.close(ws, {});
94 });
95
96 // drain invalid message frame after close
97 {
98 echo_server es{log};
99 stream<test::stream> ws{ioc_};
100 ws.next_layer().connect(es.stream());
101 w.handshake(ws, "localhost", "/");
102 ws.next_layer().append("\x81\x81\xff\xff\xff\xff*");
103 try
104 {
105 w.close(ws, {});
106 fail("", __FILE__, __LINE__);
107 }
108 catch(system_error const& se)
109 {
110 BEAST_EXPECTS(
111 se.code() == error::failed,
112 se.code().message());
113 }
114 }
115
116 // drain invalid close frame after close
117 {
118 echo_server es{log};
119 stream<test::stream> ws{ioc_};
120 ws.next_layer().connect(es.stream());
121 w.handshake(ws, "localhost", "/");
122 ws.next_layer().append("\x88\x01*");
123 try
124 {
125 w.close(ws, {});
126 fail("", __FILE__, __LINE__);
127 }
128 catch(system_error const& se)
129 {
130 BEAST_EXPECTS(
131 se.code() == error::failed,
132 se.code().message());
133 }
134 }
135
136 // drain masked close frame
137 {
138 echo_server es{log, kind::async_client};
139 stream<test::stream> ws{ioc_};
140 ws.next_layer().connect(es.stream());
141 ws.set_option(pmd);
142 es.async_handshake();
143 ws.accept();
144 w.close(ws, {});
145 }
146
147 // close with incomplete read message
148 doTest(pmd, [&](ws_type& ws)
149 {
150 ws.next_layer().append("\x81\x02**");
151 static_buffer<1> b;
152 w.read_some(ws, 1, b);
153 w.close(ws, {});
154 });
155 }
156
157 void
158 testClose()
159 {
160 doTestClose(SyncClient{});
161
162 yield_to([&](yield_context yield)
163 {
164 doTestClose(AsyncClient{yield});
165 });
166 }
167
168 void
169 testSuspend()
170 {
171 using boost::asio::buffer;
172
173 // suspend on ping
174 doFailLoop([&](test::fail_counter& fc)
175 {
176 echo_server es{log};
177 boost::asio::io_context ioc;
178 stream<test::stream> ws{ioc, fc};
179 ws.next_layer().connect(es.stream());
180 ws.handshake("localhost", "/");
181 std::size_t count = 0;
182 ws.async_ping("",
183 [&](error_code ec)
184 {
185 ++count;
186 if(ec)
187 BOOST_THROW_EXCEPTION(
188 system_error{ec});
189 });
190 BEAST_EXPECT(ws.wr_block_);
191 BEAST_EXPECT(count == 0);
192 ws.async_close({},
193 [&](error_code ec)
194 {
195 ++count;
196 if(ec)
197 BOOST_THROW_EXCEPTION(
198 system_error{ec});
199 });
200 BEAST_EXPECT(count == 0);
201 ioc.run();
202 BEAST_EXPECT(count == 2);
203 });
204
205 // suspend on write
206 doFailLoop([&](test::fail_counter& fc)
207 {
208 echo_server es{log};
209 boost::asio::io_context ioc;
210 stream<test::stream> ws{ioc, fc};
211 ws.next_layer().connect(es.stream());
212 ws.handshake("localhost", "/");
213 std::size_t count = 0;
214 ws.async_write(sbuf("*"),
215 [&](error_code ec, std::size_t n)
216 {
217 ++count;
218 if(ec)
219 BOOST_THROW_EXCEPTION(
220 system_error{ec});
221 BEAST_EXPECT(n == 1);
222 });
223 BEAST_EXPECT(ws.wr_block_);
224 BEAST_EXPECT(count == 0);
225 ws.async_close({},
226 [&](error_code ec)
227 {
228 ++count;
229 if(ec)
230 BOOST_THROW_EXCEPTION(
231 system_error{ec});
232 });
233 BEAST_EXPECT(count == 0);
234 ioc.run();
235 BEAST_EXPECT(count == 2);
236 });
237
238 // suspend on read ping + message
239 doFailLoop([&](test::fail_counter& fc)
240 {
241 echo_server es{log};
242 boost::asio::io_context ioc;
243 stream<test::stream> ws{ioc, fc};
244 ws.next_layer().connect(es.stream());
245 ws.handshake("localhost", "/");
246 // add a ping and message to the input
247 ws.next_layer().append(string_view{
248 "\x89\x00" "\x81\x01*", 5});
249 std::size_t count = 0;
250 multi_buffer b;
251 ws.async_read(b,
252 [&](error_code ec, std::size_t)
253 {
254 ++count;
255 if(ec)
256 BOOST_THROW_EXCEPTION(
257 system_error{ec});
258 });
259 while(! ws.wr_block_)
260 {
261 ioc.run_one();
262 if(! BEAST_EXPECT(! ioc.stopped()))
263 break;
264 }
265 BEAST_EXPECT(count == 0);
266 ws.async_close({},
267 [&](error_code ec)
268 {
269 ++count;
270 if(ec)
271 BOOST_THROW_EXCEPTION(
272 system_error{ec});
273 });
274 BEAST_EXPECT(count == 0);
275 ioc.run();
276 BEAST_EXPECT(count == 2);
277 });
278
279 // suspend on read bad message
280 doFailLoop([&](test::fail_counter& fc)
281 {
282 echo_server es{log};
283 boost::asio::io_context ioc;
284 stream<test::stream> ws{ioc, fc};
285 ws.next_layer().connect(es.stream());
286 ws.handshake("localhost", "/");
287 // add an invalid frame to the input
288 ws.next_layer().append(string_view{
289 "\x09\x00", 2});
290 std::size_t count = 0;
291 multi_buffer b;
292 ws.async_read(b,
293 [&](error_code ec, std::size_t)
294 {
295 if(ec != error::failed)
296 BOOST_THROW_EXCEPTION(
297 system_error{ec});
298 BEAST_EXPECT(++count == 1);
299 });
300 while(! ws.wr_block_)
301 {
302 ioc.run_one();
303 if(! BEAST_EXPECT(! ioc.stopped()))
304 break;
305 }
306 BEAST_EXPECT(count == 0);
307 ws.async_close({},
308 [&](error_code ec)
309 {
310 if(ec != boost::asio::error::operation_aborted)
311 BOOST_THROW_EXCEPTION(
312 system_error{ec});
313 BEAST_EXPECT(++count == 2);
314 });
315 BEAST_EXPECT(count == 0);
316 ioc.run();
317 BEAST_EXPECT(count == 2);
318 });
319
320 // suspend on read close #1
321 doFailLoop([&](test::fail_counter& fc)
322 {
323 echo_server es{log};
324 boost::asio::io_context ioc;
325 stream<test::stream> ws{ioc, fc};
326 ws.next_layer().connect(es.stream());
327 ws.handshake("localhost", "/");
328 // add a close frame to the input
329 ws.next_layer().append(string_view{
330 "\x88\x00", 2});
331 std::size_t count = 0;
332 multi_buffer b;
333 ws.async_read(b,
334 [&](error_code ec, std::size_t)
335 {
336 if(ec != error::closed)
337 BOOST_THROW_EXCEPTION(
338 system_error{ec});
339 BEAST_EXPECT(++count == 1);
340 });
341 while(! ws.wr_block_)
342 {
343 ioc.run_one();
344 if(! BEAST_EXPECT(! ioc.stopped()))
345 break;
346 }
347 BEAST_EXPECT(count == 0);
348 ws.async_close({},
349 [&](error_code ec)
350 {
351 if(ec != boost::asio::error::operation_aborted)
352 BOOST_THROW_EXCEPTION(
353 system_error{ec});
354 BEAST_EXPECT(++count == 2);
355 });
356 BEAST_EXPECT(count == 0);
357 ioc.run();
358 BEAST_EXPECT(count == 2);
359 });
360
361 // teardown on received close
362 doFailLoop([&](test::fail_counter& fc)
363 {
364 echo_server es{log};
365 boost::asio::io_context ioc;
366 stream<test::stream> ws{ioc, fc};
367 ws.next_layer().connect(es.stream());
368 ws.handshake("localhost", "/");
369 // add a close frame to the input
370 ws.next_layer().append(string_view{
371 "\x88\x00", 2});
372 std::size_t count = 0;
373 std::string const s = "Hello, world!";
374 ws.async_write(buffer(s),
375 [&](error_code ec, std::size_t n)
376 {
377 if(ec)
378 BOOST_THROW_EXCEPTION(
379 system_error{ec});
380 BEAST_EXPECT(n == s.size());
381 BEAST_EXPECT(++count == 1);
382 });
383 multi_buffer b;
384 ws.async_read(b,
385 [&](error_code ec, std::size_t)
386 {
387 if(ec != boost::asio::error::operation_aborted)
388 BOOST_THROW_EXCEPTION(
389 system_error{ec});
390 BEAST_EXPECT(++count == 3);
391 });
392 ws.async_close({},
393 [&](error_code ec)
394 {
395 if(ec)
396 BOOST_THROW_EXCEPTION(
397 system_error{ec});
398 BEAST_EXPECT(++count == 2);
399 });
400 BEAST_EXPECT(count == 0);
401 ioc.run();
402 BEAST_EXPECT(count == 3);
403 });
404
405 // check for deadlock
406 doFailLoop([&](test::fail_counter& fc)
407 {
408 echo_server es{log};
409 boost::asio::io_context ioc;
410 stream<test::stream> ws{ioc, fc};
411 ws.next_layer().connect(es.stream());
412 ws.handshake("localhost", "/");
413 // add a ping frame to the input
414 ws.next_layer().append(string_view{
415 "\x89\x00", 2});
416 std::size_t count = 0;
417 multi_buffer b;
418 std::string const s = "Hello, world!";
419 ws.async_write(buffer(s),
420 [&](error_code ec, std::size_t n)
421 {
422 if(ec)
423 BOOST_THROW_EXCEPTION(
424 system_error{ec});
425 BEAST_EXPECT(n == s.size());
426 BEAST_EXPECT(++count == 1);
427 });
428 ws.async_read(b,
429 [&](error_code ec, std::size_t)
430 {
431 if(ec != boost::asio::error::operation_aborted)
432 BOOST_THROW_EXCEPTION(
433 system_error{ec});
434 BEAST_EXPECT(++count == 3);
435 });
436 BEAST_EXPECT(ws.rd_block_);
437 ws.async_close({},
438 [&](error_code ec)
439 {
440 if(ec)
441 BOOST_THROW_EXCEPTION(
442 system_error{ec});
443 BEAST_EXPECT(++count == 2);
444 });
445 BEAST_EXPECT(ws.is_open());
446 BEAST_EXPECT(ws.wr_block_);
447 BEAST_EXPECT(count == 0);
448 ioc.run();
449 BEAST_EXPECT(count == 3);
450 });
451
452 // Four-way: close, read, write, ping
453 doFailLoop([&](test::fail_counter& fc)
454 {
455 echo_server es{log};
456 boost::asio::io_context ioc;
457 stream<test::stream> ws{ioc, fc};
458 ws.next_layer().connect(es.stream());
459 ws.handshake("localhost", "/");
460 std::size_t count = 0;
461 std::string const s = "Hello, world!";
462 multi_buffer b;
463 ws.async_close({},
464 [&](error_code ec)
465 {
466 if(ec)
467 BOOST_THROW_EXCEPTION(
468 system_error{ec});
469 BEAST_EXPECT(++count == 1);
470 });
471 ws.async_read(b,
472 [&](error_code ec, std::size_t)
473 {
474 if(ec != boost::asio::error::operation_aborted)
475 BOOST_THROW_EXCEPTION(
476 system_error{ec});
477 ++count;
478 });
479 ws.async_write(buffer(s),
480 [&](error_code ec, std::size_t)
481 {
482 if(ec != boost::asio::error::operation_aborted)
483 BOOST_THROW_EXCEPTION(
484 system_error{ec});
485 ++count;
486 });
487 ws.async_ping({},
488 [&](error_code ec)
489 {
490 if(ec != boost::asio::error::operation_aborted)
491 BOOST_THROW_EXCEPTION(
492 system_error{ec});
493 ++count;
494 });
495 BEAST_EXPECT(count == 0);
496 ioc.run();
497 BEAST_EXPECT(count == 4);
498 });
499
500 // Four-way: read, write, ping, close
501 doFailLoop([&](test::fail_counter& fc)
502 {
503 echo_server es{log};
504 boost::asio::io_context ioc;
505 stream<test::stream> ws{ioc, fc};
506 ws.next_layer().connect(es.stream());
507 ws.handshake("localhost", "/");
508 std::size_t count = 0;
509 std::string const s = "Hello, world!";
510 multi_buffer b;
511 ws.async_read(b,
512 [&](error_code ec, std::size_t)
513 {
514 if(ec && ec != boost::asio::error::operation_aborted)
515 {
516 BEAST_EXPECTS(ec, ec.message());
517 BOOST_THROW_EXCEPTION(
518 system_error{ec});
519 }
520 if(! ec)
521 BEAST_EXPECT(to_string(b.data()) == s);
522 ++count;
523 if(count == 4)
524 BEAST_EXPECT(
525 ec == boost::asio::error::operation_aborted);
526 });
527 ws.async_write(buffer(s),
528 [&](error_code ec, std::size_t n)
529 {
530 if(ec)
531 BOOST_THROW_EXCEPTION(
532 system_error{ec});
533 BEAST_EXPECT(n == s.size());
534 BEAST_EXPECT(++count == 1);
535 });
536 ws.async_ping({},
537 [&](error_code ec)
538 {
539 if(ec != boost::asio::error::operation_aborted)
540 {
541 BEAST_EXPECTS(ec, ec.message());
542 BOOST_THROW_EXCEPTION(
543 system_error{ec});
544 }
545 ++count;
546 });
547 ws.async_close({},
548 [&](error_code ec)
549 {
550 if(ec)
551 BOOST_THROW_EXCEPTION(
552 system_error{ec});
553 ++count;
554 BEAST_EXPECT(count == 2 || count == 3);
555 });
556 BEAST_EXPECT(count == 0);
557 ioc.run();
558 BEAST_EXPECT(count == 4);
559 });
560
561 // Four-way: ping, read, write, close
562 doFailLoop([&](test::fail_counter& fc)
563 {
564 echo_server es{log};
565 boost::asio::io_context ioc;
566 stream<test::stream> ws{ioc, fc};
567 ws.next_layer().connect(es.stream());
568 ws.handshake("localhost", "/");
569 std::size_t count = 0;
570 std::string const s = "Hello, world!";
571 multi_buffer b;
572 ws.async_ping({},
573 [&](error_code ec)
574 {
575 if(ec)
576 BOOST_THROW_EXCEPTION(
577 system_error{ec});
578 BEAST_EXPECT(++count == 1);
579 });
580 ws.async_read(b,
581 [&](error_code ec, std::size_t)
582 {
583 if(ec != boost::asio::error::operation_aborted)
584 BOOST_THROW_EXCEPTION(
585 system_error{ec});
586 ++count;
587 });
588 ws.async_write(buffer(s),
589 [&](error_code ec, std::size_t)
590 {
591 if(ec != boost::asio::error::operation_aborted)
592 BOOST_THROW_EXCEPTION(
593 system_error{ec});
594 ++count;
595 });
596 ws.async_close({},
597 [&](error_code ec)
598 {
599 if(ec)
600 BOOST_THROW_EXCEPTION(
601 system_error{ec});
602 BEAST_EXPECT(++count == 2);
603 });
604 BEAST_EXPECT(count == 0);
605 ioc.run();
606 BEAST_EXPECT(count == 4);
607 });
608 }
609
610 void
611 testContHook()
612 {
613 struct handler
614 {
615 void operator()(error_code) {}
616 };
617
618 stream<test::stream> ws{ioc_};
619 stream<test::stream>::close_op<handler> op{
620 handler{}, ws, {}};
621 using boost::asio::asio_handler_is_continuation;
622 asio_handler_is_continuation(&op);
623 }
624
625 void
626 run() override
627 {
628 testClose();
629 testSuspend();
630 testContHook();
631 }
632 };
633
634 BEAST_DEFINE_TESTSUITE(beast,websocket,close);
635
636 } // websocket
637 } // beast
638 } // boost