include/boost/url/impl/authority_view.hpp

100.0% Lines (149/153) 100.0% Functions (18/18)
include/boost/url/impl/authority_view.hpp
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2023 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_AUTHORITY_VIEW_HPP
12 #define BOOST_URL_IMPL_AUTHORITY_VIEW_HPP
13
14 #include <boost/url/detail/config.hpp>
15 #include <boost/url/detail/memcpy.hpp>
16 #include <boost/url/grammar/parse.hpp>
17 #include <boost/url/rfc/authority_rule.hpp>
18
19 namespace boost {
20 namespace urls {
21
22 //------------------------------------------------
23
24 namespace detail {
25
26 // Forward declarations for normalize functions
27 // defined in src/detail/normalize.cpp
28 BOOST_URL_DECL
29 int
30 compare_encoded(
31 core::string_view lhs,
32 core::string_view rhs) noexcept;
33
34 BOOST_URL_DECL
35 int
36 ci_compare_encoded(
37 core::string_view lhs,
38 core::string_view rhs) noexcept;
39
40 BOOST_URL_DECL
41 int
42 compare(
43 core::string_view lhs,
44 core::string_view rhs) noexcept;
45
46 } // detail
47
48 //------------------------------------------------
49 //
50 // Special Members
51 //
52 //------------------------------------------------
53
54 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
55 2 authority_view::
56 authority_view(
57 2 core::string_view s)
58 : authority_view(
59 2 parse_authority(s
60 2 ).value(BOOST_URL_POS))
61 {
62 2 }
63
64 //------------------------------------------------
65 //
66 // Userinfo
67 //
68 //------------------------------------------------
69
70 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
71 bool
72 593 authority_view::
73 has_userinfo() const noexcept
74 {
75 593 auto n = u_.len(id_pass);
76 593 if(n == 0)
77 501 return false;
78 92 BOOST_ASSERT(u_.get(
79 id_pass).ends_with('@'));
80 92 return true;
81 }
82
83 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
84 pct_string_view
85 53 authority_view::
86 encoded_userinfo() const noexcept
87 {
88 53 auto s = u_.get(
89 id_user, id_host);
90 53 if(s.empty())
91 2 return s;
92 51 BOOST_ASSERT(
93 s.ends_with('@'));
94 51 s.remove_suffix(1);
95 51 return make_pct_string_view_unsafe(
96 s.data(),
97 s.size(),
98 51 u_.decoded_[id_user] +
99 102 u_.decoded_[id_pass] +
100 102 has_password());
101 }
102
103 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
104 pct_string_view
105 74 authority_view::
106 encoded_user() const noexcept
107 {
108 74 auto s = u_.get(id_user);
109 74 return make_pct_string_view_unsafe(
110 s.data(),
111 s.size(),
112 148 u_.decoded_[id_user]);
113 }
114
115 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
116 bool
117 113 authority_view::
118 has_password() const noexcept
119 {
120 113 auto const n = u_.len(id_pass);
121 113 if(n > 1)
122 {
123 80 BOOST_ASSERT(u_.get(id_pass
124 ).starts_with(':'));
125 80 BOOST_ASSERT(u_.get(id_pass
126 ).ends_with('@'));
127 80 return true;
128 }
129 33 BOOST_ASSERT(n == 0 || u_.get(
130 id_pass).ends_with('@'));
131 33 return false;
132 }
133
134 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
135 pct_string_view
136 58 authority_view::
137 encoded_password() const noexcept
138 {
139 58 auto s = u_.get(id_pass);
140 58 switch(s.size())
141 {
142 8 case 1:
143 8 BOOST_ASSERT(
144 s.starts_with('@'));
145 8 s.remove_prefix(1);
146 BOOST_FALLTHROUGH;
147 8 case 0:
148 8 return make_pct_string_view_unsafe(
149 8 s.data(), s.size(), 0);
150 50 default:
151 50 break;
152 }
153 50 BOOST_ASSERT(s.ends_with('@'));
154 50 BOOST_ASSERT(s.starts_with(':'));
155 50 return make_pct_string_view_unsafe(
156 50 s.data() + 1,
157 50 s.size() - 2,
158 100 u_.decoded_[id_pass]);
159 }
160
161 //------------------------------------------------
162 //
163 // Host
164 //
165 //------------------------------------------------
166 /*
167 host_type host_type() // ipv4, ipv6, ipvfuture, name
168
169 std::string host() // return encoded_host().decode()
170 pct_string_view encoded_host() // return host part, as-is
171 std::string host_address() // return encoded_host_address().decode()
172 pct_string_view encoded_host_address() // ipv4, ipv6, ipvfut, or encoded name, no brackets
173
174 ipv4_address host_ipv4_address() // return ipv4_address or {}
175 ipv6_address host_ipv6_address() // return ipv6_address or {}
176 core::string_view host_ipvfuture() // return ipvfuture or {}
177 std::string host_name() // return decoded name or ""
178 pct_string_view encoded_host_name() // return encoded host name or ""
179 */
180
181 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
182 pct_string_view
183 349 authority_view::
184 encoded_host() const noexcept
185 {
186 349 return u_.pct_get(id_host);
187 }
188
189 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
190 pct_string_view
191 7 authority_view::
192 encoded_host_address() const noexcept
193 {
194 7 core::string_view s = u_.get(id_host);
195 std::size_t n;
196 7 switch(u_.host_type_)
197 {
198 5 case urls::host_type::name:
199 case urls::host_type::ipv4:
200 5 n = u_.decoded_[id_host];
201 5 break;
202
203 2 case urls::host_type::ipv6:
204 case urls::host_type::ipvfuture:
205 {
206 2 BOOST_ASSERT(
207 u_.decoded_[id_host] ==
208 s.size());
209 2 BOOST_ASSERT(s.size() >= 2);
210 2 BOOST_ASSERT(s.front() == '[');
211 2 BOOST_ASSERT(s.back() == ']');
212 2 s = s.substr(1, s.size() - 2);
213 2 n = u_.decoded_[id_host] - 2;
214 2 break;
215 }
216 // LCOV_EXCL_START
217 default:
218 case urls::host_type::none:
219 /*
220 * This condition is for correctness
221 * only.
222 * This should never happen, because
223 * the `host_rule` will set the host
224 * type to `name` when it's empty.
225 * This is correct because `reg-name`
226 * accepts empty strings.
227 */
228 BOOST_ASSERT(s.empty());
229 n = 0;
230 break;
231 // LCOV_EXCL_STOP
232 }
233 7 return make_pct_string_view_unsafe(
234 7 s.data(), s.size(), n);
235 }
236
237 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
238 ipv4_address
239 2 authority_view::
240 host_ipv4_address() const noexcept
241 {
242 2 if(u_.host_type_ !=
243 urls::host_type::ipv4)
244 1 return {};
245 1 ipv4_address::bytes_type b{{}};
246 1 detail::memcpy(
247 1 &b[0], &u_.ip_addr_[0], b.size());
248 1 return urls::ipv4_address(b);
249 }
250
251 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
252 ipv6_address
253 2 authority_view::
254 host_ipv6_address() const noexcept
255 {
256 2 if(u_.host_type_ !=
257 urls::host_type::ipv6)
258 1 return {};
259 1 ipv6_address::bytes_type b{{}};
260 1 detail::memcpy(
261 1 &b[0], &u_.ip_addr_[0], b.size());
262 1 return urls::ipv6_address(b);
263 }
264
265 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
266 core::string_view
267 2 authority_view::
268 host_ipvfuture() const noexcept
269 {
270 2 if(u_.host_type_ !=
271 urls::host_type::ipvfuture)
272 1 return {};
273 1 core::string_view s = u_.get(id_host);
274 1 BOOST_ASSERT(s.size() >= 6);
275 1 BOOST_ASSERT(s.front() == '[');
276 1 BOOST_ASSERT(s.back() == ']');
277 1 s = s.substr(1, s.size() - 2);
278 1 return s;
279 }
280
281 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
282 pct_string_view
283 3 authority_view::
284 encoded_host_name() const noexcept
285 {
286 3 if(u_.host_type_ !=
287 urls::host_type::name)
288 1 return {};
289 2 return u_.pct_get(id_host);
290 }
291
292 //------------------------------------------------
293 //
294 // Port
295 //
296 //------------------------------------------------
297
298 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
299 bool
300 593 authority_view::
301 has_port() const noexcept
302 {
303 593 auto const n = u_.len(id_port);
304 593 if(n == 0)
305 306 return false;
306 287 BOOST_ASSERT(
307 u_.get(id_port).starts_with(':'));
308 287 return true;
309 }
310
311 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
312 core::string_view
313 114 authority_view::
314 port() const noexcept
315 {
316 114 auto s = u_.get(id_port);
317 114 if(s.empty())
318 4 return s;
319 110 BOOST_ASSERT(has_port());
320 110 return s.substr(1);
321 }
322
323 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
324 std::uint16_t
325 20 authority_view::
326 port_number() const noexcept
327 {
328 20 BOOST_ASSERT(
329 has_port() ||
330 u_.port_number_ == 0);
331 20 return u_.port_number_;
332 }
333
334 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
335 pct_string_view
336 10 authority_view::
337 encoded_host_and_port() const noexcept
338 {
339 10 return u_.pct_get(id_host, id_end);
340 }
341
342 //------------------------------------------------
343 //
344 // Comparisons
345 //
346 //------------------------------------------------
347
348 inline
349 int
350 190 authority_view::
351 compare(const authority_view& other) const noexcept
352 {
353 190 auto comp = static_cast<int>(has_userinfo()) -
354 190 static_cast<int>(other.has_userinfo());
355 190 if ( comp != 0 )
356 1 return comp;
357
358 189 if (has_userinfo())
359 {
360 46 comp = detail::compare_encoded(
361 23 encoded_user(),
362 23 other.encoded_user());
363 23 if ( comp != 0 )
364 7 return comp;
365
366 16 comp = static_cast<int>(has_password()) -
367 16 static_cast<int>(other.has_password());
368 16 if ( comp != 0 )
369 1 return comp;
370
371 15 if (has_password())
372 {
373 30 comp = detail::compare_encoded(
374 15 encoded_password(),
375 15 other.encoded_password());
376 15 if ( comp != 0 )
377 14 return comp;
378 }
379 }
380
381 334 comp = detail::ci_compare_encoded(
382 167 encoded_host(),
383 167 other.encoded_host());
384 167 if ( comp != 0 )
385 17 return comp;
386
387 150 comp = static_cast<int>(has_port()) -
388 150 static_cast<int>(other.has_port());
389 150 if ( comp != 0 )
390 7 return comp;
391
392 143 if (has_port())
393 {
394 46 comp = detail::compare(
395 port(),
396 other.port());
397 46 if ( comp != 0 )
398 42 return comp;
399 }
400
401 101 return 0;
402 }
403
404 //------------------------------------------------
405
406 BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
407 system::result<authority_view>
408 46 parse_authority(
409 core::string_view s) noexcept
410 {
411 46 return grammar::parse(s, authority_rule);
412 }
413
414 } // urls
415 } // boost
416
417 #endif
418