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) 2023 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2023 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_AUTHORITY_VIEW_HPP
11  
#ifndef BOOST_URL_IMPL_AUTHORITY_VIEW_HPP
12  
#define BOOST_URL_IMPL_AUTHORITY_VIEW_HPP
12  
#define BOOST_URL_IMPL_AUTHORITY_VIEW_HPP
13  

13  

14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
15  
#include <boost/url/detail/memcpy.hpp>
15  
#include <boost/url/detail/memcpy.hpp>
16  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/parse.hpp>
17  
#include <boost/url/rfc/authority_rule.hpp>
17  
#include <boost/url/rfc/authority_rule.hpp>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace urls {
20  
namespace urls {
21  

21  

22  
//------------------------------------------------
22  
//------------------------------------------------
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  
int
29  
int
30  
compare_encoded(
30  
compare_encoded(
31  
    core::string_view lhs,
31  
    core::string_view lhs,
32  
    core::string_view rhs) noexcept;
32  
    core::string_view rhs) noexcept;
33  

33  

34  
BOOST_URL_DECL
34  
BOOST_URL_DECL
35  
int
35  
int
36  
ci_compare_encoded(
36  
ci_compare_encoded(
37  
    core::string_view lhs,
37  
    core::string_view lhs,
38  
    core::string_view rhs) noexcept;
38  
    core::string_view rhs) noexcept;
39  

39  

40  
BOOST_URL_DECL
40  
BOOST_URL_DECL
41  
int
41  
int
42  
compare(
42  
compare(
43  
    core::string_view lhs,
43  
    core::string_view lhs,
44  
    core::string_view rhs) noexcept;
44  
    core::string_view rhs) noexcept;
45  

45  

46  
} // detail
46  
} // detail
47  

47  

48  
//------------------------------------------------
48  
//------------------------------------------------
49  
//
49  
//
50  
// Special Members
50  
// Special Members
51  
//
51  
//
52  
//------------------------------------------------
52  
//------------------------------------------------
53  

53  

54  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
54  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
55  
authority_view::
55  
authority_view::
56  
authority_view(
56  
authority_view(
57  
    core::string_view s)
57  
    core::string_view s)
58  
    : authority_view(
58  
    : authority_view(
59  
        parse_authority(s
59  
        parse_authority(s
60  
            ).value(BOOST_URL_POS))
60  
            ).value(BOOST_URL_POS))
61  
{
61  
{
62  
}
62  
}
63  

63  

64  
//------------------------------------------------
64  
//------------------------------------------------
65  
//
65  
//
66  
// Userinfo
66  
// Userinfo
67  
//
67  
//
68  
//------------------------------------------------
68  
//------------------------------------------------
69  

69  

70  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
70  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
71  
bool
71  
bool
72  
authority_view::
72  
authority_view::
73  
has_userinfo() const noexcept
73  
has_userinfo() const noexcept
74  
{
74  
{
75  
    auto n = u_.len(id_pass);
75  
    auto n = u_.len(id_pass);
76  
    if(n == 0)
76  
    if(n == 0)
77  
        return false;
77  
        return false;
78  
    BOOST_ASSERT(u_.get(
78  
    BOOST_ASSERT(u_.get(
79  
        id_pass).ends_with('@'));
79  
        id_pass).ends_with('@'));
80  
    return true;
80  
    return true;
81  
}
81  
}
82  

82  

83  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
83  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
84  
pct_string_view
84  
pct_string_view
85  
authority_view::
85  
authority_view::
86  
encoded_userinfo() const noexcept
86  
encoded_userinfo() const noexcept
87  
{
87  
{
88  
    auto s = u_.get(
88  
    auto s = u_.get(
89  
        id_user, id_host);
89  
        id_user, id_host);
90  
    if(s.empty())
90  
    if(s.empty())
91  
        return s;
91  
        return s;
92  
    BOOST_ASSERT(
92  
    BOOST_ASSERT(
93  
        s.ends_with('@'));
93  
        s.ends_with('@'));
94  
    s.remove_suffix(1);
94  
    s.remove_suffix(1);
95  
    return make_pct_string_view_unsafe(
95  
    return make_pct_string_view_unsafe(
96  
        s.data(),
96  
        s.data(),
97  
        s.size(),
97  
        s.size(),
98  
        u_.decoded_[id_user] +
98  
        u_.decoded_[id_user] +
99  
            u_.decoded_[id_pass] +
99  
            u_.decoded_[id_pass] +
100  
            has_password());
100  
            has_password());
101  
}
101  
}
102  

