serializer.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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_HTTP_SERIALIZER_HPP
  10. #define BOOST_BEAST_HTTP_SERIALIZER_HPP
  11. #include <boost/beast/core/detail/config.hpp>
  12. #include <boost/beast/core/buffers_cat.hpp>
  13. #include <boost/beast/core/buffers_prefix.hpp>
  14. #include <boost/beast/core/buffers_suffix.hpp>
  15. #include <boost/beast/core/string.hpp>
  16. #include <boost/beast/core/detail/variant.hpp>
  17. #include <boost/beast/http/message.hpp>
  18. #include <boost/beast/http/chunk_encode.hpp>
  19. #include <boost/asio/buffer.hpp>
  20. #include <boost/optional.hpp>
  21. namespace boost {
  22. namespace beast {
  23. namespace http {
  24. /** Provides buffer oriented HTTP message serialization functionality.
  25. An object of this type is used to serialize a complete
  26. HTTP message into a sequence of octets. To use this class,
  27. construct an instance with the message to be serialized.
  28. The implementation will automatically perform chunk encoding
  29. if the contents of the message indicate that chunk encoding
  30. is required.
  31. Chunked output produced by the serializer never contains chunk
  32. extensions or trailers, and the location of chunk boundaries
  33. is not specified. If callers require chunk extensions, trailers,
  34. or control over the exact contents of each chunk they should
  35. use the serializer to write just the message header, and then
  36. assume control over serializing the chunked payload by using
  37. the chunk buffer sequence types @ref chunk_body, @ref chunk_crlf,
  38. @ref chunk_header, and @ref chunk_last.
  39. @note
  40. Moving or copying the serializer after the first call to
  41. @ref serializer::next results in undefined behavior. Try to heap-allocate
  42. the serializer object if you need to move the serializer between multiple
  43. async operations (for example, between a call to `async_write_header` and
  44. `async_write`).
  45. @tparam isRequest `true` if the message is a request.
  46. @tparam Body The body type of the message.
  47. @tparam Fields The type of fields in the message.
  48. */
  49. template<
  50. bool isRequest,
  51. class Body,
  52. class Fields = fields>
  53. class serializer
  54. {
  55. public:
  56. static_assert(is_body<Body>::value,
  57. "Body type requirements not met");
  58. static_assert(is_body_writer<Body>::value,
  59. "BodyWriter type requirements not met");
  60. /** The type of message this serializer uses
  61. This may be const or non-const depending on the
  62. implementation of the corresponding <em>BodyWriter</em>.
  63. */
  64. #if BOOST_BEAST_DOXYGEN
  65. using value_type = __implementation_defined__;
  66. #else
  67. using value_type = typename std::conditional<
  68. std::is_constructible<typename Body::writer,
  69. header<isRequest, Fields>&,
  70. typename Body::value_type&>::value &&
  71. ! std::is_constructible<typename Body::writer,
  72. header<isRequest, Fields> const&,
  73. typename Body::value_type const&>::value,
  74. message<isRequest, Body, Fields>,
  75. message<isRequest, Body, Fields> const>::type;
  76. #endif
  77. private:
  78. enum
  79. {
  80. do_construct = 0,
  81. do_init = 10,
  82. do_header_only = 20,
  83. do_header = 30,
  84. do_body = 40,
  85. do_init_c = 50,
  86. do_header_only_c = 60,
  87. do_header_c = 70,
  88. do_body_c = 80,
  89. do_final_c = 90,
  90. #ifndef BOOST_BEAST_NO_BIG_VARIANTS
  91. do_body_final_c = 100,
  92. do_all_c = 110,
  93. #endif
  94. do_complete = 120
  95. };
  96. void fwrinit(std::true_type);
  97. void fwrinit(std::false_type);
  98. template<std::size_t, class Visit>
  99. void
  100. do_visit(error_code& ec, Visit& visit);
  101. using writer = typename Body::writer;
  102. using cb1_t = buffers_suffix<typename
  103. Fields::writer::const_buffers_type>; // header
  104. using pcb1_t = buffers_prefix_view<cb1_t const&>;
  105. using cb2_t = buffers_suffix<buffers_cat_view<
  106. typename Fields::writer::const_buffers_type,// header
  107. typename writer::const_buffers_type>>; // body
  108. using pcb2_t = buffers_prefix_view<cb2_t const&>;
  109. using cb3_t = buffers_suffix<
  110. typename writer::const_buffers_type>; // body
  111. using pcb3_t = buffers_prefix_view<cb3_t const&>;
  112. using cb4_t = buffers_suffix<buffers_cat_view<
  113. typename Fields::writer::const_buffers_type,// header
  114. detail::chunk_size, // chunk-size
  115. net::const_buffer, // chunk-ext
  116. chunk_crlf, // crlf
  117. typename writer::const_buffers_type, // body
  118. chunk_crlf>>; // crlf
  119. using pcb4_t = buffers_prefix_view<cb4_t const&>;
  120. using cb5_t = buffers_suffix<buffers_cat_view<
  121. detail::chunk_size, // chunk-header
  122. net::const_buffer, // chunk-ext
  123. chunk_crlf, // crlf
  124. typename writer::const_buffers_type, // body
  125. chunk_crlf>>; // crlf
  126. using pcb5_t = buffers_prefix_view<cb5_t const&>;
  127. using cb6_t = buffers_suffix<buffers_cat_view<
  128. detail::chunk_size, // chunk-header
  129. net::const_buffer, // chunk-size
  130. chunk_crlf, // crlf
  131. typename writer::const_buffers_type, // body
  132. chunk_crlf, // crlf
  133. net::const_buffer, // chunk-final
  134. net::const_buffer, // trailers
  135. chunk_crlf>>; // crlf
  136. using pcb6_t = buffers_prefix_view<cb6_t const&>;
  137. using cb7_t = buffers_suffix<buffers_cat_view<
  138. typename Fields::writer::const_buffers_type,// header
  139. detail::chunk_size, // chunk-size
  140. net::const_buffer, // chunk-ext
  141. chunk_crlf, // crlf
  142. typename writer::const_buffers_type, // body
  143. chunk_crlf, // crlf
  144. net::const_buffer, // chunk-final
  145. net::const_buffer, // trailers
  146. chunk_crlf>>; // crlf
  147. using pcb7_t = buffers_prefix_view<cb7_t const&>;
  148. using cb8_t = buffers_suffix<buffers_cat_view<
  149. net::const_buffer, // chunk-final
  150. net::const_buffer, // trailers
  151. chunk_crlf>>; // crlf
  152. using pcb8_t = buffers_prefix_view<cb8_t const&>;
  153. value_type& m_;
  154. writer wr_;
  155. boost::optional<typename Fields::writer> fwr_;
  156. beast::detail::variant<
  157. cb1_t, cb2_t, cb3_t, cb4_t,
  158. cb5_t ,cb6_t, cb7_t, cb8_t> v_;
  159. beast::detail::variant<
  160. pcb1_t, pcb2_t, pcb3_t, pcb4_t,
  161. pcb5_t ,pcb6_t, pcb7_t, pcb8_t> pv_;
  162. std::size_t limit_ =
  163. (std::numeric_limits<std::size_t>::max)();
  164. int s_ = do_construct;
  165. bool split_ = false;
  166. bool header_done_ = false;
  167. bool more_ = false;
  168. public:
  169. /** Move Constructor
  170. @note
  171. Moving or copying the serializer after the first call to
  172. @ref serializer::next results in undefined behavior. Try to heap-allocate
  173. the serializer object if you need to move the serializer between multiple
  174. async operations (for example, between a call to `async_write_header` and
  175. `async_write`).
  176. */
  177. serializer(serializer&&) = default;
  178. /** Copy Constructor
  179. @note
  180. Moving or copying the serializer after the first call to
  181. @ref serializer::next results in undefined behavior. Try to heap-allocate
  182. the serializer object if you need to move the serializer between multiple
  183. async operations (for example, between a call to `async_write_header` and
  184. `async_write`).
  185. */
  186. serializer(serializer const&) = default;
  187. /// Assignment
  188. serializer& operator=(serializer const&) = delete;
  189. /** Constructor
  190. The implementation guarantees that the message passed on
  191. construction will not be accessed until the first call to
  192. @ref next. This allows the message to be lazily created.
  193. For example, if the header is filled in before serialization.
  194. @param msg A reference to the message to serialize, which must
  195. remain valid for the lifetime of the serializer. Depending on
  196. the type of Body used, this may or may not be a `const` reference.
  197. @note This function participates in overload resolution only if
  198. Body::writer is constructible from a `const` message reference.
  199. */
  200. explicit
  201. serializer(value_type& msg);
  202. /// Returns the message being serialized
  203. value_type&
  204. get()
  205. {
  206. return m_;
  207. }
  208. /// Returns the serialized buffer size limit
  209. std::size_t
  210. limit()
  211. {
  212. return limit_;
  213. }
  214. /** Set the serialized buffer size limit
  215. This function adjusts the limit on the maximum size of the
  216. buffers passed to the visitor. The new size limit takes effect
  217. in the following call to @ref next.
  218. The default is no buffer size limit.
  219. @param limit The new buffer size limit. If this number
  220. is zero, the size limit is removed.
  221. */
  222. void
  223. limit(std::size_t limit)
  224. {
  225. limit_ = limit > 0 ? limit :
  226. (std::numeric_limits<std::size_t>::max)();
  227. }
  228. /** Returns `true` if we will pause after writing the complete header.
  229. */
  230. bool
  231. split()
  232. {
  233. return split_;
  234. }
  235. /** Set whether the header and body are written separately.
  236. When the split feature is enabled, the implementation will
  237. write only the octets corresponding to the serialized header
  238. first. If the header has already been written, this function
  239. will have no effect on output.
  240. */
  241. void
  242. split(bool v)
  243. {
  244. split_ = v;
  245. }
  246. /** Return `true` if serialization of the header is complete.
  247. This function indicates whether or not all buffers containing
  248. serialized header octets have been retrieved.
  249. */
  250. bool
  251. is_header_done()
  252. {
  253. return header_done_;
  254. }
  255. /** Return `true` if serialization is complete.
  256. The operation is complete when all octets corresponding
  257. to the serialized representation of the message have been
  258. successfully retrieved.
  259. */
  260. bool
  261. is_done() const
  262. {
  263. return s_ == do_complete;
  264. }
  265. /** Returns the next set of buffers in the serialization.
  266. This function will attempt to call the `visit` function
  267. object with a <em>ConstBufferSequence</em> of unspecified type
  268. representing the next set of buffers in the serialization
  269. of the message represented by this object.
  270. If there are no more buffers in the serialization, the
  271. visit function will not be called. In this case, no error
  272. will be indicated, and the function @ref is_done will
  273. return `true`.
  274. @param ec Set to the error, if any occurred.
  275. @param visit The function to call. The equivalent function
  276. signature of this object must be:
  277. @code
  278. template<class ConstBufferSequence>
  279. void visit(error_code&, ConstBufferSequence const&);
  280. @endcode
  281. The function is not copied, if no error occurs it will be
  282. invoked before the call to @ref next returns.
  283. */
  284. template<class Visit>
  285. void
  286. next(error_code& ec, Visit&& visit);
  287. /** Consume buffer octets in the serialization.
  288. This function should be called after one or more octets
  289. contained in the buffers provided in the prior call
  290. to @ref next have been used.
  291. After a call to @ref consume, callers should check the
  292. return value of @ref is_done to determine if the entire
  293. message has been serialized.
  294. @param n The number of octets to consume. This number must
  295. be greater than zero and no greater than the number of
  296. octets in the buffers provided in the prior call to @ref next.
  297. */
  298. void
  299. consume(std::size_t n);
  300. /** Provides low-level access to the associated <em>BodyWriter</em>
  301. This function provides access to the instance of the writer
  302. associated with the body and created by the serializer
  303. upon construction. The behavior of accessing this object
  304. is defined by the specification of the particular writer
  305. and its associated body.
  306. @return A reference to the writer.
  307. */
  308. writer&
  309. writer_impl()
  310. {
  311. return wr_;
  312. }
  313. };
  314. /// A serializer for HTTP/1 requests
  315. template<class Body, class Fields = fields>
  316. using request_serializer = serializer<true, Body, Fields>;
  317. /// A serializer for HTTP/1 responses
  318. template<class Body, class Fields = fields>
  319. using response_serializer = serializer<false, Body, Fields>;
  320. } // http
  321. } // beast
  322. } // boost
  323. #include <boost/beast/http/impl/serializer.hpp>
  324. #endif