File indexing completed on 2025-07-11 08:05:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
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/parser.hpp>
0017 #include <boost/beast/http/read.hpp>
0018 #include <boost/beast/http/string_body.hpp>
0019 #include <boost/beast/http/write.hpp>
0020 #include <boost/beast/core/async_base.hpp>
0021 #include <boost/beast/core/buffer_traits.hpp>
0022 #include <boost/beast/core/stream_traits.hpp>
0023 #include <boost/beast/core/detail/buffer.hpp>
0024 #include <boost/beast/version.hpp>
0025 #include <boost/asio/coroutine.hpp>
0026 #include <boost/assert.hpp>
0027 #include <boost/throw_exception.hpp>
0028 #include <memory>
0029 #include <type_traits>
0030
0031 namespace boost {
0032 namespace beast {
0033 namespace websocket {
0034
0035
0036
0037 namespace detail {
0038
0039 template<class Body, class Allocator>
0040 void
0041 impl_base<true>::
0042 build_response_pmd(
0043 http::response<http::string_body>& res,
0044 http::request<Body,
0045 http::basic_fields<Allocator>> const& req)
0046 {
0047 pmd_offer offer;
0048 pmd_offer unused;
0049 pmd_read(offer, req);
0050 pmd_negotiate(res, unused, offer, pmd_opts_);
0051 }
0052
0053 template<class Body, class Allocator>
0054 void
0055 impl_base<false>::
0056 build_response_pmd(
0057 http::response<http::string_body>&,
0058 http::request<Body,
0059 http::basic_fields<Allocator>> const&)
0060 {
0061 }
0062
0063 }
0064
0065 template<class NextLayer, bool deflateSupported>
0066 template<class Body, class Allocator, class Decorator>
0067 response_type
0068 stream<NextLayer, deflateSupported>::impl_type::
0069 build_response(
0070 http::request<Body,
0071 http::basic_fields<Allocator>> const& req,
0072 Decorator const& decorator,
0073 error_code& result)
0074 {
0075 auto const decorate =
0076 [this, &decorator](response_type& res)
0077 {
0078 decorator_opt(res);
0079 decorator(res);
0080 if(! res.count(http::field::server))
0081 res.set(http::field::server,
0082 string_view(BOOST_BEAST_VERSION_STRING));
0083 };
0084 auto err =
0085 [&](error e)
0086 {
0087 result = e;
0088 response_type res;
0089 res.version(req.version());
0090 res.result(http::status::bad_request);
0091 res.body() = result.message();
0092 res.prepare_payload();
0093 decorate(res);
0094 return res;
0095 };
0096 if(req.version() != 11)
0097 return err(error::bad_http_version);
0098 if(req.method() != http::verb::get)
0099 return err(error::bad_method);
0100 if(! req.count(http::field::host))
0101 return err(error::no_host);
0102 {
0103 auto const it = req.find(http::field::connection);
0104 if(it == req.end())
0105 return err(error::no_connection);
0106 if(! http::token_list{it->value()}.exists("upgrade"))
0107 return err(error::no_connection_upgrade);
0108 }
0109 {
0110 auto const it = req.find(http::field::upgrade);
0111 if(it == req.end())
0112 return err(error::no_upgrade);
0113 if(! http::token_list{it->value()}.exists("websocket"))
0114 return err(error::no_upgrade_websocket);
0115 }
0116 string_view key;
0117 {
0118 auto const it = req.find(http::field::sec_websocket_key);
0119 if(it == req.end())
0120 return err(error::no_sec_key);
0121 key = it->value();
0122 if(key.size() > detail::sec_ws_key_type::static_capacity)
0123 return err(error::bad_sec_key);
0124 }
0125 {
0126 auto const it = req.find(http::field::sec_websocket_version);
0127 if(it == req.end())
0128 return err(error::no_sec_version);
0129 if(it->value() != "13")
0130 {
0131 response_type res;
0132 res.result(http::status::upgrade_required);
0133 res.version(req.version());
0134 res.set(http::field::sec_websocket_version, "13");
0135 result = error::bad_sec_version;
0136 res.body() = result.message();
0137 res.prepare_payload();
0138 decorate(res);
0139 return res;
0140 }
0141 }
0142
0143 response_type res;
0144 res.result(http::status::switching_protocols);
0145 res.version(req.version());
0146 res.set(http::field::upgrade, "websocket");
0147 res.set(http::field::connection, "Upgrade");
0148 {
0149 detail::sec_ws_accept_type acc;
0150 detail::make_sec_ws_accept(acc, key);
0151 res.set(http::field::sec_websocket_accept, to_string_view(acc));
0152 }
0153 this->build_response_pmd(res, req);
0154 decorate(res);
0155 result = {};
0156 return res;
0157 }
0158
0159
0160
0161
0162
0163 template<class NextLayer, bool deflateSupported>
0164 template<class Handler>
0165 class stream<NextLayer, deflateSupported>::response_op
0166 : public beast::stable_async_base<
0167 Handler, beast::executor_type<stream>>
0168 , public asio::coroutine
0169 {
0170 boost::weak_ptr<impl_type> wp_;
0171 error_code result_;
0172 response_type& res_;
0173 http::response<http::empty_body> res_100_;
0174 bool needs_res_100_{false};
0175
0176 public:
0177 template<
0178 class Handler_,
0179 class Body, class Allocator,
0180 class Decorator>
0181 response_op(
0182 Handler_&& h,
0183 boost::shared_ptr<impl_type> const& sp,
0184 http::request<Body,
0185 http::basic_fields<Allocator>> const& req,
0186 Decorator const& decorator,
0187 bool cont = false)
0188 : stable_async_base<Handler,
0189 beast::executor_type<stream>>(
0190 std::forward<Handler_>(h),
0191 sp->stream().get_executor())
0192 , wp_(sp)
0193 , res_(beast::allocate_stable<response_type>(*this,
0194 sp->build_response(req, decorator, result_)))
0195 {
0196 auto itr = req.find(http::field::expect);
0197 if (itr != req.end() && iequals(itr->value(), "100-continue"))
0198 {
0199 res_100_.version(res_.version());
0200 res_100_.set(http::field::server, res_[http::field::server]);
0201 res_100_.result(http::status::continue_);
0202 res_100_.prepare_payload();
0203 needs_res_100_ = true;
0204 }
0205 (*this)({}, 0, cont);
0206 }
0207
0208 void operator()(
0209 error_code ec = {},
0210 std::size_t bytes_transferred = 0,
0211 bool cont = true)
0212 {
0213 boost::ignore_unused(bytes_transferred);
0214 auto sp = wp_.lock();
0215 if(! sp)
0216 {
0217 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0218 return this->complete(cont, ec);
0219 }
0220 auto& impl = *sp;
0221 BOOST_ASIO_CORO_REENTER(*this)
0222 {
0223 impl.change_status(status::handshake);
0224 impl.update_timer(this->get_executor());
0225
0226 if (needs_res_100_)
0227 {
0228 BOOST_ASIO_CORO_YIELD
0229 {
0230 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "websocket::async_accept"));
0231 http::async_write(
0232 impl.stream(), res_100_, std::move(*this));
0233 }
0234 }
0235
0236
0237 BOOST_ASIO_CORO_YIELD
0238 {
0239 BOOST_ASIO_HANDLER_LOCATION((
0240 __FILE__, __LINE__,
0241 "websocket::async_accept"));
0242
0243 http::async_write(
0244 impl.stream(), res_, std::move(*this));
0245 }
0246 if(impl.check_stop_now(ec))
0247 goto upcall;
0248 if(! ec)
0249 {
0250 BOOST_BEAST_ASSIGN_EC(ec, result_);
0251 BOOST_BEAST_ASSIGN_EC(ec, result_);
0252 }
0253 if(! ec)
0254 {
0255 impl.do_pmd_config(res_);
0256 impl.open(role_type::server);
0257 }
0258 upcall:
0259 this->complete(cont, ec);
0260 }
0261 }
0262 };
0263
0264
0265
0266
0267
0268
0269
0270
0271 template<class NextLayer, bool deflateSupported>
0272 template<class Handler, class Decorator>
0273 class stream<NextLayer, deflateSupported>::accept_op
0274 : public beast::stable_async_base<
0275 Handler, beast::executor_type<stream>>
0276 , public asio::coroutine
0277 {
0278 boost::weak_ptr<impl_type> wp_;
0279 http::request_parser<http::empty_body>& p_;
0280 Decorator d_;
0281
0282 public:
0283 template<class Handler_, class Buffers>
0284 accept_op(
0285 Handler_&& h,
0286 boost::shared_ptr<impl_type> const& sp,
0287 Decorator const& decorator,
0288 Buffers const& buffers)
0289 : stable_async_base<Handler,
0290 beast::executor_type<stream>>(
0291 std::forward<Handler_>(h),
0292 sp->stream().get_executor())
0293 , wp_(sp)
0294 , p_(beast::allocate_stable<
0295 http::request_parser<http::empty_body>>(*this))
0296 , d_(decorator)
0297 {
0298 auto& impl = *sp;
0299 error_code ec;
0300 auto const mb =
0301 beast::detail::dynamic_buffer_prepare(
0302 impl.rd_buf, buffer_bytes(buffers),
0303 ec, error::buffer_overflow);
0304 if(! ec)
0305 impl.rd_buf.commit(
0306 net::buffer_copy(*mb, buffers));
0307 (*this)(ec);
0308 }
0309
0310 void operator()(
0311 error_code ec = {},
0312 std::size_t bytes_transferred = 0,
0313 bool cont = true)
0314 {
0315 boost::ignore_unused(bytes_transferred);
0316 auto sp = wp_.lock();
0317 if(! sp)
0318 {
0319 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0320 return this->complete(cont, ec);
0321 }
0322 auto& impl = *sp;
0323 BOOST_ASIO_CORO_REENTER(*this)
0324 {
0325 impl.change_status(status::handshake);
0326 impl.update_timer(this->get_executor());
0327
0328
0329 if(ec)
0330 goto upcall;
0331
0332 BOOST_ASIO_CORO_YIELD
0333 {
0334 BOOST_ASIO_HANDLER_LOCATION((
0335 __FILE__, __LINE__,
0336 "websocket::async_accept"));
0337
0338 http::async_read(impl.stream(),
0339 impl.rd_buf, p_, std::move(*this));
0340 }
0341 if(ec == http::error::end_of_stream)
0342 {
0343 BOOST_BEAST_ASSIGN_EC(ec, error::closed);
0344 }
0345 if(impl.check_stop_now(ec))
0346 goto upcall;
0347
0348 {
0349
0350
0351
0352 auto const req = p_.release();
0353 auto const decorator = d_;
0354
0355 response_op<Handler>(
0356 this->release_handler(),
0357 sp, req, decorator, true);
0358 return;
0359 }
0360
0361 upcall:
0362 this->complete(cont, ec);
0363 }
0364 }
0365 };
0366
0367 template<class NextLayer, bool deflateSupported>
0368 struct stream<NextLayer, deflateSupported>::
0369 run_response_op
0370 {
0371 boost::shared_ptr<impl_type> const& self;
0372
0373 using executor_type = typename stream::executor_type;
0374
0375 executor_type
0376 get_executor() const noexcept
0377 {
0378 return self->stream().get_executor();
0379 }
0380
0381 template<
0382 class AcceptHandler,
0383 class Body, class Allocator,
0384 class Decorator>
0385 void
0386 operator()(
0387 AcceptHandler&& h,
0388 http::request<Body,
0389 http::basic_fields<Allocator>> const* m,
0390 Decorator const& d)
0391 {
0392
0393
0394
0395
0396 static_assert(
0397 beast::detail::is_invocable<AcceptHandler,
0398 void(error_code)>::value,
0399 "AcceptHandler type requirements not met");
0400
0401 response_op<
0402 typename std::decay<AcceptHandler>::type>(
0403 std::forward<AcceptHandler>(h), self, *m, d);
0404 }
0405 };
0406
0407 template<class NextLayer, bool deflateSupported>
0408 struct stream<NextLayer, deflateSupported>::
0409 run_accept_op
0410 {
0411 boost::shared_ptr<impl_type> const& self;
0412
0413 using executor_type = typename stream::executor_type;
0414
0415 executor_type
0416 get_executor() const noexcept
0417 {
0418 return self->stream().get_executor();
0419 }
0420
0421 template<
0422 class AcceptHandler,
0423 class Decorator,
0424 class Buffers>
0425 void
0426 operator()(
0427 AcceptHandler&& h,
0428 Decorator const& d,
0429 Buffers const& b)
0430 {
0431
0432
0433
0434
0435 static_assert(
0436 beast::detail::is_invocable<AcceptHandler,
0437 void(error_code)>::value,
0438 "AcceptHandler type requirements not met");
0439
0440 accept_op<
0441 typename std::decay<AcceptHandler>::type,
0442 Decorator>(
0443 std::forward<AcceptHandler>(h),
0444 self,
0445 d,
0446 b);
0447 }
0448 };
0449
0450
0451
0452 template<class NextLayer, bool deflateSupported>
0453 template<class Body, class Allocator,
0454 class Decorator>
0455 void
0456 stream<NextLayer, deflateSupported>::
0457 do_accept(
0458 http::request<Body,
0459 http::basic_fields<Allocator>> const& req,
0460 Decorator const& decorator,
0461 error_code& ec)
0462 {
0463 impl_->change_status(status::handshake);
0464
0465 error_code result;
0466 auto const res = impl_->build_response(req, decorator, result);
0467
0468 auto itr = req.find(http::field::expect);
0469 if (itr != req.end() && iequals(itr->value(), "100-continue"))
0470 {
0471 http::response<http::empty_body> res_100;
0472 res_100.version(res.version());
0473 res_100.set(http::field::server, res[http::field::server]);
0474 res_100.result(http::status::continue_);
0475 res_100.prepare_payload();
0476 http::write(impl_->stream(), res_100, ec);
0477 if (ec)
0478 return;
0479 }
0480
0481 http::write(impl_->stream(), res, ec);
0482 if(ec)
0483 return;
0484 BOOST_BEAST_ASSIGN_EC(ec, result);
0485 if(ec)
0486 {
0487
0488
0489 return;
0490 }
0491 impl_->do_pmd_config(res);
0492 impl_->open(role_type::server);
0493 }
0494
0495 template<class NextLayer, bool deflateSupported>
0496 template<class Buffers, class Decorator>
0497 void
0498 stream<NextLayer, deflateSupported>::
0499 do_accept(
0500 Buffers const& buffers,
0501 Decorator const& decorator,
0502 error_code& ec)
0503 {
0504 impl_->reset();
0505 auto const mb =
0506 beast::detail::dynamic_buffer_prepare(
0507 impl_->rd_buf, buffer_bytes(buffers), ec,
0508 error::buffer_overflow);
0509 if(ec)
0510 return;
0511 impl_->rd_buf.commit(net::buffer_copy(*mb, buffers));
0512
0513 http::request_parser<http::empty_body> p;
0514 http::read(next_layer(), impl_->rd_buf, p, ec);
0515 if(ec == http::error::end_of_stream)
0516 {
0517 BOOST_BEAST_ASSIGN_EC(ec, error::closed);
0518 }
0519 if(ec)
0520 return;
0521 do_accept(p.get(), decorator, ec);
0522 }
0523
0524
0525
0526 template<class NextLayer, bool deflateSupported>
0527 void
0528 stream<NextLayer, deflateSupported>::
0529 accept()
0530 {
0531 static_assert(is_sync_stream<next_layer_type>::value,
0532 "SyncStream type requirements not met");
0533 error_code ec;
0534 accept(ec);
0535 if(ec)
0536 BOOST_THROW_EXCEPTION(system_error{ec});
0537 }
0538
0539 template<class NextLayer, bool deflateSupported>
0540 void
0541 stream<NextLayer, deflateSupported>::
0542 accept(error_code& ec)
0543 {
0544 static_assert(is_sync_stream<next_layer_type>::value,
0545 "SyncStream type requirements not met");
0546 do_accept(
0547 net::const_buffer{},
0548 &default_decorate_res, ec);
0549 }
0550
0551 template<class NextLayer, bool deflateSupported>
0552 template<class ConstBufferSequence>
0553 typename std::enable_if<! http::detail::is_header<
0554 ConstBufferSequence>::value>::type
0555 stream<NextLayer, deflateSupported>::
0556 accept(ConstBufferSequence const& buffers)
0557 {
0558 static_assert(is_sync_stream<next_layer_type>::value,
0559 "SyncStream type requirements not met");
0560 static_assert(net::is_const_buffer_sequence<
0561 ConstBufferSequence>::value,
0562 "ConstBufferSequence type requirements not met");
0563 error_code ec;
0564 accept(buffers, ec);
0565 if(ec)
0566 BOOST_THROW_EXCEPTION(system_error{ec});
0567 }
0568 template<class NextLayer, bool deflateSupported>
0569 template<class ConstBufferSequence>
0570 typename std::enable_if<! http::detail::is_header<
0571 ConstBufferSequence>::value>::type
0572 stream<NextLayer, deflateSupported>::
0573 accept(
0574 ConstBufferSequence const& buffers, error_code& ec)
0575 {
0576 static_assert(is_sync_stream<next_layer_type>::value,
0577 "SyncStream type requirements not met");
0578 static_assert(net::is_const_buffer_sequence<
0579 ConstBufferSequence>::value,
0580 "ConstBufferSequence type requirements not met");
0581 do_accept(buffers, &default_decorate_res, ec);
0582 }
0583
0584
0585 template<class NextLayer, bool deflateSupported>
0586 template<class Body, class Allocator>
0587 void
0588 stream<NextLayer, deflateSupported>::
0589 accept(
0590 http::request<Body,
0591 http::basic_fields<Allocator>> const& req)
0592 {
0593 static_assert(is_sync_stream<next_layer_type>::value,
0594 "SyncStream type requirements not met");
0595 error_code ec;
0596 accept(req, ec);
0597 if(ec)
0598 BOOST_THROW_EXCEPTION(system_error{ec});
0599 }
0600
0601 template<class NextLayer, bool deflateSupported>
0602 template<class Body, class Allocator>
0603 void
0604 stream<NextLayer, deflateSupported>::
0605 accept(
0606 http::request<Body,
0607 http::basic_fields<Allocator>> const& req,
0608 error_code& ec)
0609 {
0610 static_assert(is_sync_stream<next_layer_type>::value,
0611 "SyncStream type requirements not met");
0612 impl_->reset();
0613 do_accept(req, &default_decorate_res, ec);
0614 }
0615
0616
0617
0618 template<class NextLayer, bool deflateSupported>
0619 template<
0620 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0621 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0622 stream<NextLayer, deflateSupported>::
0623 async_accept(
0624 AcceptHandler&& handler,
0625 typename std::enable_if<
0626 ! net::is_const_buffer_sequence<
0627 AcceptHandler>::value>::type*
0628 )
0629 {
0630 static_assert(is_async_stream<next_layer_type>::value,
0631 "AsyncStream type requirements not met");
0632 impl_->reset();
0633 return net::async_initiate<
0634 AcceptHandler,
0635 void(error_code)>(
0636 run_accept_op{impl_},
0637 handler,
0638 &default_decorate_res,
0639 net::const_buffer{});
0640 }
0641
0642 template<class NextLayer, bool deflateSupported>
0643 template<
0644 class ConstBufferSequence,
0645 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0646 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0647 stream<NextLayer, deflateSupported>::
0648 async_accept(
0649 ConstBufferSequence const& buffers,
0650 AcceptHandler&& handler,
0651 typename std::enable_if<
0652 net::is_const_buffer_sequence<
0653 ConstBufferSequence>::value>::type*,
0654 typename std::enable_if<
0655 ! http::detail::is_header<
0656 ConstBufferSequence>::value>::type*
0657 )
0658 {
0659 static_assert(is_async_stream<next_layer_type>::value,
0660 "AsyncStream type requirements not met");
0661 static_assert(net::is_const_buffer_sequence<
0662 ConstBufferSequence>::value,
0663 "ConstBufferSequence type requirements not met");
0664 impl_->reset();
0665 return net::async_initiate<
0666 AcceptHandler,
0667 void(error_code)>(
0668 run_accept_op{impl_},
0669 handler,
0670 &default_decorate_res,
0671 buffers);
0672 }
0673
0674 template<class NextLayer, bool deflateSupported>
0675 template<
0676 class Body, class Allocator,
0677 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
0678 BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
0679 stream<NextLayer, deflateSupported>::
0680 async_accept(
0681 http::request<Body, http::basic_fields<Allocator>> const& req,
0682 AcceptHandler&& handler)
0683 {
0684 static_assert(is_async_stream<next_layer_type>::value,
0685 "AsyncStream type requirements not met");
0686 impl_->reset();
0687 return net::async_initiate<
0688 AcceptHandler,
0689 void(error_code)>(
0690 run_response_op{impl_},
0691 handler,
0692 &req,
0693 &default_decorate_res);
0694 }
0695
0696 }
0697 }
0698 }
0699
0700 #endif