request.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_HTTP_REQUEST_IMPL_HPP__
  11. #define __ASIO2_HTTP_REQUEST_IMPL_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <asio2/base/detail/push_options.hpp>
  16. #include <asio2/base/define.hpp>
  17. #include <asio2/base/impl/user_data_cp.hpp>
  18. #include <asio2/http/detail/http_util.hpp>
  19. #include <asio2/http/detail/http_url.hpp>
  20. #ifdef ASIO2_HEADER_ONLY
  21. namespace bho::beast::websocket
  22. #else
  23. namespace boost::beast::websocket
  24. #endif
  25. {
  26. template <class> class listener;
  27. }
  28. namespace asio2::detail
  29. {
  30. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  31. ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE;
  32. ASIO2_CLASS_FORWARD_DECLARE_TCP_CLIENT;
  33. ASIO2_CLASS_FORWARD_DECLARE_TCP_SESSION;
  34. template<class Body, class Fields = http::fields>
  35. class http_request_impl_t
  36. : public http::message<true, Body, Fields>
  37. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  38. , public user_data_cp<http_request_impl_t<Body, Fields>>
  39. #endif
  40. {
  41. template <class> friend class beast::websocket::listener;
  42. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  43. ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE;
  44. ASIO2_CLASS_FRIEND_DECLARE_TCP_CLIENT;
  45. ASIO2_CLASS_FRIEND_DECLARE_TCP_SESSION;
  46. public:
  47. using self = http_request_impl_t<Body, Fields>;
  48. using super = http::message<true, Body, Fields>;
  49. using header_type = typename super::header_type;
  50. using body_type = typename super::body_type;
  51. public:
  52. /**
  53. * @brief constructor
  54. */
  55. template<typename... Args>
  56. explicit http_request_impl_t(Args&&... args)
  57. : super(std::forward<Args>(args)...)
  58. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  59. , user_data_cp<http_request_impl_t<Body, Fields>>()
  60. #endif
  61. {
  62. }
  63. http_request_impl_t(const http_request_impl_t& o)
  64. : super()
  65. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  66. , user_data_cp<http_request_impl_t<Body, Fields>>()
  67. #endif
  68. {
  69. this->base() = o.base();
  70. this->url_ = o.url_;
  71. this->ws_frame_type_ = o.ws_frame_type_;
  72. this->ws_frame_data_ = o.ws_frame_data_;
  73. }
  74. http_request_impl_t(http_request_impl_t&& o)
  75. : super()
  76. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  77. , user_data_cp<http_request_impl_t<Body, Fields>>()
  78. #endif
  79. {
  80. this->base() = std::move(o.base());
  81. this->url_ = std::move(o.url_);
  82. this->ws_frame_type_ = o.ws_frame_type_;
  83. this->ws_frame_data_ = o.ws_frame_data_;
  84. }
  85. self& operator=(const http_request_impl_t& o)
  86. {
  87. this->base() = o.base();
  88. this->url_ = o.url_;
  89. this->ws_frame_type_ = o.ws_frame_type_;
  90. this->ws_frame_data_ = o.ws_frame_data_;
  91. return *this;
  92. }
  93. self& operator=(http_request_impl_t&& o)
  94. {
  95. this->base() = std::move(o.base());
  96. this->url_ = std::move(o.url_);
  97. this->ws_frame_type_ = o.ws_frame_type_;
  98. this->ws_frame_data_ = o.ws_frame_data_;
  99. return *this;
  100. }
  101. http_request_impl_t(const http::message<true, Body, Fields>& req)
  102. : super()
  103. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  104. , user_data_cp<http_request_impl_t<Body, Fields>>()
  105. #endif
  106. {
  107. this->base() = req;
  108. }
  109. http_request_impl_t(http::message<true, Body, Fields>&& req)
  110. : super()
  111. #ifdef ASIO2_ENABLE_HTTP_REQUEST_USER_DATA
  112. , user_data_cp<http_request_impl_t<Body, Fields>>()
  113. #endif
  114. {
  115. this->base() = std::move(req);
  116. }
  117. self& operator=(const http::message<true, Body, Fields>& req)
  118. {
  119. this->base() = req;
  120. return *this;
  121. }
  122. self& operator=(http::message<true, Body, Fields>&& req)
  123. {
  124. this->base() = std::move(req);
  125. return *this;
  126. }
  127. /**
  128. * @brief destructor
  129. */
  130. ~http_request_impl_t()
  131. {
  132. }
  133. /// Returns the base portion of the message
  134. inline super const& base() const noexcept
  135. {
  136. return *this;
  137. }
  138. /// Returns the base portion of the message
  139. inline super& base() noexcept
  140. {
  141. return *this;
  142. }
  143. inline void reset()
  144. {
  145. static_cast<super&>(*this) = {};
  146. }
  147. public:
  148. /**
  149. * @brief Returns `true` if this HTTP request is a WebSocket Upgrade.
  150. */
  151. inline bool is_upgrade() const noexcept { return websocket::is_upgrade(*this); }
  152. /**
  153. * @brief Gets the content of the "schema" section, maybe empty
  154. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  155. */
  156. inline std::string_view get_schema() const noexcept
  157. {
  158. return this->url_.schema();
  159. }
  160. /**
  161. * @brief Gets the content of the "schema" section, maybe empty
  162. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  163. * same as get_schema
  164. */
  165. inline std::string_view schema() const noexcept
  166. {
  167. return this->get_schema();
  168. }
  169. /**
  170. * @brief Gets the content of the "host" section, maybe empty
  171. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  172. */
  173. inline std::string_view get_host() const noexcept
  174. {
  175. return this->url_.host();
  176. }
  177. /**
  178. * @brief Gets the content of the "host" section, maybe empty
  179. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  180. * same as get_host
  181. */
  182. inline std::string_view host() const noexcept
  183. {
  184. return this->get_host();
  185. }
  186. /**
  187. * @brief Gets the content of the "port" section, maybe empty
  188. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  189. */
  190. inline std::string_view get_port() const noexcept
  191. {
  192. return this->url_.port();
  193. }
  194. /**
  195. * @brief Gets the content of the "port" section, maybe empty
  196. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  197. * same as get_port
  198. */
  199. inline std::string_view port() const noexcept
  200. {
  201. return this->get_port();
  202. }
  203. /**
  204. * @brief Gets the content of the "path" section of the target
  205. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  206. */
  207. inline std::string_view get_path() const
  208. {
  209. if (!this->url_.string().empty())
  210. return this->url_.path();
  211. if (!(this->url_.parser().field_set & (1 << (int)http::parses::url_fields::UF_PATH)))
  212. return std::string_view{ "/" };
  213. std::string_view target = this->target();
  214. return std::string_view{ &target[
  215. this->url_.parser().field_data[(int)http::parses::url_fields::UF_PATH].off],
  216. this->url_.parser().field_data[(int)http::parses::url_fields::UF_PATH].len };
  217. }
  218. /**
  219. * @brief Gets the content of the "path" section of the target
  220. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  221. * same as get_path
  222. */
  223. inline std::string_view path() const
  224. {
  225. return this->get_path();
  226. }
  227. /**
  228. * @brief Gets the content of the "query" section of the target
  229. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  230. */
  231. inline std::string_view get_query() const
  232. {
  233. if (!this->url_.string().empty())
  234. return this->url_.query();
  235. if (!(this->url_.parser().field_set & (1 << (int)http::parses::url_fields::UF_QUERY)))
  236. return std::string_view{};
  237. std::string_view target = this->target();
  238. return std::string_view{ &target[
  239. this->url_.parser().field_data[(int)http::parses::url_fields::UF_QUERY].off],
  240. this->url_.parser().field_data[(int)http::parses::url_fields::UF_QUERY].len };
  241. }
  242. /**
  243. * @brief Gets the content of the "query" section of the target
  244. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  245. * same as get_query
  246. */
  247. inline std::string_view query() const
  248. {
  249. return this->get_query();
  250. }
  251. /**
  252. * @brief Returns `true` if this HTTP request's Content-Type is "multipart/form-data";
  253. */
  254. inline bool has_multipart() const noexcept
  255. {
  256. return http::has_multipart(*this);
  257. }
  258. /**
  259. * @brief Get the "multipart/form-data" body content.
  260. */
  261. inline decltype(auto) get_multipart()
  262. {
  263. return http::multipart(*this);
  264. }
  265. /**
  266. * @brief Get the "multipart/form-data" body content. same as get_multipart
  267. */
  268. inline decltype(auto) multipart()
  269. {
  270. return this->get_multipart();
  271. }
  272. /**
  273. * @brief Get the url object reference. same as get_url
  274. */
  275. inline http::url& url() { return this->url_; }
  276. /**
  277. * @brief Get the url object reference. same as get_url
  278. */
  279. inline http::url const& url() const { return this->url_; }
  280. /**
  281. * @brief Get the url object reference.
  282. */
  283. inline http::url& get_url() { return this->url_; }
  284. /**
  285. * @brief Get the url object reference.
  286. */
  287. inline http::url const& get_url() const { return this->url_; }
  288. protected:
  289. http::url url_{ "" };
  290. websocket::frame ws_frame_type_ = websocket::frame::unknown;
  291. std::string_view ws_frame_data_;
  292. };
  293. struct http_request_convert_helper
  294. {
  295. template<class Body, class Fields>
  296. void from(http::request<Body, Fields>) {}
  297. template<class Body, class Fields>
  298. void from(detail::http_request_impl_t<Body, Fields>) {}
  299. };
  300. template<typename T, typename = void>
  301. struct can_convert_to_http_request : std::false_type {};
  302. template<typename T>
  303. struct can_convert_to_http_request<T, std::void_t<decltype(std::declval<
  304. http_request_convert_helper>().from(std::declval<T>()))>> : std::true_type {};
  305. template<class T>
  306. inline constexpr bool can_convert_to_http_request_v =
  307. can_convert_to_http_request<detail::remove_cvref_t<T>>::value;
  308. }
  309. #ifdef ASIO2_HEADER_ONLY
  310. namespace bho::beast::http
  311. #else
  312. namespace boost::beast::http
  313. #endif
  314. {
  315. using web_request = asio2::detail::http_request_impl_t<http::string_body>;
  316. }
  317. #include <asio2/base/detail/pop_options.hpp>
  318. #endif // !__ASIO2_HTTP_REQUEST_IMPL_HPP__