chunk_encode.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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_DETAIL_CHUNK_ENCODE_HPP
  10. #define BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
  11. #include <boost/beast/core/type_traits.hpp>
  12. #include <boost/beast/http/type_traits.hpp>
  13. #include <boost/asio/buffer.hpp>
  14. #include <algorithm>
  15. #include <array>
  16. #include <cstddef>
  17. #include <memory>
  18. namespace boost {
  19. namespace beast {
  20. namespace http {
  21. namespace detail {
  22. struct chunk_extensions
  23. {
  24. virtual ~chunk_extensions() = default;
  25. virtual boost::asio::const_buffer str() = 0;
  26. };
  27. template<class ChunkExtensions>
  28. struct chunk_extensions_impl : chunk_extensions
  29. {
  30. ChunkExtensions ext_;
  31. chunk_extensions_impl(ChunkExtensions&& ext)
  32. : ext_(std::move(ext))
  33. {
  34. }
  35. chunk_extensions_impl(ChunkExtensions const& ext)
  36. : ext_(ext)
  37. {
  38. }
  39. boost::asio::const_buffer
  40. str() override
  41. {
  42. auto const s = ext_.str();
  43. return {s.data(), s.size()};
  44. }
  45. };
  46. template<class T, class = void>
  47. struct is_chunk_extensions : std::false_type {};
  48. template<class T>
  49. struct is_chunk_extensions<T, beast::detail::void_t<decltype(
  50. std::declval<string_view&>() = std::declval<T&>().str()
  51. )>> : std::true_type
  52. {
  53. };
  54. //------------------------------------------------------------------------------
  55. /** A buffer sequence containing a chunk-encoding header
  56. */
  57. class chunk_size
  58. {
  59. template<class OutIter>
  60. static
  61. OutIter
  62. to_hex(OutIter last, std::size_t n)
  63. {
  64. if(n == 0)
  65. {
  66. *--last = '0';
  67. return last;
  68. }
  69. while(n)
  70. {
  71. *--last = "0123456789abcdef"[n&0xf];
  72. n>>=4;
  73. }
  74. return last;
  75. }
  76. struct sequence
  77. {
  78. boost::asio::const_buffer b;
  79. char data[1 + 2 * sizeof(std::size_t)];
  80. explicit
  81. sequence(std::size_t n)
  82. {
  83. char* it0 = data + sizeof(data);
  84. auto it = to_hex(it0, n);
  85. b = {it,
  86. static_cast<std::size_t>(it0 - it)};
  87. }
  88. };
  89. std::shared_ptr<sequence> sp_;
  90. public:
  91. using value_type = boost::asio::const_buffer;
  92. using const_iterator = value_type const*;
  93. chunk_size(chunk_size const& other) = default;
  94. /** Construct a chunk header
  95. @param n The number of octets in this chunk.
  96. */
  97. chunk_size(std::size_t n)
  98. : sp_(std::make_shared<sequence>(n))
  99. {
  100. }
  101. const_iterator
  102. begin() const
  103. {
  104. return &sp_->b;
  105. }
  106. const_iterator
  107. end() const
  108. {
  109. return begin() + 1;
  110. }
  111. };
  112. //------------------------------------------------------------------------------
  113. /// Returns a buffer sequence holding a CRLF for chunk encoding
  114. inline
  115. boost::asio::const_buffer
  116. chunk_crlf()
  117. {
  118. return {"\r\n", 2};
  119. }
  120. /// Returns a buffer sequence holding a final chunk header
  121. inline
  122. boost::asio::const_buffer
  123. chunk_last()
  124. {
  125. return {"0\r\n", 3};
  126. }
  127. //------------------------------------------------------------------------------
  128. template<class = void>
  129. struct chunk_crlf_iter_type
  130. {
  131. class value_type
  132. {
  133. char const s[2] = {'\r', '\n'};
  134. public:
  135. value_type() = default;
  136. operator
  137. boost::asio::const_buffer() const
  138. {
  139. return {s, sizeof(s)};
  140. }
  141. };
  142. static value_type value;
  143. };
  144. template<class T>
  145. typename chunk_crlf_iter_type<T>::value_type
  146. chunk_crlf_iter_type<T>::value;
  147. using chunk_crlf_iter = chunk_crlf_iter_type<void>;
  148. //------------------------------------------------------------------------------
  149. template<class = void>
  150. struct chunk_size0_iter_type
  151. {
  152. class value_type
  153. {
  154. char const s[3] = {'0', '\r', '\n'};
  155. public:
  156. value_type() = default;
  157. operator
  158. boost::asio::const_buffer() const
  159. {
  160. return {s, sizeof(s)};
  161. }
  162. };
  163. static value_type value;
  164. };
  165. template<class T>
  166. typename chunk_size0_iter_type<T>::value_type
  167. chunk_size0_iter_type<T>::value;
  168. using chunk_size0_iter = chunk_size0_iter_type<void>;
  169. struct chunk_size0
  170. {
  171. using value_type = chunk_size0_iter::value_type;
  172. using const_iterator = value_type const*;
  173. const_iterator
  174. begin() const
  175. {
  176. return &chunk_size0_iter::value;
  177. }
  178. const_iterator
  179. end() const
  180. {
  181. return begin() + 1;
  182. }
  183. };
  184. //------------------------------------------------------------------------------
  185. template<class T,
  186. bool = is_fields<T>::value>
  187. struct buffers_or_fields
  188. {
  189. using type = typename
  190. T::writer::const_buffers_type;
  191. };
  192. template<class T>
  193. struct buffers_or_fields<T, false>
  194. {
  195. using type = T;
  196. };
  197. } // detail
  198. } // http
  199. } // beast
  200. } // boost
  201. #endif