1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_IMPL_URL_VIEW_BASE_HPP
11  
#ifndef BOOST_URL_IMPL_URL_VIEW_BASE_HPP
12  
#define BOOST_URL_IMPL_URL_VIEW_BASE_HPP
12  
#define BOOST_URL_IMPL_URL_VIEW_BASE_HPP
13  

13  

14  
#include <boost/url/detail/memcpy.hpp>
14  
#include <boost/url/detail/memcpy.hpp>
15  
#include <boost/url/detail/except.hpp>
15  
#include <boost/url/detail/except.hpp>
16  
#include <boost/url/detail/fnv_1a.hpp>
16  
#include <boost/url/detail/fnv_1a.hpp>
17  
#include <boost/assert.hpp>
17  
#include <boost/assert.hpp>
18  
#include <cstring>
18  
#include <cstring>
19  
#include <memory>
19  
#include <memory>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace urls {
22  
namespace urls {
23  

23  

24  
namespace detail {
24  
namespace detail {
25  

25  

26  
// Forward declarations for normalize functions
26  
// Forward declarations for normalize functions
27  
// defined in src/detail/normalize.cpp
27  
// defined in src/detail/normalize.cpp
28  
BOOST_URL_DECL
28  
BOOST_URL_DECL
29  
void
29  
void
30  
ci_digest(
30  
ci_digest(
31  
    core::string_view s,
31  
    core::string_view s,
32  
    fnv_1a& hasher) noexcept;
32  
    fnv_1a& hasher) noexcept;
33  

33  

34  
BOOST_URL_DECL
34  
BOOST_URL_DECL
35  
void
35  
void
36  
digest_encoded(
36  
digest_encoded(
37  
    core::string_view s,
37  
    core::string_view s,
38  
    fnv_1a& hasher) noexcept;
38  
    fnv_1a& hasher) noexcept;
39  

39  

40  
BOOST_URL_DECL
40  
BOOST_URL_DECL
41  
void
41  
void
42  
ci_digest_encoded(
42  
ci_digest_encoded(
43  
    core::string_view s,
43  
    core::string_view s,
44  
    fnv_1a& hasher) noexcept;
44  
    fnv_1a& hasher) noexcept;
45  

45  

46  
BOOST_URL_DECL
46  
BOOST_URL_DECL
47  
void
47  
void
48  
normalized_path_digest(
48  
normalized_path_digest(
49  
    core::string_view str,
49  
    core::string_view str,
50  
    bool remove_unmatched,
50  
    bool remove_unmatched,
51  
    fnv_1a& hasher) noexcept;
51  
    fnv_1a& hasher) noexcept;
52  

52  

53  
BOOST_URL_DECL
53  
BOOST_URL_DECL
54  
int
54  
int
55  
ci_compare(
55  
ci_compare(
56  
    core::string_view lhs,
56  
    core::string_view lhs,
57  
    core::string_view rhs) noexcept;
57  
    core::string_view rhs) noexcept;
58  

58  

59  
BOOST_URL_DECL
59  
BOOST_URL_DECL
60  
int
60  
int
61  
compare_encoded(
61  
compare_encoded(
62  
    core::string_view lhs,
62  
    core::string_view lhs,
63  
    core::string_view rhs) noexcept;
63  
    core::string_view rhs) noexcept;
64  

64  

65  
BOOST_URL_DECL
65  
BOOST_URL_DECL
66  
int
66  
int
67  
compare_encoded_query(
67  
compare_encoded_query(
68  
    core::string_view lhs,
68  
    core::string_view lhs,
69  
    core::string_view rhs) noexcept;
69  
    core::string_view rhs) noexcept;
70  

70  

71  
BOOST_URL_DECL
71  
BOOST_URL_DECL
72  
int
72  
int
73  
segments_compare(
73  
segments_compare(
74  
    segments_encoded_view seg0,
74  
    segments_encoded_view seg0,
75  
    segments_encoded_view seg1) noexcept;
75  
    segments_encoded_view seg1) noexcept;
76  

76  

77  
} // detail
77  
} // detail
78  

78  

79  
//------------------------------------------------
79  
//------------------------------------------------
80  

80  

81  
inline
81  
inline
82  
std::size_t
82  
std::size_t
83  
url_view_base::
83  
url_view_base::
84  
digest(std::size_t salt) const noexcept
84  
digest(std::size_t salt) const noexcept
85  
{
85  
{
86  
    detail::fnv_1a h(salt);
86  
    detail::fnv_1a h(salt);
87  
    detail::ci_digest(impl().get(id_scheme), h);
87  
    detail::ci_digest(impl().get(id_scheme), h);
88  
    detail::digest_encoded(impl().get(id_user), h);
88  
    detail::digest_encoded(impl().get(id_user), h);
89  
    detail::digest_encoded(impl().get(id_pass), h);
89  
    detail::digest_encoded(impl().get(id_pass), h);
90  
    detail::ci_digest_encoded(impl().get(id_host), h);
90  
    detail::ci_digest_encoded(impl().get(id_host), h);
91  
    h.put(impl().get(id_port));
91  
    h.put(impl().get(id_port));
92  
    detail::normalized_path_digest(
92  
    detail::normalized_path_digest(
93  
        impl().get(id_path), is_path_absolute(), h);
93  
        impl().get(id_path), is_path_absolute(), h);
94  
    detail::digest_encoded(impl().get(id_query), h);
94  
    detail::digest_encoded(impl().get(id_query), h);
95  
    detail::digest_encoded(impl().get(id_frag), h);
95  
    detail::digest_encoded(impl().get(id_frag), h);
96  
    return h.digest();
96  
    return h.digest();
97  
}
97  
}
98  

98  

99  
//------------------------------------------------
99  
//------------------------------------------------
100  
//
100  
//
101  
// Scheme
101  
// Scheme
102  
//
102  
//
103  
//------------------------------------------------
103  
//------------------------------------------------
104  

104  

105  
inline
105  
inline
106  
bool
106  
bool
107  
url_view_base::
107  
url_view_base::
108  
has_scheme() const noexcept
108  
has_scheme() const noexcept
109  
{
109  
{
110  
    auto const n = impl().len(
110  
    auto const n = impl().len(
111  
        id_scheme);
111  
        id_scheme);
112  
    if(n == 0)
112  
    if(n == 0)
113  
        return false;
113  
        return false;
114  
    BOOST_ASSERT(n > 1);
114  
    BOOST_ASSERT(n > 1);
115  
    BOOST_ASSERT(
115  
    BOOST_ASSERT(
116  
        impl().get(id_scheme
116  
        impl().get(id_scheme
117  
            ).ends_with(':'));
117  
            ).ends_with(':'));
118  
    return true;
118  
    return true;
119  
}
119  
}
120  

120  

121  
inline
121  
inline
122  
core::string_view
122  
core::string_view
123  
url_view_base::
123  
url_view_base::
124  
scheme() const noexcept
124  
scheme() const noexcept
125  
{
125  
{
126  
    auto s = impl().get(id_scheme);
126  
    auto s = impl().get(id_scheme);
127  
    if(! s.empty())
127  
    if(! s.empty())
128  
    {
128  
    {
129  
        BOOST_ASSERT(s.size() > 1);
129  
        BOOST_ASSERT(s.size() > 1);
130  
        BOOST_ASSERT(s.ends_with(':'));
130  
        BOOST_ASSERT(s.ends_with(':'));
131  
        s.remove_suffix(1);
131  
        s.remove_suffix(1);
132  
    }
132  
    }
133  
    return s;
133  
    return s;
134  
}
134  
}
135  

135  

136  
inline
136  
inline
137  
urls::scheme
137  
urls::scheme
138  
url_view_base::
138  
url_view_base::
139  
scheme_id() const noexcept
139  
scheme_id() const noexcept
140  
{
140  
{
141  
    return impl().scheme_;
141  
    return impl().scheme_;
142  
}
142  
}
143  

143  

144  
//------------------------------------------------
144  
//------------------------------------------------
145  
//
145  
//
146  
// Authority
146  
// Authority
147  
//
147  
//
148  
//------------------------------------------------
148  
//------------------------------------------------
149  

149  

150  
inline
150  
inline
151  
authority_view
151  
authority_view
152  
url_view_base::
152  
url_view_base::
153  
authority() const noexcept
153  
authority() const noexcept
154  
{
154  
{
155  
    detail::url_impl u(from::authority);
155  
    detail::url_impl u(from::authority);
156  
    u.cs_ = encoded_authority().data();
156  
    u.cs_ = encoded_authority().data();
157  
    if(has_authority())
157  
    if(has_authority())
158  
    {
158  
    {
159  
        u.set_size(id_user, impl().len(id_user) - 2);
159  
        u.set_size(id_user, impl().len(id_user) - 2);
160  
        u.set_size(id_pass, impl().len(id_pass));
160  
        u.set_size(id_pass, impl().len(id_pass));
161  
        u.set_size(id_host, impl().len(id_host));
161  
        u.set_size(id_host, impl().len(id_host));
162  
        u.set_size(id_port, impl().len(id_port));
162  
        u.set_size(id_port, impl().len(id_port));
163  
    }
163  
    }
164  
    else
164  
    else
165  
    {
165  
    {
166  
        u.set_size(id_user, impl().len(id_user));
166  
        u.set_size(id_user, impl().len(id_user));
167  
        BOOST_ASSERT(impl().len(id_pass) == 0);
167  
        BOOST_ASSERT(impl().len(id_pass) == 0);
168  
        BOOST_ASSERT(impl().len(id_host) == 0);
168  
        BOOST_ASSERT(impl().len(id_host) == 0);
169  
        BOOST_ASSERT(impl().len(id_port) == 0);
169  
        BOOST_ASSERT(impl().len(id_port) == 0);
170  
    }
170  
    }
171  
    u.decoded_[id_user] = impl().decoded_[id_user];
171  
    u.decoded_[id_user] = impl().decoded_[id_user];
172  
    u.decoded_[id_pass] = impl().decoded_[id_pass];
172  
    u.decoded_[id_pass] = impl().decoded_[id_pass];
173  
    u.decoded_[id_host] = impl().decoded_[id_host];
173  
    u.decoded_[id_host] = impl().decoded_[id_host];
174  
    detail::memcpy(
174  
    detail::memcpy(
175  
        u.ip_addr_,
175  
        u.ip_addr_,
176  
        impl().ip_addr_,
176  
        impl().ip_addr_,
177  
        16);
177  
        16);
178  
    u.port_number_ = impl().port_number_;
178  
    u.port_number_ = impl().port_number_;
179  
    u.host_type_ = impl().host_type_;
179  
    u.host_type_ = impl().host_type_;
180  
    return authority_view(u);
180  
    return authority_view(u);
181  
}
181  
}
182  

182  

183  
inline
183  
inline
184  
pct_string_view
184  
pct_string_view
185  
url_view_base::
185  
url_view_base::
186  
encoded_authority() const noexcept
186  
encoded_authority() const noexcept
187  
{
187  
{
188  
    auto s = impl().get(id_user, id_path);
188  
    auto s = impl().get(id_user, id_path);
189  
    if(! s.empty())
189  
    if(! s.empty())
190  
    {
190  
    {
191  
        BOOST_ASSERT(has_authority());
191  
        BOOST_ASSERT(has_authority());
192  
        s.remove_prefix(2);
192  
        s.remove_prefix(2);
193  
    }
193  
    }
194  
    return make_pct_string_view_unsafe(
194  
    return make_pct_string_view_unsafe(
195  
        s.data(),
195  
        s.data(),
196  
        s.size(),
196  
        s.size(),
197  
        impl().decoded_[id_user] +
197  
        impl().decoded_[id_user] +
198  
            impl().decoded_[id_pass] +
198  
            impl().decoded_[id_pass] +
199  
            impl().decoded_[id_host] +
199  
            impl().decoded_[id_host] +
200  
            impl().decoded_[id_port] +
200  
            impl().decoded_[id_port] +
201  
            has_password());
201  
            has_password());
202  
}
202  
}
203  

203  

204  
//------------------------------------------------
204  
//------------------------------------------------
205  
//
205  
//
206  
// Userinfo
206  
// Userinfo
207  
//
207  
//
208  
//------------------------------------------------
208  
//------------------------------------------------
209  

209  

210  
inline
210  
inline
211  
bool
211  
bool
212  
url_view_base::
212  
url_view_base::
213  
has_userinfo() const noexcept
213  
has_userinfo() const noexcept
214  
{
214  
{
215  
    auto n = impl().len(id_pass);
215  
    auto n = impl().len(id_pass);
216  
    if(n == 0)
216  
    if(n == 0)
217  
        return false;
217  
        return false;
218  
    BOOST_ASSERT(has_authority());
218  
    BOOST_ASSERT(has_authority());
219  
    BOOST_ASSERT(impl().get(
219  
    BOOST_ASSERT(impl().get(
220  
        id_pass).ends_with('@'));
220  
        id_pass).ends_with('@'));
221  
    return true;
221  
    return true;
222  
}
222  
}
223  

223  

224  
inline
224  
inline
225  
bool
225  
bool
226  
url_view_base::
226  
url_view_base::
227  
has_password() const noexcept
227  
has_password() const noexcept
228  
{
228  
{
229  
    auto const n = impl().len(id_pass);
229  
    auto const n = impl().len(id_pass);
230  
    if(n > 1)
230  
    if(n > 1)
231  
    {
231  
    {
232  
        BOOST_ASSERT(impl().get(id_pass
232  
        BOOST_ASSERT(impl().get(id_pass
233  
            ).starts_with(':'));
233  
            ).starts_with(':'));
234  
        BOOST_ASSERT(impl().get(id_pass
234  
        BOOST_ASSERT(impl().get(id_pass
235  
            ).ends_with('@'));
235  
            ).ends_with('@'));
236  
        return true;
236  
        return true;
237  
    }
237  
    }
238  
    BOOST_ASSERT(n == 0 || impl().get(
238  
    BOOST_ASSERT(n == 0 || impl().get(
239  
        id_pass).ends_with('@'));
239  
        id_pass).ends_with('@'));
240  
    return false;
240  
    return false;
241  
}
241  
}
242  

242  

243  
inline
243  
inline
244  
pct_string_view
244  
pct_string_view
245  
url_view_base::
245  
url_view_base::
246  
encoded_userinfo() const noexcept
246  
encoded_userinfo() const noexcept
247  
{
247  
{
248  
    auto s = impl().get(
248  
    auto s = impl().get(
249  
        id_user, id_host);
249  
        id_user, id_host);
250  
    if(s.empty())
250  
    if(s.empty())
251  
        return s;
251  
        return s;
252  
    BOOST_ASSERT(
252  
    BOOST_ASSERT(
253  
        has_authority());
253  
        has_authority());
254  
    s.remove_prefix(2);
254  
    s.remove_prefix(2);
255  
    if(s.empty())
255  
    if(s.empty())
256  
        return s;
256  
        return s;
257  
    BOOST_ASSERT(
257  
    BOOST_ASSERT(
258  
        s.ends_with('@'));
258  
        s.ends_with('@'));
259  
    s.remove_suffix(1);
259  
    s.remove_suffix(1);
260  
    return make_pct_string_view_unsafe(
260  
    return make_pct_string_view_unsafe(
261  
        s.data(),
261  
        s.data(),
262  
        s.size(),
262  
        s.size(),
263  
        impl().decoded_[id_user] +
263  
        impl().decoded_[id_user] +
264  
            impl().decoded_[id_pass] +
264  
            impl().decoded_[id_pass] +
265  
            has_password());
265  
            has_password());
266  
}
266  
}
267  

267  

268  
inline
268  
inline
269  
pct_string_view
269  
pct_string_view
270  
url_view_base::
270  
url_view_base::
271  
encoded_user() const noexcept
271  
encoded_user() const noexcept
272  
{
272  
{
273  
    auto s = impl().get(id_user);
273  
    auto s = impl().get(id_user);
274  
    if(! s.empty())
274  
    if(! s.empty())
275  
    {
275  
    {
276  
        BOOST_ASSERT(
276  
        BOOST_ASSERT(
277  
            has_authority());
277  
            has_authority());
278  
        s.remove_prefix(2);
278  
        s.remove_prefix(2);
279  
    }
279  
    }
280  
    return make_pct_string_view_unsafe(
280  
    return make_pct_string_view_unsafe(
281  
        s.data(),
281  
        s.data(),
282  
        s.size(),
282  
        s.size(),
283  
        impl().decoded_[id_user]);
283  
        impl().decoded_[id_user]);
284  
}
284  
}
285  

285  

286  
inline
286  
inline
287  
pct_string_view
287  
pct_string_view
288  
url_view_base::
288  
url_view_base::
289  
encoded_password() const noexcept
289  
encoded_password() const noexcept
290  
{
290  
{
291  
    auto s = impl().get(id_pass);
291  
    auto s = impl().get(id_pass);
292  
    switch(s.size())
292  
    switch(s.size())
293  
    {
293  
    {
294  
    case 1:
294  
    case 1:
295  
        BOOST_ASSERT(
295  
        BOOST_ASSERT(
296  
            s.starts_with('@'));
296  
            s.starts_with('@'));
297  
        s.remove_prefix(1);
297  
        s.remove_prefix(1);
298  
        BOOST_FALLTHROUGH;
298  
        BOOST_FALLTHROUGH;
299  
    case 0:
299  
    case 0:
300  
        return make_pct_string_view_unsafe(
300  
        return make_pct_string_view_unsafe(
301  
            s.data(), s.size(), 0);
301  
            s.data(), s.size(), 0);
302  
    default:
302  
    default:
303  
        break;
303  
        break;
304  
    }
304  
    }
305  
    BOOST_ASSERT(s.ends_with('@'));
305  
    BOOST_ASSERT(s.ends_with('@'));
306  
    BOOST_ASSERT(s.starts_with(':'));
306  
    BOOST_ASSERT(s.starts_with(':'));
307  
    return make_pct_string_view_unsafe(
307  
    return make_pct_string_view_unsafe(
308  
        s.data() + 1,
308  
        s.data() + 1,
309  
        s.size() - 2,
309  
        s.size() - 2,
310  
        impl().decoded_[id_pass]);
310  
        impl().decoded_[id_pass]);
311  
}
311  
}
312  

312  

313  
//------------------------------------------------
313  
//------------------------------------------------
314  
//
314  
//
315  
// Host
315  
// Host
316  
//
316  
//
317  
//------------------------------------------------
317  
//------------------------------------------------
318  
/*
318  
/*
319  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
319  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
320  

320  

321  
std::string     host()                      // return encoded_host().decode()
321  
std::string     host()                      // return encoded_host().decode()
322  
pct_string_view encoded_host()              // return host part, as-is
322  
pct_string_view encoded_host()              // return host part, as-is
323  
std::string     host_address()              // return encoded_host_address().decode()
323  
std::string     host_address()              // return encoded_host_address().decode()
324  
pct_string_view encoded_host_address()      // ipv4, ipv6, ipvfut, or encoded name, no brackets
324  
pct_string_view encoded_host_address()      // ipv4, ipv6, ipvfut, or encoded name, no brackets
325  

325  

326  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
326  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
327  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
327  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
328  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
328  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
329  
std::string     host_name()                 // return decoded name or ""
329  
std::string     host_name()                 // return decoded name or ""
330  
pct_string_view encoded_host_name()         // return encoded host name or ""
330  
pct_string_view encoded_host_name()         // return encoded host name or ""
331  
*/
331  
*/
332  

332  

333  
inline
333  
inline
334  
pct_string_view
334  
pct_string_view
335  
url_view_base::
335  
url_view_base::
336  
encoded_host() const noexcept
336  
encoded_host() const noexcept
337  
{
337  
{
338  
    return impl().pct_get(id_host);
338  
    return impl().pct_get(id_host);
339  
}
339  
}
340  

340  

341  
inline
341  
inline
342  
pct_string_view
342  
pct_string_view
343  
url_view_base::
343  
url_view_base::
344  
encoded_host_address() const noexcept
344  
encoded_host_address() const noexcept
345  
{
345  
{
346  
    core::string_view s = impl().get(id_host);
346  
    core::string_view s = impl().get(id_host);
347  
    std::size_t n;
347  
    std::size_t n;
348  
    switch(impl().host_type_)
348  
    switch(impl().host_type_)
349  
    {
349  
    {
350  
    default:
350  
    default:
351  
    case urls::host_type::none:
351  
    case urls::host_type::none:
352  
        BOOST_ASSERT(s.empty());
352  
        BOOST_ASSERT(s.empty());
353  
        n = 0;
353  
        n = 0;
354  
        break;
354  
        break;
355  

355  

356  
    case urls::host_type::name:
356  
    case urls::host_type::name:
357  
    case urls::host_type::ipv4:
357  
    case urls::host_type::ipv4:
358  
        n = impl().decoded_[id_host];
358  
        n = impl().decoded_[id_host];
359  
        break;
359  
        break;
360  

360  

361  
    case urls::host_type::ipv6:
361  
    case urls::host_type::ipv6:
362  
    case urls::host_type::ipvfuture:
362  
    case urls::host_type::ipvfuture:
363  
    {
363  
    {
364  
        BOOST_ASSERT(
364  
        BOOST_ASSERT(
365  
            impl().decoded_[id_host] ==
365  
            impl().decoded_[id_host] ==
366  
                s.size() ||
366  
                s.size() ||
367  
            !this->encoded_zone_id().empty());
367  
            !this->encoded_zone_id().empty());
368  
        BOOST_ASSERT(s.size() >= 2);
368  
        BOOST_ASSERT(s.size() >= 2);
369  
        BOOST_ASSERT(s.front() == '[');
369  
        BOOST_ASSERT(s.front() == '[');
370  
        BOOST_ASSERT(s.back() == ']');
370  
        BOOST_ASSERT(s.back() == ']');
371  
        s = s.substr(1, s.size() - 2);
371  
        s = s.substr(1, s.size() - 2);
372  
        n = impl().decoded_[id_host] - 2;
372  
        n = impl().decoded_[id_host] - 2;
373  
        break;
373  
        break;
374  
    }
374  
    }
375  
    }
375  
    }
376  
    return make_pct_string_view_unsafe(
376  
    return make_pct_string_view_unsafe(
377  
        s.data(),
377  
        s.data(),
378  
        s.size(),
378  
        s.size(),
379  
        n);
379  
        n);
380  
}
380  
}
381  

381  

382  
inline
382  
inline
383  
urls::ipv4_address
383  
urls::ipv4_address
384  
url_view_base::
384  
url_view_base::
385  
host_ipv4_address() const noexcept
385  
host_ipv4_address() const noexcept
386  
{
386  
{
387  
    if(impl().host_type_ !=
387  
    if(impl().host_type_ !=
388  
            urls::host_type::ipv4)
388  
            urls::host_type::ipv4)
389  
        return {};
389  
        return {};
390  
    ipv4_address::bytes_type b{{}};
390  
    ipv4_address::bytes_type b{{}};
391  
    std::memcpy(
391  
    std::memcpy(
392  
        &b[0], &impl().ip_addr_[0], b.size());
392  
        &b[0], &impl().ip_addr_[0], b.size());
393  
    return urls::ipv4_address(b);
393  
    return urls::ipv4_address(b);
394  
}
394  
}
395  

395  

396  
inline
396  
inline
397  
urls::ipv6_address
397  
urls::ipv6_address
398  
url_view_base::
398  
url_view_base::
399  
host_ipv6_address() const noexcept
399  
host_ipv6_address() const noexcept
400  
{
400  
{
401  
    if(impl().host_type_ !=
401  
    if(impl().host_type_ !=
402  
            urls::host_type::ipv6)
402  
            urls::host_type::ipv6)
403  
        return {};
403  
        return {};
404  
    ipv6_address::bytes_type b{{}};
404  
    ipv6_address::bytes_type b{{}};
405  
    std::memcpy(
405  
    std::memcpy(
406  
        &b[0], &impl().ip_addr_[0], b.size());
406  
        &b[0], &impl().ip_addr_[0], b.size());
407  
    return {b};
407  
    return {b};
408  
}
408  
}
409  

409  

410  
inline
410  
inline
411  
core::string_view
411  
core::string_view
412  
url_view_base::
412  
url_view_base::
413  
host_ipvfuture() const noexcept
413  
host_ipvfuture() const noexcept
414  
{
414  
{
415  
    if(impl().host_type_ !=
415  
    if(impl().host_type_ !=
416  
            urls::host_type::ipvfuture)
416  
            urls::host_type::ipvfuture)
417  
        return {};
417  
        return {};
418  
    core::string_view s = impl().get(id_host);
418  
    core::string_view s = impl().get(id_host);
419  
    BOOST_ASSERT(s.size() >= 6);
419  
    BOOST_ASSERT(s.size() >= 6);
420  
    BOOST_ASSERT(s.front() == '[');
420  
    BOOST_ASSERT(s.front() == '[');
421  
    BOOST_ASSERT(s.back() == ']');
421  
    BOOST_ASSERT(s.back() == ']');
422  
    s = s.substr(1, s.size() - 2);
422  
    s = s.substr(1, s.size() - 2);
423  
    return s;
423  
    return s;
424  
}
424  
}
425  

425  

426  
inline
426  
inline
427  
pct_string_view
427  
pct_string_view
428  
url_view_base::
428  
url_view_base::
429  
encoded_host_name() const noexcept
429  
encoded_host_name() const noexcept
430  
{
430  
{
431  
    if(impl().host_type_ !=
431  
    if(impl().host_type_ !=
432  
            urls::host_type::name)
432  
            urls::host_type::name)
433  
        return {};
433  
        return {};
434  
    core::string_view s = impl().get(id_host);
434  
    core::string_view s = impl().get(id_host);
435  
    return make_pct_string_view_unsafe(
435  
    return make_pct_string_view_unsafe(
436  
        s.data(),
436  
        s.data(),
437  
        s.size(),
437  
        s.size(),
438  
        impl().decoded_[id_host]);
438  
        impl().decoded_[id_host]);
439  
}
439  
}
440  

440  

441  
inline
441  
inline
442  
pct_string_view
442  
pct_string_view
443  
url_view_base::
443  
url_view_base::
444  
encoded_zone_id() const noexcept
444  
encoded_zone_id() const noexcept
445  
{
445  
{
446  
    if(impl().host_type_ !=
446  
    if(impl().host_type_ !=
447  
        urls::host_type::ipv6)
447  
        urls::host_type::ipv6)
448  
        return {};
448  
        return {};
449  
    core::string_view s = impl().get(id_host);
449  
    core::string_view s = impl().get(id_host);
450  
    BOOST_ASSERT(s.front() == '[');
450  
    BOOST_ASSERT(s.front() == '[');
451  
    BOOST_ASSERT(s.back() == ']');
451  
    BOOST_ASSERT(s.back() == ']');
452  
    s = s.substr(1, s.size() - 2);
452  
    s = s.substr(1, s.size() - 2);
453  
    auto pos = s.find("%25");
453  
    auto pos = s.find("%25");
454  
    if (pos == core::string_view::npos)
454  
    if (pos == core::string_view::npos)
455  
        return {};
455  
        return {};
456  
    s.remove_prefix(pos + 3);
456  
    s.remove_prefix(pos + 3);
457  
    return *make_pct_string_view(s);
457  
    return *make_pct_string_view(s);
458  
}
458  
}
459  

459  

460  
//------------------------------------------------
460  
//------------------------------------------------
461  

461  

462  
inline
462  
inline
463  
bool
463  
bool
464  
url_view_base::
464  
url_view_base::
465  
has_port() const noexcept
465  
has_port() const noexcept
466  
{
466  
{
467  
    auto const n = impl().len(id_port);
467  
    auto const n = impl().len(id_port);
468  
    if(n == 0)
468  
    if(n == 0)
469  
        return false;
469  
        return false;
470  
    BOOST_ASSERT(
470  
    BOOST_ASSERT(
471  
        impl().get(id_port).starts_with(':'));
471  
        impl().get(id_port).starts_with(':'));
472  
    return true;
472  
    return true;
473  
}
473  
}
474  

474  

475  
inline
475  
inline
476  
core::string_view
476  
core::string_view
477  
url_view_base::
477  
url_view_base::
478  
port() const noexcept
478  
port() const noexcept
479  
{
479  
{
480  
    auto s = impl().get(id_port);
480  
    auto s = impl().get(id_port);
481  
    if(s.empty())
481  
    if(s.empty())
482  
        return s;
482  
        return s;
483  
    BOOST_ASSERT(has_port());
483  
    BOOST_ASSERT(has_port());
484  
    return s.substr(1);
484  
    return s.substr(1);
485  
}
485  
}
486  

486  

487  
inline
487  
inline
488  
std::uint16_t
488  
std::uint16_t
489  
url_view_base::
489  
url_view_base::
490  
port_number() const noexcept
490  
port_number() const noexcept
491  
{
491  
{
492  
    BOOST_ASSERT(
492  
    BOOST_ASSERT(
493  
        has_port() ||
493  
        has_port() ||
494  
        impl().port_number_ == 0);
494  
        impl().port_number_ == 0);
495  
    return impl().port_number_;
495  
    return impl().port_number_;
496  
}
496  
}
497  

497  

498  
//------------------------------------------------
498  
//------------------------------------------------
499  
//
499  
//
500  
// Path
500  
// Path
501  
//
501  
//
502  
//------------------------------------------------
502  
//------------------------------------------------
503  

503  

504  
inline
504  
inline
505  
pct_string_view
505  
pct_string_view
506  
url_view_base::
506  
url_view_base::
507  
encoded_path() const noexcept
507  
encoded_path() const noexcept
508  
{
508  
{
509  
    return impl().pct_get(id_path);
509  
    return impl().pct_get(id_path);
510  
}
510  
}
511  

511  

512  
inline
512  
inline
513  
segments_view
513  
segments_view
514  
url_view_base::
514  
url_view_base::
515  
segments() const noexcept
515  
segments() const noexcept
516  
{
516  
{
517  
    return {detail::path_ref(impl())};
517  
    return {detail::path_ref(impl())};
518  
}
518  
}
519  

519  

520  
inline
520  
inline
521  
segments_encoded_view
521  
segments_encoded_view
522  
url_view_base::
522  
url_view_base::
523  
encoded_segments() const noexcept
523  
encoded_segments() const noexcept
524  
{
524  
{
525  
    return segments_encoded_view(
525  
    return segments_encoded_view(
526  
        detail::path_ref(impl()));
526  
        detail::path_ref(impl()));
527  
}
527  
}
528  

528  

529  
//------------------------------------------------
529  
//------------------------------------------------
530  
//
530  
//
531  
// Query
531  
// Query
532  
//
532  
//
533  
//------------------------------------------------
533  
//------------------------------------------------
534  

534  

535  
inline
535  
inline
536  
bool
536  
bool
537  
url_view_base::
537  
url_view_base::
538  
has_query() const noexcept
538  
has_query() const noexcept
539  
{
539  
{
540  
    auto const n = impl().len(
540  
    auto const n = impl().len(
541  
        id_query);
541  
        id_query);
542  
    if(n == 0)
542  
    if(n == 0)
543  
        return false;
543  
        return false;
544  
    BOOST_ASSERT(
544  
    BOOST_ASSERT(
545  
        impl().get(id_query).
545  
        impl().get(id_query).
546  
            starts_with('?'));
546  
            starts_with('?'));
547  
    return true;
547  
    return true;
548  
}
548  
}
549  

549  

550  
inline
550  
inline
551  
pct_string_view
551  
pct_string_view
552  
url_view_base::
552  
url_view_base::
553  
encoded_query() const noexcept
553  
encoded_query() const noexcept
554  
{
554  
{
555  
    auto s = impl().get(id_query);
555  
    auto s = impl().get(id_query);
556  
    if(s.empty())
556  
    if(s.empty())
557  
        return s;
557  
        return s;
558  
    BOOST_ASSERT(
558  
    BOOST_ASSERT(
559  
        s.starts_with('?'));
559  
        s.starts_with('?'));
560  
    return s.substr(1);
560  
    return s.substr(1);
561  
}
561  
}
562  

562  

563  
inline
563  
inline
564  
params_encoded_view
564  
params_encoded_view
565  
url_view_base::
565  
url_view_base::
566  
encoded_params() const noexcept
566  
encoded_params() const noexcept
567  
{
567  
{
568  
    return params_encoded_view(impl());
568  
    return params_encoded_view(impl());
569  
}
569  
}
570  

570  

571  
inline
571  
inline
572  
params_view
572  
params_view
573  
url_view_base::
573  
url_view_base::
574  
params() const noexcept
574  
params() const noexcept
575  
{
575  
{
576  
    return params_view(
576  
    return params_view(
577  
        impl(),
577  
        impl(),
578  
        encoding_opts{
578  
        encoding_opts{
579  
            true,false,false});
579  
            true,false,false});
580  
}
580  
}
581  

581  

582  
inline
582  
inline
583  
params_view
583  
params_view
584  
url_view_base::
584  
url_view_base::
585  
params(encoding_opts opt) const noexcept
585  
params(encoding_opts opt) const noexcept
586  
{
586  
{
587  
    return params_view(impl(), opt);
587  
    return params_view(impl(), opt);
588  
}
588  
}
589  

589  

590  
//------------------------------------------------
590  
//------------------------------------------------
591  
//
591  
//
592  
// Fragment
592  
// Fragment
593  
//
593  
//
594  
//------------------------------------------------
594  
//------------------------------------------------
595  

595  

596  
inline
596  
inline
597  
bool
597  
bool
598  
url_view_base::
598  
url_view_base::
599  
has_fragment() const noexcept
599  
has_fragment() const noexcept
600  
{
600  
{
601  
    auto const n = impl().len(id_frag);
601  
    auto const n = impl().len(id_frag);
602  
    if(n == 0)
602  
    if(n == 0)
603  
        return false;
603  
        return false;
604  
    BOOST_ASSERT(
604  
    BOOST_ASSERT(
605  
        impl().get(id_frag).
605  
        impl().get(id_frag).
606  
            starts_with('#'));
606  
            starts_with('#'));
607  
    return true;
607  
    return true;
608  
}
608  
}
609  

609  

610  
inline
610  
inline
611  
pct_string_view
611  
pct_string_view
612  
url_view_base::
612  
url_view_base::
613  
encoded_fragment() const noexcept
613  
encoded_fragment() const noexcept
614  
{
614  
{
615  
    auto s = impl().get(id_frag);
615  
    auto s = impl().get(id_frag);
616  
    if(! s.empty())
616  
    if(! s.empty())
617  
    {
617  
    {
618  
        BOOST_ASSERT(
618  
        BOOST_ASSERT(
619  
            s.starts_with('#'));
619  
            s.starts_with('#'));
620  
        s.remove_prefix(1);
620  
        s.remove_prefix(1);
621  
    }
621  
    }
622  
    return make_pct_string_view_unsafe(
622  
    return make_pct_string_view_unsafe(
623  
        s.data(),
623  
        s.data(),
624  
        s.size(),
624  
        s.size(),
625  
        impl().decoded_[id_frag]);
625  
        impl().decoded_[id_frag]);
626  
}
626  
}
627  

627  

628  
//------------------------------------------------
628  
//------------------------------------------------
629  
//
629  
//
630  
// Compound Fields
630  
// Compound Fields
631  
//
631  
//
632  
//------------------------------------------------
632  
//------------------------------------------------
633  

633  

634  
inline
634  
inline
635  
pct_string_view
635  
pct_string_view
636  
url_view_base::
636  
url_view_base::
637  
encoded_host_and_port() const noexcept
637  
encoded_host_and_port() const noexcept
638  
{
638  
{
639  
    return impl().pct_get(id_host, id_path);
639  
    return impl().pct_get(id_host, id_path);
640  
}
640  
}
641  

641  

642  
inline
642  
inline
643  
pct_string_view
643  
pct_string_view
644  
url_view_base::
644  
url_view_base::
645  
encoded_origin() const noexcept
645  
encoded_origin() const noexcept
646  
{
646  
{
647  
    if(impl().len(id_user) < 2)
647  
    if(impl().len(id_user) < 2)
648  
        return {};
648  
        return {};
649  
    return impl().get(id_scheme, id_path);
649  
    return impl().get(id_scheme, id_path);
650  
}
650  
}
651  

651  

652  
inline
652  
inline
653  
pct_string_view
653  
pct_string_view
654  
url_view_base::
654  
url_view_base::
655  
encoded_resource() const noexcept
655  
encoded_resource() const noexcept
656  
{
656  
{
657  
    auto n =
657  
    auto n =
658  
        impl().decoded_[id_path] +
658  
        impl().decoded_[id_path] +
659  
        impl().decoded_[id_query] +
659  
        impl().decoded_[id_query] +
660  
        impl().decoded_[id_frag];
660  
        impl().decoded_[id_frag];
661  
    if(has_query())
661  
    if(has_query())
662  
        ++n;
662  
        ++n;
663  
    if(has_fragment())
663  
    if(has_fragment())
664  
        ++n;
664  
        ++n;
665  
    BOOST_ASSERT(pct_string_view(
665  
    BOOST_ASSERT(pct_string_view(
666  
        impl().get(id_path, id_end)
666  
        impl().get(id_path, id_end)
667  
            ).decoded_size() == n);
667  
            ).decoded_size() == n);
668  
    auto s = impl().get(id_path, id_end);
668  
    auto s = impl().get(id_path, id_end);
669  
    return make_pct_string_view_unsafe(
669  
    return make_pct_string_view_unsafe(
670  
        s.data(), s.size(), n);
670  
        s.data(), s.size(), n);
671  
}
671  
}
672  

672  

673  
inline
673  
inline
674  
pct_string_view
674  
pct_string_view
675  
url_view_base::
675  
url_view_base::
676  
encoded_target() const noexcept
676  
encoded_target() const noexcept
677  
{
677  
{
678  
    auto n =
678  
    auto n =
679  
        impl().decoded_[id_path] +
679  
        impl().decoded_[id_path] +
680  
        impl().decoded_[id_query];
680  
        impl().decoded_[id_query];
681  
    if(has_query())
681  
    if(has_query())
682  
        ++n;
682  
        ++n;
683  
    BOOST_ASSERT(pct_string_view(
683  
    BOOST_ASSERT(pct_string_view(
684  
        impl().get(id_path, id_frag)
684  
        impl().get(id_path, id_frag)
685  
            ).decoded_size() == n);
685  
            ).decoded_size() == n);
686  
    auto s = impl().get(id_path, id_frag);
686  
    auto s = impl().get(id_path, id_frag);
687  
    return make_pct_string_view_unsafe(
687  
    return make_pct_string_view_unsafe(
688  
        s.data(), s.size(), n);
688  
        s.data(), s.size(), n);
689  
}
689  
}
690  

690  

691  
//------------------------------------------------
691  
//------------------------------------------------
692  
//
692  
//
693  
// Comparisons
693  
// Comparisons
694  
//
694  
//
695  
//------------------------------------------------
695  
//------------------------------------------------
696  

696  

697  
inline
697  
inline
698  
int
698  
int
699  
url_view_base::
699  
url_view_base::
700  
compare(const url_view_base& other) const noexcept
700  
compare(const url_view_base& other) const noexcept
701  
{
701  
{
702  
    int comp =
702  
    int comp =
703  
        static_cast<int>(has_scheme()) -
703  
        static_cast<int>(has_scheme()) -
704  
        static_cast<int>(other.has_scheme());
704  
        static_cast<int>(other.has_scheme());
705  
    if ( comp != 0 )
705  
    if ( comp != 0 )
706  
        return comp;
706  
        return comp;
707  

707  

708  
    if (has_scheme())
708  
    if (has_scheme())
709  
    {
709  
    {
710  
        comp = detail::ci_compare(
710  
        comp = detail::ci_compare(
711  
            scheme(),
711  
            scheme(),
712  
            other.scheme());
712  
            other.scheme());
713  
        if ( comp != 0 )
713  
        if ( comp != 0 )
714  
            return comp;
714  
            return comp;
715  
    }
715  
    }
716  

716  

717  
    comp =
717  
    comp =
718  
        static_cast<int>(has_authority()) -
718  
        static_cast<int>(has_authority()) -
719  
        static_cast<int>(other.has_authority());
719  
        static_cast<int>(other.has_authority());
720  
    if ( comp != 0 )
720  
    if ( comp != 0 )
721  
        return comp;
721  
        return comp;
722  

722  

723  
    if (has_authority())
723  
    if (has_authority())
724  
    {
724  
    {
725  
        comp = authority().compare(other.authority());
725  
        comp = authority().compare(other.authority());
726  
        if ( comp != 0 )
726  
        if ( comp != 0 )
727  
            return comp;
727  
            return comp;
728  
    }
728  
    }
729  

729  

730  
    comp = detail::segments_compare(
730  
    comp = detail::segments_compare(
731  
        encoded_segments(),
731  
        encoded_segments(),
732  
        other.encoded_segments());
732  
        other.encoded_segments());
733  
    if ( comp != 0 )
733  
    if ( comp != 0 )
734  
        return comp;
734  
        return comp;
735  

735  

736  
    comp =
736  
    comp =
737  
        static_cast<int>(has_query()) -
737  
        static_cast<int>(has_query()) -
738  
        static_cast<int>(other.has_query());
738  
        static_cast<int>(other.has_query());
739  
    if ( comp != 0 )
739  
    if ( comp != 0 )
740  
        return comp;
740  
        return comp;
741  

741  

742  
    if (has_query())
742  
    if (has_query())
743  
    {
743  
    {
744  
        comp = detail::compare_encoded_query(
744  
        comp = detail::compare_encoded_query(
745  
            encoded_query(),
745  
            encoded_query(),
746  
            other.encoded_query());
746  
            other.encoded_query());
747  
        if ( comp != 0 )
747  
        if ( comp != 0 )
748  
            return comp;
748  
            return comp;
749  
    }
749  
    }
750  

750  

751  
    comp =
751  
    comp =
752  
        static_cast<int>(has_fragment()) -
752  
        static_cast<int>(has_fragment()) -
753  
        static_cast<int>(other.has_fragment());
753  
        static_cast<int>(other.has_fragment());
754  
    if ( comp != 0 )
754  
    if ( comp != 0 )
755  
        return comp;
755  
        return comp;
756  

756  

757  
    if (has_fragment())
757  
    if (has_fragment())
758  
    {
758  
    {
759  
        comp = detail::compare_encoded(
759  
        comp = detail::compare_encoded(
760  
            encoded_fragment(),
760  
            encoded_fragment(),
761  
            other.encoded_fragment());
761  
            other.encoded_fragment());
762  
        if ( comp != 0 )
762  
        if ( comp != 0 )
763  
            return comp;
763  
            return comp;
764  
    }
764  
    }
765  

765  

766  
    return 0;
766  
    return 0;
767  
}
767  
}
768  

768  

769  
} // urls
769  
} // urls
770  
} // boost
770  
} // boost
771  

771  

772  
#endif
772  
#endif