read.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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_DETAIL_IMPL_READ_HPP
  10. #define BOOST_BEAST_DETAIL_IMPL_READ_HPP
  11. #include <boost/beast/core/async_base.hpp>
  12. #include <boost/beast/core/flat_static_buffer.hpp>
  13. #include <boost/beast/core/read_size.hpp>
  14. #include <boost/asio/basic_stream_socket.hpp>
  15. #include <boost/asio/coroutine.hpp>
  16. #include <boost/throw_exception.hpp>
  17. namespace boost {
  18. namespace beast {
  19. namespace detail {
  20. // The number of bytes in the stack buffer when using non-blocking.
  21. static std::size_t constexpr default_max_stack_buffer = 16384;
  22. //------------------------------------------------------------------------------
  23. struct dynamic_read_ops
  24. {
  25. // read into a dynamic buffer until the
  26. // condition is met or an error occurs
  27. template<
  28. class Stream,
  29. class DynamicBuffer,
  30. class Condition,
  31. class Handler>
  32. class read_op
  33. : public asio::coroutine
  34. , public async_base<
  35. Handler, beast::executor_type<Stream>>
  36. {
  37. Stream& s_;
  38. DynamicBuffer& b_;
  39. Condition cond_;
  40. error_code ec_;
  41. std::size_t total_ = 0;
  42. public:
  43. read_op(read_op&&) = default;
  44. template<class Handler_, class Condition_>
  45. read_op(
  46. Handler_&& h,
  47. Stream& s,
  48. DynamicBuffer& b,
  49. Condition_&& cond)
  50. : async_base<Handler,
  51. beast::executor_type<Stream>>(
  52. std::forward<Handler_>(h),
  53. s.get_executor())
  54. , s_(s)
  55. , b_(b)
  56. , cond_(std::forward<Condition_>(cond))
  57. {
  58. (*this)({}, 0, false);
  59. }
  60. void
  61. operator()(
  62. error_code ec,
  63. std::size_t bytes_transferred,
  64. bool cont = true)
  65. {
  66. std::size_t max_prepare;
  67. BOOST_ASIO_CORO_REENTER(*this)
  68. {
  69. for(;;)
  70. {
  71. max_prepare = beast::read_size(b_, cond_(ec, total_, b_));
  72. if(max_prepare == 0)
  73. break;
  74. BOOST_ASIO_CORO_YIELD
  75. s_.async_read_some(
  76. b_.prepare(max_prepare), std::move(*this));
  77. b_.commit(bytes_transferred);
  78. total_ += bytes_transferred;
  79. }
  80. if(! cont)
  81. {
  82. // run this handler "as-if" using net::post
  83. // to reduce template instantiations
  84. ec_ = ec;
  85. BOOST_ASIO_CORO_YIELD
  86. s_.async_read_some(
  87. b_.prepare(0), std::move(*this));
  88. BOOST_BEAST_ASSIGN_EC(ec, ec_);
  89. }
  90. this->complete_now(ec, total_);
  91. }
  92. }
  93. };
  94. //------------------------------------------------------------------------------
  95. template <typename AsyncReadStream>
  96. struct run_read_op
  97. {
  98. AsyncReadStream* stream;
  99. using executor_type = typename AsyncReadStream::executor_type;
  100. executor_type
  101. get_executor() const noexcept
  102. {
  103. return stream->get_executor();
  104. }
  105. template<
  106. class DynamicBuffer,
  107. class Condition,
  108. class ReadHandler>
  109. void
  110. operator()(
  111. ReadHandler&& h,
  112. DynamicBuffer* b,
  113. Condition&& c)
  114. {
  115. // If you get an error on the following line it means
  116. // that your handler does not meet the documented type
  117. // requirements for the handler.
  118. static_assert(
  119. beast::detail::is_invocable<ReadHandler,
  120. void(error_code, std::size_t)>::value,
  121. "ReadHandler type requirements not met");
  122. read_op<
  123. AsyncReadStream,
  124. DynamicBuffer,
  125. typename std::decay<Condition>::type,
  126. typename std::decay<ReadHandler>::type>(
  127. std::forward<ReadHandler>(h),
  128. *stream,
  129. *b,
  130. std::forward<Condition>(c));
  131. }
  132. };
  133. };
  134. //------------------------------------------------------------------------------
  135. template<
  136. class SyncReadStream,
  137. class DynamicBuffer,
  138. class CompletionCondition,
  139. class>
  140. std::size_t
  141. read(
  142. SyncReadStream& stream,
  143. DynamicBuffer& buffer,
  144. CompletionCondition cond)
  145. {
  146. static_assert(is_sync_read_stream<SyncReadStream>::value,
  147. "SyncReadStream type requirements not met");
  148. static_assert(
  149. net::is_dynamic_buffer<DynamicBuffer>::value,
  150. "DynamicBuffer type requirements not met");
  151. static_assert(
  152. detail::is_invocable<CompletionCondition,
  153. void(error_code&, std::size_t, DynamicBuffer&)>::value,
  154. "CompletionCondition type requirements not met");
  155. error_code ec;
  156. auto const bytes_transferred = detail::read(
  157. stream, buffer, std::move(cond), ec);
  158. if(ec)
  159. BOOST_THROW_EXCEPTION(system_error{ec});
  160. return bytes_transferred;
  161. }
  162. template<
  163. class SyncReadStream,
  164. class DynamicBuffer,
  165. class CompletionCondition,
  166. class>
  167. std::size_t
  168. read(
  169. SyncReadStream& stream,
  170. DynamicBuffer& buffer,
  171. CompletionCondition cond,
  172. error_code& ec)
  173. {
  174. static_assert(is_sync_read_stream<SyncReadStream>::value,
  175. "SyncReadStream type requirements not met");
  176. static_assert(
  177. net::is_dynamic_buffer<DynamicBuffer>::value,
  178. "DynamicBuffer type requirements not met");
  179. static_assert(
  180. detail::is_invocable<CompletionCondition,
  181. void(error_code&, std::size_t, DynamicBuffer&)>::value,
  182. "CompletionCondition type requirements not met");
  183. ec = {};
  184. std::size_t total = 0;
  185. std::size_t max_prepare;
  186. for(;;)
  187. {
  188. max_prepare = beast::read_size(buffer, cond(ec, total, buffer));
  189. if(max_prepare == 0)
  190. break;
  191. std::size_t const bytes_transferred =
  192. stream.read_some(buffer.prepare(max_prepare), ec);
  193. buffer.commit(bytes_transferred);
  194. total += bytes_transferred;
  195. }
  196. return total;
  197. }
  198. template<
  199. class AsyncReadStream,
  200. class DynamicBuffer,
  201. class CompletionCondition,
  202. BOOST_BEAST_ASYNC_TPARAM2 ReadHandler,
  203. class>
  204. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  205. async_read(
  206. AsyncReadStream& stream,
  207. DynamicBuffer& buffer,
  208. CompletionCondition&& cond,
  209. ReadHandler&& handler)
  210. {
  211. static_assert(is_async_read_stream<AsyncReadStream>::value,
  212. "AsyncReadStream type requirements not met");
  213. static_assert(
  214. net::is_dynamic_buffer<DynamicBuffer>::value,
  215. "DynamicBuffer type requirements not met");
  216. static_assert(
  217. detail::is_invocable<CompletionCondition,
  218. void(error_code&, std::size_t, DynamicBuffer&)>::value,
  219. "CompletionCondition type requirements not met");
  220. return net::async_initiate<
  221. ReadHandler,
  222. void(error_code, std::size_t)>(
  223. typename dynamic_read_ops::run_read_op<AsyncReadStream>{&stream},
  224. handler,
  225. &buffer,
  226. std::forward<CompletionCondition>(cond));
  227. }
  228. } // detail
  229. } // beast
  230. } // boost
  231. #endif