url.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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_URL_DECL 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. virtual ~url();
  68. /** Constructor
  69. Default constructed urls contain
  70. a zero-length string. This matches
  71. the grammar for a relative-ref with
  72. an empty path and no query or
  73. fragment.
  74. @par Example
  75. @code
  76. url u;
  77. @endcode
  78. @par Postconditions
  79. @code
  80. this->empty() == true
  81. @endcode
  82. @par Complexity
  83. Constant.
  84. @par Exception Safety
  85. Throws nothing.
  86. @par BNF
  87. @code
  88. relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  89. @endcode
  90. @par Specification
  91. <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.2"
  92. >4.2. Relative Reference (rfc3986)</a>
  93. */
  94. url() noexcept;
  95. /** Constructor
  96. This function constructs a URL from
  97. the string `s`, which must contain a
  98. valid <em>URI</em> or <em>relative-ref</em>
  99. or else an exception is thrown.
  100. The new url retains ownership by
  101. allocating a copy of the passed string.
  102. @par Example
  103. @code
  104. url u( "https://www.example.com" );
  105. @endcode
  106. @par Effects
  107. @code
  108. return url( parse_uri_reference( s ).value() );
  109. @endcode
  110. @par Postconditions
  111. @code
  112. this->buffer().data() != s.data()
  113. @endcode
  114. @par Complexity
  115. Linear in `s.size()`.
  116. @par Exception Safety
  117. Calls to allocate may throw.
  118. Exceptions thrown on invalid input.
  119. @throw system_error
  120. The input does not contain a valid url.
  121. @param s The string to parse.
  122. @par BNF
  123. @code
  124. URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
  125. relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  126. @endcode
  127. @par Specification
  128. @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.1"
  129. >4.1. URI Reference</a>
  130. */
  131. explicit
  132. url(core::string_view s);
  133. /** Constructor
  134. The contents of `u` are transferred
  135. to the newly constructed object,
  136. which includes the underlying
  137. character buffer.
  138. After construction, the moved-from
  139. object is as if default constructed.
  140. @par Postconditions
  141. @code
  142. u.empty() == true
  143. @endcode
  144. @par Complexity
  145. Constant.
  146. @par Exception Safety
  147. Throws nothing.
  148. @param u The url to move from.
  149. */
  150. url(url&& u) noexcept;
  151. /** Constructor
  152. The newly constructed object
  153. contains a copy of `u`.
  154. @par Postconditions
  155. @code
  156. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  157. @endcode
  158. @par Complexity
  159. Linear in `u.size()`.
  160. @par Exception Safety
  161. Strong guarantee.
  162. Calls to allocate may throw.
  163. @throw std::length_error `u.size() > max_size()`.
  164. @param u The url to copy.
  165. */
  166. url(url_view_base const& u)
  167. {
  168. copy(u);
  169. }
  170. /** Constructor
  171. The newly constructed object
  172. contains a copy of `u`.
  173. @par Postconditions
  174. @code
  175. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  176. @endcode
  177. @par Complexity
  178. Linear in `u.size()`.
  179. @par Exception Safety
  180. Strong guarantee.
  181. Calls to allocate may throw.
  182. @throw std::length_error `u.size() > max_size()`.
  183. @param u The url to copy.
  184. */
  185. url(url const& u)
  186. : url(static_cast<
  187. url_view_base const&>(u))
  188. {
  189. }
  190. /** Assignment
  191. The contents of `u` are transferred to
  192. `this`, including the underlying
  193. character buffer. The previous contents
  194. of `this` are destroyed.
  195. After assignment, the moved-from
  196. object is as if default constructed.
  197. @par Postconditions
  198. @code
  199. u.empty() == true
  200. @endcode
  201. @par Complexity
  202. Constant.
  203. @par Exception Safety
  204. Throws nothing.
  205. @param u The url to assign from.
  206. @return A reference to this object.
  207. */
  208. url&
  209. operator=(url&& u) noexcept;
  210. /** Assignment
  211. The contents of `u` are copied and
  212. the previous contents of `this` are
  213. destroyed.
  214. Capacity is preserved, or increases.
  215. @par Postconditions
  216. @code
  217. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  218. @endcode
  219. @par Complexity
  220. Linear in `u.size()`.
  221. @par Exception Safety
  222. Strong guarantee.
  223. Calls to allocate may throw.
  224. @throw std::length_error `u.size() > max_size()`.
  225. @param u The url to copy.
  226. @return A reference to this object.
  227. */
  228. url&
  229. operator=(
  230. url_view_base const& u)
  231. {
  232. copy(u);
  233. return *this;
  234. }
  235. /** Assignment
  236. The contents of `u` are copied and
  237. the previous contents of `this` are
  238. destroyed.
  239. Capacity is preserved, or increases.
  240. @par Postconditions
  241. @code
  242. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  243. @endcode
  244. @par Complexity
  245. Linear in `u.size()`.
  246. @par Exception Safety
  247. Strong guarantee.
  248. Calls to allocate may throw.
  249. @param u The url to copy.
  250. @return A reference to this object.
  251. */
  252. url&
  253. operator=(url const& u)
  254. {
  255. return (*this)=static_cast<
  256. url_view_base const&>(u);
  257. }
  258. //--------------------------------------------
  259. /** Swap the contents.
  260. Exchanges the contents of this url with another
  261. url. All views, iterators and references remain valid.
  262. If `this == &other`, this function call has no effect.
  263. @par Example
  264. @code
  265. url u1( "https://www.example.com" );
  266. url u2( "https://www.boost.org" );
  267. u1.swap(u2);
  268. assert(u1 == "https://www.boost.org" );
  269. assert(u2 == "https://www.example.com" );
  270. @endcode
  271. @par Complexity
  272. Constant
  273. @par Exception Safety
  274. Throws nothing.
  275. @param other The object to swap with
  276. */
  277. void
  278. swap(url& other) noexcept;
  279. /** Swap
  280. Exchanges the contents of `v0` with another `v1`.
  281. All views, iterators and references remain
  282. valid.
  283. If `&v0 == &v1`, this function call has no effect.
  284. @par Example
  285. @code
  286. url u1( "https://www.example.com" );
  287. url u2( "https://www.boost.org" );
  288. std::swap(u1, u2);
  289. assert(u1 == "https://www.boost.org" );
  290. assert(u2 == "https://www.example.com" );
  291. @endcode
  292. @par Effects
  293. @code
  294. v0.swap( v1 );
  295. @endcode
  296. @par Complexity
  297. Constant
  298. @par Exception Safety
  299. Throws nothing
  300. @param v0 The first object to swap
  301. @param v1 The second object to swap
  302. @see
  303. @ref url::swap
  304. */
  305. friend
  306. void
  307. swap(url& v0, url& v1) noexcept
  308. {
  309. v0.swap(v1);
  310. }
  311. //--------------------------------------------
  312. //
  313. // fluent api
  314. //
  315. /// @copydoc url_base::set_scheme
  316. url& set_scheme(core::string_view s) { url_base::set_scheme(s); return *this; }
  317. /// @copydoc url_base::set_scheme_id
  318. url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; }
  319. /// @copydoc url_base::remove_scheme
  320. url& remove_scheme() { url_base::remove_scheme(); return *this; }
  321. /// @copydoc url_base::set_encoded_authority
  322. url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; }
  323. /// @copydoc url_base::remove_authority
  324. url& remove_authority() { url_base::remove_authority(); return *this; }
  325. /// @copydoc url_base::set_userinfo
  326. url& set_userinfo(core::string_view s) { url_base::set_userinfo(s); return *this; }
  327. /// @copydoc url_base::set_encoded_userinfo
  328. url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; }
  329. /// @copydoc url_base::remove_userinfo
  330. url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; }
  331. /// @copydoc url_base::set_user
  332. url& set_user(core::string_view s) { url_base::set_user(s); return *this; }
  333. /// @copydoc url_base::set_encoded_user
  334. url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; }
  335. /// @copydoc url_base::set_password
  336. url& set_password(core::string_view s) { url_base::set_password(s); return *this; }
  337. /// @copydoc url_base::set_encoded_password
  338. url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; }
  339. /// @copydoc url_base::remove_password
  340. url& remove_password() noexcept { url_base::remove_password(); return *this; }
  341. /// @copydoc url_base::set_host
  342. url& set_host(core::string_view s) { url_base::set_host(s); return *this; }
  343. /// @copydoc url_base::set_encoded_host
  344. url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; }
  345. /// @copydoc url_base::set_host_address
  346. url& set_host_address(core::string_view s) { url_base::set_host_address(s); return *this; }
  347. /// @copydoc url_base::set_encoded_host_address
  348. url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; }
  349. /// @copydoc url_base::set_host_ipv4
  350. url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
  351. /// @copydoc url_base::set_host_ipv6
  352. url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
  353. /// @copydoc url_base::set_zone_id
  354. url& set_zone_id(core::string_view s) { url_base::set_zone_id(s); return *this; }
  355. /// @copydoc url_base::set_encoded_zone_id
  356. url& set_encoded_zone_id(pct_string_view const& s) { url_base::set_encoded_zone_id(s); return *this; }
  357. /// @copydoc url_base::set_host_ipvfuture
  358. url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
  359. /// @copydoc url_base::set_host_name
  360. url& set_host_name(core::string_view s) { url_base::set_host_name(s); return *this; }
  361. /// @copydoc url_base::set_encoded_host_name
  362. url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; }
  363. /// @copydoc url_base::set_port_number
  364. url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; }
  365. /// @copydoc url_base::set_port
  366. url& set_port(core::string_view s) { url_base::set_port(s); return *this; }
  367. /// @copydoc url_base::remove_port
  368. url& remove_port() noexcept { url_base::remove_port(); return *this; }
  369. /// @copydoc url_base::set_path_absolute
  370. //bool set_path_absolute(bool absolute);
  371. /// @copydoc url_base::set_path
  372. url& set_path(core::string_view s) { url_base::set_path(s); return *this; }
  373. /// @copydoc url_base::set_encoded_path
  374. url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; }
  375. /// @copydoc url_base::set_query
  376. url& set_query(core::string_view s) { url_base::set_query(s); return *this; }
  377. /// @copydoc url_base::set_encoded_query
  378. url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; }
  379. /// @copydoc url_base::set_params
  380. url& set_params(std::initializer_list<param_view> ps, encoding_opts opts = {}) { url_base::set_params(ps, opts); return *this; }
  381. /// @copydoc url_base::set_encoded_params
  382. url& set_encoded_params(std::initializer_list< param_pct_view > ps) { url_base::set_encoded_params(ps); return *this; }
  383. /// @copydoc url_base::remove_query
  384. url& remove_query() noexcept { url_base::remove_query(); return *this; }
  385. /// @copydoc url_base::remove_fragment
  386. url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; }
  387. /// @copydoc url_base::set_fragment
  388. url& set_fragment(core::string_view s) { url_base::set_fragment(s); return *this; }
  389. /// @copydoc url_base::set_encoded_fragment
  390. url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; }
  391. /// @copydoc url_base::remove_origin
  392. url& remove_origin() { url_base::remove_origin(); return *this; }
  393. /// @copydoc url_base::normalize
  394. url& normalize() { url_base::normalize(); return *this; }
  395. /// @copydoc url_base::normalize_scheme
  396. url& normalize_scheme() { url_base::normalize_scheme(); return *this; }
  397. /// @copydoc url_base::normalize_authority
  398. url& normalize_authority() { url_base::normalize_authority(); return *this; }
  399. /// @copydoc url_base::normalize_path
  400. url& normalize_path() { url_base::normalize_path(); return *this; }
  401. /// @copydoc url_base::normalize_query
  402. url& normalize_query() { url_base::normalize_query(); return *this; }
  403. /// @copydoc url_base::normalize_fragment
  404. url& normalize_fragment() { url_base::normalize_fragment(); return *this; }
  405. //--------------------------------------------
  406. private:
  407. char* allocate(std::size_t);
  408. void deallocate(char* s);
  409. void clear_impl() noexcept override;
  410. void reserve_impl(std::size_t, op_t&) override;
  411. void cleanup(op_t&) override;
  412. };
  413. } // urls
  414. } // boost
  415. //------------------------------------------------
  416. // std::hash specialization
  417. #ifndef BOOST_URL_DOCS
  418. namespace std {
  419. template<>
  420. struct hash< ::boost::urls::url >
  421. {
  422. hash() = default;
  423. hash(hash const&) = default;
  424. hash& operator=(hash const&) = default;
  425. explicit
  426. hash(std::size_t salt) noexcept
  427. : salt_(salt)
  428. {
  429. }
  430. std::size_t
  431. operator()(::boost::urls::url const& u) const noexcept
  432. {
  433. return u.digest(salt_);
  434. }
  435. private:
  436. std::size_t salt_ = 0;
  437. };
  438. } // std
  439. #endif
  440. #endif