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 : 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 2957 : url(url_view_base const& u)
218 2957 : {
219 2957 : copy(u);
220 2957 : }
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 : @return A reference to this object.
271 : */
272 : url&
273 : operator=(url&& u) noexcept;
274 :
275 : /** Assignment
276 :
277 : The contents of `u` are copied and
278 : the previous contents of `this` are
279 : destroyed.
280 : Capacity is preserved, or increases.
281 :
282 : @par Postconditions
283 : @code
284 : this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
285 : @endcode
286 :
287 : @par Complexity
288 : Linear in `u.size()`.
289 :
290 : @par Exception Safety
291 : Strong guarantee.
292 : Calls to allocate may throw.
293 :
294 : @throw std::length_error `u.size() > max_size()`.
295 :
296 : @param u The url to copy.
297 : @return A reference to this object.
298 : */
299 : url&
300 99 : operator=(
301 : url_view_base const& u)
302 : {
303 99 : copy(u);
304 99 : return *this;
305 : }
306 :
307 : /** Assignment
308 :
309 : The contents of `u` are copied and
310 : the previous contents of `this` are
311 : destroyed.
312 : Capacity is preserved, or increases.
313 :
314 : @par Postconditions
315 : @code
316 : this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data()
317 : @endcode
318 :
319 : @par Complexity
320 : Linear in `u.size()`.
321 :
322 : @par Exception Safety
323 : Strong guarantee.
324 : Calls to allocate may throw.
325 :
326 : @param u The url to copy.
327 : @return A reference to this object.
328 : */
329 : url&
330 1 : operator=(url const& u)
331 : {
332 : return (*this)=static_cast<
333 1 : url_view_base const&>(u);
334 : }
335 :
336 : //--------------------------------------------
337 :
338 : /** Swap the contents.
339 :
340 : Exchanges the contents of this url with another
341 : url. All views, iterators and references remain valid.
342 :
343 : If `this == &other`, this function call has no effect.
344 :
345 : @par Example
346 : @code
347 : url u1( "https://www.example.com" );
348 : url u2( "https://www.boost.org" );
349 : u1.swap(u2);
350 : assert(u1 == "https://www.boost.org" );
351 : assert(u2 == "https://www.example.com" );
352 : @endcode
353 :
354 : @par Complexity
355 : Constant
356 :
357 : @par Exception Safety
358 : Throws nothing.
359 :
360 : @param other The object to swap with
361 :
362 : */
363 : void
364 : swap(url& other) noexcept;
365 :
366 : /** Swap
367 :
368 : Exchanges the contents of `v0` with another `v1`.
369 : All views, iterators and references remain
370 : valid.
371 :
372 : If `&v0 == &v1`, this function call has no effect.
373 :
374 : @par Example
375 : @code
376 : url u1( "https://www.example.com" );
377 : url u2( "https://www.boost.org" );
378 : std::swap(u1, u2);
379 : assert(u1 == "https://www.boost.org" );
380 : assert(u2 == "https://www.example.com" );
381 : @endcode
382 :
383 : @par Effects
384 : @code
385 : v0.swap( v1 );
386 : @endcode
387 :
388 : @par Complexity
389 : Constant
390 :
391 : @par Exception Safety
392 : Throws nothing
393 :
394 : @param v0 The first object to swap
395 : @param v1 The second object to swap
396 :
397 : @see
398 : @ref url::swap
399 : */
400 : friend
401 : void
402 2 : swap(url& v0, url& v1) noexcept
403 : {
404 2 : v0.swap(v1);
405 2 : }
406 :
407 : //--------------------------------------------
408 : //
409 : // fluent api
410 : //
411 :
412 : /// @copydoc url_base::set_scheme
413 51 : url& set_scheme(core::string_view s) { url_base::set_scheme(s); return *this; }
414 : /// @copydoc url_base::set_scheme_id
415 11 : url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; }
416 : /// @copydoc url_base::remove_scheme
417 21 : url& remove_scheme() { url_base::remove_scheme(); return *this; }
418 :
419 : /// @copydoc url_base::set_encoded_authority
420 41 : url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; }
421 : /// @copydoc url_base::remove_authority
422 43 : url& remove_authority() { url_base::remove_authority(); return *this; }
423 :
424 : /// @copydoc url_base::set_userinfo
425 45 : url& set_userinfo(core::string_view s) { url_base::set_userinfo(s); return *this; }
426 : /// @copydoc url_base::set_encoded_userinfo
427 51 : url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; }
428 : /// @copydoc url_base::remove_userinfo
429 22 : url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; }
430 : /// @copydoc url_base::set_user
431 1 : url& set_user(core::string_view s) { url_base::set_user(s); return *this; }
432 : /// @copydoc url_base::set_encoded_user
433 17 : url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; }
434 : /// @copydoc url_base::set_password
435 35 : url& set_password(core::string_view s) { url_base::set_password(s); return *this; }
436 : /// @copydoc url_base::set_encoded_password
437 38 : url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; }
438 : /// @copydoc url_base::remove_password
439 19 : url& remove_password() noexcept { url_base::remove_password(); return *this; }
440 :
441 : /// @copydoc url_base::set_host
442 13 : url& set_host(core::string_view s) { url_base::set_host(s); return *this; }
443 : /// @copydoc url_base::set_encoded_host
444 115 : url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; }
445 : /// @copydoc url_base::set_host_address
446 10 : url& set_host_address(core::string_view s) { url_base::set_host_address(s); return *this; }
447 : /// @copydoc url_base::set_encoded_host_address
448 8 : url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; }
449 : /// @copydoc url_base::set_host_ipv4
450 4 : url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
451 : /// @copydoc url_base::set_host_ipv6
452 5 : url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
453 : /// @copydoc url_base::set_zone_id
454 3 : url& set_zone_id(core::string_view s) { url_base::set_zone_id(s); return *this; }
455 : /// @copydoc url_base::set_encoded_zone_id
456 3 : url& set_encoded_zone_id(pct_string_view const& s) { url_base::set_encoded_zone_id(s); return *this; }
457 : /// @copydoc url_base::set_host_ipvfuture
458 3 : url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
459 : /// @copydoc url_base::set_host_name
460 4 : url& set_host_name(core::string_view s) { url_base::set_host_name(s); return *this; }
461 : /// @copydoc url_base::set_encoded_host_name
462 4 : url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; }
463 : /// @copydoc url_base::set_port_number
464 23 : url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; }
465 : /// @copydoc url_base::set_port
466 89 : url& set_port(core::string_view s) { url_base::set_port(s); return *this; }
467 : /// @copydoc url_base::remove_port
468 25 : url& remove_port() noexcept { url_base::remove_port(); return *this; }
469 :
470 : /// @copydoc url_base::set_path_absolute
471 : //bool set_path_absolute(bool absolute);
472 : /// @copydoc url_base::set_path
473 24 : url& set_path(core::string_view s) { url_base::set_path(s); return *this; }
474 : /// @copydoc url_base::set_encoded_path
475 58 : url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; }
476 :
477 : /// @copydoc url_base::set_query
478 9 : url& set_query(core::string_view s) { url_base::set_query(s); return *this; }
479 : /// @copydoc url_base::set_encoded_query
480 20 : url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; }
481 : /// @copydoc url_base::set_params
482 1 : url& set_params(std::initializer_list<param_view> ps, encoding_opts opts = {}) { url_base::set_params(ps, opts); return *this; }
483 : /// @copydoc url_base::set_encoded_params
484 1 : url& set_encoded_params(std::initializer_list< param_pct_view > ps) { url_base::set_encoded_params(ps); return *this; }
485 : /// @copydoc url_base::remove_query
486 6 : url& remove_query() noexcept { url_base::remove_query(); return *this; }
487 :
488 : /// @copydoc url_base::remove_fragment
489 4 : url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; }
490 : /// @copydoc url_base::set_fragment
491 5 : url& set_fragment(core::string_view s) { url_base::set_fragment(s); return *this; }
492 : /// @copydoc url_base::set_encoded_fragment
493 21 : url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; }
494 :
495 : /// @copydoc url_base::remove_origin
496 14 : url& remove_origin() { url_base::remove_origin(); return *this; }
497 :
498 : /// @copydoc url_base::normalize
499 37 : url& normalize() { url_base::normalize(); return *this; }
500 : /// @copydoc url_base::normalize_scheme
501 2 : url& normalize_scheme() { url_base::normalize_scheme(); return *this; }
502 : /// @copydoc url_base::normalize_authority
503 347 : url& normalize_authority() { url_base::normalize_authority(); return *this; }
504 : /// @copydoc url_base::normalize_path
505 367 : url& normalize_path() { url_base::normalize_path(); return *this; }
506 : /// @copydoc url_base::normalize_query
507 3 : url& normalize_query() { url_base::normalize_query(); return *this; }
508 : /// @copydoc url_base::normalize_fragment
509 : url& normalize_fragment() { url_base::normalize_fragment(); return *this; }
510 :
511 : //--------------------------------------------
512 :
513 : private:
514 : char* allocate(std::size_t);
515 : void deallocate(char* s);
516 :
517 : void clear_impl() noexcept override;
518 : void reserve_impl(std::size_t, op_t&) override;
519 : void cleanup(op_t&) override;
520 : };
521 :
522 : } // urls
523 : } // boost
524 :
525 : //------------------------------------------------
526 :
527 : // std::hash specialization
528 : #ifndef BOOST_URL_DOCS
529 : namespace std {
530 : template<>
531 : struct hash< ::boost::urls::url >
532 : {
533 : hash() = default;
534 : hash(hash const&) = default;
535 : hash& operator=(hash const&) = default;
536 :
537 : explicit
538 : hash(std::size_t salt) noexcept
539 : : salt_(salt)
540 : {
541 : }
542 :
543 : std::size_t
544 : operator()(::boost::urls::url const& u) const noexcept
545 : {
546 : return u.digest(salt_);
547 : }
548 :
549 : private:
550 : std::size_t salt_ = 0;
551 : };
552 : } // std
553 : #endif
554 :
555 : #endif
|