Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:35

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
0012 
0013 #include <boost/beast/websocket/rfc6455.hpp>
0014 #include <boost/beast/websocket/detail/frame.hpp>
0015 #include <boost/beast/websocket/detail/hybi13.hpp>
0016 #include <boost/beast/websocket/detail/mask.hpp>
0017 #include <boost/beast/websocket/detail/pmd_extension.hpp>
0018 #include <boost/beast/websocket/detail/prng.hpp>
0019 #include <boost/beast/websocket/detail/service.hpp>
0020 #include <boost/beast/websocket/detail/soft_mutex.hpp>
0021 #include <boost/beast/websocket/detail/utf8_checker.hpp>
0022 #include <boost/beast/http/read.hpp>
0023 #include <boost/beast/http/write.hpp>
0024 #include <boost/beast/http/rfc7230.hpp>
0025 #include <boost/beast/core/buffers_cat.hpp>
0026 #include <boost/beast/core/buffers_prefix.hpp>
0027 #include <boost/beast/core/buffers_suffix.hpp>
0028 #include <boost/beast/core/flat_static_buffer.hpp>
0029 #include <boost/beast/core/saved_handler.hpp>
0030 #include <boost/beast/core/static_buffer.hpp>
0031 #include <boost/beast/core/stream_traits.hpp>
0032 #include <boost/beast/core/detail/clamp.hpp>
0033 #include <boost/asio/steady_timer.hpp>
0034 #include <boost/core/empty_value.hpp>
0035 #include <boost/enable_shared_from_this.hpp>
0036 #include <boost/shared_ptr.hpp>
0037 #include <boost/optional.hpp>
0038 
0039 namespace boost {
0040 namespace beast {
0041 namespace websocket {
0042 
0043 template<
0044     class NextLayer, bool deflateSupported>
0045 struct stream<NextLayer, deflateSupported>::impl_type
0046     : boost::empty_value<NextLayer>
0047     , detail::service::impl_type
0048     , detail::impl_base<deflateSupported>
0049 {
0050     NextLayer& stream() noexcept
0051     {
0052         return this->boost::empty_value<
0053             NextLayer>::get();
0054     }
0055 
0056     boost::weak_ptr<impl_type>
0057     weak_from_this()
0058     {
0059         return boost::static_pointer_cast<
0060             impl_type>(this->detail::service::
0061                 impl_type::shared_from_this());
0062     }
0063 
0064     boost::shared_ptr<impl_type>
0065     shared_this()
0066     {
0067         return boost::static_pointer_cast<
0068             impl_type>(this->detail::service::
0069                 impl_type::shared_from_this());
0070     }
0071     using executor_type = typename std::decay<NextLayer>::type::executor_type;
0072     typename net::steady_timer::rebind_executor<executor_type>::other
0073                             timer;          // used for timeouts
0074     close_reason            cr;             // set from received close frame
0075     control_cb_type         ctrl_cb;        // control callback
0076 
0077     std::size_t             rd_msg_max      /* max message size */ = 16 * 1024 * 1024;
0078     std::uint64_t           rd_size         /* total size of current message so far */ = 0;
0079     std::uint64_t           rd_remain       /* message frame bytes left in current frame */ = 0;
0080     detail::frame_header    rd_fh;          // current frame header
0081     detail::prepared_key    rd_key;         // current stateful mask key
0082     detail::frame_buffer    rd_fb;          // to write control frames (during reads)
0083     detail::utf8_checker    rd_utf8;        // to validate utf8
0084     static_buffer<
0085         +tcp_frame_size>    rd_buf;         // buffer for reads
0086     detail::opcode          rd_op           /* current message binary or text */ = detail::opcode::text;
0087     bool                    rd_cont         /* `true` if the next frame is a continuation */ = false;
0088     bool                    rd_done         /* set when a message is done */ = true;
0089     bool                    rd_close        /* did we read a close frame? */ = false;
0090     detail::soft_mutex      rd_block;       // op currently reading
0091 
0092     role_type               role            /* server or client */ = role_type::client;
0093     status                  status_         /* state of the object */ = status::closed;
0094 
0095     detail::soft_mutex      wr_block;       // op currently writing
0096     bool                    wr_close        /* did we write a close frame? */ = false;
0097     bool                    wr_cont         /* next write is a continuation */ = false;
0098     bool                    wr_frag         /* autofrag the current message */ = false;
0099     bool                    wr_frag_opt     /* autofrag option setting */ = true;
0100     bool                    wr_compress;    /* compress current message */
0101     bool                    wr_compress_opt /* compress message setting */ = true;
0102     detail::opcode          wr_opcode       /* message type */ = detail::opcode::text;
0103     std::unique_ptr<
0104         std::uint8_t[]>     wr_buf;         // write buffer
0105     std::size_t             wr_buf_size     /* write buffer size (current message) */ = 0;
0106     std::size_t             wr_buf_opt      /* write buffer size option setting */ = 4096;
0107     detail::fh_buffer       wr_fb;          // header buffer used for writes
0108 
0109     saved_handler           op_rd;          // paused read op
0110     saved_handler           op_wr;          // paused write op
0111     saved_handler           op_ping;        // paused ping op
0112     saved_handler           op_idle_ping;   // paused idle ping op
0113     saved_handler           op_close;       // paused close op
0114     saved_handler           op_r_rd;        // paused read op (async read)
0115     saved_handler           op_r_close;     // paused close op (async read)
0116 
0117     bool    idle_pinging = false;
0118     bool    secure_prng_ = true;
0119     bool    ec_delivered = false;
0120     bool    timed_out = false;
0121     int     idle_counter = 0;
0122 
0123     detail::decorator       decorator_opt;  // Decorator for HTTP messages
0124     timeout                 timeout_opt;    // Timeout/idle settings
0125 
0126     template<class... Args>
0127     impl_type(Args&&... args)
0128         : boost::empty_value<NextLayer>(
0129             boost::empty_init_t{},
0130             std::forward<Args>(args)...)
0131         , detail::service::impl_type(
0132             this->get_context(
0133                 this->boost::empty_value<NextLayer>::get().get_executor()))
0134         , timer(this->boost::empty_value<NextLayer>::get().get_executor())
0135     {
0136         timeout_opt.handshake_timeout = none();
0137         timeout_opt.idle_timeout = none();
0138         timeout_opt.keep_alive_pings = false;
0139     }
0140 
0141     void
0142     shutdown() override
0143     {
0144         op_rd.reset();
0145         op_wr.reset();
0146         op_ping.reset();
0147         op_idle_ping.reset();
0148         op_close.reset();
0149         op_r_rd.reset();
0150         op_r_close.reset();
0151     }
0152 
0153     void
0154     open(role_type role_)
0155     {
0156         // VFALCO TODO analyze and remove dupe code in reset()
0157         timer.expires_at(never());
0158         timed_out = false;
0159         cr.code = close_code::none;
0160         role = role_;
0161         status_ = status::open;
0162         rd_remain = 0;
0163         rd_cont = false;
0164         rd_done = true;
0165         // Can't clear this because accept uses it
0166         //rd_buf.reset();
0167         rd_fh.fin = false;
0168         rd_close = false;
0169         wr_close = false;
0170         // These should not be necessary, because all completion
0171         // handlers must be allowed to execute otherwise the
0172         // stream exhibits undefined behavior.
0173         wr_block.reset();
0174         rd_block.reset();
0175 
0176         wr_cont = false;
0177         wr_buf_size = 0;
0178 
0179         this->open_pmd(role);
0180     }
0181 
0182     void
0183     close()
0184     {
0185         timer.cancel();
0186         wr_buf.reset();
0187         this->close_pmd();
0188     }
0189 
0190     void
0191     reset()
0192     {
0193         BOOST_ASSERT(status_ != status::open);
0194         timer.expires_at(never());
0195         cr.code = close_code::none;
0196         rd_remain = 0;
0197         rd_cont = false;
0198         rd_done = true;
0199         rd_buf.consume(rd_buf.size());
0200         rd_fh.fin = false;
0201         rd_close = false;
0202         wr_close = false;
0203         wr_cont = false;
0204         // These should not be necessary, because all completion
0205         // handlers must be allowed to execute otherwise the
0206         // stream exhibits undefined behavior.
0207         wr_block.reset();
0208         rd_block.reset();
0209 
0210         // VFALCO Is this needed?
0211         timer.cancel();
0212     }
0213 
0214     void
0215     time_out()
0216     {
0217         timed_out = true;
0218         change_status(status::closed);
0219         close_socket(get_lowest_layer(stream()));
0220     }
0221 
0222     // Called just before sending
0223     // the first frame of each message
0224     void
0225     begin_msg(std::size_t n_bytes)
0226     {
0227         wr_frag = wr_frag_opt;
0228         wr_compress =
0229             this->pmd_enabled() &&
0230             wr_compress_opt &&
0231             this->should_compress(n_bytes);
0232 
0233         // Maintain the write buffer
0234         if( this->pmd_enabled() ||
0235             role == role_type::client)
0236         {
0237             if(! wr_buf ||
0238                 wr_buf_size != wr_buf_opt)
0239             {
0240                 wr_buf_size = wr_buf_opt;
0241                 wr_buf = boost::make_unique_noinit<
0242                     std::uint8_t[]>(wr_buf_size);
0243             }
0244         }
0245         else
0246         {
0247             wr_buf_size = wr_buf_opt;
0248             wr_buf.reset();
0249         }
0250 
0251         //
0252     }
0253 
0254     //--------------------------------------------------------------------------
0255 
0256     template<class Decorator>
0257     request_type
0258     build_request(
0259         detail::sec_ws_key_type& key,
0260         string_view host, string_view target,
0261         Decorator const& decorator);
0262 
0263     void
0264     on_response(
0265         response_type const& res,
0266         detail::sec_ws_key_type const& key,
0267         error_code& ec);
0268 
0269     template<class Body, class Allocator, class Decorator>
0270     response_type
0271     build_response(
0272         http::request<Body,
0273             http::basic_fields<Allocator>> const& req,
0274         Decorator const& decorator,
0275         error_code& result);
0276 
0277     // Attempt to read a complete frame header.
0278     // Returns `false` if more bytes are needed
0279     template<class DynamicBuffer>
0280     bool
0281     parse_fh(detail::frame_header& fh,
0282         DynamicBuffer& b, error_code& ec);
0283 
0284     std::uint32_t
0285     create_mask()
0286     {
0287         auto g = detail::make_prng(secure_prng_);
0288         for(;;)
0289             if(auto key = g())
0290                 return key;
0291     }
0292 
0293     template<class DynamicBuffer>
0294     std::size_t
0295     read_size_hint_db(DynamicBuffer& buffer) const
0296     {
0297         auto const initial_size = (std::min)(
0298             +tcp_frame_size,
0299             buffer.max_size() - buffer.size());
0300         if(initial_size == 0)
0301             return 1; // buffer is full
0302         return this->read_size_hint_pmd(
0303             initial_size, rd_done, rd_remain, rd_fh);
0304     }
0305 
0306     template<class DynamicBuffer>
0307     void
0308     write_ping(DynamicBuffer& db,
0309         detail::opcode code, ping_data const& data);
0310 
0311     template<class DynamicBuffer>
0312     void
0313     write_close(DynamicBuffer& db, close_reason const& cr);
0314 
0315     //--------------------------------------------------------------------------
0316 
0317     void
0318     set_option(timeout const& opt)
0319     {
0320         if( opt.handshake_timeout == none() &&
0321             opt.idle_timeout == none())
0322         {
0323             // turn timer off
0324             timer.cancel();
0325             timer.expires_at(never());
0326         }
0327 
0328         timeout_opt = opt;
0329     }
0330 
0331     // Determine if an operation should stop and
0332     // deliver an error code to the completion handler.
0333     //
0334     // This function must be called at the beginning
0335     // of every composed operation, and every time a
0336     // composed operation receives an intermediate
0337     // completion.
0338     //
0339     bool
0340     check_stop_now(error_code& ec)
0341     {
0342         // Deliver the timeout to the first caller
0343         if(timed_out)
0344         {
0345             timed_out = false;
0346             BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0347             return true;
0348         }
0349 
0350         // If the stream is closed then abort
0351         if( status_ == status::closed ||
0352             status_ == status::failed)
0353         {
0354             //BOOST_ASSERT(ec_delivered);
0355             BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0356             return true;
0357         }
0358 
0359         // If no error then keep going
0360         if(! ec)
0361             return false;
0362 
0363         // Is this the first error seen?
0364         if(ec_delivered)
0365         {
0366             // No, so abort
0367             BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0368             return true;
0369         }
0370 
0371         // Deliver the error to the completion handler
0372         ec_delivered = true;
0373         if(status_ != status::closed)
0374             status_ = status::failed;
0375         return true;
0376     }
0377 
0378     // Change the status of the stream
0379     void
0380     change_status(status new_status)
0381     {
0382         switch(new_status)
0383         {
0384         case status::handshake:
0385             break;
0386 
0387         case status::open:
0388             break;
0389 
0390         case status::closing:
0391             //BOOST_ASSERT(status_ == status::open);
0392             break;
0393 
0394         case status::failed:
0395         case status::closed:
0396             // this->close(); // Is this right?
0397             break;
0398 
0399         default:
0400             break;
0401         }
0402         status_ = new_status;
0403     }
0404 
0405     // Called to disarm the idle timeout counter
0406     void
0407     reset_idle()
0408     {
0409         idle_counter = 0;
0410     }
0411 
0412     // Maintain the expiration timer
0413     template<class Executor>
0414     void
0415     update_timer(Executor const& ex)
0416     {
0417         switch(status_)
0418         {
0419         case status::handshake:
0420             BOOST_ASSERT(idle_counter == 0);
0421             if(! is_timer_set() &&
0422                 timeout_opt.handshake_timeout != none())
0423             {
0424                 timer.expires_after(
0425                     timeout_opt.handshake_timeout);
0426 
0427                 BOOST_ASIO_HANDLER_LOCATION((
0428                     __FILE__, __LINE__,
0429                     "websocket::check_stop_now"
0430                     ));
0431 
0432                 timer.async_wait(
0433                     timeout_handler<Executor>(
0434                         ex, this->weak_from_this()));
0435             }
0436             break;
0437 
0438         case status::open:
0439             if(timeout_opt.idle_timeout != none())
0440             {
0441                 idle_counter = 0;
0442                 if(timeout_opt.keep_alive_pings)
0443                     timer.expires_after(
0444                         timeout_opt.idle_timeout / 2);
0445                 else
0446                     timer.expires_after(
0447                         timeout_opt.idle_timeout);
0448 
0449                 BOOST_ASIO_HANDLER_LOCATION((
0450                     __FILE__, __LINE__,
0451                     "websocket::check_stop_now"
0452                     ));
0453 
0454                 timer.async_wait(
0455                     timeout_handler<Executor>(
0456                         ex, this->weak_from_this()));
0457             }
0458             else
0459             {
0460                 timer.cancel();
0461                 timer.expires_at(never());
0462             }
0463             break;
0464 
0465         case status::closing:
0466             if(timeout_opt.handshake_timeout != none())
0467             {
0468                 idle_counter = 0;
0469                 timer.expires_after(
0470                     timeout_opt.handshake_timeout);
0471 
0472                 BOOST_ASIO_HANDLER_LOCATION((
0473                     __FILE__, __LINE__,
0474                     "websocket::check_stop_now"
0475                     ));
0476 
0477                 timer.async_wait(
0478                     timeout_handler<Executor>(
0479                         ex, this->weak_from_this()));
0480             }
0481             else
0482             {
0483                 // VFALCO This assert goes off when there's also
0484                 // a pending read with the timer set. The bigger
0485                 // fix is to give close its own timeout, instead
0486                 // of using the handshake timeout.
0487                 // BOOST_ASSERT(! is_timer_set());
0488             }
0489             break;
0490 
0491         case status::failed:
0492         case status::closed:
0493             // this->close(); // Is this right?
0494             timer.cancel();
0495             timer.expires_at(never());
0496             break;
0497         }
0498     }
0499 
0500 private:
0501     template<class Executor>
0502     static net::execution_context&
0503     get_context(Executor const& ex,
0504         typename std::enable_if< net::execution::is_executor<Executor>::value >::type* = 0)
0505     {
0506         return net::query(ex, net::execution::context);
0507     }
0508 
0509     template<class Executor>
0510     static net::execution_context&
0511     get_context(Executor const& ex,
0512         typename std::enable_if< !net::execution::is_executor<Executor>::value >::type* = 0)
0513     {
0514         return ex.context();
0515     }
0516 
0517     bool
0518     is_timer_set() const
0519     {
0520         return timer.expiry() != never();
0521     }
0522 
0523     template<class Executor>
0524     class timeout_handler
0525         : boost::empty_value<Executor>
0526     {
0527         boost::weak_ptr<impl_type> wp_;
0528 
0529     public:
0530         timeout_handler(
0531             Executor const& ex,
0532             boost::weak_ptr<impl_type>&& wp)
0533             : boost::empty_value<Executor>(
0534                 boost::empty_init_t{}, ex)
0535             , wp_(std::move(wp))
0536         {
0537         }
0538 
0539         using executor_type = Executor;
0540 
0541         executor_type
0542         get_executor() const noexcept
0543         {
0544             return this->get();
0545         }
0546 
0547         void
0548         operator()(error_code ec)
0549         {
0550             // timer canceled?
0551             if(ec == net::error::operation_aborted)
0552                 return;
0553             BOOST_ASSERT(! ec);
0554 
0555             // stream destroyed?
0556             auto sp = wp_.lock();
0557             if(! sp)
0558                 return;
0559             auto& impl = *sp;
0560 
0561             switch(impl.status_)
0562             {
0563             case status::handshake:
0564                 impl.time_out();
0565                 return;
0566 
0567             case status::open:
0568                 // timeout was disabled
0569                 if(impl.timeout_opt.idle_timeout == none())
0570                     return;
0571 
0572                 if( impl.timeout_opt.keep_alive_pings &&
0573                     impl.idle_counter < 1)
0574                 {
0575                     {
0576                         BOOST_ASIO_HANDLER_LOCATION((
0577                             __FILE__, __LINE__,
0578                             "websocket::timeout_handler"
0579                             ));
0580 
0581                         idle_ping_op<Executor>(sp, get_executor());
0582                     }
0583                     ++impl.idle_counter;
0584                     impl.timer.expires_after(
0585                         impl.timeout_opt.idle_timeout / 2);
0586 
0587                     {
0588                         BOOST_ASIO_HANDLER_LOCATION((
0589                             __FILE__, __LINE__,
0590                             "websocket::timeout_handler"
0591                             ));
0592 
0593                         impl.timer.async_wait(std::move(*this));
0594                     }
0595                     return;
0596                 }
0597 
0598                 impl.time_out();
0599                 return;
0600 
0601             case status::closing:
0602                 impl.time_out();
0603                 return;
0604 
0605             case status::closed:
0606             case status::failed:
0607                 // nothing to do?
0608                 return;
0609             }
0610         }
0611     };
0612 };
0613 
0614 //--------------------------------------------------------------------------
0615 //
0616 // client
0617 //
0618 //--------------------------------------------------------------------------
0619 
0620 template<class NextLayer, bool deflateSupported>
0621 template<class Decorator>
0622 request_type
0623 stream<NextLayer, deflateSupported>::impl_type::
0624 build_request(
0625     detail::sec_ws_key_type& key,
0626     string_view host, string_view target,
0627     Decorator const& decorator)
0628 {
0629     request_type req;
0630     req.target(target);
0631     req.version(11);
0632     req.method(http::verb::get);
0633     req.set(http::field::host, host);
0634     req.set(http::field::upgrade, "websocket");
0635     req.set(http::field::connection, "Upgrade");
0636     detail::make_sec_ws_key(key);
0637     req.set(http::field::sec_websocket_key, to_string_view(key));
0638     req.set(http::field::sec_websocket_version, "13");
0639     this->build_request_pmd(req);
0640     decorator_opt(req);
0641     decorator(req);
0642     return req;
0643 }
0644 
0645 // Called when the WebSocket Upgrade response is received
0646 template<class NextLayer, bool deflateSupported>
0647 void
0648 stream<NextLayer, deflateSupported>::impl_type::
0649 on_response(
0650     response_type const& res,
0651     detail::sec_ws_key_type const& key,
0652     error_code& ec)
0653 {
0654     auto const err =
0655         [&](error e)
0656         {
0657             BOOST_BEAST_ASSIGN_EC(ec, e);
0658         };
0659     if(res.result() != http::status::switching_protocols)
0660         return err(error::upgrade_declined);
0661     if(res.version() != 11)
0662         return err(error::bad_http_version);
0663     {
0664         auto const it = res.find(http::field::connection);
0665         if(it == res.end())
0666             return err(error::no_connection);
0667         if(! http::token_list{it->value()}.exists("upgrade"))
0668             return err(error::no_connection_upgrade);
0669     }
0670     {
0671         auto const it = res.find(http::field::upgrade);
0672         if(it == res.end())
0673             return err(error::no_upgrade);
0674         if(! http::token_list{it->value()}.exists("websocket"))
0675             return err(error::no_upgrade_websocket);
0676     }
0677     {
0678         auto const it = res.find(
0679             http::field::sec_websocket_accept);
0680         if(it == res.end())
0681             return err(error::no_sec_accept);
0682         detail::sec_ws_accept_type acc;
0683         detail::make_sec_ws_accept(acc, to_string_view(key));
0684         if (to_string_view(acc).compare(it->value()) != 0)
0685             return err(error::bad_sec_accept);
0686     }
0687 
0688     ec = {};
0689     this->on_response_pmd(res);
0690     this->open(role_type::client);
0691 }
0692 
0693 //------------------------------------------------------------------------------
0694 
0695 // Attempt to read a complete frame header.
0696 // Returns `false` if more bytes are needed
0697 template<class NextLayer, bool deflateSupported>
0698 template<class DynamicBuffer>
0699 bool
0700 stream<NextLayer, deflateSupported>::impl_type::
0701 parse_fh(
0702     detail::frame_header& fh,
0703     DynamicBuffer& b,
0704     error_code& ec)
0705 {
0706     if(buffer_bytes(b.data()) < 2)
0707     {
0708         // need more bytes
0709         ec = {};
0710         return false;
0711     }
0712     buffers_suffix<typename
0713         DynamicBuffer::const_buffers_type> cb{
0714             b.data()};
0715     std::size_t need;
0716     {
0717         std::uint8_t tmp[2];
0718         cb.consume(net::buffer_copy(
0719             net::buffer(tmp), cb));
0720         fh.len = tmp[1] & 0x7f;
0721         switch(fh.len)
0722         {
0723             case 126: need = 2; break;
0724             case 127: need = 8; break;
0725             default:
0726                 need = 0;
0727         }
0728         fh.mask = (tmp[1] & 0x80) != 0;
0729         if(fh.mask)
0730             need += 4;
0731         if(buffer_bytes(cb) < need)
0732         {
0733             // need more bytes
0734             ec = {};
0735             return false;
0736         }
0737         fh.op   = static_cast<
0738             detail::opcode>(tmp[0] & 0x0f);
0739         fh.fin  = (tmp[0] & 0x80) != 0;
0740         fh.rsv1 = (tmp[0] & 0x40) != 0;
0741         fh.rsv2 = (tmp[0] & 0x20) != 0;
0742         fh.rsv3 = (tmp[0] & 0x10) != 0;
0743     }
0744     switch(fh.op)
0745     {
0746     case detail::opcode::binary:
0747     case detail::opcode::text:
0748         if(rd_cont)
0749         {
0750             // new data frame when continuation expected
0751             BOOST_BEAST_ASSIGN_EC(ec, error::bad_data_frame);
0752             return false;
0753         }
0754         if(fh.rsv2 || fh.rsv3 ||
0755             ! this->rd_deflated(fh.rsv1))
0756         {
0757             // reserved bits not cleared
0758             BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0759             return false;
0760         }
0761         break;
0762 
0763     case detail::opcode::cont:
0764         if(! rd_cont)
0765         {
0766             // continuation without an active message
0767             BOOST_BEAST_ASSIGN_EC(ec, error::bad_continuation);
0768             return false;
0769         }
0770         if(fh.rsv1 || fh.rsv2 || fh.rsv3)
0771         {
0772             // reserved bits not cleared
0773             BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0774             return false;
0775         }
0776         break;
0777 
0778     default:
0779         if(detail::is_reserved(fh.op))
0780         {
0781             // reserved opcode
0782             BOOST_BEAST_ASSIGN_EC(ec, error::bad_opcode);
0783             return false;
0784         }
0785         if(! fh.fin)
0786         {
0787             // fragmented control message
0788             BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_fragment);
0789             return false;
0790         }
0791         if(fh.len > 125)
0792         {
0793             // invalid length for control message
0794             BOOST_BEAST_ASSIGN_EC(ec, error::bad_control_size);
0795             return false;
0796         }
0797         if(fh.rsv1 || fh.rsv2 || fh.rsv3)
0798         {
0799             // reserved bits not cleared
0800             BOOST_BEAST_ASSIGN_EC(ec, error::bad_reserved_bits);
0801             return false;
0802         }
0803         break;
0804     }
0805     if(role == role_type::server && ! fh.mask)
0806     {
0807         // unmasked frame from client
0808         BOOST_BEAST_ASSIGN_EC(ec, error::bad_unmasked_frame);
0809         return false;
0810     }
0811     if(role == role_type::client && fh.mask)
0812     {
0813         // masked frame from server
0814         BOOST_BEAST_ASSIGN_EC(ec, error::bad_masked_frame);
0815         return false;
0816     }
0817     if(detail::is_control(fh.op) &&
0818         buffer_bytes(cb) < need + fh.len)
0819     {
0820         // Make the entire control frame payload
0821         // get read in before we return `true`
0822         return false;
0823     }
0824     switch(fh.len)
0825     {
0826     case 126:
0827     {
0828 
0829         std::uint16_t len_be;
0830         BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
0831         cb.consume(net::buffer_copy(
0832             net::mutable_buffer(&len_be, sizeof(len_be)), cb));
0833         fh.len = endian::big_to_native(len_be);
0834         if(fh.len < 126)
0835         {
0836             // length not canonical
0837             BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
0838             return false;
0839         }
0840         break;
0841     }
0842     case 127:
0843     {
0844         std::uint64_t len_be;
0845         BOOST_ASSERT(buffer_bytes(cb) >= sizeof(len_be));
0846         cb.consume(net::buffer_copy(
0847             net::mutable_buffer(&len_be, sizeof(len_be)), cb));
0848         fh.len = endian::big_to_native(len_be);
0849         if(fh.len < 65536)
0850         {
0851             // length not canonical
0852             BOOST_BEAST_ASSIGN_EC(ec, error::bad_size);
0853             return false;
0854         }
0855         break;
0856     }
0857     }
0858     if(fh.mask)
0859     {
0860         std::uint32_t key_le;
0861         BOOST_ASSERT(buffer_bytes(cb) >= sizeof(key_le));
0862         cb.consume(net::buffer_copy(
0863             net::mutable_buffer(&key_le, sizeof(key_le)), cb));
0864         fh.key = endian::little_to_native(key_le);
0865         detail::prepare_key(rd_key, fh.key);
0866     }
0867     else
0868     {
0869         // initialize this otherwise operator== breaks
0870         fh.key = 0;
0871     }
0872     if(! detail::is_control(fh.op))
0873     {
0874         if(fh.op != detail::opcode::cont)
0875         {
0876             rd_size = 0;
0877             rd_op = fh.op;
0878         }
0879         else
0880         {
0881             if(rd_size > (std::numeric_limits<
0882                 std::uint64_t>::max)() - fh.len)
0883             {
0884                 // message size exceeds configured limit
0885                 BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
0886                 return false;
0887             }
0888         }
0889         if(! this->rd_deflated())
0890         {
0891             if(rd_msg_max && beast::detail::sum_exceeds(
0892                 rd_size, fh.len, rd_msg_max))
0893             {
0894                 // message size exceeds configured limit
0895                 BOOST_BEAST_ASSIGN_EC(ec, error::message_too_big);
0896                 return false;
0897             }
0898         }
0899         rd_cont = ! fh.fin;
0900         rd_remain = fh.len;
0901     }
0902     b.consume(b.size() - buffer_bytes(cb));
0903     ec = {};
0904     return true;
0905 }
0906 
0907 template<class NextLayer, bool deflateSupported>
0908 template<class DynamicBuffer>
0909 void
0910 stream<NextLayer, deflateSupported>::impl_type::
0911 write_ping(DynamicBuffer& db,
0912     detail::opcode code, ping_data const& data)
0913 {
0914     detail::frame_header fh;
0915     fh.op = code;
0916     fh.fin = true;
0917     fh.rsv1 = false;
0918     fh.rsv2 = false;
0919     fh.rsv3 = false;
0920     fh.len = data.size();
0921     fh.mask = role == role_type::client;
0922     if(fh.mask)
0923         fh.key = create_mask();
0924     detail::write(db, fh);
0925     if(data.empty())
0926         return;
0927     detail::prepared_key key;
0928     if(fh.mask)
0929         detail::prepare_key(key, fh.key);
0930     auto mb = db.prepare(data.size());
0931     net::buffer_copy(mb,
0932         net::const_buffer(
0933             data.data(), data.size()));
0934     if(fh.mask)
0935         detail::mask_inplace(mb, key);
0936     db.commit(data.size());
0937 }
0938 
0939 template<class NextLayer, bool deflateSupported>
0940 template<class DynamicBuffer>
0941 void
0942 stream<NextLayer, deflateSupported>::impl_type::
0943 write_close(DynamicBuffer& db, close_reason const& cr)
0944 {
0945     using namespace boost::endian;
0946     detail::frame_header fh;
0947     fh.op = detail::opcode::close;
0948     fh.fin = true;
0949     fh.rsv1 = false;
0950     fh.rsv2 = false;
0951     fh.rsv3 = false;
0952     fh.len = cr.code == close_code::none ?
0953         0 : 2 + cr.reason.size();
0954     if(role == role_type::client)
0955     {
0956         fh.mask = true;
0957         fh.key = create_mask();
0958     }
0959     else
0960     {
0961         fh.mask = false;
0962     }
0963     detail::write(db, fh);
0964     if(cr.code != close_code::none)
0965     {
0966         detail::prepared_key key;
0967         if(fh.mask)
0968             detail::prepare_key(key, fh.key);
0969         {
0970             auto code_be = endian::native_to_big<std::uint16_t>(cr.code);
0971             auto mb = db.prepare(2);
0972             net::buffer_copy(mb,
0973                 net::const_buffer(&code_be, sizeof(code_be)));
0974             if(fh.mask)
0975                 detail::mask_inplace(mb, key);
0976             db.commit(2);
0977         }
0978         if(! cr.reason.empty())
0979         {
0980             auto mb = db.prepare(cr.reason.size());
0981             net::buffer_copy(mb,
0982                 net::const_buffer(
0983                     cr.reason.data(), cr.reason.size()));
0984             if(fh.mask)
0985                 detail::mask_inplace(mb, key);
0986             db.commit(cr.reason.size());
0987         }
0988     }
0989 }
0990 
0991 } // websocket
0992 } // beast
0993 } // boost
0994 
0995 #endif