File indexing completed on 2025-09-18 08:36:08
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 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
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
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
0135
0136
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
0156
0157
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
0172 d_.fb.clear();
0173 }
0174 if(impl.check_stop_now(ec))
0175 goto upcall;
0176
0177
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
0211
0212
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
0260
0261
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
0274
0275
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
0295 *res_p = p.release();
0296 }
0297 else
0298 {
0299
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 }
0414 }
0415 }
0416
0417 #endif