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