serializer.ipp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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_IMPL_SERIALIZER_IPP
  10. #define BOOST_BEAST_HTTP_IMPL_SERIALIZER_IPP
  11. #include <boost/beast/core/detail/buffers_ref.hpp>
  12. #include <boost/beast/http/error.hpp>
  13. #include <boost/beast/http/status.hpp>
  14. #include <boost/beast/core/detail/config.hpp>
  15. #include <boost/assert.hpp>
  16. #include <ostream>
  17. namespace boost {
  18. namespace beast {
  19. namespace http {
  20. template<
  21. bool isRequest, class Body, class Fields>
  22. void
  23. serializer<isRequest, Body, Fields>::
  24. fwrinit(std::true_type)
  25. {
  26. fwr_.emplace(m_, m_.version(), m_.method());
  27. }
  28. template<
  29. bool isRequest, class Body, class Fields>
  30. void
  31. serializer<isRequest, Body, Fields>::
  32. fwrinit(std::false_type)
  33. {
  34. fwr_.emplace(m_, m_.version(), m_.result_int());
  35. }
  36. template<
  37. bool isRequest, class Body, class Fields>
  38. template<std::size_t I, class Visit>
  39. inline
  40. void
  41. serializer<isRequest, Body, Fields>::
  42. do_visit(error_code& ec, Visit& visit)
  43. {
  44. pv_.template emplace<I>(limit_, v_.template get<I>());
  45. visit(ec, beast::detail::make_buffers_ref(
  46. pv_.template get<I>()));
  47. }
  48. //------------------------------------------------------------------------------
  49. template<
  50. bool isRequest, class Body, class Fields>
  51. serializer<isRequest, Body, Fields>::
  52. serializer(value_type& m)
  53. : m_(m)
  54. , wr_(m_.base(), m_.body())
  55. {
  56. }
  57. template<
  58. bool isRequest, class Body, class Fields>
  59. template<class Visit>
  60. void
  61. serializer<isRequest, Body, Fields>::
  62. next(error_code& ec, Visit&& visit)
  63. {
  64. using boost::asio::buffer_size;
  65. switch(s_)
  66. {
  67. case do_construct:
  68. {
  69. fwrinit(std::integral_constant<bool,
  70. isRequest>{});
  71. if(m_.chunked())
  72. goto go_init_c;
  73. s_ = do_init;
  74. BOOST_FALLTHROUGH;
  75. }
  76. case do_init:
  77. {
  78. wr_.init(ec);
  79. if(ec)
  80. return;
  81. if(split_)
  82. goto go_header_only;
  83. auto result = wr_.get(ec);
  84. if(ec == error::need_more)
  85. goto go_header_only;
  86. if(ec)
  87. return;
  88. if(! result)
  89. goto go_header_only;
  90. more_ = result->second;
  91. v_.template emplace<2>(
  92. boost::in_place_init,
  93. fwr_->get(),
  94. result->first);
  95. s_ = do_header;
  96. BOOST_FALLTHROUGH;
  97. }
  98. case do_header:
  99. do_visit<2>(ec, visit);
  100. break;
  101. go_header_only:
  102. v_.template emplace<1>(fwr_->get());
  103. s_ = do_header_only;
  104. BOOST_FALLTHROUGH;
  105. case do_header_only:
  106. do_visit<1>(ec, visit);
  107. break;
  108. case do_body:
  109. s_ = do_body + 1;
  110. BOOST_FALLTHROUGH;
  111. case do_body + 1:
  112. {
  113. auto result = wr_.get(ec);
  114. if(ec)
  115. return;
  116. if(! result)
  117. goto go_complete;
  118. more_ = result->second;
  119. v_.template emplace<3>(result->first);
  120. s_ = do_body + 2;
  121. BOOST_FALLTHROUGH;
  122. }
  123. case do_body + 2:
  124. do_visit<3>(ec, visit);
  125. break;
  126. //----------------------------------------------------------------------
  127. go_init_c:
  128. s_ = do_init_c;
  129. BOOST_FALLTHROUGH;
  130. case do_init_c:
  131. {
  132. wr_.init(ec);
  133. if(ec)
  134. return;
  135. if(split_)
  136. goto go_header_only_c;
  137. auto result = wr_.get(ec);
  138. if(ec == error::need_more)
  139. goto go_header_only_c;
  140. if(ec)
  141. return;
  142. if(! result)
  143. goto go_header_only_c;
  144. more_ = result->second;
  145. if(! more_)
  146. {
  147. // do it all in one buffer
  148. v_.template emplace<7>(
  149. boost::in_place_init,
  150. fwr_->get(),
  151. buffer_size(result->first),
  152. boost::asio::const_buffer{nullptr, 0},
  153. chunk_crlf{},
  154. result->first,
  155. chunk_crlf{},
  156. detail::chunk_last(),
  157. boost::asio::const_buffer{nullptr, 0},
  158. chunk_crlf{});
  159. goto go_all_c;
  160. }
  161. v_.template emplace<4>(
  162. boost::in_place_init,
  163. fwr_->get(),
  164. buffer_size(result->first),
  165. boost::asio::const_buffer{nullptr, 0},
  166. chunk_crlf{},
  167. result->first,
  168. chunk_crlf{});
  169. s_ = do_header_c;
  170. BOOST_FALLTHROUGH;
  171. }
  172. case do_header_c:
  173. do_visit<4>(ec, visit);
  174. break;
  175. go_header_only_c:
  176. v_.template emplace<1>(fwr_->get());
  177. s_ = do_header_only_c;
  178. BOOST_FALLTHROUGH;
  179. case do_header_only_c:
  180. do_visit<1>(ec, visit);
  181. break;
  182. case do_body_c:
  183. s_ = do_body_c + 1;
  184. BOOST_FALLTHROUGH;
  185. case do_body_c + 1:
  186. {
  187. auto result = wr_.get(ec);
  188. if(ec)
  189. return;
  190. if(! result)
  191. goto go_final_c;
  192. more_ = result->second;
  193. if(! more_)
  194. {
  195. // do it all in one buffer
  196. v_.template emplace<6>(
  197. boost::in_place_init,
  198. buffer_size(result->first),
  199. boost::asio::const_buffer{nullptr, 0},
  200. chunk_crlf{},
  201. result->first,
  202. chunk_crlf{},
  203. detail::chunk_last(),
  204. boost::asio::const_buffer{nullptr, 0},
  205. chunk_crlf{});
  206. goto go_body_final_c;
  207. }
  208. v_.template emplace<5>(
  209. boost::in_place_init,
  210. buffer_size(result->first),
  211. boost::asio::const_buffer{nullptr, 0},
  212. chunk_crlf{},
  213. result->first,
  214. chunk_crlf{});
  215. s_ = do_body_c + 2;
  216. BOOST_FALLTHROUGH;
  217. }
  218. case do_body_c + 2:
  219. do_visit<5>(ec, visit);
  220. break;
  221. go_body_final_c:
  222. s_ = do_body_final_c;
  223. BOOST_FALLTHROUGH;
  224. case do_body_final_c:
  225. do_visit<6>(ec, visit);
  226. break;
  227. go_all_c:
  228. s_ = do_all_c;
  229. BOOST_FALLTHROUGH;
  230. case do_all_c:
  231. do_visit<7>(ec, visit);
  232. break;
  233. go_final_c:
  234. case do_final_c:
  235. v_.template emplace<8>(
  236. boost::in_place_init,
  237. detail::chunk_last(),
  238. boost::asio::const_buffer{nullptr, 0},
  239. chunk_crlf{});
  240. s_ = do_final_c + 1;
  241. BOOST_FALLTHROUGH;
  242. case do_final_c + 1:
  243. do_visit<8>(ec, visit);
  244. break;
  245. //----------------------------------------------------------------------
  246. default:
  247. case do_complete:
  248. BOOST_ASSERT(false);
  249. break;
  250. go_complete:
  251. s_ = do_complete;
  252. break;
  253. }
  254. }
  255. template<
  256. bool isRequest, class Body, class Fields>
  257. void
  258. serializer<isRequest, Body, Fields>::
  259. consume(std::size_t n)
  260. {
  261. using boost::asio::buffer_size;
  262. switch(s_)
  263. {
  264. case do_header:
  265. BOOST_ASSERT(
  266. n <= buffer_size(v_.template get<2>()));
  267. v_.template get<2>().consume(n);
  268. if(buffer_size(v_.template get<2>()) > 0)
  269. break;
  270. header_done_ = true;
  271. v_.reset();
  272. if(! more_)
  273. goto go_complete;
  274. s_ = do_body + 1;
  275. break;
  276. case do_header_only:
  277. BOOST_ASSERT(
  278. n <= buffer_size(v_.template get<1>()));
  279. v_.template get<1>().consume(n);
  280. if(buffer_size(v_.template get<1>()) > 0)
  281. break;
  282. fwr_ = boost::none;
  283. header_done_ = true;
  284. if(! split_)
  285. goto go_complete;
  286. s_ = do_body;
  287. break;
  288. case do_body + 2:
  289. {
  290. BOOST_ASSERT(
  291. n <= buffer_size(v_.template get<3>()));
  292. v_.template get<3>().consume(n);
  293. if(buffer_size(v_.template get<3>()) > 0)
  294. break;
  295. v_.reset();
  296. if(! more_)
  297. goto go_complete;
  298. s_ = do_body + 1;
  299. break;
  300. }
  301. //----------------------------------------------------------------------
  302. case do_header_c:
  303. BOOST_ASSERT(
  304. n <= buffer_size(v_.template get<4>()));
  305. v_.template get<4>().consume(n);
  306. if(buffer_size(v_.template get<4>()) > 0)
  307. break;
  308. header_done_ = true;
  309. v_.reset();
  310. if(more_)
  311. s_ = do_body_c + 1;
  312. else
  313. s_ = do_final_c;
  314. break;
  315. case do_header_only_c:
  316. {
  317. BOOST_ASSERT(
  318. n <= buffer_size(v_.template get<1>()));
  319. v_.template get<1>().consume(n);
  320. if(buffer_size(v_.template get<1>()) > 0)
  321. break;
  322. fwr_ = boost::none;
  323. header_done_ = true;
  324. if(! split_)
  325. {
  326. s_ = do_final_c;
  327. break;
  328. }
  329. s_ = do_body_c;
  330. break;
  331. }
  332. case do_body_c + 2:
  333. BOOST_ASSERT(
  334. n <= buffer_size(v_.template get<5>()));
  335. v_.template get<5>().consume(n);
  336. if(buffer_size(v_.template get<5>()) > 0)
  337. break;
  338. v_.reset();
  339. if(more_)
  340. s_ = do_body_c + 1;
  341. else
  342. s_ = do_final_c;
  343. break;
  344. case do_body_final_c:
  345. {
  346. BOOST_ASSERT(
  347. n <= buffer_size(v_.template get<6>()));
  348. v_.template get<6>().consume(n);
  349. if(buffer_size(v_.template get<6>()) > 0)
  350. break;
  351. v_.reset();
  352. s_ = do_complete;
  353. break;
  354. }
  355. case do_all_c:
  356. {
  357. BOOST_ASSERT(
  358. n <= buffer_size(v_.template get<7>()));
  359. v_.template get<7>().consume(n);
  360. if(buffer_size(v_.template get<7>()) > 0)
  361. break;
  362. header_done_ = true;
  363. v_.reset();
  364. s_ = do_complete;
  365. break;
  366. }
  367. case do_final_c + 1:
  368. BOOST_ASSERT(buffer_size(v_.template get<8>()));
  369. v_.template get<8>().consume(n);
  370. if(buffer_size(v_.template get<8>()) > 0)
  371. break;
  372. v_.reset();
  373. goto go_complete;
  374. //----------------------------------------------------------------------
  375. default:
  376. BOOST_ASSERT(false);
  377. case do_complete:
  378. break;
  379. go_complete:
  380. s_ = do_complete;
  381. break;
  382. }
  383. }
  384. } // http
  385. } // beast
  386. } // boost
  387. #endif