icy_stream.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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. template<class ReadHandler, class Buffers>
  157. void
  158. operator()(
  159. ReadHandler&& h,
  160. icy_stream* s,
  161. Buffers const& b)
  162. {
  163. // If you get an error on the following line it means
  164. // that your handler does not meet the documented type
  165. // requirements for the handler.
  166. static_assert(
  167. beast::detail::is_invocable<ReadHandler,
  168. void(error_code, std::size_t)>::value,
  169. "ReadHandler type requirements not met");
  170. read_op<
  171. Buffers,
  172. typename std::decay<ReadHandler>::type>(
  173. std::forward<ReadHandler>(h), *s, b);
  174. }
  175. };
  176. };
  177. //------------------------------------------------------------------------------
  178. template<class NextLayer>
  179. template<class... Args>
  180. icy_stream<NextLayer>::
  181. icy_stream(Args&&... args)
  182. : stream_(std::forward<Args>(args)...)
  183. {
  184. std::memset(buf_, 0, sizeof(buf_));
  185. }
  186. template<class NextLayer>
  187. template<class MutableBufferSequence>
  188. std::size_t
  189. icy_stream<NextLayer>::
  190. read_some(MutableBufferSequence const& buffers)
  191. {
  192. static_assert(is_sync_read_stream<next_layer_type>::value,
  193. "SyncReadStream type requirements not met");
  194. static_assert(net::is_mutable_buffer_sequence<
  195. MutableBufferSequence>::value,
  196. "MutableBufferSequence type requirements not met");
  197. error_code ec;
  198. auto n = read_some(buffers, ec);
  199. if(ec)
  200. BOOST_THROW_EXCEPTION(system_error{ec});
  201. return n;
  202. }
  203. template<class NextLayer>
  204. template<class MutableBufferSequence>
  205. std::size_t
  206. icy_stream<NextLayer>::
  207. read_some(MutableBufferSequence const& buffers, error_code& ec)
  208. {
  209. static_assert(is_sync_read_stream<next_layer_type>::value,
  210. "SyncReadStream type requirements not met");
  211. static_assert(net::is_mutable_buffer_sequence<
  212. MutableBufferSequence>::value,
  213. "MutableBufferSequence type requirements not met");
  214. std::size_t bytes_transferred;
  215. if(detect_)
  216. {
  217. BOOST_ASSERT(n_ == 0);
  218. for(;;)
  219. {
  220. // Try to read the first three characters
  221. bytes_transferred = next_layer().read_some(
  222. net::mutable_buffer(buf_ + n_, 3 - n_), ec);
  223. n_ += static_cast<char>(bytes_transferred);
  224. if(ec)
  225. return 0;
  226. auto result = detail::is_icy(
  227. net::const_buffer(buf_, n_));
  228. if(boost::indeterminate(result))
  229. continue;
  230. if(result)
  231. n_ = static_cast<char>(net::buffer_copy(
  232. net::buffer(buf_, sizeof(buf_)),
  233. icy_stream::version()));
  234. break;
  235. }
  236. detect_ = false;
  237. }
  238. if(n_ > 0)
  239. {
  240. bytes_transferred = net::buffer_copy(
  241. buffers, net::const_buffer(buf_, n_));
  242. n_ -= static_cast<char>(bytes_transferred);
  243. std::memmove(
  244. buf_,
  245. buf_ + bytes_transferred,
  246. sizeof(buf_) - bytes_transferred);
  247. }
  248. else
  249. {
  250. bytes_transferred =
  251. next_layer().read_some(buffers, ec);
  252. }
  253. return bytes_transferred;
  254. }
  255. template<class NextLayer>
  256. template<
  257. class MutableBufferSequence,
  258. BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
  259. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  260. icy_stream<NextLayer>::
  261. async_read_some(
  262. MutableBufferSequence const& buffers,
  263. ReadHandler&& handler)
  264. {
  265. static_assert(is_async_read_stream<next_layer_type>::value,
  266. "AsyncReadStream type requirements not met");
  267. static_assert(net::is_mutable_buffer_sequence<
  268. MutableBufferSequence >::value,
  269. "MutableBufferSequence type requirements not met");
  270. return net::async_initiate<
  271. ReadHandler,
  272. void(error_code, std::size_t)>(
  273. typename ops::run_read_op{},
  274. handler,
  275. this,
  276. buffers);
  277. }
  278. template<class NextLayer>
  279. template<class MutableBufferSequence>
  280. std::size_t
  281. icy_stream<NextLayer>::
  282. write_some(MutableBufferSequence const& buffers)
  283. {
  284. static_assert(is_sync_write_stream<next_layer_type>::value,
  285. "SyncWriteStream type requirements not met");
  286. static_assert(net::is_const_buffer_sequence<
  287. MutableBufferSequence>::value,
  288. "MutableBufferSequence type requirements not met");
  289. return stream_.write_some(buffers);
  290. }
  291. template<class NextLayer>
  292. template<class MutableBufferSequence>
  293. std::size_t
  294. icy_stream<NextLayer>::
  295. write_some(MutableBufferSequence const& buffers, error_code& ec)
  296. {
  297. static_assert(is_sync_write_stream<next_layer_type>::value,
  298. "SyncWriteStream type requirements not met");
  299. static_assert(net::is_const_buffer_sequence<
  300. MutableBufferSequence>::value,
  301. "MutableBufferSequence type requirements not met");
  302. return stream_.write_some(buffers, ec);
  303. }
  304. template<class NextLayer>
  305. template<
  306. class MutableBufferSequence,
  307. BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
  308. BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
  309. icy_stream<NextLayer>::
  310. async_write_some(
  311. MutableBufferSequence const& buffers,
  312. WriteHandler&& handler)
  313. {
  314. static_assert(is_async_write_stream<next_layer_type>::value,
  315. "AsyncWriteStream type requirements not met");
  316. static_assert(net::is_const_buffer_sequence<
  317. MutableBufferSequence>::value,
  318. "MutableBufferSequence type requirements not met");
  319. return stream_.async_write_some(
  320. buffers, std::forward<WriteHandler>(handler));
  321. }
  322. } // http
  323. } // beast
  324. } // boost
  325. #endif