static_url.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. //
  2. // Copyright (c) 2019 Vinnie Falco ([email protected])
  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/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
  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. Exception thrown if maximum size exceeded.
  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. */
  236. static_url&
  237. operator=(
  238. static_url const& u) noexcept
  239. {
  240. if (this != &u)
  241. copy(u);
  242. return *this;
  243. }
  244. /** Assignment
  245. The contents of `u` are copied and
  246. the previous contents of `this` are
  247. discarded.
  248. @par Postconditions
  249. @code
  250. this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
  251. @endcode
  252. @par Complexity
  253. Linear in `u.size()`.
  254. @par Exception Safety
  255. Strong guarantee.
  256. Exception thrown if capacity exceeded.
  257. @throw system_error
  258. Capacity would be exceeded.
  259. @param u The url to copy.
  260. */
  261. static_url&
  262. operator=(
  263. url_view_base const& u)
  264. {
  265. copy(u);
  266. return *this;
  267. }
  268. //--------------------------------------------
  269. //
  270. // fluent api
  271. //
  272. /// @copydoc url_base::set_scheme
  273. static_url& set_scheme(core::string_view s) { url_base::set_scheme(s); return *this; }
  274. /// @copydoc url_base::set_scheme_id
  275. static_url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; }
  276. /// @copydoc url_base::remove_scheme
  277. static_url& remove_scheme() { url_base::remove_scheme(); return *this; }
  278. /// @copydoc url_base::set_encoded_authority
  279. static_url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; }
  280. /// @copydoc url_base::remove_authority
  281. static_url& remove_authority() { url_base::remove_authority(); return *this; }
  282. /// @copydoc url_base::set_userinfo
  283. static_url& set_userinfo(core::string_view s) { url_base::set_userinfo(s); return *this; }
  284. /// @copydoc url_base::set_encoded_userinfo
  285. static_url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; }
  286. /// @copydoc url_base::remove_userinfo
  287. static_url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; }
  288. /// @copydoc url_base::set_user
  289. static_url& set_user(core::string_view s) { url_base::set_user(s); return *this; }
  290. /// @copydoc url_base::set_encoded_user
  291. static_url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; }
  292. /// @copydoc url_base::set_password
  293. static_url& set_password(core::string_view s) { url_base::set_password(s); return *this; }
  294. /// @copydoc url_base::set_encoded_password
  295. static_url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; }
  296. /// @copydoc url_base::remove_password
  297. static_url& remove_password() noexcept { url_base::remove_password(); return *this; }
  298. /// @copydoc url_base::set_host
  299. static_url& set_host(core::string_view s) { url_base::set_host(s); return *this; }
  300. /// @copydoc url_base::set_encoded_host
  301. static_url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; }
  302. /// @copydoc url_base::set_host_address
  303. static_url& set_host_address(core::string_view s) { url_base::set_host_address(s); return *this; }
  304. /// @copydoc url_base::set_encoded_host_address
  305. static_url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; }
  306. /// @copydoc url_base::set_host_ipv4
  307. static_url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
  308. /// @copydoc url_base::set_host_ipv6
  309. static_url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
  310. /// @copydoc url_base::set_host_ipvfuture
  311. static_url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
  312. /// @copydoc url_base::set_host_name
  313. static_url& set_host_name(core::string_view s) { url_base::set_host_name(s); return *this; }
  314. /// @copydoc url_base::set_encoded_host_name
  315. static_url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; }
  316. /// @copydoc url_base::set_port_number
  317. static_url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; }
  318. /// @copydoc url_base::set_port
  319. static_url& set_port(core::string_view s) { url_base::set_port(s); return *this; }
  320. /// @copydoc url_base::remove_port
  321. static_url& remove_port() noexcept { url_base::remove_port(); return *this; }
  322. /// @copydoc url_base::set_path_absolute
  323. //bool set_path_absolute(bool absolute);
  324. /// @copydoc url_base::set_path
  325. static_url& set_path(core::string_view s) { url_base::set_path(s); return *this; }
  326. /// @copydoc url_base::set_encoded_path
  327. static_url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; }
  328. /// @copydoc url_base::set_query
  329. static_url& set_query(core::string_view s) { url_base::set_query(s); return *this; }
  330. /// @copydoc url_base::set_encoded_query
  331. static_url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; }
  332. /// @copydoc url_base::remove_query
  333. static_url& remove_query() noexcept { url_base::remove_query(); return *this; }
  334. /// @copydoc url_base::remove_fragment
  335. static_url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; }
  336. /// @copydoc url_base::set_fragment
  337. static_url& set_fragment(core::string_view s) { url_base::set_fragment(s); return *this; }
  338. /// @copydoc url_base::set_encoded_fragment
  339. static_url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; }
  340. /// @copydoc url_base::remove_origin
  341. static_url& remove_origin() { url_base::remove_origin(); return *this; }
  342. /// @copydoc url_base::normalize
  343. static_url& normalize() { url_base::normalize(); return *this; }
  344. /// @copydoc url_base::normalize_scheme
  345. static_url& normalize_scheme() { url_base::normalize_scheme(); return *this; }
  346. /// @copydoc url_base::normalize_authority
  347. static_url& normalize_authority() { url_base::normalize_authority(); return *this; }
  348. /// @copydoc url_base::normalize_path
  349. static_url& normalize_path() { url_base::normalize_path(); return *this; }
  350. /// @copydoc url_base::normalize_query
  351. static_url& normalize_query() { url_base::normalize_query(); return *this; }
  352. /// @copydoc url_base::normalize_fragment
  353. static_url& normalize_fragment() { url_base::normalize_fragment(); return *this; }
  354. //--------------------------------------------
  355. };
  356. } // urls
  357. } // boost
  358. //------------------------------------------------
  359. // std::hash specialization
  360. #ifndef BOOST_URL_DOCS
  361. namespace std {
  362. template<std::size_t N>
  363. struct hash< ::boost::urls::static_url<N> >
  364. {
  365. hash() = default;
  366. hash(hash const&) = default;
  367. hash& operator=(hash const&) = default;
  368. explicit
  369. hash(std::size_t salt) noexcept
  370. : salt_(salt)
  371. {
  372. }
  373. std::size_t
  374. operator()(::boost::urls::static_url<N> const& u) const noexcept
  375. {
  376. return u.digest(salt_);
  377. }
  378. private:
  379. std::size_t salt_ = 0;
  380. };
  381. } // std
  382. #endif
  383. #endif