message.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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_MESSAGE_HPP
  10. #define BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
  11. #include <boost/beast/core/error.hpp>
  12. #include <boost/assert.hpp>
  13. #include <boost/throw_exception.hpp>
  14. #include <stdexcept>
  15. namespace boost {
  16. namespace beast {
  17. namespace http {
  18. template<class Fields>
  19. template<class Arg1, class... ArgN, class>
  20. header<true, Fields>::
  21. header(Arg1&& arg1, ArgN&&... argn)
  22. : Fields(std::forward<Arg1>(arg1),
  23. std::forward<ArgN>(argn)...)
  24. {
  25. }
  26. template<class Fields>
  27. verb
  28. header<true, Fields>::
  29. method() const
  30. {
  31. return method_;
  32. }
  33. template<class Fields>
  34. void
  35. header<true, Fields>::
  36. method(verb v)
  37. {
  38. if(v == verb::unknown)
  39. BOOST_THROW_EXCEPTION(
  40. std::invalid_argument{"unknown method"});
  41. method_ = v;
  42. this->set_method_impl({});
  43. }
  44. template<class Fields>
  45. string_view
  46. header<true, Fields>::
  47. method_string() const
  48. {
  49. if(method_ != verb::unknown)
  50. return to_string(method_);
  51. return this->get_method_impl();
  52. }
  53. template<class Fields>
  54. void
  55. header<true, Fields>::
  56. method_string(string_view s)
  57. {
  58. method_ = string_to_verb(s);
  59. if(method_ != verb::unknown)
  60. this->set_method_impl({});
  61. else
  62. this->set_method_impl(s);
  63. }
  64. template<class Fields>
  65. string_view
  66. header<true, Fields>::
  67. target() const
  68. {
  69. return this->get_target_impl();
  70. }
  71. template<class Fields>
  72. void
  73. header<true, Fields>::
  74. target(string_view s)
  75. {
  76. this->set_target_impl(s);
  77. }
  78. template<class Fields>
  79. void
  80. swap(
  81. header<true, Fields>& h1,
  82. header<true, Fields>& h2)
  83. {
  84. using std::swap;
  85. swap(
  86. static_cast<Fields&>(h1),
  87. static_cast<Fields&>(h2));
  88. swap(h1.version_, h2.version_);
  89. swap(h1.method_, h2.method_);
  90. }
  91. //------------------------------------------------------------------------------
  92. template<class Fields>
  93. template<class Arg1, class... ArgN, class>
  94. header<false, Fields>::
  95. header(Arg1&& arg1, ArgN&&... argn)
  96. : Fields(std::forward<Arg1>(arg1),
  97. std::forward<ArgN>(argn)...)
  98. {
  99. }
  100. template<class Fields>
  101. status
  102. header<false, Fields>::
  103. result() const
  104. {
  105. return int_to_status(
  106. static_cast<int>(result_));
  107. }
  108. template<class Fields>
  109. void
  110. header<false, Fields>::
  111. result(status v)
  112. {
  113. result_ = v;
  114. }
  115. template<class Fields>
  116. void
  117. header<false, Fields>::
  118. result(unsigned v)
  119. {
  120. if(v > 999)
  121. BOOST_THROW_EXCEPTION(
  122. std::invalid_argument{
  123. "invalid status-code"});
  124. result_ = static_cast<status>(v);
  125. }
  126. template<class Fields>
  127. unsigned
  128. header<false, Fields>::
  129. result_int() const
  130. {
  131. return static_cast<unsigned>(result_);
  132. }
  133. template<class Fields>
  134. string_view
  135. header<false, Fields>::
  136. reason() const
  137. {
  138. auto const s = this->get_reason_impl();
  139. if(! s.empty())
  140. return s;
  141. return obsolete_reason(result_);
  142. }
  143. template<class Fields>
  144. void
  145. header<false, Fields>::
  146. reason(string_view s)
  147. {
  148. this->set_reason_impl(s);
  149. }
  150. template<class Fields>
  151. void
  152. swap(
  153. header<false, Fields>& h1,
  154. header<false, Fields>& h2)
  155. {
  156. using std::swap;
  157. swap(
  158. static_cast<Fields&>(h1),
  159. static_cast<Fields&>(h2));
  160. swap(h1.version_, h2.version_);
  161. swap(h1.result_, h2.result_);
  162. }
  163. //------------------------------------------------------------------------------
  164. template<bool isRequest, class Body, class Fields>
  165. template<class... BodyArgs>
  166. message<isRequest, Body, Fields>::
  167. message(header_type&& h, BodyArgs&&... body_args)
  168. : header_type(std::move(h))
  169. , boost::empty_value<
  170. typename Body::value_type>(boost::empty_init_t(),
  171. std::forward<BodyArgs>(body_args)...)
  172. {
  173. }
  174. template<bool isRequest, class Body, class Fields>
  175. template<class... BodyArgs>
  176. message<isRequest, Body, Fields>::
  177. message(header_type const& h, BodyArgs&&... body_args)
  178. : header_type(h)
  179. , boost::empty_value<
  180. typename Body::value_type>(boost::empty_init_t(),
  181. std::forward<BodyArgs>(body_args)...)
  182. {
  183. }
  184. template<bool isRequest, class Body, class Fields>
  185. template<class Version, class>
  186. message<isRequest, Body, Fields>::
  187. message(verb method, string_view target, Version version)
  188. : header_type(method, target, version)
  189. {
  190. }
  191. template<bool isRequest, class Body, class Fields>
  192. template<class Version, class BodyArg, class>
  193. message<isRequest, Body, Fields>::
  194. message(verb method, string_view target,
  195. Version version, BodyArg&& body_arg)
  196. : header_type(method, target, version)
  197. , boost::empty_value<
  198. typename Body::value_type>(boost::empty_init_t(),
  199. std::forward<BodyArg>(body_arg))
  200. {
  201. }
  202. template<bool isRequest, class Body, class Fields>
  203. template<class Version, class BodyArg, class FieldsArg, class>
  204. message<isRequest, Body, Fields>::
  205. message(
  206. verb method, string_view target, Version version,
  207. BodyArg&& body_arg,
  208. FieldsArg&& fields_arg)
  209. : header_type(method, target, version,
  210. std::forward<FieldsArg>(fields_arg))
  211. , boost::empty_value<
  212. typename Body::value_type>(boost::empty_init_t(),
  213. std::forward<BodyArg>(body_arg))
  214. {
  215. }
  216. template<bool isRequest, class Body, class Fields>
  217. template<class Version, class>
  218. message<isRequest, Body, Fields>::
  219. message(status result, Version version)
  220. : header_type(result, version)
  221. {
  222. }
  223. template<bool isRequest, class Body, class Fields>
  224. template<class Version, class BodyArg, class>
  225. message<isRequest, Body, Fields>::
  226. message(status result, Version version,
  227. BodyArg&& body_arg)
  228. : header_type(result, version)
  229. , boost::empty_value<
  230. typename Body::value_type>(boost::empty_init_t(),
  231. std::forward<BodyArg>(body_arg))
  232. {
  233. }
  234. template<bool isRequest, class Body, class Fields>
  235. template<class Version, class BodyArg, class FieldsArg, class>
  236. message<isRequest, Body, Fields>::
  237. message(status result, Version version,
  238. BodyArg&& body_arg, FieldsArg&& fields_arg)
  239. : header_type(result, version,
  240. std::forward<FieldsArg>(fields_arg))
  241. , boost::empty_value<
  242. typename Body::value_type>(boost::empty_init_t(),
  243. std::forward<BodyArg>(body_arg))
  244. {
  245. }
  246. template<bool isRequest, class Body, class Fields>
  247. message<isRequest, Body, Fields>::
  248. message(std::piecewise_construct_t)
  249. {
  250. }
  251. template<bool isRequest, class Body, class Fields>
  252. template<class... BodyArgs>
  253. message<isRequest, Body, Fields>::
  254. message(std::piecewise_construct_t,
  255. std::tuple<BodyArgs...> body_args)
  256. : message(std::piecewise_construct,
  257. body_args,
  258. mp11::make_index_sequence<
  259. sizeof...(BodyArgs)>{})
  260. {
  261. }
  262. template<bool isRequest, class Body, class Fields>
  263. template<class... BodyArgs, class... FieldsArgs>
  264. message<isRequest, Body, Fields>::
  265. message(std::piecewise_construct_t,
  266. std::tuple<BodyArgs...> body_args,
  267. std::tuple<FieldsArgs...> fields_args)
  268. : message(std::piecewise_construct,
  269. body_args,
  270. fields_args,
  271. mp11::make_index_sequence<
  272. sizeof...(BodyArgs)>{},
  273. mp11::make_index_sequence<
  274. sizeof...(FieldsArgs)>{})
  275. {
  276. }
  277. template<bool isRequest, class Body, class Fields>
  278. void
  279. message<isRequest, Body, Fields>::
  280. chunked(bool value)
  281. {
  282. this->set_chunked_impl(value);
  283. this->set_content_length_impl(boost::none);
  284. }
  285. template<bool isRequest, class Body, class Fields>
  286. void
  287. message<isRequest, Body, Fields>::
  288. content_length(
  289. boost::optional<std::uint64_t> const& value)
  290. {
  291. this->set_content_length_impl(value);
  292. this->set_chunked_impl(false);
  293. }
  294. template<bool isRequest, class Body, class Fields>
  295. boost::optional<std::uint64_t>
  296. message<isRequest, Body, Fields>::
  297. payload_size() const
  298. {
  299. return payload_size(detail::is_body_sized<Body>{});
  300. }
  301. template<bool isRequest, class Body, class Fields>
  302. bool
  303. message<isRequest, Body, Fields>::
  304. need_eof(std::false_type) const
  305. {
  306. // VFALCO Do we need a way to let the caller say "the body is intentionally skipped"?
  307. if( this->result() == status::no_content ||
  308. this->result() == status::not_modified ||
  309. to_status_class(this->result()) ==
  310. status_class::informational ||
  311. has_content_length() ||
  312. chunked())
  313. return ! keep_alive();
  314. return true;
  315. }
  316. template<bool isRequest, class Body, class Fields>
  317. void
  318. message<isRequest, Body, Fields>::
  319. prepare_payload(std::true_type)
  320. {
  321. auto const n = payload_size();
  322. if(this->method() == verb::trace && (! n || *n > 0))
  323. BOOST_THROW_EXCEPTION(std::invalid_argument{
  324. "invalid request body"});
  325. if(n)
  326. {
  327. if(*n > 0 ||
  328. this->method() == verb::options ||
  329. this->method() == verb::put ||
  330. this->method() == verb::post)
  331. {
  332. this->content_length(n);
  333. }
  334. else
  335. {
  336. this->chunked(false);
  337. }
  338. }
  339. else if(this->version() == 11)
  340. {
  341. this->chunked(true);
  342. }
  343. else
  344. {
  345. this->chunked(false);
  346. }
  347. }
  348. template<bool isRequest, class Body, class Fields>
  349. void
  350. message<isRequest, Body, Fields>::
  351. prepare_payload(std::false_type)
  352. {
  353. auto const n = payload_size();
  354. if( (! n || *n > 0) && (
  355. (status_class(this->result()) == status_class::informational ||
  356. this->result() == status::no_content ||
  357. this->result() == status::not_modified)))
  358. {
  359. // The response body MUST be empty for this case
  360. BOOST_THROW_EXCEPTION(std::invalid_argument{
  361. "invalid response body"});
  362. }
  363. if(n)
  364. this->content_length(n);
  365. else if(this->version() == 11)
  366. this->chunked(true);
  367. else
  368. this->chunked(false);
  369. }
  370. //------------------------------------------------------------------------------
  371. template<bool isRequest, class Body, class Fields>
  372. void
  373. swap(
  374. message<isRequest, Body, Fields>& m1,
  375. message<isRequest, Body, Fields>& m2)
  376. {
  377. using std::swap;
  378. swap(
  379. static_cast<header<isRequest, Fields>&>(m1),
  380. static_cast<header<isRequest, Fields>&>(m2));
  381. swap(m1.body(), m2.body());
  382. }
  383. } // http
  384. } // beast
  385. } // boost
  386. #endif