http_client.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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_CLIENT_HPP__
  11. #define __ASIO2_HTTP_CLIENT_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <fstream>
  16. #include <asio2/base/detail/push_options.hpp>
  17. #include <asio2/tcp/tcp_client.hpp>
  18. #include <asio2/http/http_execute.hpp>
  19. #include <asio2/http/http_download.hpp>
  20. #include <asio2/http/impl/http_send_op.hpp>
  21. #include <asio2/http/impl/http_recv_op.hpp>
  22. namespace asio2::detail
  23. {
  24. struct template_args_http_client : public template_args_tcp_client
  25. {
  26. using body_t = http::string_body;
  27. using buffer_t = beast::flat_buffer;
  28. using send_data_t = http::web_request&;
  29. using recv_data_t = http::web_response&;
  30. };
  31. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  32. ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE;
  33. ASIO2_CLASS_FORWARD_DECLARE_TCP_CLIENT;
  34. template<class derived_t, class args_t = template_args_http_client>
  35. class http_client_impl_t
  36. : public tcp_client_impl_t <derived_t, args_t>
  37. , public http_send_op <derived_t, args_t>
  38. , public http_recv_op <derived_t, args_t>
  39. , public http_execute_impl <derived_t, args_t>
  40. , public http_download_impl<derived_t, args_t>
  41. {
  42. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  43. ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE;
  44. ASIO2_CLASS_FRIEND_DECLARE_TCP_CLIENT;
  45. public:
  46. using super = tcp_client_impl_t <derived_t, args_t>;
  47. using self = http_client_impl_t<derived_t, args_t>;
  48. using args_type = args_t;
  49. using body_type = typename args_t::body_t;
  50. using buffer_type = typename args_t::buffer_t;
  51. using send_data_t = typename args_t::send_data_t;
  52. using recv_data_t = typename args_t::recv_data_t;
  53. using super::send;
  54. using super::async_send;
  55. public:
  56. /**
  57. * @brief constructor
  58. */
  59. template<class... Args>
  60. explicit http_client_impl_t(Args&&... args)
  61. : super(std::forward<Args>(args)...)
  62. , http_send_op<derived_t, args_t>()
  63. , req_()
  64. , rep_()
  65. {
  66. }
  67. /**
  68. * @brief destructor
  69. */
  70. ~http_client_impl_t()
  71. {
  72. this->stop();
  73. }
  74. /**
  75. * @brief start the client, blocking connect to server
  76. * @param host - A string identifying a location. May be a descriptive name or
  77. * a numeric address string.
  78. * @param port - A string identifying the requested service. This may be a
  79. * descriptive name or a numeric string corresponding to a port number.
  80. */
  81. template<typename String, typename StrOrInt, typename... Args>
  82. inline bool start(String&& host, StrOrInt&& port, Args&&... args)
  83. {
  84. if constexpr (ecs_helper::args_has_rdc<Args...>())
  85. {
  86. return this->derived().template _do_connect<false>(
  87. std::forward<String>(host), std::forward<StrOrInt>(port),
  88. ecs_helper::make_ecs('0', std::forward<Args>(args)...));
  89. }
  90. else
  91. {
  92. asio2::rdc::option rdc_option
  93. {
  94. [](http::web_request &) { return 0; },
  95. [](http::web_response&) { return 0; }
  96. };
  97. return this->derived().template _do_connect<false>(
  98. std::forward<String>(host), std::forward<StrOrInt>(port),
  99. ecs_helper::make_ecs('0', std::forward<Args>(args)..., std::move(rdc_option)));
  100. }
  101. }
  102. /**
  103. * @brief start the client, asynchronous connect to server
  104. * @param host - A string identifying a location. May be a descriptive name or
  105. * a numeric address string.
  106. * @param port - A string identifying the requested service. This may be a
  107. * descriptive name or a numeric string corresponding to a port number.
  108. */
  109. template<typename String, typename StrOrInt, typename... Args>
  110. inline bool async_start(String&& host, StrOrInt&& port, Args&&... args)
  111. {
  112. if constexpr (ecs_helper::args_has_rdc<Args...>())
  113. {
  114. return this->derived().template _do_connect<true>(
  115. std::forward<String>(host), std::forward<StrOrInt>(port),
  116. ecs_helper::make_ecs('0', std::forward<Args>(args)...));
  117. }
  118. else
  119. {
  120. asio2::rdc::option rdc_option
  121. {
  122. [](http::web_request &) { return 0; },
  123. [](http::web_response&) { return 0; }
  124. };
  125. return this->derived().template _do_connect<true>(
  126. std::forward<String>(host), std::forward<StrOrInt>(port),
  127. ecs_helper::make_ecs('0', std::forward<Args>(args)..., std::move(rdc_option)));
  128. }
  129. }
  130. public:
  131. /**
  132. * @brief get the request object, same as get_request
  133. */
  134. inline http::web_request & request() noexcept { return this->req_; }
  135. /**
  136. * @brief get the request object, same as get_request
  137. */
  138. inline const http::web_request & request() const noexcept { return this->req_; }
  139. /**
  140. * @brief get the response object, same as get_response
  141. */
  142. inline http::web_response& response() noexcept { return this->rep_; }
  143. /**
  144. * @brief get the response object, same as get_response
  145. */
  146. inline const http::web_response& response() const noexcept { return this->rep_; }
  147. /**
  148. * @brief get the request object
  149. */
  150. inline http::web_request & get_request() noexcept { return this->req_; }
  151. /**
  152. * @brief get the request object
  153. */
  154. inline const http::web_request & get_request() const noexcept { return this->req_; }
  155. /**
  156. * @brief get the response object
  157. */
  158. inline http::web_response& get_response() noexcept { return this->rep_; }
  159. /**
  160. * @brief get the response object
  161. */
  162. inline const http::web_response& get_response() const noexcept { return this->rep_; }
  163. public:
  164. /**
  165. * @brief bind recv listener
  166. * @param fun - a user defined callback function
  167. * Function signature : void(http::web_request& req, http::web_response& rep)
  168. */
  169. template<class F, class ...C>
  170. inline derived_t & bind_recv(F&& fun, C&&... obj)
  171. {
  172. this->listener_.bind(event_type::recv,
  173. observer_t<http::web_request&, http::web_response&>(std::forward<F>(fun), std::forward<C>(obj)...));
  174. return (this->derived());
  175. }
  176. protected:
  177. template<class Data, class Callback>
  178. inline bool _do_send(Data& data, Callback&& callback)
  179. {
  180. if constexpr (
  181. detail::is_template_instance_of_v<http::request, detail::remove_cvref_t<Data>> ||
  182. detail::is_template_instance_of_v<detail::http_request_impl_t, detail::remove_cvref_t<Data>>)
  183. {
  184. this->req_ = std::move(data);
  185. return this->derived()._http_send(this->req_, std::forward<Callback>(callback));
  186. }
  187. else
  188. {
  189. return this->derived()._http_send(data, std::forward<Callback>(callback));
  190. }
  191. }
  192. template<class Data>
  193. inline send_data_t _rdc_convert_to_send_data(Data& data)
  194. {
  195. return data;
  196. }
  197. template<class Invoker>
  198. inline void _rdc_invoke_with_none(const error_code& ec, Invoker& invoker)
  199. {
  200. if (invoker)
  201. invoker(ec, this->req_, this->rep_);
  202. }
  203. template<class Invoker>
  204. inline void _rdc_invoke_with_recv(const error_code& ec, Invoker& invoker, recv_data_t data)
  205. {
  206. detail::ignore_unused(data);
  207. if (invoker)
  208. invoker(ec, this->req_, this->rep_);
  209. }
  210. template<class Invoker>
  211. inline void _rdc_invoke_with_send(const error_code& ec, Invoker& invoker, send_data_t data)
  212. {
  213. if (invoker)
  214. invoker(ec, data, this->rep_);
  215. }
  216. protected:
  217. template<typename C>
  218. inline void _post_recv(std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs)
  219. {
  220. this->derived()._http_post_recv(std::move(this_ptr), std::move(ecs));
  221. }
  222. template<typename C>
  223. inline void _handle_recv(
  224. const error_code & ec, std::size_t bytes_recvd,
  225. std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs)
  226. {
  227. this->derived()._http_handle_recv(ec, bytes_recvd, std::move(this_ptr), std::move(ecs));
  228. }
  229. template<typename C>
  230. inline void _fire_recv(std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs)
  231. {
  232. this->listener_.notify(event_type::recv, this->req_, this->rep_);
  233. this->derived()._rdc_handle_recv(this_ptr, ecs, this->rep_);
  234. }
  235. protected:
  236. http::web_request req_;
  237. http::web_response rep_;
  238. };
  239. }
  240. namespace asio2
  241. {
  242. using http_client_args = detail::template_args_http_client;
  243. template<class derived_t, class args_t>
  244. using http_client_impl_t = detail::http_client_impl_t<derived_t, args_t>;
  245. template<class derived_t>
  246. class http_client_t : public detail::http_client_impl_t<derived_t, detail::template_args_http_client>
  247. {
  248. public:
  249. using detail::http_client_impl_t<derived_t, detail::template_args_http_client>::http_client_impl_t;
  250. };
  251. class http_client : public http_client_t<http_client>
  252. {
  253. public:
  254. using http_client_t<http_client>::http_client_t;
  255. };
  256. }
  257. #if defined(ASIO2_INCLUDE_RATE_LIMIT)
  258. #include <asio2/tcp/tcp_stream.hpp>
  259. namespace asio2
  260. {
  261. struct http_rate_client_args : public http_client_args
  262. {
  263. using socket_t = asio2::tcp_stream<asio2::simple_rate_policy>;
  264. };
  265. template<class derived_t>
  266. class http_rate_client_t : public asio2::http_client_impl_t<derived_t, http_rate_client_args>
  267. {
  268. public:
  269. using asio2::http_client_impl_t<derived_t, http_rate_client_args>::http_client_impl_t;
  270. };
  271. class http_rate_client : public asio2::http_rate_client_t<http_rate_client>
  272. {
  273. public:
  274. using asio2::http_rate_client_t<http_rate_client>::http_rate_client_t;
  275. };
  276. }
  277. #endif
  278. #include <asio2/base/detail/pop_options.hpp>
  279. #endif // !__ASIO2_HTTP_CLIENT_HPP__