serializer.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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_IMPL_SERIALIZER_HPP
  10. #define BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP
  11. #include <boost/beast/core/buffer_traits.hpp>
  12. #include <boost/beast/core/detail/buffers_ref.hpp>
  13. #include <boost/beast/http/error.hpp>
  14. #include <boost/beast/http/status.hpp>
  15. #include <boost/beast/core/detail/config.hpp>
  16. #include <boost/assert.hpp>
  17. #include <ostream>
  18. namespace boost {
  19. namespace beast {
  20. namespace http {
  21. template<
  22. bool isRequest, class Body, class Fields>
  23. void
  24. serializer<isRequest, Body, Fields>::
  25. fwrinit(std::true_type)
  26. {
  27. fwr_.emplace(m_, m_.version(), m_.method());
  28. }
  29. template<
  30. bool isRequest, class Body, class Fields>
  31. void
  32. serializer<isRequest, Body, Fields>::
  33. fwrinit(std::false_type)
  34. {
  35. fwr_.emplace(m_, m_.version(), m_.result_int());
  36. }
  37. template<
  38. bool isRequest, class Body, class Fields>
  39. template<std::size_t I, class Visit>
  40. inline
  41. void
  42. serializer<isRequest, Body, Fields>::
  43. do_visit(error_code& ec, Visit& visit)
  44. {
  45. pv_.template emplace<I>(limit_, v_.template get<I>());
  46. visit(ec, beast::detail::make_buffers_ref(
  47. pv_.template get<I>()));
  48. }
  49. //------------------------------------------------------------------------------
  50. template<
  51. bool isRequest, class Body, class Fields>
  52. serializer<isRequest, Body, Fields>::
  53. serializer(value_type& m)
  54. : m_(m)
  55. , wr_(m_.base(), m_.body())
  56. {
  57. }
  58. template<
  59. bool isRequest, class Body, class Fields>
  60. template<class Visit>
  61. void
  62. serializer<isRequest, Body, Fields>::
  63. next(error_code& ec, Visit&& visit)
  64. {
  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_bytes(result->first),
  152. net::const_buffer{nullptr, 0},
  153. chunk_crlf{},
  154. result->first,
  155. chunk_crlf{},
  156. detail::chunk_last(),
  157. net::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_bytes(result->first),
  165. net::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_bytes(result->first),
  199. net::const_buffer{nullptr, 0},
  200. chunk_crlf{},
  201. result->first,
  202. chunk_crlf{},
  203. detail::chunk_last(),
  204. net::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_bytes(result->first),
  211. net::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. net::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. switch(s_)
  262. {
  263. case do_header:
  264. BOOST_ASSERT(
  265. n <= buffer_bytes(v_.template get<2>()));
  266. v_.template get<2>().consume(n);
  267. if(buffer_bytes(v_.template get<2>()) > 0)
  268. break;
  269. header_done_ = true;
  270. v_.reset();
  271. if(! more_)
  272. goto go_complete;
  273. s_ = do_body + 1;
  274. break;
  275. case do_header_only:
  276. BOOST_ASSERT(
  277. n <= buffer_bytes(v_.template get<1>()));
  278. v_.template get<1>().consume(n);
  279. if(buffer_bytes(v_.template get<1>()) > 0)
  280. break;
  281. fwr_ = boost::none;
  282. header_done_ = true;
  283. if(! split_)
  284. goto go_complete;
  285. s_ = do_body;
  286. break;
  287. case do_body + 2:
  288. {
  289. BOOST_ASSERT(
  290. n <= buffer_bytes(v_.template get<3>()));
  291. v_.template get<3>().consume(n);
  292. if(buffer_bytes(v_.template get<3>()) > 0)
  293. break;
  294. v_.reset();
  295. if(! more_)
  296. goto go_complete;
  297. s_ = do_body + 1;
  298. break;
  299. }
  300. //----------------------------------------------------------------------
  301. case do_header_c:
  302. BOOST_ASSERT(
  303. n <= buffer_bytes(v_.template get<4>()));
  304. v_.template get<4>().consume(n);
  305. if(buffer_bytes(v_.template get<4>()) > 0)
  306. break;
  307. header_done_ = true;
  308. v_.reset();
  309. if(more_)
  310. s_ = do_body_c + 1;
  311. else
  312. s_ = do_final_c;
  313. break;
  314. case do_header_only_c:
  315. {
  316. BOOST_ASSERT(
  317. n <= buffer_bytes(v_.template get<1>()));
  318. v_.template get<1>().consume(n);
  319. if(buffer_bytes(v_.template get<1>()) > 0)
  320. break;
  321. fwr_ = boost::none;
  322. header_done_ = true;
  323. if(! split_)
  324. {
  325. s_ = do_final_c;
  326. break;
  327. }
  328. s_ = do_body_c;
  329. break;
  330. }
  331. case do_body_c + 2:
  332. BOOST_ASSERT(
  333. n <= buffer_bytes(v_.template get<5>()));
  334. v_.template get<5>().consume(n);
  335. if(buffer_bytes(v_.template get<5>()) > 0)
  336. break;
  337. v_.reset();
  338. if(more_)
  339. s_ = do_body_c + 1;
  340. else
  341. s_ = do_final_c;
  342. break;
  343. case do_body_final_c:
  344. {
  345. BOOST_ASSERT(
  346. n <= buffer_bytes(v_.template get<6>()));
  347. v_.template get<6>().consume(n);
  348. if(buffer_bytes(v_.template get<6>()) > 0)
  349. break;
  350. v_.reset();
  351. s_ = do_complete;
  352. break;
  353. }
  354. case do_all_c:
  355. {
  356. BOOST_ASSERT(
  357. n <= buffer_bytes(v_.template get<7>()));
  358. v_.template get<7>().consume(n);
  359. if(buffer_bytes(v_.template get<7>()) > 0)
  360. break;
  361. header_done_ = true;
  362. v_.reset();
  363. s_ = do_complete;
  364. break;
  365. }
  366. case do_final_c + 1:
  367. BOOST_ASSERT(buffer_bytes(v_.template get<8>()));
  368. v_.template get<8>().consume(n);
  369. if(buffer_bytes(v_.template get<8>()) > 0)
  370. break;
  371. v_.reset();
  372. goto go_complete;
  373. //----------------------------------------------------------------------
  374. default:
  375. BOOST_ASSERT(false);
  376. case do_complete:
  377. break;
  378. go_complete:
  379. s_ = do_complete;
  380. break;
  381. }
  382. }
  383. } // http
  384. } // beast
  385. } // boost
  386. #endif