nodejs_parser.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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_NODEJS_PARSER_HPP
  10. #define BOOST_BEAST_HTTP_NODEJS_PARSER_HPP
  11. #include "nodejs-parser/http_parser.h"
  12. #include <boost/beast/http/message.hpp>
  13. #include <boost/beast/http/rfc7230.hpp>
  14. #include <boost/beast/core/buffers_range.hpp>
  15. #include <boost/beast/core/error.hpp>
  16. #include <boost/asio/buffer.hpp>
  17. #include <boost/system/error_code.hpp>
  18. #include <boost/throw_exception.hpp>
  19. #include <cstdint>
  20. #include <string>
  21. #include <type_traits>
  22. #include <utility>
  23. namespace boost {
  24. namespace beast {
  25. namespace http {
  26. namespace detail {
  27. class nodejs_message_category final
  28. : public boost::system::error_category
  29. {
  30. public:
  31. const char*
  32. name() const noexcept override
  33. {
  34. return "nodejs-http-error";
  35. }
  36. std::string
  37. message(int ev) const override
  38. {
  39. return http_errno_description(
  40. static_cast<http_errno>(ev));
  41. }
  42. boost::system::error_condition
  43. default_error_condition(int ev) const noexcept override
  44. {
  45. return boost::system::error_condition{ev, *this};
  46. }
  47. bool
  48. equivalent(int ev,
  49. boost::system::error_condition const& condition
  50. ) const noexcept override
  51. {
  52. return condition.value() == ev &&
  53. &condition.category() == this;
  54. }
  55. bool
  56. equivalent(boost::system::error_code const& error,
  57. int ev) const noexcept override
  58. {
  59. return error.value() == ev &&
  60. &error.category() == this;
  61. }
  62. };
  63. template<class = void>
  64. boost::system::error_code
  65. make_nodejs_error(int http_errno)
  66. {
  67. static nodejs_message_category const mc{};
  68. return boost::system::error_code{http_errno, mc};
  69. }
  70. inline
  71. char const*
  72. method_to_string(unsigned method)
  73. {
  74. using namespace beast;
  75. switch(static_cast<http_method>(method))
  76. {
  77. case HTTP_DELETE: return "DELETE";
  78. case HTTP_GET: return "GET";
  79. case HTTP_HEAD: return "HEAD";
  80. case HTTP_POST: return "POST";
  81. case HTTP_PUT: return "PUT";
  82. // pathological
  83. case HTTP_CONNECT: return "CONNECT";
  84. case HTTP_OPTIONS: return "OPTIONS";
  85. case HTTP_TRACE: return "TRACE";
  86. // webdav
  87. case HTTP_COPY: return "COPY";
  88. case HTTP_LOCK: return "LOCK";
  89. case HTTP_MKCOL: return "MKCOL";
  90. case HTTP_MOVE: return "MOVE";
  91. case HTTP_PROPFIND: return "PROPFIND";
  92. case HTTP_PROPPATCH: return "PROPPATCH";
  93. case HTTP_SEARCH: return "SEARCH";
  94. case HTTP_UNLOCK: return "UNLOCK";
  95. case HTTP_BIND: return "BIND";
  96. case HTTP_REBIND: return "REBIND";
  97. case HTTP_UNBIND: return "UNBIND";
  98. case HTTP_ACL: return "ACL";
  99. // subversion
  100. case HTTP_REPORT: return "REPORT";
  101. case HTTP_MKACTIVITY: return "MKACTIVITY";
  102. case HTTP_CHECKOUT: return "CHECKOUT";
  103. case HTTP_MERGE: return "MERGE";
  104. // upnp
  105. case HTTP_MSEARCH: return "MSEARCH";
  106. case HTTP_NOTIFY: return "NOTIFY";
  107. case HTTP_SUBSCRIBE: return "SUBSCRIBE";
  108. case HTTP_UNSUBSCRIBE: return "UNSUBSCRIBE";
  109. // RFC-5789
  110. case HTTP_PATCH: return "PATCH";
  111. case HTTP_PURGE: return "PURGE";
  112. // CalDav
  113. case HTTP_MKCALENDAR: return "MKCALENDAR";
  114. // RFC-2068, section 19.6.1.2
  115. case HTTP_LINK: return "LINK";
  116. case HTTP_UNLINK: return "UNLINK";
  117. };
  118. return "<unknown>";
  119. }
  120. } // detail
  121. template<class Derived>
  122. class nodejs_basic_parser
  123. {
  124. http_parser state_;
  125. boost::system::error_code* ec_;
  126. bool complete_ = false;
  127. std::string url_;
  128. std::string status_;
  129. std::string field_;
  130. std::string value_;
  131. public:
  132. using error_code = boost::system::error_code;
  133. nodejs_basic_parser(nodejs_basic_parser&& other);
  134. nodejs_basic_parser&
  135. operator=(nodejs_basic_parser&& other);
  136. nodejs_basic_parser(nodejs_basic_parser const& other);
  137. nodejs_basic_parser& operator=(nodejs_basic_parser const& other);
  138. explicit
  139. nodejs_basic_parser(bool request) noexcept;
  140. bool
  141. complete() const noexcept
  142. {
  143. return complete_;
  144. }
  145. std::size_t
  146. write(void const* data, std::size_t size)
  147. {
  148. error_code ec;
  149. auto const used = write(data, size, ec);
  150. if(ec)
  151. BOOST_THROW_EXCEPTION(system_error{ec});
  152. return used;
  153. }
  154. std::size_t
  155. write(void const* data, std::size_t size,
  156. error_code& ec);
  157. template<class ConstBufferSequence>
  158. std::size_t
  159. write(ConstBufferSequence const& buffers)
  160. {
  161. error_code ec;
  162. auto const used = write(buffers, ec);
  163. if(ec)
  164. BOOST_THROW_EXCEPTION(system_error{ec});
  165. return used;
  166. }
  167. template<class ConstBufferSequence>
  168. std::size_t
  169. write(ConstBufferSequence const& buffers,
  170. error_code& ec);
  171. void
  172. write_eof()
  173. {
  174. error_code ec;
  175. write_eof(ec);
  176. if(ec)
  177. BOOST_THROW_EXCEPTION(system_error{ec});
  178. }
  179. void
  180. write_eof(error_code& ec);
  181. void
  182. check_header();
  183. private:
  184. Derived&
  185. impl()
  186. {
  187. return *static_cast<Derived*>(this);
  188. }
  189. static int cb_message_start(http_parser*);
  190. static int cb_url(http_parser*, char const*, std::size_t);
  191. static int cb_status(http_parser*, char const*, std::size_t);
  192. static int cb_header_field(http_parser*, char const*, std::size_t);
  193. static int cb_header_value(http_parser*, char const*, std::size_t);
  194. static int cb_headers_complete(http_parser*);
  195. static int cb_body(http_parser*, char const*, std::size_t);
  196. static int cb_message_complete(http_parser*);
  197. static int cb_chunk_header(http_parser*);
  198. static int cb_chunk_complete(http_parser*);
  199. struct hooks_t : http_parser_settings
  200. {
  201. hooks_t()
  202. {
  203. http_parser_settings_init(this);
  204. on_message_begin = &nodejs_basic_parser::cb_message_start;
  205. on_url = &nodejs_basic_parser::cb_url;
  206. on_status = &nodejs_basic_parser::cb_status;
  207. on_header_field = &nodejs_basic_parser::cb_header_field;
  208. on_header_value = &nodejs_basic_parser::cb_header_value;
  209. on_headers_complete = &nodejs_basic_parser::cb_headers_complete;
  210. on_body = &nodejs_basic_parser::cb_body;
  211. on_message_complete = &nodejs_basic_parser::cb_message_complete;
  212. on_chunk_header = &nodejs_basic_parser::cb_chunk_header;
  213. on_chunk_complete = &nodejs_basic_parser::cb_chunk_complete;
  214. }
  215. };
  216. static
  217. http_parser_settings const*
  218. hooks();
  219. };
  220. template<class Derived>
  221. template<class ConstBufferSequence>
  222. std::size_t
  223. nodejs_basic_parser<Derived>::write(
  224. ConstBufferSequence const& buffers, error_code& ec)
  225. {
  226. static_assert(net::is_const_buffer_sequence<
  227. ConstBufferSequence>::value,
  228. "ConstBufferSequence type requirements not met");
  229. std::size_t bytes_used = 0;
  230. for(auto buffer : beast::buffers_range_ref(buffers))
  231. {
  232. auto const n = write(
  233. static_cast<void const*>(buffer.data()),
  234. buffer.size(), ec);
  235. if(ec)
  236. return 0;
  237. bytes_used += n;
  238. if(complete())
  239. break;
  240. }
  241. return bytes_used;
  242. }
  243. template<class Derived>
  244. http_parser_settings const*
  245. nodejs_basic_parser<Derived>::hooks()
  246. {
  247. static hooks_t const h;
  248. return &h;
  249. }
  250. template<class Derived>
  251. nodejs_basic_parser<Derived>::
  252. nodejs_basic_parser(nodejs_basic_parser&& other)
  253. {
  254. state_ = other.state_;
  255. state_.data = this;
  256. complete_ = other.complete_;
  257. url_ = std::move(other.url_);
  258. status_ = std::move(other.status_);
  259. field_ = std::move(other.field_);
  260. value_ = std::move(other.value_);
  261. }
  262. template<class Derived>
  263. auto
  264. nodejs_basic_parser<Derived>::
  265. operator=(nodejs_basic_parser&& other) ->
  266. nodejs_basic_parser&
  267. {
  268. state_ = other.state_;
  269. state_.data = this;
  270. complete_ = other.complete_;
  271. url_ = std::move(other.url_);
  272. status_ = std::move(other.status_);
  273. field_ = std::move(other.field_);
  274. value_ = std::move(other.value_);
  275. return *this;
  276. }
  277. template<class Derived>
  278. nodejs_basic_parser<Derived>::
  279. nodejs_basic_parser(nodejs_basic_parser const& other)
  280. {
  281. state_ = other.state_;
  282. state_.data = this;
  283. complete_ = other.complete_;
  284. url_ = other.url_;
  285. status_ = other.status_;
  286. field_ = other.field_;
  287. value_ = other.value_;
  288. }
  289. template<class Derived>
  290. auto
  291. nodejs_basic_parser<Derived>::
  292. operator=(nodejs_basic_parser const& other) ->
  293. nodejs_basic_parser&
  294. {
  295. state_ = other.state_;
  296. state_.data = this;
  297. complete_ = other.complete_;
  298. url_ = other.url_;
  299. status_ = other.status_;
  300. field_ = other.field_;
  301. value_ = other.value_;
  302. return *this;
  303. }
  304. template<class Derived>
  305. nodejs_basic_parser<Derived>::
  306. nodejs_basic_parser(bool request) noexcept
  307. {
  308. state_.data = this;
  309. http_parser_init(&state_, request
  310. ? http_parser_type::HTTP_REQUEST
  311. : http_parser_type::HTTP_RESPONSE);
  312. }
  313. template<class Derived>
  314. std::size_t
  315. nodejs_basic_parser<Derived>::
  316. write(void const* data,
  317. std::size_t size, error_code& ec)
  318. {
  319. ec_ = &ec;
  320. auto const n = http_parser_execute(
  321. &state_, hooks(),
  322. static_cast<const char*>(data), size);
  323. if(! ec)
  324. ec = detail::make_nodejs_error(
  325. static_cast<int>(state_.http_errno));
  326. if(ec)
  327. return 0;
  328. return n;
  329. }
  330. template<class Derived>
  331. void
  332. nodejs_basic_parser<Derived>::
  333. write_eof(error_code& ec)
  334. {
  335. ec_ = &ec;
  336. http_parser_execute(&state_, hooks(), nullptr, 0);
  337. if(! ec)
  338. ec = detail::make_nodejs_error(
  339. static_cast<int>(state_.http_errno));
  340. }
  341. template<class Derived>
  342. void
  343. nodejs_basic_parser<Derived>::
  344. check_header()
  345. {
  346. if(! value_.empty())
  347. {
  348. impl().on_field(field_, value_);
  349. field_.clear();
  350. value_.clear();
  351. }
  352. }
  353. template<class Derived>
  354. int
  355. nodejs_basic_parser<Derived>::
  356. cb_message_start(http_parser* p)
  357. {
  358. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  359. t.complete_ = false;
  360. t.url_.clear();
  361. t.status_.clear();
  362. t.field_.clear();
  363. t.value_.clear();
  364. t.impl().on_start();
  365. return 0;
  366. }
  367. template<class Derived>
  368. int
  369. nodejs_basic_parser<Derived>::
  370. cb_url(http_parser* p,
  371. char const* in, std::size_t bytes)
  372. {
  373. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  374. t.url_.append(in, bytes);
  375. return 0;
  376. }
  377. template<class Derived>
  378. int
  379. nodejs_basic_parser<Derived>::
  380. cb_status(http_parser* p,
  381. char const* in, std::size_t bytes)
  382. {
  383. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  384. t.status_.append(in, bytes);
  385. return 0;
  386. }
  387. template<class Derived>
  388. int
  389. nodejs_basic_parser<Derived>::
  390. cb_header_field(http_parser* p,
  391. char const* in, std::size_t bytes)
  392. {
  393. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  394. t.check_header();
  395. t.field_.append(in, bytes);
  396. return 0;
  397. }
  398. template<class Derived>
  399. int
  400. nodejs_basic_parser<Derived>::
  401. cb_header_value(http_parser* p,
  402. char const* in, std::size_t bytes)
  403. {
  404. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  405. t.value_.append(in, bytes);
  406. return 0;
  407. }
  408. template<class Derived>
  409. int
  410. nodejs_basic_parser<Derived>::
  411. cb_headers_complete(http_parser* p)
  412. {
  413. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  414. t.check_header();
  415. t.impl().on_headers_complete(*t.ec_);
  416. if(*t.ec_)
  417. return 1;
  418. bool const keep_alive =
  419. http_should_keep_alive(p) != 0;
  420. if(p->type == http_parser_type::HTTP_REQUEST)
  421. {
  422. t.impl().on_request(p->method, t.url_,
  423. p->http_major, p->http_minor, keep_alive,
  424. p->upgrade);
  425. return 0;
  426. }
  427. return t.impl().on_response(p->status_code, t.status_,
  428. p->http_major, p->http_minor, keep_alive,
  429. p->upgrade) ? 0 : 1;
  430. }
  431. template<class Derived>
  432. int
  433. nodejs_basic_parser<Derived>::
  434. cb_body(http_parser* p,
  435. char const* in, std::size_t bytes)
  436. {
  437. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  438. t.impl().on_body(in, bytes, *t.ec_);
  439. return *t.ec_ ? 1 : 0;
  440. }
  441. template<class Derived>
  442. int
  443. nodejs_basic_parser<Derived>::
  444. cb_message_complete(http_parser* p)
  445. {
  446. auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
  447. t.complete_ = true;
  448. t.impl().on_complete();
  449. return 0;
  450. }
  451. template<class Derived>
  452. int
  453. nodejs_basic_parser<Derived>::
  454. cb_chunk_header(http_parser*)
  455. {
  456. return 0;
  457. }
  458. template<class Derived>
  459. int
  460. nodejs_basic_parser<Derived>::
  461. cb_chunk_complete(http_parser*)
  462. {
  463. return 0;
  464. }
  465. //------------------------------------------------------------------------------
  466. /** A HTTP parser.
  467. The parser may only be used once.
  468. */
  469. template<bool isRequest, class Body, class Fields>
  470. class nodejs_parser
  471. : public nodejs_basic_parser<nodejs_parser<isRequest, Body, Fields>>
  472. {
  473. bool started_ = false;
  474. public:
  475. nodejs_parser(nodejs_parser&&) = default;
  476. nodejs_parser()
  477. : http::nodejs_basic_parser<nodejs_parser>(isRequest)
  478. {
  479. }
  480. /// Returns `true` if at least one byte has been processed
  481. bool
  482. started()
  483. {
  484. return started_;
  485. }
  486. private:
  487. friend class http::nodejs_basic_parser<nodejs_parser>;
  488. void
  489. on_start()
  490. {
  491. started_ = true;
  492. }
  493. void
  494. on_field(std::string const&, std::string const&)
  495. {
  496. }
  497. void
  498. on_headers_complete(error_code& ec)
  499. {
  500. // vFALCO TODO Decode the Content-Length and
  501. // Transfer-Encoding, see if we can reserve the buffer.
  502. //
  503. // r_.reserve(content_length)
  504. ec = {};
  505. }
  506. bool
  507. on_request(unsigned, std::string const&,
  508. int, int, bool, bool, std::true_type)
  509. {
  510. return true;
  511. }
  512. bool
  513. on_request(unsigned, std::string const&,
  514. int, int, bool, bool, std::false_type)
  515. {
  516. return true;
  517. }
  518. bool
  519. on_request(unsigned method, std::string const& url,
  520. int major, int minor, bool keep_alive, bool upgrade)
  521. {
  522. return on_request(method, url,
  523. major, minor, keep_alive, upgrade,
  524. std::integral_constant<
  525. bool, isRequest>{});
  526. }
  527. bool
  528. on_response(int, std::string const&,
  529. int, int, bool, bool, std::true_type)
  530. {
  531. return true;
  532. }
  533. bool
  534. on_response(int, std::string const&, int, int, bool, bool,
  535. std::false_type)
  536. {
  537. return true;
  538. }
  539. bool
  540. on_response(int status, std::string const& reason,
  541. int major, int minor, bool keep_alive, bool upgrade)
  542. {
  543. return on_response(
  544. status, reason, major, minor, keep_alive, upgrade,
  545. std::integral_constant<bool, ! isRequest>{});
  546. }
  547. void
  548. on_body(void const*, std::size_t, error_code& ec)
  549. {
  550. ec = {};
  551. }
  552. void
  553. on_complete()
  554. {
  555. }
  556. };
  557. } // http
  558. } // beast
  559. } // boost
  560. #endif