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 2341 : url_impl::
29 : construct_authority() const noexcept
30 : {
31 2341 : return authority_view(*this);
32 : }
33 :
34 : } // detail
35 :
36 : //------------------------------------------------
37 :
38 2341 : authority_view::
39 : authority_view(
40 2341 : detail::url_impl const& u) noexcept
41 2341 : : u_(u)
42 : {
43 2341 : }
44 :
45 : //------------------------------------------------
46 :
47 11645 : authority_view::
48 11645 : ~authority_view()
49 : {
50 11645 : }
51 :
52 3605 : authority_view::
53 3605 : authority_view() noexcept
54 3605 : : u_(from::authority)
55 : {
56 3605 : }
57 :
58 1 : authority_view::
59 : authority_view(
60 1 : core::string_view s)
61 : : authority_view(
62 1 : parse_authority(s
63 1 : ).value(BOOST_URL_POS))
64 : {
65 1 : }
66 :
67 : authority_view::
68 : authority_view(
69 : authority_view const&) noexcept = default;
70 :
71 : authority_view&
72 : authority_view::
73 : operator=(
74 : authority_view const&) noexcept = default;
75 :
76 : //------------------------------------------------
77 : //
78 : // Userinfo
79 : //
80 : //------------------------------------------------
81 :
82 : bool
83 567 : authority_view::
84 : has_userinfo() const noexcept
85 : {
86 567 : auto n = u_.len(id_pass);
87 567 : if(n == 0)
88 475 : return false;
89 92 : BOOST_ASSERT(u_.get(
90 : id_pass).ends_with('@'));
91 92 : return true;
92 : }
93 :
94 : pct_string_view
95 50 : authority_view::
96 : encoded_userinfo() const noexcept
97 : {
98 : auto s = u_.get(
99 50 : id_user, id_host);
100 50 : if(s.empty())
101 0 : return s;
102 50 : BOOST_ASSERT(
103 : s.ends_with('@'));
104 50 : s.remove_suffix(1);
105 : 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 50 : 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 : return make_pct_string_view_unsafe(
119 : s.data(),
120 : s.size(),
121 73 : 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 : 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 : return make_pct_string_view_unsafe(
163 49 : s.data() + 1,
164 49 : s.size() - 2,
165 49 : 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 0 : authority_view::
197 : encoded_host_address() const noexcept
198 : {
199 0 : core::string_view s = u_.get(id_host);
200 : std::size_t n;
201 0 : switch(u_.host_type_)
202 : {
203 0 : default:
204 : case urls::host_type::none:
205 0 : BOOST_ASSERT(s.empty());
206 0 : n = 0;
207 0 : break;
208 :
209 0 : case urls::host_type::name:
210 : case urls::host_type::ipv4:
211 0 : n = u_.decoded_[id_host];
212 0 : break;
213 :
214 0 : case urls::host_type::ipv6:
215 : case urls::host_type::ipvfuture:
216 : {
217 0 : BOOST_ASSERT(
218 : u_.decoded_[id_host] ==
219 : s.size());
220 0 : BOOST_ASSERT(s.size() >= 2);
221 0 : BOOST_ASSERT(s.front() == '[');
222 0 : BOOST_ASSERT(s.back() == ']');
223 0 : s = s.substr(1, s.size() - 2);
224 0 : n = u_.decoded_[id_host] - 2;
225 0 : break;
226 : }
227 : }
228 : return make_pct_string_view_unsafe(
229 0 : s.data(), s.size(), n);
230 : }
231 :
232 : urls::ipv4_address
233 2 : authority_view::
234 : host_ipv4_address() const noexcept
235 : {
236 2 : if(u_.host_type_ !=
237 : urls::host_type::ipv4)
238 1 : return {};
239 1 : ipv4_address::bytes_type b{{}};
240 1 : std::memcpy(
241 1 : &b[0], &u_.ip_addr_[0], b.size());
242 1 : return urls::ipv4_address(b);
243 : }
244 :
245 : urls::ipv6_address
246 2 : authority_view::
247 : host_ipv6_address() const noexcept
248 : {
249 2 : if(u_.host_type_ !=
250 : urls::host_type::ipv6)
251 1 : return {};
252 1 : ipv6_address::bytes_type b{{}};
253 1 : std::memcpy(
254 1 : &b[0], &u_.ip_addr_[0], b.size());
255 1 : return urls::ipv6_address(b);
256 : }
257 :
258 : core::string_view
259 2 : authority_view::
260 : host_ipvfuture() const noexcept
261 : {
262 2 : if(u_.host_type_ !=
263 : urls::host_type::ipvfuture)
264 1 : return {};
265 1 : core::string_view s = u_.get(id_host);
266 1 : BOOST_ASSERT(s.size() >= 6);
267 1 : BOOST_ASSERT(s.front() == '[');
268 1 : BOOST_ASSERT(s.back() == ']');
269 1 : s = s.substr(1, s.size() - 2);
270 1 : return s;
271 : }
272 :
273 : pct_string_view
274 0 : authority_view::
275 : encoded_host_name() const noexcept
276 : {
277 0 : if(u_.host_type_ !=
278 : urls::host_type::name)
279 0 : return {};
280 0 : return u_.pct_get(id_host);
281 : }
282 :
283 : //------------------------------------------------
284 : //
285 : // Port
286 : //
287 : //------------------------------------------------
288 :
289 : bool
290 567 : authority_view::
291 : has_port() const noexcept
292 : {
293 567 : auto const n = u_.len(id_port);
294 567 : if(n == 0)
295 282 : return false;
296 285 : BOOST_ASSERT(
297 : u_.get(id_port).starts_with(':'));
298 285 : return true;
299 : }
300 :
301 : core::string_view
302 112 : authority_view::
303 : port() const noexcept
304 : {
305 112 : auto s = u_.get(id_port);
306 112 : if(s.empty())
307 4 : return s;
308 108 : BOOST_ASSERT(has_port());
309 108 : return s.substr(1);
310 : }
311 :
312 : std::uint16_t
313 20 : authority_view::
314 : port_number() const noexcept
315 : {
316 20 : BOOST_ASSERT(
317 : has_port() ||
318 : u_.port_number_ == 0);
319 20 : return u_.port_number_;
320 : }
321 :
322 : pct_string_view
323 10 : authority_view::
324 : encoded_host_and_port() const noexcept
325 : {
326 10 : return u_.get(id_host, id_end);
327 : }
328 :
329 : //------------------------------------------------
330 : //
331 : // Parsing
332 : //
333 : //------------------------------------------------
334 :
335 : system::result<authority_view>
336 42 : parse_authority(
337 : core::string_view s) noexcept
338 : {
339 42 : return grammar::parse(s, authority_rule);
340 : }
341 :
342 : //------------------------------------------------
343 : //
344 : // Comparisons
345 : //
346 : //------------------------------------------------
347 :
348 : int
349 182 : authority_view::
350 : compare(const authority_view& other) const noexcept
351 : {
352 182 : auto comp = static_cast<int>(has_userinfo()) -
353 182 : static_cast<int>(other.has_userinfo());
354 182 : if ( comp != 0 )
355 1 : return comp;
356 :
357 181 : if (has_userinfo())
358 : {
359 46 : comp = detail::compare_encoded(
360 23 : encoded_user(),
361 23 : other.encoded_user());
362 23 : if ( comp != 0 )
363 7 : return comp;
364 :
365 16 : comp = static_cast<int>(has_password()) -
366 16 : static_cast<int>(other.has_password());
367 16 : if ( comp != 0 )
368 1 : return comp;
369 :
370 15 : if (has_password())
371 : {
372 30 : comp = detail::compare_encoded(
373 15 : encoded_password(),
374 15 : other.encoded_password());
375 15 : if ( comp != 0 )
376 14 : return comp;
377 : }
378 : }
379 :
380 318 : comp = detail::ci_compare_encoded(
381 159 : encoded_host(),
382 159 : other.encoded_host());
383 159 : if ( comp != 0 )
384 17 : return comp;
385 :
386 142 : comp = static_cast<int>(has_port()) -
387 142 : static_cast<int>(other.has_port());
388 142 : if ( comp != 0 )
389 7 : return comp;
390 :
391 135 : if (has_port())
392 : {
393 46 : comp = detail::compare(
394 : port(),
395 : other.port());
396 46 : if ( comp != 0 )
397 42 : return comp;
398 : }
399 :
400 93 : return 0;
401 : }
402 :
403 : } // urls
404 : } // boost
405 :
|