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 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
|