string_body.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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_STRING_BODY_HPP
  10. #define BOOST_BEAST_HTTP_STRING_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/core/detail/type_traits.hpp>
  15. #include <boost/asio/buffer.hpp>
  16. #include <boost/optional.hpp>
  17. #include <cstdint>
  18. #include <limits>
  19. #include <memory>
  20. #include <stdexcept>
  21. #include <string>
  22. #include <utility>
  23. namespace boost {
  24. namespace beast {
  25. namespace http {
  26. /** A @b Body using `std::basic_string`
  27. This body uses `std::basic_string` as a memory-based container
  28. for holding message payloads. Messages using this body type
  29. may be serialized and parsed.
  30. */
  31. template<
  32. class CharT,
  33. class Traits = std::char_traits<CharT>,
  34. class Allocator = std::allocator<CharT>>
  35. struct basic_string_body
  36. {
  37. private:
  38. static_assert(
  39. std::is_integral<CharT>::value &&
  40. sizeof(CharT) == 1,
  41. "CharT requirements not met");
  42. public:
  43. /** The type of container used for the body
  44. This determines the type of @ref message::body
  45. when this body type is used with a message container.
  46. */
  47. using value_type =
  48. std::basic_string<CharT, Traits, Allocator>;
  49. /** Returns the payload size of the body
  50. When this body is used with @ref message::prepare_payload,
  51. the Content-Length will be set to the payload size, and
  52. any chunked Transfer-Encoding will be removed.
  53. */
  54. static
  55. std::uint64_t
  56. size(value_type const& body)
  57. {
  58. return body.size();
  59. }
  60. /** The algorithm for parsing the body
  61. Meets the requirements of @b BodyReader.
  62. */
  63. #if BOOST_BEAST_DOXYGEN
  64. using reader = implementation_defined;
  65. #else
  66. class reader
  67. {
  68. value_type& body_;
  69. public:
  70. template<bool isRequest, class Fields>
  71. explicit
  72. reader(header<isRequest, Fields>&, value_type& b)
  73. : body_(b)
  74. {
  75. }
  76. void
  77. init(boost::optional<
  78. std::uint64_t> const& length, error_code& ec)
  79. {
  80. if(length)
  81. {
  82. if(static_cast<std::size_t>(*length) != *length)
  83. {
  84. ec = error::buffer_overflow;
  85. return;
  86. }
  87. try
  88. {
  89. body_.reserve(
  90. static_cast<std::size_t>(*length));
  91. }
  92. catch(std::exception const&)
  93. {
  94. ec = error::buffer_overflow;
  95. return;
  96. }
  97. }
  98. ec.assign(0, ec.category());
  99. }
  100. template<class ConstBufferSequence>
  101. std::size_t
  102. put(ConstBufferSequence const& buffers,
  103. error_code& ec)
  104. {
  105. using boost::asio::buffer_size;
  106. using boost::asio::buffer_copy;
  107. auto const extra = buffer_size(buffers);
  108. auto const size = body_.size();
  109. try
  110. {
  111. body_.resize(size + extra);
  112. }
  113. catch(std::exception const&)
  114. {
  115. ec = error::buffer_overflow;
  116. return 0;
  117. }
  118. ec.assign(0, ec.category());
  119. CharT* dest = &body_[size];
  120. for(auto b : beast::detail::buffers_range(buffers))
  121. {
  122. Traits::copy(dest, static_cast<
  123. CharT const*>(b.data()), b.size());
  124. dest += b.size();
  125. }
  126. return extra;
  127. }
  128. void
  129. finish(error_code& ec)
  130. {
  131. ec.assign(0, ec.category());
  132. }
  133. };
  134. #endif
  135. /** The algorithm for serializing the body
  136. Meets the requirements of @b BodyWriter.
  137. */
  138. #if BOOST_BEAST_DOXYGEN
  139. using writer = implementation_defined;
  140. #else
  141. class writer
  142. {
  143. value_type const& body_;
  144. public:
  145. using const_buffers_type =
  146. boost::asio::const_buffer;
  147. template<bool isRequest, class Fields>
  148. explicit
  149. writer(header<isRequest, Fields> const&, value_type const& b)
  150. : body_(b)
  151. {
  152. }
  153. void
  154. init(error_code& ec)
  155. {
  156. ec.assign(0, ec.category());
  157. }
  158. boost::optional<std::pair<const_buffers_type, bool>>
  159. get(error_code& ec)
  160. {
  161. ec.assign(0, ec.category());
  162. return {{const_buffers_type{
  163. body_.data(), body_.size()}, false}};
  164. }
  165. };
  166. #endif
  167. };
  168. /// A @b Body using `std::string`
  169. using string_body = basic_string_body<char>;
  170. } // http
  171. } // beast
  172. } // boost
  173. #endif