• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2016-2019 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 #ifndef BEAST_TEST_WEBSOCKET_TEST_HPP
11 #define BEAST_TEST_WEBSOCKET_TEST_HPP
12 
13 #include <boost/beast/core/bind_handler.hpp>
14 #include <boost/beast/core/buffer_traits.hpp>
15 #include <boost/beast/core/buffers_to_string.hpp>
16 #include <boost/beast/core/ostream.hpp>
17 #include <boost/beast/core/multi_buffer.hpp>
18 #include <boost/beast/websocket/stream.hpp>
19 #include <boost/beast/_experimental/test/stream.hpp>
20 #include <boost/beast/test/yield_to.hpp>
21 #include <boost/beast/_experimental/unit_test/suite.hpp>
22 #include <boost/asio/executor_work_guard.hpp>
23 #include <boost/asio/io_context.hpp>
24 #include <boost/optional.hpp>
25 #include <cstdlib>
26 #include <memory>
27 #include <random>
28 #include <string>
29 
30 namespace boost {
31 namespace beast {
32 namespace websocket {
33 
34 class websocket_test_suite
35     : public beast::unit_test::suite
36     , public test::enable_yield_to
37 {
38 public:
39     template<bool deflateSupported>
40     using ws_type_t =
41         websocket::stream<test::stream&, deflateSupported>;
42 
43     using ws_type =
44         websocket::stream<test::stream&>;
45 
46     struct move_only_handler
47     {
48         move_only_handler() = default;
49         move_only_handler(move_only_handler&&) = default;
50         move_only_handler(move_only_handler const&) = delete;
51 
52         template<class... Args>
53         void
operator ()boost::beast::websocket::websocket_test_suite::move_only_handler54         operator()(Args&&...) const
55         {
56         }
57     };
58 
59     enum class kind
60     {
61         sync,
62         async,
63         async_client
64     };
65 
66     class echo_server
67     {
68         enum
69         {
70             buf_size = 20000
71         };
72 
73         std::ostream& log_;
74         net::io_context ioc_;
75         net::any_io_executor work_;
76         static_buffer<buf_size> buffer_;
77         test::stream ts_;
78         std::thread t_;
79         websocket::stream<test::stream&> ws_;
80         bool close_ = false;
81 
82     public:
83         explicit
echo_server(std::ostream & log,kind k=kind::sync)84         echo_server(
85             std::ostream& log,
86             kind k = kind::sync)
87             : log_(log)
88             , work_(net::require(ioc_.get_executor(),
89                 net::execution::outstanding_work.tracked))
90             , ts_(ioc_)
91             , ws_(ts_)
92         {
93             permessage_deflate pmd;
94             pmd.server_enable = true;
95             pmd.server_max_window_bits = 9;
96             pmd.compLevel = 1;
97             ws_.set_option(pmd);
98 
99             switch(k)
100             {
101             case kind::sync:
102                 t_ = std::thread{[&]{ do_sync(); }};
103                 break;
104 
105             case kind::async:
106                 t_ = std::thread{[&]{ ioc_.run(); }};
107                 do_accept();
108                 break;
109 
110             case kind::async_client:
111                 t_ = std::thread{[&]{ ioc_.run(); }};
112                 break;
113             }
114         }
115 
~echo_server()116         ~echo_server()
117         {
118             work_ = {};
119             t_.join();
120         }
121 
122         test::stream&
stream()123         stream()
124         {
125             return ts_;
126         }
127 
128         void
async_handshake()129         async_handshake()
130         {
131             ws_.async_handshake("localhost", "/",
132                 bind_front_handler(
133                     &echo_server::on_handshake,
134                     this));
135         }
136 
137         void
async_close()138         async_close()
139         {
140             net::post(ioc_,
141             [&]
142             {
143                 if(ws_.is_open())
144                 {
145                     ws_.async_close({},
146                         bind_front_handler(
147                             &echo_server::on_close,
148                             this));
149                 }
150                 else
151                 {
152                     close_ = true;
153                 }
154             });
155         }
156 
157     private:
158         void
do_sync()159         do_sync()
160         {
161             try
162             {
163                 ws_.accept();
164                 for(;;)
165                 {
166                     ws_.read(buffer_);
167                     ws_.text(ws_.got_text());
168                     ws_.write(buffer_.data());
169                     buffer_.consume(buffer_.size());
170                 }
171             }
172             catch(system_error const& se)
173             {
174                 boost::ignore_unused(se);
175     #if 0
176                 if( se.code() != error::closed &&
177                     se.code() != error::failed &&
178                     se.code() != net::error::eof)
179                     log_ << "echo_server: " << se.code().message() << std::endl;
180     #endif
181             }
182             catch(std::exception const& e)
183             {
184                 log_ << "echo_server: " << e.what() << std::endl;
185             }
186         }
187 
188         void
do_accept()189         do_accept()
190         {
191             ws_.async_accept(
192                 bind_front_handler(
193                     &echo_server::on_accept,
194                     this));
195         }
196 
197         void
on_handshake(error_code ec)198         on_handshake(error_code ec)
199         {
200             if(ec)
201                 return fail(ec);
202 
203             do_read();
204         }
205 
206         void
on_accept(error_code ec)207         on_accept(error_code ec)
208         {
209             if(ec)
210                 return fail(ec);
211 
212             if(close_)
213             {
214                 return ws_.async_close({},
215                     bind_front_handler(
216                         &echo_server::on_close,
217                         this));
218             }
219 
220             do_read();
221         }
222 
223         void
do_read()224         do_read()
225         {
226             ws_.async_read(buffer_,
227                 beast::bind_front_handler(
228                     &echo_server::on_read,
229                     this));
230         }
231 
232         void
on_read(error_code ec,std::size_t)233         on_read(error_code ec, std::size_t)
234         {
235             if(ec)
236                 return fail(ec);
237             ws_.text(ws_.got_text());
238             ws_.async_write(buffer_.data(),
239                 beast::bind_front_handler(
240                     &echo_server::on_write,
241                     this));
242         }
243 
244         void
on_write(error_code ec,std::size_t)245         on_write(error_code ec, std::size_t)
246         {
247             if(ec)
248                 return fail(ec);
249             buffer_.consume(buffer_.size());
250             do_read();
251         }
252 
253         void
on_close(error_code ec)254         on_close(error_code ec)
255         {
256             if(ec)
257                 return fail(ec);
258         }
259 
260         void
fail(error_code ec)261         fail(error_code ec)
262         {
263             boost::ignore_unused(ec);
264     #if 0
265             if( ec != error::closed &&
266                 ec != error::failed &&
267                 ec != net::error::eof)
268                 log_ <<
269                     "echo_server_async: " <<
270                     ec.message() <<
271                     std::endl;
272     #endif
273         }
274     };
275 
276     template<class Test>
277     void
doFailLoop(Test const & f,std::size_t limit=200)278     doFailLoop(
279         Test const& f, std::size_t limit = 200)
280     {
281         std::size_t n;
282         for(n = 0; n < limit; ++n)
283         {
284             test::fail_count fc{n};
285             try
286             {
287                 f(fc);
288                 break;
289             }
290             catch(system_error const& se)
291             {
292                 BEAST_EXPECTS(
293                     se.code() == test::error::test_failure,
294                     se.code().message());
295             }
296         }
297         BEAST_EXPECT(n < limit);
298     }
299 
300     template<class Test>
301     void
doStreamLoop(Test const & f)302     doStreamLoop(Test const& f)
303     {
304         // This number has to be high for the
305         // test that writes the large buffer.
306         static std::size_t constexpr limit = 200;
307 
308         doFailLoop(
309             [&](test::fail_count& fc)
310             {
311                 test::stream ts{ioc_, fc};
312                 f(ts);
313                 ts.close();
314             }
315             , limit);
316     }
317 
318     template<bool deflateSupported = true, class Test>
319     void
doTest(permessage_deflate const & pmd,Test const & f)320     doTest(
321         permessage_deflate const& pmd,
322         Test const& f)
323     {
324         // This number has to be high for the
325         // test that writes the large buffer.
326         static std::size_t constexpr limit = 200;
327 
328         for(int i = 0; i < 2; ++i)
329         {
330             std::size_t n;
331             for(n = 0; n < limit; ++n)
332             {
333                 test::fail_count fc{n};
334                 test::stream ts{ioc_, fc};
335                 ws_type_t<deflateSupported> ws{ts};
336                 ws.set_option(pmd);
337 
338                 echo_server es{log, i==1 ?
339                     kind::async : kind::sync};
340                 error_code ec;
341                 ws.next_layer().connect(es.stream());
342                 ws.handshake("localhost", "/", ec);
343                 if(ec)
344                 {
345                     ts.close();
346                     if( ! BEAST_EXPECTS(
347                             ec == test::error::test_failure,
348                             ec.message()))
349                         BOOST_THROW_EXCEPTION(system_error{ec});
350                     continue;
351                 }
352                 try
353                 {
354                     f(ws);
355                     ts.close();
356                     break;
357                 }
358                 catch(system_error const& se)
359                 {
360                     BEAST_EXPECTS(
361                         se.code() == test::error::test_failure,
362                         se.code().message());
363                 }
364                 catch(std::exception const& e)
365                 {
366                     fail(e.what(), __FILE__, __LINE__);
367                 }
368                 ts.close();
369                 continue;
370             }
371             BEAST_EXPECT(n < limit);
372         }
373     }
374 
375     //--------------------------------------------------------------------------
376 
cbuf(std::initializer_list<std::uint8_t> bytes)377     net::const_buffer cbuf(std::initializer_list<std::uint8_t> bytes)
378     {
379         return {bytes.begin(), bytes.size()};
380     }
381 
382     template<std::size_t N>
383     static
384     net::const_buffer
sbuf(const char (& s)[N])385     sbuf(const char (&s)[N])
386     {
387         return net::const_buffer(&s[0], N-1);
388     }
389 
390     template<
391         class DynamicBuffer,
392         class ConstBufferSequence>
393     void
put(DynamicBuffer & buffer,ConstBufferSequence const & buffers)394     put(
395         DynamicBuffer& buffer,
396         ConstBufferSequence const& buffers)
397     {
398         buffer.commit(net::buffer_copy(
399             buffer.prepare(buffer_bytes(buffers)),
400             buffers));
401     }
402 
403     template<class Pred>
404     bool
run_until(net::io_context & ioc,std::size_t limit,Pred && pred)405     run_until(net::io_context& ioc,
406         std::size_t limit, Pred&& pred)
407     {
408         for(std::size_t i = 0; i < limit; ++i)
409         {
410             if(pred())
411                 return true;
412             ioc.run_one();
413         }
414         return false;
415     }
416 
417     template<class Pred>
418     bool
run_until(net::io_context & ioc,Pred && pred)419     run_until(
420         net::io_context& ioc, Pred&& pred)
421     {
422         return run_until(ioc, 100, pred);
423     }
424 
425     inline
426     std::string const&
random_string()427     random_string()
428     {
429         static std::string const s = []
430         {
431             std::size_t constexpr N = 16384;
432             std::mt19937 mt{1};
433             std::string tmp;
434             tmp.reserve(N);
435             for(std::size_t i = 0; i < N; ++ i)
436                 tmp.push_back(static_cast<char>(
437                     std::uniform_int_distribution<
438                         unsigned>{0, 255}(mt)));
439             return tmp;
440         }();
441         return s;
442     }
443 
444     //--------------------------------------------------------------------------
445 
446     struct SyncClient
447     {
448         template<class NextLayer, bool deflateSupported>
449         void
acceptboost::beast::websocket::websocket_test_suite::SyncClient450         accept(
451             stream<NextLayer, deflateSupported>& ws) const
452         {
453             ws.accept();
454         }
455 
456         template<
457             class NextLayer, bool deflateSupported,
458             class Buffers>
459         typename std::enable_if<
460             ! http::detail::is_header<Buffers>::value>::type
acceptboost::beast::websocket::websocket_test_suite::SyncClient461         accept(stream<NextLayer, deflateSupported>& ws,
462             Buffers const& buffers) const
463         {
464             ws.accept(buffers);
465         }
466 
467         template<class NextLayer, bool deflateSupported>
468         void
acceptboost::beast::websocket::websocket_test_suite::SyncClient469         accept(
470             stream<NextLayer, deflateSupported>& ws,
471             http::request<http::empty_body> const& req) const
472         {
473             ws.accept(req);
474         }
475 
476         template<
477             class NextLayer, bool deflateSupported,
478             class Decorator>
479         void
accept_exboost::beast::websocket::websocket_test_suite::SyncClient480         accept_ex(
481             stream<NextLayer, deflateSupported>& ws,
482             Decorator const& d) const
483         {
484             ws.accept_ex(d);
485         }
486 
487         template<
488             class NextLayer, bool deflateSupported,
489             class Buffers, class Decorator>
490         typename std::enable_if<
491             ! http::detail::is_header<Buffers>::value>::type
accept_exboost::beast::websocket::websocket_test_suite::SyncClient492         accept_ex(
493             stream<NextLayer, deflateSupported>& ws,
494             Buffers const& buffers,
495             Decorator const& d) const
496         {
497             ws.accept_ex(buffers, d);
498         }
499 
500         template<
501             class NextLayer, bool deflateSupported,
502             class Decorator>
503         void
accept_exboost::beast::websocket::websocket_test_suite::SyncClient504         accept_ex(
505             stream<NextLayer, deflateSupported>& ws,
506             http::request<http::empty_body> const& req,
507             Decorator const& d) const
508         {
509             ws.accept_ex(req, d);
510         }
511 
512         template<
513             class NextLayer, bool deflateSupported,
514             class Buffers, class Decorator>
515         void
accept_exboost::beast::websocket::websocket_test_suite::SyncClient516         accept_ex(
517             stream<NextLayer, deflateSupported>& ws,
518             http::request<http::empty_body> const& req,
519             Buffers const& buffers,
520             Decorator const& d) const
521         {
522             ws.accept_ex(req, buffers, d);
523         }
524 
525         template<class NextLayer, bool deflateSupported>
526         void
handshakeboost::beast::websocket::websocket_test_suite::SyncClient527         handshake(
528             stream<NextLayer, deflateSupported>& ws,
529             string_view uri,
530             string_view path) const
531         {
532             ws.handshake(uri, path);
533         }
534 
535         template<class NextLayer, bool deflateSupported>
536         void
handshakeboost::beast::websocket::websocket_test_suite::SyncClient537         handshake(
538             stream<NextLayer, deflateSupported>& ws,
539             response_type& res,
540             string_view uri,
541             string_view path) const
542         {
543             ws.handshake(res, uri, path);
544         }
545 
546         template<
547             class NextLayer, bool deflateSupported,
548             class Decorator>
549         void
handshake_exboost::beast::websocket::websocket_test_suite::SyncClient550         handshake_ex(
551             stream<NextLayer, deflateSupported>& ws,
552             string_view uri,
553             string_view path,
554             Decorator const& d) const
555         {
556             ws.handshake_ex(uri, path, d);
557         }
558 
559         template<
560             class NextLayer, bool deflateSupported,
561             class Decorator>
562         void
handshake_exboost::beast::websocket::websocket_test_suite::SyncClient563         handshake_ex(
564             stream<NextLayer, deflateSupported>& ws,
565             response_type& res,
566             string_view uri,
567             string_view path,
568             Decorator const& d) const
569         {
570             ws.handshake_ex(res, uri, path, d);
571         }
572 
573         template<class NextLayer, bool deflateSupported>
574         void
pingboost::beast::websocket::websocket_test_suite::SyncClient575         ping(stream<NextLayer, deflateSupported>& ws,
576             ping_data const& payload) const
577         {
578             ws.ping(payload);
579         }
580 
581         template<class NextLayer, bool deflateSupported>
582         void
pongboost::beast::websocket::websocket_test_suite::SyncClient583         pong(stream<NextLayer, deflateSupported>& ws,
584             ping_data const& payload) const
585         {
586             ws.pong(payload);
587         }
588 
589         template<class NextLayer, bool deflateSupported>
590         void
closeboost::beast::websocket::websocket_test_suite::SyncClient591         close(stream<NextLayer, deflateSupported>& ws,
592             close_reason const& cr) const
593         {
594             ws.close(cr);
595         }
596 
597         template<
598             class NextLayer, bool deflateSupported,
599             class DynamicBuffer>
600         std::size_t
readboost::beast::websocket::websocket_test_suite::SyncClient601         read(stream<NextLayer, deflateSupported>& ws,
602             DynamicBuffer& buffer) const
603         {
604             return ws.read(buffer);
605         }
606 
607         template<
608             class NextLayer, bool deflateSupported,
609             class DynamicBuffer>
610         std::size_t
read_someboost::beast::websocket::websocket_test_suite::SyncClient611         read_some(
612             stream<NextLayer, deflateSupported>& ws,
613             std::size_t limit,
614             DynamicBuffer& buffer) const
615         {
616             return ws.read_some(buffer, limit);
617         }
618 
619         template<
620             class NextLayer, bool deflateSupported,
621             class MutableBufferSequence>
622         std::size_t
read_someboost::beast::websocket::websocket_test_suite::SyncClient623         read_some(
624             stream<NextLayer, deflateSupported>& ws,
625             MutableBufferSequence const& buffers) const
626         {
627             return ws.read_some(buffers);
628         }
629 
630         template<
631             class NextLayer, bool deflateSupported,
632             class ConstBufferSequence>
633         std::size_t
writeboost::beast::websocket::websocket_test_suite::SyncClient634         write(
635             stream<NextLayer, deflateSupported>& ws,
636             ConstBufferSequence const& buffers) const
637         {
638             return ws.write(buffers);
639         }
640 
641         template<
642             class NextLayer, bool deflateSupported,
643             class ConstBufferSequence>
644         std::size_t
write_someboost::beast::websocket::websocket_test_suite::SyncClient645         write_some(
646             stream<NextLayer, deflateSupported>& ws,
647             bool fin,
648             ConstBufferSequence const& buffers) const
649         {
650             return ws.write_some(fin, buffers);
651         }
652 
653         template<
654             class NextLayer, bool deflateSupported,
655             class ConstBufferSequence>
656         std::size_t
write_rawboost::beast::websocket::websocket_test_suite::SyncClient657         write_raw(
658             stream<NextLayer, deflateSupported>& ws,
659             ConstBufferSequence const& buffers) const
660         {
661             return net::write(
662                 ws.next_layer(), buffers);
663         }
664     };
665 
666     //--------------------------------------------------------------------------
667 
668     class AsyncClient
669     {
670         net::yield_context& yield_;
671 
672     public:
673         explicit
AsyncClient(net::yield_context & yield)674         AsyncClient(net::yield_context& yield)
675             : yield_(yield)
676         {
677         }
678 
679         template<class NextLayer, bool deflateSupported>
680         void
accept(stream<NextLayer,deflateSupported> & ws) const681         accept(stream<NextLayer, deflateSupported>& ws) const
682         {
683             error_code ec;
684             ws.async_accept(yield_[ec]);
685             if(ec)
686                 throw system_error{ec};
687         }
688 
689         template<
690             class NextLayer, bool deflateSupported,
691             class Buffers>
692         typename std::enable_if<
693             ! http::detail::is_header<Buffers>::value>::type
accept(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers) const694         accept(
695             stream<NextLayer, deflateSupported>& ws,
696             Buffers const& buffers) const
697         {
698             error_code ec;
699             ws.async_accept(buffers, yield_[ec]);
700             if(ec)
701                 throw system_error{ec};
702         }
703 
704         template<class NextLayer, bool deflateSupported>
705         void
accept(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req) const706         accept(
707             stream<NextLayer, deflateSupported>& ws,
708             http::request<http::empty_body> const& req) const
709         {
710             error_code ec;
711             ws.async_accept(req, yield_[ec]);
712             if(ec)
713                 throw system_error{ec};
714         }
715 
716         template<
717             class NextLayer, bool deflateSupported,
718             class Decorator>
719         void
accept_ex(stream<NextLayer,deflateSupported> & ws,Decorator const & d) const720         accept_ex(
721             stream<NextLayer, deflateSupported>& ws,
722             Decorator const& d) const
723         {
724             error_code ec;
725             ws.async_accept_ex(d, yield_[ec]);
726             if(ec)
727                 throw system_error{ec};
728         }
729 
730         template<
731             class NextLayer, bool deflateSupported,
732             class Buffers, class Decorator>
733         typename std::enable_if<
734             ! http::detail::is_header<Buffers>::value>::type
accept_ex(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers,Decorator const & d) const735         accept_ex(
736             stream<NextLayer, deflateSupported>& ws,
737             Buffers const& buffers,
738             Decorator const& d) const
739         {
740             error_code ec;
741             ws.async_accept_ex(buffers, d, yield_[ec]);
742             if(ec)
743                 throw system_error{ec};
744         }
745 
746         template<
747             class NextLayer, bool deflateSupported,
748             class Decorator>
749         void
accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Decorator const & d) const750         accept_ex(
751             stream<NextLayer, deflateSupported>& ws,
752             http::request<http::empty_body> const& req,
753             Decorator const& d) const
754         {
755             error_code ec;
756             ws.async_accept_ex(req, d, yield_[ec]);
757             if(ec)
758                 throw system_error{ec};
759         }
760 
761         template<
762             class NextLayer, bool deflateSupported,
763             class Buffers, class Decorator>
764         void
accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Buffers const & buffers,Decorator const & d) const765         accept_ex(
766             stream<NextLayer, deflateSupported>& ws,
767             http::request<http::empty_body> const& req,
768             Buffers const& buffers,
769             Decorator const& d) const
770         {
771             error_code ec;
772             ws.async_accept_ex(
773                 req, buffers, d, yield_[ec]);
774             if(ec)
775                 throw system_error{ec};
776         }
777 
778         template<
779             class NextLayer, bool deflateSupported>
780         void
handshake(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path) const781         handshake(
782             stream<NextLayer, deflateSupported>& ws,
783             string_view uri,
784             string_view path) const
785         {
786             error_code ec;
787             ws.async_handshake(
788                 uri, path, yield_[ec]);
789             if(ec)
790                 throw system_error{ec};
791         }
792 
793         template<class NextLayer, bool deflateSupported>
794         void
handshake(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path) const795         handshake(
796             stream<NextLayer, deflateSupported>& ws,
797             response_type& res,
798             string_view uri,
799             string_view path) const
800         {
801             error_code ec;
802             ws.async_handshake(
803                 res, uri, path, yield_[ec]);
804             if(ec)
805                 throw system_error{ec};
806         }
807 
808         template<
809             class NextLayer, bool deflateSupported,
810             class Decorator>
811         void
handshake_ex(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path,Decorator const & d) const812         handshake_ex(
813             stream<NextLayer, deflateSupported>& ws,
814             string_view uri,
815             string_view path,
816             Decorator const &d) const
817         {
818             error_code ec;
819             ws.async_handshake_ex(
820                 uri, path, d, yield_[ec]);
821             if(ec)
822                 throw system_error{ec};
823         }
824 
825         template<
826             class NextLayer, bool deflateSupported,
827             class Decorator>
828         void
handshake_ex(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path,Decorator const & d) const829         handshake_ex(
830             stream<NextLayer, deflateSupported>& ws,
831             response_type& res,
832             string_view uri,
833             string_view path,
834             Decorator const &d) const
835         {
836             error_code ec;
837             ws.async_handshake_ex(
838                 res, uri, path, d, yield_[ec]);
839             if(ec)
840                 throw system_error{ec};
841         }
842 
843         template<class NextLayer, bool deflateSupported>
844         void
ping(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const845         ping(
846             stream<NextLayer, deflateSupported>& ws,
847             ping_data const& payload) const
848         {
849             error_code ec;
850             ws.async_ping(payload, yield_[ec]);
851             if(ec)
852                 throw system_error{ec};
853         }
854 
855         template<class NextLayer, bool deflateSupported>
856         void
pong(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const857         pong(
858             stream<NextLayer, deflateSupported>& ws,
859             ping_data const& payload) const
860         {
861             error_code ec;
862             ws.async_pong(payload, yield_[ec]);
863             if(ec)
864                 throw system_error{ec};
865         }
866 
867         template<class NextLayer, bool deflateSupported>
868         void
close(stream<NextLayer,deflateSupported> & ws,close_reason const & cr) const869         close(
870             stream<NextLayer, deflateSupported>& ws,
871             close_reason const& cr) const
872         {
873             error_code ec;
874             ws.async_close(cr, yield_[ec]);
875             if(ec)
876                 throw system_error{ec};
877         }
878 
879         template<
880             class NextLayer, bool deflateSupported,
881             class DynamicBuffer>
882         std::size_t
read(stream<NextLayer,deflateSupported> & ws,DynamicBuffer & buffer) const883         read(
884             stream<NextLayer, deflateSupported>& ws,
885             DynamicBuffer& buffer) const
886         {
887             error_code ec;
888             auto const bytes_written =
889                 ws.async_read(buffer, yield_[ec]);
890             if(ec)
891                 throw system_error{ec};
892             return bytes_written;
893         }
894 
895         template<
896             class NextLayer, bool deflateSupported,
897             class DynamicBuffer>
898         std::size_t
read_some(stream<NextLayer,deflateSupported> & ws,std::size_t limit,DynamicBuffer & buffer) const899         read_some(
900             stream<NextLayer, deflateSupported>& ws,
901             std::size_t limit,
902             DynamicBuffer& buffer) const
903         {
904             error_code ec;
905             auto const bytes_written =
906                 ws.async_read_some(buffer, limit, yield_[ec]);
907             if(ec)
908                 throw system_error{ec};
909             return bytes_written;
910         }
911 
912         template<
913             class NextLayer, bool deflateSupported,
914             class MutableBufferSequence>
915         std::size_t
read_some(stream<NextLayer,deflateSupported> & ws,MutableBufferSequence const & buffers) const916         read_some(
917             stream<NextLayer, deflateSupported>& ws,
918             MutableBufferSequence const& buffers) const
919         {
920             error_code ec;
921             auto const bytes_written =
922                 ws.async_read_some(buffers, yield_[ec]);
923             if(ec)
924                 throw system_error{ec};
925             return bytes_written;
926         }
927 
928         template<
929             class NextLayer, bool deflateSupported,
930             class ConstBufferSequence>
931         std::size_t
write(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const932         write(
933             stream<NextLayer, deflateSupported>& ws,
934             ConstBufferSequence const& buffers) const
935         {
936             error_code ec;
937             auto const bytes_transferred =
938                 ws.async_write(buffers, yield_[ec]);
939             if(ec)
940                 throw system_error{ec};
941             return bytes_transferred;
942         }
943 
944         template<
945             class NextLayer, bool deflateSupported,
946             class ConstBufferSequence>
947         std::size_t
write_some(stream<NextLayer,deflateSupported> & ws,bool fin,ConstBufferSequence const & buffers) const948         write_some(
949             stream<NextLayer, deflateSupported>& ws,
950             bool fin,
951             ConstBufferSequence const& buffers) const
952         {
953             error_code ec;
954             auto const bytes_transferred =
955                 ws.async_write_some(fin, buffers, yield_[ec]);
956             if(ec)
957                 throw system_error{ec};
958             return bytes_transferred;
959         }
960 
961         template<
962             class NextLayer, bool deflateSupported,
963             class ConstBufferSequence>
964         std::size_t
write_raw(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const965         write_raw(
966             stream<NextLayer, deflateSupported>& ws,
967             ConstBufferSequence const& buffers) const
968         {
969             error_code ec;
970             auto const bytes_transferred =
971                 net::async_write(
972                     ws.next_layer(), buffers, yield_[ec]);
973             if(ec)
974                 throw system_error{ec};
975             return bytes_transferred;
976         }
977     };
978 };
979 
980 struct test_sync_api
981 {
982     template<class NextLayer, bool deflateSupported>
983     void
acceptboost::beast::websocket::test_sync_api984     accept(
985         stream<NextLayer, deflateSupported>& ws) const
986     {
987         ws.accept();
988     }
989 
990     template<
991         class NextLayer, bool deflateSupported,
992         class Buffers>
993     typename std::enable_if<
994         ! http::detail::is_header<Buffers>::value>::type
acceptboost::beast::websocket::test_sync_api995     accept(stream<NextLayer, deflateSupported>& ws,
996         Buffers const& buffers) const
997     {
998         ws.accept(buffers);
999     }
1000 
1001     template<class NextLayer, bool deflateSupported>
1002     void
acceptboost::beast::websocket::test_sync_api1003     accept(
1004         stream<NextLayer, deflateSupported>& ws,
1005         http::request<http::empty_body> const& req) const
1006     {
1007         ws.accept(req);
1008     }
1009 
1010     template<
1011         class NextLayer, bool deflateSupported,
1012         class Decorator>
1013     void
accept_exboost::beast::websocket::test_sync_api1014     accept_ex(
1015         stream<NextLayer, deflateSupported>& ws,
1016         Decorator const& d) const
1017     {
1018         ws.accept_ex(d);
1019     }
1020 
1021     template<
1022         class NextLayer, bool deflateSupported,
1023         class Buffers, class Decorator>
1024     typename std::enable_if<
1025         ! http::detail::is_header<Buffers>::value>::type
accept_exboost::beast::websocket::test_sync_api1026     accept_ex(
1027         stream<NextLayer, deflateSupported>& ws,
1028         Buffers const& buffers,
1029         Decorator const& d) const
1030     {
1031         ws.accept_ex(buffers, d);
1032     }
1033 
1034     template<
1035         class NextLayer, bool deflateSupported,
1036         class Decorator>
1037     void
accept_exboost::beast::websocket::test_sync_api1038     accept_ex(
1039         stream<NextLayer, deflateSupported>& ws,
1040         http::request<http::empty_body> const& req,
1041         Decorator const& d) const
1042     {
1043         ws.accept_ex(req, d);
1044     }
1045 
1046     template<
1047         class NextLayer, bool deflateSupported,
1048         class Buffers, class Decorator>
1049     void
accept_exboost::beast::websocket::test_sync_api1050     accept_ex(
1051         stream<NextLayer, deflateSupported>& ws,
1052         http::request<http::empty_body> const& req,
1053         Buffers const& buffers,
1054         Decorator const& d) const
1055     {
1056         ws.accept_ex(req, buffers, d);
1057     }
1058 
1059     template<class NextLayer, bool deflateSupported>
1060     void
handshakeboost::beast::websocket::test_sync_api1061     handshake(
1062         stream<NextLayer, deflateSupported>& ws,
1063         response_type& res,
1064         string_view uri,
1065         string_view path) const
1066     {
1067         ws.handshake(res, uri, path);
1068     }
1069 
1070     template<
1071         class NextLayer, bool deflateSupported,
1072         class Decorator>
1073     void
handshake_exboost::beast::websocket::test_sync_api1074     handshake_ex(
1075         stream<NextLayer, deflateSupported>& ws,
1076         string_view uri,
1077         string_view path,
1078         Decorator const& d) const
1079     {
1080         ws.handshake_ex(uri, path, d);
1081     }
1082 
1083     template<
1084         class NextLayer, bool deflateSupported,
1085         class Decorator>
1086     void
handshake_exboost::beast::websocket::test_sync_api1087     handshake_ex(
1088         stream<NextLayer, deflateSupported>& ws,
1089         response_type& res,
1090         string_view uri,
1091         string_view path,
1092         Decorator const& d) const
1093     {
1094         ws.handshake_ex(res, uri, path, d);
1095     }
1096 
1097     template<class NextLayer, bool deflateSupported>
1098     void
pingboost::beast::websocket::test_sync_api1099     ping(stream<NextLayer, deflateSupported>& ws,
1100         ping_data const& payload) const
1101     {
1102         ws.ping(payload);
1103     }
1104 
1105     template<class NextLayer, bool deflateSupported>
1106     void
pongboost::beast::websocket::test_sync_api1107     pong(stream<NextLayer, deflateSupported>& ws,
1108         ping_data const& payload) const
1109     {
1110         ws.pong(payload);
1111     }
1112 
1113     template<class NextLayer, bool deflateSupported>
1114     void
closeboost::beast::websocket::test_sync_api1115     close(stream<NextLayer, deflateSupported>& ws,
1116         close_reason const& cr) const
1117     {
1118         ws.close(cr);
1119     }
1120 
1121     template<
1122         class NextLayer, bool deflateSupported,
1123         class DynamicBuffer>
1124     std::size_t
readboost::beast::websocket::test_sync_api1125     read(stream<NextLayer, deflateSupported>& ws,
1126         DynamicBuffer& buffer) const
1127     {
1128         return ws.read(buffer);
1129     }
1130 
1131     template<
1132         class NextLayer, bool deflateSupported,
1133         class DynamicBuffer>
1134     std::size_t
read_someboost::beast::websocket::test_sync_api1135     read_some(
1136         stream<NextLayer, deflateSupported>& ws,
1137         std::size_t limit,
1138         DynamicBuffer& buffer) const
1139     {
1140         return ws.read_some(buffer, limit);
1141     }
1142 
1143     template<
1144         class NextLayer, bool deflateSupported,
1145         class MutableBufferSequence>
1146     std::size_t
read_someboost::beast::websocket::test_sync_api1147     read_some(
1148         stream<NextLayer, deflateSupported>& ws,
1149         MutableBufferSequence const& buffers) const
1150     {
1151         return ws.read_some(buffers);
1152     }
1153 
1154     template<
1155         class NextLayer, bool deflateSupported,
1156         class ConstBufferSequence>
1157     std::size_t
writeboost::beast::websocket::test_sync_api1158     write(
1159         stream<NextLayer, deflateSupported>& ws,
1160         ConstBufferSequence const& buffers) const
1161     {
1162         return ws.write(buffers);
1163     }
1164 
1165     template<
1166         class NextLayer, bool deflateSupported,
1167         class ConstBufferSequence>
1168     std::size_t
write_someboost::beast::websocket::test_sync_api1169     write_some(
1170         stream<NextLayer, deflateSupported>& ws,
1171         bool fin,
1172         ConstBufferSequence const& buffers) const
1173     {
1174         return ws.write_some(fin, buffers);
1175     }
1176 
1177     template<
1178         class NextLayer, bool deflateSupported,
1179         class ConstBufferSequence>
1180     std::size_t
write_rawboost::beast::websocket::test_sync_api1181     write_raw(
1182         stream<NextLayer, deflateSupported>& ws,
1183         ConstBufferSequence const& buffers) const
1184     {
1185         return net::write(
1186             ws.next_layer(), buffers);
1187     }
1188 };
1189 
1190 //--------------------------------------------------------------------------
1191 
1192 class test_async_api
1193 {
1194     struct handler
1195     {
1196         error_code& ec_;
1197         std::size_t* n_ = 0;
1198         bool pass_ = false;
1199 
1200         explicit
handlerboost::beast::websocket::test_async_api::handler1201         handler(error_code& ec)
1202             : ec_(ec)
1203         {
1204         }
1205 
1206         explicit
handlerboost::beast::websocket::test_async_api::handler1207         handler(error_code& ec, std::size_t& n)
1208             : ec_(ec)
1209             , n_(&n)
1210         {
1211             *n_ = 0;
1212         }
1213 
handlerboost::beast::websocket::test_async_api::handler1214         handler(handler&& other)
1215             : ec_(other.ec_)
1216             , pass_(boost::exchange(other.pass_, true))
1217         {
1218         }
1219 
~handlerboost::beast::websocket::test_async_api::handler1220         ~handler()
1221         {
1222             BEAST_EXPECT(pass_);
1223         }
1224 
1225         void
operator ()boost::beast::websocket::test_async_api::handler1226         operator()(error_code ec)
1227         {
1228             BEAST_EXPECT(! pass_);
1229             pass_ = true;
1230             ec_ = ec;
1231         }
1232 
1233         void
operator ()boost::beast::websocket::test_async_api::handler1234         operator()(error_code ec, std::size_t n)
1235         {
1236             BEAST_EXPECT(! pass_);
1237             pass_ = true;
1238             ec_ = ec;
1239             if(n_)
1240                 *n_ = n;
1241         }
1242     };
1243 
1244 public:
1245     template<class NextLayer, bool deflateSupported>
1246     void
accept(stream<NextLayer,deflateSupported> & ws) const1247     accept(
1248         stream<NextLayer, deflateSupported>& ws) const
1249     {
1250         error_code ec;
1251         ws.async_accept(handler(ec));
1252         net::query(ws.get_executor(), net::execution::context).run();
1253         net::query(ws.get_executor(), net::execution::context).restart();
1254         if(ec)
1255             throw system_error{ec};
1256     }
1257 
1258     template<
1259         class NextLayer, bool deflateSupported,
1260         class Buffers>
1261     typename std::enable_if<
1262         ! http::detail::is_header<Buffers>::value>::type
accept(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers) const1263     accept(
1264         stream<NextLayer, deflateSupported>& ws,
1265         Buffers const& buffers) const
1266     {
1267         error_code ec;
1268         ws.async_accept(buffers, handler(ec));
1269         net::query(ws.get_executor(), net::execution::context).run();
1270         net::query(ws.get_executor(), net::execution::context).restart();
1271         if(ec)
1272             throw system_error{ec};
1273     }
1274 
1275     template<class NextLayer, bool deflateSupported>
1276     void
accept(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req) const1277     accept(
1278         stream<NextLayer, deflateSupported>& ws,
1279         http::request<http::empty_body> const& req) const
1280     {
1281         error_code ec;
1282         ws.async_accept(req, handler(ec));
1283         net::query(ws.get_executor(), net::execution::context).run();
1284         net::query(ws.get_executor(), net::execution::context).restart();
1285         if(ec)
1286             throw system_error{ec};
1287     }
1288 
1289     template<
1290         class NextLayer, bool deflateSupported,
1291         class Decorator>
1292     void
accept_ex(stream<NextLayer,deflateSupported> & ws,Decorator const & d) const1293     accept_ex(
1294         stream<NextLayer, deflateSupported>& ws,
1295         Decorator const& d) const
1296     {
1297         error_code ec;
1298         ws.async_accept_ex(d, handler(ec));
1299         net::query(ws.get_executor(), net::execution::context).run();
1300         net::query(ws.get_executor(), net::execution::context).restart();
1301         if(ec)
1302             throw system_error{ec};
1303     }
1304 
1305     template<
1306         class NextLayer, bool deflateSupported,
1307         class Buffers, class Decorator>
1308     typename std::enable_if<
1309         ! http::detail::is_header<Buffers>::value>::type
accept_ex(stream<NextLayer,deflateSupported> & ws,Buffers const & buffers,Decorator const & d) const1310     accept_ex(
1311         stream<NextLayer, deflateSupported>& ws,
1312         Buffers const& buffers,
1313         Decorator const& d) const
1314     {
1315         error_code ec;
1316         ws.async_accept_ex(buffers, d, handler(ec));
1317         net::query(ws.get_executor(), net::execution::context).run();
1318         net::query(ws.get_executor(), net::execution::context).restart();
1319         if(ec)
1320             throw system_error{ec};
1321     }
1322 
1323     template<
1324         class NextLayer, bool deflateSupported,
1325         class Decorator>
1326     void
accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Decorator const & d) const1327     accept_ex(
1328         stream<NextLayer, deflateSupported>& ws,
1329         http::request<http::empty_body> const& req,
1330         Decorator const& d) const
1331     {
1332         error_code ec;
1333         ws.async_accept_ex(req, d, handler(ec));
1334         net::query(ws.get_executor(), net::execution::context).run();
1335         net::query(ws.get_executor(), net::execution::context).restart();
1336         if(ec)
1337             throw system_error{ec};
1338     }
1339 
1340     template<
1341         class NextLayer, bool deflateSupported,
1342         class Buffers, class Decorator>
1343     void
accept_ex(stream<NextLayer,deflateSupported> & ws,http::request<http::empty_body> const & req,Buffers const & buffers,Decorator const & d) const1344     accept_ex(
1345         stream<NextLayer, deflateSupported>& ws,
1346         http::request<http::empty_body> const& req,
1347         Buffers const& buffers,
1348         Decorator const& d) const
1349     {
1350         error_code ec;
1351         ws.async_accept_ex(
1352             req, buffers, d, handler(ec));
1353         net::query(ws.get_executor(), net::execution::context).run();
1354         net::query(ws.get_executor(), net::execution::context).restart();
1355         if(ec)
1356             throw system_error{ec};
1357     }
1358 
1359     template<
1360         class NextLayer, bool deflateSupported>
1361     void
handshake(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path) const1362     handshake(
1363         stream<NextLayer, deflateSupported>& ws,
1364         string_view uri,
1365         string_view path) const
1366     {
1367         error_code ec;
1368         ws.async_handshake(
1369             uri, path, handler(ec));
1370         net::query(ws.get_executor(), net::execution::context).run();
1371         net::query(ws.get_executor(), net::execution::context).restart();
1372         if(ec)
1373             throw system_error{ec};
1374     }
1375 
1376     template<class NextLayer, bool deflateSupported>
1377     void
handshake(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path) const1378     handshake(
1379         stream<NextLayer, deflateSupported>& ws,
1380         response_type& res,
1381         string_view uri,
1382         string_view path) const
1383     {
1384         error_code ec;
1385         ws.async_handshake(
1386             res, uri, path, handler(ec));
1387         net::query(ws.get_executor(), net::execution::context).run();
1388         net::query(ws.get_executor(), net::execution::context).restart();
1389         if(ec)
1390             throw system_error{ec};
1391     }
1392 
1393     template<
1394         class NextLayer, bool deflateSupported,
1395         class Decorator>
1396     void
handshake_ex(stream<NextLayer,deflateSupported> & ws,string_view uri,string_view path,Decorator const & d) const1397     handshake_ex(
1398         stream<NextLayer, deflateSupported>& ws,
1399         string_view uri,
1400         string_view path,
1401         Decorator const &d) const
1402     {
1403         error_code ec;
1404         ws.async_handshake_ex(
1405             uri, path, d, handler(ec));
1406         net::query(ws.get_executor(), net::execution::context).run();
1407         net::query(ws.get_executor(), net::execution::context).restart();
1408         if(ec)
1409             throw system_error{ec};
1410     }
1411 
1412     template<
1413         class NextLayer, bool deflateSupported,
1414         class Decorator>
1415     void
handshake_ex(stream<NextLayer,deflateSupported> & ws,response_type & res,string_view uri,string_view path,Decorator const & d) const1416     handshake_ex(
1417         stream<NextLayer, deflateSupported>& ws,
1418         response_type& res,
1419         string_view uri,
1420         string_view path,
1421         Decorator const &d) const
1422     {
1423         error_code ec;
1424         ws.async_handshake_ex(
1425             res, uri, path, d, handler(ec));
1426         net::query(ws.get_executor(), net::execution::context).run();
1427         net::query(ws.get_executor(), net::execution::context).restart();
1428         if(ec)
1429             throw system_error{ec};
1430     }
1431 
1432     template<class NextLayer, bool deflateSupported>
1433     void
ping(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const1434     ping(
1435         stream<NextLayer, deflateSupported>& ws,
1436         ping_data const& payload) const
1437     {
1438         error_code ec;
1439         ws.async_ping(payload, handler(ec));
1440         net::query(ws.get_executor(), net::execution::context).run();
1441         net::query(ws.get_executor(), net::execution::context).restart();
1442         if(ec)
1443             throw system_error{ec};
1444     }
1445 
1446     template<class NextLayer, bool deflateSupported>
1447     void
pong(stream<NextLayer,deflateSupported> & ws,ping_data const & payload) const1448     pong(
1449         stream<NextLayer, deflateSupported>& ws,
1450         ping_data const& payload) const
1451     {
1452         error_code ec;
1453         ws.async_pong(payload, handler(ec));
1454         net::query(ws.get_executor(), net::execution::context).run();
1455         net::query(ws.get_executor(), net::execution::context).restart();
1456         if(ec)
1457             throw system_error{ec};
1458     }
1459 
1460     template<class NextLayer, bool deflateSupported>
1461     void
close(stream<NextLayer,deflateSupported> & ws,close_reason const & cr) const1462     close(
1463         stream<NextLayer, deflateSupported>& ws,
1464         close_reason const& cr) const
1465     {
1466         error_code ec;
1467         ws.async_close(cr, handler(ec));
1468         net::query(ws.get_executor(), net::execution::context).run();
1469         net::query(ws.get_executor(), net::execution::context).restart();
1470         if(ec)
1471             throw system_error{ec};
1472     }
1473 
1474     template<
1475         class NextLayer, bool deflateSupported,
1476         class DynamicBuffer>
1477     std::size_t
read(stream<NextLayer,deflateSupported> & ws,DynamicBuffer & buffer) const1478     read(
1479         stream<NextLayer, deflateSupported>& ws,
1480         DynamicBuffer& buffer) const
1481     {
1482         error_code ec;
1483         std::size_t n;
1484         ws.async_read(buffer, handler(ec, n));
1485         net::query(ws.get_executor(), net::execution::context).run();
1486         net::query(ws.get_executor(), net::execution::context).restart();
1487         if(ec)
1488             throw system_error{ec};
1489         return n;
1490     }
1491 
1492     template<
1493         class NextLayer, bool deflateSupported,
1494         class DynamicBuffer>
1495     std::size_t
read_some(stream<NextLayer,deflateSupported> & ws,std::size_t limit,DynamicBuffer & buffer) const1496     read_some(
1497         stream<NextLayer, deflateSupported>& ws,
1498         std::size_t limit,
1499         DynamicBuffer& buffer) const
1500     {
1501         error_code ec;
1502         std::size_t n;
1503         ws.async_read_some(buffer, limit, handler(ec, n));
1504         net::query(ws.get_executor(), net::execution::context).run();
1505         net::query(ws.get_executor(), net::execution::context).restart();
1506         if(ec)
1507             throw system_error{ec};
1508         return n;
1509     }
1510 
1511     template<
1512         class NextLayer, bool deflateSupported,
1513         class MutableBufferSequence>
1514     std::size_t
read_some(stream<NextLayer,deflateSupported> & ws,MutableBufferSequence const & buffers) const1515     read_some(
1516         stream<NextLayer, deflateSupported>& ws,
1517         MutableBufferSequence const& buffers) const
1518     {
1519         error_code ec;
1520         std::size_t n;
1521         ws.async_read_some(buffers, handler(ec, n));
1522         net::query(ws.get_executor(), net::execution::context).run();
1523         net::query(ws.get_executor(), net::execution::context).restart();
1524         if(ec)
1525             throw system_error{ec};
1526         return n;
1527     }
1528 
1529     template<
1530         class NextLayer, bool deflateSupported,
1531         class ConstBufferSequence>
1532     std::size_t
write(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const1533     write(
1534         stream<NextLayer, deflateSupported>& ws,
1535         ConstBufferSequence const& buffers) const
1536     {
1537         error_code ec;
1538         std::size_t n;
1539         ws.async_write(buffers, handler(ec, n));
1540         net::query(ws.get_executor(), net::execution::context).run();
1541         net::query(ws.get_executor(), net::execution::context).restart();
1542         if(ec)
1543             throw system_error{ec};
1544         return n;
1545     }
1546 
1547     template<
1548         class NextLayer, bool deflateSupported,
1549         class ConstBufferSequence>
1550     std::size_t
write_some(stream<NextLayer,deflateSupported> & ws,bool fin,ConstBufferSequence const & buffers) const1551     write_some(
1552         stream<NextLayer, deflateSupported>& ws,
1553         bool fin,
1554         ConstBufferSequence const& buffers) const
1555     {
1556         error_code ec;
1557         std::size_t n;
1558         ws.async_write_some(fin, buffers, handler(ec, n));
1559         net::query(ws.get_executor(), net::execution::context).run();
1560         net::query(ws.get_executor(), net::execution::context).restart();
1561         if(ec)
1562             throw system_error{ec};
1563         return n;
1564     }
1565 
1566     template<
1567         class NextLayer, bool deflateSupported,
1568         class ConstBufferSequence>
1569     std::size_t
write_raw(stream<NextLayer,deflateSupported> & ws,ConstBufferSequence const & buffers) const1570     write_raw(
1571         stream<NextLayer, deflateSupported>& ws,
1572         ConstBufferSequence const& buffers) const
1573     {
1574         error_code ec;
1575         std::size_t n;
1576         net::async_write(ws.next_layer(),
1577             buffers, handler(ec, n));
1578         net::query(ws.get_executor(), net::execution::context).run();
1579         net::query(ws.get_executor(), net::execution::context).restart();
1580         if(ec)
1581             throw system_error{ec};
1582         return n;
1583     }
1584 };
1585 
1586 } // websocket
1587 } // beast
1588 } // boost
1589 
1590 #endif
1591