Line | Branch | Exec | Source |
---|---|---|---|
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 | 2938 | url(url_view_base const& u) | |
218 | 2938 | { | |
219 |
1/2✓ Branch 1 taken 2938 times.
✗ Branch 2 not taken.
|
2938 | copy(u); |
220 | 2938 | } | |
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 | 36 | 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 | ||
548 |