static_url.hpp 14 KB

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