chunk_encode.hpp 22 KB

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