102  

103  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
103  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
104  
pct_string_view
104  
pct_string_view
105  
authority_view::
105  
authority_view::
106  
encoded_user() const noexcept
106  
encoded_user() const noexcept
107  
{
107  
{
108  
    auto s = u_.get(id_user);
108  
    auto s = u_.get(id_user);
109  
    return make_pct_string_view_unsafe(
109  
    return make_pct_string_view_unsafe(
110  
        s.data(),
110  
        s.data(),
111  
        s.size(),
111  
        s.size(),
112  
        u_.decoded_[id_user]);
112  
        u_.decoded_[id_user]);
113  
}
113  
}
114  

114  

115  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
115  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
116  
bool
116  
bool
117  
authority_view::
117  
authority_view::
118  
has_password() const noexcept
118  
has_password() const noexcept
119  
{
119  
{
120  
    auto const n = u_.len(id_pass);
120  
    auto const n = u_.len(id_pass);
121  
    if(n > 1)
121  
    if(n > 1)
122  
    {
122  
    {
123  
        BOOST_ASSERT(u_.get(id_pass
123  
        BOOST_ASSERT(u_.get(id_pass
124  
            ).starts_with(':'));
124  
            ).starts_with(':'));
125  
        BOOST_ASSERT(u_.get(id_pass
125  
        BOOST_ASSERT(u_.get(id_pass
126  
            ).ends_with('@'));
126  
            ).ends_with('@'));
127  
        return true;
127  
        return true;
128  
    }
128  
    }
129  
    BOOST_ASSERT(n == 0 || u_.get(
129  
    BOOST_ASSERT(n == 0 || u_.get(
130  
        id_pass).ends_with('@'));
130  
        id_pass).ends_with('@'));
131  
    return false;
131  
    return false;
132  
}
132  
}
133  

133  

134  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
134  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
135  
pct_string_view
135  
pct_string_view
136  
authority_view::
136  
authority_view::
137  
encoded_password() const noexcept
137  
encoded_password() const noexcept
138  
{
138  
{
139  
    auto s = u_.get(id_pass);
139  
    auto s = u_.get(id_pass);
140  
    switch(s.size())
140  
    switch(s.size())
141  
    {
141  
    {
142  
    case 1:
142  
    case 1:
143  
        BOOST_ASSERT(
143  
        BOOST_ASSERT(
144  
            s.starts_with('@'));
144  
            s.starts_with('@'));
145  
        s.remove_prefix(1);
145  
        s.remove_prefix(1);
146  
        BOOST_FALLTHROUGH;
146  
        BOOST_FALLTHROUGH;
147  
    case 0:
147  
    case 0:
148  
        return make_pct_string_view_unsafe(
148  
        return make_pct_string_view_unsafe(
149  
            s.data(), s.size(), 0);
149  
            s.data(), s.size(), 0);
150  
    default:
150  
    default:
151  
        break;
151  
        break;
152  
    }
152  
    }
153  
    BOOST_ASSERT(s.ends_with('@'));
153  
    BOOST_ASSERT(s.ends_with('@'));
154  
    BOOST_ASSERT(s.starts_with(':'));
154  
    BOOST_ASSERT(s.starts_with(':'));
155  
    return make_pct_string_view_unsafe(
155  
    return make_pct_string_view_unsafe(
156  
        s.data() + 1,
156  
        s.data() + 1,
157  
        s.size() - 2,
157  
        s.size() - 2,
158  
        u_.decoded_[id_pass]);
158  
        u_.decoded_[id_pass]);
159  
}
159  
}
160  

160  

161  
//------------------------------------------------
161  
//------------------------------------------------
162  
//
162  
//
163  
// Host
163  
// Host
164  
//
164  
//
165  
//------------------------------------------------
165  
//------------------------------------------------
166  
/*
166  
/*
167  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
167  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
168  

168  

169  
std::string     host()                      // return encoded_host().decode()
169  
std::string     host()                      // return encoded_host().decode()
170  
pct_string_view encoded_host()              // return host part, as-is
170  
pct_string_view encoded_host()              // return host part, as-is
171  
std::string     host_address()              // return encoded_host_address().decode()
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
172  
pct_string_view encoded_host_address()      // ipv4, ipv6, ipvfut, or encoded name, no brackets
173  

173  

174  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
174  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
175  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
175  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
176  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
176  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
177  
std::string     host_name()                 // return decoded name or ""
177  
std::string     host_name()                 // return decoded name or ""
178  
pct_string_view encoded_host_name()         // return encoded host name or ""
178  
pct_string_view encoded_host_name()         // return encoded host name or ""
179  
*/
179  
*/
180  

