chunk_encode.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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_CHUNK_ENCODE_HPP
  10. #define BOOST_BEAST_HTTP_CHUNK_ENCODE_HPP
  11. #include <boost/beast/core/detail/config.hpp>
  12. #include <boost/beast/core/buffers_cat.hpp>
  13. #include <boost/beast/core/string.hpp>
  14. #include <boost/beast/http/type_traits.hpp>
  15. #include <boost/beast/http/detail/chunk_encode.hpp>
  16. #include <boost/asio/buffer.hpp>
  17. #include <memory>
  18. #include <type_traits>
  19. namespace boost {
  20. namespace beast {
  21. namespace http {
  22. /** A chunked encoding crlf
  23. This implements a @b ConstBufferSequence holding the CRLF
  24. (`"\r\n"`) used as a delimiter in a @em chunk.
  25. To use this class, pass an instance of it to a
  26. stream algorithm as the buffer sequence:
  27. @code
  28. // writes "\r\n"
  29. boost::asio::write(stream, chunk_crlf{});
  30. @endcode
  31. @see https://tools.ietf.org/html/rfc7230#section-4.1
  32. */
  33. struct chunk_crlf
  34. {
  35. /// Constructor
  36. chunk_crlf() = default;
  37. //-----
  38. /// Required for @b ConstBufferSequence
  39. #if BOOST_BEAST_DOXYGEN
  40. using value_type = implementation_defined;
  41. #else
  42. using value_type = detail::chunk_crlf_iter::value_type;
  43. #endif
  44. /// Required for @b ConstBufferSequence
  45. using const_iterator = value_type const*;
  46. /// Required for @b ConstBufferSequence
  47. chunk_crlf(chunk_crlf const&) = default;
  48. /// Required for @b ConstBufferSequence
  49. const_iterator
  50. begin() const
  51. {
  52. return &detail::chunk_crlf_iter::value;
  53. }
  54. /// Required for @b ConstBufferSequence
  55. const_iterator
  56. end() const
  57. {
  58. return begin() + 1;
  59. }
  60. };
  61. //------------------------------------------------------------------------------
  62. /** A @em chunk header
  63. This implements a @b ConstBufferSequence representing the
  64. header of a @em chunk. The serialized format is as follows:
  65. @code
  66. chunk-header = 1*HEXDIG chunk-ext CRLF
  67. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  68. chunk-ext-name = token
  69. chunk-ext-val = token / quoted-string
  70. @endcode
  71. The chunk extension is optional. After the header and
  72. chunk body have been serialized, it is the callers
  73. responsibility to also serialize the final CRLF (`"\r\n"`).
  74. This class allows the caller to emit piecewise chunk bodies,
  75. by first serializing the chunk header using this class and then
  76. serializing the chunk body in a series of one or more calls to
  77. a stream write operation.
  78. To use this class, pass an instance of it to a
  79. stream algorithm as the buffer sequence:
  80. @code
  81. // writes "400;x\r\n"
  82. boost::asio::write(stream, chunk_header{1024, "x"});
  83. @endcode
  84. @see https://tools.ietf.org/html/rfc7230#section-4.1
  85. */
  86. class chunk_header
  87. {
  88. using view_type = buffers_cat_view<
  89. detail::chunk_size, // chunk-size
  90. boost::asio::const_buffer, // chunk-extensions
  91. chunk_crlf>; // CRLF
  92. std::shared_ptr<
  93. detail::chunk_extensions> exts_;
  94. view_type view_;
  95. public:
  96. /** Constructor
  97. This constructs a buffer sequence representing a
  98. @em chunked-body size and terminating CRLF (`"\r\n"`)
  99. with no chunk extensions.
  100. @param size The size of the chunk body that follows.
  101. The value must be greater than zero.
  102. @see https://tools.ietf.org/html/rfc7230#section-4.1
  103. */
  104. explicit
  105. chunk_header(std::size_t size);
  106. /** Constructor
  107. This constructs a buffer sequence representing a
  108. @em chunked-body size and terminating CRLF (`"\r\n"`)
  109. with provided chunk extensions.
  110. @param size The size of the chunk body that follows.
  111. The value must be greater than zero.
  112. @param extensions The chunk extensions string. This
  113. string must be formatted correctly as per rfc7230,
  114. using this BNF syntax:
  115. @code
  116. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  117. chunk-ext-name = token
  118. chunk-ext-val = token / quoted-string
  119. @endcode
  120. The data pointed to by this string view must remain
  121. valid for the lifetime of any operations performed on
  122. the object.
  123. @see https://tools.ietf.org/html/rfc7230#section-4.1.1
  124. */
  125. chunk_header(
  126. std::size_t size,
  127. string_view extensions);
  128. /** Constructor
  129. This constructs a buffer sequence representing a
  130. @em chunked-body size and terminating CRLF (`"\r\n"`)
  131. with provided chunk extensions.
  132. The default allocator is used to provide storage for the
  133. extensions object.
  134. @param size The size of the chunk body that follows.
  135. The value must be greater than zero.
  136. @param extensions The chunk extensions object. The expression
  137. `extensions.str()` must be valid, and the return type must
  138. be convertible to @ref string_view. This object will be copied
  139. or moved as needed to ensure that the chunk header object retains
  140. ownership of the buffers provided by the chunk extensions object.
  141. @note This function participates in overload resolution only
  142. if @b ChunkExtensions meets the requirements stated above.
  143. @see https://tools.ietf.org/html/rfc7230#section-4.1
  144. */
  145. template<class ChunkExtensions
  146. #if ! BOOST_BEAST_DOXYGEN
  147. , class = typename std::enable_if<
  148. detail::is_chunk_extensions<
  149. ChunkExtensions>::value>::type
  150. #endif
  151. >
  152. chunk_header(
  153. std::size_t size,
  154. ChunkExtensions&& extensions);
  155. /** Constructor
  156. This constructs a buffer sequence representing a
  157. @em chunked-body size and terminating CRLF (`"\r\n"`)
  158. with provided chunk extensions.
  159. The specified allocator is used to provide storage for the
  160. extensions object.
  161. @param size The size of the chunk body that follows.
  162. The value be greater than zero.
  163. @param extensions The chunk extensions object. The expression
  164. `extensions.str()` must be valid, and the return type must
  165. be convertible to @ref string_view. This object will be copied
  166. or moved as needed to ensure that the chunk header object retains
  167. ownership of the buffers provided by the chunk extensions object.
  168. @param allocator The allocator to provide storage for the moved
  169. or copied extensions object.
  170. @note This function participates in overload resolution only
  171. if @b ChunkExtensions meets the requirements stated above.
  172. @see https://tools.ietf.org/html/rfc7230#section-4.1
  173. */
  174. template<class ChunkExtensions, class Allocator
  175. #if ! BOOST_BEAST_DOXYGEN
  176. , class = typename std::enable_if<
  177. detail::is_chunk_extensions<
  178. ChunkExtensions>::value>::type
  179. #endif
  180. >
  181. chunk_header(
  182. std::size_t size,
  183. ChunkExtensions&& extensions,
  184. Allocator const& allocator);
  185. //-----
  186. /// Required for @b ConstBufferSequence
  187. #if BOOST_BEAST_DOXYGEN
  188. using value_type = implementation_defined;
  189. #else
  190. using value_type = typename view_type::value_type;
  191. #endif
  192. /// Required for @b ConstBufferSequence
  193. #if BOOST_BEAST_DOXYGEN
  194. using const_iterator = implementation_defined;
  195. #else
  196. using const_iterator = typename view_type::const_iterator;
  197. #endif
  198. /// Required for @b ConstBufferSequence
  199. chunk_header(chunk_header const&) = default;
  200. /// Required for @b ConstBufferSequence
  201. const_iterator
  202. begin() const
  203. {
  204. return view_.begin();
  205. }
  206. /// Required for @b ConstBufferSequence
  207. const_iterator
  208. end() const
  209. {
  210. return view_.end();
  211. }
  212. };
  213. //------------------------------------------------------------------------------
  214. /** A @em chunk
  215. This implements a @b ConstBufferSequence representing
  216. a @em chunk. The serialized format is as follows:
  217. @code
  218. chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF
  219. chunk-size = 1*HEXDIG
  220. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  221. chunk-ext-name = token
  222. chunk-ext-val = token / quoted-string
  223. chunk-data = 1*OCTET ; a sequence of chunk-size octets
  224. @endcode
  225. The chunk extension is optional.
  226. To use this class, pass an instance of it to a
  227. stream algorithm as the buffer sequence.
  228. @see https://tools.ietf.org/html/rfc7230#section-4.1
  229. */
  230. template<class ConstBufferSequence>
  231. class chunk_body
  232. {
  233. using view_type = buffers_cat_view<
  234. detail::chunk_size, // chunk-size
  235. boost::asio::const_buffer, // chunk-extensions
  236. chunk_crlf, // CRLF
  237. ConstBufferSequence, // chunk-body
  238. chunk_crlf>; // CRLF
  239. std::shared_ptr<
  240. detail::chunk_extensions> exts_;
  241. view_type view_;
  242. public:
  243. /** Constructor
  244. This constructs buffers representing a complete @em chunk
  245. with no chunk extensions and having the size and contents
  246. of the specified buffer sequence.
  247. @param buffers A buffer sequence representing the chunk
  248. body. Although the buffers object may be copied as necessary,
  249. ownership of the underlying memory blocks is retained by the
  250. caller, which must guarantee that they remain valid while this
  251. object is in use.
  252. @see https://tools.ietf.org/html/rfc7230#section-4.1
  253. */
  254. explicit
  255. chunk_body(
  256. ConstBufferSequence const& buffers);
  257. /** Constructor
  258. This constructs buffers representing a complete @em chunk
  259. with the passed chunk extensions and having the size and
  260. contents of the specified buffer sequence.
  261. @param buffers A buffer sequence representing the chunk
  262. body. Although the buffers object may be copied as necessary,
  263. ownership of the underlying memory blocks is retained by the
  264. caller, which must guarantee that they remain valid while this
  265. object is in use.
  266. @param extensions The chunk extensions string. This
  267. string must be formatted correctly as per rfc7230,
  268. using this BNF syntax:
  269. @code
  270. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  271. chunk-ext-name = token
  272. chunk-ext-val = token / quoted-string
  273. @endcode
  274. The data pointed to by this string view must remain
  275. valid for the lifetime of any operations performed on
  276. the object.
  277. @see https://tools.ietf.org/html/rfc7230#section-4.1.1
  278. */
  279. chunk_body(
  280. ConstBufferSequence const& buffers,
  281. string_view extensions);
  282. /** Constructor
  283. This constructs buffers representing a complete @em chunk
  284. with the passed chunk extensions and having the size and
  285. contents of the specified buffer sequence.
  286. The default allocator is used to provide storage for the
  287. extensions object.
  288. @param buffers A buffer sequence representing the chunk
  289. body. Although the buffers object may be copied as necessary,
  290. ownership of the underlying memory blocks is retained by the
  291. caller, which must guarantee that they remain valid while this
  292. object is in use.
  293. @param extensions The chunk extensions object. The expression
  294. `extensions.str()` must be valid, and the return type must
  295. be convertible to @ref string_view. This object will be copied
  296. or moved as needed to ensure that the chunk header object retains
  297. ownership of the buffers provided by the chunk extensions object.
  298. @note This function participates in overload resolution only
  299. if @b ChunkExtensions meets the requirements stated above.
  300. @see https://tools.ietf.org/html/rfc7230#section-4.1
  301. */
  302. template<class ChunkExtensions
  303. #if ! BOOST_BEAST_DOXYGEN
  304. , class = typename std::enable_if<
  305. ! std::is_convertible<typename std::decay<
  306. ChunkExtensions>::type, string_view>::value>::type
  307. #endif
  308. >
  309. chunk_body(
  310. ConstBufferSequence const& buffers,
  311. ChunkExtensions&& extensions);
  312. /** Constructor
  313. This constructs buffers representing a complete @em chunk
  314. with the passed chunk extensions and having the size and
  315. contents of the specified buffer sequence.
  316. The specified allocator is used to provide storage for the
  317. extensions object.
  318. @param buffers A buffer sequence representing the chunk
  319. body. Although the buffers object may be copied as necessary,
  320. ownership of the underlying memory blocks is retained by the
  321. caller, which must guarantee that they remain valid while this
  322. object is in use.
  323. @param extensions The chunk extensions object. The expression
  324. `extensions.str()` must be valid, and the return type must
  325. be convertible to @ref string_view. This object will be copied
  326. or moved as needed to ensure that the chunk header object retains
  327. ownership of the buffers provided by the chunk extensions object.
  328. @param allocator The allocator to provide storage for the moved
  329. or copied extensions object.
  330. @note This function participates in overload resolution only
  331. if @b ChunkExtensions meets the requirements stated above.
  332. @see https://tools.ietf.org/html/rfc7230#section-4.1
  333. */
  334. template<class ChunkExtensions, class Allocator
  335. #if ! BOOST_BEAST_DOXYGEN
  336. , class = typename std::enable_if<
  337. ! std::is_convertible<typename std::decay<
  338. ChunkExtensions>::type, string_view>::value>::type
  339. #endif
  340. >
  341. chunk_body(
  342. ConstBufferSequence const& buffers,
  343. ChunkExtensions&& extensions,
  344. Allocator const& allocator);
  345. //-----
  346. /// Required for @b ConstBufferSequence
  347. #if BOOST_BEAST_DOXYGEN
  348. using value_type = implementation_defined;
  349. #else
  350. using value_type = typename view_type::value_type;
  351. #endif
  352. /// Required for @b ConstBufferSequence
  353. #if BOOST_BEAST_DOXYGEN
  354. using const_iterator = implementation_defined;
  355. #else
  356. using const_iterator = typename view_type::const_iterator;
  357. #endif
  358. /// Required for @b ConstBufferSequence
  359. const_iterator
  360. begin() const
  361. {
  362. return view_.begin();
  363. }
  364. /// Required for @b ConstBufferSequence
  365. const_iterator
  366. end() const
  367. {
  368. return view_.end();
  369. }
  370. };
  371. //------------------------------------------------------------------------------
  372. /** A chunked-encoding last chunk
  373. */
  374. template<class Trailer = chunk_crlf>
  375. class chunk_last
  376. {
  377. static_assert(
  378. is_fields<Trailer>::value ||
  379. boost::asio::is_const_buffer_sequence<Trailer>::value,
  380. "Trailer requirements not met");
  381. using buffers_type = typename
  382. detail::buffers_or_fields<Trailer>::type;
  383. using view_type =
  384. buffers_cat_view<
  385. detail::chunk_size0, // "0\r\n"
  386. buffers_type>; // Trailer (includes CRLF)
  387. template<class Allocator>
  388. buffers_type
  389. prepare(Trailer const& trailer, Allocator const& alloc);
  390. buffers_type
  391. prepare(Trailer const& trailer, std::true_type);
  392. buffers_type
  393. prepare(Trailer const& trailer, std::false_type);
  394. std::shared_ptr<void> sp_;
  395. view_type view_;
  396. public:
  397. /** Constructor
  398. The last chunk will have an empty trailer
  399. */
  400. chunk_last();
  401. /** Constructor
  402. @param trailer The trailer to use. This may be
  403. a type meeting the requirements of either Fields
  404. or ConstBufferSequence. If it is a ConstBufferSequence,
  405. the trailer must be formatted correctly as per rfc7230
  406. including a CRLF on its own line to denote the end
  407. of the trailer.
  408. */
  409. explicit
  410. chunk_last(Trailer const& trailer);
  411. /** Constructor
  412. @param trailer The trailer to use. This type must
  413. meet the requirements of Fields.
  414. @param allocator The allocator to use for storing temporary
  415. data associated with the serialized trailer buffers.
  416. */
  417. #if BOOST_BEAST_DOXYGEN
  418. template<class Allocator>
  419. chunk_last(Trailer const& trailer, Allocator const& allocator);
  420. #else
  421. template<class DeducedTrailer, class Allocator,
  422. class = typename std::enable_if<
  423. is_fields<DeducedTrailer>::value>::type>
  424. chunk_last(
  425. DeducedTrailer const& trailer, Allocator const& allocator);
  426. #endif
  427. //-----
  428. /// Required for @b ConstBufferSequence
  429. chunk_last(chunk_last const&) = default;
  430. /// Required for @b ConstBufferSequence
  431. #if BOOST_BEAST_DOXYGEN
  432. using value_type = implementation_defined;
  433. #else
  434. using value_type =
  435. typename view_type::value_type;
  436. #endif
  437. /// Required for @b ConstBufferSequence
  438. #if BOOST_BEAST_DOXYGEN
  439. using const_iterator = implementation_defined;
  440. #else
  441. using const_iterator =
  442. typename view_type::const_iterator;
  443. #endif
  444. /// Required for @b ConstBufferSequence
  445. const_iterator
  446. begin() const
  447. {
  448. return view_.begin();
  449. }
  450. /// Required for @b ConstBufferSequence
  451. const_iterator
  452. end() const
  453. {
  454. return view_.end();
  455. }
  456. };
  457. //------------------------------------------------------------------------------
  458. /** A set of chunk extensions
  459. This container stores a set of chunk extensions suited for use with
  460. @ref chunk_header and @ref chunk_body. The container may be iterated
  461. to access the extensions in their structured form.
  462. Meets the requirements of ChunkExtensions
  463. */
  464. template<class Allocator>
  465. class basic_chunk_extensions
  466. {
  467. std::basic_string<char,
  468. std::char_traits<char>, Allocator> s_;
  469. std::basic_string<char,
  470. std::char_traits<char>, Allocator> range_;
  471. template<class FwdIt>
  472. FwdIt
  473. do_parse(FwdIt it, FwdIt last, error_code& ec);
  474. void
  475. do_insert(string_view name, string_view value);
  476. public:
  477. /** The type of value when iterating.
  478. The first element of the pair is the name, and the second
  479. element is the value which may be empty. The value is
  480. stored in its raw representation, without quotes or escapes.
  481. */
  482. using value_type = std::pair<string_view, string_view>;
  483. class const_iterator;
  484. /// Constructor
  485. basic_chunk_extensions() = default;
  486. /// Constructor
  487. basic_chunk_extensions(basic_chunk_extensions&&) = default;
  488. /// Constructor
  489. basic_chunk_extensions(basic_chunk_extensions const&) = default;
  490. /** Constructor
  491. @param allocator The allocator to use for storing the serialized extension
  492. */
  493. explicit
  494. basic_chunk_extensions(Allocator const& allocator)
  495. : s_(allocator)
  496. {
  497. }
  498. /** Clear the chunk extensions
  499. This preserves the capacity of the internal string
  500. used to hold the serialized representation.
  501. */
  502. void
  503. clear()
  504. {
  505. s_.clear();
  506. }
  507. /** Parse a set of chunk extensions
  508. Any previous extensions will be cleared
  509. */
  510. void
  511. parse(string_view s, error_code& ec);
  512. /** Insert an extension name with an empty value
  513. @param name The name of the extension
  514. */
  515. void
  516. insert(string_view name);
  517. /** Insert an extension value
  518. @param name The name of the extension
  519. @param value The value to insert. Depending on the
  520. contents, the serialized extension may use a quoted string.
  521. */
  522. void
  523. insert(string_view name, string_view value);
  524. /// Return the serialized representation of the chunk extension
  525. string_view
  526. str() const
  527. {
  528. return s_;
  529. }
  530. const_iterator
  531. begin() const;
  532. const_iterator
  533. end() const;
  534. };
  535. //------------------------------------------------------------------------------
  536. /// A set of chunk extensions
  537. using chunk_extensions =
  538. basic_chunk_extensions<std::allocator<char>>;
  539. /** Returns a @ref chunk_body
  540. This functions constructs and returns a complete
  541. @ref chunk_body for a chunk body represented by the
  542. specified buffer sequence.
  543. @param buffers The buffers representing the chunk body.
  544. @param args Optional arguments passed to the @ref chunk_body constructor.
  545. @note This function is provided as a notational convenience
  546. to omit specification of the class template arguments.
  547. */
  548. template<class ConstBufferSequence, class... Args>
  549. auto
  550. make_chunk(
  551. ConstBufferSequence const& buffers,
  552. Args&&... args) ->
  553. chunk_body<ConstBufferSequence>
  554. {
  555. return chunk_body<ConstBufferSequence>(
  556. buffers, std::forward<Args>(args)...);
  557. }
  558. /** Returns a @ref chunk_last
  559. @note This function is provided as a notational convenience
  560. to omit specification of the class template arguments.
  561. */
  562. inline
  563. chunk_last<chunk_crlf>
  564. make_chunk_last()
  565. {
  566. return chunk_last<chunk_crlf>{};
  567. }
  568. /** Returns a @ref chunk_last
  569. This function construct and returns a complete
  570. @ref chunk_last for a last chunk containing the
  571. specified trailers.
  572. @param trailer A ConstBufferSequence or
  573. @note This function is provided as a notational convenience
  574. to omit specification of the class template arguments.
  575. @param args Optional arguments passed to the @ref chunk_last
  576. constructor.
  577. */
  578. template<class Trailer, class... Args>
  579. chunk_last<Trailer>
  580. make_chunk_last(
  581. Trailer const& trailer,
  582. Args&&... args)
  583. {
  584. return chunk_last<Trailer>{
  585. trailer, std::forward<Args>(args)...};
  586. }
  587. } // http
  588. } // beast
  589. } // boost
  590. #include <boost/beast/http/impl/chunk_encode.ipp>
  591. #endif