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 2938 : url(url_view_base const& u)
218 2938 : {
219 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
|