180  

181  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
181  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
182  
pct_string_view
182  
pct_string_view
183  
authority_view::
183  
authority_view::
184  
encoded_host() const noexcept
184  
encoded_host() const noexcept
185  
{
185  
{
186  
    return u_.pct_get(id_host);
186  
    return u_.pct_get(id_host);
187  
}
187  
}
188  

188  

189  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
189  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
190  
pct_string_view
190  
pct_string_view
191  
authority_view::
191  
authority_view::
192  
encoded_host_address() const noexcept
192  
encoded_host_address() const noexcept
193  
{
193  
{
194  
    core::string_view s = u_.get(id_host);
194  
    core::string_view s = u_.get(id_host);
195  
    std::size_t n;
195  
    std::size_t n;
196  
    switch(u_.host_type_)
196  
    switch(u_.host_type_)
197  
    {
197  
    {
198  
    case urls::host_type::name:
198  
    case urls::host_type::name:
199  
    case urls::host_type::ipv4:
199  
    case urls::host_type::ipv4:
200  
        n = u_.decoded_[id_host];
200  
        n = u_.decoded_[id_host];
201  
        break;
201  
        break;
202  

202  

203  
    case urls::host_type::ipv6:
203  
    case urls::host_type::ipv6:
204  
    case urls::host_type::ipvfuture:
204  
    case urls::host_type::ipvfuture:
205  
    {
205  
    {
206  
        BOOST_ASSERT(
206  
        BOOST_ASSERT(
207  
            u_.decoded_[id_host] ==
207  
            u_.decoded_[id_host] ==
208  
                s.size());
208  
                s.size());
209  
        BOOST_ASSERT(s.size() >= 2);
209  
        BOOST_ASSERT(s.size() >= 2);
210  
        BOOST_ASSERT(s.front() == '[');
210  
        BOOST_ASSERT(s.front() == '[');
211  
        BOOST_ASSERT(s.back() == ']');
211  
        BOOST_ASSERT(s.back() == ']');
212  
        s = s.substr(1, s.size() - 2);
212  
        s = s.substr(1, s.size() - 2);
213  
        n = u_.decoded_[id_host] - 2;
213  
        n = u_.decoded_[id_host] - 2;
214  
        break;
214  
        break;
215  
    }
215  
    }
216  
    // LCOV_EXCL_START
216  
    // LCOV_EXCL_START
217  
    default:
217  
    default:
218  
    case urls::host_type::none:
218  
    case urls::host_type::none:
219  
        /*
219  
        /*
220  
         * This condition is for correctness
220  
         * This condition is for correctness
221  
         * only.
221  
         * only.
222  
         * This should never happen, because
222  
         * This should never happen, because
223  
         * the `host_rule` will set the host
223  
         * the `host_rule` will set the host
224  
         * type to `name` when it's empty.
224  
         * type to `name` when it's empty.
225  
         * This is correct because `reg-name`
225  
         * This is correct because `reg-name`
226  
         * accepts empty strings.
226  
         * accepts empty strings.
227  
         */
227  
         */
228  
        BOOST_ASSERT(s.empty());
228  
        BOOST_ASSERT(s.empty());
229  
        n = 0;
229  
        n = 0;
230  
        break;
230  
        break;
231  
    // LCOV_EXCL_STOP
231  
    // LCOV_EXCL_STOP
232  
    }
232  
    }
233  
    return make_pct_string_view_unsafe(
233  
    return make_pct_string_view_unsafe(
234  
        s.data(), s.size(), n);
234  
        s.data(), s.size(), n);
235  
}
235  
}
236  

236  

237  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
237  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
238  
ipv4_address
238  
ipv4_address
239  
authority_view::
239  
authority_view::
240  
host_ipv4_address() const noexcept
240  
host_ipv4_address() const noexcept
241  
{
241  
{
242  
    if(u_.host_type_ !=
242  
    if(u_.host_type_ !=
243  
            urls::host_type::ipv4)
243  
            urls::host_type::ipv4)
244  
        return {};
244  
        return {};
245  
    ipv4_address::bytes_type b{{}};
245  
    ipv4_address::bytes_type b{{}};
246  
    detail::memcpy(
246  
    detail::memcpy(
247  
        &b[0], &u_.ip_addr_[0], b.size());
247  
        &b[0], &u_.ip_addr_[0], b.size());
248  
    return urls::ipv4_address(b);
248  
    return urls::ipv4_address(b);
249  
}
249  
}
250  

