url.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/url
  9. //
  10. #ifndef BOOST_URL_URL_HPP
  11. #define BOOST_URL_URL_HPP
  12. #include <boost/url/detail/config.hpp>
  13. #include <boost/url/url_base.hpp>
  14. #include <boost/assert.hpp>
  15. #include <utility>
  16. namespace boost {
  17. namespace urls {
  18. /** A modifiable container for a URL.
  19. This container owns a url, represented
  20. by a null-terminated character buffer
  21. which is managed by performing dymamic
  22. memory allocations as needed.
  23. The contents may be inspected and modified,
  24. and the implementation maintains a useful
  25. invariant: changes to the url always
  26. leave it in a valid state.
  27. @par Exception Safety
  28. @li Functions marked `noexcept` provide the
  29. no-throw guarantee, otherwise:
  30. @li Functions which throw offer the strong
  31. exception safety guarantee.
  32. @par BNF
  33. @code
  34. URI-reference = URI / relative-ref
  35. URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
  36. relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  37. absolute-URI = scheme ":" hier-part [ "?" query ]
  38. @endcode
  39. @par Specification
  40. @li <a href="https://tools.ietf.org/html/rfc3986"
  41. >Uniform Resource Identifier (URI): Generic Syntax (rfc3986)</a>
  42. @see
  43. @ref parse_absolute_uri,
  44. @ref parse_relative_ref,
  45. @ref parse_uri,
  46. @ref parse_uri_reference,
  47. @ref resolve.
  48. */
  49. class BOOST_SYMBOL_VISIBLE url
  50. : public url_base
  51. {
  52. friend std::hash<url>;
  53. using url_view_base::digest;
  54. public:
  55. //--------------------------------------------
  56. //
  57. // Special Members
  58. //
  59. //--------------------------------------------
  60. /** Destructor
  61. Any params, segments, iterators, or
  62. views which reference this object are
  63. invalidated. The underlying character
  64. buffer is destroyed, invalidating all
  65. references to it.
  66. */
  67. BOOST_URL_DECL
  68. virtual ~url();
  69. /** Constructor
  70. Default constructed urls contain
  71. a zero-length string. This matches
  72. the grammar for a relative-ref with
  73. an empty path and no query or
  74. fragment.
  75. @par Example
  76. @code
  77. url u;
  78. @endcode
  79. @par Postconditions
  80. @code
  81. this->empty() == true
  82. @endcode
  83. @par Complexity
  84. Constant.
  85. @par Exception Safety
  86. Throws nothing.
  87. @par BNF
  88. @code
  89. relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  90. @endcode
  91. @par Specification
  92. <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.2"
  93. >4.2. Relative Reference (rfc3986)</a>
  94. */
  95. BOOST_URL_DECL
  96. url() noexcept;
  97. /** Constructor
  98. This function constructs a URL from
  99. the string `s`, which must contain a
  100. valid <em>URI</em> or <em>relative-ref</em>
  101. or else an exception is thrown.
  102. The new url retains ownership by
  103. allocating a copy of the passed string.
  104. @par Example
  105. @code
  106. url u( "https://www.example.com" );
  107. @endcode
  108. @par Effects
  109. @code
  110. return url( parse_uri_reference( s ).value() );
  111. @endcode
  112. @par Postconditions
  113. @code
  114. this->buffer().data() != s.data()
  115. @endcode
  116. @par Complexity
  117. Linear in `s.size()`.
  118. @par Exception Safety
  119. Calls to allocate may throw.
  120. Exceptions thrown on invalid input.
  121. @throw system_error
  122. The input does not contain a valid url.
  123. @param s The string to parse.
  124. @par BNF
  125. @code
  126. URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
  127. relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  128. @endcode
  129. @par Specification
  130. @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.1"
  131. >4.1. URI Reference</a>
  132. */
  133. BOOST_URL_DECL
  134. explicit
  135. url(string_view s);
  136. /** Constructor
  137. The contents of `u` are transferred
  138. to the newly constructed object,
  139. which includes the underlying
  140. character buffer.
  141. After construction, the moved-from
  142. object is as if default constructed.
  143. @par Postconditions
  144. @code
  145. u.empty() == true
  146. @endcode
  147. @par Complexity
  148. Constant.
  149. @par Exception Safety
  150. Throws nothing.
  151. @param u The url to move from.
  152. */
  153. BOOST_URL_DECL
  154. url(url&& u) noexcept;
  155. /** Constructor
  156. The newly constructed object
  157. contains a copy of `u`.
  158. @par Postconditions
  159. @code
  160. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  161. @endcode
  162. @par Complexity
  163. Linear in `u.size()`.
  164. @par Exception Safety
  165. Strong guarantee.
  166. Calls to allocate may throw.
  167. @throw std::length_error `u.size() > max_size()`.
  168. @param u The url to copy.
  169. */
  170. url(url_view_base const& u)
  171. {
  172. copy(u);
  173. }
  174. /** Constructor
  175. The newly constructed object
  176. contains a copy of `u`.
  177. @par Postconditions
  178. @code
  179. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  180. @endcode
  181. @par Complexity
  182. Linear in `u.size()`.
  183. @par Exception Safety
  184. Strong guarantee.
  185. Calls to allocate may throw.
  186. @throw std::length_error `u.size() > max_size()`.
  187. @param u The url to copy.
  188. */
  189. url(url const& u)
  190. : url(static_cast<
  191. url_view_base const&>(u))
  192. {
  193. }
  194. /** Assignment
  195. The contents of `u` are transferred to
  196. `this`, including the underlying
  197. character buffer. The previous contents
  198. of `this` are destroyed.
  199. After assignment, the moved-from
  200. object is as if default constructed.
  201. @par Postconditions
  202. @code
  203. u.empty() == true
  204. @endcode
  205. @par Complexity
  206. Constant.
  207. @par Exception Safety
  208. Throws nothing.
  209. @param u The url to assign from.
  210. */
  211. BOOST_URL_DECL
  212. url&
  213. operator=(url&& u) noexcept;
  214. /** Assignment
  215. The contents of `u` are copied and
  216. the previous contents of `this` are
  217. destroyed.
  218. Capacity is preserved, or increases.
  219. @par Postconditions
  220. @code
  221. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  222. @endcode
  223. @par Complexity
  224. Linear in `u.size()`.
  225. @par Exception Safety
  226. Strong guarantee.
  227. Calls to allocate may throw.
  228. @throw std::length_error `u.size() > max_size()`.
  229. @param u The url to copy.
  230. */
  231. url&
  232. operator=(
  233. url_view_base const& u)
  234. {
  235. copy(u);
  236. return *this;
  237. }
  238. /** Assignment
  239. The contents of `u` are copied and
  240. the previous contents of `this` are
  241. destroyed.
  242. Capacity is preserved, or increases.
  243. @par Postconditions
  244. @code
  245. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  246. @endcode
  247. @par Complexity
  248. Linear in `u.size()`.
  249. @par Exception Safety
  250. Strong guarantee.
  251. Calls to allocate may throw.
  252. @param u The url to copy.
  253. */
  254. url&
  255. operator=(url const& u)
  256. {
  257. return (*this)=static_cast<
  258. url_view_base const&>(u);
  259. }
  260. //--------------------------------------------
  261. /** Swap the contents.
  262. Exchanges the contents of this url with another
  263. url. All views, iterators and references remain valid.
  264. If `this == &other`, this function call has no effect.
  265. @par Example
  266. @code
  267. url u1( "https://www.example.com" );
  268. url u2( "https://www.boost.org" );
  269. u1.swap(u2);
  270. assert(u1 == "https://www.boost.org" );
  271. assert(u2 == "https://www.example.com" );
  272. @endcode
  273. @par Complexity
  274. Constant
  275. @par Exception Safety
  276. Throws nothing.
  277. @param other The object to swap with
  278. */
  279. BOOST_URL_DECL
  280. void
  281. swap(url& other) noexcept;
  282. /** Swap
  283. Exchanges the contents of `v0` with another `v1`.
  284. All views, iterators and references remain
  285. valid.
  286. If `&v0 == &v1`, this function call has no effect.
  287. @par Example
  288. @code
  289. url u1( "https://www.example.com" );
  290. url u2( "https://www.boost.org" );
  291. std::swap(u1, u2);
  292. assert(u1 == "https://www.boost.org" );
  293. assert(u2 == "https://www.example.com" );
  294. @endcode
  295. @par Effects
  296. @code
  297. v0.swap( v1 );
  298. @endcode
  299. @par Complexity
  300. Constant
  301. @par Exception Safety
  302. Throws nothing
  303. @param v0, v1 The objects to swap
  304. @see
  305. @ref url::swap
  306. */
  307. friend
  308. void
  309. swap(url& v0, url& v1) noexcept
  310. {
  311. v0.swap(v1);
  312. }
  313. //--------------------------------------------
  314. //
  315. // fluent api
  316. //
  317. /// @copydoc url_base::set_scheme
  318. url& set_scheme(string_view s) { url_base::set_scheme(s); return *this; }
  319. /// @copydoc url_base::set_scheme_id
  320. url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; }
  321. /// @copydoc url_base::remove_scheme
  322. url& remove_scheme() { url_base::remove_scheme(); return *this; }
  323. /// @copydoc url_base::set_encoded_authority
  324. url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; }
  325. /// @copydoc url_base::remove_authority
  326. url& remove_authority() { url_base::remove_authority(); return *this; }
  327. /// @copydoc url_base::set_userinfo
  328. url& set_userinfo(string_view s) { url_base::set_userinfo(s); return *this; }
  329. /// @copydoc url_base::set_encoded_userinfo
  330. url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; }
  331. /// @copydoc url_base::remove_userinfo
  332. url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; }
  333. /// @copydoc url_base::set_user
  334. url& set_user(string_view s) { url_base::set_user(s); return *this; }
  335. /// @copydoc url_base::set_encoded_user
  336. url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; }
  337. /// @copydoc url_base::set_password
  338. url& set_password(string_view s) { url_base::set_password(s); return *this; }
  339. /// @copydoc url_base::set_encoded_password
  340. url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; }
  341. /// @copydoc url_base::remove_password
  342. url& remove_password() noexcept { url_base::remove_password(); return *this; }
  343. /// @copydoc url_base::set_host
  344. url& set_host(string_view s) { url_base::set_host(s); return *this; }
  345. /// @copydoc url_base::set_encoded_host
  346. url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; }
  347. /// @copydoc url_base::set_host_address
  348. url& set_host_address(string_view s) { url_base::set_host_address(s); return *this; }
  349. /// @copydoc url_base::set_encoded_host_address
  350. url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; }
  351. /// @copydoc url_base::set_host_ipv4
  352. url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
  353. /// @copydoc url_base::set_host_ipv6
  354. url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
  355. /// @copydoc url_base::set_host_ipvfuture
  356. url& set_host_ipvfuture(string_view s) { url_base::set_host_ipvfuture(s); return *this; }
  357. /// @copydoc url_base::set_host_name
  358. url& set_host_name(string_view s) { url_base::set_host_name(s); return *this; }
  359. /// @copydoc url_base::set_encoded_host_name
  360. url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; }
  361. /// @copydoc url_base::set_port_number
  362. url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; }
  363. /// @copydoc url_base::set_port
  364. url& set_port(string_view s) { url_base::set_port(s); return *this; }
  365. /// @copydoc url_base::remove_port
  366. url& remove_port() noexcept { url_base::remove_port(); return *this; }
  367. /// @copydoc url_base::set_path_absolute
  368. //bool set_path_absolute(bool absolute);
  369. /// @copydoc url_base::set_path
  370. url& set_path(string_view s) { url_base::set_path(s); return *this; }
  371. /// @copydoc url_base::set_encoded_path
  372. url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; }
  373. /// @copydoc url_base::set_query
  374. url& set_query(string_view s) { url_base::set_query(s); return *this; }
  375. /// @copydoc url_base::set_encoded_query
  376. url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; }
  377. /// @copydoc url_base::set_params
  378. url& set_params(std::initializer_list<param_view> s) { url_base::set_params(s); return *this; }
  379. /// @copydoc url_base::set_encoded_params
  380. url& set_encoded_params(std::initializer_list< param_pct_view > ps) { url_base::set_encoded_params(ps); return *this; }
  381. /// @copydoc url_base::remove_query
  382. url& remove_query() noexcept { url_base::remove_query(); return *this; }
  383. /// @copydoc url_base::remove_fragment
  384. url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; }
  385. /// @copydoc url_base::set_fragment
  386. url& set_fragment(string_view s) { url_base::set_fragment(s); return *this; }
  387. /// @copydoc url_base::set_encoded_fragment
  388. url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; }
  389. /// @copydoc url_base::remove_origin
  390. url& remove_origin() { url_base::remove_origin(); return *this; }
  391. /// @copydoc url_base::normalize
  392. url& normalize() { url_base::normalize(); return *this; }
  393. /// @copydoc url_base::normalize_scheme
  394. url& normalize_scheme() { url_base::normalize_scheme(); return *this; }
  395. /// @copydoc url_base::normalize_authority
  396. url& normalize_authority() { url_base::normalize_authority(); return *this; }
  397. /// @copydoc url_base::normalize_path
  398. url& normalize_path() { url_base::normalize_path(); return *this; }
  399. /// @copydoc url_base::normalize_query
  400. url& normalize_query() { url_base::normalize_query(); return *this; }
  401. /// @copydoc url_base::normalize_fragment
  402. url& normalize_fragment() { url_base::normalize_fragment(); return *this; }
  403. //--------------------------------------------
  404. private:
  405. char* allocate(std::size_t);
  406. void deallocate(char* s);
  407. BOOST_URL_DECL void clear_impl() noexcept override;
  408. BOOST_URL_DECL void reserve_impl(std::size_t, op_t&) override;
  409. BOOST_URL_DECL void cleanup(op_t&) override;
  410. };
  411. } // urls
  412. } // boost
  413. //------------------------------------------------
  414. // std::hash specialization
  415. #ifndef BOOST_URL_DOCS
  416. namespace std {
  417. template<>
  418. struct hash< ::boost::urls::url >
  419. {
  420. hash() = default;
  421. hash(hash const&) = default;
  422. hash& operator=(hash const&) = default;
  423. explicit
  424. hash(std::size_t salt) noexcept
  425. : salt_(salt)
  426. {
  427. }
  428. std::size_t
  429. operator()(::boost::urls::url const& u) const noexcept
  430. {
  431. return u.digest(salt_);
  432. }
  433. private:
  434. std::size_t salt_ = 0;
  435. };
  436. } // std
  437. #endif
  438. #endif