serializer.hpp 13 KB

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