GCC Code Coverage Report


Directory: libs/url/
File: include/boost/url/url.hpp
Date: 2025-11-10 19:06:22
Exec Total Coverage
Lines: 59 59 100.0%
Functions: 48 48 100.0%
Branches: 1 2 50.0%

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 2957 url(url_view_base const& u)
218 2957 {
219
1/2
✓ Branch 1 taken 2957 times.
✗ Branch 2 not taken.
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
556