Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:36:08

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_HANDSHAKE_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_HPP
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/message.hpp>
0017 #include <boost/beast/http/read.hpp>
0018 #include <boost/beast/http/write.hpp>
0019 #include <boost/beast/core/async_base.hpp>
0020 #include <boost/beast/core/flat_buffer.hpp>
0021 #include <boost/beast/core/stream_traits.hpp>
0022 #include <boost/asio/coroutine.hpp>
0023 #include <boost/assert.hpp>
0024 #include <boost/throw_exception.hpp>
0025 #include <memory>
0026 
0027 namespace boost {
0028 namespace beast {
0029 namespace websocket {
0030 
0031 //------------------------------------------------------------------------------
0032 
0033 // send the upgrade request and process the response
0034 //
0035 template<class NextLayer, bool deflateSupported>
0036 template<class Handler>
0037 class stream<NextLayer, deflateSupported>::handshake_op
0038     : public beast::stable_async_base<Handler,
0039         beast::executor_type<stream>>
0040     , public asio::coroutine
0041 {
0042     struct data
0043     {
0044         // VFALCO This really should be two separate
0045         //        composed operations, to save on memory
0046         request_type req;
0047         http::response_parser<
0048             typename response_type::body_type> p;
0049         flat_buffer fb;
0050         bool overflow = false; // could be a member of the op
0051 
0052         explicit
0053         data(request_type&& req_)
0054             : req(std::move(req_))
0055         {
0056         }
0057     };
0058 
0059     boost::weak_ptr<impl_type> wp_;
0060     detail::sec_ws_key_type key_;
0061     response_type* res_p_;
0062     data& d_;
0063 
0064 public:
0065     template<class Handler_>
0066     handshake_op(
0067         Handler_&& h,
0068         boost::shared_ptr<impl_type> const& sp,
0069         request_type&& req,
0070         detail::sec_ws_key_type key,
0071         response_type* res_p)
0072         : stable_async_base<Handler,
0073             beast::executor_type<stream>>(
0074                 std::forward<Handler_>(h),
0075                     sp->stream().get_executor())
0076         , wp_(sp)
0077         , key_(key)
0078         , res_p_(res_p)
0079         , d_(beast::allocate_stable<data>(
0080             *this, std::move(req)))
0081     {
0082         sp->reset(); // VFALCO I don't like this
0083         if(res_p)
0084             res_p->result(http::status::internal_server_error);
0085         (*this)({}, 0, false);
0086     }
0087 
0088     void
0089     operator()(
0090         error_code ec = {},
0091         std::size_t bytes_used = 0,
0092         bool cont = true)
0093     {
0094         boost::ignore_unused(bytes_used);
0095         auto sp = wp_.lock();
0096         if(! sp)
0097         {
0098             BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0099             return this->complete(cont, ec);
0100         }
0101         auto& impl = *sp;
0102         BOOST_ASIO_CORO_REENTER(*this)
0103         {
0104             impl.change_status(status::handshake);
0105             impl.update_timer(this->get_executor());
0106 
0107             // write HTTP request
0108             impl.do_pmd_config(d_.req);
0109             BOOST_ASIO_CORO_YIELD
0110             {
0111                 BOOST_ASIO_HANDLER_LOCATION((
0112                     __FILE__, __LINE__,
0113                     "websocket::async_handshake"));
0114 
0115                 http::async_write(impl.stream(),
0116                     d_.req, std::move(*this));
0117             }
0118             if(impl.check_stop_now(ec))
0119                 goto upcall;
0120 
0121             // read HTTP response
0122             BOOST_ASIO_CORO_YIELD
0123             {
0124                 BOOST_ASIO_HANDLER_LOCATION((
0125                     __FILE__, __LINE__,
0126                     "websocket::async_handshake"));
0127 
0128                 http::async_read(impl.stream(),
0129                     impl.rd_buf, d_.p,
0130                         std::move(*this));
0131             }
0132             if(ec == http::error::buffer_overflow)
0133             {
0134                 // If the response overflows the internal
0135                 // read buffer, switch to a dynamically
0136                 // allocated flat buffer.
0137 
0138                 d_.fb.commit(net::buffer_copy(
0139                     d_.fb.prepare(impl.rd_buf.size()),
0140                     impl.rd_buf.data()));
0141                 impl.rd_buf.clear();
0142 
0143                 BOOST_ASIO_CORO_YIELD
0144                 {
0145                     BOOST_ASIO_HANDLER_LOCATION((
0146                         __FILE__, __LINE__,
0147                         "websocket::async_handshake"));
0148 
0149                     http::async_read(impl.stream(),
0150                         d_.fb, d_.p, std::move(*this));
0151                 }
0152 
0153                 if(! ec)
0154                 {
0155                     // Copy any leftovers back into the read
0156                     // buffer, since this represents websocket
0157                     // frame data.
0158 
0159                     if(d_.fb.size() <= impl.rd_buf.capacity())
0160                     {
0161                         impl.rd_buf.commit(net::buffer_copy(
0162                             impl.rd_buf.prepare(d_.fb.size()),
0163                             d_.fb.data()));
0164                     }
0165                     else
0166                     {
0167                         BOOST_BEAST_ASSIGN_EC(ec, http::error::buffer_overflow);
0168                     }
0169                 }
0170 
0171                 // Do this before the upcall
0172                 d_.fb.clear();
0173             }
0174             if(impl.check_stop_now(ec))
0175                 goto upcall;
0176 
0177             // success
0178             impl.reset_idle();
0179             impl.on_response(d_.p.get(), key_, ec);
0180             if(res_p_)
0181                 swap(d_.p.get(), *res_p_);
0182 
0183         upcall:
0184             this->complete(cont ,ec);
0185         }
0186     }
0187 };
0188 
0189 template<class NextLayer, bool deflateSupported>
0190 struct stream<NextLayer, deflateSupported>::
0191     run_handshake_op
0192 {
0193     boost::shared_ptr<impl_type> const& self;
0194 
0195     using executor_type = typename stream::executor_type;
0196 
0197     executor_type
0198     get_executor() const noexcept
0199     {
0200         return self->stream().get_executor();
0201     }
0202 
0203     template<class HandshakeHandler>
0204     void operator()(
0205         HandshakeHandler&& h,
0206         request_type&& req,
0207         detail::sec_ws_key_type key,
0208         response_type* res_p)
0209     {
0210         // If you get an error on the following line it means
0211         // that your handler does not meet the documented type
0212         // requirements for the handler.
0213 
0214         static_assert(
0215             beast::detail::is_invocable<HandshakeHandler,
0216                 void(error_code)>::value,
0217             "HandshakeHandler type requirements not met");
0218 
0219         handshake_op<
0220             typename std::decay<HandshakeHandler>::type>(
0221                 std::forward<HandshakeHandler>(h),
0222                     self, std::move(req), key, res_p);
0223     }
0224 };
0225 
0226 //------------------------------------------------------------------------------
0227 
0228 template<class NextLayer, bool deflateSupported>
0229 template<class RequestDecorator>
0230 void
0231 stream<NextLayer, deflateSupported>::
0232 do_handshake(
0233     response_type* res_p,
0234     string_view host,
0235     string_view target,
0236     RequestDecorator const& decorator,
0237     error_code& ec)
0238 {
0239     if(res_p)
0240         res_p->result(http::status::internal_server_error);
0241 
0242     auto& impl = *impl_;
0243     impl.change_status(status::handshake);
0244     impl.reset();
0245     detail::sec_ws_key_type key;
0246     {
0247         auto const req = impl.build_request(
0248             key, host, target, decorator);
0249         impl.do_pmd_config(req);
0250         http::write(impl.stream(), req, ec);
0251     }
0252     if(impl.check_stop_now(ec))
0253         return;
0254     http::response_parser<
0255         typename response_type::body_type> p;
0256     http::read(next_layer(), impl.rd_buf, p, ec);
0257     if(ec == http::error::buffer_overflow)
0258     {
0259         // If the response overflows the internal
0260         // read buffer, switch to a dynamically
0261         // allocated flat buffer.
0262 
0263         flat_buffer fb;
0264         fb.commit(net::buffer_copy(
0265             fb.prepare(impl.rd_buf.size()),
0266             impl.rd_buf.data()));
0267         impl.rd_buf.clear();
0268 
0269         http::read(next_layer(), fb, p, ec);;
0270 
0271         if(! ec)
0272         {
0273             // Copy any leftovers back into the read
0274             // buffer, since this represents websocket
0275             // frame data.
0276 
0277             if(fb.size() <= impl.rd_buf.capacity())
0278             {
0279                 impl.rd_buf.commit(net::buffer_copy(
0280                     impl.rd_buf.prepare(fb.size()),
0281                     fb.data()));
0282             }
0283             else
0284             {
0285                 BOOST_BEAST_ASSIGN_EC(ec, http::error::buffer_overflow);
0286             }
0287         }
0288     }
0289     if(impl.check_stop_now(ec))
0290         return;
0291 
0292     if (res_p)
0293     {
0294         // If res_p is not null, move parser's response into it.
0295         *res_p = p.release();
0296     }
0297     else
0298     {
0299         // Otherwise point res_p at the response in the parser.
0300         res_p = &p.get();
0301     }
0302 
0303     impl.on_response(*res_p, key, ec);
0304 }
0305 
0306 //------------------------------------------------------------------------------
0307 
0308 template<class NextLayer, bool deflateSupported>
0309 template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
0310 BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
0311 stream<NextLayer, deflateSupported>::
0312 async_handshake(
0313     string_view host,
0314     string_view target,
0315     HandshakeHandler&& handler)
0316 {
0317     static_assert(is_async_stream<next_layer_type>::value,
0318         "AsyncStream type requirements not met");
0319     detail::sec_ws_key_type key;
0320     auto req = impl_->build_request(
0321         key, host, target, &default_decorate_req);
0322     return net::async_initiate<
0323         HandshakeHandler,
0324         void(error_code)>(
0325             run_handshake_op{impl_},
0326             handler,
0327             std::move(req),
0328             key,
0329             nullptr);
0330 }
0331 
0332 template<class NextLayer, bool deflateSupported>
0333 template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
0334 BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
0335 stream<NextLayer, deflateSupported>::
0336 async_handshake(
0337     response_type& res,
0338     string_view host,
0339     string_view target,
0340     HandshakeHandler&& handler)
0341 {
0342     static_assert(is_async_stream<next_layer_type>::value,
0343         "AsyncStream type requirements not met");
0344     detail::sec_ws_key_type key;
0345     auto req = impl_->build_request(
0346         key, host, target, &default_decorate_req);
0347     return net::async_initiate<
0348         HandshakeHandler,
0349         void(error_code)>(
0350             run_handshake_op{impl_},
0351             handler,
0352             std::move(req),
0353             key,
0354             &res);
0355 }
0356 
0357 template<class NextLayer, bool deflateSupported>
0358 void
0359 stream<NextLayer, deflateSupported>::
0360 handshake(string_view host,
0361     string_view target)
0362 {
0363     static_assert(is_sync_stream<next_layer_type>::value,
0364         "SyncStream type requirements not met");
0365     error_code ec;
0366     handshake(
0367         host, target, ec);
0368     if(ec)
0369         BOOST_THROW_EXCEPTION(system_error{ec});
0370 }
0371 
0372 template<class NextLayer, bool deflateSupported>
0373 void
0374 stream<NextLayer, deflateSupported>::
0375 handshake(response_type& res,
0376     string_view host,
0377         string_view target)
0378 {
0379     static_assert(is_sync_stream<next_layer_type>::value,
0380         "SyncStream type requirements not met");
0381     error_code ec;
0382     handshake(res, host, target, ec);
0383     if(ec)
0384         BOOST_THROW_EXCEPTION(system_error{ec});
0385 }
0386 
0387 template<class NextLayer, bool deflateSupported>
0388 void
0389 stream<NextLayer, deflateSupported>::
0390 handshake(string_view host,
0391     string_view target, error_code& ec)
0392 {
0393     static_assert(is_sync_stream<next_layer_type>::value,
0394         "SyncStream type requirements not met");
0395     do_handshake(nullptr,
0396         host, target, &default_decorate_req, ec);
0397 }
0398 
0399 template<class NextLayer, bool deflateSupported>
0400 void
0401 stream<NextLayer, deflateSupported>::
0402 handshake(response_type& res,
0403     string_view host,
0404         string_view target,
0405             error_code& ec)
0406 {
0407     static_assert(is_sync_stream<next_layer_type>::value,
0408         "SyncStream type requirements not met");
0409     do_handshake(&res,
0410         host, target, &default_decorate_req, ec);
0411 }
0412 
0413 } // websocket
0414 } // beast
0415 } // boost
0416 
0417 #endif