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