250  

251  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
251  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
252  
ipv6_address
252  
ipv6_address
253  
authority_view::
253  
authority_view::
254  
host_ipv6_address() const noexcept
254  
host_ipv6_address() const noexcept
255  
{
255  
{
256  
    if(u_.host_type_ !=
256  
    if(u_.host_type_ !=
257  
            urls::host_type::ipv6)
257  
            urls::host_type::ipv6)
258  
        return {};
258  
        return {};
259  
    ipv6_address::bytes_type b{{}};
259  
    ipv6_address::bytes_type b{{}};
260  
    detail::memcpy(
260  
    detail::memcpy(
261  
        &b[0], &u_.ip_addr_[0], b.size());
261  
        &b[0], &u_.ip_addr_[0], b.size());
262  
    return urls::ipv6_address(b);
262  
    return urls::ipv6_address(b);
263  
}
263  
}
264  

264  

265  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
265  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
266  
core::string_view
266  
core::string_view
267  
authority_view::
267  
authority_view::
268  
host_ipvfuture() const noexcept
268  
host_ipvfuture() const noexcept
269  
{
269  
{
270  
    if(u_.host_type_ !=
270  
    if(u_.host_type_ !=
271  
            urls::host_type::ipvfuture)
271  
            urls::host_type::ipvfuture)
272  
        return {};
272  
        return {};
273  
    core::string_view s = u_.get(id_host);
273  
    core::string_view s = u_.get(id_host);
274  
    BOOST_ASSERT(s.size() >= 6);
274  
    BOOST_ASSERT(s.size() >= 6);
275  
    BOOST_ASSERT(s.front() == '[');
275  
    BOOST_ASSERT(s.front() == '[');
276  
    BOOST_ASSERT(s.back() == ']');
276  
    BOOST_ASSERT(s.back() == ']');
277  
    s = s.substr(1, s.size() - 2);
277  
    s = s.substr(1, s.size() - 2);
278  
    return s;
278  
    return s;
279  
}
279  
}
280  

280  

281  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
281  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
282  
pct_string_view
282  
pct_string_view
283  
authority_view::
283  
authority_view::
284  
encoded_host_name() const noexcept
284  
encoded_host_name() const noexcept
285  
{
285  
{
286  
    if(u_.host_type_ !=
286  
    if(u_.host_type_ !=
287  
            urls::host_type::name)
287  
            urls::host_type::name)
288  
        return {};
288  
        return {};
289  
    return u_.pct_get(id_host);
289  
    return u_.pct_get(id_host);
290  
}
290  
}
291  

291  

292  
//------------------------------------------------
292  
//------------------------------------------------
293  
//
293  
//
294  
// Port
294  
// Port
295  
//
295  
//
296  
//------------------------------------------------
296  
//------------------------------------------------
297  

297  

298  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
298  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
299  
bool
299  
bool
300  
authority_view::
300  
authority_view::
301  
has_port() const noexcept
301  
has_port() const noexcept
302  
{
302  
{
303  
    auto const n = u_.len(id_port);
303  
    auto const n = u_.len(id_port);
304  
    if(n == 0)
304  
    if(n == 0)
305  
        return false;
305  
        return false;
306  
    BOOST_ASSERT(
306  
    BOOST_ASSERT(
307  
        u_.get(id_port).starts_with(':'));
307  
        u_.get(id_port).starts_with(':'));
308  
    return true;
308  
    return true;
309  
}
309  
}
310  

310  

311  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
311  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
312  
core::string_view
312  
core::string_view
313  
authority_view::
313  
authority_view::
314  
port() const noexcept
314  
port() const noexcept
315  
{
315  
{
316  
    auto s = u_.get(id_port);
316  
    auto s = u_.get(id_port);
317  
    if(s.empty())
317  
    if(s.empty())
318  
        return s;
318  
        return s;
319  
    BOOST_ASSERT(has_port());
319  
    BOOST_ASSERT(has_port());
320  
    return s.substr(1);
320  
    return s.substr(1);
321  
}
321  
}
322  

322  

323  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
323  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
324  
std::uint16_t
324  
std::uint16_t
325  
authority_view::
325  
authority_view::
326  
port_number() const noexcept
326  
port_number() const noexcept
327  
{
327  
{
328  
    BOOST_ASSERT(
328  
    BOOST_ASSERT(
329  
        has_port() ||
329  
        has_port() ||
330  
        u_.port_number_ == 0);
330  
        u_.port_number_ == 0);
331  
    return u_.port_number_;
331  
    return u_.port_number_;
332  
}
332  
}
333  

