Back to home page

EIC code displayed by LXR

 
 

    


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

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     template<class HandshakeHandler>
0192     void operator()(
0193         HandshakeHandler&& h,
0194         boost::shared_ptr<impl_type> const& sp,
0195         request_type&& req,
0196         detail::sec_ws_key_type key,
0197         response_type* res_p)
0198     {
0199         // If you get an error on the following line it means
0200         // that your handler does not meet the documented type
0201         // requirements for the handler.
0202 
0203         static_assert(
0204             beast::detail::is_invocable<HandshakeHandler,
0205                 void(error_code)>::value,
0206             "HandshakeHandler type requirements not met");
0207 
0208         handshake_op<
0209             typename std::decay<HandshakeHandler>::type>(
0210                 std::forward<HandshakeHandler>(h),
0211                     sp, std::move(req), key, res_p);
0212     }
0213 };
0214 
0215 //------------------------------------------------------------------------------
0216 
0217 template<class NextLayer, bool deflateSupported>
0218 template<class RequestDecorator>
0219 void
0220 stream<NextLayer, deflateSupported>::
0221 do_handshake(
0222     response_type* res_p,
0223     string_view host,
0224     string_view target,
0225     RequestDecorator const& decorator,
0226     error_code& ec)
0227 {
0228     if(res_p)
0229         res_p->result(http::status::internal_server_error);
0230 
0231     auto& impl = *impl_;
0232     impl.change_status(status::handshake);
0233     impl.reset();
0234     detail::sec_ws_key_type key;
0235     {
0236         auto const req = impl.build_request(
0237             key, host, target, decorator);
0238         impl.do_pmd_config(req);
0239         http::write(impl.stream(), req, ec);
0240     }
0241     if(impl.check_stop_now(ec))
0242         return;
0243     http::response_parser<
0244         typename response_type::body_type> p;
0245     http::read(next_layer(), impl.rd_buf, p, ec);
0246     if(ec == http::error::buffer_overflow)
0247     {
0248         // If the response overflows the internal
0249         // read buffer, switch to a dynamically
0250         // allocated flat buffer.
0251 
0252         flat_buffer fb;
0253         fb.commit(net::buffer_copy(
0254             fb.prepare(impl.rd_buf.size()),
0255             impl.rd_buf.data()));
0256         impl.rd_buf.clear();
0257 
0258         http::read(next_layer(), fb, p, ec);;
0259 
0260         if(! ec)
0261         {
0262             // Copy any leftovers back into the read
0263             // buffer, since this represents websocket
0264             // frame data.
0265 
0266             if(fb.size() <= impl.rd_buf.capacity())
0267             {
0268                 impl.rd_buf.commit(net::buffer_copy(
0269                     impl.rd_buf.prepare(fb.size()),
0270                     fb.data()));
0271             }
0272             else
0273             {
0274                 BOOST_BEAST_ASSIGN_EC(ec, http::error::buffer_overflow);
0275             }
0276         }
0277     }
0278     if(impl.check_stop_now(ec))
0279         return;
0280 
0281     if (res_p)
0282     {
0283         // If res_p is not null, move parser's response into it.
0284         *res_p = p.release();
0285     }
0286     else
0287     {
0288         // Otherwise point res_p at the response in the parser.
0289         res_p = &p.get();
0290     }
0291 
0292     impl.on_response(*res_p, key, ec);
0293 }
0294 
0295 //------------------------------------------------------------------------------
0296 
0297 template<class NextLayer, bool deflateSupported>
0298 template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
0299 BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
0300 stream<NextLayer, deflateSupported>::
0301 async_handshake(
0302     string_view host,
0303     string_view target,
0304     HandshakeHandler&& handler)
0305 {
0306     static_assert(is_async_stream<next_layer_type>::value,
0307         "AsyncStream type requirements not met");
0308     detail::sec_ws_key_type key;
0309     auto req = impl_->build_request(
0310         key, host, target, &default_decorate_req);
0311     return net::async_initiate<
0312         HandshakeHandler,
0313         void(error_code)>(
0314             run_handshake_op{},
0315             handler,
0316             impl_,
0317             std::move(req),
0318             key,
0319             nullptr);
0320 }
0321 
0322 template<class NextLayer, bool deflateSupported>
0323 template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler>
0324 BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
0325 stream<NextLayer, deflateSupported>::
0326 async_handshake(
0327     response_type& res,
0328     string_view host,
0329     string_view target,
0330     HandshakeHandler&& handler)
0331 {
0332     static_assert(is_async_stream<next_layer_type>::value,
0333         "AsyncStream type requirements not met");
0334     detail::sec_ws_key_type key;
0335     auto req = impl_->build_request(
0336         key, host, target, &default_decorate_req);
0337     res.result(http::status::internal_server_error);
0338     return net::async_initiate<
0339         HandshakeHandler,
0340         void(error_code)>(
0341             run_handshake_op{},
0342             handler,
0343             impl_,
0344             std::move(req),
0345             key,
0346             &res);
0347 }
0348 
0349 template<class NextLayer, bool deflateSupported>
0350 void
0351 stream<NextLayer, deflateSupported>::
0352 handshake(string_view host,
0353     string_view target)
0354 {
0355     static_assert(is_sync_stream<next_layer_type>::value,
0356         "SyncStream type requirements not met");
0357     error_code ec;
0358     handshake(
0359         host, target, ec);
0360     if(ec)
0361         BOOST_THROW_EXCEPTION(system_error{ec});
0362 }
0363 
0364 template<class NextLayer, bool deflateSupported>
0365 void
0366 stream<NextLayer, deflateSupported>::
0367 handshake(response_type& res,
0368     string_view host,
0369         string_view target)
0370 {
0371     static_assert(is_sync_stream<next_layer_type>::value,
0372         "SyncStream type requirements not met");
0373     error_code ec;
0374     handshake(res, host, target, ec);
0375     if(ec)
0376         BOOST_THROW_EXCEPTION(system_error{ec});
0377 }
0378 
0379 template<class NextLayer, bool deflateSupported>
0380 void
0381 stream<NextLayer, deflateSupported>::
0382 handshake(string_view host,
0383     string_view target, error_code& ec)
0384 {
0385     static_assert(is_sync_stream<next_layer_type>::value,
0386         "SyncStream type requirements not met");
0387     do_handshake(nullptr,
0388         host, target, &default_decorate_req, ec);
0389 }
0390 
0391 template<class NextLayer, bool deflateSupported>
0392 void
0393 stream<NextLayer, deflateSupported>::
0394 handshake(response_type& res,
0395     string_view host,
0396         string_view target,
0397             error_code& ec)
0398 {
0399     static_assert(is_sync_stream<next_layer_type>::value,
0400         "SyncStream type requirements not met");
0401     do_handshake(&res,
0402         host, target, &default_decorate_req, ec);
0403 }
0404 
0405 } // websocket
0406 } // beast
0407 } // boost
0408 
0409 #endif