icy_stream.ipp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. //
  2. // Copyright (c) 2018 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_CORE_IMPL_ICY_STREAM_IPP
  10. #define BOOST_BEAST_CORE_IMPL_ICY_STREAM_IPP
  11. #include <boost/beast/core/bind_handler.hpp>
  12. #include <boost/beast/core/buffers_adapter.hpp>
  13. #include <boost/beast/core/buffers_prefix.hpp>
  14. #include <boost/beast/core/buffers_suffix.hpp>
  15. #include <boost/beast/core/detail/buffers_ref.hpp>
  16. #include <boost/beast/core/handler_ptr.hpp>
  17. #include <boost/asio/associated_allocator.hpp>
  18. #include <boost/asio/associated_executor.hpp>
  19. #include <boost/asio/buffer.hpp>
  20. #include <boost/asio/buffers_iterator.hpp>
  21. #include <boost/asio/coroutine.hpp>
  22. #include <boost/asio/handler_continuation_hook.hpp>
  23. #include <boost/asio/handler_invoke_hook.hpp>
  24. #include <boost/asio/post.hpp>
  25. #include <boost/asio/read.hpp>
  26. #include <boost/asio/read_until.hpp>
  27. #include <boost/assert.hpp>
  28. #include <boost/throw_exception.hpp>
  29. #include <algorithm>
  30. #include <memory>
  31. #include <utility>
  32. namespace boost {
  33. namespace beast {
  34. namespace http {
  35. namespace detail {
  36. template<class DynamicBuffer>
  37. class dynamic_buffer_ref
  38. {
  39. DynamicBuffer& b_;
  40. public:
  41. using const_buffers_type =
  42. typename DynamicBuffer::const_buffers_type;
  43. using mutable_buffers_type =
  44. typename DynamicBuffer::mutable_buffers_type;
  45. dynamic_buffer_ref(dynamic_buffer_ref&&) = default;
  46. explicit
  47. dynamic_buffer_ref(DynamicBuffer& b)
  48. : b_(b)
  49. {
  50. }
  51. std::size_t
  52. size() const
  53. {
  54. return b_.size();
  55. }
  56. std::size_t
  57. max_size() const
  58. {
  59. return b_.max_size();
  60. }
  61. std::size_t
  62. capacity() const
  63. {
  64. return b_.capacity();
  65. }
  66. const_buffers_type
  67. data() const
  68. {
  69. return b_.data();
  70. }
  71. mutable_buffers_type
  72. prepare(std::size_t n)
  73. {
  74. return b_.prepare(n);
  75. }
  76. void
  77. commit(std::size_t n)
  78. {
  79. b_.commit(n);
  80. }
  81. void
  82. consume(std::size_t n)
  83. {
  84. b_.consume(n);
  85. }
  86. };
  87. template<class DynamicBuffer>
  88. typename std::enable_if<
  89. boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
  90. dynamic_buffer_ref<DynamicBuffer>>::type
  91. ref(DynamicBuffer& b)
  92. {
  93. return dynamic_buffer_ref<DynamicBuffer>(b);
  94. }
  95. template<class MutableBuffers, class ConstBuffers>
  96. void
  97. buffer_shift(MutableBuffers const& out, ConstBuffers const& in)
  98. {
  99. using boost::asio::buffer_size;
  100. auto in_pos = boost::asio::buffer_sequence_end(in);
  101. auto out_pos = boost::asio::buffer_sequence_end(out);
  102. auto const in_begin = boost::asio::buffer_sequence_begin(in);
  103. auto const out_begin = boost::asio::buffer_sequence_begin(out);
  104. BOOST_ASSERT(buffer_size(in) == buffer_size(out));
  105. if(in_pos == in_begin || out_pos == out_begin)
  106. return;
  107. boost::asio::const_buffer cb{*--in_pos};
  108. boost::asio::mutable_buffer mb{*--out_pos};
  109. for(;;)
  110. {
  111. if(mb.size() >= cb.size())
  112. {
  113. std::memmove(
  114. static_cast<char*>(
  115. mb.data()) + mb.size() - cb.size(),
  116. cb.data(),
  117. cb.size());
  118. mb = boost::asio::mutable_buffer{
  119. mb.data(), mb.size() - cb.size()};
  120. if(in_pos == in_begin)
  121. break;
  122. cb = *--in_pos;
  123. }
  124. else
  125. {
  126. std::memmove(
  127. mb.data(),
  128. static_cast<char const*>(
  129. cb.data()) + cb.size() - mb.size(),
  130. mb.size());
  131. cb = boost::asio::const_buffer{
  132. cb.data(), cb.size() - mb.size()};
  133. if(out_pos == out_begin)
  134. break;
  135. mb = *--out_pos;
  136. }
  137. }
  138. }
  139. template<class FwdIt>
  140. class match_icy
  141. {
  142. bool& match_;
  143. public:
  144. using result_type = std::pair<FwdIt, bool>;
  145. explicit
  146. match_icy(bool& b)
  147. : match_(b)
  148. {
  149. }
  150. result_type
  151. operator()(FwdIt first, FwdIt last) const
  152. {
  153. auto it = first;
  154. if(it == last)
  155. return {first, false};
  156. if(*it != 'I')
  157. return {last, true};
  158. if(++it == last)
  159. return {first, false};
  160. if(*it != 'C')
  161. return {last, true};
  162. if(++it == last)
  163. return {first, false};
  164. if(*it != 'Y')
  165. return {last, true};
  166. match_ = true;
  167. return {last, true};
  168. };
  169. };
  170. } // detail
  171. template<class NextLayer>
  172. template<class MutableBufferSequence, class Handler>
  173. class icy_stream<NextLayer>::read_op
  174. : public boost::asio::coroutine
  175. {
  176. using alloc_type = typename
  177. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  178. boost::asio::associated_allocator_t<Handler>::template
  179. rebind<char>::other;
  180. #else
  181. std::allocator_traits<boost::asio::associated_allocator_t<Handler>>
  182. ::template rebind_alloc<char>;
  183. #endif
  184. struct data
  185. {
  186. icy_stream<NextLayer>& s;
  187. buffers_adapter<MutableBufferSequence> b;
  188. bool match = false;
  189. data(
  190. Handler const&,
  191. icy_stream<NextLayer>& s_,
  192. MutableBufferSequence const& b_)
  193. : s(s_)
  194. , b(b_)
  195. {
  196. }
  197. };
  198. handler_ptr<data, Handler> d_;
  199. public:
  200. read_op(read_op&&) = default;
  201. read_op(read_op const&) = delete;
  202. template<class DeducedHandler, class... Args>
  203. read_op(
  204. DeducedHandler&& h,
  205. icy_stream<NextLayer>& s,
  206. MutableBufferSequence const& b)
  207. : d_(std::forward<DeducedHandler>(h), s, b)
  208. {
  209. }
  210. using allocator_type =
  211. boost::asio::associated_allocator_t<Handler>;
  212. allocator_type
  213. get_allocator() const noexcept
  214. {
  215. return (boost::asio::get_associated_allocator)(d_.handler());
  216. }
  217. using executor_type = boost::asio::associated_executor_t<
  218. Handler, decltype(std::declval<NextLayer&>().get_executor())>;
  219. executor_type
  220. get_executor() const noexcept
  221. {
  222. return (boost::asio::get_associated_executor)(
  223. d_.handler(), d_->s.get_executor());
  224. }
  225. void
  226. operator()(
  227. boost::system::error_code ec,
  228. std::size_t bytes_transferred);
  229. template<class Function>
  230. friend
  231. void asio_handler_invoke(Function&& f, read_op* op)
  232. {
  233. using boost::asio::asio_handler_invoke;
  234. asio_handler_invoke(f, std::addressof(op->d_.handler()));
  235. }
  236. };
  237. template<class NextLayer>
  238. template<class MutableBufferSequence, class Handler>
  239. void
  240. icy_stream<NextLayer>::
  241. read_op<MutableBufferSequence, Handler>::
  242. operator()(
  243. error_code ec,
  244. std::size_t bytes_transferred)
  245. {
  246. using boost::asio::buffer_copy;
  247. using boost::asio::buffer_size;
  248. using iterator = boost::asio::buffers_iterator<
  249. typename detail::dynamic_buffer_ref<
  250. buffers_adapter<MutableBufferSequence>>::const_buffers_type>;
  251. auto& d = *d_;
  252. BOOST_ASIO_CORO_REENTER(*this)
  253. {
  254. if(d.b.max_size() == 0)
  255. {
  256. BOOST_ASIO_CORO_YIELD
  257. boost::asio::post(d.s.get_executor(),
  258. bind_handler(std::move(*this), ec, 0));
  259. goto upcall;
  260. }
  261. if(! d.s.detect_)
  262. {
  263. if(d.s.copy_ > 0)
  264. {
  265. auto const n = buffer_copy(
  266. d.b.prepare(std::min<std::size_t>(
  267. d.s.copy_, d.b.max_size())),
  268. boost::asio::buffer(d.s.buf_));
  269. d.b.commit(n);
  270. d.s.copy_ = static_cast<unsigned char>(
  271. d.s.copy_ - n);
  272. if(d.s.copy_ > 0)
  273. std::memmove(
  274. d.s.buf_,
  275. &d.s.buf_[n],
  276. d.s.copy_);
  277. }
  278. if(d.b.size() < d.b.max_size())
  279. {
  280. BOOST_ASIO_CORO_YIELD
  281. d.s.next_layer().async_read_some(
  282. d.b.prepare(d.b.max_size() - d.b.size()),
  283. std::move(*this));
  284. d.b.commit(bytes_transferred);
  285. }
  286. bytes_transferred = d.b.size();
  287. goto upcall;
  288. }
  289. d.s.detect_ = false;
  290. if(d.b.max_size() < 8)
  291. {
  292. BOOST_ASIO_CORO_YIELD
  293. boost::asio::async_read(
  294. d.s.next_layer(),
  295. boost::asio::buffer(d.s.buf_, 3),
  296. std::move(*this));
  297. if(ec)
  298. goto upcall;
  299. auto n = bytes_transferred;
  300. BOOST_ASSERT(n == 3);
  301. if(
  302. d.s.buf_[0] != 'I' ||
  303. d.s.buf_[1] != 'C' ||
  304. d.s.buf_[2] != 'Y')
  305. {
  306. buffer_copy(
  307. d.b.value(),
  308. boost::asio::buffer(d.s.buf_, n));
  309. if(d.b.max_size() < 3)
  310. {
  311. d.s.copy_ = static_cast<unsigned char>(
  312. 3 - d.b.max_size());
  313. std::memmove(
  314. d.s.buf_,
  315. &d.s.buf_[d.b.max_size()],
  316. d.s.copy_);
  317. }
  318. bytes_transferred = (std::min)(
  319. n, d.b.max_size());
  320. goto upcall;
  321. }
  322. d.s.copy_ = static_cast<unsigned char>(
  323. buffer_copy(
  324. boost::asio::buffer(d.s.buf_),
  325. icy_stream::version() + d.b.max_size()));
  326. bytes_transferred = buffer_copy(
  327. d.b.value(),
  328. icy_stream::version());
  329. goto upcall;
  330. }
  331. BOOST_ASIO_CORO_YIELD
  332. boost::asio::async_read_until(
  333. d.s.next_layer(),
  334. detail::ref(d.b),
  335. detail::match_icy<iterator>(d.match),
  336. std::move(*this));
  337. if(ec)
  338. goto upcall;
  339. {
  340. auto n = bytes_transferred;
  341. BOOST_ASSERT(n == d.b.size());
  342. if(! d.match)
  343. goto upcall;
  344. if(d.b.size() + 5 > d.b.max_size())
  345. {
  346. d.s.copy_ = static_cast<unsigned char>(
  347. n + 5 - d.b.max_size());
  348. std::copy(
  349. boost::asio::buffers_begin(d.b.value()) + n - d.s.copy_,
  350. boost::asio::buffers_begin(d.b.value()) + n,
  351. d.s.buf_);
  352. n = d.b.max_size() - 5;
  353. }
  354. {
  355. buffers_suffix<beast::detail::buffers_ref<
  356. MutableBufferSequence>> dest(
  357. boost::in_place_init, d.b.value());
  358. dest.consume(5);
  359. detail::buffer_shift(
  360. buffers_prefix(n, dest),
  361. buffers_prefix(n, d.b.value()));
  362. buffer_copy(d.b.value(), icy_stream::version());
  363. n += 5;
  364. bytes_transferred = n;
  365. }
  366. }
  367. upcall:
  368. d_.invoke(ec, bytes_transferred);
  369. }
  370. }
  371. //------------------------------------------------------------------------------
  372. template<class NextLayer>
  373. template<class... Args>
  374. icy_stream<NextLayer>::
  375. icy_stream(Args&&... args)
  376. : stream_(std::forward<Args>(args)...)
  377. {
  378. }
  379. template<class NextLayer>
  380. template<class MutableBufferSequence>
  381. std::size_t
  382. icy_stream<NextLayer>::
  383. read_some(MutableBufferSequence const& buffers)
  384. {
  385. static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
  386. "SyncReadStream requirements not met");
  387. static_assert(boost::asio::is_mutable_buffer_sequence<
  388. MutableBufferSequence>::value,
  389. "MutableBufferSequence requirements not met");
  390. error_code ec;
  391. auto n = read_some(buffers, ec);
  392. if(ec)
  393. BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
  394. return n;
  395. }
  396. template<class NextLayer>
  397. template<class MutableBufferSequence>
  398. std::size_t
  399. icy_stream<NextLayer>::
  400. read_some(MutableBufferSequence const& buffers, error_code& ec)
  401. {
  402. static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
  403. "SyncReadStream requirements not met");
  404. static_assert(boost::asio::is_mutable_buffer_sequence<
  405. MutableBufferSequence>::value,
  406. "MutableBufferSequence requirements not met");
  407. using boost::asio::buffer_copy;
  408. using boost::asio::buffer_size;
  409. using iterator = boost::asio::buffers_iterator<
  410. typename detail::dynamic_buffer_ref<
  411. buffers_adapter<MutableBufferSequence>>::const_buffers_type>;
  412. buffers_adapter<MutableBufferSequence> b(buffers);
  413. if(b.max_size() == 0)
  414. {
  415. ec.assign(0, ec.category());
  416. return 0;
  417. }
  418. if(! detect_)
  419. {
  420. if(copy_ > 0)
  421. {
  422. auto const n = buffer_copy(
  423. b.prepare(std::min<std::size_t>(
  424. copy_, b.max_size())),
  425. boost::asio::buffer(buf_));
  426. b.commit(n);
  427. copy_ = static_cast<unsigned char>(
  428. copy_ - n);
  429. if(copy_ > 0)
  430. std::memmove(
  431. buf_,
  432. &buf_[n],
  433. copy_);
  434. }
  435. if(b.size() < b.max_size())
  436. b.commit(stream_.read_some(
  437. b.prepare(b.max_size() - b.size()), ec));
  438. return b.size();
  439. }
  440. detect_ = false;
  441. if(b.max_size() < 8)
  442. {
  443. auto n = boost::asio::read(
  444. stream_,
  445. boost::asio::buffer(buf_, 3),
  446. ec);
  447. if(ec)
  448. return 0;
  449. BOOST_ASSERT(n == 3);
  450. if(
  451. buf_[0] != 'I' ||
  452. buf_[1] != 'C' ||
  453. buf_[2] != 'Y')
  454. {
  455. buffer_copy(
  456. buffers,
  457. boost::asio::buffer(buf_, n));
  458. if(b.max_size() < 3)
  459. {
  460. copy_ = static_cast<unsigned char>(
  461. 3 - b.max_size());
  462. std::memmove(
  463. buf_,
  464. &buf_[b.max_size()],
  465. copy_);
  466. }
  467. return (std::min)(n, b.max_size());
  468. }
  469. copy_ = static_cast<unsigned char>(
  470. buffer_copy(
  471. boost::asio::buffer(buf_),
  472. version() + b.max_size()));
  473. return buffer_copy(
  474. buffers,
  475. version());
  476. }
  477. bool match = false;
  478. auto n = boost::asio::read_until(
  479. stream_,
  480. detail::ref(b),
  481. detail::match_icy<iterator>(match),
  482. ec);
  483. if(ec)
  484. return n;
  485. BOOST_ASSERT(n == b.size());
  486. if(! match)
  487. return n;
  488. if(b.size() + 5 > b.max_size())
  489. {
  490. copy_ = static_cast<unsigned char>(
  491. n + 5 - b.max_size());
  492. std::copy(
  493. boost::asio::buffers_begin(buffers) + n - copy_,
  494. boost::asio::buffers_begin(buffers) + n,
  495. buf_);
  496. n = b.max_size() - 5;
  497. }
  498. buffers_suffix<beast::detail::buffers_ref<
  499. MutableBufferSequence>> dest(
  500. boost::in_place_init, buffers);
  501. dest.consume(5);
  502. detail::buffer_shift(
  503. buffers_prefix(n, dest),
  504. buffers_prefix(n, buffers));
  505. buffer_copy(buffers, version());
  506. n += 5;
  507. return n;
  508. }
  509. template<class NextLayer>
  510. template<
  511. class MutableBufferSequence,
  512. class ReadHandler>
  513. BOOST_ASIO_INITFN_RESULT_TYPE(
  514. ReadHandler, void(error_code, std::size_t))
  515. icy_stream<NextLayer>::
  516. async_read_some(
  517. MutableBufferSequence const& buffers,
  518. ReadHandler&& handler)
  519. {
  520. static_assert(boost::beast::is_async_read_stream<next_layer_type>::value,
  521. "AsyncReadStream requirements not met");
  522. static_assert(boost::asio::is_mutable_buffer_sequence<
  523. MutableBufferSequence >::value,
  524. "MutableBufferSequence requirements not met");
  525. BOOST_BEAST_HANDLER_INIT(
  526. ReadHandler, void(error_code, std::size_t));
  527. read_op<
  528. MutableBufferSequence,
  529. BOOST_ASIO_HANDLER_TYPE(
  530. ReadHandler, void(error_code, std::size_t))>{
  531. std::move(init.completion_handler), *this, buffers}(
  532. {}, 0);
  533. return init.result.get();
  534. }
  535. template<class NextLayer>
  536. template<class MutableBufferSequence>
  537. std::size_t
  538. icy_stream<NextLayer>::
  539. write_some(MutableBufferSequence const& buffers)
  540. {
  541. static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
  542. "SyncWriteStream requirements not met");
  543. static_assert(boost::asio::is_const_buffer_sequence<
  544. MutableBufferSequence>::value,
  545. "MutableBufferSequence requirements not met");
  546. return stream_.write_some(buffers);
  547. }
  548. template<class NextLayer>
  549. template<class MutableBufferSequence>
  550. std::size_t
  551. icy_stream<NextLayer>::
  552. write_some(MutableBufferSequence const& buffers, error_code& ec)
  553. {
  554. static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
  555. "SyncWriteStream requirements not met");
  556. static_assert(boost::asio::is_const_buffer_sequence<
  557. MutableBufferSequence>::value,
  558. "MutableBufferSequence requirements not met");
  559. return stream_.write_some(buffers, ec);
  560. }
  561. template<class NextLayer>
  562. template<
  563. class MutableBufferSequence,
  564. class WriteHandler>
  565. BOOST_ASIO_INITFN_RESULT_TYPE(
  566. WriteHandler, void(error_code, std::size_t))
  567. icy_stream<NextLayer>::
  568. async_write_some(
  569. MutableBufferSequence const& buffers,
  570. WriteHandler&& handler)
  571. {
  572. static_assert(boost::beast::is_async_write_stream<next_layer_type>::value,
  573. "AsyncWriteStream requirements not met");
  574. static_assert(boost::asio::is_const_buffer_sequence<
  575. MutableBufferSequence>::value,
  576. "MutableBufferSequence requirements not met");
  577. return stream_.async_write_some(buffers, std::forward<WriteHandler>(handler));
  578. }
  579. } // http
  580. } // beast
  581. } // boost
  582. #endif