333  

334  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
334  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
335  
pct_string_view
335  
pct_string_view
336  
authority_view::
336  
authority_view::
337  
encoded_host_and_port() const noexcept
337  
encoded_host_and_port() const noexcept
338  
{
338  
{
339  
    return u_.pct_get(id_host, id_end);
339  
    return u_.pct_get(id_host, id_end);
340  
}
340  
}
341  

341  

342  
//------------------------------------------------
342  
//------------------------------------------------
343  
//
343  
//
344  
// Comparisons
344  
// Comparisons
345  
//
345  
//
346  
//------------------------------------------------
346  
//------------------------------------------------
347  

347  

348  
inline
348  
inline
349  
int
349  
int
350  
authority_view::
350  
authority_view::
351  
compare(const authority_view& other) const noexcept
351  
compare(const authority_view& other) const noexcept
352  
{
352  
{
353  
    auto comp = static_cast<int>(has_userinfo()) -
353  
    auto comp = static_cast<int>(has_userinfo()) -
354  
        static_cast<int>(other.has_userinfo());
354  
        static_cast<int>(other.has_userinfo());
355  
    if ( comp != 0 )
355  
    if ( comp != 0 )
356  
        return comp;
356  
        return comp;
357  

357  

358  
    if (has_userinfo())
358  
    if (has_userinfo())
359  
    {
359  
    {
360  
        comp = detail::compare_encoded(
360  
        comp = detail::compare_encoded(
361  
            encoded_user(),
361  
            encoded_user(),
362  
            other.encoded_user());
362  
            other.encoded_user());
363  
        if ( comp != 0 )
363  
        if ( comp != 0 )
364  
            return comp;
364  
            return comp;
365  

365  

366  
        comp = static_cast<int>(has_password()) -
366  
        comp = static_cast<int>(has_password()) -
367  
               static_cast<int>(other.has_password());
367  
               static_cast<int>(other.has_password());
368  
        if ( comp != 0 )
368  
        if ( comp != 0 )
369  
            return comp;
369  
            return comp;
370  

370  

371  
        if (has_password())
371  
        if (has_password())
372  
        {
372  
        {
373  
            comp = detail::compare_encoded(
373  
            comp = detail::compare_encoded(
374  
                encoded_password(),
374  
                encoded_password(),
375  
                other.encoded_password());
375  
                other.encoded_password());
376  
            if ( comp != 0 )
376  
            if ( comp != 0 )
377  
                return comp;
377  
                return comp;
378  
        }
378  
        }
379  
    }
379  
    }
380  

380  

381  
    comp = detail::ci_compare_encoded(
381  
    comp = detail::ci_compare_encoded(
382  
        encoded_host(),
382  
        encoded_host(),
383  
        other.encoded_host());
383  
        other.encoded_host());
384  
    if ( comp != 0 )
384  
    if ( comp != 0 )
385  
        return comp;
385  
        return comp;
386  

386  

387  
    comp = static_cast<int>(has_port()) -
387  
    comp = static_cast<int>(has_port()) -
388  
           static_cast<int>(other.has_port());
388  
           static_cast<int>(other.has_port());
389  
    if ( comp != 0 )
389  
    if ( comp != 0 )
390  
        return comp;
390  
        return comp;
391  

391  

392  
    if (has_port())
392  
    if (has_port())
393  
    {
393  
    {
394  
        comp = detail::compare(
394  
        comp = detail::compare(
395  
            port(),
395  
            port(),
396  
            other.port());
396  
            other.port());
397  
        if ( comp != 0 )
397  
        if ( comp != 0 )
398  
            return comp;
398  
            return comp;
399  
    }
399  
    }
400  

400  

401  
    return 0;
401  
    return 0;
402  
}
402  
}
403  

403  

404  
//------------------------------------------------
404  
//------------------------------------------------
405  

405  

406  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
406  
BOOST_URL_CXX20_CONSTEXPR_OR_INLINE
407  
system::result<authority_view>
407  
system::result<authority_view>
408  
parse_authority(
408  
parse_authority(
409  
    core::string_view s) noexcept
409  
    core::string_view s) noexcept
410  
{
410  
{
411  
    return grammar::parse(s, authority_rule);
411  
    return grammar::parse(s, authority_rule);
412  
}
412  
}
413  

413  

414  
} // urls
414  
} // urls
415  
} // boost
415  
} // boost
416  

416  

417  
#endif
417  
#endif