Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:29:01

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