handshake.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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_HANDSHAKE_HPP
  10. #define BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_HPP
  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/message.hpp>
  15. #include <boost/beast/http/read.hpp>
  16. #include <boost/beast/http/write.hpp>
  17. #include <boost/beast/core/async_base.hpp>
  18. #include <boost/beast/core/flat_buffer.hpp>
  19. #include <boost/beast/core/stream_traits.hpp>
  20. #include <boost/asio/coroutine.hpp>
  21. #include <boost/assert.hpp>
  22. #include <boost/throw_exception.hpp>
  23. #include <memory>
  24. namespace boost {
  25. namespace beast {
  26. namespace websocket {
  27. //------------------------------------------------------------------------------
  28. // send the upgrade request and process the response
  29. //
  30. template<class NextLayer, bool deflateSupported>
  31. template<class Handler>
  32. class stream<NextLayer, deflateSupported>::handshake_op
  33. : public beast::stable_async_base<Handler,
  34. beast::executor_type<stream>>
  35. , public asio::coroutine
  36. {
  37. struct data
  38. {
  39. // VFALCO This really should be two separate
  40. // composed operations, to save on memory
  41. request_type req;
  42. http::response_parser<
  43. typename response_type::body_type> p;
  44. flat_buffer fb;
  45. bool overflow = false; // could be a member of the op
  46. explicit
  47. data(request_type&& req_)
  48. : req(std::move(req_))
  49. {
  50. }
  51. };
  52. boost::weak_ptr<impl_type> wp_;
  53. detail::sec_ws_key_type key_;
  54. response_type* res_p_;
  55. data& d_;
  56. public:
  57. template<class Handler_>
  58. handshake_op(
  59. Handler_&& h,
  60. boost::shared_ptr<impl_type> const& sp,
  61. request_type&& req,
  62. detail::sec_ws_key_type key,
  63. response_type* res_p)
  64. : stable_async_base<Handler,
  65. beast::executor_type<stream>>(
  66. std::forward<Handler_>(h),
  67. sp->stream().get_executor())
  68. , wp_(sp)
  69. , key_(key)
  70. , res_p_(res_p)
  71. , d_(beast::allocate_stable<data>(
  72. *this, std::move(req)))
  73. {
  74. sp->reset(); // VFALCO I don't like this
  75. (*this)({}, 0, false);
  76. }
  77. void
  78. operator()(
  79. error_code ec = {},
  80. std::size_t bytes_used = 0,
  81. bool cont = true)
  82. {
  83. boost::ignore_unused(bytes_used);
  84. auto sp = wp_.lock();
  85. if(! sp)
  86. {
  87. ec = net::error::operation_aborted;
  88. return this->complete(cont, ec);
  89. }
  90. auto& impl = *sp;
  91. BOOST_ASIO_CORO_REENTER(*this)
  92. {
  93. impl.change_status(status::handshake);
  94. impl.update_timer(this->get_executor());
  95. // write HTTP request
  96. impl.do_pmd_config(d_.req);
  97. BOOST_ASIO_CORO_YIELD
  98. http::async_write(impl.stream(),
  99. d_.req, std::move(*this));
  100. if(impl.check_stop_now(ec))
  101. goto upcall;
  102. // read HTTP response
  103. BOOST_ASIO_CORO_YIELD
  104. http::async_read(impl.stream(),
  105. impl.rd_buf, d_.p,
  106. std::move(*this));
  107. if(ec == http::error::buffer_overflow)
  108. {
  109. // If the response overflows the internal
  110. // read buffer, switch to a dynamically
  111. // allocated flat buffer.
  112. d_.fb.commit(net::buffer_copy(
  113. d_.fb.prepare(impl.rd_buf.size()),
  114. impl.rd_buf.data()));
  115. impl.rd_buf.clear();
  116. BOOST_ASIO_CORO_YIELD
  117. http::async_read(impl.stream(),
  118. d_.fb, d_.p, std::move(*this));
  119. if(! ec)
  120. {
  121. // Copy any leftovers back into the read
  122. // buffer, since this represents websocket
  123. // frame data.
  124. if(d_.fb.size() <= impl.rd_buf.capacity())
  125. {
  126. impl.rd_buf.commit(net::buffer_copy(
  127. impl.rd_buf.prepare(d_.fb.size()),
  128. d_.fb.data()));
  129. }
  130. else
  131. {
  132. ec = http::error::buffer_overflow;
  133. }
  134. }
  135. // Do this before the upcall
  136. d_.fb.clear();
  137. }
  138. if(impl.check_stop_now(ec))
  139. goto upcall;
  140. // success
  141. impl.reset_idle();
  142. impl.on_response(d_.p.get(), key_, ec);
  143. if(res_p_)
  144. swap(d_.p.get(), *res_p_);
  145. upcall:
  146. this->complete(cont ,ec);
  147. }
  148. }
  149. };
  150. template<class NextLayer, bool deflateSupported>
  151. struct stream<NextLayer, deflateSupported>::
  152. run_handshake_op
  153. {
  154. template<class HandshakeHandler>
  155. void operator()(
  156. HandshakeHandler&& h,
  157. boost::shared_ptr<impl_type> const& sp,
  158. request_type&& req,
  159. detail::sec_ws_key_type key,
  160. response_type* res_p)
  161. {
  162. // If you get an error on the following line it means
  163. // that your handler does not meet the documented type
  164. // requirements for the handler.
  165. static_assert(
  166. beast::detail::is_invocable<HandshakeHandler,
  167. void(error_code)>::value,
  168. "HandshakeHandler type requirements not met");
  169. handshake_op<
  170. typename std::decay<HandshakeHandler>::type>(
  171. std::forward<HandshakeHandler>(h),
  172. sp, std::move(req), key, res_p);
  173. }
  174. };
  175. //------------------------------------------------------------------------------
  176. template<class NextLayer, bool deflateSupported>
  177. template<class RequestDecorator>
  178. void
  179. stream<NextLayer, deflateSupported>::
  180. do_handshake(
  181. response_type* res_p,
  182. string_view host,
  183. string_view target,
  184. RequestDecorator const& decorator,
  185. error_code& ec)
  186. {
  187. auto& impl = *impl_;
  188. impl.change_status(status::handshake);
  189. impl.reset();
  190. detail::sec_ws_key_type key;
  191. {
  192. auto const req = impl.build_request(
  193. key, host, target, decorator);
  194. impl.do_pmd_config(req);
  195. http::write(impl.stream(), req, ec);
  196. }
  197. if(impl.check_stop_now(ec))
  198. return;
  199. http::response_parser<
  200. typename response_type::body_type> p;
  201. http::read(next_layer(), impl.rd_buf, p, ec);
  202. if(ec == http::error::buffer_overflow)
  203. {
  204. // If the response overflows the internal
  205. // read buffer, switch to a dynamically
  206. // allocated flat buffer.
  207. flat_buffer fb;
  208. fb.commit(net::buffer_copy(
  209. fb.prepare(impl.rd_buf.size()),
  210. impl.rd_buf.data()));
  211. impl.rd_buf.clear();
  212. http::read(next_layer(), fb, p, ec);;
  213. if(! ec)
  214. {
  215. // Copy any leftovers back into the read
  216. // buffer, since this represents websocket
  217. // frame data.
  218. if(fb.size() <= impl.rd_buf.capacity())
  219. {
  220. impl.rd_buf.commit(net::buffer_copy(
  221. impl.rd_buf.prepare(fb.size()),
  222. fb.data()));
  223. }
  224. else
  225. {
  226. ec = http::error::buffer_overflow;
  227. }
  228. }
  229. }
  230. if(impl.check_stop_now(ec))
  231. return;
  232. impl.on_response(p.get(), key, ec);
  233. if(impl.check_stop_now(ec))
  234. return;
  235. if(res_p)
  236. *res_p = p.release();
  237. }
  238. //------------------------------------------------------------------------------
  239. template<class NextLayer, bool deflateSupported>
  240. template<class HandshakeHandler>
  241. BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
  242. stream<NextLayer, deflateSupported>::
  243. async_handshake(
  244. string_view host,
  245. string_view target,
  246. HandshakeHandler&& handler)
  247. {
  248. static_assert(is_async_stream<next_layer_type>::value,
  249. "AsyncStream type requirements not met");
  250. detail::sec_ws_key_type key;
  251. auto req = impl_->build_request(
  252. key, host, target, &default_decorate_req);
  253. return net::async_initiate<
  254. HandshakeHandler,
  255. void(error_code)>(
  256. run_handshake_op{},
  257. handler,
  258. impl_,
  259. std::move(req),
  260. key,
  261. nullptr);
  262. }
  263. template<class NextLayer, bool deflateSupported>
  264. template<class HandshakeHandler>
  265. BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
  266. stream<NextLayer, deflateSupported>::
  267. async_handshake(
  268. response_type& res,
  269. string_view host,
  270. string_view target,
  271. HandshakeHandler&& handler)
  272. {
  273. static_assert(is_async_stream<next_layer_type>::value,
  274. "AsyncStream type requirements not met");
  275. detail::sec_ws_key_type key;
  276. auto req = impl_->build_request(
  277. key, host, target, &default_decorate_req);
  278. return net::async_initiate<
  279. HandshakeHandler,
  280. void(error_code)>(
  281. run_handshake_op{},
  282. handler,
  283. impl_,
  284. std::move(req),
  285. key,
  286. &res);
  287. }
  288. template<class NextLayer, bool deflateSupported>
  289. void
  290. stream<NextLayer, deflateSupported>::
  291. handshake(string_view host,
  292. string_view target)
  293. {
  294. static_assert(is_sync_stream<next_layer_type>::value,
  295. "SyncStream type requirements not met");
  296. error_code ec;
  297. handshake(
  298. host, target, ec);
  299. if(ec)
  300. BOOST_THROW_EXCEPTION(system_error{ec});
  301. }
  302. template<class NextLayer, bool deflateSupported>
  303. void
  304. stream<NextLayer, deflateSupported>::
  305. handshake(response_type& res,
  306. string_view host,
  307. string_view target)
  308. {
  309. static_assert(is_sync_stream<next_layer_type>::value,
  310. "SyncStream type requirements not met");
  311. error_code ec;
  312. handshake(res, host, target, ec);
  313. if(ec)
  314. BOOST_THROW_EXCEPTION(system_error{ec});
  315. }
  316. template<class NextLayer, bool deflateSupported>
  317. void
  318. stream<NextLayer, deflateSupported>::
  319. handshake(string_view host,
  320. string_view target, error_code& ec)
  321. {
  322. static_assert(is_sync_stream<next_layer_type>::value,
  323. "SyncStream type requirements not met");
  324. do_handshake(nullptr,
  325. host, target, &default_decorate_req, ec);
  326. }
  327. template<class NextLayer, bool deflateSupported>
  328. void
  329. stream<NextLayer, deflateSupported>::
  330. handshake(response_type& res,
  331. string_view host,
  332. string_view target,
  333. error_code& ec)
  334. {
  335. static_assert(is_sync_stream<next_layer_type>::value,
  336. "SyncStream type requirements not met");
  337. do_handshake(&res,
  338. host, target, &default_decorate_req, ec);
  339. }
  340. //------------------------------------------------------------------------------
  341. template<class NextLayer, bool deflateSupported>
  342. template<class RequestDecorator>
  343. void
  344. stream<NextLayer, deflateSupported>::
  345. handshake_ex(string_view host,
  346. string_view target,
  347. RequestDecorator const& decorator)
  348. {
  349. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  350. static_assert(sizeof(RequestDecorator) == 0,
  351. BOOST_BEAST_DEPRECATION_STRING);
  352. #endif
  353. static_assert(is_sync_stream<next_layer_type>::value,
  354. "SyncStream type requirements not met");
  355. static_assert(detail::is_request_decorator<
  356. RequestDecorator>::value,
  357. "RequestDecorator requirements not met");
  358. error_code ec;
  359. handshake_ex(host, target, decorator, ec);
  360. if(ec)
  361. BOOST_THROW_EXCEPTION(system_error{ec});
  362. }
  363. template<class NextLayer, bool deflateSupported>
  364. template<class RequestDecorator>
  365. void
  366. stream<NextLayer, deflateSupported>::
  367. handshake_ex(response_type& res,
  368. string_view host,
  369. string_view target,
  370. RequestDecorator const& decorator)
  371. {
  372. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  373. static_assert(sizeof(RequestDecorator) == 0,
  374. BOOST_BEAST_DEPRECATION_STRING);
  375. #endif
  376. static_assert(is_sync_stream<next_layer_type>::value,
  377. "SyncStream type requirements not met");
  378. static_assert(detail::is_request_decorator<
  379. RequestDecorator>::value,
  380. "RequestDecorator requirements not met");
  381. error_code ec;
  382. handshake_ex(res, host, target, decorator, ec);
  383. if(ec)
  384. BOOST_THROW_EXCEPTION(system_error{ec});
  385. }
  386. template<class NextLayer, bool deflateSupported>
  387. template<class RequestDecorator>
  388. void
  389. stream<NextLayer, deflateSupported>::
  390. handshake_ex(string_view host,
  391. string_view target,
  392. RequestDecorator const& decorator,
  393. error_code& ec)
  394. {
  395. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  396. static_assert(sizeof(RequestDecorator) == 0,
  397. BOOST_BEAST_DEPRECATION_STRING);
  398. #endif
  399. static_assert(is_sync_stream<next_layer_type>::value,
  400. "SyncStream type requirements not met");
  401. static_assert(detail::is_request_decorator<
  402. RequestDecorator>::value,
  403. "RequestDecorator requirements not met");
  404. do_handshake(nullptr,
  405. host, target, decorator, ec);
  406. }
  407. template<class NextLayer, bool deflateSupported>
  408. template<class RequestDecorator>
  409. void
  410. stream<NextLayer, deflateSupported>::
  411. handshake_ex(response_type& res,
  412. string_view host,
  413. string_view target,
  414. RequestDecorator const& decorator,
  415. error_code& ec)
  416. {
  417. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  418. static_assert(sizeof(RequestDecorator) == 0,
  419. BOOST_BEAST_DEPRECATION_STRING);
  420. #endif
  421. static_assert(is_sync_stream<next_layer_type>::value,
  422. "SyncStream type requirements not met");
  423. static_assert(detail::is_request_decorator<
  424. RequestDecorator>::value,
  425. "RequestDecorator requirements not met");
  426. do_handshake(&res,
  427. host, target, decorator, ec);
  428. }
  429. template<class NextLayer, bool deflateSupported>
  430. template<class RequestDecorator, class HandshakeHandler>
  431. BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
  432. stream<NextLayer, deflateSupported>::
  433. async_handshake_ex(string_view host,
  434. string_view target,
  435. RequestDecorator const& decorator,
  436. HandshakeHandler&& handler)
  437. {
  438. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  439. static_assert(sizeof(RequestDecorator) == 0,
  440. BOOST_BEAST_DEPRECATION_STRING);
  441. #endif
  442. static_assert(is_async_stream<next_layer_type>::value,
  443. "AsyncStream type requirements not met");
  444. static_assert(detail::is_request_decorator<
  445. RequestDecorator>::value,
  446. "RequestDecorator requirements not met");
  447. detail::sec_ws_key_type key;
  448. auto req = impl_->build_request(
  449. key, host, target, decorator);
  450. return net::async_initiate<
  451. HandshakeHandler,
  452. void(error_code)>(
  453. run_handshake_op{},
  454. handler,
  455. impl_,
  456. std::move(req),
  457. key,
  458. nullptr);
  459. }
  460. template<class NextLayer, bool deflateSupported>
  461. template<class RequestDecorator, class HandshakeHandler>
  462. BOOST_BEAST_ASYNC_RESULT1(HandshakeHandler)
  463. stream<NextLayer, deflateSupported>::
  464. async_handshake_ex(response_type& res,
  465. string_view host,
  466. string_view target,
  467. RequestDecorator const& decorator,
  468. HandshakeHandler&& handler)
  469. {
  470. #ifndef BOOST_BEAST_ALLOW_DEPRECATED
  471. static_assert(sizeof(RequestDecorator) == 0,
  472. BOOST_BEAST_DEPRECATION_STRING);
  473. #endif
  474. static_assert(is_async_stream<next_layer_type>::value,
  475. "AsyncStream type requirements not met");
  476. static_assert(detail::is_request_decorator<
  477. RequestDecorator>::value,
  478. "RequestDecorator requirements not met");
  479. detail::sec_ws_key_type key;
  480. auto req = impl_->build_request(
  481. key, host, target, decorator);
  482. return net::async_initiate<
  483. HandshakeHandler,
  484. void(error_code)>(
  485. run_handshake_op{},
  486. handler,
  487. impl_,
  488. std::move(req),
  489. key,
  490. &res);
  491. }
  492. } // websocket
  493. } // beast
  494. } // boost
  495. #endif