message.hpp 10 KB

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