url.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. //
  2. // Copyright (c) 2019 Vinnie Falco ([email protected])
  3. // Copyright (c) 2022 Alan de Freitas ([email protected])
  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. */
  207. url&
  208. operator=(url&& u) noexcept;
  209. /** Assignment
  210. The contents of `u` are copied and
  211. the previous contents of `this` are
  212. destroyed.
  213. Capacity is preserved, or increases.
  214. @par Postconditions
  215. @code
  216. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  217. @endcode
  218. @par Complexity
  219. Linear in `u.size()`.
  220. @par Exception Safety
  221. Strong guarantee.
  222. Calls to allocate may throw.
  223. @throw std::length_error `u.size() > max_size()`.
  224. @param u The url to copy.
  225. */
  226. url&
  227. operator=(
  228. url_view_base const& u)
  229. {
  230. copy(u);
  231. return *this;
  232. }
  233. /** Assignment
  234. The contents of `u` are copied and
  235. the previous contents of `this` are
  236. destroyed.
  237. Capacity is preserved, or increases.
  238. @par Postconditions
  239. @code
  240. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  241. @endcode
  242. @par Complexity
  243. Linear in `u.size()`.
  244. @par Exception Safety
  245. Strong guarantee.
  246. Calls to allocate may throw.
  247. @param u The url to copy.
  248. */
  249. url&
  250. operator=(url const& u)
  251. {
  252. return (*this)=static_cast<
  253. url_view_base const&>(u);
  254. }
  255. //--------------------------------------------
  256. /** Swap the contents.
  257. Exchanges the contents of this url with another
  258. url. All views, iterators and references remain valid.
  259. If `this == &other`, this function call has no effect.
  260. @par Example
  261. @code
  262. url u1( "https://www.example.com" );
  263. url u2( "https://www.boost.org" );
  264. u1.swap(u2);
  265. assert(u1 == "https://www.boost.org" );
  266. assert(u2 == "https://www.example.com" );
  267. @endcode
  268. @par Complexity
  269. Constant
  270. @par Exception Safety
  271. Throws nothing.
  272. @param other The object to swap with
  273. */
  274. void
  275. swap(url& other) noexcept;
  276. /** Swap
  277. Exchanges the contents of `v0` with another `v1`.
  278. All views, iterators and references remain
  279. valid.
  280. If `&v0 == &v1`, this function call has no effect.
  281. @par Example
  282. @code
  283. url u1( "https://www.example.com" );
  284. url u2( "https://www.boost.org" );
  285. std::swap(u1, u2);
  286. assert(u1 == "https://www.boost.org" );
  287. assert(u2 == "https://www.example.com" );
  288. @endcode
  289. @par Effects
  290. @code
  291. v0.swap( v1 );
  292. @endcode
  293. @par Complexity
  294. Constant
  295. @par Exception Safety
  296. Throws nothing
  297. @param v0, v1 The objects to swap
  298. @see
  299. @ref url::swap
  300. */
  301. friend
  302. void
  303. swap(url& v0, url& v1) noexcept
  304. {
  305. v0.swap(v1);
  306. }
  307. //--------------------------------------------
  308. //
  309. // fluent api
  310. //
  311. /// @copydoc url_base::set_scheme
  312. url& set_scheme(core::string_view s) { url_base::set_scheme(s); return *this; }
  313. /// @copydoc url_base::set_scheme_id
  314. url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; }
  315. /// @copydoc url_base::remove_scheme
  316. url& remove_scheme() { url_base::remove_scheme(); return *this; }
  317. /// @copydoc url_base::set_encoded_authority
  318. url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; }
  319. /// @copydoc url_base::remove_authority
  320. url& remove_authority() { url_base::remove_authority(); return *this; }
  321. /// @copydoc url_base::set_userinfo
  322. url& set_userinfo(core::string_view s) { url_base::set_userinfo(s); return *this; }
  323. /// @copydoc url_base::set_encoded_userinfo
  324. url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; }
  325. /// @copydoc url_base::remove_userinfo
  326. url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; }
  327. /// @copydoc url_base::set_user
  328. url& set_user(core::string_view s) { url_base::set_user(s); return *this; }
  329. /// @copydoc url_base::set_encoded_user
  330. url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; }
  331. /// @copydoc url_base::set_password
  332. url& set_password(core::string_view s) { url_base::set_password(s); return *this; }
  333. /// @copydoc url_base::set_encoded_password
  334. url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; }
  335. /// @copydoc url_base::remove_password
  336. url& remove_password() noexcept { url_base::remove_password(); return *this; }
  337. /// @copydoc url_base::set_host
  338. url& set_host(core::string_view s) { url_base::set_host(s); return *this; }
  339. /// @copydoc url_base::set_encoded_host
  340. url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; }
  341. /// @copydoc url_base::set_host_address
  342. url& set_host_address(core::string_view s) { url_base::set_host_address(s); return *this; }
  343. /// @copydoc url_base::set_encoded_host_address
  344. url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; }
  345. /// @copydoc url_base::set_host_ipv4
  346. url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
  347. /// @copydoc url_base::set_host_ipv6
  348. url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
  349. /// @copydoc url_base::set_host_ipvfuture
  350. url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
  351. /// @copydoc url_base::set_host_name
  352. url& set_host_name(core::string_view s) { url_base::set_host_name(s); return *this; }
  353. /// @copydoc url_base::set_encoded_host_name
  354. url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; }
  355. /// @copydoc url_base::set_port_number
  356. url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; }
  357. /// @copydoc url_base::set_port
  358. url& set_port(core::string_view s) { url_base::set_port(s); return *this; }
  359. /// @copydoc url_base::remove_port
  360. url& remove_port() noexcept { url_base::remove_port(); return *this; }
  361. /// @copydoc url_base::set_path_absolute
  362. //bool set_path_absolute(bool absolute);
  363. /// @copydoc url_base::set_path
  364. url& set_path(core::string_view s) { url_base::set_path(s); return *this; }
  365. /// @copydoc url_base::set_encoded_path
  366. url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; }
  367. /// @copydoc url_base::set_query
  368. url& set_query(core::string_view s) { url_base::set_query(s); return *this; }
  369. /// @copydoc url_base::set_encoded_query
  370. url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; }
  371. /// @copydoc url_base::set_params
  372. url& set_params(std::initializer_list<param_view> ps) { url_base::set_params(ps); return *this; }
  373. /// @copydoc url_base::set_encoded_params
  374. url& set_encoded_params(std::initializer_list< param_pct_view > ps) { url_base::set_encoded_params(ps); return *this; }
  375. /// @copydoc url_base::remove_query
  376. url& remove_query() noexcept { url_base::remove_query(); return *this; }
  377. /// @copydoc url_base::remove_fragment
  378. url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; }
  379. /// @copydoc url_base::set_fragment
  380. url& set_fragment(core::string_view s) { url_base::set_fragment(s); return *this; }
  381. /// @copydoc url_base::set_encoded_fragment
  382. url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; }
  383. /// @copydoc url_base::remove_origin
  384. url& remove_origin() { url_base::remove_origin(); return *this; }
  385. /// @copydoc url_base::normalize
  386. url& normalize() { url_base::normalize(); return *this; }
  387. /// @copydoc url_base::normalize_scheme
  388. url& normalize_scheme() { url_base::normalize_scheme(); return *this; }
  389. /// @copydoc url_base::normalize_authority
  390. url& normalize_authority() { url_base::normalize_authority(); return *this; }
  391. /// @copydoc url_base::normalize_path
  392. url& normalize_path() { url_base::normalize_path(); return *this; }
  393. /// @copydoc url_base::normalize_query
  394. url& normalize_query() { url_base::normalize_query(); return *this; }
  395. /// @copydoc url_base::normalize_fragment
  396. url& normalize_fragment() { url_base::normalize_fragment(); return *this; }
  397. //--------------------------------------------
  398. private:
  399. char* allocate(std::size_t);
  400. void deallocate(char* s);
  401. void clear_impl() noexcept override;
  402. void reserve_impl(std::size_t, op_t&) override;
  403. void cleanup(op_t&) override;
  404. };
  405. } // urls
  406. } // boost
  407. //------------------------------------------------
  408. // std::hash specialization
  409. #ifndef BOOST_URL_DOCS
  410. namespace std {
  411. template<>
  412. struct hash< ::boost::urls::url >
  413. {
  414. hash() = default;
  415. hash(hash const&) = default;
  416. hash& operator=(hash const&) = default;
  417. explicit
  418. hash(std::size_t salt) noexcept
  419. : salt_(salt)
  420. {
  421. }
  422. std::size_t
  423. operator()(::boost::urls::url const& u) const noexcept
  424. {
  425. return u.digest(salt_);
  426. }
  427. private:
  428. std::size_t salt_ = 0;
  429. };
  430. } // std
  431. #endif
  432. #endif