parser.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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_PARSER_HPP
  10. #define BOOST_BEAST_HTTP_PARSER_HPP
  11. #include <boost/beast/core/detail/config.hpp>
  12. #include <boost/beast/http/basic_parser.hpp>
  13. #include <boost/beast/http/message.hpp>
  14. #include <boost/beast/http/type_traits.hpp>
  15. #include <boost/optional.hpp>
  16. #include <boost/throw_exception.hpp>
  17. #include <functional>
  18. #include <memory>
  19. #include <type_traits>
  20. #include <utility>
  21. namespace boost {
  22. namespace beast {
  23. namespace http {
  24. /** An HTTP/1 parser for producing a message.
  25. This class uses the basic HTTP/1 wire format parser to convert
  26. a series of octets into a @ref message using the @ref basic_fields
  27. container to represent the fields.
  28. @tparam isRequest Indicates whether a request or response
  29. will be parsed.
  30. @tparam Body The type used to represent the body. This must
  31. meet the requirements of @b Body.
  32. @tparam Allocator The type of allocator used with the
  33. @ref basic_fields container.
  34. @note A new instance of the parser is required for each message.
  35. */
  36. template<
  37. bool isRequest,
  38. class Body,
  39. class Allocator = std::allocator<char>>
  40. class parser
  41. : public basic_parser<isRequest,
  42. parser<isRequest, Body, Allocator>>
  43. {
  44. static_assert(is_body<Body>::value,
  45. "Body requirements not met");
  46. static_assert(is_body_reader<Body>::value,
  47. "BodyReader requirements not met");
  48. template<bool, class, class>
  49. friend class parser;
  50. using base_type = basic_parser<isRequest,
  51. parser<isRequest, Body, Allocator>>;
  52. message<isRequest, Body, basic_fields<Allocator>> m_;
  53. typename Body::reader rd_;
  54. bool rd_inited_ = false;
  55. std::function<void(
  56. std::uint64_t,
  57. string_view,
  58. error_code&)> cb_h_;
  59. std::function<std::size_t(
  60. std::uint64_t,
  61. string_view,
  62. error_code&)> cb_b_;
  63. public:
  64. /// The type of message returned by the parser
  65. using value_type =
  66. message<isRequest, Body, basic_fields<Allocator>>;
  67. /// Destructor
  68. ~parser() = default;
  69. /// Constructor (disallowed)
  70. parser(parser const&) = delete;
  71. /// Assignment (disallowed)
  72. parser& operator=(parser const&) = delete;
  73. /// Constructor (disallowed)
  74. parser(parser&& other) = delete;
  75. /// Constructor
  76. parser();
  77. /** Constructor
  78. @param args Optional arguments forwarded to the
  79. @ref http::message constructor.
  80. @note This function participates in overload
  81. resolution only if the first argument is not a
  82. @ref parser.
  83. */
  84. #if BOOST_BEAST_DOXYGEN
  85. template<class... Args>
  86. explicit
  87. parser(Args&&... args);
  88. #else
  89. template<class Arg1, class... ArgN,
  90. class = typename std::enable_if<
  91. ! detail::is_parser<typename
  92. std::decay<Arg1>::type>::value>::type>
  93. explicit
  94. parser(Arg1&& arg1, ArgN&&... argn);
  95. #endif
  96. /** Construct a parser from another parser, changing the Body type.
  97. This constructs a new parser by move constructing the
  98. header from another parser with a different body type. The
  99. constructed-from parser must not have any parsed body octets or
  100. initialized @b BodyReader, otherwise an exception is generated.
  101. @par Example
  102. @code
  103. // Deferred body type commitment
  104. request_parser<empty_body> req0;
  105. ...
  106. request_parser<string_body> req{std::move(req0)};
  107. @endcode
  108. If an exception is thrown, the state of the constructed-from
  109. parser is undefined.
  110. @param parser The other parser to construct from. After
  111. this call returns, the constructed-from parser may only
  112. be destroyed.
  113. @param args Optional arguments forwarded to the message
  114. constructor.
  115. @throws std::invalid_argument Thrown when the constructed-from
  116. parser has already initialized a body reader.
  117. @note This function participates in overload resolution only
  118. if the other parser uses a different body type.
  119. */
  120. #if BOOST_BEAST_DOXYGEN
  121. template<class OtherBody, class... Args>
  122. #else
  123. template<class OtherBody, class... Args,
  124. class = typename std::enable_if<
  125. ! std::is_same<Body, OtherBody>::value>::type>
  126. #endif
  127. explicit
  128. parser(parser<isRequest, OtherBody,
  129. Allocator>&& parser, Args&&... args);
  130. /** Returns the parsed message.
  131. Depending on the parser's progress,
  132. parts of this object may be incomplete.
  133. */
  134. value_type const&
  135. get() const
  136. {
  137. return m_;
  138. }
  139. /** Returns the parsed message.
  140. Depending on the parser's progress,
  141. parts of this object may be incomplete.
  142. */
  143. value_type&
  144. get()
  145. {
  146. return m_;
  147. }
  148. /** Returns ownership of the parsed message.
  149. Ownership is transferred to the caller.
  150. Depending on the parser's progress,
  151. parts of this object may be incomplete.
  152. @par Requires
  153. @ref value_type is @b MoveConstructible
  154. */
  155. value_type
  156. release()
  157. {
  158. static_assert(std::is_move_constructible<decltype(m_)>::value,
  159. "MoveConstructible requirements not met");
  160. return std::move(m_);
  161. }
  162. /** Set a callback to be invoked on each chunk header.
  163. The callback will be invoked once for every chunk in the message
  164. payload, as well as once for the last chunk. The invocation
  165. happens after the chunk header is available but before any body
  166. octets have been parsed.
  167. The extensions are provided in raw, validated form, use
  168. @ref chunk_extensions::parse to parse the extensions into a
  169. structured container for easier access.
  170. The implementation type-erases the callback without requiring
  171. a dynamic allocation. For this reason, the callback object is
  172. passed by a non-constant reference.
  173. @par Example
  174. @code
  175. auto callback =
  176. [](std::uint64_t size, string_view extensions, error_code& ec)
  177. {
  178. //...
  179. };
  180. parser.on_chunk_header(callback);
  181. @endcode
  182. @param cb The function to set, which must be invocable with
  183. this equivalent signature:
  184. @code
  185. void
  186. on_chunk_header(
  187. std::uint64_t size, // Size of the chunk, zero for the last chunk
  188. string_view extensions, // The chunk-extensions in raw form
  189. error_code& ec); // May be set by the callback to indicate an error
  190. @endcode
  191. */
  192. template<class Callback>
  193. void
  194. on_chunk_header(Callback& cb)
  195. {
  196. // Callback may not be constant, caller is responsible for
  197. // managing the lifetime of the callback. Copies are not made.
  198. BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
  199. // Can't set the callback after receiving any chunk data!
  200. BOOST_ASSERT(! rd_inited_);
  201. cb_h_ = std::ref(cb);
  202. }
  203. /** Set a callback to be invoked on chunk body data
  204. The provided function object will be invoked one or more times
  205. to provide buffers corresponding to the chunk body for the current
  206. chunk. The callback receives the number of octets remaining in this
  207. chunk body including the octets in the buffer provided.
  208. The callback must return the number of octets actually consumed.
  209. Any octets not consumed will be presented again in a subsequent
  210. invocation of the callback.
  211. The implementation type-erases the callback without requiring
  212. a dynamic allocation. For this reason, the callback object is
  213. passed by a non-constant reference.
  214. @par Example
  215. @code
  216. auto callback =
  217. [](std::uint64_t remain, string_view body, error_code& ec)
  218. {
  219. //...
  220. };
  221. parser.on_chunk_body(callback);
  222. @endcode
  223. @param cb The function to set, which must be invocable with
  224. this equivalent signature:
  225. @code
  226. std::size_t
  227. on_chunk_header(
  228. std::uint64_t remain, // Octets remaining in this chunk, includes `body`
  229. string_view body, // A buffer holding some or all of the remainder of the chunk body
  230. error_code& ec); // May be set by the callback to indicate an error
  231. @endcode
  232. */
  233. template<class Callback>
  234. void
  235. on_chunk_body(Callback& cb)
  236. {
  237. // Callback may not be constant, caller is responsible for
  238. // managing the lifetime of the callback. Copies are not made.
  239. BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
  240. // Can't set the callback after receiving any chunk data!
  241. BOOST_ASSERT(! rd_inited_);
  242. cb_b_ = std::ref(cb);
  243. }
  244. private:
  245. friend class basic_parser<isRequest, parser>;
  246. parser(std::true_type);
  247. parser(std::false_type);
  248. template<class OtherBody, class... Args,
  249. class = typename std::enable_if<
  250. ! std::is_same<Body, OtherBody>::value>::type>
  251. parser(
  252. std::true_type,
  253. parser<isRequest, OtherBody, Allocator>&& parser,
  254. Args&&... args);
  255. template<class OtherBody, class... Args,
  256. class = typename std::enable_if<
  257. ! std::is_same<Body, OtherBody>::value>::type>
  258. parser(
  259. std::false_type,
  260. parser<isRequest, OtherBody, Allocator>&& parser,
  261. Args&&... args);
  262. template<class Arg1, class... ArgN,
  263. class = typename std::enable_if<
  264. ! detail::is_parser<typename
  265. std::decay<Arg1>::type>::value>::type>
  266. explicit
  267. parser(Arg1&& arg1, std::true_type, ArgN&&... argn);
  268. template<class Arg1, class... ArgN,
  269. class = typename std::enable_if<
  270. ! detail::is_parser<typename
  271. std::decay<Arg1>::type>::value>::type>
  272. explicit
  273. parser(Arg1&& arg1, std::false_type, ArgN&&... argn);
  274. void
  275. on_request_impl(
  276. verb method,
  277. string_view method_str,
  278. string_view target,
  279. int version,
  280. error_code& ec)
  281. {
  282. try
  283. {
  284. m_.target(target);
  285. if(method != verb::unknown)
  286. m_.method(method);
  287. else
  288. m_.method_string(method_str);
  289. ec.assign(0, ec.category());
  290. }
  291. catch(std::bad_alloc const&)
  292. {
  293. ec = error::bad_alloc;
  294. }
  295. m_.version(version);
  296. }
  297. void
  298. on_response_impl(
  299. int code,
  300. string_view reason,
  301. int version,
  302. error_code& ec)
  303. {
  304. m_.result(code);
  305. m_.version(version);
  306. try
  307. {
  308. m_.reason(reason);
  309. ec.assign(0, ec.category());
  310. }
  311. catch(std::bad_alloc const&)
  312. {
  313. ec = error::bad_alloc;
  314. }
  315. }
  316. void
  317. on_field_impl(
  318. field name,
  319. string_view name_string,
  320. string_view value,
  321. error_code& ec)
  322. {
  323. try
  324. {
  325. m_.insert(name, name_string, value);
  326. ec.assign(0, ec.category());
  327. }
  328. catch(std::bad_alloc const&)
  329. {
  330. ec = error::bad_alloc;
  331. }
  332. }
  333. void
  334. on_header_impl(error_code& ec)
  335. {
  336. ec.assign(0, ec.category());
  337. }
  338. void
  339. on_body_init_impl(
  340. boost::optional<std::uint64_t> const& content_length,
  341. error_code& ec)
  342. {
  343. rd_.init(content_length, ec);
  344. rd_inited_ = true;
  345. }
  346. std::size_t
  347. on_body_impl(
  348. string_view body,
  349. error_code& ec)
  350. {
  351. return rd_.put(boost::asio::buffer(
  352. body.data(), body.size()), ec);
  353. }
  354. void
  355. on_chunk_header_impl(
  356. std::uint64_t size,
  357. string_view extensions,
  358. error_code& ec)
  359. {
  360. if(cb_h_)
  361. return cb_h_(size, extensions, ec);
  362. ec.assign(0, ec.category());
  363. }
  364. std::size_t
  365. on_chunk_body_impl(
  366. std::uint64_t remain,
  367. string_view body,
  368. error_code& ec)
  369. {
  370. if(cb_b_)
  371. return cb_b_(remain, body, ec);
  372. return rd_.put(boost::asio::buffer(
  373. body.data(), body.size()), ec);
  374. }
  375. void
  376. on_finish_impl(error_code& ec)
  377. {
  378. rd_.finish(ec);
  379. }
  380. };
  381. /// An HTTP/1 parser for producing a request message.
  382. template<class Body, class Allocator = std::allocator<char>>
  383. using request_parser = parser<true, Body, Allocator>;
  384. /// An HTTP/1 parser for producing a response message.
  385. template<class Body, class Allocator = std::allocator<char>>
  386. using response_parser = parser<false, Body, Allocator>;
  387. } // http
  388. } // beast
  389. } // boost
  390. #include <boost/beast/http/impl/parser.ipp>
  391. #endif