include/boost/url/impl/url_view_base.hpp

98.6% Lines (291 / 295) 100.0% Functions (35 / 35)
url_view_base.hpp
f(x) Functions (35)
Function Calls Lines Blocks
boost::urls::url_view_base::digest(unsigned long) const :83 304x 100.0% 100.0% boost::urls::url_view_base::has_scheme() const :107 4151x 100.0% 85.0% boost::urls::url_view_base::scheme() const :123 1564x 100.0% 85.0% boost::urls::url_view_base::scheme_id() const :138 46x 100.0% 100.0% boost::urls::url_view_base::authority() const :152 621x 100.0% 93.0% boost::urls::url_view_base::encoded_authority() const :185 842x 100.0% 95.0% boost::urls::url_view_base::has_userinfo() const :214 1106x 100.0% 86.0% boost::urls::url_view_base::has_password() const :228 989x 100.0% 86.0% boost::urls::url_view_base::encoded_userinfo() const :247 128x 100.0% 92.0% boost::urls::url_view_base::encoded_user() const :272 150x 100.0% 93.0% boost::urls::url_view_base::encoded_password() const :290 108x 100.0% 88.0% boost::urls::url_view_base::encoded_host() const :337 631x 100.0% 100.0% boost::urls::url_view_base::encoded_host_address() const :345 142x 100.0% 86.0% boost::urls::url_view_base::host_ipv4_address() const :382 53x 100.0% 100.0% boost::urls::url_view_base::host_ipv6_address() const :396 66x 100.0% 100.0% boost::urls::url_view_base::host_ipvfuture() const :410 51x 100.0% 86.0% boost::urls::url_view_base::encoded_host_name() const :426 146x 100.0% 100.0% boost::urls::url_view_base::encoded_zone_id() const :441 28x 100.0% 91.0% boost::urls::url_view_base::has_port() const :462 389x 100.0% 91.0% boost::urls::url_view_base::port() const :475 193x 100.0% 91.0% boost::urls::url_view_base::port_number() const :487 108x 100.0% 88.0% boost::urls::url_view_base::encoded_path() const :504 2458x 100.0% 100.0% boost::urls::url_view_base::segments() const :512 5785x 100.0% 100.0% boost::urls::url_view_base::encoded_segments() const :520 895x 100.0% 100.0% boost::urls::url_view_base::has_query() const :535 1172x 100.0% 91.0% boost::urls::url_view_base::encoded_query() const :550 445x 100.0% 92.0% boost::urls::url_view_base::encoded_params() const :563 72x 100.0% 100.0% boost::urls::url_view_base::params() const :571 5803x 100.0% 100.0% boost::urls::url_view_base::has_fragment() const :596 971x 100.0% 91.0% boost::urls::url_view_base::encoded_fragment() const :610 198x 100.0% 93.0% boost::urls::url_view_base::encoded_host_and_port() const :634 120x 100.0% 100.0% boost::urls::url_view_base::encoded_origin() const :642 16x 100.0% 100.0% boost::urls::url_view_base::encoded_resource() const :652 98x 100.0% 96.0% boost::urls::url_view_base::encoded_target() const :673 105x 100.0% 95.0% boost::urls::url_view_base::compare(boost::urls::url_view_base const&) const :697 348x 90.9% 93.0%
Line TLA Hits 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_IMPL_URL_VIEW_BASE_HPP
12 #define BOOST_URL_IMPL_URL_VIEW_BASE_HPP
13
14 #include <boost/url/detail/memcpy.hpp>
15 #include <boost/url/detail/except.hpp>
16 #include <boost/url/detail/fnv_1a.hpp>
17 #include <boost/assert.hpp>
18 #include <cstring>
19 #include <memory>
20
21 namespace boost {
22 namespace urls {
23
24 namespace detail {
25
26 // Forward declarations for normalize functions
27 // defined in src/detail/normalize.cpp
28 BOOST_URL_DECL
29 void
30 ci_digest(
31 core::string_view s,
32 fnv_1a& hasher) noexcept;
33
34 BOOST_URL_DECL
35 void
36 digest_encoded(
37 core::string_view s,
38 fnv_1a& hasher) noexcept;
39
40 BOOST_URL_DECL
41 void
42 ci_digest_encoded(
43 core::string_view s,
44 fnv_1a& hasher) noexcept;
45
46 BOOST_URL_DECL
47 void
48 normalized_path_digest(
49 core::string_view str,
50 bool remove_unmatched,
51 fnv_1a& hasher) noexcept;
52
53 BOOST_URL_DECL
54 int
55 ci_compare(
56 core::string_view lhs,
57 core::string_view rhs) noexcept;
58
59 BOOST_URL_DECL
60 int
61 compare_encoded(
62 core::string_view lhs,
63 core::string_view rhs) noexcept;
64
65 BOOST_URL_DECL
66 int
67 compare_encoded_query(
68 core::string_view lhs,
69 core::string_view rhs) noexcept;
70
71 BOOST_URL_DECL
72 int
73 segments_compare(
74 segments_encoded_view seg0,
75 segments_encoded_view seg1) noexcept;
76
77 } // detail
78
79 //------------------------------------------------
80
81 inline
82 std::size_t
83 304x url_view_base::
84 digest(std::size_t salt) const noexcept
85 {
86 304x detail::fnv_1a h(salt);
87 304x detail::ci_digest(impl().get(id_scheme), h);
88 304x detail::digest_encoded(impl().get(id_user), h);
89 304x detail::digest_encoded(impl().get(id_pass), h);
90 304x detail::ci_digest_encoded(impl().get(id_host), h);
91 304x h.put(impl().get(id_port));
92 304x detail::normalized_path_digest(
93 304x impl().get(id_path), is_path_absolute(), h);
94 304x detail::digest_encoded(impl().get(id_query), h);
95 304x detail::digest_encoded(impl().get(id_frag), h);
96 304x return h.digest();
97 }
98
99 //------------------------------------------------
100 //
101 // Scheme
102 //
103 //------------------------------------------------
104
105 inline
106 bool
107 4151x url_view_base::
108 has_scheme() const noexcept
109 {
110 4151x auto const n = impl().len(
111 id_scheme);
112 4151x if(n == 0)
113 980x return false;
114 3171x BOOST_ASSERT(n > 1);
115 3171x BOOST_ASSERT(
116 impl().get(id_scheme
117 ).ends_with(':'));
118 3171x return true;
119 }
120
121 inline
122 core::string_view
123 1564x url_view_base::
124 scheme() const noexcept
125 {
126 1564x auto s = impl().get(id_scheme);
127 1564x if(! s.empty())
128 {
129 1463x BOOST_ASSERT(s.size() > 1);
130 1463x BOOST_ASSERT(s.ends_with(':'));
131 1463x s.remove_suffix(1);
132 }
133 1564x return s;
134 }
135
136 inline
137 urls::scheme
138 46x url_view_base::
139 scheme_id() const noexcept
140 {
141 46x return impl().scheme_;
142 }
143
144 //------------------------------------------------
145 //
146 // Authority
147 //
148 //------------------------------------------------
149
150 inline
151 authority_view
152 621x url_view_base::
153 authority() const noexcept
154 {
155 621x detail::url_impl u(from::authority);
156 621x u.cs_ = encoded_authority().data();
157 621x if(has_authority())
158 {
159 619x u.set_size(id_user, impl().len(id_user) - 2);
160 619x u.set_size(id_pass, impl().len(id_pass));
161 619x u.set_size(id_host, impl().len(id_host));
162 619x u.set_size(id_port, impl().len(id_port));
163 }
164 else
165 {
166 2x u.set_size(id_user, impl().len(id_user));
167 2x BOOST_ASSERT(impl().len(id_pass) == 0);
168 2x BOOST_ASSERT(impl().len(id_host) == 0);
169 2x BOOST_ASSERT(impl().len(id_port) == 0);
170 }
171 621x u.decoded_[id_user] = impl().decoded_[id_user];
172 621x u.decoded_[id_pass] = impl().decoded_[id_pass];
173 621x u.decoded_[id_host] = impl().decoded_[id_host];
174 detail::memcpy(
175 u.ip_addr_,
176 621x impl().ip_addr_,
177 16);
178 621x u.port_number_ = impl().port_number_;
179 621x u.host_type_ = impl().host_type_;
180 621x return authority_view(u);
181 }
182
183 inline
184 pct_string_view
185 842x url_view_base::
186 encoded_authority() const noexcept
187 {
188 842x auto s = impl().get(id_user, id_path);
189 842x if(! s.empty())
190 {
191 798x BOOST_ASSERT(has_authority());
192 798x s.remove_prefix(2);
193 }
194 // [ user [ ":" pass ] "@" ] host [ ":" port ]
195 842x return make_pct_string_view_unsafe(
196 s.data(),
197 s.size(),
198 842x impl().decoded_[id_user] +
199 842x has_password() +
200 842x impl().decoded_[id_pass] +
201 842x has_userinfo() +
202 842x impl().decoded_[id_host] +
203 1684x impl().len(id_port));
204 }
205
206 //------------------------------------------------
207 //
208 // Userinfo
209 //
210 //------------------------------------------------
211
212 inline
213 bool
214 1106x url_view_base::
215 has_userinfo() const noexcept
216 {
217 1106x auto n = impl().len(id_pass);
218 1106x if(n == 0)
219 763x return false;
220 343x BOOST_ASSERT(has_authority());
221 343x BOOST_ASSERT(impl().get(
222 id_pass).ends_with('@'));
223 343x return true;
224 }
225
226 inline
227 bool
228 989x url_view_base::
229 has_password() const noexcept
230 {
231 989x auto const n = impl().len(id_pass);
232 989x if(n > 1)
233 {
234 153x BOOST_ASSERT(impl().get(id_pass
235 ).starts_with(':'));
236 153x BOOST_ASSERT(impl().get(id_pass
237 ).ends_with('@'));
238 153x return true;
239 }
240 836x BOOST_ASSERT(n == 0 || impl().get(
241 id_pass).ends_with('@'));
242 836x return false;
243 }
244
245 inline
246 pct_string_view
247 128x url_view_base::
248 encoded_userinfo() const noexcept
249 {
250 128x auto s = impl().get(
251 id_user, id_host);
252 128x if(s.empty())
253 8x return s;
254 120x BOOST_ASSERT(
255 has_authority());
256 120x s.remove_prefix(2);
257 120x if(s.empty())
258 34x return s;
259 86x BOOST_ASSERT(
260 s.ends_with('@'));
261 86x s.remove_suffix(1);
262 86x return make_pct_string_view_unsafe(
263 s.data(),
264 s.size(),
265 86x impl().decoded_[id_user] +
266 86x impl().decoded_[id_pass] +
267 172x has_password());
268 }
269
270 inline
271 pct_string_view
272 150x url_view_base::
273 encoded_user() const noexcept
274 {
275 150x auto s = impl().get(id_user);
276 150x if(! s.empty())
277 {
278 148x BOOST_ASSERT(
279 has_authority());
280 148x s.remove_prefix(2);
281 }
282 150x return make_pct_string_view_unsafe(
283 s.data(),
284 s.size(),
285 300x impl().decoded_[id_user]);
286 }
287
288 inline
289 pct_string_view
290 108x url_view_base::
291 encoded_password() const noexcept
292 {
293 108x auto s = impl().get(id_pass);
294 108x switch(s.size())
295 {
296 24x case 1:
297 24x BOOST_ASSERT(
298 s.starts_with('@'));
299 24x s.remove_prefix(1);
300 BOOST_FALLTHROUGH;
301 43x case 0:
302 43x return make_pct_string_view_unsafe(
303 43x s.data(), s.size(), 0);
304 65x default:
305 65x break;
306 }
307 65x BOOST_ASSERT(s.ends_with('@'));
308 65x BOOST_ASSERT(s.starts_with(':'));
309 65x return make_pct_string_view_unsafe(
310 65x s.data() + 1,
311 65x s.size() - 2,
312 130x impl().decoded_[id_pass]);
313 }
314
315 //------------------------------------------------
316 //
317 // Host
318 //
319 //------------------------------------------------
320 /*
321 host_type host_type() // ipv4, ipv6, ipvfuture, name
322
323 std::string host() // return encoded_host().decode()
324 pct_string_view encoded_host() // return host part, as-is
325 std::string host_address() // return encoded_host_address().decode()
326 pct_string_view encoded_host_address() // ipv4, ipv6, ipvfut, or encoded name, no brackets
327
328 ipv4_address host_ipv4_address() // return ipv4_address or {}
329 ipv6_address host_ipv6_address() // return ipv6_address or {}
330 core::string_view host_ipvfuture() // return ipvfuture or {}
331 std::string host_name() // return decoded name or ""
332 pct_string_view encoded_host_name() // return encoded host name or ""
333 */
334
335 inline
336 pct_string_view
337 631x url_view_base::
338 encoded_host() const noexcept
339 {
340 631x return impl().pct_get(id_host);
341 }
342
343 inline
344 pct_string_view
345 142x url_view_base::
346 encoded_host_address() const noexcept
347 {
348 142x core::string_view s = impl().get(id_host);
349 std::size_t n;
350 142x switch(impl().host_type_)
351 {
352 42x default:
353 case urls::host_type::none:
354 42x BOOST_ASSERT(s.empty());
355 42x n = 0;
356 42x break;
357
358 53x case urls::host_type::name:
359 case urls::host_type::ipv4:
360 53x n = impl().decoded_[id_host];
361 53x break;
362
363 47x case urls::host_type::ipv6:
364 case urls::host_type::ipvfuture:
365 {
366 47x BOOST_ASSERT(s.size() >= 2);
367 47x BOOST_ASSERT(s.front() == '[');
368 47x BOOST_ASSERT(s.back() == ']');
369 47x s = s.substr(1, s.size() - 2);
370 47x n = impl().decoded_[id_host] - 2;
371 47x break;
372 }
373 }
374 142x return make_pct_string_view_unsafe(
375 s.data(),
376 s.size(),
377 142x n);
378 }
379
380 inline
381 urls::ipv4_address
382 53x url_view_base::
383 host_ipv4_address() const noexcept
384 {
385 53x if(impl().host_type_ !=
386 urls::host_type::ipv4)
387 35x return {};
388 18x ipv4_address::bytes_type b{{}};
389 36x std::memcpy(
390 18x &b[0], &impl().ip_addr_[0], b.size());
391 18x return urls::ipv4_address(b);
392 }
393
394 inline
395 urls::ipv6_address
396 66x url_view_base::
397 host_ipv6_address() const noexcept
398 {
399 66x if(impl().host_type_ !=
400 urls::host_type::ipv6)
401 45x return {};
402 21x ipv6_address::bytes_type b{{}};
403 42x std::memcpy(
404 21x &b[0], &impl().ip_addr_[0], b.size());
405 21x return {b};
406 }
407
408 inline
409 core::string_view
410 51x url_view_base::
411 host_ipvfuture() const noexcept
412 {
413 51x if(impl().host_type_ !=
414 urls::host_type::ipvfuture)
415 44x return {};
416 7x core::string_view s = impl().get(id_host);
417 7x BOOST_ASSERT(s.size() >= 6);
418 7x BOOST_ASSERT(s.front() == '[');
419 7x BOOST_ASSERT(s.back() == ']');
420 7x s = s.substr(1, s.size() - 2);
421 7x return s;
422 }
423
424 inline
425 pct_string_view
426 146x url_view_base::
427 encoded_host_name() const noexcept
428 {
429 146x if(impl().host_type_ !=
430 urls::host_type::name)
431 78x return {};
432 68x core::string_view s = impl().get(id_host);
433 68x return make_pct_string_view_unsafe(
434 s.data(),
435 s.size(),
436 136x impl().decoded_[id_host]);
437 }
438
439 inline
440 pct_string_view
441 28x url_view_base::
442 encoded_zone_id() const noexcept
443 {
444 28x if(impl().host_type_ !=
445 urls::host_type::ipv6)
446 6x return {};
447 22x core::string_view s = impl().get(id_host);
448 22x BOOST_ASSERT(s.front() == '[');
449 22x BOOST_ASSERT(s.back() == ']');
450 22x s = s.substr(1, s.size() - 2);
451 22x auto pos = s.find("%25");
452 22x if (pos == core::string_view::npos)
453 2x return {};
454 20x s.remove_prefix(pos + 3);
455 20x return *make_pct_string_view(s);
456 }
457
458 //------------------------------------------------
459
460 inline
461 bool
462 389x url_view_base::
463 has_port() const noexcept
464 {
465 389x auto const n = impl().len(id_port);
466 389x if(n == 0)
467 89x return false;
468 300x BOOST_ASSERT(
469 impl().get(id_port).starts_with(':'));
470 300x return true;
471 }
472
473 inline
474 core::string_view
475 193x url_view_base::
476 port() const noexcept
477 {
478 193x auto s = impl().get(id_port);
479 193x if(s.empty())
480 58x return s;
481 135x BOOST_ASSERT(has_port());
482 135x return s.substr(1);
483 }
484
485 inline
486 std::uint16_t
487 108x url_view_base::
488 port_number() const noexcept
489 {
490 108x BOOST_ASSERT(
491 has_port() ||
492 impl().port_number_ == 0);
493 108x return impl().port_number_;
494 }
495
496 //------------------------------------------------
497 //
498 // Path
499 //
500 //------------------------------------------------
501
502 inline
503 pct_string_view
504 2458x url_view_base::
505 encoded_path() const noexcept
506 {
507 2458x return impl().pct_get(id_path);
508 }
509
510 inline
511 segments_view
512 5785x url_view_base::
513 segments() const noexcept
514 {
515 5785x return {detail::path_ref(impl())};
516 }
517
518 inline
519 segments_encoded_view
520 895x url_view_base::
521 encoded_segments() const noexcept
522 {
523 return segments_encoded_view(
524 895x detail::path_ref(impl()));
525 }
526
527 //------------------------------------------------
528 //
529 // Query
530 //
531 //------------------------------------------------
532
533 inline
534 bool
535 1172x url_view_base::
536 has_query() const noexcept
537 {
538 1172x auto const n = impl().len(
539 id_query);
540 1172x if(n == 0)
541 813x return false;
542 359x BOOST_ASSERT(
543 impl().get(id_query).
544 starts_with('?'));
545 359x return true;
546 }
547
548 inline
549 pct_string_view
550 445x url_view_base::
551 encoded_query() const noexcept
552 {
553 445x auto s = impl().get(id_query);
554 445x if(s.empty())
555 16x return s;
556 429x BOOST_ASSERT(
557 s.starts_with('?'));
558 429x return s.substr(1);
559 }
560
561 inline
562 params_encoded_view
563 72x url_view_base::
564 encoded_params() const noexcept
565 {
566 72x return params_encoded_view(impl());
567 }
568
569 inline
570 params_view
571 5803x url_view_base::
572 params() const noexcept
573 {
574 return params_view(
575 impl(),
576 encoding_opts{
577 5803x true,false,false});
578 }
579
580 inline
581 params_view
582 url_view_base::
583 params(encoding_opts opt) const noexcept
584 {
585 return params_view(impl(), opt);
586 }
587
588 //------------------------------------------------
589 //
590 // Fragment
591 //
592 //------------------------------------------------
593
594 inline
595 bool
596 971x url_view_base::
597 has_fragment() const noexcept
598 {
599 971x auto const n = impl().len(id_frag);
600 971x if(n == 0)
601 812x return false;
602 159x BOOST_ASSERT(
603 impl().get(id_frag).
604 starts_with('#'));
605 159x return true;
606 }
607
608 inline
609 pct_string_view
610 198x url_view_base::
611 encoded_fragment() const noexcept
612 {
613 198x auto s = impl().get(id_frag);
614 198x if(! s.empty())
615 {
616 190x BOOST_ASSERT(
617 s.starts_with('#'));
618 190x s.remove_prefix(1);
619 }
620 198x return make_pct_string_view_unsafe(
621 s.data(),
622 s.size(),
623 396x impl().decoded_[id_frag]);
624 }
625
626 //------------------------------------------------
627 //
628 // Compound Fields
629 //
630 //------------------------------------------------
631
632 inline
633 pct_string_view
634 120x url_view_base::
635 encoded_host_and_port() const noexcept
636 {
637 120x return impl().pct_get(id_host, id_path);
638 }
639
640 inline
641 pct_string_view
642 16x url_view_base::
643 encoded_origin() const noexcept
644 {
645 16x if(impl().len(id_user) < 2)
646 14x return {};
647 2x return impl().get(id_scheme, id_path);
648 }
649
650 inline
651 pct_string_view
652 98x url_view_base::
653 encoded_resource() const noexcept
654 {
655 auto n =
656 98x impl().decoded_[id_path] +
657 98x impl().decoded_[id_query] +
658 98x impl().decoded_[id_frag];
659 98x if(has_query())
660 92x ++n;
661 98x if(has_fragment())
662 1x ++n;
663 98x BOOST_ASSERT(pct_string_view(
664 impl().get(id_path, id_end)
665 ).decoded_size() == n);
666 98x auto s = impl().get(id_path, id_end);
667 98x return make_pct_string_view_unsafe(
668 98x s.data(), s.size(), n);
669 }
670
671 inline
672 pct_string_view
673 105x url_view_base::
674 encoded_target() const noexcept
675 {
676 auto n =
677 105x impl().decoded_[id_path] +
678 105x impl().decoded_[id_query];
679 105x if(has_query())
680 98x ++n;
681 105x BOOST_ASSERT(pct_string_view(
682 impl().get(id_path, id_frag)
683 ).decoded_size() == n);
684 105x auto s = impl().get(id_path, id_frag);
685 105x return make_pct_string_view_unsafe(
686 105x s.data(), s.size(), n);
687 }
688
689 //------------------------------------------------
690 //
691 // Comparisons
692 //
693 //------------------------------------------------
694
695 inline
696 int
697 348x url_view_base::
698 compare(const url_view_base& other) const noexcept
699 {
700 int comp =
701 348x static_cast<int>(has_scheme()) -
702 348x static_cast<int>(other.has_scheme());
703 348x if ( comp != 0 )
704 ✗ return comp;
705
706 348x if (has_scheme())
707 {
708 223x comp = detail::ci_compare(
709 scheme(),
710 other.scheme());
711 223x if ( comp != 0 )
712 15x return comp;
713 }
714
715 333x comp =
716 333x static_cast<int>(has_authority()) -
717 333x static_cast<int>(other.has_authority());
718 333x if ( comp != 0 )
719 ✗ return comp;
720
721 333x if (has_authority())
722 {
723 206x comp = authority().compare(other.authority());
724 206x if ( comp != 0 )
725 91x return comp;
726 }
727
728 242x comp = detail::segments_compare(
729 encoded_segments(),
730 other.encoded_segments());
731 242x if ( comp != 0 )
732 54x return comp;
733
734 188x comp =
735 188x static_cast<int>(has_query()) -
736 188x static_cast<int>(other.has_query());
737 188x if ( comp != 0 )
738 ✗ return comp;
739
740 188x if (has_query())
741 {
742 56x comp = detail::compare_encoded_query(
743 28x encoded_query(),
744 28x other.encoded_query());
745 28x if ( comp != 0 )
746 19x return comp;
747 }
748
749 169x comp =
750 169x static_cast<int>(has_fragment()) -
751 169x static_cast<int>(other.has_fragment());
752 169x if ( comp != 0 )
753 ✗ return comp;
754
755 169x if (has_fragment())
756 {
757 52x comp = detail::compare_encoded(
758 26x encoded_fragment(),
759 26x other.encoded_fragment());
760 26x if ( comp != 0 )
761 21x return comp;
762 }
763
764 148x return 0;
765 }
766
767 } // urls
768 } // boost
769
770 #endif
771