buffer_body.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // Copyright (c) 2016-2017 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_HTTP_BUFFER_BODY_HPP
  10. #define BOOST_BEAST_HTTP_BUFFER_BODY_HPP
  11. #include <boost/beast/core/detail/config.hpp>
  12. #include <boost/beast/http/error.hpp>
  13. #include <boost/beast/http/message.hpp>
  14. #include <boost/beast/http/type_traits.hpp>
  15. #include <boost/optional.hpp>
  16. #include <type_traits>
  17. #include <utility>
  18. namespace boost {
  19. namespace beast {
  20. namespace http {
  21. /** A @b Body using a caller provided buffer
  22. Messages using this body type may be serialized and parsed.
  23. To use this class, the caller must initialize the members
  24. of @ref buffer_body::value_type to appropriate values before
  25. each call to read or write during a stream operation.
  26. */
  27. struct buffer_body
  28. {
  29. /// The type of the body member when used in a message.
  30. struct value_type
  31. {
  32. /** A pointer to a contiguous area of memory of @ref size octets, else `nullptr`.
  33. @par When Serializing
  34. If this is `nullptr` and `more` is `true`, the error
  35. @ref error::need_buffer will be returned from @ref serializer::get
  36. Otherwise, the serializer will use the memory pointed to
  37. by `data` having `size` octets of valid storage as the
  38. next buffer representing the body.
  39. @par When Parsing
  40. If this is `nullptr`, the error @ref error::need_buffer
  41. will be returned from @ref parser::put. Otherwise, the
  42. parser will store body octets into the memory pointed to
  43. by `data` having `size` octets of valid storage. After
  44. octets are stored, the `data` and `size` members are
  45. adjusted: `data` is incremented to point to the next
  46. octet after the data written, while `size` is decremented
  47. to reflect the remaining space at the memory location
  48. pointed to by `data`.
  49. */
  50. void* data = nullptr;
  51. /** The number of octets in the buffer pointed to by @ref data.
  52. @par When Serializing
  53. If `data` is `nullptr` during serialization, this value
  54. is ignored. Otherwise, it represents the number of valid
  55. body octets pointed to by `data`.
  56. @par When Parsing
  57. The value of this field will be decremented during parsing
  58. to indicate the number of remaining free octets in the
  59. buffer pointed to by `data`. When it reaches zero, the
  60. parser will return @ref error::need_buffer, indicating to
  61. the caller that the values of `data` and `size` should be
  62. updated to point to a new memory buffer.
  63. */
  64. std::size_t size = 0;
  65. /** `true` if this is not the last buffer.
  66. @par When Serializing
  67. If this is `true` and `data` is `nullptr`, the error
  68. @ref error::need_buffer will be returned from @ref serializer::get
  69. @par When Parsing
  70. This field is not used during parsing.
  71. */
  72. bool more = true;
  73. };
  74. /** The algorithm for parsing the body
  75. Meets the requirements of @b BodyReader.
  76. */
  77. #if BOOST_BEAST_DOXYGEN
  78. using reader = implementation_defined;
  79. #else
  80. class reader
  81. {
  82. value_type& body_;
  83. public:
  84. template<bool isRequest, class Fields>
  85. explicit
  86. reader(header<isRequest, Fields>&, value_type& b)
  87. : body_(b)
  88. {
  89. }
  90. void
  91. init(boost::optional<std::uint64_t> const&, error_code& ec)
  92. {
  93. ec.assign(0, ec.category());
  94. }
  95. template<class ConstBufferSequence>
  96. std::size_t
  97. put(ConstBufferSequence const& buffers,
  98. error_code& ec)
  99. {
  100. using boost::asio::buffer_size;
  101. using boost::asio::buffer_copy;
  102. if(! body_.data)
  103. {
  104. ec = error::need_buffer;
  105. return 0;
  106. }
  107. auto const bytes_transferred =
  108. buffer_copy(boost::asio::buffer(
  109. body_.data, body_.size), buffers);
  110. body_.data = static_cast<char*>(
  111. body_.data) + bytes_transferred;
  112. body_.size -= bytes_transferred;
  113. if(bytes_transferred == buffer_size(buffers))
  114. ec.assign(0, ec.category());
  115. else
  116. ec = error::need_buffer;
  117. return bytes_transferred;
  118. }
  119. void
  120. finish(error_code& ec)
  121. {
  122. ec.assign(0, ec.category());
  123. }
  124. };
  125. #endif
  126. /** The algorithm for serializing the body
  127. Meets the requirements of @b BodyWriter.
  128. */
  129. #if BOOST_BEAST_DOXYGEN
  130. using writer = implementation_defined;
  131. #else
  132. class writer
  133. {
  134. bool toggle_ = false;
  135. value_type const& body_;
  136. public:
  137. using const_buffers_type =
  138. boost::asio::const_buffer;
  139. template<bool isRequest, class Fields>
  140. explicit
  141. writer(header<isRequest, Fields> const&, value_type const& b)
  142. : body_(b)
  143. {
  144. }
  145. void
  146. init(error_code& ec)
  147. {
  148. ec.assign(0, ec.category());
  149. }
  150. boost::optional<
  151. std::pair<const_buffers_type, bool>>
  152. get(error_code& ec)
  153. {
  154. if(toggle_)
  155. {
  156. if(body_.more)
  157. {
  158. toggle_ = false;
  159. ec = error::need_buffer;
  160. }
  161. else
  162. {
  163. ec.assign(0, ec.category());
  164. }
  165. return boost::none;
  166. }
  167. if(body_.data)
  168. {
  169. ec.assign(0, ec.category());
  170. toggle_ = true;
  171. return {{const_buffers_type{
  172. body_.data, body_.size}, body_.more}};
  173. }
  174. if(body_.more)
  175. ec = error::need_buffer;
  176. else
  177. ec.assign(0, ec.category());
  178. return boost::none;
  179. }
  180. };
  181. #endif
  182. };
  183. #if ! BOOST_BEAST_DOXYGEN
  184. // operator<< is not supported for buffer_body
  185. template<bool isRequest, class Fields>
  186. std::ostream&
  187. operator<<(std::ostream& os, message<isRequest,
  188. buffer_body, Fields> const& msg) = delete;
  189. #endif
  190. } // http
  191. } // beast
  192. } // boost
  193. #endif