buffered_read_stream.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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_BUFFERED_READ_STREAM_HPP
  10. #define BOOST_BEAST_BUFFERED_READ_STREAM_HPP
  11. #include <boost/beast/core/detail/config.hpp>
  12. #include <boost/beast/core/error.hpp>
  13. #include <boost/beast/core/multi_buffer.hpp>
  14. #include <boost/beast/core/stream_traits.hpp>
  15. #include <boost/asio/async_result.hpp>
  16. #include <boost/asio/buffer.hpp>
  17. #include <boost/asio/io_context.hpp>
  18. #include <cstdint>
  19. #include <utility>
  20. namespace boost {
  21. namespace beast {
  22. /** A <em>Stream</em> with attached <em>DynamicBuffer</em> to buffer reads.
  23. This wraps a <em>Stream</em> implementation so that calls to write are
  24. passed through to the underlying stream, while calls to read will
  25. first consume the input sequence stored in a <em>DynamicBuffer</em> which
  26. is part of the object.
  27. The use-case for this class is different than that of the
  28. `net::buffered_read_stream`. It is designed to facilitate
  29. the use of `net::read_until`, and to allow buffers
  30. acquired during detection of handshakes to be made transparently
  31. available to callers. A hypothetical implementation of the
  32. buffered version of `net::ssl::stream::async_handshake`
  33. could make use of this wrapper.
  34. Uses:
  35. @li Transparently leave untouched input acquired in calls
  36. to `net::read_until` behind for subsequent callers.
  37. @li "Preload" a stream with handshake input data acquired
  38. from other sources.
  39. Example:
  40. @code
  41. // Process the next HTTP header on the stream,
  42. // leaving excess bytes behind for the next call.
  43. //
  44. template<class Stream, class DynamicBuffer>
  45. void process_http_message(
  46. buffered_read_stream<Stream, DynamicBuffer>& stream)
  47. {
  48. // Read up to and including the end of the HTTP
  49. // header, leaving the sequence in the stream's
  50. // buffer. read_until may read past the end of the
  51. // headers; the return value will include only the
  52. // part up to the end of the delimiter.
  53. //
  54. std::size_t bytes_transferred =
  55. net::read_until(
  56. stream.next_layer(), stream.buffer(), "\r\n\r\n");
  57. // Use buffers_prefix() to limit the input
  58. // sequence to only the data up to and including
  59. // the trailing "\r\n\r\n".
  60. //
  61. auto header_buffers = buffers_prefix(
  62. bytes_transferred, stream.buffer().data());
  63. ...
  64. // Discard the portion of the input corresponding
  65. // to the HTTP headers.
  66. //
  67. stream.buffer().consume(bytes_transferred);
  68. // Everything we read from the stream
  69. // is part of the content-body.
  70. }
  71. @endcode
  72. @tparam Stream The type of stream to wrap.
  73. @tparam DynamicBuffer The type of stream buffer to use.
  74. */
  75. template<class Stream, class DynamicBuffer>
  76. class buffered_read_stream
  77. {
  78. static_assert(
  79. net::is_dynamic_buffer<DynamicBuffer>::value,
  80. "DynamicBuffer type requirements not met");
  81. struct ops;
  82. DynamicBuffer buffer_;
  83. std::size_t capacity_ = 0;
  84. Stream next_layer_;
  85. public:
  86. /// The type of the internal buffer
  87. using buffer_type = DynamicBuffer;
  88. /// The type of the next layer.
  89. using next_layer_type =
  90. typename std::remove_reference<Stream>::type;
  91. /** Move constructor.
  92. @note The behavior of move assignment on or from streams
  93. with active or pending operations is undefined.
  94. */
  95. buffered_read_stream(buffered_read_stream&&) = default;
  96. /** Move assignment.
  97. @note The behavior of move assignment on or from streams
  98. with active or pending operations is undefined.
  99. */
  100. buffered_read_stream& operator=(buffered_read_stream&&) = default;
  101. /** Construct the wrapping stream.
  102. @param args Parameters forwarded to the `Stream` constructor.
  103. */
  104. template<class... Args>
  105. explicit
  106. buffered_read_stream(Args&&... args);
  107. /// Get a reference to the next layer.
  108. next_layer_type&
  109. next_layer() noexcept
  110. {
  111. return next_layer_;
  112. }
  113. /// Get a const reference to the next layer.
  114. next_layer_type const&
  115. next_layer() const noexcept
  116. {
  117. return next_layer_;
  118. }
  119. using executor_type =
  120. beast::executor_type<next_layer_type>;
  121. /** Get the executor associated with the object.
  122. This function may be used to obtain the executor object that the stream
  123. uses to dispatch handlers for asynchronous operations.
  124. @return A copy of the executor that stream will use to dispatch handlers.
  125. */
  126. executor_type
  127. get_executor() noexcept
  128. {
  129. return next_layer_.get_executor();
  130. }
  131. /** Access the internal buffer.
  132. The internal buffer is returned. It is possible for the
  133. caller to break invariants with this function. For example,
  134. by causing the internal buffer size to increase beyond
  135. the caller defined maximum.
  136. */
  137. DynamicBuffer&
  138. buffer() noexcept
  139. {
  140. return buffer_;
  141. }
  142. /// Access the internal buffer
  143. DynamicBuffer const&
  144. buffer() const noexcept
  145. {
  146. return buffer_;
  147. }
  148. /** Set the maximum buffer size.
  149. This changes the maximum size of the internal buffer used
  150. to hold read data. No bytes are discarded by this call. If
  151. the buffer size is set to zero, no more data will be buffered.
  152. Thread safety:
  153. The caller is responsible for making sure the call is
  154. made from the same implicit or explicit strand.
  155. @param size The number of bytes in the read buffer.
  156. @note This is a soft limit. If the new maximum size is smaller
  157. than the amount of data in the buffer, no bytes are discarded.
  158. */
  159. void
  160. capacity(std::size_t size) noexcept
  161. {
  162. capacity_ = size;
  163. }
  164. /** Read some data from the stream.
  165. This function is used to read data from the stream.
  166. The function call will block until one or more bytes of
  167. data has been read successfully, or until an error occurs.
  168. @param buffers One or more buffers into which the data will be read.
  169. @return The number of bytes read.
  170. @throws system_error Thrown on failure.
  171. */
  172. template<class MutableBufferSequence>
  173. std::size_t
  174. read_some(MutableBufferSequence const& buffers);
  175. /** Read some data from the stream.
  176. This function is used to read data from the stream.
  177. The function call will block until one or more bytes of
  178. data has been read successfully, or until an error occurs.
  179. @param buffers One or more buffers into which the data will be read.
  180. @param ec Set to the error, if any occurred.
  181. @return The number of bytes read, or 0 on error.
  182. */
  183. template<class MutableBufferSequence>
  184. std::size_t
  185. read_some(MutableBufferSequence const& buffers,
  186. error_code& ec);
  187. /** Start an asynchronous read.
  188. This function is used to asynchronously read data from
  189. the stream. The function call always returns immediately.
  190. @param buffers One or more buffers into which the data
  191. will be read. Although the buffers object may be copied
  192. as necessary, ownership of the underlying memory blocks
  193. is retained by the caller, which must guarantee that they
  194. remain valid until the handler is called.
  195. @param handler The completion handler to invoke when the operation
  196. completes. The implementation takes ownership of the handler by
  197. performing a decay-copy. The equivalent function signature of
  198. the handler must be:
  199. @code
  200. void handler(
  201. error_code const& error, // result of operation
  202. std::size_t bytes_transferred // number of bytes transferred
  203. );
  204. @endcode
  205. If the handler has an associated immediate executor,
  206. an immediate completion will be dispatched to it.
  207. Otherwise, the handler will not be invoked from within
  208. this function. Invocation of the handler will be performed
  209. by dispatching to the immediate executor. If no
  210. immediate executor is specified, this is equivalent
  211. to using `net::post`. */
  212. template<
  213. class MutableBufferSequence,
  214. BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
  215. net::default_completion_token_t<executor_type>>
  216. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  217. async_read_some(
  218. MutableBufferSequence const& buffers,
  219. ReadHandler&& handler =
  220. net::default_completion_token_t<executor_type>{});
  221. /** Write some data to the stream.
  222. This function is used to write data to the stream.
  223. The function call will block until one or more bytes of the
  224. data has been written successfully, or until an error occurs.
  225. @param buffers One or more data buffers to be written to the stream.
  226. @return The number of bytes written.
  227. @throws system_error Thrown on failure.
  228. */
  229. template<class ConstBufferSequence>
  230. std::size_t
  231. write_some(ConstBufferSequence const& buffers)
  232. {
  233. static_assert(is_sync_write_stream<next_layer_type>::value,
  234. "SyncWriteStream type requirements not met");
  235. return next_layer_.write_some(buffers);
  236. }
  237. /** Write some data to the stream.
  238. This function is used to write data to the stream.
  239. The function call will block until one or more bytes of the
  240. data has been written successfully, or until an error occurs.
  241. @param buffers One or more data buffers to be written to the stream.
  242. @param ec Set to the error, if any occurred.
  243. @return The number of bytes written.
  244. */
  245. template<class ConstBufferSequence>
  246. std::size_t
  247. write_some(ConstBufferSequence const& buffers,
  248. error_code& ec)
  249. {
  250. static_assert(is_sync_write_stream<next_layer_type>::value,
  251. "SyncWriteStream type requirements not met");
  252. return next_layer_.write_some(buffers, ec);
  253. }
  254. /** Start an asynchronous write.
  255. This function is used to asynchronously write data from
  256. the stream. The function call always returns immediately.
  257. @param buffers One or more data buffers to be written to
  258. the stream. Although the buffers object may be copied as
  259. necessary, ownership of the underlying memory blocks is
  260. retained by the caller, which must guarantee that they
  261. remain valid until the handler is called.
  262. @param handler The completion handler to invoke when the operation
  263. completes. The implementation takes ownership of the handler by
  264. performing a decay-copy. The equivalent function signature of
  265. the handler must be:
  266. @code
  267. void handler(
  268. error_code const& error, // result of operation
  269. std::size_t bytes_transferred // number of bytes transferred
  270. );
  271. @endcode
  272. If the handler has an associated immediate executor,
  273. an immediate completion will be dispatched to it.
  274. Otherwise, the handler will not be invoked from within
  275. this function. Invocation of the handler will be performed
  276. by dispatching to the immediate executor. If no
  277. immediate executor is specified, this is equivalent
  278. to using `net::post`. */
  279. template<
  280. class ConstBufferSequence,
  281. BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
  282. net::default_completion_token_t<executor_type>>
  283. BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
  284. async_write_some(
  285. ConstBufferSequence const& buffers,
  286. WriteHandler&& handler =
  287. net::default_completion_token_t<executor_type>{});
  288. };
  289. } // beast
  290. } // boost
  291. #include <boost/beast/core/impl/buffered_read_stream.hpp>
  292. #endif