Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:05:55

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_ACCEPT_IPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
0012 
0013 #include <boost/beast/websocket/impl/stream_impl.hpp>
0014 #include <boost/beast/websocket/detail/type_traits.hpp>
0015 #include <boost/beast/http/empty_body.hpp>
0016 #include <boost/beast/http/parser.hpp>
0017 #include <boost/beast/http/read.hpp>
0018 #include <boost/beast/http/string_body.hpp>
0019 #include <boost/beast/http/write.hpp>
0020 #include <boost/beast/core/async_base.hpp>
0021 #include <boost/beast/core/buffer_traits.hpp>
0022 #include <boost/beast/core/stream_traits.hpp>
0023 #include <boost/beast/core/detail/buffer.hpp>
0024 #include <boost/beast/version.hpp>
0025 #include <boost/asio/coroutine.hpp>
0026 #include <boost/assert.hpp>
0027 #include <boost/throw_exception.hpp>
0028 #include <memory>
0029 #include <type_traits>
0030 
0031 namespace boost {
0032 namespace beast {
0033 namespace websocket {
0034 
0035 //------------------------------------------------------------------------------
0036 
0037 namespace detail {
0038 
0039 template<class Body, class Allocator>
0040 void
0041 impl_base<true>::
0042 build_response_pmd(
0043     http::response<http::string_body>& res,
0044     http::request<Body,
0045         http::basic_fields<Allocator>> const& req)
0046 {
0047     pmd_offer offer;
0048     pmd_offer unused;
0049     pmd_read(offer, req);
0050     pmd_negotiate(res, unused, offer, pmd_opts_);
0051 }
0052 
0053 template<class Body, class Allocator>
0054 void
0055 impl_base<false>::
0056 build_response_pmd(
0057     http::response<http::string_body>&,
0058     http::request<Body,
0059         http::basic_fields<Allocator>> const&)
0060 {
0061 }
0062 
0063 } // detail
0064 
0065 template<class NextLayer, bool deflateSupported>
0066 template<class Body, class Allocator, class Decorator>
0067 response_type
0068 stream<NextLayer, deflateSupported>::impl_type::
0069 build_response(
0070     http::request<Body,
0071         http::basic_fields<Allocator>> const& req,
0072     Decorator const& decorator,
0073     error_code& result)
0074 {
0075     auto const decorate =
0076         [this, &decorator](response_type& res)
0077         {
0078             decorator_opt(res);
0079             decorator(res);
0080             if(! res.count(http::field::server))
0081                 res.set(http::field::server,
0082                     string_view(BOOST_BEAST_VERSION_STRING));
0083         };
0084     auto err =
0085         [&](error e)
0086         {
0087             result = e;
0088             response_type res;
0089             res.version(req.version());
0090             res.result(http::status::bad_request);
0091             res.body() = result.message();
0092             res.prepare_payload();
0093             decorate(res);
0094             return res;
0095         };
0096     if(req.version() != 11)
0097         return err(error::bad_http_version);
0098     if(req.method() != http::verb::get)
0099         return err(error::bad_method);
0100     if(! req.count(http::field::host))
0101         return err(error::no_host);
0102     {
0103         auto const it = req.find(http::field::connection);
0104         if(it == req.end())
0105             return err(error::no_connection);
0106         if(! http::token_list{it->value()}.exists("upgrade"))
0107             return err(error::no_connection_upgrade);
0108     }
0109     {
0110         auto const it = req.find(http::field::upgrade);
0111         if(it == req.end())
0112             return err(error::no_upgrade);
0113         if(! http::token_list{it->value()}.exists("websocket"))
0114             return err(error::no_upgrade_websocket);
0115     }
0116     string_view key;
0117     {
0118         auto const it = req.find(http::field::sec_websocket_key);
0119         if(it == req.end())
0120             return err(error::no_sec_key);
0121         key = it->value();
0122         if(key.size() > detail::sec_ws_key_type::static_capacity)
0123             return err(error::bad_sec_key);
0124     }
0125     {
0126         auto const it = req.find(http::field::sec_websocket_version);
0127         if(it == req.end())
0128             return err(error::no_sec_version);
0129         if(it->value() != "13")
0130         {
0131             response_type res;
0132             res.result(http::status::upgrade_required);
0133             res.version(req.version());
0134             res.set(http::field::sec_websocket_version, "13");
0135             result = error::bad_sec_version;
0136             res.body() = result.message();
0137             res.prepare_payload();
0138             decorate(res);
0139             return res;
0140         }
0141     }
0142 
0143     response_type res;
0144     res.result(http::status::switching_protocols);
0145     res.version(req.version());
0146     res.set(http::field::upgrade, "websocket");
0147     res.set(http::field::connection, "Upgrade");
0148     {
0149         detail::sec_ws_accept_type acc;
0150         detail::make_sec_ws_accept(acc, key);
0151         res.set(http::field::sec_websocket_accept, to_string_view(acc));
0152     }
0153     this->build_response_pmd(res, req);
0154     decorate(res);
0155     result = {};
0156     return res;
0157 }
0158 
0159 //------------------------------------------------------------------------------
0160 
0161 /** Respond to an HTTP request
0162 */
0163 template<class NextLayer, bool deflateSupported>
0164 template<class Handler>
0165 class stream<NextLayer, deflateSupported>::response_op
0166     : public beast::stable_async_base<
0167         Handler, beast::executor_type<stream>>
0168     , public asio::coroutine
0169 {
0170     boost::weak_ptr<impl_type> wp_;
0171     error_code result_; // must come before res_
0172     response_type& res_;
0173     http::response<http::empty_body> res_100_;
0174     bool needs_res_100_{false};
0175 
0176 public:
0177     template<
0178         class Handler_,
0179         class Body, class Allocator,
0180         class Decorator>
0181     response_op(
0182         Handler_&& h,
0183         boost::shared_ptr<impl_type> const& sp,
0184         http::request<Body,
0185             http::basic_fields<Allocator>> const& req,
0186         Decorator const& decorator,
0187         bool cont = false)
0188         : stable_async_base<Handler,
0189             beast::executor_type<stream>>(
0190                 std::forward<Handler_>(h),
0191                     sp->stream().get_executor())
0192         , wp_(sp)
0193         , res_(beast::allocate_stable<response_type>(*this,
0194             sp->build_response(req, decorator, result_)))
0195     {
0196         auto itr = req.find(http::field::expect);
0197         if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
0198         {
0199             res_100_.version(res_.version());
0200             res_100_.set(http::field::server, res_[http::field::server]);
0201             res_100_.result(http::status::continue_);
0202             res_100_.prepare_payload();
0203             needs_res_100_ = true;
0204         }
0205         (*this)({}, 0, cont);
0206     }
0207 
0208     void operator()(
0209         error_code ec = {},
0210         std::size_t bytes_transferred = 0,
0211         bool cont = true)
0212     {
0213         boost::ignore_unused(bytes_transferred);
0214         auto sp = wp_.lock();
0215         if(! sp)
0216         {
0217             BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0218             return this->complete(cont, ec);
0219         }
0220         auto& impl = *sp;
0221         BOOST_ASIO_CORO_REENTER(*this)
0222         {
0223             impl.change_status(status::handshake);
0224             impl.update_timer(this->get_executor());
0225 
0226             if (needs_res_100_)
0227             {
0228                 BOOST_ASIO_CORO_YIELD
0229                 {
0230                     BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "websocket::async_accept"));
0231                     http::async_write(
0232                             impl.stream(), res_100_, std::move(*this));
0233                 }
0234             }
0235 
0236             // Send response
0237             BOOST_ASIO_CORO_YIELD
0238             {
0239                 BOOST_ASIO_HANDLER_LOCATION((
0240                     __FILE__, __LINE__,
0241                     "websocket::async_accept"));
0242 
0243                 http::async_write(
0244                     impl.stream(), res_, std::move(*this));
0245             }
0246             if(impl.check_stop_now(ec))
0247                 goto upcall;
0248             if(! ec)
0249             {
0250                 BOOST_BEAST_ASSIGN_EC(ec, result_);
0251                 BOOST_BEAST_ASSIGN_EC(ec, result_);
0252             }
0253             if(! ec)
0254             {
0255                 impl.do_pmd_config(res_);
0256                 impl.open(role_type::server);
0257             }
0258         upcall:
0259             this->complete(cont, ec);
0260         }
0261     }
0262 };
0263 
0264 //------------------------------------------------------------------------------
0265 
0266 // read and respond to an upgrade request
0267 //
0268 // Cancellation: the async_accept cancellation can be terminal
0269 // because it will just interrupt the reading of the header.
0270 //
0271 template<class NextLayer, bool deflateSupported>
0272 template<class Handler, class Decorator>
0273 class stream<NextLayer, deflateSupported>::accept_op
0274     : public beast::stable_async_base<
0275         Handler, beast::executor_type<stream>>
0276     , public asio::coroutine
0277 {
0278     boost::weak_ptr<impl_type> wp_;
0279     http::request_parser<http::empty_body>& p_;
0280     Decorator d_;
0281 
0282 public:
0283     template<class Handler_, class Buffers>
0284     accept_op(
0285         Handler_&& h,
0286         boost::shared_ptr<impl_type> const& sp,
0287         Decorator const& decorator,
0288         Buffers const& buffers)
0289         : stable_async_base<Handler,
0290             beast::executor_type<stream>>(
0291                 std::forward<Handler_>(h),
0292                     sp->stream().get_executor())
0293         , wp_(sp)
0294         , p_(beast::allocate_stable<
0295             http::request_parser<http::empty_body>>(*this))
0296         , d_(decorator)
0297     {
0298         auto& impl = *sp;
0299         error_code ec;
0300         auto const mb =
0301             beast::detail::dynamic_buffer_prepare(
0302             impl.rd_buf, buffer_bytes(buffers),
0303                 ec, error::buffer_overflow);
0304         if(! ec)
0305             impl.rd_buf.commit(
0306                 net::buffer_copy(*mb, buffers));
0307         (*this)(ec);
0308     }
0309 
0310     void operator()(
0311         error_code ec = {},
0312         std::size_t bytes_transferred = 0,
0313         bool cont = true)
0314     {
0315         boost::ignore_unused(bytes_transferred);
0316         auto sp = wp_.lock();
0317         if(! sp)
0318         {
0319             BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0320             return this->complete(cont, ec);
0321         }
0322         auto& impl = *sp;
0323         BOOST_ASIO_CORO_REENTER(*this)
0324         {
0325             impl.change_status(status::handshake);
0326             impl.update_timer(this->get_executor());
0327 
0328             // The constructor could have set ec
0329             if(ec)
0330                 goto upcall;
0331 
0332             BOOST_ASIO_CORO_YIELD
0333             {
0334                 BOOST_ASIO_HANDLER_LOCATION((
0335                     __FILE__, __LINE__,
0336                     "websocket::async_accept"));
0337 
0338                 http::async_read(impl.stream(),
0339                     impl.rd_buf, p_, std::move(*this));
0340             }
0341             if(ec == http::error::end_of_stream)
0342             {
0343                 BOOST_BEAST_ASSIGN_EC(ec, error::closed);
0344             }
0345             if(impl.check_stop_now(ec))
0346                 goto upcall;
0347 
0348             {
0349                 // Arguments from our state must be
0350                 // moved to the stack before releasing
0351                 // the handler.
0352                 auto const req = p_.release();
0353                 auto const decorator = d_;
0354 
0355                 response_op<Handler>(
0356                     this->release_handler(),
0357                         sp, req, decorator, true);
0358                 return;
0359             }
0360 
0361         upcall:
0362             this->complete(cont, ec);
0363         }
0364     }
0365 };
0366 
0367 template<class NextLayer, bool deflateSupported>
0368 struct stream<NextLayer, deflateSupported>::
0369     run_response_op
0370 {
0371     boost::shared_ptr<impl_type> const& self;
0372 
0373     using executor_type = typename stream::executor_type;
0374 
0375     executor_type
0376     get_executor() const noexcept
0377     {
0378         return self->stream().get_executor();
0379     }
0380 
0381     template<
0382         class AcceptHandler,
0383         class Body, class Allocator,
0384         class Decorator>
0385     void
0386     operator()(
0387         AcceptHandler&& h,
0388         http::request<Body,
0389             http::basic_fields<Allocator>> const* m,
0390         Decorator const& d)
0391     {
0392         // If you get an error on the following line it means
0393         // that your handler does not meet the documented type
0394         // requirements for the handler.
0395 
0396         static_assert(
0397             beast::detail::is_invocable<AcceptHandler,
0398                 void(error_code)>::value,
0399             "AcceptHandler type requirements not met");
0400 
0401         response_op<
0402             typename std::decay<AcceptHandler>::type>(
0403                 std::forward<AcceptHandler>(h), self, *m, d);
0404     }
0405 };
0406 
0407 template<class NextLayer, bool deflateSupported>
0408 struct stream<NextLayer, deflateSupported>::
0409     run_accept_op
0410 {
0411     boost::shared_ptr<impl_type> const& self;
0412 
0413     using executor_type = typename stream::executor_type;
0414 
0415     executor_type
0416     get_executor() const noexcept
0417     {
0418         return self->stream().get_executor();
0419     }
0420 
0421     template<
0422         class AcceptHandler,
0423         class Decorator,
0424         class Buffers>
0425     void
0426     operator()(
0427         AcceptHandler&& h,
0428         Decorator const& d,
0429         Buffers const& b)
0430     {
0431         // If you get an error on the following line it means
0432         // that your handler does not meet the documented type
0433         // requirements for the handler.
0434 
0435         static_assert(
0436             beast::detail::is_invocable<AcceptHandler,
0437                 void(error_code)>::value,
0438             "AcceptHandler type requirements not met");
0439 
0440         accept_op<
0441             typename std::decay<AcceptHandler>::type,
0442             Decorator>(
0443                 std::forward<AcceptHandler>(h),
0444                 self,
0445                 d,
0446                 b);
0447     }
0448 };
0449 
0450 //------------------------------------------------------------------------------
0451 
0452 template<class NextLayer, bool deflateSupported>
0453 template<class Body, class Allocator,
0454     class Decorator>
0455 void
0456 stream<NextLayer, deflateSupported>::
0457 do_accept(
0458     http::request<Body,
0459         http::basic_fields<Allocator>> const& req,
0460     Decorator const& decorator,
0461     error_code& ec)
0462 {
0463     impl_->change_status(status::handshake);
0464 
0465     error_code result;
0466     auto const res = impl_->build_response(req, decorator, result);
0467 
0468     auto itr = req.find(http::field::expect);
0469     if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
0470     {
0471         http::response<http::empty_body> res_100;
0472         res_100.version(res.version());
0473         res_100.set(http::field::server, res[http::field::server]);
0474         res_100.result(http::status::continue_);
0475         res_100.prepare_payload();
0476         http::write(impl_->stream(), res_100, ec);
0477         if (ec)
0478             return;
0479     }
0480 
0481     http::write(impl_->stream(), res, ec);
0482     if(ec)
0483         return;
0484     BOOST_BEAST_ASSIGN_EC(ec, result);
0485     if(ec)
0486     {
0487         // VFALCO TODO Respect keep alive setting, perform
0488         //             teardown if Connection: close.
0489         return;
0490     }
0491     impl_->do_pmd_config(res);
0492     impl_->open(role_type::server);
0493 }
0494 
0495 template<class NextLayer, bool deflateSupported>
0496 template<class Buffers, class Decorator>
0497 void
0498 stream<NextLayer, deflateSupported>::
0499 do_accept(
0500     Buffers const& buffers,
0501     Decorator const& decorator,
0502     error_code& ec)
0503 {
0504     impl_->reset();
0505     auto const mb =
0506         beast::detail::dynamic_buffer_prepare(
0507         impl_->rd_buf, buffer_bytes(buffers), ec,
0508             error::buffer_overflow);
0509     if(ec)
0510         return;
0511     impl_->rd_buf.commit(net::buffer_copy(*mb, buffers));
0512 
0513     http::request_parser<http::empty_body> p;
0514     http::read(next_layer(), impl_->rd_buf, p, ec);
0515     if(ec == http::error::end_of_stream)
0516     {
0517         BOOST_BEAST_ASSIGN_EC(ec, error::closed);
0518     }
0519     if(ec)
0520         return;
0521     do_accept(p.get(), decorator, ec);
0522 }
0523 
0524 //------------------------------------------------------------------------------
0525 
0526 template<class NextLayer, bool deflateSupported>
0527 void
0528 stream<NextLayer, deflateSupported>::
0529 accept()
0530 {
0531     static_assert(is_sync_stream<next_layer_type>::value,
0532         "SyncStream type requirements not met");
0533     error_code ec;
0534     accept(ec);
0535     if(ec)
0536         BOOST_THROW_EXCEPTION(system_error{ec});
0537 }
0538 
0539 template<class NextLayer, bool deflateSupported>
0540 void
0541 stream<NextLayer, deflateSupported>::
0542 accept(error_code& ec)
0543 {
0544     static_assert(is_sync_stream<next_layer_type>::value,
0545         "SyncStream type requirements not met");
0546     do_accept(
0547         net::const_buffer{},
0548         &default_decorate_res, ec);
0549 }
0550 
0551 template<class NextLayer, bool deflateSupported>
0552 template<class ConstBufferSequence>
0553 typename std::enable_if<! http::detail::is_header<
0554     ConstBufferSequence>::value>::type
0555 stream<NextLayer, deflateSupported>::
0556 accept(ConstBufferSequence const& buffers)
0557 {
0558     static_assert(is_sync_stream<next_layer_type>::value,
0559         "SyncStream type requirements not met");
0560     static_assert(net::is_const_buffer_sequence<
0561         ConstBufferSequence>::value,
0562             "ConstBufferSequence type requirements not met");
0563     error_code ec;
0564     accept(buffers, ec);
0565     if(ec)
0566         BOOST_THROW_EXCEPTION(system_error{ec});
0567 }
0568 template<class NextLayer, bool deflateSupported>
0569 template<class ConstBufferSequence>
0570 typename std::enable_if<! http::detail::is_header<
0571     ConstBufferSequence>::value>::type
0572 stream<NextLayer, deflateSupported>::
0573 accept(
0574     ConstBufferSequence const& buffers, error_code& ec)
0575 {
0576     static_assert(is_sync_stream<next_layer_type>::value,
0577         "SyncStream type requirements not met");
0578     static_assert(net::is_const_buffer_sequence<
0579         ConstBufferSequence>::value,
0580             "ConstBufferSequence type requirements not met");
0581     do_accept(buffers, &default_decorate_res, ec);
0582 }
0583 
0584 
0585 template<class NextLayer, bool deflateSupported>
0586 template<class Body, class Allocator>
0587 void
0588 stream<NextLayer, deflateSupported>::
0589 accept(
0590     http::request<Body,
0591         http::basic_fields<Allocator>> const& req)
0592 {
0593     static_assert(is_sync_stream<next_layer_type>::value,
0594         "SyncStream type requirements not met");
0595     error_code ec;
0596     accept(req, ec);
0597     if(ec)
0598         BOOST_THROW_EXCEPTION(system_error{ec});
0599 }
0600 
0601 template<class NextLayer, bool deflateSupported>
0602 template<class Body, class Allocator>
0603 void
0604 stream<NextLayer, deflateSupported>::
0605 accept(
0606     http::request<Body,
0607         http::basic_fields<Allocator>> const& req,
0608     error_code& ec)
0609 {
0610     static_assert(is_sync_stream<next_layer_type>::value,
0611         "SyncStream type requirements not met");
0612     impl_->reset();
0613     do_accept(req, &default_decorate_res, ec);
0614 }
0615 
0616 //------------------------------------------------------------------------------
0617 
0618 template<class NextLayer, bool deflateSupported>
0619 template<
0620     BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0621 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0622 stream<NextLayer, deflateSupported>::
0623 async_accept(
0624     AcceptHandler&& handler,
0625     typename std::enable_if<
0626         ! net::is_const_buffer_sequence<
0627         AcceptHandler>::value>::type*
0628 )
0629 {
0630     static_assert(is_async_stream<next_layer_type>::value,
0631         "AsyncStream type requirements not met");
0632     impl_->reset();
0633     return net::async_initiate<
0634         AcceptHandler,
0635         void(error_code)>(
0636             run_accept_op{impl_},
0637             handler,
0638             &default_decorate_res,
0639             net::const_buffer{});
0640 }
0641 
0642 template<class NextLayer, bool deflateSupported>
0643 template<
0644     class ConstBufferSequence,
0645     BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0646 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0647 stream<NextLayer, deflateSupported>::
0648 async_accept(
0649     ConstBufferSequence const& buffers,
0650     AcceptHandler&& handler,
0651     typename std::enable_if<
0652         net::is_const_buffer_sequence<
0653         ConstBufferSequence>::value>::type*,
0654     typename std::enable_if<
0655         ! http::detail::is_header<
0656         ConstBufferSequence>::value>::type*
0657 )
0658 {
0659     static_assert(is_async_stream<next_layer_type>::value,
0660         "AsyncStream type requirements not met");
0661     static_assert(net::is_const_buffer_sequence<
0662         ConstBufferSequence>::value,
0663             "ConstBufferSequence type requirements not met");
0664     impl_->reset();
0665     return net::async_initiate<
0666         AcceptHandler,
0667         void(error_code)>(
0668             run_accept_op{impl_},
0669             handler,
0670             &default_decorate_res,
0671             buffers);
0672 }
0673 
0674 template<class NextLayer, bool deflateSupported>
0675 template<
0676     class Body, class Allocator,
0677     BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0678 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0679 stream<NextLayer, deflateSupported>::
0680 async_accept(
0681     http::request<Body, http::basic_fields<Allocator>> const& req,
0682     AcceptHandler&& handler)
0683 {
0684     static_assert(is_async_stream<next_layer_type>::value,
0685         "AsyncStream type requirements not met");
0686     impl_->reset();
0687     return net::async_initiate<
0688         AcceptHandler,
0689         void(error_code)>(
0690             run_response_op{impl_},
0691             handler,
0692             &req,
0693             &default_decorate_res);
0694 }
0695 
0696 } // websocket
0697 } // beast
0698 } // boost
0699 
0700 #endif