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