icy_stream.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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_CORE_IMPL_ICY_STREAM_HPP
  10. #define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
  11. #include <boost/beast/core/async_base.hpp>
  12. #include <boost/beast/core/buffer_traits.hpp>
  13. #include <boost/beast/core/error.hpp>
  14. #include <boost/beast/core/stream_traits.hpp>
  15. #include <boost/beast/core/detail/is_invocable.hpp>
  16. #include <boost/asio/coroutine.hpp>
  17. #include <boost/assert.hpp>
  18. #include <boost/throw_exception.hpp>
  19. #include <cstring>
  20. #include <memory>
  21. #include <utility>
  22. namespace boost {
  23. namespace beast {
  24. namespace http {
  25. namespace detail {
  26. template<class ConstBufferSequence>
  27. boost::tribool
  28. is_icy(ConstBufferSequence const& buffers)
  29. {
  30. char buf[3];
  31. auto const n = net::buffer_copy(
  32. net::mutable_buffer(buf, 3),
  33. buffers);
  34. if(n >= 1 && buf[0] != 'I')
  35. return false;
  36. if(n >= 2 && buf[1] != 'C')
  37. return false;
  38. if(n >= 3 && buf[2] != 'Y')
  39. return false;
  40. if(n < 3)
  41. return boost::indeterminate;
  42. return true;
  43. }
  44. } // detail
  45. template<class NextLayer>
  46. struct icy_stream<NextLayer>::ops
  47. {
  48. template<class Buffers, class Handler>
  49. class read_op
  50. : public beast::async_base<Handler,
  51. beast::executor_type<icy_stream>>
  52. , public asio::coroutine
  53. {
  54. icy_stream& s_;
  55. Buffers b_;
  56. std::size_t n_ = 0;
  57. error_code ec_;
  58. bool match_ = false;
  59. public:
  60. template<class Handler_>
  61. read_op(
  62. Handler_&& h,
  63. icy_stream& s,
  64. Buffers const& b)
  65. : async_base<Handler,
  66. beast::executor_type<icy_stream>>(
  67. std::forward<Handler_>(h), s.get_executor())
  68. , s_(s)
  69. , b_(b)
  70. {
  71. (*this)({}, 0, false);
  72. }
  73. void
  74. operator()(
  75. error_code ec,
  76. std::size_t bytes_transferred,
  77. bool cont = true)
  78. {
  79. BOOST_ASIO_CORO_REENTER(*this)
  80. {
  81. if(s_.detect_)
  82. {
  83. BOOST_ASSERT(s_.n_ == 0);
  84. for(;;)
  85. {
  86. // Try to read the first three characters
  87. BOOST_ASIO_CORO_YIELD
  88. {
  89. BOOST_ASIO_HANDLER_LOCATION((
  90. __FILE__, __LINE__,
  91. "http::icy_stream::async_read_some"));
  92. s_.next_layer().async_read_some(
  93. net::mutable_buffer(
  94. s_.buf_ + s_.n_, 3 - s_.n_),
  95. std::move(*this));
  96. }
  97. s_.n_ += static_cast<char>(bytes_transferred);
  98. if(ec)
  99. goto upcall;
  100. auto result = detail::is_icy(
  101. net::const_buffer(s_.buf_, s_.n_));
  102. if(boost::indeterminate(result))
  103. continue;
  104. if(result)
  105. s_.n_ = static_cast<char>(net::buffer_copy(
  106. net::buffer(s_.buf_, sizeof(s_.buf_)),
  107. icy_stream::version()));
  108. break;
  109. }
  110. s_.detect_ = false;
  111. }
  112. if(s_.n_ > 0)
  113. {
  114. bytes_transferred = net::buffer_copy(
  115. b_, net::const_buffer(s_.buf_, s_.n_));
  116. s_.n_ -= static_cast<char>(bytes_transferred);
  117. std::memmove(
  118. s_.buf_,
  119. s_.buf_ + bytes_transferred,
  120. sizeof(s_.buf_) - bytes_transferred);
  121. }
  122. else
  123. {
  124. BOOST_ASIO_CORO_YIELD
  125. {
  126. BOOST_ASIO_HANDLER_LOCATION((
  127. __FILE__, __LINE__,
  128. "http::icy_stream::async_read_some"));
  129. s_.next_layer().async_read_some(
  130. b_, std::move(*this));
  131. }
  132. }
  133. upcall:
  134. if(! cont)
  135. {
  136. ec_ = ec;
  137. n_ = bytes_transferred;
  138. BOOST_ASIO_CORO_YIELD
  139. {
  140. BOOST_ASIO_HANDLER_LOCATION((
  141. __FILE__, __LINE__,
  142. "http::icy_stream::async_read_some"));
  143. s_.next_layer().async_read_some(
  144. net::mutable_buffer{},
  145. std::move(*this));
  146. }
  147. BOOST_BEAST_ASSIGN_EC(ec, ec_);
  148. bytes_transferred = n_;
  149. }
  150. this->complete_now(ec, bytes_transferred);
  151. }
  152. }
  153. };
  154. struct run_read_op
  155. {
  156. icy_stream* self;
  157. using executor_type = typename icy_stream::executor_type;
  158. executor_type
  159. get_executor() const noexcept
  160. {
  161. return self->get_executor();
  162. }
  163. template<class ReadHandler, class Buffers>
  164. void
  165. operator()(
  166. ReadHandler&& h,
  167. Buffers const& b)
  168. {
  169. // If you get an error on the following line it means
  170. // that your handler does not meet the documented type
  171. // requirements for the handler.
  172. static_assert(
  173. beast::detail::is_invocable<ReadHandler,
  174. void(error_code, std::size_t)>::value,
  175. "ReadHandler type requirements not met");
  176. read_op<
  177. Buffers,
  178. typename std::decay<ReadHandler>::type>(
  179. std::forward<ReadHandler>(h), *self, b);
  180. }
  181. };
  182. };
  183. //------------------------------------------------------------------------------
  184. template<class NextLayer>
  185. template<class... Args>
  186. icy_stream<NextLayer>::
  187. icy_stream(Args&&... args)
  188. : stream_(std::forward<Args>(args)...)
  189. {
  190. std::memset(buf_, 0, sizeof(buf_));
  191. }
  192. template<class NextLayer>
  193. template<class MutableBufferSequence>
  194. std::size_t
  195. icy_stream<NextLayer>::
  196. read_some(MutableBufferSequence const& buffers)
  197. {
  198. static_assert(is_sync_read_stream<next_layer_type>::value,
  199. "SyncReadStream type requirements not met");
  200. static_assert(net::is_mutable_buffer_sequence<
  201. MutableBufferSequence>::value,
  202. "MutableBufferSequence type requirements not met");
  203. error_code ec;
  204. auto n = read_some(buffers, ec);
  205. if(ec)
  206. BOOST_THROW_EXCEPTION(system_error{ec});
  207. return n;
  208. }
  209. template<class NextLayer>
  210. template<class MutableBufferSequence>
  211. std::size_t
  212. icy_stream<NextLayer>::
  213. read_some(MutableBufferSequence const& buffers, error_code& ec)
  214. {
  215. static_assert(is_sync_read_stream<next_layer_type>::value,
  216. "SyncReadStream type requirements not met");
  217. static_assert(net::is_mutable_buffer_sequence<
  218. MutableBufferSequence>::value,
  219. "MutableBufferSequence type requirements not met");
  220. std::size_t bytes_transferred;
  221. if(detect_)
  222. {
  223. BOOST_ASSERT(n_ == 0);
  224. for(;;)
  225. {
  226. // Try to read the first three characters
  227. bytes_transferred = next_layer().read_some(
  228. net::mutable_buffer(buf_ + n_, 3 - n_), ec);
  229. n_ += static_cast<char>(bytes_transferred);
  230. if(ec)
  231. return 0;
  232. auto result = detail::is_icy(
  233. net::const_buffer(buf_, n_));
  234. if(boost::indeterminate(result))
  235. continue;
  236. if(result)
  237. n_ = static_cast<char>(net::buffer_copy(
  238. net::buffer(buf_, sizeof(buf_)),
  239. icy_stream::version()));
  240. break;
  241. }
  242. detect_ = false;
  243. }
  244. if(n_ > 0)
  245. {
  246. bytes_transferred = net::buffer_copy(
  247. buffers, net::const_buffer(buf_, n_));
  248. n_ -= static_cast<char>(bytes_transferred);
  249. std::memmove(
  250. buf_,
  251. buf_ + bytes_transferred,
  252. sizeof(buf_) - bytes_transferred);
  253. }
  254. else
  255. {
  256. bytes_transferred =
  257. next_layer().read_some(buffers, ec);
  258. }
  259. return bytes_transferred;
  260. }
  261. template<class NextLayer>
  262. template<
  263. class MutableBufferSequence,
  264. BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
  265. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  266. icy_stream<NextLayer>::
  267. async_read_some(
  268. MutableBufferSequence const& buffers,
  269. ReadHandler&& handler)
  270. {
  271. static_assert(is_async_read_stream<next_layer_type>::value,
  272. "AsyncReadStream type requirements not met");
  273. static_assert(net::is_mutable_buffer_sequence<
  274. MutableBufferSequence >::value,
  275. "MutableBufferSequence type requirements not met");
  276. return net::async_initiate<
  277. ReadHandler,
  278. void(error_code, std::size_t)>(
  279. typename ops::run_read_op{this},
  280. handler,
  281. buffers);
  282. }
  283. template<class NextLayer>
  284. template<class MutableBufferSequence>
  285. std::size_t
  286. icy_stream<NextLayer>::
  287. write_some(MutableBufferSequence const& buffers)
  288. {
  289. static_assert(is_sync_write_stream<next_layer_type>::value,
  290. "SyncWriteStream type requirements not met");
  291. static_assert(net::is_const_buffer_sequence<
  292. MutableBufferSequence>::value,
  293. "MutableBufferSequence type requirements not met");
  294. return stream_.write_some(buffers);
  295. }
  296. template<class NextLayer>
  297. template<class MutableBufferSequence>
  298. std::size_t
  299. icy_stream<NextLayer>::
  300. write_some(MutableBufferSequence const& buffers, error_code& ec)
  301. {
  302. static_assert(is_sync_write_stream<next_layer_type>::value,
  303. "SyncWriteStream type requirements not met");
  304. static_assert(net::is_const_buffer_sequence<
  305. MutableBufferSequence>::value,
  306. "MutableBufferSequence type requirements not met");
  307. return stream_.write_some(buffers, ec);
  308. }
  309. template<class NextLayer>
  310. template<
  311. class MutableBufferSequence,
  312. BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
  313. BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
  314. icy_stream<NextLayer>::
  315. async_write_some(
  316. MutableBufferSequence const& buffers,
  317. WriteHandler&& handler)
  318. {
  319. static_assert(is_async_write_stream<next_layer_type>::value,
  320. "AsyncWriteStream type requirements not met");
  321. static_assert(net::is_const_buffer_sequence<
  322. MutableBufferSequence>::value,
  323. "MutableBufferSequence type requirements not met");
  324. return stream_.async_write_some(
  325. buffers, std::forward<WriteHandler>(handler));
  326. }
  327. } // http
  328. } // beast
  329. } // boost
  330. #endif