http_url.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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_URL_HPP__
  11. #define __ASIO2_HTTP_URL_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <asio2/http/detail/http_util.hpp>
  16. #ifdef ASIO2_HEADER_ONLY
  17. namespace bho::beast::http
  18. #else
  19. namespace boost::beast::http
  20. #endif
  21. {
  22. /**
  23. * The object wrapped for a url string like "http://www.github.com"
  24. * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
  25. */
  26. class url
  27. {
  28. public:
  29. /**
  30. * @brief constructor
  31. */
  32. url()
  33. {
  34. this->reset("");
  35. }
  36. /**
  37. * @brief constructor
  38. */
  39. url(std::string str)
  40. {
  41. this->reset(std::move(str));
  42. }
  43. url(std::string_view str)
  44. {
  45. this->reset(str);
  46. }
  47. url(const char* str)
  48. {
  49. this->reset(str);
  50. }
  51. url(url&&) noexcept = default;
  52. url(url const&) = default;
  53. url& operator=(url&&) noexcept = default;
  54. url& operator=(url const&) = default;
  55. url& reset(std::string str)
  56. {
  57. string_ = std::move(str);
  58. std::memset((void*)(std::addressof(parser_)), 0, sizeof(http::parses::http_parser_url));
  59. if (!string_.empty())
  60. {
  61. if (0 != http::parses::http_parser_parse_url(
  62. string_.data(), string_.size(), 0, std::addressof(parser_)))
  63. {
  64. asio2::set_last_error(asio::error::invalid_argument);
  65. }
  66. }
  67. return *this;
  68. }
  69. url& reset(std::string_view str)
  70. {
  71. return reset(std::string(str));
  72. }
  73. url& reset(const char* str)
  74. {
  75. return reset(std::string(str));
  76. }
  77. /**
  78. * @brief Gets the content of the "schema" section, maybe empty
  79. * The return value is usually http or https
  80. */
  81. inline std::string_view get_schema() const noexcept
  82. {
  83. return this->field(http::parses::url_fields::UF_SCHEMA);
  84. }
  85. /**
  86. * @brief Gets the content of the "schema" section, maybe empty
  87. * The return value is usually http or https
  88. * same as get_schema
  89. */
  90. inline std::string_view schema() const noexcept
  91. {
  92. return this->get_schema();
  93. }
  94. /**
  95. * @brief Gets the content of the "host" section, maybe empty
  96. */
  97. inline std::string_view get_host() const noexcept
  98. {
  99. return this->field(http::parses::url_fields::UF_HOST);
  100. }
  101. /**
  102. * @brief Gets the content of the "host" section, maybe empty
  103. * same as get_host
  104. */
  105. inline std::string_view host() const noexcept
  106. {
  107. return this->get_host();
  108. }
  109. inline std::string_view get_default_port() const noexcept
  110. {
  111. std::string_view schema = this->schema();
  112. if (asio2::iequals(schema, "http"))
  113. return std::string_view{ "80" };
  114. if (asio2::iequals(schema, "https"))
  115. return std::string_view{ "443" };
  116. return std::string_view{ "80" };
  117. }
  118. inline std::string_view default_port() const noexcept
  119. {
  120. return this->get_default_port();
  121. }
  122. /**
  123. * @brief Gets the content of the "port" section
  124. */
  125. inline std::string_view get_port() const noexcept
  126. {
  127. std::string_view p = this->field(http::parses::url_fields::UF_PORT);
  128. if (p.empty())
  129. return this->default_port();
  130. return p;
  131. }
  132. /**
  133. * @brief Gets the content of the "port" section
  134. * same as get_port
  135. */
  136. inline std::string_view port() const noexcept
  137. {
  138. return this->get_port();
  139. }
  140. /**
  141. * @brief Gets the content of the "path" section
  142. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  143. */
  144. inline std::string_view get_path() const noexcept
  145. {
  146. std::string_view p = this->field(http::parses::url_fields::UF_PATH);
  147. if (p.empty())
  148. return std::string_view{ "/" };
  149. return p;
  150. }
  151. /**
  152. * @brief Gets the content of the "path" section
  153. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  154. * same as get_path
  155. */
  156. inline std::string_view path() const noexcept
  157. {
  158. return this->get_path();
  159. }
  160. /**
  161. * @brief Gets the content of the "query" section, maybe empty
  162. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  163. */
  164. inline std::string_view get_query() const noexcept
  165. {
  166. return this->field(http::parses::url_fields::UF_QUERY);
  167. }
  168. /**
  169. * @brief Gets the content of the "query" section, maybe empty
  170. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  171. * same as get_query
  172. */
  173. inline std::string_view query() const noexcept
  174. {
  175. return this->get_query();
  176. }
  177. /**
  178. * @brief Gets the "target", which composed by path and query
  179. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  180. */
  181. inline std::string_view get_target() const noexcept
  182. {
  183. if (parser_.field_set & (1 << (int)http::parses::url_fields::UF_PATH))
  184. {
  185. return std::string_view{ &string_[
  186. parser_.field_data[(int)http::parses::url_fields::UF_PATH].off],
  187. string_.size() -
  188. parser_.field_data[(int)http::parses::url_fields::UF_PATH].off };
  189. }
  190. return std::string_view{ "/" };
  191. }
  192. /**
  193. * @brief Gets the "target", which composed by path and query
  194. * the return value maybe has undecoded char, you can use http::url_decode(...) to decoded it.
  195. * same as get_target
  196. */
  197. inline std::string_view target() const noexcept
  198. {
  199. return this->get_target();
  200. }
  201. /**
  202. * @brief Gets the content of the specific section, maybe empty
  203. */
  204. inline std::string_view get_field(http::parses::url_fields f) const noexcept
  205. {
  206. if (!(parser_.field_set & (1 << int(f))))
  207. return std::string_view{};
  208. return std::string_view{ &string_[parser_.field_data[int(f)].off], parser_.field_data[int(f)].len };
  209. }
  210. /**
  211. * @brief Gets the content of the specific section, maybe empty
  212. * same as get_field
  213. */
  214. inline std::string_view field(http::parses::url_fields f) const noexcept
  215. {
  216. return this->get_field(std::move(f));
  217. }
  218. inline http::parses::http_parser_url & parser() noexcept { return this->parser_; }
  219. inline std::string & string() noexcept { return this->string_; }
  220. inline http::parses::http_parser_url & get_parser() noexcept { return this->parser_; }
  221. inline std::string & get_string() noexcept { return this->string_; }
  222. inline http::parses::http_parser_url const& parser() const noexcept { return this->parser_; }
  223. inline std::string const& string() const noexcept { return this->string_; }
  224. inline http::parses::http_parser_url const& get_parser() const noexcept { return this->parser_; }
  225. inline std::string const& get_string() const noexcept { return this->string_; }
  226. protected:
  227. http::parses::http_parser_url parser_;
  228. std::string string_;
  229. };
  230. template<class derived_t>
  231. std::string make_url_string(derived_t& derive, std::string_view target)
  232. {
  233. std::string url;
  234. if constexpr (std::is_base_of_v<asio2::detail::ssl_stream_tag, derived_t>)
  235. {
  236. url += "https://";
  237. url += derive.get_local_address();
  238. if (unsigned short n = derive.get_local_port(); n != 443)
  239. {
  240. url += ":";
  241. url += std::to_string(n);
  242. }
  243. }
  244. else
  245. {
  246. url = "http://";
  247. url += derive.get_local_address();
  248. if (unsigned short n = derive.get_local_port(); n != 80)
  249. {
  250. url += ":";
  251. url += std::to_string(n);
  252. }
  253. }
  254. url += target;
  255. return url;
  256. }
  257. template<class derived_t>
  258. std::string make_url_string(std::shared_ptr<derived_t>& derive_ptr, std::string_view target)
  259. {
  260. return make_url_string(*derive_ptr, target);
  261. }
  262. template<class derived_t>
  263. http::url make_url(derived_t& derive, std::string_view target)
  264. {
  265. return http::url(make_url_string(derive, target));
  266. }
  267. template<class derived_t>
  268. http::url make_url(std::shared_ptr<derived_t>& derive_ptr, std::string_view target)
  269. {
  270. return http::url(make_url_string(derive_ptr, target));
  271. }
  272. }
  273. #endif // !__ASIO2_HTTP_URL_HPP__