message.ipp 10 KB

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