accept.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
  10. #define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
  11. #include <boost/beast/websocket/impl/stream_impl.hpp>
  12. #include <boost/beast/websocket/detail/type_traits.hpp>
  13. #include <boost/beast/http/empty_body.hpp>
  14. #include <boost/beast/http/parser.hpp>
  15. #include <boost/beast/http/read.hpp>
  16. #include <boost/beast/http/string_body.hpp>
  17. #include <boost/beast/http/write.hpp>
  18. #include <boost/beast/core/async_base.hpp>
  19. #include <boost/beast/core/buffer_traits.hpp>
  20. #include <boost/beast/core/stream_traits.hpp>
  21. #include <boost/beast/core/detail/buffer.hpp>
  22. #include <boost/beast/version.hpp>
  23. #include <boost/asio/coroutine.hpp>
  24. #include <boost/asio/post.hpp>
  25. #include <boost/assert.hpp>
  26. #include <boost/throw_exception.hpp>
  27. #include <memory>
  28. #include <type_traits>
  29. namespace boost {
  30. namespace beast {
  31. namespace websocket {
  32. //------------------------------------------------------------------------------
  33. namespace detail {
  34. template<class Body, class Allocator>
  35. void
  36. impl_base<true>::
  37. build_response_pmd(
  38. http::response<http::string_body>& res,
  39. http::request<Body,
  40. http::basic_fields<Allocator>> const& req)
  41. {
  42. pmd_offer offer;
  43. pmd_offer unused;
  44. pmd_read(offer, req);
  45. pmd_negotiate(res, unused, offer, pmd_opts_);
  46. }
  47. template<class Body, class Allocator>
  48. void
  49. impl_base<false>::
  50. build_response_pmd(
  51. http::response<http::string_body>&,
  52. http::request<Body,
  53. http::basic_fields<Allocator>> const&)
  54. {
  55. }
  56. } // detail
  57. template<class NextLayer, bool deflateSupported>
  58. template<class Body, class Allocator, class Decorator>
  59. response_type
  60. stream<NextLayer, deflateSupported>::impl_type::
  61. build_response(
  62. http::request<Body,
  63. http::basic_fields<Allocator>> const& req,
  64. Decorator const& decorator,
  65. error_code& result)
  66. {
  67. auto const decorate =
  68. [this, &decorator](response_type& res)
  69. {
  70. decorator_opt(res);
  71. decorator(res);
  72. if(! res.count(http::field::server))
  73. res.set(http::field::server,
  74. string_view(BOOST_BEAST_VERSION_STRING));
  75. };
  76. auto err =
  77. [&](error e)
  78. {
  79. result = e;
  80. response_type res;
  81. res.version(req.version());
  82. res.result(http::status::bad_request);
  83. res.body() = result.message();
  84. res.prepare_payload();
  85. decorate(res);
  86. return res;
  87. };
  88. if(req.version() != 11)
  89. return err(error::bad_http_version);
  90. if(req.method() != http::verb::get)
  91. return err(error::bad_method);
  92. if(! req.count(http::field::host))
  93. return err(error::no_host);
  94. {
  95. auto const it = req.find(http::field::connection);
  96. if(it == req.end())
  97. return err(error::no_connection);
  98. if(! http::token_list{it->value()}.exists("upgrade"))
  99. return err(error::no_connection_upgrade);
  100. }
  101. {
  102. auto const it = req.find(http::field::upgrade);
  103. if(it == req.end())
  104. return err(error::no_upgrade);
  105. if(! http::token_list{it->value()}.exists("websocket"))
  106. return err(error::no_upgrade_websocket);
  107. }
  108. string_view key;
  109. {
  110. auto const it = req.find(http::field::sec_websocket_key);
  111. if(it == req.end())
  112. return err(error::no_sec_key);
  113. key = it->value();
  114. if(key.size() > detail::sec_ws_key_type::max_size_n)
  115. return err(error::bad_sec_key);
  116. }
  117. {
  118. auto const it = req.find(http::field::sec_websocket_version);
  119. if(it == req.end())
  120. return err(error::no_sec_version);
  121. if(it->value() != "13")
  122. {
  123. response_type res;
  124. res.result(http::status::upgrade_required);
  125. res.version(req.version());
  126. res.set(http::field::sec_websocket_version, "13");
  127. result = error::bad_sec_version;
  128. res.body() = result.message();
  129. res.prepare_payload();
  130. decorate(res);
  131. return res;
  132. }
  133. }
  134. response_type res;
  135. res.result(http::status::switching_protocols);
  136. res.version(req.version());
  137. res.set(http::field::upgrade, "websocket");
  138. res.set(http::field::connection, "upgrade");
  139. {
  140. detail::sec_ws_accept_type acc;
  141. detail::make_sec_ws_accept(acc, key);
  142. res.set(http::field::sec_websocket_accept, acc);
  143. }
  144. this->build_response_pmd(res, req);
  145. decorate(res);
  146. result = {};
  147. return res;
  148. }
  149. //------------------------------------------------------------------------------
  150. /** Respond to an HTTP request
  151. */
  152. template<class NextLayer, bool deflateSupported>
  153. template<class Handler>
  154. class stream<NextLayer, deflateSupported>::response_op
  155. : public beast::stable_async_base<
  156. Handler, beast::executor_type<stream>>
  157. , public asio::coroutine
  158. {
  159. boost::weak_ptr<impl_type> wp_;
  160. error_code result_; // must come before res_
  161. response_type& res_;
  162. public:
  163. template<
  164. class Handler_,
  165. class Body, class Allocator,
  166. class Decorator>
  167. response_op(
  168. Handler_&& h,
  169. boost::shared_ptr<impl_type> const& sp,
  170. http::request<Body,
  171. http::basic_fields<Allocator>> const& req,
  172. Decorator const& decorator,
  173. bool cont = false)
  174. : stable_async_base<Handler,
  175. beast::executor_type<stream>>(
  176. std::forward<Handler_>(h),
  177. sp->stream().get_executor())
  178. , wp_(sp)
  179. , res_(beast::allocate_stable<response_type>(*this,
  180. sp->build_response(req, decorator, result_)))
  181. {
  182. (*this)({}, 0, cont);
  183. }
  184. void operator()(
  185. error_code ec = {},
  186. std::size_t bytes_transferred = 0,
  187. bool cont = true)
  188. {
  189. boost::ignore_unused(bytes_transferred);
  190. auto sp = wp_.lock();
  191. if(! sp)
  192. {
  193. ec = net::error::operation_aborted;
  194. return this->complete(cont, ec);
  195. }
  196. auto& impl = *sp;
  197. BOOST_ASIO_CORO_REENTER(*this)
  198. {
  199. impl.change_status(status::handshake);
  200. impl.update_timer(this->get_executor());
  201. // Send response
  202. BOOST_ASIO_CORO_YIELD
  203. {
  204. BOOST_ASIO_HANDLER_LOCATION((
  205. __FILE__, __LINE__,
  206. "websocket::async_accept"));
  207. http::async_write(
  208. impl.stream(), res_, std::move(*this));
  209. }
  210. if(impl.check_stop_now(ec))
  211. goto upcall;
  212. if(! ec)
  213. ec = result_;
  214. if(! ec)
  215. {
  216. impl.do_pmd_config(res_);
  217. impl.open(role_type::server);
  218. }
  219. upcall:
  220. this->complete(cont, ec);
  221. }
  222. }
  223. };
  224. //------------------------------------------------------------------------------
  225. // read and respond to an upgrade request
  226. //
  227. template<class NextLayer, bool deflateSupported>
  228. template<class Handler, class Decorator>
  229. class stream<NextLayer, deflateSupported>::accept_op
  230. : public beast::stable_async_base<
  231. Handler, beast::executor_type<stream>>
  232. , public asio::coroutine
  233. {
  234. boost::weak_ptr<impl_type> wp_;
  235. http::request_parser<http::empty_body>& p_;
  236. Decorator d_;
  237. public:
  238. template<class Handler_, class Buffers>
  239. accept_op(
  240. Handler_&& h,
  241. boost::shared_ptr<impl_type> const& sp,
  242. Decorator const& decorator,
  243. Buffers const& buffers)
  244. : stable_async_base<Handler,
  245. beast::executor_type<stream>>(
  246. std::forward<Handler_>(h),
  247. sp->stream().get_executor())
  248. , wp_(sp)
  249. , p_(beast::allocate_stable<
  250. http::request_parser<http::empty_body>>(*this))
  251. , d_(decorator)
  252. {
  253. auto& impl = *sp;
  254. error_code ec;
  255. auto const mb =
  256. beast::detail::dynamic_buffer_prepare(
  257. impl.rd_buf, buffer_bytes(buffers),
  258. ec, error::buffer_overflow);
  259. if(! ec)
  260. impl.rd_buf.commit(
  261. net::buffer_copy(*mb, buffers));
  262. (*this)(ec);
  263. }
  264. void operator()(
  265. error_code ec = {},
  266. std::size_t bytes_transferred = 0,
  267. bool cont = true)
  268. {
  269. boost::ignore_unused(bytes_transferred);
  270. auto sp = wp_.lock();
  271. if(! sp)
  272. {
  273. ec = net::error::operation_aborted;
  274. return this->complete(cont, ec);
  275. }
  276. auto& impl = *sp;
  277. BOOST_ASIO_CORO_REENTER(*this)
  278. {
  279. impl.change_status(status::handshake);
  280. impl.update_timer(this->get_executor());
  281. // The constructor could have set ec
  282. if(ec)
  283. goto upcall;
  284. BOOST_ASIO_CORO_YIELD
  285. {
  286. BOOST_ASIO_HANDLER_LOCATION((
  287. __FILE__, __LINE__,
  288. "websocket::async_accept"));
  289. http::async_read(impl.stream(),
  290. impl.rd_buf, p_, std::move(*this));
  291. }
  292. if(ec == http::error::end_of_stream)
  293. ec = error::closed;
  294. if(impl.check_stop_now(ec))
  295. goto upcall;
  296. {
  297. // Arguments from our state must be
  298. // moved to the stack before releasing
  299. // the handler.
  300. auto const req = p_.release();
  301. auto const decorator = d_;
  302. response_op<Handler>(
  303. this->release_handler(),
  304. sp, req, decorator, true);
  305. return;
  306. }
  307. upcall:
  308. this->complete(cont, ec);
  309. }
  310. }
  311. };
  312. template<class NextLayer, bool deflateSupported>
  313. struct stream<NextLayer, deflateSupported>::
  314. run_response_op
  315. {
  316. template<
  317. class AcceptHandler,
  318. class Body, class Allocator,
  319. class Decorator>
  320. void
  321. operator()(
  322. AcceptHandler&& h,
  323. boost::shared_ptr<impl_type> const& sp,
  324. http::request<Body,
  325. http::basic_fields<Allocator>> const* m,
  326. Decorator const& d)
  327. {
  328. // If you get an error on the following line it means
  329. // that your handler does not meet the documented type
  330. // requirements for the handler.
  331. static_assert(
  332. beast::detail::is_invocable<AcceptHandler,
  333. void(error_code)>::value,
  334. "AcceptHandler type requirements not met");
  335. response_op<
  336. typename std::decay<AcceptHandler>::type>(
  337. std::forward<AcceptHandler>(h), sp, *m, d);
  338. }
  339. };
  340. template<class NextLayer, bool deflateSupported>
  341. struct stream<NextLayer, deflateSupported>::
  342. run_accept_op
  343. {
  344. template<
  345. class AcceptHandler,
  346. class Decorator,
  347. class Buffers>
  348. void
  349. operator()(
  350. AcceptHandler&& h,
  351. boost::shared_ptr<impl_type> const& sp,
  352. Decorator const& d,
  353. Buffers const& b)
  354. {
  355. // If you get an error on the following line it means
  356. // that your handler does not meet the documented type
  357. // requirements for the handler.
  358. static_assert(
  359. beast::detail::is_invocable<AcceptHandler,
  360. void(error_code)>::value,
  361. "AcceptHandler type requirements not met");
  362. accept_op<
  363. typename std::decay<AcceptHandler>::type,
  364. Decorator>(
  365. std::forward<AcceptHandler>(h),
  366. sp,
  367. d,
  368. b);
  369. }
  370. };
  371. //------------------------------------------------------------------------------
  372. template<class NextLayer, bool deflateSupported>
  373. template<class Body, class Allocator,
  374. class Decorator>
  375. void
  376. stream<NextLayer, deflateSupported>::
  377. do_accept(
  378. http::request<Body,
  379. http::basic_fields<Allocator>> const& req,
  380. Decorator const& decorator,
  381. error_code& ec)
  382. {
  383. impl_->change_status(status::handshake);
  384. error_code result;
  385. auto const res = impl_->build_response(req, decorator, result);
  386. http::write(impl_->stream(), res, ec);
  387. if(ec)
  388. return;
  389. ec = result;
  390. if(ec)
  391. {
  392. // VFALCO TODO Respect keep alive setting, perform
  393. // teardown if Connection: close.
  394. return;
  395. }
  396. impl_->do_pmd_config(res);
  397. impl_->open(role_type::server);
  398. }
  399. template<class NextLayer, bool deflateSupported>
  400. template<class Buffers, class Decorator>
  401. void
  402. stream<NextLayer, deflateSupported>::
  403. do_accept(
  404. Buffers const& buffers,
  405. Decorator const& decorator,
  406. error_code& ec)
  407. {
  408. impl_->reset();
  409. auto const mb =
  410. beast::detail::dynamic_buffer_prepare(
  411. impl_->rd_buf, buffer_bytes(buffers), ec,
  412. error::buffer_overflow);
  413. if(ec)
  414. return;
  415. impl_->rd_buf.commit(net::buffer_copy(*mb, buffers));
  416. http::request_parser<http::empty_body> p;
  417. http::read(next_layer(), impl_->rd_buf, p, ec);
  418. if(ec == http::error::end_of_stream)
  419. ec = error::closed;
  420. if(ec)
  421. return;
  422. do_accept(p.get(), decorator, ec);
  423. }
  424. //------------------------------------------------------------------------------
  425. template<class NextLayer, bool deflateSupported>
  426. void
  427. stream<NextLayer, deflateSupported>::
  428. accept()
  429. {
  430. static_assert(is_sync_stream<next_layer_type>::value,
  431. "SyncStream type requirements not met");
  432. error_code ec;
  433. accept(ec);
  434. if(ec)
  435. BOOST_THROW_EXCEPTION(system_error{ec});
  436. }
  437. template<class NextLayer, bool deflateSupported>
  438. void
  439. stream<NextLayer, deflateSupported>::
  440. accept(error_code& ec)
  441. {
  442. static_assert(is_sync_stream<next_layer_type>::value,
  443. "SyncStream type requirements not met");
  444. do_accept(
  445. net::const_buffer{},
  446. &default_decorate_res, ec);
  447. }
  448. template<class NextLayer, bool deflateSupported>
  449. template<class ConstBufferSequence>
  450. typename std::enable_if<! http::detail::is_header<
  451. ConstBufferSequence>::value>::type
  452. stream<NextLayer, deflateSupported>::
  453. accept(ConstBufferSequence const& buffers)
  454. {
  455. static_assert(is_sync_stream<next_layer_type>::value,
  456. "SyncStream type requirements not met");
  457. static_assert(net::is_const_buffer_sequence<
  458. ConstBufferSequence>::value,
  459. "ConstBufferSequence type requirements not met");
  460. error_code ec;
  461. accept(buffers, ec);
  462. if(ec)
  463. BOOST_THROW_EXCEPTION(system_error{ec});
  464. }
  465. template<class NextLayer, bool deflateSupported>
  466. template<class ConstBufferSequence>
  467. typename std::enable_if<! http::detail::is_header<
  468. ConstBufferSequence>::value>::type
  469. stream<NextLayer, deflateSupported>::
  470. accept(
  471. ConstBufferSequence const& buffers, error_code& ec)
  472. {
  473. static_assert(is_sync_stream<next_layer_type>::value,
  474. "SyncStream type requirements not met");
  475. static_assert(net::is_const_buffer_sequence<
  476. ConstBufferSequence>::value,
  477. "ConstBufferSequence type requirements not met");
  478. do_accept(buffers, &default_decorate_res, ec);
  479. }
  480. template<class NextLayer, bool deflateSupported>
  481. template<class Body, class Allocator>
  482. void
  483. stream<NextLayer, deflateSupported>::
  484. accept(
  485. http::request<Body,
  486. http::basic_fields<Allocator>> const& req)
  487. {
  488. static_assert(is_sync_stream<next_layer_type>::value,
  489. "SyncStream type requirements not met");
  490. error_code ec;
  491. accept(req, ec);
  492. if(ec)
  493. BOOST_THROW_EXCEPTION(system_error{ec});
  494. }
  495. template<class NextLayer, bool deflateSupported>
  496. template<class Body, class Allocator>
  497. void
  498. stream<NextLayer, deflateSupported>::
  499. accept(
  500. http::request<Body,
  501. http::basic_fields<Allocator>> const& req,
  502. error_code& ec)
  503. {
  504. static_assert(is_sync_stream<next_layer_type>::value,
  505. "SyncStream type requirements not met");
  506. impl_->reset();
  507. do_accept(req, &default_decorate_res, ec);
  508. }
  509. //------------------------------------------------------------------------------
  510. template<class NextLayer, bool deflateSupported>
  511. template<
  512. BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
  513. BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
  514. stream<NextLayer, deflateSupported>::
  515. async_accept(
  516. AcceptHandler&& handler)
  517. {
  518. static_assert(is_async_stream<next_layer_type>::value,
  519. "AsyncStream type requirements not met");
  520. impl_->reset();
  521. return net::async_initiate<
  522. AcceptHandler,
  523. void(error_code)>(
  524. run_accept_op{},
  525. handler,
  526. impl_,
  527. &default_decorate_res,
  528. net::const_buffer{});
  529. }
  530. template<class NextLayer, bool deflateSupported>
  531. template<
  532. class ConstBufferSequence,
  533. BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
  534. BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
  535. stream<NextLayer, deflateSupported>::
  536. async_accept(
  537. ConstBufferSequence const& buffers,
  538. AcceptHandler&& handler,
  539. typename std::enable_if<
  540. ! http::detail::is_header<
  541. ConstBufferSequence>::value>::type*
  542. )
  543. {
  544. static_assert(is_async_stream<next_layer_type>::value,
  545. "AsyncStream type requirements not met");
  546. static_assert(net::is_const_buffer_sequence<
  547. ConstBufferSequence>::value,
  548. "ConstBufferSequence type requirements not met");
  549. impl_->reset();
  550. return net::async_initiate<
  551. AcceptHandler,
  552. void(error_code)>(
  553. run_accept_op{},
  554. handler,
  555. impl_,
  556. &default_decorate_res,
  557. buffers);
  558. }
  559. template<class NextLayer, bool deflateSupported>
  560. template<
  561. class Body, class Allocator,
  562. BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
  563. BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
  564. stream<NextLayer, deflateSupported>::
  565. async_accept(
  566. http::request<Body, http::basic_fields<Allocator>> const& req,
  567. AcceptHandler&& handler)
  568. {
  569. static_assert(is_async_stream<next_layer_type>::value,
  570. "AsyncStream type requirements not met");
  571. impl_->reset();
  572. return net::async_initiate<
  573. AcceptHandler,
  574. void(error_code)>(
  575. run_response_op{},
  576. handler,
  577. impl_,
  578. &req,
  579. &default_decorate_res);
  580. }
  581. } // websocket
  582. } // beast
  583. } // boost
  584. #endif