File indexing completed on 2025-07-15 08:29:01
0001
0002
0003
0004
0005
0006
0007
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
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
0045
0046 request_type req;
0047 http::response_parser<
0048 typename response_type::body_type> p;
0049 flat_buffer fb;
0050 bool overflow = false;
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();
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
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
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
0133
0134
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
0154
0155
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
0170 d_.fb.clear();
0171 }
0172 if(impl.check_stop_now(ec))
0173 goto upcall;
0174
0175
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
0209
0210
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
0258
0259
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
0272
0273
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
0293 *res_p = p.release();
0294 }
0295 else
0296 {
0297
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 }
0413 }
0414 }
0415
0416 #endif