TLA Line data 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 HIT 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 641 : authority_view::
73 : has_userinfo() const noexcept
74 : {
75 641 : auto n = u_.len(id_pass);
76 641 : if(n == 0)
77 549 : 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 75 : authority_view::
106 : encoded_user() const noexcept
107 : {
108 75 : auto s = u_.get(id_user);
109 75 : return make_pct_string_view_unsafe(
110 : s.data(),
111 : s.size(),
112 150 : 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 59 : authority_view::
137 : encoded_password() const noexcept
138 : {
139 59 : auto s = u_.get(id_pass);
140 59 : 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 51 : default:
151 51 : break;
152 : }
153 51 : BOOST_ASSERT(s.ends_with('@'));
154 51 : BOOST_ASSERT(s.starts_with(':'));
155 51 : return make_pct_string_view_unsafe(
156 51 : s.data() + 1,
157 51 : s.size() - 2,
158 102 : 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 409 : authority_view::
184 : encoded_host() const noexcept
185 : {
186 409 : return u_.pct_get(id_host);
187 : }
188 :
189 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
190 : pct_string_view
191 34 : authority_view::
192 : encoded_host_address() const noexcept
193 : {
194 34 : core::string_view s = u_.get(id_host);
195 : std::size_t n;
196 34 : 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 29 : case urls::host_type::ipv6:
204 : case urls::host_type::ipvfuture:
205 : {
206 29 : BOOST_ASSERT(s.size() >= 2);
207 29 : BOOST_ASSERT(s.front() == '[');
208 29 : BOOST_ASSERT(s.back() == ']');
209 29 : s = s.substr(1, s.size() - 2);
210 29 : n = u_.decoded_[id_host] - 2;
211 29 : break;
212 : }
213 : // LCOV_EXCL_START
214 : default:
215 : case urls::host_type::none:
216 : /*
217 : * This condition is for correctness
218 : * only.
219 : * This should never happen, because
220 : * the `host_rule` will set the host
221 : * type to `name` when it's empty.
222 : * This is correct because `reg-name`
223 : * accepts empty strings.
224 : */
225 : BOOST_ASSERT(s.empty());
226 : n = 0;
227 : break;
228 : // LCOV_EXCL_STOP
229 : }
230 34 : return make_pct_string_view_unsafe(
231 34 : s.data(), s.size(), n);
232 : }
233 :
234 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
235 : ipv4_address
236 2 : authority_view::
237 : host_ipv4_address() const noexcept
238 : {
239 2 : if(u_.host_type_ !=
240 : urls::host_type::ipv4)
241 1 : return {};
242 1 : ipv4_address::bytes_type b{{}};
243 1 : detail::memcpy(
244 1 : &b[0], &u_.ip_addr_[0], b.size());
245 1 : return urls::ipv4_address(b);
246 : }
247 :
248 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
249 : ipv6_address
250 2 : authority_view::
251 : host_ipv6_address() const noexcept
252 : {
253 2 : if(u_.host_type_ !=
254 : urls::host_type::ipv6)
255 1 : return {};
256 1 : ipv6_address::bytes_type b{{}};
257 1 : detail::memcpy(
258 1 : &b[0], &u_.ip_addr_[0], b.size());
259 1 : return urls::ipv6_address(b);
260 : }
261 :
262 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
263 : core::string_view
264 2 : authority_view::
265 : host_ipvfuture() const noexcept
266 : {
267 2 : if(u_.host_type_ !=
268 : urls::host_type::ipvfuture)
269 1 : return {};
270 1 : core::string_view s = u_.get(id_host);
271 1 : BOOST_ASSERT(s.size() >= 6);
272 1 : BOOST_ASSERT(s.front() == '[');
273 1 : BOOST_ASSERT(s.back() == ']');
274 1 : s = s.substr(1, s.size() - 2);
275 1 : return s;
276 : }
277 :
278 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
279 : pct_string_view
280 3 : authority_view::
281 : encoded_host_name() const noexcept
282 : {
283 3 : if(u_.host_type_ !=
284 : urls::host_type::name)
285 1 : return {};
286 2 : return u_.pct_get(id_host);
287 : }
288 :
289 : //------------------------------------------------
290 : //
291 : // Port
292 : //
293 : //------------------------------------------------
294 :
295 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
296 : bool
297 640 : authority_view::
298 : has_port() const noexcept
299 : {
300 640 : auto const n = u_.len(id_port);
301 640 : if(n == 0)
302 348 : return false;
303 292 : BOOST_ASSERT(
304 : u_.get(id_port).starts_with(':'));
305 292 : return true;
306 : }
307 :
308 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
309 : core::string_view
310 115 : authority_view::
311 : port() const noexcept
312 : {
313 115 : auto s = u_.get(id_port);
314 115 : if(s.empty())
315 4 : return s;
316 111 : BOOST_ASSERT(has_port());
317 111 : return s.substr(1);
318 : }
319 :
320 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
321 : std::uint16_t
322 22 : authority_view::
323 : port_number() const noexcept
324 : {
325 22 : BOOST_ASSERT(
326 : has_port() ||
327 : u_.port_number_ == 0);
328 22 : return u_.port_number_;
329 : }
330 :
331 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
332 : pct_string_view
333 10 : authority_view::
334 : encoded_host_and_port() const noexcept
335 : {
336 10 : return u_.pct_get(id_host, id_end);
337 : }
338 :
339 : //------------------------------------------------
340 : //
341 : // Comparisons
342 : //
343 : //------------------------------------------------
344 :
345 : inline
346 : int
347 206 : authority_view::
348 : compare(const authority_view& other) const noexcept
349 : {
350 206 : auto comp = static_cast<int>(has_userinfo()) -
351 206 : static_cast<int>(other.has_userinfo());
352 206 : if ( comp != 0 )
353 1 : return comp;
354 :
355 205 : if (has_userinfo())
356 : {
357 46 : comp = detail::compare_encoded(
358 23 : encoded_user(),
359 23 : other.encoded_user());
360 23 : if ( comp != 0 )
361 7 : return comp;
362 :
363 16 : comp = static_cast<int>(has_password()) -
364 16 : static_cast<int>(other.has_password());
365 16 : if ( comp != 0 )
366 1 : return comp;
367 :
368 15 : if (has_password())
369 : {
370 30 : comp = detail::compare_encoded(
371 15 : encoded_password(),
372 15 : other.encoded_password());
373 15 : if ( comp != 0 )
374 14 : return comp;
375 : }
376 : }
377 :
378 366 : comp = detail::ci_compare_encoded(
379 183 : encoded_host(),
380 183 : other.encoded_host());
381 183 : if ( comp != 0 )
382 19 : return comp;
383 :
384 164 : comp = static_cast<int>(has_port()) -
385 164 : static_cast<int>(other.has_port());
386 164 : if ( comp != 0 )
387 7 : return comp;
388 :
389 157 : if (has_port())
390 : {
391 46 : comp = detail::compare(
392 : port(),
393 : other.port());
394 46 : if ( comp != 0 )
395 42 : return comp;
396 : }
397 :
398 115 : return 0;
399 : }
400 :
401 : //------------------------------------------------
402 :
403 : BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
404 : system::result<authority_view>
405 53 : parse_authority(
406 : core::string_view s) noexcept
407 : {
408 53 : return grammar::parse(s, authority_rule);
409 : }
410 :
411 : } // urls
412 : } // boost
413 :
414 : #endif
|